fci.c 57.2 KB
Newer Older
1 2 3 4
/*
 * File Compression Interface
 *
 * Copyright 2002 Patrik Stridvall
5
 * Copyright 2005 Gerold Jens Wucherpfennig
6
 * Copyright 2011 Alexandre Julliard
7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 22
 */

23 24 25 26
/*

There is still some work to be done:

27
- unknown behaviour if files>=2GB or cabinet >=4GB
28 29 30 31 32 33 34
- check if the maximum size for a cabinet is too small to store any data
- call pfnfcignc on exactly the same position as MS FCIAddFile in every case

*/



35 36
#include "config.h"

37
#include <assert.h>
38
#include <stdarg.h>
39 40
#include <stdio.h>
#include <string.h>
41 42 43
#ifdef HAVE_ZLIB
# include <zlib.h>
#endif
44

45
#include "windef.h"
46 47
#include "winbase.h"
#include "winerror.h"
48
#include "winternl.h"
49
#include "fci.h"
50
#include "cabinet.h"
51
#include "wine/list.h"
52 53
#include "wine/debug.h"

54
WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
55 56 57 58 59 60 61 62 63 64

#ifdef WORDS_BIGENDIAN
#define fci_endian_ulong(x) RtlUlongByteSwap(x)
#define fci_endian_uword(x) RtlUshortByteSwap(x)
#else
#define fci_endian_ulong(x) (x)
#define fci_endian_uword(x) (x)
#endif


65 66 67 68 69 70 71 72 73 74 75
typedef struct {
  cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */
  cab_ULONG reserved1;
  cab_ULONG cbCabinet;    /*  size of the cabinet file in bytes*/
  cab_ULONG reserved2;
  cab_ULONG coffFiles;    /* offset to first CFFILE section */
  cab_ULONG reserved3;
  cab_UBYTE versionMinor; /* 3 */
  cab_UBYTE versionMajor; /* 1 */
  cab_UWORD cFolders;     /* number of CFFOLDER entries in the cabinet*/
  cab_UWORD cFiles;       /* number of CFFILE entries in the cabinet*/
Austin English's avatar
Austin English committed
76
  cab_UWORD flags;        /* 1=prev cab, 2=next cabinet, 4=reserved sections*/
77 78 79 80 81 82 83 84 85 86
  cab_UWORD setID;        /* identification number of all cabinets in a set*/
  cab_UWORD iCabinet;     /* number of the cabinet in a set */
  /* additional area if "flags" were set*/
} CFHEADER; /* minimum 36 bytes */

typedef struct {
  cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */
  cab_UWORD cCFData;      /* number of this folder's CFDATA sections */
  cab_UWORD typeCompress; /* compression type of data in CFDATA section*/
  /* additional area if reserve flag was set */
87
} CFFOLDER; /* minimum 8 bytes */
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108

typedef struct {
  cab_ULONG cbFile;          /* size of the uncompressed file in bytes */
  cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */
  cab_UWORD iFolder;         /* number of folder in the cabinet 0=first  */
                             /* for special values see below this structure*/
  cab_UWORD date;            /* last modification date*/
  cab_UWORD time;            /* last modification time*/
  cab_UWORD attribs;         /* DOS fat attributes and UTF indicator */
  /* ... and a C string with the name of the file */
} CFFILE; /* 16 bytes + name of file */


typedef struct {
  cab_ULONG csum;          /* checksum of this entry*/
  cab_UWORD cbData;        /* number of compressed bytes  */
  cab_UWORD cbUncomp;      /* number of bytes when data is uncompressed */
  /* optional reserved area */
  /* compressed data */
} CFDATA;

109 110 111 112 113 114
struct temp_file
{
    INT_PTR   handle;
    char      name[CB_MAX_FILENAME];
};

115 116
struct folder
{
117 118 119 120 121 122
    struct list      entry;
    struct list      files_list;
    struct list      blocks_list;
    struct temp_file data;
    cab_ULONG        data_start;
    cab_UWORD        data_count;
123
    TCOMP            compression;
124
};
125

126 127 128 129 130 131 132 133 134 135 136 137
struct file
{
    struct list entry;
    cab_ULONG   size;    /* uncompressed size */
    cab_ULONG   offset;  /* offset in folder */
    cab_UWORD   folder;  /* index of folder */
    cab_UWORD   date;
    cab_UWORD   time;
    cab_UWORD   attribs;
    char        name[1];
};

138 139 140 141 142 143 144
struct data_block
{
    struct list entry;
    cab_UWORD   compressed;
    cab_UWORD   uncompressed;
};

145
typedef struct FCI_Int
146 147
{
  unsigned int       magic;
148
  PERF               perf;
149 150 151 152 153 154 155 156 157 158
  PFNFCIFILEPLACED   fileplaced;
  PFNFCIALLOC        alloc;
  PFNFCIFREE         free;
  PFNFCIOPEN         open;
  PFNFCIREAD         read;
  PFNFCIWRITE        write;
  PFNFCICLOSE        close;
  PFNFCISEEK         seek;
  PFNFCIDELETE       delete;
  PFNFCIGETTEMPFILE  gettemp;
159
  CCAB               ccab;
160 161 162 163 164 165 166 167
  PCCAB              pccab;
  BOOL               fPrevCab;
  BOOL               fNextCab;
  BOOL               fSplitFolder;
  cab_ULONG          statusFolderCopied;
  cab_ULONG          statusFolderTotal;
  BOOL               fGetNextCabInVain;
  void               *pv;
168 169 170 171
  char               szPrevCab[CB_MAX_CABINET_NAME]; /* previous cabinet name */
  char               szPrevDisk[CB_MAX_DISK_NAME];   /* disk name of previous cabinet */
  unsigned char      data_in[CAB_BLOCKMAX];          /* uncompressed data blocks */
  unsigned char      data_out[2 * CAB_BLOCKMAX];     /* compressed data blocks */
172 173 174 175 176 177 178
  cab_UWORD          cdata_in;
  ULONG              cCompressedBytesInFolder;
  cab_UWORD          cFolders;
  cab_UWORD          cFiles;
  cab_ULONG          cDataBlocks;
  cab_ULONG          cbFileRemainer; /* uncompressed, yet to be written data */
               /* of spanned file of a spanning folder of a spanning cabinet */
179
  struct temp_file   data;
180 181
  BOOL               fNewPrevious;
  cab_ULONG          estimatedCabinetSize;
182
  struct list        folders_list;
183
  struct list        files_list;
184
  struct list        blocks_list;
185
  cab_ULONG          folders_size;
186 187 188 189
  cab_ULONG          files_size;          /* size of files not yet assigned to a folder */
  cab_ULONG          placed_files_size;   /* size of files already placed into a folder */
  cab_ULONG          pending_data_size;   /* size of data not yet assigned to a folder */
  cab_ULONG          folders_data_size;   /* total size of data contained in the current folders */
190 191
  TCOMP              compression;
  cab_UWORD        (*compress)(struct FCI_Int *);
192 193 194 195
} FCI_Int;

#define FCI_INT_MAGIC 0xfcfcfc05

196 197 198 199 200 201 202 203
static void set_error( FCI_Int *fci, int oper, int err )
{
    fci->perf->erfOper = oper;
    fci->perf->erfType = err;
    fci->perf->fError = TRUE;
    if (err) SetLastError( err );
}

204 205 206 207
static FCI_Int *get_fci_ptr( HFCI hfci )
{
    FCI_Int *fci= (FCI_Int *)hfci;

208
    if (!fci || fci->magic != FCI_INT_MAGIC)
209 210 211 212 213 214 215
    {
        SetLastError( ERROR_INVALID_HANDLE );
        return NULL;
    }
    return fci;
}

