Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenfci.c
Go to the documentation of this file.
00001 /* 00002 * File Compression Interface 00003 * 00004 * Copyright 2002 Patrik Stridvall 00005 * Copyright 2005 Gerold Jens Wucherpfennig 00006 * Copyright 2011 Alexandre Julliard 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00021 */ 00022 00023 /* 00024 00025 There is still some work to be done: 00026 00027 - unknown behaviour if files>=2GB or cabinet >=4GB 00028 - check if the maximum size for a cabinet is too small to store any data 00029 - call pfnfcignc on exactly the same position as MS FCIAddFile in every case 00030 00031 */ 00032 00033 00034 00035 #include "config.h" 00036 00037 #include <assert.h> 00038 #include <stdarg.h> 00039 #include <stdio.h> 00040 #include <string.h> 00041 #ifdef HAVE_ZLIB 00042 # include <zlib.h> 00043 #endif 00044 00045 #include "windef.h" 00046 #include "winbase.h" 00047 #include "winerror.h" 00048 #include "winternl.h" 00049 #include "fci.h" 00050 #include "cabinet.h" 00051 #include "wine/list.h" 00052 #include "wine/debug.h" 00053 00054 WINE_DEFAULT_DEBUG_CHANNEL(cabinet); 00055 00056 #ifdef WORDS_BIGENDIAN 00057 #define fci_endian_ulong(x) RtlUlongByteSwap(x) 00058 #define fci_endian_uword(x) RtlUshortByteSwap(x) 00059 #else 00060 #define fci_endian_ulong(x) (x) 00061 #define fci_endian_uword(x) (x) 00062 #endif 00063 00064 00065 typedef struct { 00066 cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */ 00067 cab_ULONG reserved1; 00068 cab_ULONG cbCabinet; /* size of the cabinet file in bytes*/ 00069 cab_ULONG reserved2; 00070 cab_ULONG coffFiles; /* offset to first CFFILE section */ 00071 cab_ULONG reserved3; 00072 cab_UBYTE versionMinor; /* 3 */ 00073 cab_UBYTE versionMajor; /* 1 */ 00074 cab_UWORD cFolders; /* number of CFFOLDER entries in the cabinet*/ 00075 cab_UWORD cFiles; /* number of CFFILE entries in the cabinet*/ 00076 cab_UWORD flags; /* 1=prev cab, 2=next cabinet, 4=reserved sections*/ 00077 cab_UWORD setID; /* identification number of all cabinets in a set*/ 00078 cab_UWORD iCabinet; /* number of the cabinet in a set */ 00079 /* additional area if "flags" were set*/ 00080 } CFHEADER; /* minimum 36 bytes */ 00081 00082 typedef struct { 00083 cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */ 00084 cab_UWORD cCFData; /* number of this folder's CFDATA sections */ 00085 cab_UWORD typeCompress; /* compression type of data in CFDATA section*/ 00086 /* additional area if reserve flag was set */ 00087 } CFFOLDER; /* minimum 8 bytes */ 00088 00089 typedef struct { 00090 cab_ULONG cbFile; /* size of the uncompressed file in bytes */ 00091 cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */ 00092 cab_UWORD iFolder; /* number of folder in the cabinet 0=first */ 00093 /* for special values see below this structure*/ 00094 cab_UWORD date; /* last modification date*/ 00095 cab_UWORD time; /* last modification time*/ 00096 cab_UWORD attribs; /* DOS fat attributes and UTF indicator */ 00097 /* ... and a C string with the name of the file */ 00098 } CFFILE; /* 16 bytes + name of file */ 00099 00100 00101 typedef struct { 00102 cab_ULONG csum; /* checksum of this entry*/ 00103 cab_UWORD cbData; /* number of compressed bytes */ 00104 cab_UWORD cbUncomp; /* number of bytes when data is uncompressed */ 00105 /* optional reserved area */ 00106 /* compressed data */ 00107 } CFDATA; 00108 00109 struct temp_file 00110 { 00111 INT_PTR handle; 00112 char name[CB_MAX_FILENAME]; 00113 }; 00114 00115 struct folder 00116 { 00117 struct list entry; 00118 struct list files_list; 00119 struct list blocks_list; 00120 struct temp_file data; 00121 cab_ULONG data_start; 00122 cab_UWORD data_count; 00123 TCOMP compression; 00124 }; 00125 00126 struct file 00127 { 00128 struct list entry; 00129 cab_ULONG size; /* uncompressed size */ 00130 cab_ULONG offset; /* offset in folder */ 00131 cab_UWORD folder; /* index of folder */ 00132 cab_UWORD date; 00133 cab_UWORD time; 00134 cab_UWORD attribs; 00135 char name[1]; 00136 }; 00137 00138 struct data_block 00139 { 00140 struct list entry; 00141 cab_UWORD compressed; 00142 cab_UWORD uncompressed; 00143 }; 00144 00145 typedef struct FCI_Int 00146 { 00147 unsigned int magic; 00148 PERF perf; 00149 PFNFCIFILEPLACED fileplaced; 00150 PFNFCIALLOC alloc; 00151 PFNFCIFREE free; 00152 PFNFCIOPEN open; 00153 PFNFCIREAD read; 00154 PFNFCIWRITE write; 00155 PFNFCICLOSE close; 00156 PFNFCISEEK seek; 00157 PFNFCIDELETE delete; 00158 PFNFCIGETTEMPFILE gettemp; 00159 CCAB ccab; 00160 PCCAB pccab; 00161 BOOL fPrevCab; 00162 BOOL fNextCab; 00163 BOOL fSplitFolder; 00164 cab_ULONG statusFolderCopied; 00165 cab_ULONG statusFolderTotal; 00166 BOOL fGetNextCabInVain; 00167 void *pv; 00168 char szPrevCab[CB_MAX_CABINET_NAME]; /* previous cabinet name */ 00169 char szPrevDisk[CB_MAX_DISK_NAME]; /* disk name of previous cabinet */ 00170 unsigned char data_in[CAB_BLOCKMAX]; /* uncompressed data blocks */ 00171 unsigned char data_out[2 * CAB_BLOCKMAX]; /* compressed data blocks */ 00172 cab_UWORD cdata_in; 00173 ULONG cCompressedBytesInFolder; 00174 cab_UWORD cFolders; 00175 cab_UWORD cFiles; 00176 cab_ULONG cDataBlocks; 00177 cab_ULONG cbFileRemainer; /* uncompressed, yet to be written data */ 00178 /* of spanned file of a spanning folder of a spanning cabinet */ 00179 struct temp_file data; 00180 BOOL fNewPrevious; 00181 cab_ULONG estimatedCabinetSize; 00182 struct list folders_list; 00183 struct list files_list; 00184 struct list blocks_list; 00185 cab_ULONG folders_size; 00186 cab_ULONG files_size; /* size of files not yet assigned to a folder */ 00187 cab_ULONG placed_files_size; /* size of files already placed into a folder */ 00188 cab_ULONG pending_data_size; /* size of data not yet assigned to a folder */ 00189 cab_ULONG folders_data_size; /* total size of data contained in the current folders */ 00190 TCOMP compression; 00191 cab_UWORD (*compress)(struct FCI_Int *); 00192 } FCI_Int; 00193 00194 #define FCI_INT_MAGIC 0xfcfcfc05 00195 00196 static void set_error( FCI_Int *fci, int oper, int err ) 00197 { 00198 fci->perf->erfOper = oper; 00199 fci->perf->erfType = err; 00200 fci->perf->fError = TRUE; 00201 if (err) SetLastError( err ); 00202 } 00203 00204 static FCI_Int *get_fci_ptr( HFCI hfci ) 00205 { 00206 FCI_Int *fci= (FCI_Int *)hfci; 00207 00208 if (!fci || fci->magic != FCI_INT_MAGIC) 00209 { 00210 SetLastError( ERROR_INVALID_HANDLE ); 00211 return NULL; 00212 } 00213 return fci; 00214 } 00215 00216 /* compute the cabinet header size */ 00217 static cab_ULONG get_header_size( FCI_Int *fci ) 00218 { 00219 cab_ULONG ret = sizeof(CFHEADER) + fci->ccab.cbReserveCFHeader; 00220 00221 if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData) 00222 ret += 4; 00223 00224 if (fci->fPrevCab) 00225 ret += strlen( fci->szPrevCab ) + 1 + strlen( fci->szPrevDisk ) + 1; 00226 00227 if (fci->fNextCab) 00228 ret += strlen( fci->pccab->szCab ) + 1 + strlen( fci->pccab->szDisk ) + 1; 00229 00230 return ret; 00231 } 00232 00233 static BOOL create_temp_file( FCI_Int *fci, struct temp_file *file ) 00234 { 00235 int err; 00236 00237 if (!fci->gettemp( file->name, CB_MAX_FILENAME, fci->pv )) 00238 { 00239 set_error( fci, FCIERR_TEMP_FILE, ERROR_FUNCTION_FAILED ); 00240 return FALSE; 00241 } 00242 if ((file->handle = fci->open( file->name, _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY, 00243 _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1) 00244 { 00245 set_error( fci, FCIERR_TEMP_FILE, err ); 00246 return FALSE; 00247 } 00248 return TRUE; 00249 } 00250 00251 static BOOL close_temp_file( FCI_Int *fci, struct temp_file *file ) 00252 { 00253 int err; 00254 00255 if (file->handle == -1) return TRUE; 00256 if (fci->close( file->handle, &err, fci->pv ) == -1) 00257 { 00258 set_error( fci, FCIERR_TEMP_FILE, err ); 00259 return FALSE; 00260 } 00261 file->handle = -1; 00262 if (fci->delete( file->name, &err, fci->pv ) == -1) 00263 { 00264 set_error( fci, FCIERR_TEMP_FILE, err ); 00265 return FALSE; 00266 } 00267 return TRUE; 00268 } 00269 00270 static struct file *add_file( FCI_Int *fci, const char *filename ) 00271 { 00272 unsigned int size = FIELD_OFFSET( struct file, name[strlen(filename) + 1] ); 00273 struct file *file = fci->alloc( size ); 00274 00275 if (!file) 00276 { 00277 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY ); 00278 return NULL; 00279 } 00280 file->size = 0; 00281 file->offset = fci->cDataBlocks * CAB_BLOCKMAX + fci->cdata_in; 00282 file->folder = fci->cFolders; 00283 file->date = 0; 00284 file->time = 0; 00285 file->attribs = 0; 00286 strcpy( file->name, filename ); 00287 list_add_tail( &fci->files_list, &file->entry ); 00288 fci->files_size += sizeof(CFFILE) + strlen(filename) + 1; 00289 return file; 00290 } 00291 00292 static struct file *copy_file( FCI_Int *fci, const struct file *orig ) 00293 { 00294 unsigned int size = FIELD_OFFSET( struct file, name[strlen(orig->name) + 1] ); 00295 struct file *file = fci->alloc( size ); 00296 00297 if (!file) 00298 { 00299 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY ); 00300 return NULL; 00301 } 00302 memcpy( file, orig, size ); 00303 return file; 00304 } 00305 00306 static void free_file( FCI_Int *fci, struct file *file ) 00307 { 00308 list_remove( &file->entry ); 00309 fci->free( file ); 00310 } 00311 00312 /* create a new data block for the data in fci->data_in */ 00313 static BOOL add_data_block( FCI_Int *fci, PFNFCISTATUS status_callback ) 00314 { 00315 int err; 00316 struct data_block *block; 00317 00318 if (!fci->cdata_in) return TRUE; 00319 00320 if (fci->data.handle == -1 && !create_temp_file( fci, &fci->data )) return FALSE; 00321 00322 if (!(block = fci->alloc( sizeof(*block) ))) 00323 { 00324 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY ); 00325 return FALSE; 00326 } 00327 block->uncompressed = fci->cdata_in; 00328 block->compressed = fci->compress( fci ); 00329 00330 if (fci->write( fci->data.handle, fci->data_out, 00331 block->compressed, &err, fci->pv ) != block->compressed) 00332 { 00333 set_error( fci, FCIERR_TEMP_FILE, err ); 00334 fci->free( block ); 00335 return FALSE; 00336 } 00337 00338 fci->cdata_in = 0; 00339 fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed; 00340 fci->cCompressedBytesInFolder += block->compressed; 00341 fci->cDataBlocks++; 00342 list_add_tail( &fci->blocks_list, &block->entry ); 00343 00344 if (status_callback( statusFile, block->compressed, block->uncompressed, fci->pv ) == -1) 00345 { 00346 set_error( fci, FCIERR_USER_ABORT, 0 ); 00347 return FALSE; 00348 } 00349 return TRUE; 00350 } 00351 00352 /* add compressed blocks for all the data that can be read from the file */ 00353 static BOOL add_file_data( FCI_Int *fci, char *sourcefile, char *filename, BOOL execute, 00354 PFNFCIGETOPENINFO get_open_info, PFNFCISTATUS status_callback ) 00355 { 00356 int err, len; 00357 INT_PTR handle; 00358 struct file *file; 00359 00360 if (!(file = add_file( fci, filename ))) return FALSE; 00361 00362 handle = get_open_info( sourcefile, &file->date, &file->time, &file->attribs, &err, fci->pv ); 00363 if (handle == -1) 00364 { 00365 free_file( fci, file ); 00366 set_error( fci, FCIERR_OPEN_SRC, err ); 00367 return FALSE; 00368 } 00369 if (execute) file->attribs |= _A_EXEC; 00370 00371 for (;;) 00372 { 00373 len = fci->read( handle, fci->data_in + fci->cdata_in, 00374 CAB_BLOCKMAX - fci->cdata_in, &err, fci->pv ); 00375 if (!len) break; 00376 00377 if (len == -1) 00378 { 00379 set_error( fci, FCIERR_READ_SRC, err ); 00380 return FALSE; 00381 } 00382 file->size += len; 00383 fci->cdata_in += len; 00384 if (fci->cdata_in == CAB_BLOCKMAX && !add_data_block( fci, status_callback )) return FALSE; 00385 } 00386 fci->close( handle, &err, fci->pv ); 00387 return TRUE; 00388 } 00389 00390 static void free_data_block( FCI_Int *fci, struct data_block *block ) 00391 { 00392 list_remove( &block->entry ); 00393 fci->free( block ); 00394 } 00395 00396 static struct folder *add_folder( FCI_Int *fci ) 00397 { 00398 struct folder *folder = fci->alloc( sizeof(*folder) ); 00399 00400 if (!folder) 00401 { 00402 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY ); 00403 return NULL; 00404 } 00405 folder->data.handle = -1; 00406 folder->data_start = fci->folders_data_size; 00407 folder->data_count = 0; 00408 folder->compression = fci->compression; 00409 list_init( &folder->files_list ); 00410 list_init( &folder->blocks_list ); 00411 list_add_tail( &fci->folders_list, &folder->entry ); 00412 fci->folders_size += sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder; 00413 fci->cFolders++; 00414 return folder; 00415 } 00416 00417 static void free_folder( FCI_Int *fci, struct folder *folder ) 00418 { 00419 struct file *file, *file_next; 00420 struct data_block *block, *block_next; 00421 00422 LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &folder->files_list, struct file, entry ) 00423 free_file( fci, file ); 00424 LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &folder->blocks_list, struct data_block, entry ) 00425 free_data_block( fci, block ); 00426 close_temp_file( fci, &folder->data ); 00427 list_remove( &folder->entry ); 00428 fci->free( folder ); 00429 } 00430 00431 /* reset state for the next cabinet file once the current one has been flushed */ 00432 static void reset_cabinet( FCI_Int *fci ) 00433 { 00434 struct folder *folder, *folder_next; 00435 00436 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &fci->folders_list, struct folder, entry ) 00437 free_folder( fci, folder ); 00438 00439 fci->cFolders = 0; 00440 fci->cFiles = 0; 00441 fci->folders_size = 0; 00442 fci->placed_files_size = 0; 00443 fci->folders_data_size = 0; 00444 } 00445 00446 static cab_ULONG fci_get_checksum( const void *pv, UINT cb, cab_ULONG seed ) 00447 { 00448 cab_ULONG csum; 00449 cab_ULONG ul; 00450 int cUlong; 00451 const BYTE *pb; 00452 00453 csum = seed; 00454 cUlong = cb / 4; 00455 pb = pv; 00456 00457 while (cUlong-- > 0) { 00458 ul = *pb++; 00459 ul |= (((cab_ULONG)(*pb++)) << 8); 00460 ul |= (((cab_ULONG)(*pb++)) << 16); 00461 ul |= (((cab_ULONG)(*pb++)) << 24); 00462 csum ^= ul; 00463 } 00464 00465 ul = 0; 00466 switch (cb % 4) { 00467 case 3: 00468 ul |= (((ULONG)(*pb++)) << 16); 00469 /* fall through */ 00470 case 2: 00471 ul |= (((ULONG)(*pb++)) << 8); 00472 /* fall through */ 00473 case 1: 00474 ul |= *pb; 00475 /* fall through */ 00476 default: 00477 break; 00478 } 00479 csum ^= ul; 00480 00481 return csum; 00482 } 00483 00484 /* copy all remaining data block to a new temp file */ 00485 static BOOL copy_data_blocks( FCI_Int *fci, INT_PTR handle, cab_ULONG start_pos, 00486 struct temp_file *temp, PFNFCISTATUS status_callback ) 00487 { 00488 struct data_block *block; 00489 int err; 00490 00491 if (fci->seek( handle, start_pos, SEEK_SET, &err, fci->pv ) != start_pos) 00492 { 00493 set_error( fci, FCIERR_TEMP_FILE, err ); 00494 return FALSE; 00495 } 00496 if (!create_temp_file( fci, temp )) return FALSE; 00497 00498 LIST_FOR_EACH_ENTRY( block, &fci->blocks_list, struct data_block, entry ) 00499 { 00500 if (fci->read( handle, fci->data_out, block->compressed, 00501 &err, fci->pv ) != block->compressed) 00502 { 00503 close_temp_file( fci, temp ); 00504 set_error( fci, FCIERR_TEMP_FILE, err ); 00505 return FALSE; 00506 } 00507 if (fci->write( temp->handle, fci->data_out, block->compressed, 00508 &err, fci->pv ) != block->compressed) 00509 { 00510 close_temp_file( fci, temp ); 00511 set_error( fci, FCIERR_TEMP_FILE, err ); 00512 return FALSE; 00513 } 00514 fci->pending_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + block->compressed; 00515 fci->statusFolderCopied += block->compressed; 00516 00517 if (status_callback( statusFolder, fci->statusFolderCopied, 00518 fci->statusFolderTotal, fci->pv) == -1) 00519 { 00520 close_temp_file( fci, temp ); 00521 set_error( fci, FCIERR_USER_ABORT, 0 ); 00522 return FALSE; 00523 } 00524 } 00525 return TRUE; 00526 } 00527 00528 /* write all folders to disk and remove them from the list */ 00529 static BOOL write_folders( FCI_Int *fci, INT_PTR handle, cab_ULONG header_size, PFNFCISTATUS status_callback ) 00530 { 00531 struct folder *folder; 00532 int err; 00533 CFFOLDER *cffolder = (CFFOLDER *)fci->data_out; 00534 cab_ULONG folder_size = sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder; 00535 00536 memset( cffolder, 0, folder_size ); 00537 00538 /* write the folders */ 00539 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry ) 00540 { 00541 cffolder->coffCabStart = fci_endian_ulong( folder->data_start + header_size ); 00542 cffolder->cCFData = fci_endian_uword( folder->data_count ); 00543 cffolder->typeCompress = fci_endian_uword( folder->compression ); 00544 if (fci->write( handle, cffolder, folder_size, &err, fci->pv ) != folder_size) 00545 { 00546 set_error( fci, FCIERR_CAB_FILE, err ); 00547 return FALSE; 00548 } 00549 } 00550 return TRUE; 00551 } 00552 00553 /* write all the files to the cabinet file */ 00554 static BOOL write_files( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback ) 00555 { 00556 cab_ULONG file_size; 00557 struct folder *folder; 00558 struct file *file; 00559 int err; 00560 CFFILE *cffile = (CFFILE *)fci->data_out; 00561 00562 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry ) 00563 { 00564 LIST_FOR_EACH_ENTRY( file, &folder->files_list, struct file, entry ) 00565 { 00566 cffile->cbFile = fci_endian_ulong( file->size ); 00567 cffile->uoffFolderStart = fci_endian_ulong( file->offset ); 00568 cffile->iFolder = fci_endian_uword( file->folder ); 00569 cffile->date = fci_endian_uword( file->date ); 00570 cffile->time = fci_endian_uword( file->time ); 00571 cffile->attribs = fci_endian_uword( file->attribs ); 00572 lstrcpynA( (char *)(cffile + 1), file->name, CB_MAX_FILENAME ); 00573 file_size = sizeof(CFFILE) + strlen( (char *)(cffile + 1) ) + 1; 00574 if (fci->write( handle, cffile, file_size, &err, fci->pv ) != file_size) 00575 { 00576 set_error( fci, FCIERR_CAB_FILE, err ); 00577 return FALSE; 00578 } 00579 if (!fci->fSplitFolder) 00580 { 00581 fci->statusFolderCopied = 0; 00582 /* TODO TEST THIS further */ 00583 fci->statusFolderTotal = fci->folders_data_size + fci->placed_files_size; 00584 } 00585 fci->statusFolderCopied += file_size; 00586 /* report status about copied size of folder */ 00587 if (status_callback( statusFolder, fci->statusFolderCopied, 00588 fci->statusFolderTotal, fci->pv ) == -1) 00589 { 00590 set_error( fci, FCIERR_USER_ABORT, 0 ); 00591 return FALSE; 00592 } 00593 } 00594 } 00595 return TRUE; 00596 } 00597 00598 /* write all data blocks to the cabinet file */ 00599 static BOOL write_data_blocks( FCI_Int *fci, INT_PTR handle, PFNFCISTATUS status_callback ) 00600 { 00601 struct folder *folder; 00602 struct data_block *block; 00603 int err, len; 00604 CFDATA *cfdata; 00605 void *data; 00606 cab_UWORD header_size; 00607 00608 header_size = sizeof(CFDATA) + fci->ccab.cbReserveCFData; 00609 cfdata = (CFDATA *)fci->data_out; 00610 memset( cfdata, 0, header_size ); 00611 data = (char *)cfdata + header_size; 00612 00613 LIST_FOR_EACH_ENTRY( folder, &fci->folders_list, struct folder, entry ) 00614 { 00615 if (fci->seek( folder->data.handle, 0, SEEK_SET, &err, fci->pv ) != 0) 00616 { 00617 set_error( fci, FCIERR_CAB_FILE, err ); 00618 return FALSE; 00619 } 00620 LIST_FOR_EACH_ENTRY( block, &folder->blocks_list, struct data_block, entry ) 00621 { 00622 len = fci->read( folder->data.handle, data, block->compressed, &err, fci->pv ); 00623 if (len != block->compressed) return FALSE; 00624 00625 cfdata->cbData = fci_endian_uword( block->compressed ); 00626 cfdata->cbUncomp = fci_endian_uword( block->uncompressed ); 00627 cfdata->csum = fci_endian_ulong( fci_get_checksum( &cfdata->cbData, 00628 header_size - FIELD_OFFSET(CFDATA, cbData), 00629 fci_get_checksum( data, len, 0 ))); 00630 00631 fci->statusFolderCopied += len; 00632 len += header_size; 00633 if (fci->write( handle, fci->data_out, len, &err, fci->pv ) != len) 00634 { 00635 set_error( fci, FCIERR_CAB_FILE, err ); 00636 return FALSE; 00637 } 00638 if (status_callback( statusFolder, fci->statusFolderCopied, fci->statusFolderTotal, fci->pv) == -1) 00639 { 00640 set_error( fci, FCIERR_USER_ABORT, 0 ); 00641 return FALSE; 00642 } 00643 } 00644 } 00645 return TRUE; 00646 } 00647 00648 /* write the cabinet file to disk */ 00649 static BOOL write_cabinet( FCI_Int *fci, PFNFCISTATUS status_callback ) 00650 { 00651 char filename[CB_MAX_CAB_PATH + CB_MAX_CABINET_NAME]; 00652 int err; 00653 char *ptr; 00654 INT_PTR handle; 00655 CFHEADER *cfheader = (CFHEADER *)fci->data_out; 00656 cab_UWORD flags = 0; 00657 cab_ULONG header_size = get_header_size( fci ); 00658 cab_ULONG total_size = header_size + fci->folders_size + 00659 fci->placed_files_size + fci->folders_data_size; 00660 00661 assert( header_size <= sizeof(fci->data_out) ); 00662 memset( cfheader, 0, header_size ); 00663 00664 if (fci->fPrevCab) flags |= cfheadPREV_CABINET; 00665 if (fci->fNextCab) flags |= cfheadNEXT_CABINET; 00666 if (fci->ccab.cbReserveCFHeader || fci->ccab.cbReserveCFFolder || fci->ccab.cbReserveCFData) 00667 flags |= cfheadRESERVE_PRESENT; 00668 00669 memcpy( cfheader->signature, "!CAB", 4 ); 00670 cfheader->cbCabinet = fci_endian_ulong( total_size ); 00671 cfheader->coffFiles = fci_endian_ulong( header_size + fci->folders_size ); 00672 cfheader->versionMinor = 3; 00673 cfheader->versionMajor = 1; 00674 cfheader->cFolders = fci_endian_uword( fci->cFolders ); 00675 cfheader->cFiles = fci_endian_uword( fci->cFiles ); 00676 cfheader->flags = fci_endian_uword( flags ); 00677 cfheader->setID = fci_endian_uword( fci->ccab.setID ); 00678 cfheader->iCabinet = fci_endian_uword( fci->ccab.iCab ); 00679 ptr = (char *)(cfheader + 1); 00680 00681 if (flags & cfheadRESERVE_PRESENT) 00682 { 00683 struct 00684 { 00685 cab_UWORD cbCFHeader; 00686 cab_UBYTE cbCFFolder; 00687 cab_UBYTE cbCFData; 00688 } *reserve = (void *)ptr; 00689 00690 reserve->cbCFHeader = fci_endian_uword( fci->ccab.cbReserveCFHeader ); 00691 reserve->cbCFFolder = fci->ccab.cbReserveCFFolder; 00692 reserve->cbCFData = fci->ccab.cbReserveCFData; 00693 ptr = (char *)(reserve + 1); 00694 } 00695 ptr += fci->ccab.cbReserveCFHeader; 00696 00697 if (flags & cfheadPREV_CABINET) 00698 { 00699 strcpy( ptr, fci->szPrevCab ); 00700 ptr += strlen( ptr ) + 1; 00701 strcpy( ptr, fci->szPrevDisk ); 00702 ptr += strlen( ptr ) + 1; 00703 } 00704 00705 if (flags & cfheadNEXT_CABINET) 00706 { 00707 strcpy( ptr, fci->pccab->szCab ); 00708 ptr += strlen( ptr ) + 1; 00709 strcpy( ptr, fci->pccab->szDisk ); 00710 ptr += strlen( ptr ) + 1; 00711 } 00712 00713 assert( ptr - (char *)cfheader == header_size ); 00714 00715 strcpy( filename, fci->ccab.szCabPath ); 00716 strcat( filename, fci->ccab.szCab ); 00717 00718 if ((handle = fci->open( filename, _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY, 00719 _S_IREAD | _S_IWRITE, &err, fci->pv )) == -1) 00720 { 00721 set_error( fci, FCIERR_CAB_FILE, err ); 00722 return FALSE; 00723 } 00724 00725 if (fci->write( handle, cfheader, header_size, &err, fci->pv ) != header_size) 00726 { 00727 set_error( fci, FCIERR_CAB_FILE, err ); 00728 goto failed; 00729 } 00730 00731 /* add size of header size of all CFFOLDERs and size of all CFFILEs */ 00732 header_size += fci->placed_files_size + fci->folders_size; 00733 if (!write_folders( fci, handle, header_size, status_callback )) goto failed; 00734 if (!write_files( fci, handle, status_callback )) goto failed; 00735 if (!write_data_blocks( fci, handle, status_callback )) goto failed; 00736 00737 /* update the signature */ 00738 if (fci->seek( handle, 0, SEEK_SET, &err, fci->pv ) != 0 ) 00739 { 00740 set_error( fci, FCIERR_CAB_FILE, err ); 00741 goto failed; 00742 } 00743 memcpy( cfheader->signature, "MSCF", 4 ); 00744 if (fci->write( handle, cfheader->signature, 4, &err, fci->pv ) != 4) 00745 { 00746 set_error( fci, FCIERR_CAB_FILE, err ); 00747 goto failed; 00748 } 00749 fci->close( handle, &err, fci->pv ); 00750 00751 reset_cabinet( fci ); 00752 status_callback( statusCabinet, fci->estimatedCabinetSize, total_size, fci->pv ); 00753 return TRUE; 00754 00755 failed: 00756 fci->close( handle, &err, fci->pv ); 00757 fci->delete( filename, &err, fci->pv ); 00758 return FALSE; 00759 } 00760 00761 /* add all pending data blocks folder */ 00762 static BOOL add_data_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG *payload, 00763 PFNFCISTATUS status_callback ) 00764 { 00765 struct data_block *block, *new, *next; 00766 BOOL split_block = FALSE; 00767 cab_ULONG current_size, start_pos = 0; 00768 00769 *payload = 0; 00770 current_size = get_header_size( fci ) + fci->folders_size + 00771 fci->files_size + fci->placed_files_size + fci->folders_data_size; 00772 00773 /* move the temp file into the folder structure */ 00774 folder->data = fci->data; 00775 fci->data.handle = -1; 00776 fci->pending_data_size = 0; 00777 00778 LIST_FOR_EACH_ENTRY_SAFE( block, next, &fci->blocks_list, struct data_block, entry ) 00779 { 00780 /* No more CFDATA fits into the cabinet under construction */ 00781 /* So don't try to store more data into it */ 00782 if (fci->fNextCab && (fci->ccab.cb <= sizeof(CFDATA) + fci->ccab.cbReserveCFData + 00783 current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder)) 00784 break; 00785 00786 if (!(new = fci->alloc( sizeof(*new) ))) 00787 { 00788 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY ); 00789 return FALSE; 00790 } 00791 /* Is cabinet with new CFDATA too large? Then data block has to be split */ 00792 if( fci->fNextCab && 00793 (fci->ccab.cb < sizeof(CFDATA) + fci->ccab.cbReserveCFData + 00794 block->compressed + current_size + sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder)) 00795 { 00796 /* Modify the size of the compressed data to store only a part of the */ 00797 /* data block into the current cabinet. This is done to prevent */ 00798 /* that the maximum cabinet size will be exceeded. The remainder */ 00799 /* will be stored into the next following cabinet. */ 00800 00801 new->compressed = fci->ccab.cb - (sizeof(CFDATA) + fci->ccab.cbReserveCFData + current_size + 00802 sizeof(CFFOLDER) + fci->ccab.cbReserveCFFolder ); 00803 new->uncompressed = 0; /* on split blocks of data this is zero */ 00804 block->compressed -= new->compressed; 00805 split_block = TRUE; 00806 } 00807 else 00808 { 00809 new->compressed = block->compressed; 00810 new->uncompressed = block->uncompressed; 00811 } 00812 00813 start_pos += new->compressed; 00814 current_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed; 00815 fci->folders_data_size += sizeof(CFDATA) + fci->ccab.cbReserveCFData + new->compressed; 00816 fci->statusFolderCopied += new->compressed; 00817 (*payload) += new->uncompressed; 00818 00819 list_add_tail( &folder->blocks_list, &new->entry ); 00820 folder->data_count++; 00821 00822 /* report status with pfnfcis about copied size of folder */ 00823 if (status_callback( statusFolder, fci->statusFolderCopied, 00824 fci->statusFolderTotal, fci->pv ) == -1) 00825 { 00826 set_error( fci, FCIERR_USER_ABORT, 0 ); 00827 return FALSE; 00828 } 00829 if (split_block) break; 00830 free_data_block( fci, block ); 00831 fci->cDataBlocks--; 00832 } 00833 00834 if (list_empty( &fci->blocks_list )) return TRUE; 00835 return copy_data_blocks( fci, folder->data.handle, start_pos, &fci->data, status_callback ); 00836 } 00837 00838 /* add all pending files to folder */ 00839 static BOOL add_files_to_folder( FCI_Int *fci, struct folder *folder, cab_ULONG payload ) 00840 { 00841 cab_ULONG sizeOfFiles = 0, sizeOfFilesPrev; 00842 cab_ULONG cbFileRemainer = 0; 00843 struct file *file, *next; 00844 00845 LIST_FOR_EACH_ENTRY_SAFE( file, next, &fci->files_list, struct file, entry ) 00846 { 00847 cab_ULONG size = sizeof(CFFILE) + strlen(file->name) + 1; 00848 00849 /* fnfilfnfildest: placed file on cabinet */ 00850 fci->fileplaced( &fci->ccab, file->name, file->size, 00851 (file->folder == cffileCONTINUED_FROM_PREV), fci->pv ); 00852 00853 sizeOfFilesPrev = sizeOfFiles; 00854 /* set complete size of all processed files */ 00855 if (file->folder == cffileCONTINUED_FROM_PREV && fci->cbFileRemainer != 0) 00856 { 00857 sizeOfFiles += fci->cbFileRemainer; 00858 fci->cbFileRemainer = 0; 00859 } 00860 else sizeOfFiles += file->size; 00861 00862 /* check if spanned file fits into this cabinet folder */ 00863 if (sizeOfFiles > payload) 00864 { 00865 if (file->folder == cffileCONTINUED_FROM_PREV) 00866 file->folder = cffileCONTINUED_PREV_AND_NEXT; 00867 else 00868 file->folder = cffileCONTINUED_TO_NEXT; 00869 } 00870 00871 list_remove( &file->entry ); 00872 list_add_tail( &folder->files_list, &file->entry ); 00873 fci->placed_files_size += size; 00874 fci->cFiles++; 00875 00876 /* This is only true for files which will be written into the */ 00877 /* next cabinet of the spanning folder */ 00878 if (sizeOfFiles > payload) 00879 { 00880 /* add a copy back onto the list */ 00881 if (!(file = copy_file( fci, file ))) return FALSE; 00882 list_add_before( &next->entry, &file->entry ); 00883 00884 /* Files which data will be partially written into the current cabinet */ 00885 if (file->folder == cffileCONTINUED_PREV_AND_NEXT || file->folder == cffileCONTINUED_TO_NEXT) 00886 { 00887 if (sizeOfFilesPrev <= payload) 00888 { 00889 /* The size of the uncompressed, data of a spanning file in a */ 00890 /* spanning data */ 00891 cbFileRemainer = sizeOfFiles - payload; 00892 } 00893 file->folder = cffileCONTINUED_FROM_PREV; 00894 } 00895 else file->folder = 0; 00896 } 00897 else 00898 { 00899 fci->files_size -= size; 00900 } 00901 } 00902 fci->cbFileRemainer = cbFileRemainer; 00903 return TRUE; 00904 } 00905 00906 static cab_UWORD compress_NONE( FCI_Int *fci ) 00907 { 00908 memcpy( fci->data_out, fci->data_in, fci->cdata_in ); 00909 return fci->cdata_in; 00910 } 00911 00912 #ifdef HAVE_ZLIB 00913 00914 static void *zalloc( void *opaque, unsigned int items, unsigned int size ) 00915 { 00916 FCI_Int *fci = opaque; 00917 return fci->alloc( items * size ); 00918 } 00919 00920 static void zfree( void *opaque, void *ptr ) 00921 { 00922 FCI_Int *fci = opaque; 00923 fci->free( ptr ); 00924 } 00925 00926 static cab_UWORD compress_MSZIP( FCI_Int *fci ) 00927 { 00928 z_stream stream; 00929 00930 stream.zalloc = zalloc; 00931 stream.zfree = zfree; 00932 stream.opaque = fci; 00933 if (deflateInit2( &stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY ) != Z_OK) 00934 { 00935 set_error( fci, FCIERR_ALLOC_FAIL, ERROR_NOT_ENOUGH_MEMORY ); 00936 return 0; 00937 } 00938 stream.next_in = fci->data_in; 00939 stream.avail_in = fci->cdata_in; 00940 stream.next_out = fci->data_out + 2; 00941 stream.avail_out = sizeof(fci->data_out) - 2; 00942 /* insert the signature */ 00943 fci->data_out[0] = 'C'; 00944 fci->data_out[1] = 'K'; 00945 deflate( &stream, Z_FINISH ); 00946 deflateEnd( &stream ); 00947 return stream.total_out + 2; 00948 } 00949 00950 #endif /* HAVE_ZLIB */ 00951 00952 00953 /*********************************************************************** 00954 * FCICreate (CABINET.10) 00955 * 00956 * FCICreate is provided with several callbacks and 00957 * returns a handle which can be used to create cabinet files. 00958 * 00959 * PARAMS 00960 * perf [IO] A pointer to an ERF structure. When FCICreate 00961 * returns an error condition, error information may 00962 * be found here as well as from GetLastError. 00963 * pfnfiledest [I] A pointer to a function which is called when a file 00964 * is placed. Only useful for subsequent cabinet files. 00965 * pfnalloc [I] A pointer to a function which allocates ram. Uses 00966 * the same interface as malloc. 00967 * pfnfree [I] A pointer to a function which frees ram. Uses the 00968 * same interface as free. 00969 * pfnopen [I] A pointer to a function which opens a file. Uses 00970 * the same interface as _open. 00971 * pfnread [I] A pointer to a function which reads from a file into 00972 * a caller-provided buffer. Uses the same interface 00973 * as _read. 00974 * pfnwrite [I] A pointer to a function which writes to a file from 00975 * a caller-provided buffer. Uses the same interface 00976 * as _write. 00977 * pfnclose [I] A pointer to a function which closes a file handle. 00978 * Uses the same interface as _close. 00979 * pfnseek [I] A pointer to a function which seeks in a file. 00980 * Uses the same interface as _lseek. 00981 * pfndelete [I] A pointer to a function which deletes a file. 00982 * pfnfcigtf [I] A pointer to a function which gets the name of a 00983 * temporary file. 00984 * pccab [I] A pointer to an initialized CCAB structure. 00985 * pv [I] A pointer to an application-defined notification 00986 * function which will be passed to other FCI functions 00987 * as a parameter. 00988 * 00989 * RETURNS 00990 * On success, returns an FCI handle of type HFCI. 00991 * On failure, the NULL file handle is returned. Error 00992 * info can be retrieved from perf. 00993 * 00994 * INCLUDES 00995 * fci.h 00996 * 00997 */ 00998 HFCI __cdecl FCICreate( 00999 PERF perf, 01000 PFNFCIFILEPLACED pfnfiledest, 01001 PFNFCIALLOC pfnalloc, 01002 PFNFCIFREE pfnfree, 01003 PFNFCIOPEN pfnopen, 01004 PFNFCIREAD pfnread, 01005 PFNFCIWRITE pfnwrite, 01006 PFNFCICLOSE pfnclose, 01007 PFNFCISEEK pfnseek, 01008 PFNFCIDELETE pfndelete, 01009 PFNFCIGETTEMPFILE pfnfcigtf, 01010 PCCAB pccab, 01011 void *pv) 01012 { 01013 FCI_Int *p_fci_internal; 01014 01015 if (!perf) { 01016 SetLastError(ERROR_BAD_ARGUMENTS); 01017 return NULL; 01018 } 01019 if ((!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) || 01020 (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) || 01021 (!pfnfcigtf) || (!pccab)) { 01022 perf->erfOper = FCIERR_NONE; 01023 perf->erfType = ERROR_BAD_ARGUMENTS; 01024 perf->fError = TRUE; 01025 01026 SetLastError(ERROR_BAD_ARGUMENTS); 01027 return NULL; 01028 } 01029 01030 if (!((p_fci_internal = pfnalloc(sizeof(FCI_Int))))) { 01031 perf->erfOper = FCIERR_ALLOC_FAIL; 01032 perf->erfType = ERROR_NOT_ENOUGH_MEMORY; 01033 perf->fError = TRUE; 01034 01035 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 01036 return NULL; 01037 } 01038 01039 p_fci_internal->magic = FCI_INT_MAGIC; 01040 p_fci_internal->perf = perf; 01041 p_fci_internal->fileplaced = pfnfiledest; 01042 p_fci_internal->alloc = pfnalloc; 01043 p_fci_internal->free = pfnfree; 01044 p_fci_internal->open = pfnopen; 01045 p_fci_internal->read = pfnread; 01046 p_fci_internal->write = pfnwrite; 01047 p_fci_internal->close = pfnclose; 01048 p_fci_internal->seek = pfnseek; 01049 p_fci_internal->delete = pfndelete; 01050 p_fci_internal->gettemp = pfnfcigtf; 01051 p_fci_internal->ccab = *pccab; 01052 p_fci_internal->pccab = pccab; 01053 p_fci_internal->fPrevCab = FALSE; 01054 p_fci_internal->fNextCab = FALSE; 01055 p_fci_internal->fSplitFolder = FALSE; 01056 p_fci_internal->fGetNextCabInVain = FALSE; 01057 p_fci_internal->pv = pv; 01058 p_fci_internal->cdata_in = 0; 01059 p_fci_internal->cCompressedBytesInFolder = 0; 01060 p_fci_internal->cFolders = 0; 01061 p_fci_internal->cFiles = 0; 01062 p_fci_internal->cDataBlocks = 0; 01063 p_fci_internal->data.handle = -1; 01064 p_fci_internal->fNewPrevious = FALSE; 01065 p_fci_internal->estimatedCabinetSize = 0; 01066 p_fci_internal->statusFolderTotal = 0; 01067 p_fci_internal->folders_size = 0; 01068 p_fci_internal->files_size = 0; 01069 p_fci_internal->placed_files_size = 0; 01070 p_fci_internal->pending_data_size = 0; 01071 p_fci_internal->folders_data_size = 0; 01072 p_fci_internal->compression = tcompTYPE_NONE; 01073 p_fci_internal->compress = compress_NONE; 01074 01075 list_init( &p_fci_internal->folders_list ); 01076 list_init( &p_fci_internal->files_list ); 01077 list_init( &p_fci_internal->blocks_list ); 01078 01079 memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME); 01080 memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME); 01081 01082 return (HFCI)p_fci_internal; 01083 } 01084 01085 01086 01087 01088 static BOOL fci_flush_folder( FCI_Int *p_fci_internal, 01089 BOOL fGetNextCab, 01090 PFNFCIGETNEXTCABINET pfnfcignc, 01091 PFNFCISTATUS pfnfcis) 01092 { 01093 cab_ULONG payload; 01094 cab_ULONG read_result; 01095 struct folder *folder; 01096 01097 if ((!pfnfcignc) || (!pfnfcis)) { 01098 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS ); 01099 return FALSE; 01100 } 01101 01102 if( p_fci_internal->fGetNextCabInVain && 01103 p_fci_internal->fNextCab ){ 01104 /* internal error */ 01105 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE ); 01106 return FALSE; 01107 } 01108 01109 /* If there was no FCIAddFile or FCIFlushFolder has already been called */ 01110 /* this function will return TRUE */ 01111 if( p_fci_internal->files_size == 0 ) { 01112 if ( p_fci_internal->pending_data_size != 0 ) { 01113 /* error handling */ 01114 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE ); 01115 return FALSE; 01116 } 01117 return TRUE; 01118 } 01119 01120 /* FCIFlushFolder has already been called... */ 01121 if (p_fci_internal->fSplitFolder && p_fci_internal->placed_files_size!=0) { 01122 return TRUE; 01123 } 01124 01125 /* This can be set already, because it makes only a difference */ 01126 /* when the current function exits with return FALSE */ 01127 p_fci_internal->fSplitFolder=FALSE; 01128 01129 /* START of COPY */ 01130 if (!add_data_block( p_fci_internal, pfnfcis )) return FALSE; 01131 01132 /* reset to get the number of data blocks of this folder which are */ 01133 /* actually in this cabinet ( at least partially ) */ 01134 p_fci_internal->cDataBlocks=0; 01135 01136 p_fci_internal->statusFolderTotal = get_header_size( p_fci_internal ) + 01137 sizeof(CFFOLDER) + p_fci_internal->ccab.cbReserveCFFolder + 01138 p_fci_internal->placed_files_size+ 01139 p_fci_internal->folders_data_size + p_fci_internal->files_size+ 01140 p_fci_internal->pending_data_size + p_fci_internal->folders_size; 01141 p_fci_internal->statusFolderCopied = 0; 01142 01143 /* report status with pfnfcis about copied size of folder */ 01144 if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied, 01145 p_fci_internal->statusFolderTotal, /* TODO total folder size */ 01146 p_fci_internal->pv) == -1) { 01147 set_error( p_fci_internal, FCIERR_USER_ABORT, 0 ); 01148 return FALSE; 01149 } 01150 01151 /* USE the variable read_result */ 01152 read_result = get_header_size( p_fci_internal ) + p_fci_internal->folders_data_size + 01153 p_fci_internal->placed_files_size + p_fci_internal->folders_size; 01154 01155 if(p_fci_internal->files_size!=0) { 01156 read_result+= sizeof(CFFOLDER)+p_fci_internal->ccab.cbReserveCFFolder; 01157 } 01158 01159 /* Check if multiple cabinets have to be created. */ 01160 01161 /* Might be too much data for the maximum allowed cabinet size.*/ 01162 /* When any further data will be added later, it might not */ 01163 /* be possible to flush the cabinet, because there might */ 01164 /* not be enough space to store the name of the following */ 01165 /* cabinet and name of the corresponding disk. */ 01166 /* So take care of this and get the name of the next cabinet */ 01167 if( p_fci_internal->fGetNextCabInVain==FALSE && 01168 p_fci_internal->fNextCab==FALSE && 01169 ( 01170 ( 01171 p_fci_internal->ccab.cb < read_result + 01172 p_fci_internal->pending_data_size + 01173 p_fci_internal->files_size + 01174 CB_MAX_CABINET_NAME + /* next cabinet name */ 01175 CB_MAX_DISK_NAME /* next disk name */ 01176 ) || fGetNextCab 01177 ) 01178 ) { 01179 /* increment cabinet index */ 01180 ++(p_fci_internal->pccab->iCab); 01181 /* get name of next cabinet */ 01182 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal; 01183 if (!(*pfnfcignc)(p_fci_internal->pccab, 01184 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */ 01185 p_fci_internal->pv)) { 01186 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED ); 01187 return FALSE; 01188 } 01189 01190 /* Skip a few lines of code. This is caught by the next if. */ 01191 p_fci_internal->fGetNextCabInVain=TRUE; 01192 } 01193 01194 /* too much data for cabinet */ 01195 if( (p_fci_internal->fGetNextCabInVain || 01196 p_fci_internal->fNextCab ) && 01197 ( 01198 ( 01199 p_fci_internal->ccab.cb < read_result + 01200 p_fci_internal->pending_data_size + 01201 p_fci_internal->files_size + 01202 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */ 01203 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */ 01204 ) || fGetNextCab 01205 ) 01206 ) { 01207 p_fci_internal->fGetNextCabInVain=FALSE; 01208 p_fci_internal->fNextCab=TRUE; 01209 01210 /* return FALSE if there is not enough space left*/ 01211 /* this should never happen */ 01212 if (p_fci_internal->ccab.cb <= 01213 p_fci_internal->files_size + 01214 read_result + 01215 strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */ 01216 strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */ 01217 ) { 01218 01219 return FALSE; 01220 } 01221 01222 /* the folder will be split across cabinets */ 01223 p_fci_internal->fSplitFolder=TRUE; 01224 01225 } else { 01226 /* this should never happen */ 01227 if (p_fci_internal->fNextCab) { 01228 /* internal error */ 01229 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE ); 01230 return FALSE; 01231 } 01232 } 01233 01234 if (!(folder = add_folder( p_fci_internal ))) return FALSE; 01235 if (!add_data_to_folder( p_fci_internal, folder, &payload, pfnfcis )) return FALSE; 01236 if (!add_files_to_folder( p_fci_internal, folder, payload )) return FALSE; 01237 01238 /* reset CFFolder specific information */ 01239 p_fci_internal->cDataBlocks=0; 01240 p_fci_internal->cCompressedBytesInFolder=0; 01241 01242 return TRUE; 01243 } 01244 01245 01246 01247 01248 static BOOL fci_flush_cabinet( FCI_Int *p_fci_internal, 01249 BOOL fGetNextCab, 01250 PFNFCIGETNEXTCABINET pfnfcignc, 01251 PFNFCISTATUS pfnfcis) 01252 { 01253 cab_ULONG read_result=0; 01254 BOOL returntrue=FALSE; 01255 01256 /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */ 01257 01258 /* when FCIFlushCabinet was or FCIAddFile hasn't been called */ 01259 if( p_fci_internal->files_size==0 && fGetNextCab ) { 01260 returntrue=TRUE; 01261 } 01262 01263 if (!fci_flush_folder(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)){ 01264 /* TODO set error */ 01265 return FALSE; 01266 } 01267 01268 if(returntrue) return TRUE; 01269 01270 if ( (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE)|| 01271 (p_fci_internal->folders_size==0 && 01272 (p_fci_internal->files_size!=0 || 01273 p_fci_internal->placed_files_size!=0 ) 01274 ) ) 01275 { 01276 /* error */ 01277 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE ); 01278 return FALSE; 01279 } 01280 01281 /* create the cabinet */ 01282 if (!write_cabinet( p_fci_internal, pfnfcis )) return FALSE; 01283 01284 p_fci_internal->fPrevCab=TRUE; 01285 /* The sections szPrevCab and szPrevDisk are not being updated, because */ 01286 /* MS CABINET.DLL always puts the first cabinet name and disk into them */ 01287 01288 if (p_fci_internal->fNextCab) { 01289 p_fci_internal->fNextCab=FALSE; 01290 01291 if (p_fci_internal->files_size==0 && p_fci_internal->pending_data_size!=0) { 01292 /* THIS CAN NEVER HAPPEN */ 01293 /* set error code */ 01294 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE ); 01295 return FALSE; 01296 } 01297 01298 if( p_fci_internal->fNewPrevious ) { 01299 memcpy(p_fci_internal->szPrevCab, p_fci_internal->ccab.szCab, 01300 CB_MAX_CABINET_NAME); 01301 memcpy(p_fci_internal->szPrevDisk, p_fci_internal->ccab.szDisk, 01302 CB_MAX_DISK_NAME); 01303 p_fci_internal->fNewPrevious=FALSE; 01304 } 01305 p_fci_internal->ccab = *p_fci_internal->pccab; 01306 01307 /* REUSE the variable read_result */ 01308 read_result=get_header_size( p_fci_internal ); 01309 if(p_fci_internal->files_size!=0) { 01310 read_result+=p_fci_internal->ccab.cbReserveCFFolder; 01311 } 01312 read_result+= p_fci_internal->pending_data_size + 01313 p_fci_internal->files_size + p_fci_internal->folders_data_size + 01314 p_fci_internal->placed_files_size + p_fci_internal->folders_size + 01315 sizeof(CFFOLDER); /* set size of new CFFolder entry */ 01316 01317 /* too much data for the maximum size of a cabinet */ 01318 if( p_fci_internal->fGetNextCabInVain==FALSE && 01319 p_fci_internal->ccab.cb < read_result ) { 01320 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis); 01321 } 01322 01323 /* Might be too much data for the maximum size of a cabinet.*/ 01324 /* When any further data will be added later, it might not */ 01325 /* be possible to flush the cabinet, because there might */ 01326 /* not be enough space to store the name of the following */ 01327 /* cabinet and name of the corresponding disk. */ 01328 /* So take care of this and get the name of the next cabinet */ 01329 if (p_fci_internal->fGetNextCabInVain==FALSE && ( 01330 p_fci_internal->ccab.cb < read_result + 01331 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME 01332 )) { 01333 /* increment cabinet index */ 01334 ++(p_fci_internal->pccab->iCab); 01335 /* get name of next cabinet */ 01336 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal; 01337 if (!(*pfnfcignc)(p_fci_internal->pccab, 01338 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */ 01339 p_fci_internal->pv)) { 01340 /* error handling */ 01341 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED ); 01342 return FALSE; 01343 } 01344 /* Skip a few lines of code. This is caught by the next if. */ 01345 p_fci_internal->fGetNextCabInVain=TRUE; 01346 } 01347 01348 /* too much data for cabinet */ 01349 if (p_fci_internal->fGetNextCabInVain && ( 01350 p_fci_internal->ccab.cb < read_result + 01351 strlen(p_fci_internal->ccab.szCab)+1+ 01352 strlen(p_fci_internal->ccab.szDisk)+1 01353 )) { 01354 p_fci_internal->fGetNextCabInVain=FALSE; 01355 p_fci_internal->fNextCab=TRUE; 01356 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis); 01357 } 01358 01359 /* if the FolderThreshold has been reached flush the folder automatically */ 01360 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh) 01361 return fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis); 01362 01363 if( p_fci_internal->files_size>0 ) { 01364 if( !fci_flush_folder(p_fci_internal, FALSE, pfnfcignc, pfnfcis) ) return FALSE; 01365 p_fci_internal->fNewPrevious=TRUE; 01366 } 01367 } else { 01368 p_fci_internal->fNewPrevious=FALSE; 01369 if( p_fci_internal->files_size>0 || p_fci_internal->pending_data_size) { 01370 /* THIS MAY NEVER HAPPEN */ 01371 /* set error structures */ 01372 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE ); 01373 return FALSE; 01374 } 01375 } 01376 01377 return TRUE; 01378 } /* end of fci_flush_cabinet */ 01379 01380 01381 01382 01383 01384 /*********************************************************************** 01385 * FCIAddFile (CABINET.11) 01386 * 01387 * FCIAddFile adds a file to the to be created cabinet file 01388 * 01389 * PARAMS 01390 * hfci [I] An HFCI from FCICreate 01391 * pszSourceFile [I] A pointer to a C string which contains the name and 01392 * location of the file which will be added to the cabinet 01393 * pszFileName [I] A pointer to a C string which contains the name under 01394 * which the file will be stored in the cabinet 01395 * fExecute [I] A boolean value which indicates if the file should be 01396 * executed after extraction of self extracting 01397 * executables 01398 * pfnfcignc [I] A pointer to a function which gets information about 01399 * the next cabinet 01400 * pfnfcis [IO] A pointer to a function which will report status 01401 * information about the compression process 01402 * pfnfcioi [I] A pointer to a function which reports file attributes 01403 * and time and date information 01404 * typeCompress [I] Compression type 01405 * 01406 * RETURNS 01407 * On success, returns TRUE 01408 * On failure, returns FALSE 01409 * 01410 * INCLUDES 01411 * fci.h 01412 * 01413 */ 01414 BOOL __cdecl FCIAddFile( 01415 HFCI hfci, 01416 char *pszSourceFile, 01417 char *pszFileName, 01418 BOOL fExecute, 01419 PFNFCIGETNEXTCABINET pfnfcignc, 01420 PFNFCISTATUS pfnfcis, 01421 PFNFCIGETOPENINFO pfnfcigoi, 01422 TCOMP typeCompress) 01423 { 01424 cab_ULONG read_result; 01425 FCI_Int *p_fci_internal = get_fci_ptr( hfci ); 01426 01427 if (!p_fci_internal) return FALSE; 01428 01429 if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) || 01430 (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) { 01431 set_error( p_fci_internal, FCIERR_NONE, ERROR_BAD_ARGUMENTS ); 01432 return FALSE; 01433 } 01434 01435 if (typeCompress != p_fci_internal->compression) 01436 { 01437 if (!FCIFlushFolder( hfci, pfnfcignc, pfnfcis )) return FALSE; 01438 switch (typeCompress) 01439 { 01440 case tcompTYPE_MSZIP: 01441 #ifdef HAVE_ZLIB 01442 p_fci_internal->compression = tcompTYPE_MSZIP; 01443 p_fci_internal->compress = compress_MSZIP; 01444 break; 01445 #endif 01446 default: 01447 FIXME( "compression %x not supported, defaulting to none\n", typeCompress ); 01448 /* fall through */ 01449 case tcompTYPE_NONE: 01450 p_fci_internal->compression = tcompTYPE_NONE; 01451 p_fci_internal->compress = compress_NONE; 01452 break; 01453 } 01454 } 01455 01456 /* TODO check if pszSourceFile??? */ 01457 01458 if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) { 01459 /* internal error */ 01460 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE ); 01461 return FALSE; 01462 } 01463 01464 if(p_fci_internal->fNextCab) { 01465 /* internal error */ 01466 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE ); 01467 return FALSE; 01468 } 01469 01470 /* REUSE the variable read_result */ 01471 read_result=get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder; 01472 01473 read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 + 01474 p_fci_internal->files_size + p_fci_internal->folders_data_size + 01475 p_fci_internal->placed_files_size + p_fci_internal->folders_size + 01476 sizeof(CFFOLDER); /* size of new CFFolder entry */ 01477 01478 /* Might be too much data for the maximum size of a cabinet.*/ 01479 /* When any further data will be added later, it might not */ 01480 /* be possible to flush the cabinet, because there might */ 01481 /* not be enough space to store the name of the following */ 01482 /* cabinet and name of the corresponding disk. */ 01483 /* So take care of this and get the name of the next cabinet */ 01484 if( p_fci_internal->fGetNextCabInVain==FALSE && 01485 p_fci_internal->fNextCab==FALSE && 01486 ( p_fci_internal->ccab.cb < read_result + 01487 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME 01488 ) 01489 ) { 01490 /* increment cabinet index */ 01491 ++(p_fci_internal->pccab->iCab); 01492 /* get name of next cabinet */ 01493 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal; 01494 if (!(*pfnfcignc)(p_fci_internal->pccab, 01495 p_fci_internal->estimatedCabinetSize, /* estimated size of cab */ 01496 p_fci_internal->pv)) { 01497 /* error handling */ 01498 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED ); 01499 return FALSE; 01500 } 01501 /* Skip a few lines of code. This is caught by the next if. */ 01502 p_fci_internal->fGetNextCabInVain=TRUE; 01503 } 01504 01505 if( p_fci_internal->fGetNextCabInVain && 01506 p_fci_internal->fNextCab 01507 ) { 01508 /* THIS CAN NEVER HAPPEN */ 01509 /* set error code */ 01510 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE ); 01511 return FALSE; 01512 } 01513 01514 /* too much data for cabinet */ 01515 if( p_fci_internal->fGetNextCabInVain && 01516 ( 01517 p_fci_internal->ccab.cb < read_result + 01518 strlen(p_fci_internal->pccab->szCab)+1+ 01519 strlen(p_fci_internal->pccab->szDisk)+1 01520 )) { 01521 p_fci_internal->fGetNextCabInVain=FALSE; 01522 p_fci_internal->fNextCab=TRUE; 01523 if(!fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis)) return FALSE; 01524 } 01525 01526 if( p_fci_internal->fNextCab ) { 01527 /* THIS MAY NEVER HAPPEN */ 01528 /* set error code */ 01529 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE ); 01530 return FALSE; 01531 } 01532 01533 if (!add_file_data( p_fci_internal, pszSourceFile, pszFileName, fExecute, pfnfcigoi, pfnfcis )) 01534 return FALSE; 01535 01536 /* REUSE the variable read_result */ 01537 read_result = get_header_size( p_fci_internal ) + p_fci_internal->ccab.cbReserveCFFolder; 01538 read_result+= p_fci_internal->pending_data_size + 01539 p_fci_internal->files_size + p_fci_internal->folders_data_size + 01540 p_fci_internal->placed_files_size + p_fci_internal->folders_size + 01541 sizeof(CFFOLDER); /* set size of new CFFolder entry */ 01542 01543 /* too much data for the maximum size of a cabinet */ 01544 /* (ignoring the unflushed data block) */ 01545 if( p_fci_internal->fGetNextCabInVain==FALSE && 01546 p_fci_internal->fNextCab==FALSE && /* this is always the case */ 01547 p_fci_internal->ccab.cb < read_result ) { 01548 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis); 01549 } 01550 01551 /* Might be too much data for the maximum size of a cabinet.*/ 01552 /* When any further data will be added later, it might not */ 01553 /* be possible to flush the cabinet, because there might */ 01554 /* not be enough space to store the name of the following */ 01555 /* cabinet and name of the corresponding disk. */ 01556 /* So take care of this and get the name of the next cabinet */ 01557 /* (ignoring the unflushed data block) */ 01558 if( p_fci_internal->fGetNextCabInVain==FALSE && 01559 p_fci_internal->fNextCab==FALSE && 01560 ( p_fci_internal->ccab.cb < read_result + 01561 CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME 01562 ) 01563 ) { 01564 /* increment cabinet index */ 01565 ++(p_fci_internal->pccab->iCab); 01566 /* get name of next cabinet */ 01567 p_fci_internal->estimatedCabinetSize=p_fci_internal->statusFolderTotal; 01568 if (!(*pfnfcignc)(p_fci_internal->pccab, 01569 p_fci_internal->estimatedCabinetSize,/* estimated size of cab */ 01570 p_fci_internal->pv)) { 01571 /* error handling */ 01572 set_error( p_fci_internal, FCIERR_NONE, ERROR_FUNCTION_FAILED ); 01573 return FALSE; 01574 } 01575 /* Skip a few lines of code. This is caught by the next if. */ 01576 p_fci_internal->fGetNextCabInVain=TRUE; 01577 } 01578 01579 if( p_fci_internal->fGetNextCabInVain && 01580 p_fci_internal->fNextCab 01581 ) { 01582 /* THIS CAN NEVER HAPPEN */ 01583 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE ); 01584 return FALSE; 01585 } 01586 01587 /* too much data for cabinet */ 01588 if( (p_fci_internal->fGetNextCabInVain || 01589 p_fci_internal->fNextCab) && ( 01590 p_fci_internal->ccab.cb < read_result + 01591 strlen(p_fci_internal->pccab->szCab)+1+ 01592 strlen(p_fci_internal->pccab->szDisk)+1 01593 )) { 01594 01595 p_fci_internal->fGetNextCabInVain=FALSE; 01596 p_fci_internal->fNextCab=TRUE; 01597 return fci_flush_cabinet( p_fci_internal, FALSE, pfnfcignc, pfnfcis); 01598 } 01599 01600 if( p_fci_internal->fNextCab ) { 01601 /* THIS MAY NEVER HAPPEN */ 01602 /* set error code */ 01603 set_error( p_fci_internal, FCIERR_NONE, ERROR_GEN_FAILURE ); 01604 return FALSE; 01605 } 01606 01607 /* if the FolderThreshold has been reached flush the folder automatically */ 01608 if (p_fci_internal->cCompressedBytesInFolder >= p_fci_internal->ccab.cbFolderThresh) 01609 return FCIFlushFolder(hfci, pfnfcignc, pfnfcis); 01610 01611 return TRUE; 01612 } /* end of FCIAddFile */ 01613 01614 01615 01616 01617 01618 /*********************************************************************** 01619 * FCIFlushFolder (CABINET.12) 01620 * 01621 * FCIFlushFolder completes the CFFolder structure under construction. 01622 * 01623 * All further data which is added by FCIAddFile will be associated to 01624 * the next CFFolder structure. 01625 * 01626 * FCIFlushFolder will be called by FCIAddFile automatically if the 01627 * threshold (stored in the member cbFolderThresh of the CCAB structure 01628 * pccab passed to FCICreate) is exceeded. 01629 * 01630 * FCIFlushFolder will be called by FCIFlushFolder automatically before 01631 * any data will be written into the cabinet file. 01632 * 01633 * PARAMS 01634 * hfci [I] An HFCI from FCICreate 01635 * pfnfcignc [I] A pointer to a function which gets information about 01636 * the next cabinet 01637 * pfnfcis [IO] A pointer to a function which will report status 01638 * information about the compression process 01639 * 01640 * RETURNS 01641 * On success, returns TRUE 01642 * On failure, returns FALSE 01643 * 01644 * INCLUDES 01645 * fci.h 01646 * 01647 */ 01648 BOOL __cdecl FCIFlushFolder( 01649 HFCI hfci, 01650 PFNFCIGETNEXTCABINET pfnfcignc, 01651 PFNFCISTATUS pfnfcis) 01652 { 01653 FCI_Int *p_fci_internal = get_fci_ptr( hfci ); 01654 01655 if (!p_fci_internal) return FALSE; 01656 return fci_flush_folder(p_fci_internal,FALSE,pfnfcignc,pfnfcis); 01657 } 01658 01659 01660 01661 /*********************************************************************** 01662 * FCIFlushCabinet (CABINET.13) 01663 * 01664 * FCIFlushCabinet stores the data which has been added by FCIAddFile 01665 * into the cabinet file. If the maximum cabinet size (stored in the 01666 * member cb of the CCAB structure pccab passed to FCICreate) has been 01667 * exceeded FCIFlushCabinet will be called automatic by FCIAddFile. 01668 * The remaining data still has to be flushed manually by calling 01669 * FCIFlushCabinet. 01670 * 01671 * After FCIFlushCabinet has been called (manually) FCIAddFile must 01672 * NOT be called again. Then hfci has to be released by FCIDestroy. 01673 * 01674 * PARAMS 01675 * hfci [I] An HFCI from FCICreate 01676 * fGetNextCab [I] Whether you want to add additional files to a 01677 * cabinet set (TRUE) or whether you want to 01678 * finalize it (FALSE) 01679 * pfnfcignc [I] A pointer to a function which gets information about 01680 * the next cabinet 01681 * pfnfcis [IO] A pointer to a function which will report status 01682 * information about the compression process 01683 * 01684 * RETURNS 01685 * On success, returns TRUE 01686 * On failure, returns FALSE 01687 * 01688 * INCLUDES 01689 * fci.h 01690 * 01691 */ 01692 BOOL __cdecl FCIFlushCabinet( 01693 HFCI hfci, 01694 BOOL fGetNextCab, 01695 PFNFCIGETNEXTCABINET pfnfcignc, 01696 PFNFCISTATUS pfnfcis) 01697 { 01698 FCI_Int *p_fci_internal = get_fci_ptr( hfci ); 01699 01700 if (!p_fci_internal) return FALSE; 01701 01702 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE; 01703 01704 while( p_fci_internal->files_size>0 || 01705 p_fci_internal->placed_files_size>0 ) { 01706 if(!fci_flush_cabinet(p_fci_internal,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE; 01707 } 01708 01709 return TRUE; 01710 } 01711 01712 01713 /*********************************************************************** 01714 * FCIDestroy (CABINET.14) 01715 * 01716 * Frees a handle created by FCICreate. 01717 * Only reason for failure would be an invalid handle. 01718 * 01719 * PARAMS 01720 * hfci [I] The HFCI to free 01721 * 01722 * RETURNS 01723 * TRUE for success 01724 * FALSE for failure 01725 */ 01726 BOOL __cdecl FCIDestroy(HFCI hfci) 01727 { 01728 struct folder *folder, *folder_next; 01729 struct file *file, *file_next; 01730 struct data_block *block, *block_next; 01731 FCI_Int *p_fci_internal = get_fci_ptr( hfci ); 01732 01733 if (!p_fci_internal) return FALSE; 01734 01735 /* before hfci can be removed all temporary files must be closed */ 01736 /* and deleted */ 01737 p_fci_internal->magic = 0; 01738 01739 LIST_FOR_EACH_ENTRY_SAFE( folder, folder_next, &p_fci_internal->folders_list, struct folder, entry ) 01740 { 01741 free_folder( p_fci_internal, folder ); 01742 } 01743 LIST_FOR_EACH_ENTRY_SAFE( file, file_next, &p_fci_internal->files_list, struct file, entry ) 01744 { 01745 free_file( p_fci_internal, file ); 01746 } 01747 LIST_FOR_EACH_ENTRY_SAFE( block, block_next, &p_fci_internal->blocks_list, struct data_block, entry ) 01748 { 01749 free_data_block( p_fci_internal, block ); 01750 } 01751 01752 close_temp_file( p_fci_internal, &p_fci_internal->data ); 01753 01754 /* hfci can now be removed */ 01755 p_fci_internal->free(hfci); 01756 return TRUE; 01757 } Generated on Mon May 28 2012 04:22:35 for ReactOS by
1.7.6.1
|