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