216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
/* compute the cabinet header size */
static cab_ULONG get_header_size( FCI_Int *fci )
{
    cab_ULONG ret = sizeof(CFHEADER) + fci->ccab.cbReserveCFHeader;

    if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
        ret += 4;

    if (fci->fPrevCab)
        ret += strlen( fci->szPrevCab ) + 1 + strlen( fci->szPrevDisk ) + 1;

    if (fci->fNextCab)
        ret += strlen( fci->pccab->szCab ) + 1 + strlen( fci->pccab->szDisk ) + 1;

    return ret;
}

233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
static BOOL create_temp_file( FCI_Int *fci, struct temp_file *file )
{
    int err;

    if (!fci->gettemp( file->name, CB_MAX_FILENAME, fci->pv ))
    {
        set_error( fci, FCIERR_TEMP_FILE, ERROR_FUNCTION_FAILED );
        return FALSE;
    }
    if ((file->handle = fci->open( file->name, _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
                                   _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
    {
        set_error( fci, FCIERR_TEMP_FILE, err );
        return FALSE;
    }
    return TRUE;
}

static BOOL close_temp_file( FCI_Int *fci, struct temp_file *file )
{
    int err;

    if (file->handle == -1) return TRUE;
    if (fci->close( file->handle, &err, fci->pv ) == -1)
    {
        set_error( fci, FCIERR_TEMP_FILE, err );
        return FALSE;
    }
    file->handle = -1;
    if (fci->delete( file->name, &err, fci->pv ) == -1)
    {
        set_error( fci, FCIERR_TEMP_FILE, err );
        return FALSE;
    }
    return TRUE;
}

270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
static struct file *add_file( FCI_Int *fci, const char *filename )
{
    unsigned int size = FIELD_OFFSET( struct file, name[strlen(filename) + 1] );
    struct file *file = fci->alloc( size );

    if (!file)
    {
        set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
        return NULL;
    }
    file->size    = 0;
    file->offset  = fci->cDataBlocks * CAB_BLOCKMAX + fci->cdata_in;
    file->folder  = fci->cFolders;
    file->date    = 0;
    file->time    = 0;
    file->attribs = 0;
    strcpy( file->name, filename );
    list_add_tail( &fci->files_list, &file->entry );
288
    fci->files_size += sizeof(CFFILE) + strlen(filename) + 1;
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
    return file;
}

static struct file *copy_file( FCI_Int *fci, const struct file *orig )
{
    unsigned int size = FIELD_OFFSET( struct file, name[strlen(orig->name) + 1] );
    struct file *file = fci->alloc( size );

    if (!file)
    {
        set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
        return NULL;
    }
    memcpy( file, orig, size );
    return file;
}

static void free_file( FCI_Int *fci, struct file *file )
{
    list_remove( &file->entry );
    fci->free( file );
}

312 313
/* create a new data block for the data in fci->data_in */
static BOOL add_data_block( FCI_Int *fci, PFNFCISTATUS status_callback )
314
{
315 316
    int err;
    struct data_block *block;
317

318 319
    if (!fci->cdata_in) return TRUE;

320 321
    if (fci->data.handle == -1 && !create_temp_file( fci, &fci->data )) return FALSE;

322
    if (!(block = fci->alloc( sizeof(*block) )))
323 324
    {
        set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
325
        return FALSE;
326
    }
327 328 329 330 331 332 333 334 335 336 337 338
    block->uncompressed = fci->cdata_in;
    block->compressed   = fci->compress( fci );

    if (fci->write( fci->data.handle, fci->data_out,
                    block->compressed, &err, fci->pv ) != block->compressed)
    {
        set_error( fci, FCIERR_TEMP_FILE, err );
        fci->free( block );
        return FALSE;
    }

    fci->cdata_in = 0;
339
    fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
340
    fci->cCompressedBytesInFolder += block->compressed;
341
    fci->cDataBlocks++;
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
    list_add_tail( &fci->blocks_list, &block->entry );

    if (status_callback( statusFile, block->compressed, block->uncompressed, fci->pv ) == -1)
    {
        set_error( fci, FCIERR_USER_ABORT, 0 );
        return FALSE;
    }
    return TRUE;
}

/* add compressed blocks for all the data that can be read from the file */
static BOOL add_file_data( FCI_Int *fci, char *sourcefile, char *filename, BOOL execute,
                           PFNFCIGETOPENINFO get_open_info, PFNFCISTATUS status_callback )
{
    int err, len;
    INT_PTR handle;
    struct file *file;

    if (!(file = add_file( fci, filename ))) return FALSE;

    handle = get_open_info( sourcefile, &file->date, &file->time, &file->attribs, &err, fci->pv );
    if (handle == -1)
    {
        free_file( fci, file );
        set_error( fci, FCIERR_OPEN_SRC, err );
        return FALSE;
    }
    if (execute) file->attribs |= _A_EXEC;

    for (;;)
    {
        len = fci->read( handle, fci->data_in + fci->cdata_in,
                         CAB_BLOCKMAX - fci->cdata_in, &err, fci->pv );
        if (!len) break;

        if (len == -1)
        {
            set_error( fci, FCIERR_READ_SRC, err );
            return FALSE;
        }
        file->size += len;
        fci->cdata_in += len;
        if (fci->cdata_in == CAB_BLOCKMAX && !add_data_block( fci, status_callback )) return FALSE;
    }
    fci->close( handle, &err, fci->pv );
    return TRUE;
388 389 390 391 392 393 394 395
}

static void free_data_block( FCI_Int *fci, struct data_block *block )
{
    list_remove( &block->entry );
    fci->free( block );
}

396 397 398 399 400 401 402 403 404
static struct folder *add_folder( FCI_Int *fci )
{
    struct folder *folder = fci->alloc( sizeof(*folder) );

    if (!folder)
    {
        set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
        return NULL;
    }
405 406 407
    folder->data.handle = -1;
    folder->data_start  = fci->folders_data_size;
    folder->data_count  = 0;
408
    folder->compression = fci->compression;
409
    list_init( &folder->files_list );
410
    list_init( &folder->blocks_list );
411
    list_add_tail( &fci->folders_list, &folder->entry );
412
    fci->folders_size += sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
413 414 415 416
    fci->cFolders++;
    return folder;
}

417 418
static void free_folder( FCI_Int *fci, struct folder *folder )
{
419 420
    struct file *file, *file_next;
    struct data_block *block, *block_next;
421

422 423 424 425 426
    LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &folder->files_list, struct file, entry )
        free_file( fci, file );
    LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &folder->blocks_list, struct data_block, entry )
        free_data_block( fci, block );
    close_temp_file( fci, &folder->data );
427 428 429 430
    list_remove( &folder->entry );
    fci->free( folder );
}

431 432 433 434 435 436 437 438 439 440 441 442
/* reset state for the next cabinet file once the current one has been flushed */
static void reset_cabinet( FCI_Int *fci )
{
    struct folder *folder, *folder_next;

    LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &fci->folders_list, struct folder, entry )
        free_folder( fci, folder );

    fci->cFolders          = 0;
    fci->cFiles            = 0;
    fci->folders_size      = 0;
    fci->placed_files_size = 0;
443
    fci->folders_data_size = 0;
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
}

static cab_ULONG fci_get_checksum( const void *pv, UINT cb, cab_ULONG seed )
{
  cab_ULONG     csum;
  cab_ULONG     ul;
  int           cUlong;
  const BYTE    *pb;

  csum = seed;
  cUlong = cb / 4;
  pb = pv;

  while (cUlong-- > 0) {
    ul = *pb++;
    ul |= (((cab_ULONG)(*pb++)) <<  8);
    ul |= (((cab_ULONG)(*pb++)) << 16);
    ul |= (((cab_ULONG)(*pb++)) << 24);
    csum ^= ul;
  }

  ul = 0;
  switch (cb % 4) {
    case 3:
      ul |= (((ULONG)(*pb++)) << 16);
469
      /* fall through */
470 471
    case 2:
      ul |= (((ULONG)(*pb++)) <<  8);
472
      /* fall through */
473 474
    case 1:
      ul |= *pb;
475
      /* fall through */
476 477 478 479 480 481 482 483
    default:
      break;
  }
  csum ^= ul;

  return csum;
}

