ReactOS  0.4.12-dev-918-g6c6e7b8
cabinet.cxx
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: ReactOS cabinet manager
4  * FILE: tools/cabman/cabinet.cxx
5  * PURPOSE: Cabinet routines
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * Colin Finck <mail@colinfinck.de>
8  * NOTES: Define CAB_READ_ONLY for read only version
9  * REVISIONS:
10  * CSH 21/03-2001 Created
11  * CSH 15/08-2003 Made it portable
12  * CF 04/05-2007 Made it compatible with 64-bit operating systems
13  * TODO:
14  * - Checksum of datablocks should be calculated
15  * - EXTRACT.EXE complains if a disk is created manually
16  * - Folders that are created manually and span disks will result in a damaged cabinet
17  */
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #if !defined(_WIN32)
22 # include <dirent.h>
23 # include <sys/stat.h>
24 # include <sys/types.h>
25 #endif
26 #include "cabinet.h"
27 #include "raw.h"
28 #include "mszip.h"
29 
30 #ifndef CAB_READ_ONLY
31 
32 #if 0
33 #if DBG
34 
35 void DumpBuffer(void* Buffer, ULONG Size)
36 {
39 
40  /* Create file, overwrite if it already exists */
41  FileHandle = CreateFile("dump.bin", // Create this file
42  GENERIC_WRITE, // Open for writing
43  0, // No sharing
44  NULL, // No security
45  CREATE_ALWAYS, // Create or overwrite
46  FILE_ATTRIBUTE_NORMAL, // Normal file
47  NULL); // No attribute template
49  {
50  DPRINT(MID_TRACE, ("ERROR OPENING '%u'.\n", (UINT)GetLastError()));
51  return;
52  }
53 
55  {
56  DPRINT(MID_TRACE, ("ERROR WRITING '%u'.\n", (UINT)GetLastError()));
57  }
58 
60 }
61 
62 #endif /* DBG */
63 #endif
64 
65 #endif /* CAB_READ_ONLY */
66 
67 
68 /* CCabinet */
69 
71 /*
72  * FUNCTION: Default constructor
73  */
74 {
75  *CabinetName = '\0';
76  *CabinetPrev = '\0';
77  *DiskPrev = '\0';
78  *CabinetNext = '\0';
79  *DiskNext = '\0';
80  *DestPath = '\0';
81  *CabinetReservedFile = '\0';
82 
83  FileOpen = false;
86 
93 
94  Codec = NULL;
95  CodecId = -1;
96  CodecSelected = false;
97 
99  InputBuffer = NULL;
100  MaxDiskSize = 0;
101  BlockIsSplit = false;
102  ScratchFile = NULL;
103 
104  FolderUncompSize = 0;
105  BytesLeftInBlock = 0;
106  ReuseBlock = false;
108 }
109 
110 
112 /*
113  * FUNCTION: Default destructor
114  */
115 {
117  {
121  }
122 
123  if (CodecSelected)
124  delete Codec;
125 }
126 
128 /*
129  * FUNCTION: Determines if a character is a separator
130  * ARGUMENTS:
131  * Char = Character to check
132  * RETURNS:
133  * Whether it is a separator
134  */
135 {
136  if ((Char == '\\') || (Char == '/'))
137  return true;
138  else
139  return false;
140 }
141 
143 /*
144  * FUNCTION: Replaces \ or / with the one used by the host environment
145  * ARGUMENTS:
146  * Path = Pointer to string with pathname
147  * Allocate = Specifies whether to allocate memory for the new
148  * string or to change the existing buffer
149  * RETURNS:
150  * Pointer to new path
151  */
152 {
153  char *newpath;
154  int i;
155 
156  if (Allocate)
157  newpath = strdup(Path);
158  else
159  newpath = Path;
160 
161  i = 0;
162  while (Path[i] != 0)
163  {
164 #if defined(_WIN32)
165  if (Path[i] == '/')
166  newpath[i] = '\\';
167  else
168 #else
169  if (Path[i] == '\\')
170  newpath[i] = '/';
171  else
172 #endif
173  newpath[i] = Path[i];
174 
175  i++;
176  }
177  newpath[i] = 0;
178 
179  return(newpath);
180 }
181 
182 
184 /*
185  * FUNCTION: Returns a pointer to file name
186  * ARGUMENTS:
187  * Path = Pointer to string with pathname
188  * RETURNS:
189  * Pointer to filename
190  */
191 {
192  ULONG i, j;
193 
194  j = i = (Path[0] ? (Path[1] == ':' ? 2 : 0) : 0);
195 
196  while (Path [i++])
197  if (IsSeparator(Path [i - 1]))
198  j = i;
199 
200  return Path + j;
201 }
202 
203 
205 /*
206  * FUNCTION: Removes a file name from a path
207  * ARGUMENTS:
208  * Path = Pointer to string with path
209  */
210 {
211  char* FileName;
212  ULONG i;
213 
214  i = (Path [0] ? (Path[1] == ':' ? 2 : 0) : 0);
215  FileName = GetFileName(Path + i);
216 
217  if ((FileName != (Path + i)) && (IsSeparator(FileName [-1])))
218  FileName--;
219  if ((FileName == (Path + i)) && (IsSeparator(FileName [0])))
220  FileName++;
221  FileName[0] = 0;
222 }
223 
224 
226  ULONG Length)
227 /*
228  * FUNCTION: Normalizes a path
229  * ARGUMENTS:
230  * Path = Pointer to string with pathname
231  * Length = Number of bytes in Path
232  * RETURNS:
233  * true if there was enough room in Path, or false
234  */
235 {
236  ULONG n;
237  bool OK = true;
238 
239  if ((n = (ULONG)strlen(Path)) &&
240  (!IsSeparator(Path[n - 1])) &&
241  (OK = ((n + 1) < Length)))
242  {
244  Path[n + 1] = 0;
245  }
246  return OK;
247 }
248 
249 
251 /*
252  * FUNCTION: Returns pointer to cabinet file name
253  * RETURNS:
254  * Pointer to string with name of cabinet
255  */
256 {
257  return CabinetName;
258 }
259 
260 
262 /*
263  * FUNCTION: Sets cabinet file name
264  * ARGUMENTS:
265  * FileName = Pointer to string with name of cabinet
266  */
267 {
269 }
270 
271 
272 void CCabinet::SetDestinationPath(char* DestinationPath)
273 /*
274  * FUNCTION: Sets destination path
275  * ARGUMENTS:
276  * DestinationPath = Pointer to string with name of destination path
277  */
278 {
279  strcpy(DestPath, DestinationPath);
280  ConvertPath(DestPath, false);
281  if (strlen(DestPath) > 0)
283 }
284 
285 ULONG CCabinet::AddSearchCriteria(char* SearchCriteria)
286 /*
287  * FUNCTION: Adds a criteria to the search criteria list
288  * ARGUMENTS:
289  * SearchCriteria = String with the search criteria to add
290  * RETURNS:
291  * Status of operation
292  */
293 {
294  PSEARCH_CRITERIA Criteria;
295 
296  // Add the criteria to the list of search criteria
297  Criteria = (PSEARCH_CRITERIA)malloc(sizeof(SEARCH_CRITERIA));
298  if(!Criteria)
299  {
300  DPRINT(MIN_TRACE, ("Insufficient memory.\n"));
301  return CAB_STATUS_NOMEMORY;
302  }
303 
304  Criteria->Prev = CriteriaListTail;
305  Criteria->Next = NULL;
306 
307  if(CriteriaListTail)
308  CriteriaListTail->Next = Criteria;
309  else
310  CriteriaListHead = Criteria;
311 
312  CriteriaListTail = Criteria;
313 
314  // Set the actual criteria string
315  Criteria->Search = (char*)malloc(strlen(SearchCriteria) + 1);
316  if (!Criteria->Search)
317  {
318  DPRINT(MIN_TRACE, ("Insufficient memory.\n"));
319  return CAB_STATUS_NOMEMORY;
320  }
321 
322  strcpy(Criteria->Search, SearchCriteria);
323 
324  return CAB_STATUS_SUCCESS;
325 }
326 
328 /*
329  * FUNCTION: Destroys the list with the search criteria
330  */
331 {
332  PSEARCH_CRITERIA Criteria;
333  PSEARCH_CRITERIA NextCriteria;
334 
335  Criteria = CriteriaListHead;
336 
337  while(Criteria)
338  {
339  NextCriteria = Criteria->Next;
340 
341  free(Criteria->Search);
342  free(Criteria);
343 
344  Criteria = NextCriteria;
345  }
346 
349 }
350 
352 /*
353  * FUNCTION: Returns whether we have search criteria
354  * RETURNS:
355  * Whether we have search criteria or not.
356  */
357 {
358  return (CriteriaListHead != NULL);
359 }
360 
361 bool CCabinet::SetCompressionCodec(char* CodecName)
362 /*
363  * FUNCTION: Selects the codec to use for compression
364  * ARGUMENTS:
365  * CodecName = Pointer to a string with the name of the codec
366  */
367 {
368  if( !strcasecmp(CodecName, "raw") )
370  else if( !strcasecmp(CodecName, "mszip") )
372  else
373  {
374  printf("ERROR: Invalid codec specified!\n");
375  return false;
376  }
377 
378  return true;
379 }
380 
382 /*
383  * FUNCTION: Returns destination path
384  * RETURNS:
385  * Pointer to string with name of destination path
386  */
387 {
388  return DestPath;
389 }
390 
391 
393 /*
394  * FUNCTION: Sets cabinet reserved file
395  * ARGUMENTS:
396  * FileName = Pointer to string with name of cabinet reserved file
397  */
398 {
399  FILE* FileHandle;
401  char* ConvertedFileName;
402 
403  ConvertedFileName = ConvertPath(FileName, true);
404 
405  FileHandle = fopen(ConvertedFileName, "rb");
406  free(ConvertedFileName);
407  if (FileHandle == NULL)
408  {
409  DPRINT(MID_TRACE, ("Cannot open cabinet reserved file.\n"));
410  return false;
411  }
412 
414  if (CabinetReservedFileSize == (ULONG)-1)
415  {
416  DPRINT(MIN_TRACE, ("Cannot read from cabinet reserved file.\n"));
417  return false;
418  }
419 
420  if (CabinetReservedFileSize == 0)
421  {
423  return false;
424  }
425 
428  {
430  return false;
431  }
432 
435  {
437  return false;
438  }
439 
441 
443 
444  return true;
445 }
446 
447 
449 /*
450  * FUNCTION: Returns cabionet reserved file
451  * RETURNS:
452  * Pointer to string with name of cabinet reserved file
453  */
454 {
455  return CabinetReservedFile;
456 }
457 
458 
460 /*
461  * FUNCTION: Returns current disk number
462  * RETURNS:
463  * Current disk number
464  */
465 {
466  return CurrentDiskNumber;
467 }
468 
469 
471 /*
472  * FUNCTION: Opens a cabinet file
473  * RETURNS:
474  * Status of operation
475  */
476 {
477  PCFFOLDER_NODE FolderNode;
478  ULONG Status;
479  ULONG Index;
480 
481  if (!FileOpen)
482  {
484  ULONG Size;
485 
486  OutputBuffer = malloc(CAB_BLOCKSIZE + 12); // This should be enough
487  if (!OutputBuffer)
488  return CAB_STATUS_NOMEMORY;
489 
490  FileHandle = fopen(CabinetName, "rb");
491  if (FileHandle == NULL)
492  {
493  DPRINT(MID_TRACE, ("Cannot open file.\n"));
494  return CAB_STATUS_CANNOT_OPEN;
495  }
496 
497  FileOpen = true;
498 
499  /* Load CAB header */
500  if ((Status = ReadBlock(&CABHeader, sizeof(CFHEADER), &BytesRead))
502  {
503  DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
504  return CAB_STATUS_INVALID_CAB;
505  }
506 
507  /* Check header */
508  if ((BytesRead != sizeof(CFHEADER)) ||
509  (CABHeader.Signature != CAB_SIGNATURE ) ||
510  (CABHeader.Version != CAB_VERSION ) ||
511  (CABHeader.FolderCount == 0 ) ||
512  (CABHeader.FileCount == 0 ) ||
513  (CABHeader.FileTableOffset < sizeof(CFHEADER)))
514  {
515  CloseCabinet();
516  DPRINT(MID_TRACE, ("File has invalid header.\n"));
517  return CAB_STATUS_INVALID_CAB;
518  }
519 
520  Size = 0;
521 
522  /* Read/skip any reserved bytes */
523  if (CABHeader.Flags & CAB_FLAG_RESERVE)
524  {
525  if ((Status = ReadBlock(&Size, sizeof(ULONG), &BytesRead))
527  {
528  DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
529  return CAB_STATUS_INVALID_CAB;
530  }
531  CabinetReserved = Size & 0xFFFF;
532  FolderReserved = (Size >> 16) & 0xFF;
533  DataReserved = (Size >> 24) & 0xFF;
534 
536  {
537  DPRINT(MIN_TRACE, ("fseek() failed.\n"));
538  return CAB_STATUS_FAILURE;
539  }
540  }
541 
542  if ((CABHeader.Flags & CAB_FLAG_HASPREV) > 0)
543  {
544  /* Read name of previous cabinet */
545  Status = ReadString(CabinetPrev, 256);
546  if (Status != CAB_STATUS_SUCCESS)
547  return Status;
548  /* Read label of previous disk */
549  Status = ReadString(DiskPrev, 256);
550  if (Status != CAB_STATUS_SUCCESS)
551  return Status;
552  }
553  else
554  {
555  strcpy(CabinetPrev, "");
556  strcpy(DiskPrev, "");
557  }
558 
559  if ((CABHeader.Flags & CAB_FLAG_HASNEXT) > 0)
560  {
561  /* Read name of next cabinet */
562  Status = ReadString(CabinetNext, 256);
563  if (Status != CAB_STATUS_SUCCESS)
564  return Status;
565  /* Read label of next disk */
566  Status = ReadString(DiskNext, 256);
567  if (Status != CAB_STATUS_SUCCESS)
568  return Status;
569  }
570  else
571  {
572  strcpy(CabinetNext, "");
573  strcpy(DiskNext, "");
574  }
575 
576  /* Read all folders */
577  for (Index = 0; Index < CABHeader.FolderCount; Index++)
578  {
579  FolderNode = NewFolderNode();
580  if (!FolderNode)
581  {
582  DPRINT(MIN_TRACE, ("Insufficient resources.\n"));
583  return CAB_STATUS_NOMEMORY;
584  }
585 
586  if (Index == 0)
587  FolderNode->UncompOffset = FolderUncompSize;
588 
589  FolderNode->Index = Index;
590 
591  if ((Status = ReadBlock(&FolderNode->Folder,
592  sizeof(CFFOLDER), &BytesRead)) != CAB_STATUS_SUCCESS)
593  {
594  DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
595  return CAB_STATUS_INVALID_CAB;
596  }
597  }
598 
599  /* Read file entries */
600  Status = ReadFileTable();
601  if (Status != CAB_STATUS_SUCCESS)
602  {
603  DPRINT(MIN_TRACE, ("ReadFileTable() failed (%u).\n", (UINT)Status));
604  return Status;
605  }
606 
607  /* Read data blocks for all folders */
608  FolderNode = FolderListHead;
609  while (FolderNode != NULL)
610  {
611  Status = ReadDataBlocks(FolderNode);
612  if (Status != CAB_STATUS_SUCCESS)
613  {
614  DPRINT(MIN_TRACE, ("ReadDataBlocks() failed (%u).\n", (UINT)Status));
615  return Status;
616  }
617  FolderNode = FolderNode->Next;
618  }
619  }
620  return CAB_STATUS_SUCCESS;
621 }
622 
623 
625 /*
626  * FUNCTION: Closes the cabinet file
627  */
628 {
629  if (FileOpen)
630  {
632  FileOpen = false;
633  }
634 }
635 
636 
638 /*
639  * FUNCTION: Finds the first file in the cabinet that matches a search criteria
640  * ARGUMENTS:
641  * Search = Pointer to search structure
642  * RETURNS:
643  * Status of operation
644  */
645 {
646  RestartSearch = false;
647  Search->Next = FileListHead;
648  return FindNext(Search);
649 }
650 
651 
653 /*
654  * FUNCTION: Finds next file in the cabinet that matches a search criteria
655  * ARGUMENTS:
656  * Search = Pointer to search structure
657  * RETURNS:
658  * Status of operation
659  */
660 {
661  bool bFound = false;
662  PSEARCH_CRITERIA Criteria;
663  ULONG Status;
664 
665  if (RestartSearch)
666  {
667  Search->Next = FileListHead;
668 
669  /* Skip split files already extracted */
670  while ((Search->Next) &&
671  (Search->Next->File.FileControlID > CAB_FILE_MAX_FOLDER) &&
672  (Search->Next->File.FileOffset <= LastFileOffset))
673  {
674  DPRINT(MAX_TRACE, ("Skipping file (%s) FileOffset (0x%X) LastFileOffset (0x%X).\n",
675  Search->Next->FileName, (UINT)Search->Next->File.FileOffset, (UINT)LastFileOffset));
676  Search->Next = Search->Next->Next;
677  }
678 
679  RestartSearch = false;
680  }
681 
682  /* Check each search criteria against each file */
683  while(Search->Next)
684  {
685  // Some features (like displaying cabinets) don't require search criteria, so we can just break here.
686  // If a feature requires it, handle this in the ParseCmdline() function in "main.cxx".
687  if(!CriteriaListHead)
688  break;
689 
690  Criteria = CriteriaListHead;
691 
692  while(Criteria)
693  {
694  if(MatchFileNamePattern(Search->Next->FileName, Criteria->Search))
695  {
696  bFound = true;
697  break;
698  }
699 
700  Criteria = Criteria->Next;
701  }
702 
703  if(bFound)
704  break;
705 
706  Search->Next = Search->Next->Next;
707  }
708 
709  if (!Search->Next)
710  {
711  if (strlen(DiskNext) > 0)
712  {
713  CloseCabinet();
714 
716 
718 
719  Status = Open();
720  if (Status != CAB_STATUS_SUCCESS)
721  return Status;
722 
723  Search->Next = FileListHead;
724  if (!Search->Next)
725  return CAB_STATUS_NOFILE;
726  }
727  else
728  return CAB_STATUS_NOFILE;
729  }
730 
731  Search->File = &Search->Next->File;
732  Search->FileName = Search->Next->FileName;
733  Search->Next = Search->Next->Next;
734  return CAB_STATUS_SUCCESS;
735 }
736 
737 
739 /*
740  * FUNCTION: Extracts a file from the cabinet
741  * ARGUMENTS:
742  * FileName = Pointer to buffer with name of file
743  * RETURNS
744  * Status of operation
745  */
746 {
747  ULONG Size;
748  ULONG Offset;
750  ULONG BytesToRead;
752  ULONG BytesSkipped;
753  ULONG BytesToWrite;
754  ULONG TotalBytesRead;
755  ULONG CurrentOffset;
756  PUCHAR Buffer;
758  FILE* DestFile;
760  CFDATA CFData;
761  ULONG Status;
762  bool Skip;
763 #if defined(_WIN32)
764  FILETIME FileTime;
765 #endif
766  CHAR DestName[PATH_MAX];
767  CHAR TempName[PATH_MAX];
768 
770  if (Status != CAB_STATUS_SUCCESS)
771  {
772  DPRINT(MID_TRACE, ("Cannot locate file (%u).\n", (UINT)Status));
773  return Status;
774  }
775 
776  LastFileOffset = File->File.FileOffset;
777 
778  switch (CurrentFolderNode->Folder.CompressionType & CAB_COMP_MASK)
779  {
780  case CAB_COMP_NONE:
782  break;
783 
784  case CAB_COMP_MSZIP:
786  break;
787 
788  default:
789  return CAB_STATUS_UNSUPPCOMP;
790  }
791 
792  DPRINT(MAX_TRACE, ("Extracting file at uncompressed offset (0x%X) Size (%u bytes) AO (0x%X) UO (0x%X).\n",
793  (UINT)File->File.FileOffset,
794  (UINT)File->File.FileSize,
795  (UINT)File->DataBlock->AbsoluteOffset,
796  (UINT)File->DataBlock->UncompOffset));
797 
798  strcpy(DestName, DestPath);
799  strcat(DestName, FileName);
800 
801  /* Create destination file, fail if it already exists */
802  DestFile = fopen(DestName, "rb");
803  if (DestFile != NULL)
804  {
805  fclose(DestFile);
806  /* If file exists, ask to overwrite file */
807  if (OnOverwrite(&File->File, FileName))
808  {
809  DestFile = fopen(DestName, "w+b");
810  if (DestFile == NULL)
812  }
813  else
814  return CAB_STATUS_FILE_EXISTS;
815  }
816  else
817  {
818  DestFile = fopen(DestName, "w+b");
819  if (DestFile == NULL)
821  }
822 
823 #if defined(_WIN32)
824  if (!DosDateTimeToFileTime(File->File.FileDate, File->File.FileTime, &FileTime))
825  {
826  fclose(DestFile);
827  DPRINT(MIN_TRACE, ("DosDateTimeToFileTime() failed (%u).\n", (UINT)GetLastError()));
829  }
830 
831  SetFileTime(DestFile, NULL, &FileTime, NULL);
832 #else
833  //DPRINT(MIN_TRACE, ("FIXME: DosDateTimeToFileTime\n"));
834 #endif
835 
836  SetAttributesOnFile(DestName, File->File.Attributes);
837 
838  Buffer = (PUCHAR)malloc(CAB_BLOCKSIZE + 12); // This should be enough
839  if (!Buffer)
840  {
841  fclose(DestFile);
842  DPRINT(MIN_TRACE, ("Insufficient memory.\n"));
843  return CAB_STATUS_NOMEMORY;
844  }
845 
846  /* Call OnExtract event handler */
848 
849  /* Search to start of file */
850  if (fseek(FileHandle, (off_t)File->DataBlock->AbsoluteOffset, SEEK_SET) != 0)
851  {
852  DPRINT(MIN_TRACE, ("fseek() failed.\n"));
853  fclose(DestFile);
854  free(Buffer);
855  return CAB_STATUS_INVALID_CAB;
856  }
857 
858  Size = File->File.FileSize;
859  Offset = File->File.FileOffset;
860  CurrentOffset = File->DataBlock->UncompOffset;
861 
862  Skip = true;
863 
864  ReuseBlock = (CurrentDataNode == File->DataBlock);
865  if (Size > 0)
866  {
867  do
868  {
869  DPRINT(MAX_TRACE, ("CO (0x%X) ReuseBlock (%u) Offset (0x%X) Size (%d) BytesLeftInBlock (%d)\n",
870  (UINT)File->DataBlock->UncompOffset, (UINT)ReuseBlock, (UINT)Offset, (UINT)Size,
872 
873  if (/*(CurrentDataNode != File->DataBlock) &&*/ (!ReuseBlock) || (BytesLeftInBlock <= 0))
874  {
875  DPRINT(MAX_TRACE, ("Filling buffer. ReuseBlock (%u)\n", (UINT)ReuseBlock));
876 
878  TotalBytesRead = 0;
879  do
880  {
881  DPRINT(MAX_TRACE, ("Size (%u bytes).\n", (UINT)Size));
882 
883  if (((Status = ReadBlock(&CFData, sizeof(CFDATA), &BytesRead)) !=
884  CAB_STATUS_SUCCESS) || (BytesRead != sizeof(CFDATA)))
885  {
886  fclose(DestFile);
887  free(Buffer);
888  DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
889  return CAB_STATUS_INVALID_CAB;
890  }
891 
892  DPRINT(MAX_TRACE, ("Data block: Checksum (0x%X) CompSize (%u bytes) UncompSize (%u bytes)\n",
893  (UINT)CFData.Checksum,
894  CFData.CompSize,
895  CFData.UncompSize));
896 
897  ASSERT(CFData.CompSize <= CAB_BLOCKSIZE + 12);
898 
899  BytesToRead = CFData.CompSize;
900 
901  DPRINT(MAX_TRACE, ("Read: (0x%lX,0x%lX).\n",
902  (unsigned long)CurrentBuffer, (unsigned long)Buffer));
903 
904  if (((Status = ReadBlock(CurrentBuffer, BytesToRead, &BytesRead)) !=
905  CAB_STATUS_SUCCESS) || (BytesToRead != BytesRead))
906  {
907  fclose(DestFile);
908  free(Buffer);
909  DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
910  return CAB_STATUS_INVALID_CAB;
911  }
912 
913  /* FIXME: Does not work with files generated by makecab.exe */
914 /*
915  if (CFData.Checksum != 0)
916  {
917  ULONG Checksum = ComputeChecksum(CurrentBuffer, BytesRead, 0);
918  if (Checksum != CFData.Checksum)
919  {
920  CloseFile(DestFile);
921  free(Buffer);
922  DPRINT(MIN_TRACE, ("Bad checksum (is 0x%X, should be 0x%X).\n",
923  Checksum, CFData.Checksum));
924  return CAB_STATUS_INVALID_CAB;
925  }
926  }
927 */
928  TotalBytesRead += BytesRead;
929 
931 
932  if (CFData.UncompSize == 0)
933  {
934  if (strlen(DiskNext) == 0)
935  {
936  fclose(DestFile);
937  free(Buffer);
938  return CAB_STATUS_NOFILE;
939  }
940 
941  /* CloseCabinet() will destroy all file entries so in case
942  FileName refers to the FileName field of a CFFOLDER_NODE
943  structure, we have to save a copy of the filename */
944  strcpy(TempName, FileName);
945 
946  CloseCabinet();
947 
949 
951 
952  Status = Open();
953  if (Status != CAB_STATUS_SUCCESS)
954  {
955  fclose(DestFile);
956  free(Buffer);
957  return Status;
958  }
959 
960  /* The first data block of the file will not be
961  found as it is located in the previous file */
962  Status = LocateFile(TempName, &File);
963  if (Status == CAB_STATUS_NOFILE)
964  {
965  DPRINT(MID_TRACE, ("Cannot locate file (%u).\n", (UINT)Status));
966  fclose(DestFile);
967  free(Buffer);
968  return Status;
969  }
970 
971  /* The file is continued in the first data block in the folder */
972  File->DataBlock = CurrentFolderNode->DataListHead;
973 
974  /* Search to start of file */
975  if (fseek(FileHandle, (off_t)File->DataBlock->AbsoluteOffset, SEEK_SET) != 0)
976  {
977  DPRINT(MIN_TRACE, ("fseek() failed.\n"));
978  fclose(DestFile);
979  free(Buffer);
980  return CAB_STATUS_INVALID_CAB;
981  }
982 
983  DPRINT(MAX_TRACE, ("Continuing extraction of file at uncompressed offset (0x%X) Size (%u bytes) AO (0x%X) UO (0x%X).\n",
984  (UINT)File->File.FileOffset,
985  (UINT)File->File.FileSize,
986  (UINT)File->DataBlock->AbsoluteOffset,
987  (UINT)File->DataBlock->UncompOffset));
988 
989  CurrentDataNode = File->DataBlock;
990  ReuseBlock = true;
991 
992  RestartSearch = true;
993  }
994  } while (CFData.UncompSize == 0);
995 
996  DPRINT(MAX_TRACE, ("TotalBytesRead (%u).\n", (UINT)TotalBytesRead));
997 
998  Status = Codec->Uncompress(OutputBuffer, Buffer, TotalBytesRead, &BytesToWrite);
999  if (Status != CS_SUCCESS)
1000  {
1001  fclose(DestFile);
1002  free(Buffer);
1003  DPRINT(MID_TRACE, ("Cannot uncompress block.\n"));
1004  if (Status == CS_NOMEMORY)
1005  return CAB_STATUS_NOMEMORY;
1006  return CAB_STATUS_INVALID_CAB;
1007  }
1008 
1009  if (BytesToWrite != CFData.UncompSize)
1010  {
1011  DPRINT(MID_TRACE, ("BytesToWrite (%u) != CFData.UncompSize (%d)\n",
1012  (UINT)BytesToWrite, CFData.UncompSize));
1013  fclose(DestFile);
1014  free(Buffer);
1015  return CAB_STATUS_INVALID_CAB;
1016  }
1017 
1018  BytesLeftInBlock = BytesToWrite;
1019  }
1020  else
1021  {
1022  DPRINT(MAX_TRACE, ("Using same buffer. ReuseBlock (%u)\n", (UINT)ReuseBlock));
1023 
1024  BytesToWrite = BytesLeftInBlock;
1025 
1026  DPRINT(MAX_TRACE, ("Seeking to absolute offset 0x%X.\n",
1027  (UINT)(CurrentDataNode->AbsoluteOffset + sizeof(CFDATA) + CurrentDataNode->Data.CompSize)));
1028 
1029  if (((Status = ReadBlock(&CFData, sizeof(CFDATA), &BytesRead)) !=
1030  CAB_STATUS_SUCCESS) || (BytesRead != sizeof(CFDATA)))
1031  {
1032  fclose(DestFile);
1033  free(Buffer);
1034  DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
1035  return CAB_STATUS_INVALID_CAB;
1036  }
1037 
1038  DPRINT(MAX_TRACE, ("CFData.CompSize 0x%X CFData.UncompSize 0x%X.\n",
1039  CFData.CompSize, CFData.UncompSize));
1040 
1041  /* Go to next data block */
1043  CurrentDataNode->Data.CompSize, SEEK_SET) != 0)
1044  {
1045  DPRINT(MIN_TRACE, ("fseek() failed.\n"));
1046  fclose(DestFile);
1047  free(Buffer);
1048  return CAB_STATUS_INVALID_CAB;
1049  }
1050 
1051  ReuseBlock = false;
1052  }
1053 
1054  if (Skip)
1055  BytesSkipped = (Offset - CurrentOffset);
1056  else
1057  BytesSkipped = 0;
1058 
1059  BytesToWrite -= BytesSkipped;
1060 
1061  if (Size < BytesToWrite)
1062  BytesToWrite = Size;
1063 
1064  DPRINT(MAX_TRACE, ("Offset (0x%X) CurrentOffset (0x%X) ToWrite (%u) Skipped (%u)(%u) Size (%u).\n",
1065  (UINT)Offset,
1066  (UINT)CurrentOffset,
1067  (UINT)BytesToWrite,
1068  (UINT)BytesSkipped, (UINT)Skip,
1069  (UINT)Size));
1070 
1071  BytesWritten = BytesToWrite;
1072  if (fwrite((void*)((PUCHAR)OutputBuffer + BytesSkipped),
1073  BytesToWrite, 1, DestFile) < 1)
1074  {
1075  fclose(DestFile);
1076  free(Buffer);
1077  DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
1078 
1079  return CAB_STATUS_CANNOT_WRITE;
1080  }
1081 
1082  Size -= BytesToWrite;
1083 
1084  CurrentOffset += BytesToWrite;
1085 
1086  /* Don't skip any more bytes */
1087  Skip = false;
1088  } while (Size > 0);
1089  }
1090 
1091  fclose(DestFile);
1092 
1093  free(Buffer);
1094 
1095  return CAB_STATUS_SUCCESS;
1096 }
1097 
1099 /*
1100  * FUNCTION: Returns the value of CodecSelected
1101  * RETURNS:
1102  * Whether a codec is selected
1103  */
1104 {
1105  return CodecSelected;
1106 }
1107 
1109 /*
1110  * FUNCTION: Selects codec engine to use
1111  * ARGUMENTS:
1112  * Id = Codec identifier
1113  */
1114 {
1115  if (CodecSelected)
1116  {
1117  if (Id == CodecId)
1118  return;
1119 
1120  CodecSelected = false;
1121  delete Codec;
1122  }
1123 
1124  switch (Id)
1125  {
1126  case CAB_CODEC_RAW:
1127  Codec = new CRawCodec();
1128  break;
1129 
1130  case CAB_CODEC_MSZIP:
1131  Codec = new CMSZipCodec();
1132  break;
1133 
1134  default:
1135  return;
1136  }
1137 
1138  CodecId = Id;
1139  CodecSelected = true;
1140 }
1141 
1142 
1143 #ifndef CAB_READ_ONLY
1144 
1145 /* CAB write methods */
1146 
1148 /*
1149  * FUNCTION: Creates a new cabinet
1150  * RETURNS:
1151  * Status of operation
1152  */
1153 {
1154  ULONG Status;
1155 
1156  CurrentDiskNumber = 0;
1157 
1158  OutputBuffer = malloc(CAB_BLOCKSIZE + 12); // This should be enough
1159  InputBuffer = malloc(CAB_BLOCKSIZE + 12); // This should be enough
1160  if ((!OutputBuffer) || (!InputBuffer))
1161  {
1162  DPRINT(MIN_TRACE, ("Insufficient memory.\n"));
1163  return CAB_STATUS_NOMEMORY;
1164  }
1166  CurrentIBufferSize = 0;
1167 
1168  CABHeader.Signature = CAB_SIGNATURE;
1169  CABHeader.Reserved1 = 0; // Not used
1170  CABHeader.CabinetSize = 0; // Not yet known
1171  CABHeader.Reserved2 = 0; // Not used
1172  CABHeader.Reserved3 = 0; // Not used
1173  CABHeader.Version = CAB_VERSION;
1174  CABHeader.FolderCount = 0; // Not yet known
1175  CABHeader.FileCount = 0; // Not yet known
1176  CABHeader.Flags = 0; // Not yet known
1177  // FIXME: Should be random
1178  CABHeader.SetID = 0x534F;
1179  CABHeader.CabinetNumber = 0;
1180 
1181 
1182  TotalFolderSize = 0;
1183  TotalFileSize = 0;
1184 
1185  DiskSize = sizeof(CFHEADER);
1186 
1188 
1189  // NextFolderNumber is 0-based
1190  NextFolderNumber = 0;
1191 
1193  Status = NewFolder();
1194  if (Status != CAB_STATUS_SUCCESS)
1195  return Status;
1196 
1198 
1200  if (!ScratchFile)
1201  {
1202  DPRINT(MIN_TRACE, ("Insufficient memory.\n"));
1203  return CAB_STATUS_NOMEMORY;
1204  }
1205 
1206  Status = ScratchFile->Create();
1207 
1208  CreateNewFolder = false;
1209 
1210  CreateNewDisk = false;
1211 
1212  PrevCabinetNumber = 0;
1213 
1214  return Status;
1215 }
1216 
1217 
1219 /*
1220  * FUNCTION: Forces a new disk to be created
1221  * RETURNS:
1222  * Status of operation
1223  */
1224 {
1225  // NextFolderNumber is 0-based
1226  NextFolderNumber = 1;
1227 
1228  CreateNewDisk = false;
1229 
1231 
1233 
1235 
1236  CurrentFolderNode->Folder.DataBlockCount = 0;
1237 
1238  return CAB_STATUS_SUCCESS;
1239 }
1240 
1241 
1243 /*
1244  * FUNCTION: Forces a new folder to be created
1245  * RETURNS:
1246  * Status of operation
1247  */
1248 {
1249  DPRINT(MAX_TRACE, ("Creating new folder.\n"));
1250 
1252  if (!CurrentFolderNode)
1253  {
1254  DPRINT(MIN_TRACE, ("Insufficient memory.\n"));
1255  return CAB_STATUS_NOMEMORY;
1256  }
1257 
1258  switch (CodecId) {
1259  case CAB_CODEC_RAW:
1260  CurrentFolderNode->Folder.CompressionType = CAB_COMP_NONE;
1261  break;
1262 
1263  case CAB_CODEC_MSZIP:
1264  CurrentFolderNode->Folder.CompressionType = CAB_COMP_MSZIP;
1265  break;
1266 
1267  default:
1268  return CAB_STATUS_UNSUPPCOMP;
1269  }
1270 
1271  /* FIXME: This won't work if no files are added to the new folder */
1272 
1273  DiskSize += sizeof(CFFOLDER);
1274 
1275  TotalFolderSize += sizeof(CFFOLDER);
1276 
1277  NextFolderNumber++;
1278 
1279  CABHeader.FolderCount++;
1280 
1281  LastBlockStart = 0;
1282 
1283  return CAB_STATUS_SUCCESS;
1284 }
1285 
1286 
1288 /*
1289  * FUNCTION: Writes a file to the scratch file
1290  * ARGUMENTS:
1291  * FileNode = Pointer to file node
1292  * RETURNS:
1293  * Status of operation
1294  */
1295 {
1296  ULONG BytesToRead;
1297  ULONG BytesRead;
1298  ULONG Status;
1299  ULONG Size;
1300 
1301  if (!ContinueFile)
1302  {
1303  /* Try to open file */
1304  SourceFile = fopen(FileNode->FileName, "rb");
1305  if (SourceFile == NULL)
1306  {
1307  DPRINT(MID_TRACE, ("File not found (%s).\n", FileNode->FileName));
1308  return CAB_STATUS_NOFILE;
1309  }
1310 
1311  if (CreateNewFolder)
1312  {
1313  /* There is always a new folder after
1314  a split file is completely stored */
1315  Status = NewFolder();
1316  if (Status != CAB_STATUS_SUCCESS)
1317  return Status;
1318  CreateNewFolder = false;
1319  }
1320 
1321  /* Call OnAdd event handler */
1322  OnAdd(&FileNode->File, FileNode->FileName);
1323 
1324  TotalBytesLeft = FileNode->File.FileSize;
1325 
1326  FileNode->File.FileOffset = CurrentFolderNode->UncompOffset;
1328  FileNode->File.FileControlID = (USHORT)(NextFolderNumber - 1);
1329  CurrentFolderNode->Commit = true;
1331 
1332  Size = sizeof(CFFILE) + (ULONG)strlen(GetFileName(FileNode->FileName)) + 1;
1333  CABHeader.FileTableOffset += Size;
1334  TotalFileSize += Size;
1335  DiskSize += Size;
1336  }
1337 
1338  FileNode->Commit = true;
1339 
1340  if (TotalBytesLeft > 0)
1341  {
1342  do
1343  {
1345  BytesToRead = CAB_BLOCKSIZE - CurrentIBufferSize;
1346  else
1347  BytesToRead = TotalBytesLeft;
1348 
1349  if ( (BytesRead = fread(CurrentIBuffer, 1, BytesToRead, SourceFile)) != BytesToRead )
1350  {
1351  DPRINT(MIN_TRACE, ("Cannot read from file. BytesToRead (%u) BytesRead (%u) CurrentIBufferSize (%u).\n",
1352  (UINT)BytesToRead, (UINT)BytesRead, (UINT)CurrentIBufferSize));
1353  return CAB_STATUS_INVALID_CAB;
1354  }
1355 
1356  CurrentIBuffer = (unsigned char*)CurrentIBuffer + BytesRead;
1358 
1360  {
1361  Status = WriteDataBlock();
1362  if (Status != CAB_STATUS_SUCCESS)
1363  return Status;
1364  }
1366  } while ((TotalBytesLeft > 0) && (!CreateNewDisk));
1367  }
1368 
1369  if (TotalBytesLeft == 0)
1370  {
1371  fclose(SourceFile);
1372  FileNode->Delete = true;
1373 
1374  if (FileNode->File.FileControlID > CAB_FILE_MAX_FOLDER)
1375  {
1376  FileNode->File.FileControlID = CAB_FILE_CONTINUED;
1377  CurrentFolderNode->Delete = true;
1378 
1379  if ((CurrentIBufferSize > 0) || (CurrentOBufferSize > 0))
1380  {
1381  Status = WriteDataBlock();
1382  if (Status != CAB_STATUS_SUCCESS)
1383  return Status;
1384  }
1385 
1386  CreateNewFolder = true;
1387  }
1388  }
1389  else
1390  {
1391  if (FileNode->File.FileControlID <= CAB_FILE_MAX_FOLDER)
1392  FileNode->File.FileControlID = CAB_FILE_SPLIT;
1393  else
1394  FileNode->File.FileControlID = CAB_FILE_PREV_NEXT;
1395  }
1396 
1397  return CAB_STATUS_SUCCESS;
1398 }
1399 
1400 
1402 /*
1403  * FUNCTION: Forces the current disk to be written
1404  * ARGUMENTS:
1405  * MoreDisks = true if there is one or more disks after this disk
1406  * RETURNS:
1407  * Status of operation
1408  */
1409 {
1410  PCFFILE_NODE FileNode;
1411  ULONG Status;
1412 
1413  ContinueFile = false;
1414  FileNode = FileListHead;
1415  while (FileNode != NULL)
1416  {
1417  Status = WriteFileToScratchStorage(FileNode);
1418  if (Status != CAB_STATUS_SUCCESS)
1419  return Status;
1420 
1421  if (CreateNewDisk)
1422  {
1423  /* A data block could span more than two
1424  disks if MaxDiskSize is very small */
1425  while (CreateNewDisk)
1426  {
1427  DPRINT(MAX_TRACE, ("Creating new disk.\n"));
1428  CommitDisk(true);
1429  CloseDisk();
1430  NewDisk();
1431 
1432  ContinueFile = true;
1433  CreateNewDisk = false;
1434 
1435  DPRINT(MAX_TRACE, ("First on new disk. CurrentIBufferSize (%u) CurrentOBufferSize (%u).\n",
1437 
1438  if ((CurrentIBufferSize > 0) || (CurrentOBufferSize > 0))
1439  {
1440  Status = WriteDataBlock();
1441  if (Status != CAB_STATUS_SUCCESS)
1442  return Status;
1443  }
1444  }
1445  }
1446  else
1447  {
1448  ContinueFile = false;
1449  FileNode = FileNode->Next;
1450  }
1451  }
1452 
1453  if ((CurrentIBufferSize > 0) || (CurrentOBufferSize > 0))
1454  {
1455  /* A data block could span more than two
1456  disks if MaxDiskSize is very small */
1457 
1458  ASSERT(CreateNewDisk == false);
1459 
1460  do
1461  {
1462  if (CreateNewDisk)
1463  {
1464  DPRINT(MID_TRACE, ("Creating new disk 2.\n"));
1465  CommitDisk(true);
1466  CloseDisk();
1467  NewDisk();
1468  CreateNewDisk = false;
1469 
1470  ASSERT(FileNode == FileListHead);
1471  }
1472 
1473  if ((CurrentIBufferSize > 0) || (CurrentOBufferSize > 0))
1474  {
1475  Status = WriteDataBlock();
1476  if (Status != CAB_STATUS_SUCCESS)
1477  return Status;
1478  }
1479  } while (CreateNewDisk);
1480  }
1481  CommitDisk(MoreDisks);
1482 
1483  return CAB_STATUS_SUCCESS;
1484 }
1485 
1486 
1488 /*
1489  * FUNCTION: Commits the current disk
1490  * ARGUMENTS:
1491  * MoreDisks = true if there is one or more disks after this disk
1492  * RETURNS:
1493  * Status of operation
1494  */
1495 {
1496  PCFFOLDER_NODE FolderNode;
1497  ULONG Status;
1498 
1500 
1501  /* Create file, fail if it already exists */
1502  FileHandle = fopen(CabinetName, "rb");
1503  if (FileHandle != NULL)
1504  {
1505  fclose(FileHandle);
1506  /* If file exists, ask to overwrite file */
1508  {
1509  FileHandle = fopen(CabinetName, "w+b");
1510  if (FileHandle == NULL)
1511  return CAB_STATUS_CANNOT_CREATE;
1512  }
1513  else
1514  return CAB_STATUS_FILE_EXISTS;
1515 
1516  }
1517  else
1518  {
1519  FileHandle = fopen(CabinetName, "w+b");
1520  if (FileHandle == NULL)
1521  return CAB_STATUS_CANNOT_CREATE;
1522  }
1523 
1524  WriteCabinetHeader(MoreDisks != 0);
1525 
1527  if (Status != CAB_STATUS_SUCCESS)
1528  return Status;
1529 
1530  /* Write file entries */
1531  WriteFileEntries();
1532 
1533  /* Write data blocks */
1534  FolderNode = FolderListHead;
1535  while (FolderNode != NULL)
1536  {
1537  if (FolderNode->Commit)
1538  {
1539  Status = CommitDataBlocks(FolderNode);
1540  if (Status != CAB_STATUS_SUCCESS)
1541  return Status;
1542  /* Remove data blocks for folder */
1543  DestroyDataNodes(FolderNode);
1544  }
1545  FolderNode = FolderNode->Next;
1546  }
1547 
1548  fclose(FileHandle);
1549 
1550  ScratchFile->Truncate();
1551 
1552  return CAB_STATUS_SUCCESS;
1553 }
1554 
1555 
1557 /*
1558  * FUNCTION: Closes the current disk
1559  * RETURNS:
1560  * Status of operation
1561  */
1562 {
1564 
1565  /* Destroy folder nodes that are completely stored */
1567 
1569 
1570  return CAB_STATUS_SUCCESS;
1571 }
1572 
1573 
1575 /*
1576  * FUNCTION: Closes the current cabinet
1577  * RETURNS:
1578  * Status of operation
1579  */
1580 {
1581  ULONG Status;
1582 
1583  DestroyFileNodes();
1584 
1586 
1587  if (InputBuffer)
1588  {
1589  free(InputBuffer);
1590  InputBuffer = NULL;
1591  }
1592 
1593  if (OutputBuffer)
1594  {
1595  free(OutputBuffer);
1596  OutputBuffer = NULL;
1597  }
1598 
1599  Close();
1600 
1601  if (ScratchFile)
1602  {
1603  Status = ScratchFile->Destroy();
1604  delete ScratchFile;
1605  return Status;
1606  }
1607 
1608  return CAB_STATUS_SUCCESS;
1609 }
1610 
1611 
1613 /*
1614  * FUNCTION: Adds a file to the current disk
1615  * ARGUMENTS:
1616  * FileName = Pointer to string with file name (full path)
1617  * RETURNS:
1618  * Status of operation
1619  */
1620 {
1621  FILE* SrcFile;
1622  PCFFILE_NODE FileNode;
1623  char* NewFileName;
1624 
1625  NewFileName = (char*)malloc(strlen(FileName) + 1);
1626  if (!NewFileName)
1627  {
1628  DPRINT(MIN_TRACE, ("Insufficient memory.\n"));
1629  return CAB_STATUS_NOMEMORY;
1630  }
1631  strcpy(NewFileName, FileName);
1632  ConvertPath(NewFileName, false);
1633 
1634  /* Try to open file */
1635  SrcFile = fopen(NewFileName, "rb");
1636  if (SrcFile == NULL)
1637  {
1638  DPRINT(MID_TRACE, ("File not found (%s).\n", NewFileName));
1639  free(NewFileName);
1640  return CAB_STATUS_CANNOT_OPEN;
1641  }
1642 
1643  FileNode = NewFileNode();
1644  if (!FileNode)
1645  {
1646  DPRINT(MIN_TRACE, ("Insufficient memory.\n"));
1647  free(NewFileName);
1648  fclose(SrcFile);
1649  return CAB_STATUS_NOMEMORY;
1650  }
1651 
1652  FileNode->FolderNode = CurrentFolderNode;
1653  FileNode->FileName = NewFileName;
1654 
1655  /* FIXME: Check for and handle large files (>= 2GB) */
1656  FileNode->File.FileSize = GetSizeOfFile(SrcFile);
1657  if (FileNode->File.FileSize == (ULONG)-1)
1658  {
1659  DPRINT(MIN_TRACE, ("Cannot read from file.\n"));
1660  fclose(SrcFile);
1661  return CAB_STATUS_CANNOT_READ;
1662  }
1663 
1664  if (GetFileTimes(SrcFile, FileNode) != CAB_STATUS_SUCCESS)
1665  {
1666  DPRINT(MIN_TRACE, ("Cannot read file times.\n"));
1667  fclose(SrcFile);
1668  return CAB_STATUS_CANNOT_READ;
1669  }
1670 
1671  if (GetAttributesOnFile(FileNode) != CAB_STATUS_SUCCESS)
1672  {
1673  DPRINT(MIN_TRACE, ("Cannot read file attributes.\n"));
1674  fclose(SrcFile);
1675  return CAB_STATUS_CANNOT_READ;
1676  }
1677 
1678  fclose(SrcFile);
1679 
1680  return CAB_STATUS_SUCCESS;
1681 }
1682 
1684 /*
1685  * FUNCTION: Create a simple cabinet based on the files in the criteria list
1686  */
1687 {
1688  bool bRet = false;
1689  char* pszFile;
1690  char szFilePath[PATH_MAX];
1691  char szFile[PATH_MAX];
1692  PSEARCH_CRITERIA Criteria;
1693  ULONG Status;
1694 
1695 #if defined(_WIN32)
1696  HANDLE hFind;
1697  WIN32_FIND_DATA FindFileData;
1698 #else
1699  DIR* dirp;
1700  struct dirent* dp;
1701  struct stat stbuf;
1702 #endif
1703 
1704  // Initialize a new cabinet
1705  Status = NewCabinet();
1706  if (Status != CAB_STATUS_SUCCESS)
1707  {
1708  DPRINT(MIN_TRACE, ("Cannot create cabinet (%u).\n", (UINT)Status));
1709  goto cleanup2;
1710  }
1711 
1712  // Add each file in the criteria list
1713  Criteria = CriteriaListHead;
1714 
1715  while(Criteria)
1716  {
1717  // Store the file path with a trailing slash in szFilePath
1718  ConvertPath(Criteria->Search, false);
1719  pszFile = strrchr(Criteria->Search, DIR_SEPARATOR_CHAR);
1720 
1721  if(pszFile)
1722  {
1723  // Set the pointer to the start of the file name, not the slash
1724  pszFile++;
1725 
1726  strncpy(szFilePath, Criteria->Search, pszFile - Criteria->Search);
1727  szFilePath[pszFile - Criteria->Search] = 0;
1728  }
1729  else
1730  {
1731  pszFile = Criteria->Search;
1732 
1733 #if defined(_WIN32)
1734  szFilePath[0] = 0;
1735 #else
1736  // needed for opendir()
1737  strcpy(szFilePath, "./");
1738 #endif
1739  }
1740 
1741 #if defined(_WIN32)
1742  // Windows: Use the easy FindFirstFile/FindNextFile API for getting all files and checking them against the pattern
1743  hFind = FindFirstFile(Criteria->Search, &FindFileData);
1744 
1745  // Don't stop if a search criteria is not found
1747  {
1748  DPRINT(MIN_TRACE, ("FindFirstFile failed, Criteria: %s, error code is %u\n", Criteria->Search, (UINT)GetLastError()));
1749  goto cleanup;
1750  }
1751 
1752  do
1753  {
1754  if(!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
1755  {
1756  strcpy(szFile, szFilePath);
1757  strcat(szFile, FindFileData.cFileName);
1758 
1759  Status = AddFile(szFile);
1760 
1761  if(Status != CAB_STATUS_SUCCESS)
1762  {
1763  DPRINT(MIN_TRACE, ("Cannot add file to cabinet (%u).\n", (UINT)Status));
1764  goto cleanup;
1765  }
1766  }
1767  }
1768  while(FindNextFile(hFind, &FindFileData));
1769 
1770  FindClose(hFind);
1771 #else
1772  // Unix: Use opendir/readdir to loop through all entries, stat to check if it's a file and MatchFileNamePattern to match the file against the pattern
1773  dirp = opendir(szFilePath);
1774 
1775  if(dirp)
1776  {
1777  while( (dp = readdir(dirp)) )
1778  {
1779  strcpy(szFile, szFilePath);
1780  strcat(szFile, dp->d_name);
1781 
1782  if(stat(szFile, &stbuf) == 0)
1783  {
1784  if(stbuf.st_mode != S_IFDIR)
1785  {
1786  if(MatchFileNamePattern(dp->d_name, pszFile))
1787  {
1788  Status = AddFile(szFile);
1789 
1790  if(Status != CAB_STATUS_SUCCESS)
1791  {
1792  DPRINT(MIN_TRACE, ("Cannot add file to cabinet (%u).\n", (UINT)Status));
1793  goto cleanup;
1794  }
1795  }
1796  }
1797  }
1798  else
1799  {
1800  DPRINT(MIN_TRACE, ("stat failed, error code is %i\n", errno));
1801  goto cleanup;
1802  }
1803  }
1804 
1805  closedir(dirp);
1806  }
1807 #endif
1808 
1809  Criteria = Criteria->Next;
1810  }
1811 
1812  Status = WriteDisk(false);
1813  if (Status == CAB_STATUS_SUCCESS)
1814  Status = CloseDisk();
1815  if (Status != CAB_STATUS_SUCCESS)
1816  {
1817  DPRINT(MIN_TRACE, ("Cannot write disk (%u).\n", (UINT)Status));
1818  goto cleanup;
1819  }
1820 
1821 cleanup:
1822  CloseCabinet();
1823  bRet = true;
1824 
1825 cleanup2:
1827  return bRet;
1828 }
1829 
1831 /*
1832  * FUNCTION: Sets the maximum size of the current disk
1833  * ARGUMENTS:
1834  * Size = Maximum size of current disk (0 means no maximum size)
1835  */
1836 {
1837  MaxDiskSize = Size;
1838 }
1839 
1840 #endif /* CAB_READ_ONLY */
1841 
1842 
1843 /* Default event handlers */
1844 
1846  char* FileName)
1847 /*
1848  * FUNCTION: Called when extracting a file and it already exists
1849  * ARGUMENTS:
1850  * File = Pointer to CFFILE for file being extracted
1851  * FileName = Pointer to buffer with name of file (full path)
1852  * RETURNS
1853  * true if the file should be overwritten, false if not
1854  */
1855 {
1856  return false;
1857 }
1858 
1859 
1861  char* FileName)
1862 /*
1863  * FUNCTION: Called just before extracting a file
1864  * ARGUMENTS:
1865  * File = Pointer to CFFILE for file being extracted
1866  * FileName = Pointer to buffer with name of file (full path)
1867  */
1868 {
1869 }
1870 
1871 
1872 void CCabinet::OnDiskChange(char* CabinetName,
1873  char* DiskLabel)
1874 /*
1875  * FUNCTION: Called when a new disk is to be processed
1876  * ARGUMENTS:
1877  * CabinetName = Pointer to buffer with name of cabinet
1878  * DiskLabel = Pointer to buffer with label of disk
1879  */
1880 {
1881 }
1882 
1883 
1884 #ifndef CAB_READ_ONLY
1885 
1887  char* FileName)
1888 /*
1889  * FUNCTION: Called just before adding a file to a cabinet
1890  * ARGUMENTS:
1891  * File = Pointer to CFFILE for file being added
1892  * FileName = Pointer to buffer with name of file (full path)
1893  */
1894 {
1895 }
1896 
1897 
1899 /*
1900  * FUNCTION: Called when a disk needs a label
1901  * ARGUMENTS:
1902  * Number = Cabinet number that needs a label
1903  * Label = Pointer to buffer to place label of disk
1904  * RETURNS:
1905  * true if a disk label was returned, false if not
1906  */
1907 {
1908  return false;
1909 }
1910 
1911 
1913 /*
1914  * FUNCTION: Called when a cabinet needs a name
1915  * ARGUMENTS:
1916  * Number = Disk number that needs a name
1917  * Name = Pointer to buffer to place name of cabinet
1918  * RETURNS:
1919  * true if a cabinet name was returned, false if not
1920  */
1921 {
1922  return false;
1923 }
1924 
1925 #endif /* CAB_READ_ONLY */
1926 
1928 /*
1929  * FUNCTION: Locates a folder node
1930  * ARGUMENTS:
1931  * Index = Folder index
1932  * RETURNS:
1933  * Pointer to folder node or NULL if the folder node was not found
1934  */
1935 {
1937 
1938  switch (Index)
1939  {
1940  case CAB_FILE_SPLIT:
1941  return FolderListTail;
1942 
1943  case CAB_FILE_CONTINUED:
1944  case CAB_FILE_PREV_NEXT:
1945  return FolderListHead;
1946  }
1947 
1948  Node = FolderListHead;
1949  while (Node != NULL)
1950  {
1951  if (Node->Index == Index)
1952  return Node;
1953  Node = Node->Next;
1954  }
1955  return NULL;
1956 }
1957 
1958 
1960 /*
1961  * FUNCTION: Returns the absolute offset of a file
1962  * ARGUMENTS:
1963  * File = Pointer to CFFILE_NODE structure for file
1964  * RETURNS:
1965  * Status of operation
1966  */
1967 {
1969 
1970  DPRINT(MAX_TRACE, ("FileName '%s' FileOffset (0x%X) FileSize (%u).\n",
1971  File->FileName,
1972  (UINT)File->File.FileOffset,
1973  (UINT)File->File.FileSize));
1974 
1976  while (Node != NULL)
1977  {
1978  DPRINT(MAX_TRACE, ("GetAbsoluteOffset(): Comparing (0x%X, 0x%X) (%u).\n",
1979  (UINT)Node->UncompOffset,
1980  (UINT)(Node->UncompOffset + Node->Data.UncompSize),
1981  (UINT)Node->Data.UncompSize));
1982 
1983  /* Node->Data.UncompSize will be 0 if the block is split
1984  (ie. it is the last block in this cabinet) */
1985  if ((Node->Data.UncompSize == 0) ||
1986  ((File->File.FileOffset >= Node->UncompOffset) &&
1987  (File->File.FileOffset < Node->UncompOffset +
1988  Node->Data.UncompSize)))
1989  {
1990  File->DataBlock = Node;
1991  return CAB_STATUS_SUCCESS;
1992  }
1993 
1994  Node = Node->Next;
1995  }
1996  return CAB_STATUS_INVALID_CAB;
1997 }
1998 
1999 
2001  PCFFILE_NODE *File)
2002 /*
2003  * FUNCTION: Locates a file in the cabinet
2004  * ARGUMENTS:
2005  * FileName = Pointer to string with name of file to locate
2006  * File = Address of pointer to CFFILE_NODE structure to fill
2007  * RETURNS:
2008  * Status of operation
2009  * NOTES:
2010  * Current folder is set to the folder of the file
2011  */
2012 {
2014  ULONG Status;
2015 
2016  DPRINT(MAX_TRACE, ("FileName '%s'\n", FileName));
2017 
2018  Node = FileListHead;
2019  while (Node != NULL)
2020  {
2021  if (strcasecmp(FileName, Node->FileName) == 0)
2022  {
2023  CurrentFolderNode = LocateFolderNode(Node->File.FileControlID);
2024  if (!CurrentFolderNode)
2025  {
2026  DPRINT(MID_TRACE, ("Folder with index number (%u) not found.\n",
2027  Node->File.FileControlID));
2028  return CAB_STATUS_INVALID_CAB;
2029  }
2030 
2031  if (Node->DataBlock == NULL)
2033  else
2035 
2036  *File = Node;
2037  return Status;
2038  }
2039  Node = Node->Next;
2040  }
2041  return CAB_STATUS_NOFILE;
2042 }
2043 
2044 
2046 /*
2047  * FUNCTION: Reads a NULL-terminated string from the cabinet
2048  * ARGUMENTS:
2049  * String = Pointer to buffer to place string
2050  * MaxLength = Maximum length of string
2051  * RETURNS:
2052  * Status of operation
2053  */
2054 {
2055  ULONG BytesRead;
2056  ULONG Status;
2057  LONG Size;
2058  bool Found;
2059 
2060  Found = false;
2061 
2062  Status = ReadBlock(String, MaxLength, &BytesRead);
2063  if (Status != CAB_STATUS_SUCCESS)
2064  {
2065  DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
2066  return CAB_STATUS_INVALID_CAB;
2067  }
2068 
2069  // Find the terminating NULL character
2070  for (Size = 0; Size < MaxLength; Size++)
2071  {
2072  if (String[Size] == '\0')
2073  {
2074  Found = true;
2075  break;
2076  }
2077  }
2078 
2079  if (!Found)
2080  {
2081  DPRINT(MIN_TRACE, ("Filename in the cabinet file is too long.\n"));
2082  return CAB_STATUS_INVALID_CAB;
2083  }
2084 
2085  // Compute the offset of the next CFFILE.
2086  // We have to subtract from the current offset here, because we read MaxLength characters above and most-probably the file name isn't MaxLength characters long.
2087  // + 1 to skip the terminating NULL character as well.
2088  Size = -(MaxLength - Size) + 1;
2089 
2090  if (fseek(FileHandle, (off_t)Size, SEEK_CUR) != 0)
2091  {
2092  DPRINT(MIN_TRACE, ("fseek() failed.\n"));
2093  return CAB_STATUS_INVALID_CAB;
2094  }
2095 
2096  return CAB_STATUS_SUCCESS;
2097 }
2098 
2099 
2101 /*
2102  * FUNCTION: Reads the file table from the cabinet file
2103  * RETURNS:
2104  * Status of operation
2105  */
2106 {
2107  ULONG i;
2108  ULONG Status;
2109  ULONG BytesRead;
2111 
2112  DPRINT(MAX_TRACE, ("Reading file table at absolute offset (0x%X).\n",
2113  (UINT)CABHeader.FileTableOffset));
2114 
2115  /* Seek to file table */
2116  if (fseek(FileHandle, (off_t)CABHeader.FileTableOffset, SEEK_SET) != 0)
2117  {
2118  DPRINT(MIN_TRACE, ("fseek() failed.\n"));
2119  return CAB_STATUS_INVALID_CAB;
2120  }
2121 
2122  for (i = 0; i < CABHeader.FileCount; i++)
2123  {
2124  File = NewFileNode();
2125  if (!File)
2126  {
2127  DPRINT(MIN_TRACE, ("Insufficient memory.\n"));
2128  return CAB_STATUS_NOMEMORY;
2129  }
2130 
2131  if ((Status = ReadBlock(&File->File, sizeof(CFFILE),
2133  {
2134  DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
2135  return CAB_STATUS_INVALID_CAB;
2136  }
2137 
2138  File->FileName = (char*)malloc(PATH_MAX);
2139  if (!File->FileName)
2140  {
2141  DPRINT(MIN_TRACE, ("Insufficient memory.\n"));
2142  return CAB_STATUS_NOMEMORY;
2143  }
2144 
2145  /* Read file name */
2146  Status = ReadString(File->FileName, PATH_MAX);
2147  if (Status != CAB_STATUS_SUCCESS)
2148  return Status;
2149 
2150  DPRINT(MAX_TRACE, ("Found file '%s' at uncompressed offset (0x%X). Size (%u bytes) ControlId (0x%X).\n",
2151  File->FileName,
2152  (UINT)File->File.FileOffset,
2153  (UINT)File->File.FileSize,
2154  File->File.FileControlID));
2155 
2156  }
2157  return CAB_STATUS_SUCCESS;
2158 }
2159 
2160 
2162 /*
2163  * FUNCTION: Reads all CFDATA blocks for a folder from the cabinet file
2164  * ARGUMENTS:
2165  * FolderNode = Pointer to CFFOLDER_NODE structure for folder
2166  * RETURNS:
2167  * Status of operation
2168  */
2169 {
2170  ULONG AbsoluteOffset;
2171  ULONG UncompOffset;
2173  ULONG BytesRead;
2174  ULONG Status;
2175  ULONG i;
2176 
2177  DPRINT(MAX_TRACE, ("Reading data blocks for folder (%u) at absolute offset (0x%X).\n",
2178  (UINT)FolderNode->Index, (UINT)FolderNode->Folder.DataOffset));
2179 
2180  AbsoluteOffset = FolderNode->Folder.DataOffset;
2181  UncompOffset = FolderNode->UncompOffset;
2182 
2183  for (i = 0; i < FolderNode->Folder.DataBlockCount; i++)
2184  {
2185  Node = NewDataNode(FolderNode);
2186  if (!Node)
2187  {
2188  DPRINT(MIN_TRACE, ("Insufficient memory.\n"));
2189  return CAB_STATUS_NOMEMORY;
2190  }
2191 
2192  /* Seek to data block */
2193  if (fseek(FileHandle, (off_t)AbsoluteOffset, SEEK_SET) != 0)
2194  {
2195  DPRINT(MIN_TRACE, ("fseek() failed.\n"));
2196  return CAB_STATUS_INVALID_CAB;
2197  }
2198 
2199  if ((Status = ReadBlock(&Node->Data, sizeof(CFDATA),
2201  {
2202  DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
2203  return CAB_STATUS_INVALID_CAB;
2204  }
2205 
2206  DPRINT(MAX_TRACE, ("AbsOffset (0x%X) UncompOffset (0x%X) Checksum (0x%X) CompSize (%u) UncompSize (%u).\n",
2207  (UINT)AbsoluteOffset,
2208  (UINT)UncompOffset,
2209  (UINT)Node->Data.Checksum,
2210  Node->Data.CompSize,
2211  Node->Data.UncompSize));
2212 
2213  Node->AbsoluteOffset = AbsoluteOffset;
2214  Node->UncompOffset = UncompOffset;
2215 
2216  AbsoluteOffset += sizeof(CFDATA) + Node->Data.CompSize;
2217  UncompOffset += Node->Data.UncompSize;
2218  }
2219 
2220  FolderUncompSize = UncompOffset;
2221 
2222  return CAB_STATUS_SUCCESS;
2223 }
2224 
2225 
2227 /*
2228  * FUNCTION: Creates a new folder node
2229  * RETURNS:
2230  * Pointer to node if there was enough free memory available, otherwise NULL
2231  */
2232 {
2234 
2236  if (!Node)
2237  return NULL;
2238 
2239  memset(Node, 0, sizeof(CFFOLDER_NODE));
2240 
2241  Node->Folder.CompressionType = CAB_COMP_NONE;
2242 
2243  Node->Prev = FolderListTail;
2244 
2245  if (FolderListTail != NULL)
2247  else
2248  FolderListHead = Node;
2249 
2250  FolderListTail = Node;
2251 
2252  return Node;
2253 }
2254 
2255 
2257 /*
2258  * FUNCTION: Creates a new file node
2259  * ARGUMENTS:
2260  * FolderNode = Pointer to folder node to bind file to
2261  * RETURNS:
2262  * Pointer to node if there was enough free memory available, otherwise NULL
2263  */
2264 {
2266 
2267  Node = (PCFFILE_NODE)malloc(sizeof(CFFILE_NODE));
2268  if (!Node)
2269  return NULL;
2270 
2271  memset(Node, 0, sizeof(CFFILE_NODE));
2272 
2273  Node->Prev = FileListTail;
2274 
2275  if (FileListTail != NULL)
2276  FileListTail->Next = Node;
2277  else
2278  FileListHead = Node;
2279 
2280  FileListTail = Node;
2281 
2282  return Node;
2283 }
2284 
2285 
2287 /*
2288  * FUNCTION: Creates a new data block node
2289  * ARGUMENTS:
2290  * FolderNode = Pointer to folder node to bind data block to
2291  * RETURNS:
2292  * Pointer to node if there was enough free memory available, otherwise NULL
2293  */
2294 {
2296 
2297  Node = (PCFDATA_NODE)malloc(sizeof(CFDATA_NODE));
2298  if (!Node)
2299  return NULL;
2300 
2301  memset(Node, 0, sizeof(CFDATA_NODE));
2302 
2303  Node->Prev = FolderNode->DataListTail;
2304 
2305  if (FolderNode->DataListTail != NULL)
2306  FolderNode->DataListTail->Next = Node;
2307  else
2308  FolderNode->DataListHead = Node;
2309 
2310  FolderNode->DataListTail = Node;
2311 
2312  return Node;
2313 }
2314 
2315 
2317 /*
2318  * FUNCTION: Destroys data block nodes bound to a folder node
2319  * ARGUMENTS:
2320  * FolderNode = Pointer to folder node
2321  */
2322 {
2323  PCFDATA_NODE PrevNode;
2324  PCFDATA_NODE NextNode;
2325 
2326  NextNode = FolderNode->DataListHead;
2327  while (NextNode != NULL)
2328  {
2329  PrevNode = NextNode->Next;
2330  free(NextNode);
2331  NextNode = PrevNode;
2332  }
2333  FolderNode->DataListHead = NULL;
2334  FolderNode->DataListTail = NULL;
2335 }
2336 
2337 
2339 /*
2340  * FUNCTION: Destroys file nodes
2341  */
2342 {
2343  PCFFILE_NODE PrevNode;
2344  PCFFILE_NODE NextNode;
2345 
2346  NextNode = FileListHead;
2347  while (NextNode != NULL)
2348  {
2349  PrevNode = NextNode->Next;
2350  if (NextNode->FileName)
2351  free(NextNode->FileName);
2352  free(NextNode);
2353  NextNode = PrevNode;
2354  }
2355  FileListHead = NULL;
2356  FileListTail = NULL;
2357 }
2358 
2359 
2361 /*
2362  * FUNCTION: Destroys file nodes that are marked for deletion
2363  */
2364 {
2365  PCFFILE_NODE CurNode;
2366  PCFFILE_NODE NextNode;
2367 
2368  CurNode = FileListHead;
2369  while (CurNode != NULL)
2370  {
2371  NextNode = CurNode->Next;
2372 
2373  if (CurNode->Delete)
2374  {
2375  if (CurNode->Prev != NULL)
2376  CurNode->Prev->Next = CurNode->Next;
2377  else
2378  {
2379  FileListHead = CurNode->Next;
2380  if (FileListHead)
2381  FileListHead->Prev = NULL;
2382  }
2383 
2384  if (CurNode->Next != NULL)
2385  CurNode->Next->Prev = CurNode->Prev;
2386  else
2387  {
2388  FileListTail = CurNode->Prev;
2389  if (FileListTail)
2390  FileListTail->Next = NULL;
2391  }
2392 
2393  DPRINT(MAX_TRACE, ("Deleting file: '%s'\n", CurNode->FileName));
2394 
2395  TotalFileSize -= (sizeof(CFFILE) + (ULONG)strlen(GetFileName(CurNode->FileName)) + 1);
2396 
2397  if (CurNode->FileName)
2398  free(CurNode->FileName);
2399  free(CurNode);
2400  }
2401  CurNode = NextNode;
2402  }
2403 }
2404 
2405 
2407 /*
2408  * FUNCTION: Destroys folder nodes
2409  */
2410 {
2411  PCFFOLDER_NODE PrevNode;
2412  PCFFOLDER_NODE NextNode;
2413 
2414  NextNode = FolderListHead;
2415  while (NextNode != NULL)
2416  {
2417  PrevNode = NextNode->Next;
2418  DestroyDataNodes(NextNode);
2419  free(NextNode);
2420  NextNode = PrevNode;
2421  }
2422  FolderListHead = NULL;
2423  FolderListTail = NULL;
2424 }
2425 
2426 
2428 /*
2429  * FUNCTION: Destroys folder nodes that are marked for deletion
2430  */
2431 {
2432  PCFFOLDER_NODE CurNode;
2433  PCFFOLDER_NODE NextNode;
2434 
2435  CurNode = FolderListHead;
2436  while (CurNode != NULL)
2437  {
2438  NextNode = CurNode->Next;
2439 
2440  if (CurNode->Delete)
2441  {
2442  if (CurNode->Prev != NULL)
2443  CurNode->Prev->Next = CurNode->Next;
2444  else
2445  {
2446  FolderListHead = CurNode->Next;
2447  if (FolderListHead)
2449  }
2450 
2451  if (CurNode->Next != NULL)
2452  CurNode->Next->Prev = CurNode->Prev;
2453  else
2454  {
2455  FolderListTail = CurNode->Prev;
2456  if (FolderListTail)
2458  }
2459 
2460  DestroyDataNodes(CurNode);
2461  free(CurNode);
2462 
2463  TotalFolderSize -= sizeof(CFFOLDER);
2464  }
2465  CurNode = NextNode;
2466  }
2467 }
2468 
2469 
2471  ULONG Size,
2472  ULONG Seed)
2473 /*
2474  * FUNCTION: Computes checksum for data block
2475  * ARGUMENTS:
2476  * Buffer = Pointer to data buffer
2477  * Size = Length of data buffer
2478  * Seed = Previously computed checksum
2479  * RETURNS:
2480  * Checksum of buffer
2481  */
2482 {
2483  int UlongCount; // Number of ULONGs in block
2484  ULONG Checksum; // Checksum accumulator
2485  unsigned char* pb;
2486  ULONG ul;
2487 
2488  /* FIXME: Doesn't seem to be correct. EXTRACT.EXE
2489  won't accept checksums computed by this routine */
2490 
2491  DPRINT(MIN_TRACE, ("Checksumming buffer (0x%p) Size (%u)\n", Buffer, (UINT)Size));
2492 
2493  UlongCount = Size / 4; // Number of ULONGs
2494  Checksum = Seed; // Init checksum
2495  pb = (unsigned char*)Buffer; // Start at front of data block
2496 
2497  /* Checksum integral multiple of ULONGs */
2498  while (UlongCount-- > 0)
2499  {
2500  /* NOTE: Build ULONG in big/little-endian independent manner */
2501  ul = *pb++; // Get low-order byte
2502  ul |= (((ULONG)(*pb++)) << 8); // Add 2nd byte
2503  ul |= (((ULONG)(*pb++)) << 16); // Add 3nd byte
2504  ul |= (((ULONG)(*pb++)) << 24); // Add 4th byte
2505 
2506  Checksum ^= ul; // Update checksum
2507  }
2508 
2509  /* Checksum remainder bytes */
2510  ul = 0;
2511  switch (Size % 4)
2512  {
2513  case 3:
2514  ul |= (((ULONG)(*pb++)) << 16); // Add 3rd byte
2515  case 2:
2516  ul |= (((ULONG)(*pb++)) << 8); // Add 2nd byte
2517  case 1:
2518  ul |= *pb++; // Get low-order byte
2519  default:
2520  break;
2521  }
2522  Checksum ^= ul; // Update checksum
2523 
2524  /* Return computed checksum */
2525  return Checksum;
2526 }
2527 
2528 
2530  ULONG Size,
2531  PULONG BytesRead)
2532 /*
2533  * FUNCTION: Read a block of data from file
2534  * ARGUMENTS:
2535  * Buffer = Pointer to data buffer
2536  * Size = Length of data buffer
2537  * BytesRead = Pointer to ULONG that on return will contain
2538  * number of bytes read
2539  * RETURNS:
2540  * Status of operation
2541  */
2542 {
2544  if ( *BytesRead != Size )
2545  return CAB_STATUS_INVALID_CAB;
2546  return CAB_STATUS_SUCCESS;
2547 }
2548 
2549 bool CCabinet::MatchFileNamePattern(char* FileName, char* Pattern)
2550 /*
2551  * FUNCTION: Matches a wildcard character pattern against a file
2552  * ARGUMENTS:
2553  * FileName = The file name to check
2554  * Pattern = The pattern
2555  * RETURNS:
2556  * Whether the pattern matches the file
2557  *
2558  * COPYRIGHT:
2559  * This function is based on Busybox code, Copyright (C) 1998 by Erik Andersen, released under GPL2 or any later version.
2560  * Adapted from code written by Ingo Wilken.
2561  * Original location: http://www.busybox.net/cgi-bin/viewcvs.cgi/trunk/busybox/utility.c?rev=5&view=markup
2562  */
2563 {
2564  char* retryPattern = NULL;
2565  char* retryFileName = NULL;
2566  char ch;
2567 
2568  while (*FileName || *Pattern)
2569  {
2570  ch = *Pattern++;
2571 
2572  switch (ch)
2573  {
2574  case '*':
2575  retryPattern = Pattern;
2576  retryFileName = FileName;
2577  break;
2578 
2579  case '?':
2580  if (*FileName++ == '\0')
2581  return false;
2582 
2583  break;
2584 
2585  default:
2586  if (*FileName == ch)
2587  {
2588  if (*FileName)
2589  FileName++;
2590  break;
2591  }
2592 
2593  if (*FileName)
2594  {
2595  Pattern = retryPattern;
2596  FileName = ++retryFileName;
2597  break;
2598  }
2599 
2600  return false;
2601  }
2602 
2603  if (!Pattern)
2604  return false;
2605  }
2606 
2607  return true;
2608 }
2609 
2610 #ifndef CAB_READ_ONLY
2611 
2613 /*
2614  * FUNCTION: Initializes cabinet header and optional fields
2615  * RETURNS:
2616  * Status of operation
2617  */
2618 {
2619  ULONG TotalSize;
2620  ULONG Size;
2621 
2622  CABHeader.FileTableOffset = 0; // Not known yet
2623  CABHeader.FolderCount = 0; // Not known yet
2624  CABHeader.FileCount = 0; // Not known yet
2625  CABHeader.Flags = 0; // Not known yet
2626 
2627  CABHeader.CabinetNumber = (USHORT)CurrentDiskNumber;
2628 
2630  {
2631  CABHeader.Flags |= CAB_FLAG_HASPREV;
2633  strcpy(CabinetPrev, "");
2634  }
2635 
2637  {
2638  CABHeader.Flags |= CAB_FLAG_HASNEXT;
2640  strcpy(DiskNext, "");
2641  }
2642 
2643  TotalSize = 0;
2644 
2645  if ((CABHeader.Flags & CAB_FLAG_HASPREV) > 0)
2646  {
2647 
2648  DPRINT(MAX_TRACE, ("CabinetPrev '%s'.\n", CabinetPrev));
2649 
2650  /* Calculate size of name of previous cabinet */
2651  TotalSize += (ULONG)strlen(CabinetPrev) + 1;
2652 
2653  /* Calculate size of label of previous disk */
2654  TotalSize += (ULONG)strlen(DiskPrev) + 1;
2655  }
2656 
2657  if ((CABHeader.Flags & CAB_FLAG_HASNEXT) > 0)
2658  {
2659 
2660  DPRINT(MAX_TRACE, ("CabinetNext '%s'.\n", CabinetNext));
2661 
2662  /* Calculate size of name of next cabinet */
2663  Size = (ULONG)strlen(CabinetNext) + 1;
2664  TotalSize += Size;
2665  NextFieldsSize = Size;
2666 
2667  /* Calculate size of label of next disk */
2668  Size = (ULONG)strlen(DiskNext) + 1;
2669  TotalSize += Size;
2670  NextFieldsSize += Size;
2671  }
2672  else
2673  NextFieldsSize = 0;
2674 
2675  /* Add cabinet reserved area size if present */
2676  if (CabinetReservedFileSize > 0)
2677  {
2678  CABHeader.Flags |= CAB_FLAG_RESERVE;
2679  TotalSize += CabinetReservedFileSize;
2680  TotalSize += sizeof(ULONG); /* For CabinetResSize, FolderResSize, and FileResSize fields */
2681  }
2682 
2683  DiskSize += TotalSize;
2684 
2685  TotalHeaderSize = sizeof(CFHEADER) + TotalSize;
2686 
2687  return CAB_STATUS_SUCCESS;
2688 }
2689 
2690 
2692 /*
2693  * FUNCTION: Writes the cabinet header and optional fields
2694  * ARGUMENTS:
2695  * MoreDisks = true if next cabinet name should be included
2696  * RETURNS:
2697  * Status of operation
2698  */
2699 {
2700  PCFFOLDER_NODE FolderNode;
2701  PCFFILE_NODE FileNode;
2703  ULONG Size;
2704 
2705  if (MoreDisks)
2706  {
2707  CABHeader.Flags |= CAB_FLAG_HASNEXT;
2709  }
2710  else
2711  {
2712  CABHeader.Flags &= ~CAB_FLAG_HASNEXT;
2715  }
2716 
2717  /* Set absolute folder offsets */
2719  CABHeader.FolderCount = 0;
2720  FolderNode = FolderListHead;
2721  while (FolderNode != NULL)
2722  {
2723  FolderNode->Folder.DataOffset = BytesWritten;
2724 
2725  BytesWritten += FolderNode->TotalFolderSize;
2726 
2727  CABHeader.FolderCount++;
2728 
2729  FolderNode = FolderNode->Next;
2730  }
2731 
2732  /* Set absolute offset of file table */
2733  CABHeader.FileTableOffset = Size + TotalFolderSize;
2734 
2735  /* Count number of files to be committed */
2736  CABHeader.FileCount = 0;
2737  FileNode = FileListHead;
2738  while (FileNode != NULL)
2739  {
2740  if (FileNode->Commit)
2741  CABHeader.FileCount++;
2742  FileNode = FileNode->Next;
2743  }
2744 
2745  CABHeader.CabinetSize = DiskSize;
2746 
2747  /* Write header */
2748  if (fwrite(&CABHeader, sizeof(CFHEADER), 1, FileHandle) < 1)
2749  {
2750  DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
2751  return CAB_STATUS_CANNOT_WRITE;
2752  }
2753 
2754  /* Write per-cabinet reserved area if present */
2755  if (CABHeader.Flags & CAB_FLAG_RESERVE)
2756  {
2757  ULONG ReservedSize;
2758 
2759  ReservedSize = CabinetReservedFileSize & 0xffff;
2760  ReservedSize |= (0 << 16); /* Folder reserved area size */
2761  ReservedSize |= (0 << 24); /* Folder reserved area size */
2762 
2763  BytesWritten = sizeof(ULONG);
2764  if (fwrite(&ReservedSize, sizeof(ULONG), 1, FileHandle) < 1)
2765  {
2766  DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
2767  return CAB_STATUS_CANNOT_WRITE;
2768  }
2769 
2772  {
2773  DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
2774  return CAB_STATUS_CANNOT_WRITE;
2775  }
2776  }
2777 
2778  if ((CABHeader.Flags & CAB_FLAG_HASPREV) > 0)
2779  {
2780  DPRINT(MAX_TRACE, ("CabinetPrev '%s'.\n", CabinetPrev));
2781 
2782  /* Write name of previous cabinet */
2783  Size = (ULONG)strlen(CabinetPrev) + 1;
2784  BytesWritten = Size;
2785  if (fwrite(CabinetPrev, Size, 1, FileHandle) < 1)
2786  {
2787  DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
2788  return CAB_STATUS_CANNOT_WRITE;
2789  }
2790 
2791  DPRINT(MAX_TRACE, ("DiskPrev '%s'.\n", DiskPrev));
2792 
2793  /* Write label of previous disk */
2794  Size = (ULONG)strlen(DiskPrev) + 1;
2795  BytesWritten = Size;
2796  if (fwrite(DiskPrev, Size, 1, FileHandle) < 1)
2797  {
2798  DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
2799  return CAB_STATUS_CANNOT_WRITE;
2800  }
2801  }
2802 
2803  if ((CABHeader.Flags & CAB_FLAG_HASNEXT) > 0)
2804  {
2805  DPRINT(MAX_TRACE, ("CabinetNext '%s'.\n", CabinetNext));
2806 
2807  /* Write name of next cabinet */
2808  Size = (ULONG)strlen(CabinetNext) + 1;
2809  BytesWritten = Size;
2810  if (fwrite(CabinetNext, Size, 1, FileHandle) < 1)
2811  {
2812  DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
2813  return CAB_STATUS_CANNOT_WRITE;
2814  }
2815 
2816  DPRINT(MAX_TRACE, ("DiskNext '%s'.\n", DiskNext));
2817 
2818  /* Write label of next disk */
2819  Size = (ULONG)strlen(DiskNext) + 1;
2820  BytesWritten = Size;
2821  if (fwrite(DiskNext, Size, 1, FileHandle) < 1)
2822  {
2823  DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
2824  return CAB_STATUS_CANNOT_WRITE;
2825  }
2826  }
2827 
2828  return CAB_STATUS_SUCCESS;
2829 }
2830 
2831 
2833 /*
2834  * FUNCTION: Writes folder entries
2835  * RETURNS:
2836  * Status of operation
2837  */
2838 {
2839  PCFFOLDER_NODE FolderNode;
2840 
2841  DPRINT(MAX_TRACE, ("Writing folder table.\n"));
2842 
2843  FolderNode = FolderListHead;
2844  while (FolderNode != NULL)
2845  {
2846  if (FolderNode->Commit)
2847  {
2848  DPRINT(MAX_TRACE, ("Writing folder entry. CompressionType (0x%X) DataBlockCount (%d) DataOffset (0x%X).\n",
2849  FolderNode->Folder.CompressionType, FolderNode->Folder.DataBlockCount, (UINT)FolderNode->Folder.DataOffset));
2850 
2851  if (fwrite(&FolderNode->Folder, sizeof(CFFOLDER), 1, FileHandle) < 1)
2852  {
2853  DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
2854  return CAB_STATUS_CANNOT_WRITE;
2855  }
2856  }
2857  FolderNode = FolderNode->Next;
2858  }
2859 
2860  return CAB_STATUS_SUCCESS;
2861 }
2862 
2863 
2865 /*
2866  * FUNCTION: Writes file entries for all files
2867  * RETURNS:
2868  * Status of operation
2869  */
2870 {
2872  bool SetCont = false;
2873 
2874  DPRINT(MAX_TRACE, ("Writing file table.\n"));
2875 
2876  File = FileListHead;
2877  while (File != NULL)
2878  {
2879  if (File->Commit)
2880  {
2881  /* Remove any continued files that ends in this disk */
2882  if (File->File.FileControlID == CAB_FILE_CONTINUED)
2883  File->Delete = true;
2884 
2885  /* The file could end in the last (split) block and should therefore
2886  appear in the next disk too */
2887 
2888  if ((File->File.FileOffset + File->File.FileSize >= LastBlockStart) &&
2889  (File->File.FileControlID <= CAB_FILE_MAX_FOLDER) && (BlockIsSplit))
2890  {
2891  File->File.FileControlID = CAB_FILE_SPLIT;
2892  File->Delete = false;
2893  SetCont = true;
2894  }
2895 
2896  DPRINT(MAX_TRACE, ("Writing file entry. FileControlID (0x%X) FileOffset (0x%X) FileSize (%u) FileName (%s).\n",
2897  File->File.FileControlID, (UINT)File->File.FileOffset, (UINT)File->File.FileSize, File->FileName));
2898 
2899  if (fwrite(&File->File, sizeof(CFFILE), 1, FileHandle) < 1)
2900  {
2901  DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
2902  return CAB_STATUS_CANNOT_WRITE;
2903  }
2904 
2905  if (fwrite(GetFileName(File->FileName), strlen(GetFileName(File->FileName)) + 1, 1, FileHandle) < 1)
2906  {
2907  DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
2908  return CAB_STATUS_CANNOT_WRITE;
2909  }
2910 
2911  if (SetCont)
2912  {
2913  File->File.FileControlID = CAB_FILE_CONTINUED;
2914  SetCont = false;
2915  }
2916  }
2917 
2918  File = File->Next;
2919  }
2920  return CAB_STATUS_SUCCESS;
2921 }
2922 
2923 
2925 /*
2926  * FUNCTION: Writes data blocks to the cabinet
2927  * ARGUMENTS:
2928  * FolderNode = Pointer to folder node containing the data blocks
2929  * RETURNS:
2930  * Status of operation
2931  */
2932 {
2933  PCFDATA_NODE DataNode;
2934  ULONG BytesRead;
2935  ULONG Status;
2936 
2937  DataNode = FolderNode->DataListHead;
2938  if (DataNode != NULL)
2940 
2941  while (DataNode != NULL)
2942  {
2943  DPRINT(MAX_TRACE, ("Reading block at (0x%X) CompSize (%u) UncompSize (%u).\n",
2944  (UINT)DataNode->ScratchFilePosition,
2945  DataNode->Data.CompSize,
2946  DataNode->Data.UncompSize));
2947 
2948  /* InputBuffer is free for us to use here, so we use it and avoid a
2949  memory allocation. OutputBuffer can't be used here because it may
2950  still contain valid data (if a data block spans two or more disks) */
2952  if (Status != CAB_STATUS_SUCCESS)
2953  {
2954  DPRINT(MIN_TRACE, ("Cannot read from scratch file (%u).\n", (UINT)Status));
2955  return Status;
2956  }
2957 
2958  if (fwrite(&DataNode->Data, sizeof(CFDATA), 1, FileHandle) < 1)
2959  {
2960  DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
2961  return CAB_STATUS_CANNOT_WRITE;
2962  }
2963 
2964  if (fwrite(InputBuffer, DataNode->Data.CompSize, 1, FileHandle) < 1)
2965  {
2966  DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
2967  return CAB_STATUS_CANNOT_WRITE;
2968  }
2969 
2970  DataNode = DataNode->Next;
2971  }
2972  return CAB_STATUS_SUCCESS;
2973 }
2974 
2975 
2977 /*
2978  * FUNCTION: Writes the current data block to the scratch file
2979  * RETURNS:
2980  * Status of operation
2981  */
2982 {
2983  ULONG Status;
2985  PCFDATA_NODE DataNode;
2986 
2987  if (!BlockIsSplit)
2988  {
2990  InputBuffer,
2992  &TotalCompSize);
2993 
2994  DPRINT(MAX_TRACE, ("Block compressed. CurrentIBufferSize (%u) TotalCompSize(%u).\n",
2996 
2999  }
3000 
3001  DataNode = NewDataNode(CurrentFolderNode);
3002  if (!DataNode)
3003  {
3004  DPRINT(MIN_TRACE, ("Insufficient memory.\n"));
3005  return CAB_STATUS_NOMEMORY;
3006  }
3007 
3008  DiskSize += sizeof(CFDATA);
3009 
3010  if (MaxDiskSize > 0)
3011  /* Disk size is limited */
3013  else
3014  BlockIsSplit = false;
3015 
3016  if (BlockIsSplit)
3017  {
3018  DataNode->Data.CompSize = (USHORT)(MaxDiskSize - DiskSize);
3019  DataNode->Data.UncompSize = 0;
3020  CreateNewDisk = true;
3021  }
3022  else
3023  {
3024  DataNode->Data.CompSize = (USHORT)CurrentOBufferSize;
3025  DataNode->Data.UncompSize = (USHORT)CurrentIBufferSize;
3026  }
3027 
3028  DataNode->Data.Checksum = 0;
3029  DataNode->ScratchFilePosition = ScratchFile->Position();
3030 
3031  // FIXME: MAKECAB.EXE does not like this checksum algorithm
3032  //DataNode->Data.Checksum = ComputeChecksum(CurrentOBuffer, DataNode->Data.CompSize, 0);
3033 
3034  DPRINT(MAX_TRACE, ("Writing block. Checksum (0x%X) CompSize (%u) UncompSize (%u).\n",
3035  (UINT)DataNode->Data.Checksum,
3036  DataNode->Data.CompSize,
3037  DataNode->Data.UncompSize));
3038 
3039  Status = ScratchFile->WriteBlock(&DataNode->Data,
3041  if (Status != CAB_STATUS_SUCCESS)
3042  return Status;
3043 
3045 
3047  CurrentFolderNode->Folder.DataBlockCount++;
3048 
3049  CurrentOBuffer = (unsigned char*)CurrentOBuffer + DataNode->Data.CompSize;
3050  CurrentOBufferSize -= DataNode->Data.CompSize;
3051 
3052  LastBlockStart += DataNode->Data.UncompSize;
3053 
3054  if (!BlockIsSplit)
3055  {
3056  CurrentIBufferSize = 0;
3058  }
3059 
3060  return CAB_STATUS_SUCCESS;
3061 }
3062 
3063 #if !defined(_WIN32)
3064 
3066  PUSHORT DosDate,
3067  PUSHORT DosTime)
3068 /*
3069  * FUNCTION: Returns file times of a file
3070  * ARGUMENTS:
3071  * FileHandle = File handle of file to get file times from
3072  * File = Pointer to CFFILE node for file
3073  * RETURNS:
3074  * Status of operation
3075  */
3076 {
3077  struct tm *timedef;
3078 
3079  timedef = localtime(Time);
3080 
3081  DPRINT(MAX_TRACE, ("day: %d, mon: %d, year:%d, hour: %d, min: %d, sec: %d\n",
3082  timedef->tm_mday, timedef->tm_mon, timedef->tm_year,
3083  timedef->tm_sec, timedef->tm_min, timedef->tm_hour));
3084 
3085  *DosDate = ((timedef->tm_mday + 1) << 0)
3086  | ((timedef->tm_mon + 1) << 5)
3087  | (((timedef->tm_year + 1900) - 1980) << 9);
3088 
3089  *DosTime = (timedef->tm_sec << 0)
3090  | (timedef->tm_min << 5)
3091  | (timedef->tm_hour << 11);
3092 }
3093 
3094 #endif // !_WIN32
3095 
3096 
3098 /*
3099  * FUNCTION: Returns file times of a file
3100  * ARGUMENTS:
3101  * FileHandle = File handle of file to get file times from
3102  * File = Pointer to CFFILE node for file
3103  * RETURNS:
3104  * Status of operation
3105  */
3106 {
3107 #if defined(_WIN32)
3108  FILETIME FileTime;
3109  HANDLE FileNo = (HANDLE)_fileno(FileHandle);
3110 
3111  if (GetFileTime(FileNo, NULL, NULL, &FileTime))
3112  FileTimeToDosDateTime(&FileTime,
3113  &File->File.FileDate,
3114  &File->File.FileTime);
3115 #else
3116  struct stat stbuf;
3117  char buf[PATH_MAX];
3118 
3119  // Check for an absolute path
3120  if (IsSeparator(File->FileName[0]))
3121  strcpy(buf, File->FileName);
3122  else
3123  {
3124  if (!getcwd(buf, sizeof(buf)))
3125  return CAB_STATUS_CANNOT_READ;
3127  strcat(buf, File->FileName);
3128  }
3129 
3130  if (stat(buf, &stbuf) == -1)
3131  return CAB_STATUS_CANNOT_READ;
3132 
3133  ConvertDateAndTime(&stbuf.st_mtime, &File->File.FileDate, &File->File.FileTime);
3134 #endif
3135  return CAB_STATUS_SUCCESS;
3136 }
3137 
3138 
3140 /*
3141  * FUNCTION: Returns attributes on a file
3142  * ARGUMENTS:
3143  * File = Pointer to CFFILE node for file
3144  * RETURNS:
3145  * Status of operation
3146  */
3147 {
3148 #if defined(_WIN32)
3149  LONG Attributes;
3150 
3151  Attributes = GetFileAttributes(File->FileName);
3152  if (Attributes == -1)
3153  return CAB_STATUS_CANNOT_READ;
3154 
3155  // 0x37 = READONLY | HIDDEN | SYSTEM | DIRECTORY | ARCHIVE
3156  // The IDs for these attributes are the same in the CAB file and under Windows
3157  // If the file has any other attributes, strip them off by the logical AND.
3158  File->File.Attributes = (USHORT)(Attributes & 0x37);
3159 #else
3160  struct stat stbuf;
3161  char buf[PATH_MAX];
3162 
3163  // Check for an absolute path
3164  if (IsSeparator(File->FileName[0]))
3165  strcpy(buf, File->FileName);
3166  else
3167  {
3168  if (!getcwd(buf, sizeof(buf)))
3169  return CAB_STATUS_CANNOT_READ;
3171  strcat(buf, File->FileName);
3172  }
3173 
3174  if (stat(buf, &stbuf) == -1)
3175  return CAB_STATUS_CANNOT_READ;
3176 
3177 #if 0
3178  File->File.Attributes |= CAB_ATTRIB_READONLY;
3179  File->File.Attributes |= CAB_ATTRIB_HIDDEN;
3180  File->File.Attributes |= CAB_ATTRIB_SYSTEM;
3181 #endif
3182 
3183  if (stbuf.st_mode & S_IFDIR)
3184  File->File.Attributes |= CAB_ATTRIB_DIRECTORY;
3185 
3186  File->File.Attributes |= CAB_ATTRIB_ARCHIVE;
3187 
3188 #endif
3189  return CAB_STATUS_SUCCESS;
3190 }
3191 
3192 
3194 /*
3195  * FUNCTION: Sets attributes on a file
3196  * ARGUMENTS:
3197  * FileName = File name with path
3198  * FileAttributes = Attributes of that file
3199  * RETURNS:
3200  * Status of operation
3201  */
3202 {
3203 #if defined(_WIN32)
3204  // 0x37 = READONLY | HIDDEN | SYSTEM | DIRECTORY | ARCHIVE
3205  // The IDs for these attributes are the same in the CAB file and under Windows
3206  // If the file has any other attributes, strip them off by the logical AND.
3208 
3209  return CAB_STATUS_SUCCESS;
3210 #else
3211  //DPRINT(MIN_TRACE, ("FIXME: SetAttributesOnFile() is unimplemented\n"));
3212  return CAB_STATUS_SUCCESS;
3213 #endif
3214 }
3215 
3216 #endif /* CAB_READ_ONLY */
3217 
3218 /* EOF */
PCFDATA_NODE DataListTail
Definition: cabinet.h:210
#define CAB_STATUS_INVALID_CAB
Definition: cabinet.h:31
void SetDestinationPath(char *DestinationPath)
Definition: cabinet.cxx:272
PCFFILE_NODE FileListTail
Definition: cabinet.h:476
struct _CFHEADER CFHEADER
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
#define SEEK_CUR
Definition: util.h:63
ULONG DataReserved
Definition: cabinet.h:470
ULONG LocateFile(char *FileName, PCFFILE_NODE *File)
Definition: cabinet.cxx:2000
int tm_min
Definition: time.h:78
ULONG FindFirst(PCAB_SEARCH Search)
Definition: cabinet.cxx:637
#define OK(condition, fail_message,...)
void DestroyDataNodes(PCFFOLDER_NODE FolderNode)
Definition: cabinet.cxx:2316
_Must_inspect_result_ _In_ PFILE_OBJECT _In_opt_ PLARGE_INTEGER _In_ ULONG _In_ FLT_IO_OPERATION_FLAGS _Out_opt_ PULONG BytesWritten
Definition: fltkernel.h:1293
struct _CFFOLDER_NODE * Prev
Definition: cabinet.h:205
ULONG LastFileOffset
Definition: cabinet.h:491
#define MID_TRACE
Definition: debug.h:15
virtual void OnAdd(PCFFILE Entry, char *FileName)
Definition: cabinet.cxx:1886
bool ContinueFile
Definition: cabinet.h:502
FILE * FileHandle
Definition: cabinet.h:465
#define CAB_FILE_PREV_NEXT
Definition: cabinet.c:73
static WCHAR szFilePath[]
Definition: qotd.c:14
ULONG Index
Definition: cabinet.h:211
PSEARCH_CRITERIA CriteriaListHead
Definition: cabinet.h:477
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
#define strcasecmp
Definition: fake.h:9
ULONG AddFile(char *FileName)
Definition: cabinet.cxx:1612
char * GetCabinetName()
Definition: cabinet.cxx:250
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
ULONG CloseCabinet()
Definition: cabinet.cxx:1574
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
ULONG NewCabinet()
Definition: cabinet.cxx:1147
CFFILE File
Definition: cabinet.h:221
ULONG ScratchFilePosition
Definition: cabinet.h:196
#define CAB_CODEC_RAW
Definition: cabinet.h:46
PCFDATA_NODE DataListHead
Definition: cabinet.h:209
char CabinetReservedFile[PATH_MAX]
Definition: cabinet.h:462
ULONG DiskSize
Definition: cabinet.h:495
ULONG GetAttributesOnFile(PCFFILE_NODE File)
Definition: cabinet.cxx:3139
#define CAB_STATUS_CANNOT_READ
Definition: cabinet.h:28
ULONG WriteFileToScratchStorage(PCFFILE_NODE FileNode)
Definition: cabinet.cxx:1287
char * strncpy(char *DstString, const char *SrcString, ACPI_SIZE Count)
Definition: utclib.c:427
PCFFOLDER_NODE FolderListHead
Definition: cabinet.h:471
unsigned char * PUCHAR
Definition: retypes.h:3
#define CAB_FILE_SPLIT
Definition: cabinet.c:72
char CHAR
Definition: xmlstorage.h:175
#define free
Definition: debug_ros.c:5
virtual ~CCabinet()
Definition: cabinet.cxx:111
__kernel_off_t off_t
Definition: linux.h:201
ULONG WriteCabinetHeader(bool MoreDisks)
Definition: cabinet.cxx:2691
virtual ULONG Compress(void *OutputBuffer, void *InputBuffer, ULONG InputLength, PULONG OutputLength)=0
ULONG Seek(LONG Position)
CCABCodec * Codec
Definition: cabinet.h:479
int tm_mday
Definition: time.h:80
CFFOLDER Folder
Definition: cabinet.h:214
virtual void OnExtract(PCFFILE Entry, char *FileName)
Definition: cabinet.cxx:1860
GLdouble n
Definition: glext.h:7729
ULONG SetAttributesOnFile(char *FileName, USHORT FileAttributes)
Definition: cabinet.cxx:3193
ULONG NextFieldsSize
Definition: cabinet.h:455
bool IsCodecSelected()
Definition: cabinet.cxx:1098
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define CAB_ATTRIB_SYSTEM
Definition: cabinet.c:63
struct _CFFILE_NODE * Next
Definition: cabinet.h:219
PCFFOLDER_NODE LocateFolderNode(ULONG Index)
Definition: cabinet.cxx:1927
#define CAB_ATTRIB_HIDDEN
Definition: cabinet.c:62
struct _CFFOLDER_NODE * Next
Definition: cabinet.h:204
static WCHAR String[]
Definition: stringtable.c:55
PCFFOLDER_NODE FolderListTail
Definition: cabinet.h:472
char * GetCabinetReservedFile()
Definition: cabinet.cxx:448
bool CreateNewFolder
Definition: cabinet.h:498
bool SetCompressionCodec(char *CodecName)
Definition: cabinet.cxx:361
int tm_year
Definition: time.h:82
ULONG ComputeChecksum(void *Buffer, ULONG Size, ULONG Seed)
Definition: cabinet.cxx:2470
int errno
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
void * OutputBuffer
Definition: cabinet.h:485
_Check_return_opt_ _CRTIMP size_t __cdecl fwrite(_In_reads_bytes_(_Size *_Count) const void *_Str, _In_ size_t _Size, _In_ size_t _Count, _Inout_ FILE *_File)
PCFFOLDER_NODE FolderNode
Definition: cabinet.h:226
CFDATA Data
Definition: cabinet.h:199
struct _CFFILE CFFILE
bool ReuseBlock
Definition: cabinet.h:460
_In_opt_ PALLOCATE_FUNCTION Allocate
Definition: exfuncs.h:656
PCFDATA_NODE CurrentDataNode
Definition: cabinet.h:474
Definition: fatfs.h:198
#define CAB_FILE_CONTINUED
Definition: cabinet.c:71
DWORD Id
BOOL WINAPI SetFileTime(IN HANDLE hFile, CONST FILETIME *lpCreationTime OPTIONAL, CONST FILETIME *lpLastAccessTime OPTIONAL, CONST FILETIME *lpLastWriteTime OPTIONAL)
Definition: fileinfo.c:1098
ULONG MaxDiskSize
Definition: cabinet.h:494
ULONG CurrentOBufferSize
Definition: cabinet.h:488
void DestroyFolderNodes()
Definition: cabinet.cxx:2406
DIR *__cdecl opendir(const char *)
ULONG LastBlockStart
Definition: cabinet.h:493
HANDLE FileHandle
Definition: stats.c:38
Definition: raw.h:15
#define CAB_CODEC_MSZIP
Definition: cabinet.h:48
struct _CFFOLDER CFFOLDER
char * FileName
Definition: cabinet.h:222
PCFDATA_NODE NewDataNode(PCFFOLDER_NODE FolderNode)
Definition: cabinet.cxx:2286
#define CAB_COMP_MSZIP
Definition: cabinet.c:53
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
bool SetCabinetReservedFile(char *FileName)
Definition: cabinet.cxx:392
#define DIR_SEPARATOR_CHAR
Definition: config.h:5
ULONG ReadFileTable()
Definition: cabinet.cxx:2100
_Check_return_opt_ _CRTIMP size_t __cdecl fread(_Out_writes_bytes_(_ElementSize *_Count) void *_DstBuf, _In_ size_t _ElementSize, _In_ size_t _Count, _Inout_ FILE *_File)
ULONG GetFileTimes(FILE *FileHandle, PCFFILE_NODE File)
Definition: cabinet.cxx:3097
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
#define CAB_VERSION
Definition: cabinet.c:48
PCFFILE_NODE Next
Definition: cabinet.h:238
long LONG
Definition: pedump.c:60
#define CAB_FLAG_RESERVE
Definition: cabinet.c:59
char * GetFileName(char *Path)
Definition: cabinet.cxx:183
bool CodecSelected
Definition: cabinet.h:481
union node Node
Definition: types.h:1255
Definition: fci.c:82
_Check_return_ _CRTIMP char *__cdecl strdup(_In_opt_z_ const char *_Src)
char Char
Definition: bzip2.c:161
struct _SEARCH_CRITERIA * Next
Definition: cabinet.h:231
void RemoveFileName(char *Path)
Definition: cabinet.cxx:204
#define GENERIC_WRITE
Definition: nt_native.h:90
CCFDATAStorage * ScratchFile
Definition: cabinet.h:500
ULONG Open()
Definition: cabinet.cxx:470
void SetMaxDiskSize(ULONG Size)
Definition: cabinet.cxx:1830
_In_opt_ PVOID _In_ PCSTR File
Definition: iofuncs.h:615
virtual bool OnDiskLabel(ULONG Number, char *Label)
Definition: cabinet.cxx:1898
#define CAB_STATUS_CANNOT_WRITE
Definition: cabinet.h:29
ULONG CommitDisk(ULONG MoreDisks)
Definition: cabinet.cxx:1487
Definition: fci.c:101
Definition: dirent.h:39
char DiskPrev[256]
Definition: cabinet.h:451
struct _SEARCH_CRITERIA * PSEARCH_CRITERIA
#define CAB_STATUS_NOMEMORY
Definition: cabinet.h:25
ULONG CabinetReserved
Definition: cabinet.h:468
smooth NULL
Definition: ftsmooth.c:416
_Check_return_opt_ _CRTIMP int __cdecl fseek(_Inout_ FILE *_File, _In_ long _Offset, _In_ int _Origin)
char DiskNext[256]
Definition: cabinet.h:453
#define CAB_ATTRIB_DIRECTORY
Definition: cabinet.c:65
bool Commit
Definition: cabinet.h:224
char CabinetPrev[256]
Definition: cabinet.h:450
void DPRINT(...)
Definition: polytest.cpp:61
#define CAB_ATTRIB_READONLY
Definition: cabinet.c:61
PCFFOLDER_NODE NewFolderNode()
Definition: cabinet.cxx:2226
FILE * SourceFile
Definition: cabinet.h:501
Definition: bufpool.h:45
int tm_mon
Definition: time.h:81
#define CAB_BLOCKSIZE
Definition: cabinet.c:49
return Found
Definition: dirsup.c:1270
#define FindFirstFile
Definition: winbase.h:3596
_Must_inspect_result_ _In_opt_ PFLT_INSTANCE _Out_ PHANDLE _In_ ACCESS_MASK _In_ POBJECT_ATTRIBUTES _Out_ PIO_STATUS_BLOCK _In_opt_ PLARGE_INTEGER _In_ ULONG FileAttributes
Definition: fltkernel.h:1230
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
#define S_IFDIR
Definition: acwin.h:89
char * d_name
Definition: dirent.h:29
struct _CFFILE_NODE * PCFFILE_NODE
#define SEEK_SET
Definition: jmemansi.c:26
char * Search
Definition: cabinet.h:233
#define CAB_STATUS_UNSUPPCOMP
Definition: cabinet.h:33
File()
Definition: File.h:18
ULONG ReadBlock(PCFDATA Data, void *Buffer, PULONG BytesRead)
LONG CodecId
Definition: cabinet.h:480
void * InputBuffer
Definition: cabinet.h:482
if(!(yy_init))
Definition: macro.lex.yy.c:714
#define SetFileAttributes
Definition: winbase.h:3723
struct _CFFOLDER_NODE * PCFFOLDER_NODE
BOOL WINAPI DosDateTimeToFileTime(IN WORD wFatDate, IN WORD wFatTime, OUT LPFILETIME lpFileTime)
Definition: time.c:75
ULONG ReadBlock(void *Buffer, ULONG Size, PULONG BytesRead)
Definition: cabinet.cxx:2529
#define FindNextFile
Definition: winbase.h:3602
ULONG WriteFolderEntries()
Definition: cabinet.cxx:2832
void DestroySearchCriteria()
Definition: cabinet.cxx:327
bool FileOpen
Definition: cabinet.h:466
static const UCHAR Index[8]
Definition: usbohci.c:18
#define CAB_STATUS_CANNOT_CREATE
Definition: cabinet.h:27
#define CAB_FLAG_HASPREV
Definition: cabinet.c:57
unsigned long DWORD
Definition: ntddk_ex.h:95
PVOID HANDLE
Definition: typedefs.h:71
#define CAB_STATUS_FAILURE
Definition: cabinet.h:24
HRESULT Next([in] ULONG celt, [out, size_is(celt), length_is(*pceltFetched)] STATPROPSETSTG *rgelt, [out] ULONG *pceltFetched)
void ConvertDateAndTime(time_t *Time, PUSHORT DosDate, PUSHORT DosTime)
Definition: cabinet.cxx:3065
void DestroyDeletedFolderNodes()
Definition: cabinet.cxx:2427
Definition: fci.c:89
bool BlockIsSplit
Definition: cabinet.h:504
#define PATH_MAX
Definition: types.h:280
ULONG BytesLeftInBlock
Definition: cabinet.h:459
ULONG UncompOffset
Definition: cabinet.h:206
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
ULONG AddSearchCriteria(char *SearchCriteria)
Definition: cabinet.cxx:285
ULONG NewFolder()
Definition: cabinet.cxx:1242
#define CAB_SIGNATURE
Definition: cabinet.c:47
ULONG FolderUncompSize
Definition: cabinet.h:458
#define CAB_STATUS_SUCCESS
Definition: cabinet.h:23
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
char CabinetNext[256]
Definition: cabinet.h:452
ULONG ReadDataBlocks(PCFFOLDER_NODE FolderNode)
Definition: cabinet.cxx:2161
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:126
ULONG ExtractFile(char *FileName)
Definition: cabinet.cxx:738
ULONG FindNext(PCAB_SEARCH Search)
Definition: cabinet.cxx:652
void DestroyDeletedFileNodes()
Definition: cabinet.cxx:2360
void SelectCodec(LONG Id)
Definition: cabinet.cxx:1108
ULONG TotalBytesLeft
Definition: cabinet.h:503
ULONG CurrentIBufferSize
Definition: cabinet.h:484
unsigned short st_mode
Definition: stat.h:58
Definition: stat.h:55
ULONG TotalFolderSize
Definition: cabinet.h:456
#define CAB_FLAG_HASNEXT
Definition: cabinet.c:58
_Check_return_opt_ _CRTIMP int __cdecl fclose(_Inout_ FILE *_File)
_Check_return_ _CRTIMP FILE *__cdecl fopen(_In_z_ const char *_Filename, _In_z_ const char *_Mode)
Definition: time.h:76
ULONG ReadString(char *String, LONG MaxLength)
Definition: cabinet.cxx:2045
_CRTIMP struct tm *__cdecl localtime(const time_t *_Time)
Definition: time.h:426
struct _CFDATA CFDATA
IN PVOID IN PVOID IN USHORT IN USHORT Size
Definition: pci.h:359
int __cdecl closedir(DIR *)
_In_opt_ PENTER_STATE_SYSTEM_HANDLER _In_opt_ PVOID _In_ LONG _In_opt_ LONG volatile * Number
Definition: ntpoapi.h:204
ULONG WriteFileEntries()
Definition: cabinet.cxx:2864
_Check_return_ _Ret_opt_z_ _CRTIMP char *__cdecl getcwd(_Out_writes_opt_(_SizeInBytes) char *_DstBuf, _In_ int _SizeInBytes)
ULONG FolderReserved
Definition: cabinet.h:469
#define GetFileAttributes
Definition: winbase.h:3629
struct _SEARCH_CRITERIA * Prev
Definition: cabinet.h:232
Status
Definition: gdiplustypes.h:24
struct dirent *__cdecl readdir(DIR *)
char * GetDestinationPath()
Definition: cabinet.cxx:381
#define CS_NOMEMORY
Definition: cabinet.h:42
ULONG AbsoluteOffset
Definition: cabinet.h:197
void DestroyFileNodes()
Definition: cabinet.cxx:2338
void * CurrentOBuffer
Definition: cabinet.h:487
#define CAB_FILE_MAX_FOLDER
Definition: cabinet.c:70
void * CurrentIBuffer
Definition: cabinet.h:483
bool RestartSearch
Definition: cabinet.h:490
BOOL WINAPI FileTimeToDosDateTime(IN CONST FILETIME *lpFileTime, OUT LPWORD lpFatDate, OUT LPWORD lpFatTime)
Definition: time.c:37
struct _FileName FileName
Definition: fatprocs.h:884
_CRTIMP int __cdecl stat(const char *_Filename, struct stat *_Stat)
Definition: stat.h:345
ULONG NextFolderNumber
Definition: cabinet.h:505
#define CREATE_ALWAYS
Definition: disk.h:72
_Must_inspect_result_ _In_ USHORT _In_ PHIDP_PREPARSED_DATA _Out_writes_to_ LengthAttributes PHIDP_EXTENDED_ATTRIBUTES Attributes
Definition: hidpi.h:348
ULONG TotalCompSize
Definition: cabinet.h:486
char DestPath[PATH_MAX]
Definition: cabinet.h:461
PRTL_UNICODE_STRING_BUFFER Path
ULONG CurrentDiskNumber
Definition: cabinet.h:448
ULONG CabinetReservedFileSize
Definition: cabinet.h:464
bool Delete
Definition: cabinet.h:225
#define MAX_TRACE
Definition: debug.h:16
#define CAB_ATTRIB_ARCHIVE
Definition: cabinet.c:66
char CabinetName[256]
Definition: cabinet.h:449
IN OUT PVCB OUT PDIRENT OUT PBCB IN BOOLEAN CreateFile
Definition: fatprocs.h:904
bool HasSearchCriteria()
Definition: cabinet.cxx:351
__kernel_time_t time_t
Definition: linux.h:252
unsigned short USHORT
Definition: pedump.c:61
char * FileName
Definition: cabinet.h:240
#define CAB_COMP_MASK
Definition: cabinet.c:51
static PVOID CurrentBuffer
PCFFILE_NODE FileListHead
Definition: cabinet.h:475
unsigned int * PULONG
Definition: retypes.h:1
ULONG WriteBlock(PCFDATA Data, void *Buffer, PULONG BytesWritten)
ULONG PrevCabinetNumber
Definition: cabinet.h:496
unsigned int UINT
Definition: ndis.h:50
ULONG GetAbsoluteOffset(PCFFILE_NODE File)
Definition: cabinet.cxx:1959
ULONG NewDisk()
Definition: cabinet.cxx:1218
Definition: fci.c:65
bool NormalizePath(char *Path, ULONG Length)
Definition: cabinet.cxx:225
PCFFILE_NODE NewFileNode()
Definition: cabinet.cxx:2256
PCFFOLDER_NODE CurrentFolderNode
Definition: cabinet.h:473
char * ConvertPath(char *Path, bool Allocate)
Definition: cabinet.cxx:142
PCFFILE File
Definition: cabinet.h:76
int tm_sec
Definition: time.h:77
virtual bool OnOverwrite(PCFFILE Entry, char *FileName)
Definition: cabinet.cxx:1845
virtual ULONG Uncompress(void *OutputBuffer, void *InputBuffer, ULONG InputLength, PULONG OutputLength)=0
bool CreateSimpleCabinet()
Definition: cabinet.cxx:1683
void CloseFile(FILE **f)
Definition: util.c:327
#define CAB_STATUS_FILE_EXISTS
Definition: cabinet.h:30
void * CabinetReservedFileBuffer
Definition: cabinet.h:463
bool IsSeparator(char Char)
Definition: cabinet.cxx:127
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
int tm_hour
Definition: time.h:79
virtual void OnDiskChange(char *CabinetName, char *DiskLabel)
Definition: cabinet.cxx:1872
unsigned int ULONG
Definition: retypes.h:1
void Close()
Definition: cabinet.cxx:624
ULONG TotalFolderSize
Definition: cabinet.h:208
PWCHAR Label
Definition: format.c:70
#define MIN_TRACE
Definition: debug.h:14
char * cleanup(char *str)
Definition: wpickclick.c:99
#define CAB_STATUS_CANNOT_OPEN
Definition: cabinet.h:26
#define malloc
Definition: debug_ros.c:4
PSEARCH_CRITERIA CriteriaListTail
Definition: cabinet.h:478
#define DIR_SEPARATOR_STRING
Definition: config.h:6
ULONG WriteDataBlock()
Definition: cabinet.cxx:2976
virtual bool OnCabinetName(ULONG Number, char *Name)
Definition: cabinet.cxx:1912
Definition: File.h:15
#define CAB_COMP_NONE
Definition: cabinet.c:52
#define CS_SUCCESS
Definition: cabinet.h:41
bool CreateNewDisk
Definition: cabinet.h:497
bool MatchFileNamePattern(char *FileName, char *Pattern)
Definition: cabinet.cxx:2549
_Check_return_ _CRTIMP int __cdecl _fileno(_In_ FILE *_File)
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
time_t st_mtime
Definition: stat.h:65
ULONG TotalFileSize
Definition: cabinet.h:457
#define memset(x, y, z)
Definition: compat.h:39
ULONG CloseDisk()
Definition: cabinet.cxx:1556
ULONG GetCurrentDiskNumber()
Definition: cabinet.cxx:459
void SetCabinetName(char *FileName)
Definition: cabinet.cxx:261
ULONG InitCabinetHeader()
Definition: cabinet.cxx:2612
BOOL WINAPI GetFileTime(IN HANDLE hFile, OUT LPFILETIME lpCreationTime OPTIONAL, OUT LPFILETIME lpLastAccessTime OPTIONAL, OUT LPFILETIME lpLastWriteTime OPTIONAL)
Definition: fileinfo.c:1046
#define CAB_STATUS_NOFILE
Definition: cabinet.h:32
struct _CFFILE_NODE * Prev
Definition: cabinet.h:220
struct _CFDATA_NODE * PCFDATA_NODE
unsigned short * PUSHORT
Definition: retypes.h:2
static PLARGE_INTEGER Time
Definition: time.c:105
_Must_inspect_result_ _In_ PFILE_OBJECT _In_opt_ PLARGE_INTEGER _In_ ULONG _In_ FLT_IO_OPERATION_FLAGS _Out_opt_ PULONG BytesRead
Definition: fltkernel.h:1255
CFHEADER CABHeader
Definition: cabinet.h:467
LONG GetSizeOfFile(FILE *handle)
Definition: cabinet.h:43
ULONG WriteDisk(ULONG MoreDisks)
Definition: cabinet.cxx:1401
ULONG TotalHeaderSize
Definition: cabinet.h:454
struct _CFDATA_NODE * Next
Definition: cabinet.h:194
ULONG CommitDataBlocks(PCFFOLDER_NODE FolderNode)
Definition: cabinet.cxx:2924
CCabinet()
Definition: cabinet.cxx:70
#define printf
Definition: config.h:203
Definition: dlist.c:348
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502