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