484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
/* copy all remaining data block to a new temp file */
static BOOL copy_data_blocks( FCI_Int *fci, INT_PTR handle, cab_ULONG start_pos,
                              struct temp_file *temp, PFNFCISTATUS status_callback )
{
    struct data_block *block;
    int err;

    if (fci->seek( handle, start_pos, SEEK_SET, &err, fci->pv ) != start_pos)
    {
        set_error( fci, FCIERR_TEMP_FILE, err );
        return FALSE;
    }
    if (!create_temp_file( fci, temp )) return FALSE;

    LIST_FOR_EACH_ENTRY( block, &fci->blocks_list, struct data_block, entry )
    {
        if (fci->read( handle, fci->data_out, block->compressed,
                       &err, fci->pv ) != block->compressed)
        {
            close_temp_file( fci, temp );
            set_error( fci, FCIERR_TEMP_FILE, err );
            return FALSE;
        }
        if (fci->write( temp->handle, fci->data_out, block->compressed,
                        &err, fci->pv ) != block->compressed)
        {
            close_temp_file( fci, temp );
            set_error( fci, FCIERR_TEMP_FILE, err );
            return FALSE;
        }
514
        fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed;
515 516 517 518 519 520 521 522 523 524 525 526 527
        fci->statusFolderCopied += block->compressed;

        if (status_callback( statusFolder, fci->statusFolderCopied,
                             fci->statusFolderTotal, fci->pv) == -1)
        {
            close_temp_file( fci, temp );
            set_error( fci, FCIERR_USER_ABORT, 0 );
            return FALSE;
        }
    }
    return TRUE;
}

528
/* write all folders to disk and remove them from the list */
529
static BOOL write_folders( FCI_Int *fci, INT_PTR handle, cab_ULONG header_size, PFNFCISTATUS status_callback )
530
{
531
    struct folder *folder;
532
    int err;
533
    CFFOLDER *cffolder = (CFFOLDER *)fci->data_out;
534
    cab_ULONG folder_size = sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder;
535 536 537

    memset( cffolder, 0, folder_size );

538 539
    /* write the folders */
    LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
540 541 542 543 544 545 546
    {
        cffolder->coffCabStart = fci_endian_ulong( folder->data_start + header_size );
        cffolder->cCFData      = fci_endian_uword( folder->data_count );
        cffolder->typeCompress = fci_endian_uword( folder->compression );
        if (fci->write( handle, cffolder, folder_size, &err, fci->pv ) != folder_size)
        {
            set_error( fci, FCIERR_CAB_FILE, err );
547
            return FALSE;
548
        }
549
    }
550
    return TRUE;
551 552 553 554 555 556 557 558 559
}

/* write all the files to the cabinet file */
static BOOL write_files( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
{
    cab_ULONG file_size;
    struct folder *folder;
    struct file *file;
    int err;
560
    CFFILE *cffile = (CFFILE *)fci->data_out;
561

562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
    LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
    {
        LIST_FOR_EACH_ENTRY( file, &folder->files_list, struct file, entry )
        {
            cffile->cbFile          = fci_endian_ulong( file->size );
            cffile->uoffFolderStart = fci_endian_ulong( file->offset );
            cffile->iFolder         = fci_endian_uword( file->folder );
            cffile->date            = fci_endian_uword( file->date );
            cffile->time            = fci_endian_uword( file->time );
            cffile->attribs         = fci_endian_uword( file->attribs );
            lstrcpynA( (char *)(cffile + 1), file->name, CB_MAX_FILENAME );
            file_size = sizeof(CFFILE) + strlen( (char *)(cffile + 1) ) + 1;
            if (fci->write( handle, cffile, file_size, &err, fci->pv ) != file_size)
            {
                set_error( fci, FCIERR_CAB_FILE, err );
577
                return FALSE;
578 579 580 581 582
            }
            if (!fci->fSplitFolder)
            {
                fci->statusFolderCopied = 0;
                /* TODO TEST THIS further */
583
                fci->statusFolderTotal = fci->folders_data_size + fci->placed_files_size;
584 585 586 587 588 589 590
            }
            fci->statusFolderCopied += file_size;
            /* report status about copied size of folder */
            if (status_callback( statusFolder, fci->statusFolderCopied,
                                 fci->statusFolderTotal, fci->pv ) == -1)
            {
                set_error( fci, FCIERR_USER_ABORT, 0 );
591
                return FALSE;
592 593 594
            }
        }
    }
595
    return TRUE;
596 597
}

598 599 600
/* write all data blocks to the cabinet file */
static BOOL write_data_blocks( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback )
{
601
    struct folder *folder;
602 603 604 605 606 607 608 609 610 611 612
    struct data_block *block;
    int err, len;
    CFDATA *cfdata;
    void *data;
    cab_UWORD header_size;

    header_size = sizeof(CFDATA) + fci->ccab.cbReserveCFData;
    cfdata = (CFDATA *)fci->data_out;
    memset( cfdata, 0, header_size );
    data = (char *)cfdata + header_size;

613
    LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry )
614
    {
615
        if (fci->seek( folder->data.handle, 0, SEEK_SET, &err, fci->pv ) != 0)
616 617 618 619
        {
            set_error( fci, FCIERR_CAB_FILE, err );
            return FALSE;
        }
620
        LIST_FOR_EACH_ENTRY( block, &folder->blocks_list, struct data_block, entry )
621
        {
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
            len = fci->read( folder->data.handle, data, block->compressed, &err, fci->pv );
            if (len != block->compressed) return FALSE;

            cfdata->cbData = fci_endian_uword( block->compressed );
            cfdata->cbUncomp = fci_endian_uword( block->uncompressed );
            cfdata->csum = fci_endian_ulong( fci_get_checksum( &cfdata->cbData,
                                                               header_size - FIELD_OFFSET(CFDATA, cbData),
                                                               fci_get_checksum( data, len, 0 )));

            fci->statusFolderCopied += len;
            len += header_size;
            if (fci->write( handle, fci->data_out, len, &err, fci->pv ) != len)
            {
                set_error( fci, FCIERR_CAB_FILE, err );
                return FALSE;
            }
            if (status_callback( statusFolder, fci->statusFolderCopied, fci->statusFolderTotal, fci->pv) == -1)
            {
                set_error( fci, FCIERR_USER_ABORT, 0 );
                return FALSE;
            }
643 644 645 646 647
        }
    }
    return TRUE;
}

648
/* write the cabinet file to disk */
649
static BOOL write_cabinet( FCI_Int *fci, PFNFCISTATUS status_callback )
650 651 652
{
    char filename[CB_MAX_CAB_PATH + CB_MAX_CABINET_NAME];
    int err;
653
    char *ptr;
654
    INT_PTR handle;
655
    CFHEADER *cfheader = (CFHEADER *)fci->data_out;
656 657
    cab_UWORD flags = 0;
    cab_ULONG header_size = get_header_size( fci );
658 659
    cab_ULONG total_size = header_size + fci->folders_size +
                           fci->placed_files_size + fci->folders_data_size;
660

661
    assert( header_size <= sizeof(fci->data_out) );
662 663 664 665 666 667 668 669
    memset( cfheader, 0, header_size );

    if (fci->fPrevCab) flags |= cfheadPREV_CABINET;
    if (fci->fNextCab) flags |= cfheadNEXT_CABINET;
    if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData)
      flags |= cfheadRESERVE_PRESENT;

    memcpy( cfheader->signature, "!CAB", 4 );
670
    cfheader->cbCabinet    = fci_endian_ulong( total_size );
671 672 673 674 675 676 677
    cfheader->coffFiles    = fci_endian_ulong( header_size + fci->folders_size );
    cfheader->versionMinor = 3;
    cfheader->versionMajor = 1;
    cfheader->cFolders     = fci_endian_uword( fci->cFolders );
    cfheader->cFiles       = fci_endian_uword( fci->cFiles );
    cfheader->flags        = fci_endian_uword( flags );
    cfheader->setID        = fci_endian_uword( fci->ccab.setID );
