ReactOS 0.4.16-dev-306-g647d351
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
36void 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
92 MaxDiskSize = 0;
93 BlockIsSplit = false;
95
98 ReuseBlock = false;
100}
101
102
104/*
105 * FUNCTION: Default destructor
106 */
107{
109 {
113 }
114
115 if (CodecSelected)
116 delete Codec;
117}
118
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
134void CCabinet::ConvertPath(std::string& Path)
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
158std::string CCabinet::GetFileName(const std::string& Path)
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
216void 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
228ULONG 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
288bool 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{
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
342 {
343 DPRINT(MIN_TRACE, ("Cannot read from cabinet reserved file.\n"));
345 return false;
346 }
347
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{
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
407 if (FileHandle == NULL)
408 {
409 DPRINT(MID_TRACE, ("Cannot open file.\n"));
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));
421 }
422
423 /* Check header */
424 if ((BytesRead != sizeof(CFHEADER)) ||
427 (CABHeader.FolderCount == 0 ) ||
428 (CABHeader.FileCount == 0 ) ||
430 {
431 CloseCabinet();
432 DPRINT(MID_TRACE, ("File has invalid header.\n"));
434 }
435
436 Size = 0;
437
438 /* Read/skip any reserved bytes */
440 {
441 if ((Status = ReadBlock(&Size, sizeof(ULONG), &BytesRead))
443 {
444 DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
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 */
463 return Status;
464 /* Read label of previous disk */
465 Status = ReadString(DiskPrev, 256);
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 */
480 return Status;
481 /* Read label of next disk */
482 Status = ReadString(DiskNext, 256);
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,
509 {
510 DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
512 }
513 }
514
515 /* Read file entries */
518 {
519 DPRINT(MIN_TRACE, ("ReadFileTable() failed (%u).\n", (UINT)Status));
520 return Status;
521 }
522
523 /* Read data blocks for all folders */
525 {
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;
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();
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;
660 ULONG BytesToRead;
662 ULONG BytesSkipped;
663 ULONG BytesToWrite;
664 ULONG TotalBytesRead;
665 ULONG CurrentOffset;
668 FILE* DestFile;
670 CFDATA CFData;
672 bool Skip;
673#if defined(_WIN32)
674 FILETIME FileTime;
675#endif
676 CHAR DestName[PATH_MAX];
677 CHAR TempName[PATH_MAX];
678
681 {
682 DPRINT(MID_TRACE, ("Cannot locate file (%u).\n", (UINT)Status));
683 return Status;
684 }
685
686 LastFileOffset = File->File.FileOffset;
687
689 {
690 case CAB_COMP_NONE:
692 break;
693
694 case CAB_COMP_MSZIP:
696 break;
697
698 default:
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 */
718 {
719 DestFile = fopen(DestName, "w+b");
720 if (DestFile == NULL)
722 }
723 else
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);
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));
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));
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();
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);
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);
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;
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);
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",
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));
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 */
954 {
955 DPRINT(MIN_TRACE, ("fseek() failed.\n"));
956 fclose(DestFile);
957 free(Buffer);
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
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 }
1077
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
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;
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();
1105 return Status;
1106
1108
1110 if (!ScratchFile)
1111 {
1112 DPRINT(MIN_TRACE, ("Insufficient memory.\n"));
1113 return CAB_STATUS_NOMEMORY;
1114 }
1115
1117
1118 CreateNewFolder = false;
1119
1120 CreateNewDisk = false;
1121
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
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:
1171 break;
1172
1173 case CAB_CODEC_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
1188
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;
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();
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
1238 FileNode->File.FileControlID = (USHORT)(NextFolderNumber - 1);
1239 CurrentFolderNode->Commit = true;
1241
1242 Size = sizeof(CFFILE) + (ULONG)CreateCabFilename(FileNode).length() + 1;
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));
1264 }
1265
1266 CurrentIBuffer = (unsigned char*)CurrentIBuffer + BytesRead;
1268
1270 {
1273 return Status;
1274 }
1276 } while ((TotalBytesLeft > 0) && (!CreateNewDisk));
1277 }
1278
1279 if (TotalBytesLeft == 0)
1280 {
1282 FileNode->Delete = true;
1283
1284 if (FileNode->File.FileControlID > CAB_FILE_MAX_FOLDER)
1285 {
1287 CurrentFolderNode->Delete = true;
1288
1289 if ((CurrentIBufferSize > 0) || (CurrentOBufferSize > 0))
1290 {
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
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 {
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 {
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 {
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 {
1411 /* If file exists, ask to overwrite file */
1413 {
1414 FileHandle = fopen(CabinetName, "w+b");
1415 if (FileHandle == NULL)
1417 }
1418 else
1420
1421 }
1422 else
1423 {
1424 FileHandle = fopen(CabinetName, "w+b");
1425 if (FileHandle == NULL)
1427 }
1428
1429 WriteCabinetHeader(MoreDisks != 0);
1430
1433 return Status;
1434
1435 /* Write file entries */
1437
1438 /* Write data blocks */
1439 for (PCFFOLDER_NODE FolderNode : FolderList)
1440 {
1441 if (FolderNode->Commit)
1442 {
1443 Status = CommitDataBlocks(FolderNode);
1445 return Status;
1446 /* Remove data blocks for folder */
1447 DestroyDataNodes(FolderNode);
1448 }
1449 }
1450
1452
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
1487
1489
1490 if (InputBuffer)
1491 {
1493 InputBuffer = NULL;
1494 }
1495
1496 if (OutputBuffer)
1497 {
1500 }
1501
1502 Close();
1503
1504 if (ScratchFile)
1505 {
1507 delete ScratchFile;
1508 return Status;
1509 }
1510
1511 return CAB_STATUS_SUCCESS;
1512}
1513
1514
1515ULONG CCabinet::AddFile(const std::string& FileName, const std::string& TargetFolder)
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()));
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);
1560 }
1561
1562 if (GetFileTimes(SrcFile, FileNode) != CAB_STATUS_SUCCESS)
1563 {
1564 DPRINT(MIN_TRACE, ("Cannot read file times.\n"));
1565 fclose(SrcFile);
1567 }
1568
1569 if (GetAttributesOnFile(FileNode) != CAB_STATUS_SUCCESS)
1570 {
1571 DPRINT(MIN_TRACE, ("Cannot read file attributes.\n"));
1572 fclose(SrcFile);
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();
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);
1613 std::string szFilePath;
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
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
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);
1704 Status = CloseDisk();
1706 {
1707 DPRINT(MIN_TRACE, ("Cannot write disk (%u).\n", (UINT)Status));
1708 goto cleanup;
1709 }
1710
1711cleanup:
1712 CloseCabinet();
1713 bRet = true;
1714
1715cleanup2:
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
1762void 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 }
1882}
1883
1884
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));
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{
1939 ULONG Status;
1940 LONG Size;
1941 bool Found;
1942
1943 Found = false;
1944
1945 Status = ReadBlock(String, MaxLength, &BytesRead);
1947 {
1948 DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
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"));
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"));
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;
1994
1995 DPRINT(MAX_TRACE, ("Reading file table at absolute offset (0x%X).\n",
1997
1998 /* Seek to file table */
2000 {
2001 DPRINT(MIN_TRACE, ("fseek() failed.\n"));
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));
2019 }
2020
2021 /* Read file name */
2022 char Buf[PATH_MAX];
2023 Status = ReadString(Buf, PATH_MAX);
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;
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"));
2076 }
2077
2078 if ((Status = ReadBlock(&Node->Data, sizeof(CFDATA),
2080 {
2081 DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
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,
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 )
2339 return CAB_STATUS_SUCCESS;
2340}
2341
2342bool 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
2421
2423 {
2426 strcpy(CabinetPrev, "");
2427 }
2428
2430 {
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;
2459
2460 /* Calculate size of label of next disk */
2461 Size = (ULONG)strlen(DiskNext) + 1;
2462 TotalSize += Size;
2464 }
2465 else
2466 NextFieldsSize = 0;
2467
2468 /* Add cabinet reserved area size if present */
2470 {
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 {
2500 }
2501 else
2502 {
2503 CABHeader.Flags &= ~CAB_FLAG_HASNEXT;
2506 }
2507
2508 /* Set absolute folder offsets */
2511 for (PCFFOLDER_NODE FolderNode : FolderList)
2512 {
2513 FolderNode->Folder.DataOffset = BytesWritten;
2514
2515 BytesWritten += FolderNode->TotalFolderSize;
2516
2518 }
2519
2520 /* Set absolute offset of file table */
2522
2523 /* Count number of files to be committed */
2524 CABHeader.FileCount = 0;
2525 for (PCFFILE_NODE FileNode : FileList)
2526 {
2527 if (FileNode->Commit)
2529 }
2530
2532
2533 /* Write header */
2534 if (fwrite(&CABHeader, sizeof(CFHEADER), 1, FileHandle) < 1)
2535 {
2536 DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
2538 }
2539
2540 /* Write per-cabinet reserved area if present */
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"));
2554 }
2555
2558 {
2559 DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
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;
2571 if (fwrite(CabinetPrev, Size, 1, FileHandle) < 1)
2572 {
2573 DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
2575 }
2576
2577 DPRINT(MAX_TRACE, ("DiskPrev '%s'.\n", DiskPrev));
2578
2579 /* Write label of previous disk */
2580 Size = (ULONG)strlen(DiskPrev) + 1;
2582 if (fwrite(DiskPrev, Size, 1, FileHandle) < 1)
2583 {
2584 DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
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;
2596 if (fwrite(CabinetNext, Size, 1, FileHandle) < 1)
2597 {
2598 DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
2600 }
2601
2602 DPRINT(MAX_TRACE, ("DiskNext '%s'.\n", DiskNext));
2603
2604 /* Write label of next disk */
2605 Size = (ULONG)strlen(DiskNext) + 1;
2607 if (fwrite(DiskNext, Size, 1, FileHandle) < 1)
2608 {
2609 DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
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"));
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"));
2683 }
2684
2685 std::string fname = CreateCabFilename(File);
2686 if (fwrite(fname.c_str(), fname.length() + 1, 1, FileHandle) < 1)
2687 {
2688 DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
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{
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) */
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"));
2739 }
2740
2741 if (fwrite(InputBuffer, DataNode->Data.CompSize, 1, FileHandle) < 1)
2742 {
2743 DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
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 {
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 {
2801 }
2802
2803 DataNode->Data.Checksum = 0;
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,
2817 return Status;
2818
2820
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 {
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)))
2902 strcat(buf, File->FileName.c_str());
2903 }
2904
2905 if (stat(buf, &stbuf) == -1)
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)
2925
2926 Attributes = GetFileAttributes(File->FileName.c_str());
2927 if (Attributes == -1)
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)))
2946 strcat(buf, File->FileName.c_str());
2947 }
2948
2949 if (stat(buf, &stbuf) == -1)
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 */
static ACPI_BUFFER CurrentBuffer
DWORD Id
vector< FileInfo > FileList
Definition: DriveVolume.h:63
PRTL_UNICODE_STRING_BUFFER Path
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
#define S_IFDIR
Definition: acwin.h:115
#define stat
Definition: acwin.h:99
#define MID_TRACE
Definition: debug.h:15
PWCHAR Label
Definition: format.c:70
#define UlongToHandle(ul)
Definition: basetsd.h:97
return Found
Definition: dirsup.c:1270
Definition: bufpool.h:45
virtual ULONG Compress(void *OutputBuffer, void *InputBuffer, ULONG InputLength, PULONG OutputLength)=0
virtual ULONG Uncompress(void *OutputBuffer, void *InputBuffer, ULONG InputLength, PULONG OutputLength)=0
ULONG ReadBlock(PCFDATA Data, void *Buffer, PULONG BytesRead)
ULONG Seek(LONG Position)
ULONG WriteBlock(PCFDATA Data, void *Buffer, PULONG BytesWritten)
std::string DestPath
Definition: cabinet.h:450
ULONG ReadFileTable()
Definition: cabinet.cxx:1983
void SetMaxDiskSize(ULONG Size)
Definition: cabinet.cxx:1720
ULONG GetAttributesOnFile(PCFFILE_NODE File)
Definition: cabinet.cxx:2914
void Close()
Definition: cabinet.cxx:538
bool FileOpen
Definition: cabinet.h:455
bool RestartSearch
Definition: cabinet.h:476
ULONG NextFolderNumber
Definition: cabinet.h:491
ULONG AddFile(const std::string &FileName, const std::string &TargetFolder)
Definition: cabinet.cxx:1515
ULONG CurrentIBufferSize
Definition: cabinet.h:470
void NormalizePath(std::string &Path)
Definition: cabinet.cxx:179
bool CreateNewDisk
Definition: cabinet.h:483
void DestroySearchCriteria()
Definition: cabinet.cxx:256
ULONG NewCabinet()
Definition: cabinet.cxx:1057
void SetDestinationPath(const char *DestinationPath)
Definition: cabinet.cxx:216
ULONG FolderUncompSize
Definition: cabinet.h:447
ULONG PrevCabinetNumber
Definition: cabinet.h:482
PCFFOLDER_NODE CurrentFolderNode
Definition: cabinet.h:461
std::string GetFileName(const std::string &Path)
Definition: cabinet.cxx:158
ULONG ComputeChecksum(void *Buffer, ULONG Size, ULONG Seed)
Definition: cabinet.cxx:2263
ULONG BytesLeftInBlock
Definition: cabinet.h:448
void DestroyFileNodes()
Definition: cabinet.cxx:2183
ULONG NextFieldsSize
Definition: cabinet.h:444
ULONG WriteFileEntries()
Definition: cabinet.cxx:2646
void DestroyDeletedFileNodes()
Definition: cabinet.cxx:2196
CFHEADER CABHeader
Definition: cabinet.h:456
ULONG ExtractFile(const char *FileName)
Definition: cabinet.cxx:648
char DiskNext[256]
Definition: cabinet.h:442
bool SetCabinetReservedFile(const char *FileName)
Definition: cabinet.cxx:319
bool CreateNewFolder
Definition: cabinet.h:484
void DestroyFolderNodes()
Definition: cabinet.cxx:2223
ULONG FindFirst(PCAB_SEARCH Search)
Definition: cabinet.cxx:551
void * OutputBuffer
Definition: cabinet.h:471
ULONG CommitDataBlocks(PCFFOLDER_NODE FolderNode)
Definition: cabinet.cxx:2703
virtual void OnDiskChange(const char *CabinetName, const char *DiskLabel)
Definition: cabinet.cxx:1762
ULONG TotalFileSize
Definition: cabinet.h:446
void SetCabinetName(const char *FileName)
Definition: cabinet.cxx:205
PCFFILE_NODE NewFileNode()
Definition: cabinet.cxx:2126
PCFFOLDER_NODE NewFolderNode()
Definition: cabinet.cxx:2105
bool ContinueFile
Definition: cabinet.h:488
class CCFDATAStorage * ScratchFile
Definition: cabinet.h:486
ULONG InitCabinetHeader()
Definition: cabinet.cxx:2405
CCabinet()
Definition: cabinet.cxx:71
ULONG NewFolder()
Definition: cabinet.cxx:1152
ULONG CurrentDiskNumber
Definition: cabinet.h:437
virtual void OnVerboseMessage(const char *Message)
Definition: cabinet.cxx:1773
void DestroyDeletedFolderNodes()
Definition: cabinet.cxx:2237
PCFDATA_NODE CurrentDataNode
Definition: cabinet.h:462
ULONG TotalHeaderSize
Definition: cabinet.h:443
bool HasSearchCriteria()
Definition: cabinet.cxx:268
bool SetCompressionCodec(const char *CodecName)
Definition: cabinet.cxx:288
bool MatchFileNamePattern(const char *FileName, const char *Pattern)
Definition: cabinet.cxx:2342
ULONG GetFileTimes(FILE *FileHandle, PCFFILE_NODE File)
Definition: cabinet.cxx:2872
bool ReuseBlock
Definition: cabinet.h:449
ULONG TotalCompSize
Definition: cabinet.h:472
bool CodecSelected
Definition: cabinet.h:467
virtual bool OnOverwrite(PCFFILE Entry, const char *FileName)
Definition: cabinet.cxx:1735
char DiskPrev[256]
Definition: cabinet.h:440
ULONG CurrentOBufferSize
Definition: cabinet.h:474
char CabinetPrev[256]
Definition: cabinet.h:439
bool IsCodecSelected()
Definition: cabinet.cxx:1008
bool BlockIsSplit
Definition: cabinet.h:490
ULONG TotalFolderSize
Definition: cabinet.h:445
void * CurrentIBuffer
Definition: cabinet.h:469
virtual void OnExtract(PCFFILE Entry, const char *FileName)
Definition: cabinet.cxx:1750
void ConvertDateAndTime(time_t *Time, PUSHORT DosDate, PUSHORT DosTime)
Definition: cabinet.cxx:2840
ULONG DiskSize
Definition: cabinet.h:481
ULONG GetAbsoluteOffset(PCFFILE_NODE File)
Definition: cabinet.cxx:1849
ULONG Open()
Definition: cabinet.cxx:387
PCFFOLDER_NODE LocateFolderNode(ULONG Index)
Definition: cabinet.cxx:1821
void DestroyDataNodes(PCFFOLDER_NODE FolderNode)
Definition: cabinet.cxx:2168
void SelectCodec(LONG Id)
Definition: cabinet.cxx:1018
ULONG MaxDiskSize
Definition: cabinet.h:480
ULONG CloseDisk()
Definition: cabinet.cxx:1459
ULONG ReadBlock(void *Buffer, ULONG Size, PULONG BytesRead)
Definition: cabinet.cxx:2322
virtual void OnAdd(PCFFILE Entry, const char *FileName)
Definition: cabinet.cxx:1780
ULONG WriteCabinetHeader(bool MoreDisks)
Definition: cabinet.cxx:2484
void * CabinetReservedFileBuffer
Definition: cabinet.h:452
FILE * FileHandle
Definition: cabinet.h:454
const char * GetDestinationPath()
Definition: cabinet.cxx:308
ULONG FindNext(PCAB_SEARCH Search)
Definition: cabinet.cxx:566
ULONG CloseCabinet()
Definition: cabinet.cxx:1477
virtual ~CCabinet()
Definition: cabinet.cxx:103
std::string CreateCabFilename(PCFFILE_NODE Node)
Definition: cabinet.cxx:278
void * CurrentOBuffer
Definition: cabinet.h:473
ULONG CabinetReservedFileSize
Definition: cabinet.h:453
void ConvertPath(std::string &Path)
Definition: cabinet.cxx:134
LONG CodecId
Definition: cabinet.h:466
char CabinetName[256]
Definition: cabinet.h:438
ULONG WriteDataBlock()
Definition: cabinet.cxx:2751
ULONG NewDisk()
Definition: cabinet.cxx:1128
std::list< PSEARCH_CRITERIA > CriteriaList
Definition: cabinet.h:464
ULONG LastFileOffset
Definition: cabinet.h:477
bool IsSeparator(char Char)
Definition: cabinet.cxx:119
ULONG CabinetReserved
Definition: cabinet.h:457
ULONG LastBlockStart
Definition: cabinet.h:479
ULONG CommitDisk(ULONG MoreDisks)
Definition: cabinet.cxx:1393
ULONG DataReserved
Definition: cabinet.h:459
ULONG GetCurrentDiskNumber()
Definition: cabinet.cxx:376
std::string CabinetReservedFile
Definition: cabinet.h:451
ULONG ReadDataBlocks(PCFFOLDER_NODE FolderNode)
Definition: cabinet.cxx:2040
CCABCodec * Codec
Definition: cabinet.h:465
ULONG WriteDisk(ULONG MoreDisks)
Definition: cabinet.cxx:1311
ULONG TotalBytesLeft
Definition: cabinet.h:489
ULONG WriteFileToScratchStorage(PCFFILE_NODE FileNode)
Definition: cabinet.cxx:1197
ULONG ReadString(char *String, LONG MaxLength)
Definition: cabinet.cxx:1928
FILE * SourceFile
Definition: cabinet.h:487
PCFDATA_NODE NewDataNode(PCFFOLDER_NODE FolderNode)
Definition: cabinet.cxx:2147
ULONG SetAttributesOnFile(char *FileName, USHORT FileAttributes)
Definition: cabinet.cxx:2968
ULONG AddSearchCriteria(const std::string &SearchCriteria, const std::string &TargetFolder)
Definition: cabinet.cxx:228
virtual bool OnDiskLabel(ULONG Number, char *Label)
Definition: cabinet.cxx:1792
ULONG LocateFile(const char *FileName, PCFFILE_NODE *File)
Definition: cabinet.cxx:1885
char * GetCabinetName()
Definition: cabinet.cxx:194
bool CreateSimpleCabinet()
Definition: cabinet.cxx:1581
void * InputBuffer
Definition: cabinet.h:468
char CabinetNext[256]
Definition: cabinet.h:441
ULONG FolderReserved
Definition: cabinet.h:458
virtual bool OnCabinetName(ULONG Number, char *Name)
Definition: cabinet.cxx:1806
ULONG WriteFolderEntries()
Definition: cabinet.cxx:2618
Definition: raw.h:16
Definition: File.h:16
size_t length()
Definition: File.cpp:88
File()
Definition: File.h:18
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
_Check_return_ _Ret_opt_z_ _CRTIMP char *__cdecl getcwd(_Out_writes_opt_(_SizeInBytes) char *_DstBuf, _In_ int _SizeInBytes)
#define NULL
Definition: types.h:112
union node Node
Definition: types.h:1255
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
static void cleanup(void)
Definition: main.c:1335
BOOL WINAPI SetFileTime(IN HANDLE hFile, CONST FILETIME *lpCreationTime OPTIONAL, CONST FILETIME *lpLastAccessTime OPTIONAL, CONST FILETIME *lpLastWriteTime OPTIONAL)
Definition: fileinfo.c:948
BOOL WINAPI GetFileTime(IN HANDLE hFile, OUT LPFILETIME lpCreationTime OPTIONAL, OUT LPFILETIME lpLastAccessTime OPTIONAL, OUT LPFILETIME lpLastWriteTime OPTIONAL)
Definition: fileinfo.c:896
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
BOOL WINAPI DosDateTimeToFileTime(IN WORD wFatDate, IN WORD wFatTime, OUT LPFILETIME lpFileTime)
Definition: time.c:75
BOOL WINAPI FileTimeToDosDateTime(IN CONST FILETIME *lpFileTime, OUT LPWORD lpFatDate, OUT LPWORD lpFatTime)
Definition: time.c:37
static const WCHAR Message[]
Definition: register.c:74
__kernel_time_t time_t
Definition: linux.h:252
__kernel_off_t off_t
Definition: linux.h:201
#define strcasecmp
Definition: fake.h:9
struct _FileName FileName
Definition: fatprocs.h:897
unsigned long DWORD
Definition: ntddk_ex.h:95
_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:1236
_Must_inspect_result_ _In_opt_ PFLT_INSTANCE _Out_ PHANDLE FileHandle
Definition: fltkernel.h:1231
#define printf
Definition: freeldr.h:97
Status
Definition: gdiplustypes.h:25
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
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
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
int __cdecl closedir(DIR *)
DIR *__cdecl opendir(const char *)
struct dirent *__cdecl readdir(DIR *)
_Check_return_ _CRTIMP int __cdecl _fileno(_In_ FILE *_File)
_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)
_Check_return_ _CRTIMP FILE *__cdecl fopen(_In_z_ const char *_Filename, _In_z_ const char *_Mode)
_Check_return_opt_ _CRTIMP int __cdecl fseek(_Inout_ FILE *_File, _In_ long _Offset, _In_ int _Origin)
_Check_return_opt_ _CRTIMP int __cdecl fclose(_Inout_ FILE *_File)
_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)
#define SEEK_SET
Definition: jmemansi.c:26
if(dx< 0)
Definition: linetemp.h:194
void CloseFile(FILE **f)
Definition: util.c:327
#define SEEK_CUR
Definition: util.h:63
#define CREATE_ALWAYS
Definition: disk.h:72
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
static PLARGE_INTEGER Time
Definition: time.c:105
unsigned int UINT
Definition: ndis.h:50
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
#define GENERIC_WRITE
Definition: nt_native.h:90
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
_In_opt_ PENTER_STATE_SYSTEM_HANDLER _In_opt_ PVOID _In_ LONG _In_opt_ LONG volatile * Number
Definition: ntpoapi.h:207
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
static WCHAR szFilePath[]
Definition: qotd.c:14
#define errno
Definition: errno.h:18
_CRTIMP struct tm *__cdecl localtime(const time_t *_Time)
Definition: time.h:416
#define CAB_STATUS_NOFILE
Definition: cabinet.h:268
#define CAB_FILE_SPLIT
Definition: cabinet.h:138
#define CAB_STATUS_CANNOT_OPEN
Definition: cabinet.h:262
#define MIN_TRACE
Definition: cabinet.h:72
struct _CFHEADER CFHEADER
#define MID_TRACE
Definition: cabinet.h:73
#define DIR_SEPARATOR_CHAR
Definition: cabinet.h:51
#define CAB_CODEC_MSZIP
Definition: cabinet.h:304
#define CAB_FILE_MAX_FOLDER
Definition: cabinet.h:136
#define CAB_FILE_PREV_NEXT
Definition: cabinet.h:139
#define CAB_ATTRIB_HIDDEN
Definition: cabinet.h:128
#define DIR_SEPARATOR_STRING
Definition: cabinet.h:52
struct _CFFOLDER_NODE CFFOLDER_NODE
#define CAB_STATUS_CANNOT_READ
Definition: cabinet.h:264
#define DPRINT(_t_, _x_)
Definition: cabinet.h:103
#define CAB_FILE_CONTINUED
Definition: cabinet.h:137
#define CAB_ATTRIB_READONLY
Definition: cabinet.h:127
#define CAB_ATTRIB_DIRECTORY
Definition: cabinet.h:131
#define CAB_STATUS_UNSUPPCOMP
Definition: cabinet.h:269
#define CAB_STATUS_FILE_EXISTS
Definition: cabinet.h:266
#define CAB_COMP_MASK
Definition: cabinet.h:117
#define ASSERT(_x_)
Definition: cabinet.h:106
#define MAX_TRACE
Definition: cabinet.h:74
#define CAB_VERSION
Definition: cabinet.h:114
struct _CFFOLDER CFFOLDER
struct _CFDATA CFDATA
#define CAB_ATTRIB_SYSTEM
Definition: cabinet.h:129
#define CS_NOMEMORY
Definition: cabinet.h:297
#define CAB_STATUS_FAILURE
Definition: cabinet.h:260
#define CS_SUCCESS
Definition: cabinet.h:296
#define CAB_SIGNATURE
Definition: cabinet.h:113
#define CAB_STATUS_NOMEMORY
Definition: cabinet.h:261
#define CAB_COMP_NONE
Definition: cabinet.h:118
#define CAB_CODEC_RAW
Definition: cabinet.h:302
#define CAB_BLOCKSIZE
Definition: cabinet.h:115
#define CAB_STATUS_CANNOT_CREATE
Definition: cabinet.h:263
struct _CFDATA_NODE CFDATA_NODE
#define CAB_STATUS_SUCCESS
Definition: cabinet.h:259
#define CAB_FLAG_HASNEXT
Definition: cabinet.h:124
#define CAB_FLAG_RESERVE
Definition: cabinet.h:125
#define CAB_STATUS_CANNOT_WRITE
Definition: cabinet.h:265
#define CAB_ATTRIB_ARCHIVE
Definition: cabinet.h:132
#define CAB_FLAG_HASPREV
Definition: cabinet.h:123
struct _CFFILE CFFILE
LONG GetSizeOfFile(FILE *handle)
Definition: cabinet.h:55
#define CAB_COMP_MSZIP
Definition: cabinet.h:119
struct _SEARCH_CRITERIA SEARCH_CRITERIA
struct _CFFILE_NODE CFFILE_NODE
#define PATH_MAX
Definition: cabinet.h:32
#define CAB_STATUS_INVALID_CAB
Definition: cabinet.h:267
#define DPRINT
Definition: sndvol32.h:73
Definition: dirent.h:40
std::string FileName
Definition: cabinet.h:252
std::list< PCFFILE_NODE >::iterator Next
Definition: cabinet.h:250
PCFFILE File
Definition: cabinet.h:79
ULONG AbsoluteOffset
Definition: cabinet.h:214
ULONG ScratchFilePosition
Definition: cabinet.h:213
CFDATA Data
Definition: cabinet.h:216
USHORT CompSize
Definition: cabinet.c:131
USHORT UncompSize
Definition: cabinet.c:132
ULONG Checksum
Definition: cabinet.c:130
std::string TargetFolder
Definition: cabinet.h:235
std::string FileName
Definition: cabinet.h:234
CFFILE File
Definition: cabinet.h:233
bool Delete
Definition: cabinet.h:238
bool Commit
Definition: cabinet.h:237
PCFFOLDER_NODE FolderNode
Definition: cabinet.h:239
USHORT FileControlID
Definition: cabinet.h:188
ULONG FileSize
Definition: cabinet.c:118
ULONG FileOffset
Definition: cabinet.c:119
ULONG UncompOffset
Definition: cabinet.h:221
ULONG TotalFolderSize
Definition: cabinet.h:223
std::list< PCFDATA_NODE > DataList
Definition: cabinet.h:224
CFFOLDER Folder
Definition: cabinet.h:228
ULONG Index
Definition: cabinet.h:225
USHORT DataBlockCount
Definition: cabinet.c:109
USHORT CompressionType
Definition: cabinet.c:110
ULONG DataOffset
Definition: cabinet.c:108
USHORT Version
Definition: cabinet.c:88
USHORT SetID
Definition: cabinet.c:92
ULONG Reserved3
Definition: cabinet.c:87
ULONG Reserved1
Definition: cabinet.c:83
ULONG CabinetSize
Definition: cabinet.c:84
ULONG FileTableOffset
Definition: cabinet.c:86
USHORT FileCount
Definition: cabinet.c:90
USHORT FolderCount
Definition: cabinet.c:89
USHORT Flags
Definition: cabinet.c:91
USHORT CabinetNumber
Definition: cabinet.c:93
ULONG Signature
Definition: cabinet.c:82
ULONG Reserved2
Definition: cabinet.c:85
std::string TargetFolder
Definition: cabinet.h:245
std::string Search
Definition: cabinet.h:244
Definition: fatfs.h:198
char * d_name
Definition: dirent.h:29
Definition: stat.h:55
unsigned short st_mode
Definition: stat.h:58
time_t st_mtime
Definition: stat.h:65
Definition: time.h:68
int tm_mon
Definition: time.h:73
int tm_year
Definition: time.h:74
int tm_hour
Definition: time.h:71
int tm_sec
Definition: time.h:69
int tm_mday
Definition: time.h:72
int tm_min
Definition: time.h:70
uint32_t * PULONG
Definition: typedefs.h:59
uint16_t * PUSHORT
Definition: typedefs.h:56
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
Definition: dlist.c:348
_In_ WDFCOLLECTION _In_ ULONG Index
_Must_inspect_result_ _In_ WDFDMAENABLER _In_ _In_opt_ PWDF_OBJECT_ATTRIBUTES Attributes
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4533
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFSTRING String
Definition: wdfdevice.h:2433
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR OutputBuffer
Definition: wdfiotarget.h:863
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesWritten
Definition: wdfiotarget.h:960
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesRead
Definition: wdfiotarget.h:870
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR InputBuffer
Definition: wdfiotarget.h:953
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define GetFileAttributes
Definition: winbase.h:3840
#define SetFileAttributes
Definition: winbase.h:3934
#define FindNextFile
Definition: winbase.h:3813
#define FindFirstFile
Definition: winbase.h:3807
#define CreateFile
Definition: winbase.h:3774
char CHAR
Definition: xmlstorage.h:175