678
    cfheader->iCabinet     = fci_endian_uword( fci->ccab.iCab );
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
    ptr = (char *)(cfheader + 1);

    if (flags & cfheadRESERVE_PRESENT)
    {
        struct
        {
            cab_UWORD cbCFHeader;
            cab_UBYTE cbCFFolder;
            cab_UBYTE cbCFData;
        } *reserve = (void *)ptr;

        reserve->cbCFHeader = fci_endian_uword( fci->ccab.cbReserveCFHeader );
        reserve->cbCFFolder = fci->ccab.cbReserveCFFolder;
        reserve->cbCFData   = fci->ccab.cbReserveCFData;
        ptr = (char *)(reserve + 1);
    }
    ptr += fci->ccab.cbReserveCFHeader;

    if (flags & cfheadPREV_CABINET)
    {
        strcpy( ptr, fci->szPrevCab );
        ptr += strlen( ptr ) + 1;
        strcpy( ptr, fci->szPrevDisk );
        ptr += strlen( ptr ) + 1;
    }

    if (flags & cfheadNEXT_CABINET)
    {
        strcpy( ptr, fci->pccab->szCab );
        ptr += strlen( ptr ) + 1;
        strcpy( ptr, fci->pccab->szDisk );
        ptr += strlen( ptr ) + 1;
    }

    assert( ptr - (char *)cfheader == header_size );

    strcpy( filename, fci->ccab.szCabPath );
    strcat( filename, fci->ccab.szCab );

    if ((handle = fci->open( filename, _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY,
                             _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1)
    {
        set_error( fci, FCIERR_CAB_FILE, err );
722
        return FALSE;
723 724 725 726 727 728 729 730 731 732 733
    }

    if (fci->write( handle, cfheader, header_size, &err, fci->pv ) != header_size)
    {
        set_error( fci, FCIERR_CAB_FILE, err );
        goto failed;
    }

    /* add size of header size of all CFFOLDERs and size of all CFFILEs */
    header_size += fci->placed_files_size + fci->folders_size;
    if (!write_folders( fci, handle, header_size, status_callback )) goto failed;
734 735
    if (!write_files( fci, handle, status_callback )) goto failed;
    if (!write_data_blocks( fci, handle, status_callback )) goto failed;
736

737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
    /* update the signature */
    if (fci->seek( handle, 0, SEEK_SET, &err, fci->pv ) != 0 )
    {
        set_error( fci, FCIERR_CAB_FILE, err );
        goto failed;
    }
    memcpy( cfheader->signature, "MSCF", 4 );
    if (fci->write( handle, cfheader->signature, 4, &err, fci->pv ) != 4)
    {
        set_error( fci, FCIERR_CAB_FILE, err );
        goto failed;
    }
    fci->close( handle, &err, fci->pv );

    reset_cabinet( fci );
    status_callback( statusCabinet, fci->estimatedCabinetSize, total_size, fci->pv );
    return TRUE;
754 755 756 757

failed:
    fci->close( handle, &err, fci->pv );
    fci->delete( filename, &err, fci->pv );
758
    return FALSE;
759 760
}

761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
/* add all pending data blocks folder */
static BOOL add_data_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG *payload,
                                PFNFCISTATUS status_callback )
{
    struct data_block *block, *new, *next;
    BOOL split_block = FALSE;
    cab_ULONG current_size, start_pos = 0;

    *payload = 0;
    current_size = get_header_size( fci ) + fci->folders_size +
                   fci->files_size + fci->placed_files_size + fci->folders_data_size;

    /* move the temp file into the folder structure */
    folder->data = fci->data;
    fci->data.handle = -1;
776
    fci->pending_data_size = 0;
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833

    LIST_FOR_EACH_ENTRY_SAFE( block, next, &fci->blocks_list, struct data_block, entry )
    {
        /* No more CFDATA fits into the cabinet under construction */
        /* So don't try to store more data into it */
        if (fci->fNextCab && (fci->ccab.cb <= sizeof(CFDATA) + fci->ccab.cbReserveCFData +
                              current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
            break;

        if (!(new = fci->alloc( sizeof(*new) )))
        {
            set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
            return FALSE;
        }
        /* Is cabinet with new CFDATA too large? Then data block has to be split */
        if( fci->fNextCab &&
            (fci->ccab.cb < sizeof(CFDATA) + fci->ccab.cbReserveCFData +
             block->compressed + current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder))
        {
            /* Modify the size of the compressed data to store only a part of the */
            /* data block into the current cabinet. This is done to prevent */
            /* that the maximum cabinet size will be exceeded. The remainder */
            /* will be stored into the next following cabinet. */

            new->compressed = fci->ccab.cb - (sizeof(CFDATA) + fci->ccab.cbReserveCFData + current_size +
                                              sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder );
            new->uncompressed = 0; /* on split blocks of data this is zero */
            block->compressed -= new->compressed;
            split_block = TRUE;
        }
        else
        {
            new->compressed   = block->compressed;
            new->uncompressed = block->uncompressed;
        }

        start_pos += new->compressed;
        current_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
        fci->folders_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed;
        fci->statusFolderCopied += new->compressed;
        (*payload) += new->uncompressed;

        list_add_tail( &folder->blocks_list, &new->entry );
        folder->data_count++;

        /* report status with pfnfcis about copied size of folder */
        if (status_callback( statusFolder, fci->statusFolderCopied,
                             fci->statusFolderTotal, fci->pv ) == -1)
        {
            set_error( fci, FCIERR_USER_ABORT, 0 );
            return FALSE;
        }
        if (split_block) break;
        free_data_block( fci, block );
        fci->cDataBlocks--;
    }

834
    if (list_empty( &fci->blocks_list )) return TRUE;
835 836 837
    return copy_data_blocks( fci, folder->data.handle, start_pos, &fci->data, status_callback );
}

838 839 840 841 842 843 844 845 846 847 848 849
/* add all pending files to folder */
static BOOL add_files_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG payload )
{
    cab_ULONG sizeOfFiles = 0, sizeOfFilesPrev;
    cab_ULONG cbFileRemainer = 0;
    struct file *file, *next;

    LIST_FOR_EACH_ENTRY_SAFE( file, next, &fci->files_list, struct file, entry )
    {
        cab_ULONG size = sizeof(CFFILE) + strlen(file->name) + 1;

        /* fnfilfnfildest: placed file on cabinet */
850 851
        fci->fileplaced( &fci->ccab, file->name, file->size,
                         (file->folder == cffileCONTINUED_FROM_PREV), fci->pv );
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905

        sizeOfFilesPrev = sizeOfFiles;
        /* set complete size of all processed files */
        if (file->folder == cffileCONTINUED_FROM_PREV && fci->cbFileRemainer != 0)
        {
            sizeOfFiles += fci->cbFileRemainer;
            fci->cbFileRemainer = 0;
        }
        else sizeOfFiles += file->size;

        /* check if spanned file fits into this cabinet folder */
        if (sizeOfFiles > payload)
        {
            if (file->folder == cffileCONTINUED_FROM_PREV)
                file->folder = cffileCONTINUED_PREV_AND_NEXT;
            else
                file->folder = cffileCONTINUED_TO_NEXT;
        }

        list_remove( &file->entry );
        list_add_tail( &folder->files_list, &file->entry );
        fci->placed_files_size += size;
        fci->cFiles++;

        /* This is only true for files which will be written into the */
        /* next cabinet of the spanning folder */
        if (sizeOfFiles > payload)
        {
            /* add a copy back onto the list */
            if (!(file = copy_file( fci, file ))) return FALSE;
            list_add_before( &next->entry, &file->entry );

            /* Files which data will be partially written into the current cabinet */
            if (file->folder == cffileCONTINUED_PREV_AND_NEXT || file->folder == cffileCONTINUED_TO_NEXT)
            {
                if (sizeOfFilesPrev <= payload)
                {
                    /* The size of the uncompressed, data of a spanning file in a */
                    /* spanning data */
                    cbFileRemainer = sizeOfFiles - payload;
                }
                file->folder = cffileCONTINUED_FROM_PREV;
            }
            else file->folder = 0;
        }
        else
        {
            fci->files_size -= size;
        }
    }
    fci->cbFileRemainer = cbFileRemainer;
    return TRUE;
}

906 907 908 909 910 911
static cab_UWORD compress_NONE( FCI_Int *fci )
{
    memcpy( fci->data_out, fci->data_in, fci->cdata_in );
    return fci->cdata_in;
}

912 913 914 915 916 917 918 919 920 921 922
#ifdef HAVE_ZLIB

static void *zalloc( void *opaque, unsigned int items, unsigned int size )
{
    FCI_Int *fci = opaque;
    return fci->alloc( items * size );
}

static void zfree( void *opaque, void *ptr )
{
    FCI_Int *fci = opaque;
923
    fci->free( ptr );
924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940
}

static cab_UWORD compress_MSZIP( FCI_Int *fci )
{
    z_stream stream;

    stream.zalloc = zalloc;
    stream.zfree  = zfree;
    stream.opaque = fci;
    if (deflateInit2( &stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY ) != Z_OK)
    {
        set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY );
        return 0;
    }
    stream.next_in   = fci->data_in;
    stream.avail_in  = fci->cdata_in;
    stream.next_out  = fci->data_out + 2;
941
    stream.avail_out = sizeof(fci->data_out) - 2;
942 943 944 945 946 947 948 949 950 951
    /* insert the signature */
    fci->data_out[0] = 'C';
    fci->data_out[1] = 'K';
    deflate( &stream, Z_FINISH );
    deflateEnd( &stream );
    return stream.total_out + 2;
}

#endif  /* HAVE_ZLIB */

952

953 954
/***********************************************************************
 *		FCICreate (CABINET.10)
955
 *
956 957
 * FCICreate is provided with several callbacks and
 * returns a handle which can be used to create cabinet files.
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
 *
 * PARAMS
 *   perf       [IO]  A pointer to an ERF structure.  When FCICreate
 *                    returns an error condition, error information may
 *                    be found here as well as from GetLastError.
 *   pfnfiledest [I]  A pointer to a function which is called when a file
 *                    is placed. Only useful for subsequent cabinet files.
 *   pfnalloc    [I]  A pointer to a function which allocates ram.  Uses
 *                    the same interface as malloc.
 *   pfnfree     [I]  A pointer to a function which frees ram.  Uses the
 *                    same interface as free.
 *   pfnopen     [I]  A pointer to a function which opens a file.  Uses
 *                    the same interface as _open.
 *   pfnread     [I]  A pointer to a function which reads from a file into
 *                    a caller-provided buffer.  Uses the same interface
973
 *                    as _read.
974 975 976 977 978 979 980 981 982
 *   pfnwrite    [I]  A pointer to a function which writes to a file from
 *                    a caller-provided buffer.  Uses the same interface
 *                    as _write.
 *   pfnclose    [I]  A pointer to a function which closes a file handle.
 *                    Uses the same interface as _close.
 *   pfnseek     [I]  A pointer to a function which seeks in a file.
 *                    Uses the same interface as _lseek.
 *   pfndelete   [I]  A pointer to a function which deletes a file.
 *   pfnfcigtf   [I]  A pointer to a function which gets the name of a
983 984
 *                    temporary file.
 *   pccab       [I]  A pointer to an initialized CCAB structure.
985 986 987 988 989 990 991 992 993 994 995 996
 *   pv          [I]  A pointer to an application-defined notification
 *                    function which will be passed to other FCI functions
 *                    as a parameter.
 *
 * RETURNS
 *   On success, returns an FCI handle of type HFCI.
 *   On failure, the NULL file handle is returned. Error
 *   info can be retrieved from perf.
 *
 * INCLUDES
 *   fci.h
 *
997 998 999
 */
HFCI __cdecl FCICreate(
	PERF perf,
1000 1001 1002
	PFNFCIFILEPLACED   pfnfiledest,
	PFNFCIALLOC        pfnalloc,
	PFNFCIFREE         pfnfree,
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
	PFNFCIOPEN         pfnopen,
	PFNFCIREAD         pfnread,
	PFNFCIWRITE        pfnwrite,
	PFNFCICLOSE        pfnclose,
	PFNFCISEEK         pfnseek,
	PFNFCIDELETE       pfndelete,
	PFNFCIGETTEMPFILE  pfnfcigtf,
	PCCAB              pccab,
	void *pv)
{
1013
  FCI_Int *p_fci_internal;
1014

1015 1016 1017 1018 1019
  if (!perf) {
    SetLastError(ERROR_BAD_ARGUMENTS);
    return NULL;
  }
  if ((!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) ||
1020 1021
      (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) ||
      (!pfnfcigtf) || (!pccab)) {
1022
    perf->erfOper = FCIERR_NONE;
1023
    perf->erfType = ERROR_BAD_ARGUMENTS;
1024 1025
    perf->fError = TRUE;

1026 1027 1028 1029
    SetLastError(ERROR_BAD_ARGUMENTS);
    return NULL;
  }

1030
  if (!((p_fci_internal = pfnalloc(sizeof(FCI_Int))))) {
1031 1032 1033
    perf->erfOper = FCIERR_ALLOC_FAIL;
    perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
    perf->fError = TRUE;
1034

1035
    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1036
    return NULL;
1037 1038
  }

1039
  memset(p_fci_internal, 0, sizeof(FCI_Int));
1040
  p_fci_internal->magic = FCI_INT_MAGIC;
1041
  p_fci_internal->perf = perf;
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051
  p_fci_internal->fileplaced = pfnfiledest;
  p_fci_internal->alloc = pfnalloc;
  p_fci_internal->free = pfnfree;
  p_fci_internal->open = pfnopen;
  p_fci_internal->read = pfnread;
  p_fci_internal->write = pfnwrite;
  p_fci_internal->close = pfnclose;
  p_fci_internal->seek = pfnseek;
  p_fci_internal->delete = pfndelete;
  p_fci_internal->gettemp = pfnfcigtf;
1052
  p_fci_internal->ccab = *pccab;
1053 1054
  p_fci_internal->pccab = pccab;
  p_fci_internal->pv = pv;
1055
  p_fci_internal->data.handle = -1;
1056
  p_fci_internal->compress = compress_NONE;
1057 1058

  list_init( &p_fci_internal->folders_list );
1059
  list_init( &p_fci_internal->files_list );
1060
  list_init( &p_fci_internal->blocks_list );
1061

1062 1063
  memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME);
  memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME);
1064

1065 1066
  return (HFCI)p_fci_internal;
}
1067 1068 1069 1070




1071
static BOOL fci_flush_folder( FCI_Int *p_fci_internal,
1072 1073 1074 1075
	BOOL                  fGetNextCab,
	PFNFCIGETNEXTCABINET  pfnfcignc,
	PFNFCISTATUS          pfnfcis)
{
1076 1077
  cab_ULONG payload;
  cab_ULONG read_result;
1078
  struct folder *folder;
1079

1080
  if ((!pfnfcignc) || (!pfnfcis)) {
1081
    set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1082
    return FALSE;
1083
  }
1084

1085 1086
  if( p_fci_internal->fGetNextCabInVain &&
      p_fci_internal->fNextCab ){
1087
    /* internal error */
1088
    set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1089 1090 1091 1092 1093
    return FALSE;
  }

  /* If there was no FCIAddFile or FCIFlushFolder has already been called */
  /* this function will return TRUE */
1094
  if( p_fci_internal->files_size == 0 ) {
1095
    if ( p_fci_internal->pending_data_size != 0 ) {
1096
      /* error handling */
1097
      set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1098 1099 1100 1101
      return FALSE;
    }
    return TRUE;
  }
1102

1103
  /* FCIFlushFolder has already been called... */
1104
  if (p_fci_internal->fSplitFolder && p_fci_internal->placed_files_size!=0) {
1105 1106 1107
    return TRUE;
  }

1108 1109
  /* This can be set already, because it makes only a difference */
  /* when the current function exits with return FALSE */
1110 1111 1112
  p_fci_internal->fSplitFolder=FALSE;

  /* START of COPY */
1113
  if (!add_data_block( p_fci_internal, pfnfcis )) return FALSE;
1114 1115 1116 1117 1118

  /* reset to get the number of data blocks of this folder which are */
  /* actually in this cabinet ( at least partially ) */
  p_fci_internal->cDataBlocks=0;

1119 1120 1121
  p_fci_internal->statusFolderTotal = get_header_size( p_fci_internal ) +
      sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder +
      p_fci_internal->placed_files_size+
1122
      p_fci_internal->folders_data_size + p_fci_internal->files_size+
1123
      p_fci_internal->pending_data_size + p_fci_internal->folders_size;
1124 1125 1126 1127 1128 1129
  p_fci_internal->statusFolderCopied = 0;

  /* report status with pfnfcis about copied size of folder */
  if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied,
      p_fci_internal->statusFolderTotal, /* TODO total folder size */
      p_fci_internal->pv) == -1) {
1130
    set_error( p_fci_internal, FCIERR_USER_ABORT, 0 );
1131
    return FALSE;
1132
  }
1133

1134
  /* USE the variable read_result */
1135
  read_result = get_header_size( p_fci_internal ) + p_fci_internal->folders_data_size +
1136
      p_fci_internal->placed_files_size + p_fci_internal->folders_size;
1137

1138
  if(p_fci_internal->files_size!=0) {
1139
    read_result+= sizeof(CFFOLDER)+p_fci_internal->ccab.cbReserveCFFolder;
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
  }

  /* Check if multiple cabinets have to be created. */

  /* Might be too much data for the maximum allowed cabinet size.*/
  /* When any further data will be added later, it might not */
  /* be possible to flush the cabinet, because there might */
  /* not be enough space to store the name of the following */
  /* cabinet and name of the corresponding disk. */
  /* So take care of this and get the name of the next cabinet */
  if( p_fci_internal->fGetNextCabInVain==FALSE &&
      p_fci_internal->fNextCab==FALSE &&
      (
        (
1154
          p_fci_internal->ccab.cb < read_result +
1155
          p_fci_internal->pending_data_size +
1156
          p_fci_internal->files_size +
1157 1158 1159 1160 1161 1162 1163 1164
          CB_MAX_CABINET_NAME +   /* next cabinet name */
          CB_MAX_DISK_NAME        /* next disk name */
        ) || fGetNextCab
      )
  ) {
    /* increment cabinet index */
    ++(p_fci_internal->pccab->iCab);
    /* get name of next cabinet */
1165 1166 1167
    p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
    if (!(*pfnfcignc)(p_fci_internal->pccab,
        p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1168
        p_fci_internal->pv)) {
1169
      set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1170 1171 1172
      return FALSE;
    }

1173
    /* Skip a few lines of code. This is caught by the next if. */
1174 1175 1176 1177 1178 1179 1180 1181
    p_fci_internal->fGetNextCabInVain=TRUE;
  }

  /* too much data for cabinet */
  if( (p_fci_internal->fGetNextCabInVain ||
        p_fci_internal->fNextCab ) &&
      (
        (
1182
          p_fci_internal->ccab.cb < read_result +
1183
          p_fci_internal->pending_data_size +
1184
          p_fci_internal->files_size +
1185 1186 1187 1188 1189 1190 1191 1192 1193 1194
          strlen(p_fci_internal->pccab->szCab)+1 +   /* next cabinet name */
          strlen(p_fci_internal->pccab->szDisk)+1    /* next disk name */
        ) || fGetNextCab
      )
  ) {
    p_fci_internal->fGetNextCabInVain=FALSE;
    p_fci_internal->fNextCab=TRUE;

    /* return FALSE if there is not enough space left*/
    /* this should never happen */
1195
    if (p_fci_internal->ccab.cb <=
1196
        p_fci_internal->files_size +
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210
        read_result +
        strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */
        strlen(p_fci_internal->pccab->szDisk)+1  /* next disk name */
    ) {

      return FALSE;
    }

    /* the folder will be split across cabinets */
    p_fci_internal->fSplitFolder=TRUE;

  } else {
    /* this should never happen */
    if (p_fci_internal->fNextCab) {
1211
      /* internal error */
1212
      set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1213 1214 1215 1216
      return FALSE;
    }
  }

1217
  if (!(folder = add_folder( p_fci_internal ))) return FALSE;
1218 1219
  if (!add_data_to_folder( p_fci_internal, folder, &payload, pfnfcis )) return FALSE;
  if (!add_files_to_folder( p_fci_internal, folder, payload )) return FALSE;
1220 1221 1222 1223 1224 1225

  /* reset CFFolder specific information */
  p_fci_internal->cDataBlocks=0;
  p_fci_internal->cCompressedBytesInFolder=0;

  return TRUE;
1226
}
1227 1228 1229 1230




1231
static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal,
1232 1233 1234 1235
	BOOL                  fGetNextCab,
	PFNFCIGETNEXTCABINET  pfnfcignc,
	PFNFCISTATUS          pfnfcis)
{
1236
  cab_ULONG read_result=0;
1237 1238 1239 1240
  BOOL returntrue=FALSE;

  /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */

1241
  /* when FCIFlushCabinet was or FCIAddFile hasn't been called */
1242
  if( p_fci_internal->files_size==0 && fGetNextCab ) {
1243 1244 1245
    returntrue=TRUE;
  }

1246
  if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){
1247 1248 1249 1250 1251 1252
    /* TODO set error */
    return FALSE;
  }

  if(returntrue) return TRUE;

1253
  if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)||
1254
       (p_fci_internal->folders_size==0 &&
1255 1256
         (p_fci_internal->files_size!=0 ||
          p_fci_internal->placed_files_size!=0 )
1257 1258 1259
     ) )
  {
      /* error */
1260
      set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1261 1262 1263
      return FALSE;
  }

1264
  /* create the cabinet */
1265
  if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE;
1266 1267 1268 1269 1270 1271 1272 1273

  p_fci_internal->fPrevCab=TRUE;
  /* The sections szPrevCab and szPrevDisk are not being updated, because */
  /* MS CABINET.DLL always puts the first cabinet name and disk into them */

  if (p_fci_internal->fNextCab) {
    p_fci_internal->fNextCab=FALSE;

1274
    if (p_fci_internal->files_size==0 && p_fci_internal->pending_data_size!=0) {
1275
      /* THIS CAN NEVER HAPPEN */
1276
      /* set error code */
1277
      set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1278 1279 1280
      return FALSE;
    }

1281 1282 1283 1284 1285 1286 1287 1288
    if( p_fci_internal->fNewPrevious ) {
      memcpy(p_fci_internal->szPrevCab, p_fci_internal->ccab.szCab,
        CB_MAX_CABINET_NAME);
      memcpy(p_fci_internal->szPrevDisk, p_fci_internal->ccab.szDisk,
        CB_MAX_DISK_NAME);
      p_fci_internal->fNewPrevious=FALSE;
    }
    p_fci_internal->ccab = *p_fci_internal->pccab;
1289 1290

    /* REUSE the variable read_result */
1291 1292 1293
    read_result=get_header_size( p_fci_internal );
    if(p_fci_internal->files_size!=0) {
        read_result+=p_fci_internal->ccab.cbReserveCFFolder;
1294
    }
1295
    read_result+= p_fci_internal->pending_data_size +
1296
      p_fci_internal->files_size + p_fci_internal->folders_data_size +
1297
      p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1298 1299 1300 1301
      sizeof(CFFOLDER); /* set size of new CFFolder entry */

    /* too much data for the maximum size of a cabinet */
    if( p_fci_internal->fGetNextCabInVain==FALSE &&
1302
        p_fci_internal->ccab.cb < read_result ) {
1303
      return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1304 1305 1306 1307 1308 1309 1310 1311 1312
    }

    /* Might be too much data for the maximum size of a cabinet.*/
    /* When any further data will be added later, it might not */
    /* be possible to flush the cabinet, because there might */
    /* not be enough space to store the name of the following */
    /* cabinet and name of the corresponding disk. */
    /* So take care of this and get the name of the next cabinet */
    if (p_fci_internal->fGetNextCabInVain==FALSE && (
1313
      p_fci_internal->ccab.cb < read_result +
1314 1315 1316 1317 1318
      CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
    )) {
      /* increment cabinet index */
      ++(p_fci_internal->pccab->iCab);
      /* get name of next cabinet */
1319 1320 1321
      p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
      if (!(*pfnfcignc)(p_fci_internal->pccab,
          p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1322
          p_fci_internal->pv)) {
1323
        /* error handling */
1324
        set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1325 1326
        return FALSE;
      }
1327
      /* Skip a few lines of code. This is caught by the next if. */
1328 1329 1330 1331 1332
      p_fci_internal->fGetNextCabInVain=TRUE;
    }

    /* too much data for cabinet */
    if (p_fci_internal->fGetNextCabInVain && (
1333 1334 1335
        p_fci_internal->ccab.cb < read_result +
        strlen(p_fci_internal->ccab.szCab)+1+
        strlen(p_fci_internal->ccab.szDisk)+1
1336 1337 1338
    )) {
      p_fci_internal->fGetNextCabInVain=FALSE;
      p_fci_internal->fNextCab=TRUE;
1339
      return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1340 1341 1342
    }

    /* if the FolderThreshold has been reached flush the folder automatically */
1343
    if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1344
        return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1345

1346
    if( p_fci_internal->files_size>0 ) {
1347
      if( !fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis) ) return FALSE;
1348 1349 1350 1351
      p_fci_internal->fNewPrevious=TRUE;
    }
  } else {
    p_fci_internal->fNewPrevious=FALSE;
1352
    if( p_fci_internal->files_size>0 || p_fci_internal->pending_data_size) {
1353
      /* THIS MAY NEVER HAPPEN */
1354
      /* set error structures */
1355
      set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407
      return FALSE;
    }
  }

  return TRUE;
} /* end of fci_flush_cabinet */





/***********************************************************************
 *		FCIAddFile (CABINET.11)
 *
 * FCIAddFile adds a file to the to be created cabinet file
 *
 * PARAMS
 *   hfci          [I]  An HFCI from FCICreate
 *   pszSourceFile [I]  A pointer to a C string which contains the name and
 *                      location of the file which will be added to the cabinet
 *   pszFileName   [I]  A pointer to a C string which contains the name under
 *                      which the file will be stored in the cabinet
 *   fExecute      [I]  A boolean value which indicates if the file should be
 *                      executed after extraction of self extracting
 *                      executables
 *   pfnfcignc     [I]  A pointer to a function which gets information about
 *                      the next cabinet
 *   pfnfcis      [IO]  A pointer to a function which will report status
 *                      information about the compression process
 *   pfnfcioi      [I]  A pointer to a function which reports file attributes
 *                      and time and date information
 *   typeCompress  [I]  Compression type
 *
 * RETURNS
 *   On success, returns TRUE
 *   On failure, returns FALSE
 *
 * INCLUDES
 *   fci.h
 *
 */
BOOL __cdecl FCIAddFile(
	HFCI                  hfci,
	char                 *pszSourceFile,
	char                 *pszFileName,
	BOOL                  fExecute,
	PFNFCIGETNEXTCABINET  pfnfcignc,
	PFNFCISTATUS          pfnfcis,
	PFNFCIGETOPENINFO     pfnfcigoi,
	TCOMP                 typeCompress)
{
  cab_ULONG read_result;
1408
  FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1409

1410
  if (!p_fci_internal) return FALSE;
1411 1412 1413

  if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) ||
      (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) {
1414
    set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS );
1415 1416 1417
    return FALSE;
  }

1418 1419 1420 1421 1422
  if (typeCompress != p_fci_internal->compression)
  {
      if (!FCIFlushFolder( hfci, pfnfcignc, pfnfcis )) return FALSE;
      switch (typeCompress)
      {
1423 1424 1425 1426 1427 1428
      case tcompTYPE_MSZIP:
#ifdef HAVE_ZLIB
          p_fci_internal->compression = tcompTYPE_MSZIP;
          p_fci_internal->compress    = compress_MSZIP;
          break;
#endif
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438
      default:
          FIXME( "compression %x not supported, defaulting to none\n", typeCompress );
          /* fall through */
      case tcompTYPE_NONE:
          p_fci_internal->compression = tcompTYPE_NONE;
          p_fci_internal->compress    = compress_NONE;
          break;
      }
  }

1439 1440 1441
  /* TODO check if pszSourceFile??? */

  if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) {
1442
    /* internal error */
1443
    set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1444 1445 1446 1447
    return FALSE;
  }

  if(p_fci_internal->fNextCab) {
1448
    /* internal error */
1449
    set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1450 1451 1452 1453
    return FALSE;
  }

  /* REUSE the variable read_result */
1454
  read_result=get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1455 1456

  read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 +
1457
    p_fci_internal->files_size + p_fci_internal->folders_data_size +
1458
    p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1459 1460 1461 1462 1463 1464 1465 1466 1467 1468
    sizeof(CFFOLDER); /* size of new CFFolder entry */

  /* Might be too much data for the maximum size of a cabinet.*/
  /* When any further data will be added later, it might not */
  /* be possible to flush the cabinet, because there might */
  /* not be enough space to store the name of the following */
  /* cabinet and name of the corresponding disk. */
  /* So take care of this and get the name of the next cabinet */
  if( p_fci_internal->fGetNextCabInVain==FALSE &&
      p_fci_internal->fNextCab==FALSE &&
1469
      ( p_fci_internal->ccab.cb < read_result +
1470 1471 1472 1473 1474 1475
        CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
      )
  ) {
    /* increment cabinet index */
    ++(p_fci_internal->pccab->iCab);
    /* get name of next cabinet */
1476 1477 1478
    p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
    if (!(*pfnfcignc)(p_fci_internal->pccab,
        p_fci_internal->estimatedCabinetSize, /* estimated size of cab */
1479
        p_fci_internal->pv)) {
1480
      /* error handling */
1481
      set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1482 1483
      return FALSE;
    }
1484
    /* Skip a few lines of code. This is caught by the next if. */
1485 1486 1487 1488 1489 1490 1491
    p_fci_internal->fGetNextCabInVain=TRUE;
  }

  if( p_fci_internal->fGetNextCabInVain &&
      p_fci_internal->fNextCab
  ) {
    /* THIS CAN NEVER HAPPEN */
1492
    /* set error code */
1493
    set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1494 1495 1496 1497 1498 1499
    return FALSE;
  }

  /* too much data for cabinet */
  if( p_fci_internal->fGetNextCabInVain &&
     (
1500
      p_fci_internal->ccab.cb < read_result +
1501 1502 1503 1504 1505
      strlen(p_fci_internal->pccab->szCab)+1+
      strlen(p_fci_internal->pccab->szDisk)+1
  )) {
    p_fci_internal->fGetNextCabInVain=FALSE;
    p_fci_internal->fNextCab=TRUE;
1506
    if(!fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis)) return FALSE;
1507 1508 1509 1510
  }

  if( p_fci_internal->fNextCab ) {
    /* THIS MAY NEVER HAPPEN */
1511
    /* set error code */
1512
    set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1513 1514 1515
    return FALSE;
  }

1516
  if (!add_file_data( p_fci_internal, pszSourceFile, pszFileName, fExecute, pfnfcigoi, pfnfcis ))
1517 1518 1519
      return FALSE;

  /* REUSE the variable read_result */
1520
  read_result = get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder;
1521
  read_result+= p_fci_internal->pending_data_size +
1522
    p_fci_internal->files_size + p_fci_internal->folders_data_size +
1523
    p_fci_internal->placed_files_size + p_fci_internal->folders_size +
1524 1525 1526 1527 1528 1529
    sizeof(CFFOLDER); /* set size of new CFFolder entry */

  /* too much data for the maximum size of a cabinet */
  /* (ignoring the unflushed data block) */
  if( p_fci_internal->fGetNextCabInVain==FALSE &&
      p_fci_internal->fNextCab==FALSE && /* this is always the case */
1530
      p_fci_internal->ccab.cb < read_result ) {
1531
    return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542
  }

  /* Might be too much data for the maximum size of a cabinet.*/
  /* When any further data will be added later, it might not */
  /* be possible to flush the cabinet, because there might */
  /* not be enough space to store the name of the following */
  /* cabinet and name of the corresponding disk. */
  /* So take care of this and get the name of the next cabinet */
  /* (ignoring the unflushed data block) */
  if( p_fci_internal->fGetNextCabInVain==FALSE &&
      p_fci_internal->fNextCab==FALSE &&
1543
      ( p_fci_internal->ccab.cb < read_result +
1544 1545 1546 1547 1548 1549
        CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME
      )
  ) {
    /* increment cabinet index */
    ++(p_fci_internal->pccab->iCab);
    /* get name of next cabinet */
1550 1551 1552
    p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal;
    if (!(*pfnfcignc)(p_fci_internal->pccab,
        p_fci_internal->estimatedCabinetSize,/* estimated size of cab */
1553
        p_fci_internal->pv)) {
1554
      /* error handling */
1555
      set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED );
1556 1557
      return FALSE;
    }
1558
    /* Skip a few lines of code. This is caught by the next if. */
1559 1560 1561 1562 1563 1564 1565
    p_fci_internal->fGetNextCabInVain=TRUE;
  }

  if( p_fci_internal->fGetNextCabInVain &&
      p_fci_internal->fNextCab
  ) {
    /* THIS CAN NEVER HAPPEN */
1566
    set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1567 1568 1569 1570 1571 1572
    return FALSE;
  }

  /* too much data for cabinet */
  if( (p_fci_internal->fGetNextCabInVain ||
      p_fci_internal->fNextCab) && (
1573
      p_fci_internal->ccab.cb < read_result +
1574 1575 1576 1577 1578 1579
      strlen(p_fci_internal->pccab->szCab)+1+
      strlen(p_fci_internal->pccab->szDisk)+1
  )) {

    p_fci_internal->fGetNextCabInVain=FALSE;
    p_fci_internal->fNextCab=TRUE;
1580
    return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis);
1581 1582 1583 1584
  }

  if( p_fci_internal->fNextCab ) {
    /* THIS MAY NEVER HAPPEN */
1585
    /* set error code */
1586
    set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE );
1587 1588 1589 1590
    return FALSE;
  }

  /* if the FolderThreshold has been reached flush the folder automatically */
1591
  if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh)
1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605
      return FCIFlushFolder(hfci, pfnfcignc, pfnfcis);

  return TRUE;
} /* end of FCIAddFile */





/***********************************************************************
 *		FCIFlushFolder (CABINET.12)
 *
 * FCIFlushFolder completes the CFFolder structure under construction.
 *
Austin English's avatar
Austin English committed
1606
 * All further data which is added by FCIAddFile will be associated to
1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635
 * the next CFFolder structure.
 *
 * FCIFlushFolder will be called by FCIAddFile automatically if the
 * threshold (stored in the member cbFolderThresh of the CCAB structure
 * pccab passed to FCICreate) is exceeded.
 *
 * FCIFlushFolder will be called by FCIFlushFolder automatically before
 * any data will be written into the cabinet file.
 *
 * PARAMS
 *   hfci          [I]  An HFCI from FCICreate
 *   pfnfcignc     [I]  A pointer to a function which gets information about
 *                      the next cabinet
 *   pfnfcis      [IO]  A pointer to a function which will report status
 *                      information about the compression process
 *
 * RETURNS
 *   On success, returns TRUE
 *   On failure, returns FALSE
 *
 * INCLUDES
 *   fci.h
 *
 */
BOOL __cdecl FCIFlushFolder(
	HFCI                  hfci,
	PFNFCIGETNEXTCABINET  pfnfcignc,
	PFNFCISTATUS          pfnfcis)
{
1636 1637 1638 1639 1640
    FCI_Int *p_fci_internal = get_fci_ptr( hfci );

    if (!p_fci_internal) return FALSE;
    return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis);
}
1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680



/***********************************************************************
 *		FCIFlushCabinet (CABINET.13)
 *
 * FCIFlushCabinet stores the data which has been added by FCIAddFile
 * into the cabinet file. If the maximum cabinet size (stored in the
 * member cb of the CCAB structure pccab passed to FCICreate) has been
 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile.
 * The remaining data still has to be flushed manually by calling
 * FCIFlushCabinet.
 *
 * After FCIFlushCabinet has been called (manually) FCIAddFile must
 * NOT be called again. Then hfci has to be released by FCIDestroy.
 *
 * PARAMS
 *   hfci          [I]  An HFCI from FCICreate
 *   fGetNextCab   [I]  Whether you want to add additional files to a
 *                      cabinet set (TRUE) or whether you want to
 *                      finalize it (FALSE)
 *   pfnfcignc     [I]  A pointer to a function which gets information about
 *                      the next cabinet
 *   pfnfcis      [IO]  A pointer to a function which will report status
 *                      information about the compression process
 *
 * RETURNS
 *   On success, returns TRUE
 *   On failure, returns FALSE
 *
 * INCLUDES
 *   fci.h
 *
 */
BOOL __cdecl FCIFlushCabinet(
	HFCI                  hfci,
	BOOL                  fGetNextCab,
	PFNFCIGETNEXTCABINET  pfnfcignc,
	PFNFCISTATUS          pfnfcis)
{
1681
  FCI_Int *p_fci_internal = get_fci_ptr( hfci );
1682

1683 1684 1685
  if (!p_fci_internal) return FALSE;

  if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1686

1687 1688
  while( p_fci_internal->files_size>0 ||
         p_fci_internal->placed_files_size>0 ) {
1689
    if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE;
1690 1691 1692
  }

  return TRUE;
1693
}
1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710


/***********************************************************************
 *		FCIDestroy (CABINET.14)
 *
 * Frees a handle created by FCICreate.
 * Only reason for failure would be an invalid handle.
 *
 * PARAMS
 *   hfci [I] The HFCI to free
 *
 * RETURNS
 *   TRUE for success
 *   FALSE for failure
 */
BOOL __cdecl FCIDestroy(HFCI hfci)
{
1711
    struct folder *folder, *folder_next;
1712
    struct file *file, *file_next;
1713
    struct data_block *block, *block_next;
1714 1715 1716
    FCI_Int *p_fci_internal = get_fci_ptr( hfci );

    if (!p_fci_internal) return FALSE;
1717 1718 1719

    /* before hfci can be removed all temporary files must be closed */
    /* and deleted */
1720
    p_fci_internal->magic = 0;
1721

1722 1723
    LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &p_fci_internal->folders_list, struct folder, entry )
    {
1724 1725 1726 1727 1728
        free_folder( p_fci_internal, folder );
    }
    LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &p_fci_internal->files_list, struct file, entry )
    {
        free_file( p_fci_internal, file );
1729
    }
1730 1731 1732 1733
    LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry )
    {
        free_data_block( p_fci_internal, block );
    }
1734

1735
    close_temp_file( p_fci_internal, &p_fci_internal->data );
1736 1737

    /* hfci can now be removed */
1738
    p_fci_internal->free(hfci);
1739
    return TRUE;
1740
}