1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS text-mode setup
4 * FILE: base/setup/usetup/cabinet.c
5 * PURPOSE: Cabinet routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISIONS:
8 * CSH 15/08-2003 Created
9 */
10
11 #ifndef _USETUP_PCH_
12 #include "usetup.h"
13 #endif
14
15 #define Z_SOLO
16 #include <zlib.h>
17
18 #define NDEBUG
19 #include <debug.h>
20
21
22 /* DEFINITIONS **************************************************************/
23
24 /* File management definitions */
25
26 #define SEEK_BEGIN 0
27 #define SEEK_CURRENT 1
28 #ifndef SEEK_END
29 #define SEEK_END 2
30 #endif
31
32 typedef struct _DOSTIME
33 {
34 WORD Second:5;
35 WORD Minute:6;
36 WORD Hour:5;
37 } DOSTIME, *PDOSTIME;
38
39 typedef struct _DOSDATE
40 {
41 WORD Day:5;
42 WORD Month:4;
43 WORD Year:5;
44 } DOSDATE, *PDOSDATE;
45
46
47 /* Cabinet constants */
48
49 #define CAB_SIGNATURE 0x4643534D // "MSCF"
50 #define CAB_VERSION 0x0103
51 #define CAB_BLOCKSIZE 32768
52
53 #define CAB_COMP_MASK 0x00FF
54 #define CAB_COMP_NONE 0x0000
55 #define CAB_COMP_MSZIP 0x0001
56 #define CAB_COMP_QUANTUM 0x0002
57 #define CAB_COMP_LZX 0x0003
58
59 #define CAB_FLAG_HASPREV 0x0001
60 #define CAB_FLAG_HASNEXT 0x0002
61 #define CAB_FLAG_RESERVE 0x0004
62
63 #define CAB_ATTRIB_READONLY 0x0001
64 #define CAB_ATTRIB_HIDDEN 0x0002
65 #define CAB_ATTRIB_SYSTEM 0x0004
66 #define CAB_ATTRIB_VOLUME 0x0008
67 #define CAB_ATTRIB_DIRECTORY 0x0010
68 #define CAB_ATTRIB_ARCHIVE 0x0020
69 #define CAB_ATTRIB_EXECUTE 0x0040
70 #define CAB_ATTRIB_UTF_NAME 0x0080
71
72 #define CAB_FILE_MAX_FOLDER 0xFFFC
73 #define CAB_FILE_CONTINUED 0xFFFD
74 #define CAB_FILE_SPLIT 0xFFFE
75 #define CAB_FILE_PREV_NEXT 0xFFFF
76
77
78 /* Cabinet structures */
79
80 typedef struct _CFHEADER
81 {
82 ULONG Signature; // File signature 'MSCF' (CAB_SIGNATURE)
83 ULONG Reserved1; // Reserved field
84 ULONG CabinetSize; // Cabinet file size
85 ULONG Reserved2; // Reserved field
86 ULONG FileTableOffset; // Offset of first CFFILE
87 ULONG Reserved3; // Reserved field
88 USHORT Version; // Cabinet version (CAB_VERSION)
89 USHORT FolderCount; // Number of folders
90 USHORT FileCount; // Number of files
91 USHORT Flags; // Cabinet flags (CAB_FLAG_*)
92 USHORT SetID; // Cabinet set id
93 USHORT CabinetNumber; // Zero-based cabinet number
94 /* Optional fields (depends on Flags)
95 USHORT CabinetResSize // Per-cabinet reserved area size
96 CHAR FolderResSize // Per-folder reserved area size
97 CHAR FileResSize // Per-file reserved area size
98 CHAR CabinetReserved[] // Per-cabinet reserved area
99 CHAR CabinetPrev[] // Name of previous cabinet file
100 CHAR DiskPrev[] // Name of previous disk
101 CHAR CabinetNext[] // Name of next cabinet file
102 CHAR DiskNext[] // Name of next disk
103 */
104 } CFHEADER, *PCFHEADER;
105
106 typedef struct _CFFOLDER
107 {
108 ULONG DataOffset; // Absolute offset of first CFDATA block in this folder
109 USHORT DataBlockCount; // Number of CFDATA blocks in this folder in this cabinet
110 USHORT CompressionType; // Type of compression used for all CFDATA blocks in this folder
111 /* Optional fields (depends on Flags)
112 CHAR FolderReserved[] // Per-folder reserved area
113 */
114 } CFFOLDER, *PCFFOLDER;
115
116 typedef struct _CFFILE
117 {
118 ULONG FileSize; // Uncompressed file size in bytes
119 ULONG FileOffset; // Uncompressed offset of file in the folder
120 USHORT FolderIndex; // Index number of the folder that contains this file
121 USHORT FileDate; // File date stamp, as used by DOS
122 USHORT FileTime; // File time stamp, as used by DOS
123 USHORT Attributes; // File attributes (CAB_ATTRIB_*)
124 CHAR FileName[ANYSIZE_ARRAY];
125 /* After this is the NULL terminated filename */
126 } CFFILE, *PCFFILE;
127
128 typedef struct _CFDATA
129 {
130 ULONG Checksum; // Checksum of CFDATA entry
131 USHORT CompSize; // Number of compressed bytes in this block
132 USHORT UncompSize; // Number of uncompressed bytes in this block
133 /* Optional fields (depends on Flags)
134 CHAR DataReserved[] // Per-datablock reserved area
135 */
136 } CFDATA, *PCFDATA;
137
138
139 /* FUNCTIONS ****************************************************************/
140
141 #if !defined(_INC_MALLOC) && !defined(_INC_STDLIB)
142
143 /* Needed by zlib, but we don't want the dependency on the CRT */
144 void *__cdecl
malloc(size_t size)145 malloc(size_t size)
146 {
147 return RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, size);
148 }
149
150 void __cdecl
free(void * ptr)151 free(void *ptr)
152 {
153 RtlFreeHeap(ProcessHeap, 0, ptr);
154 }
155
156 void *__cdecl
calloc(size_t nmemb,size_t size)157 calloc(size_t nmemb, size_t size)
158 {
159 return (void *)RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, nmemb * size);
160 }
161
162 #endif // !_INC_MALLOC && !_INC_STDLIB
163
164
165 /* Codecs */
166
167 /* Uncompresses a data block */
168 typedef ULONG (*PCABINET_CODEC_UNCOMPRESS)(
169 IN struct _CAB_CODEC* Codec,
170 OUT PVOID OutputBuffer,
171 IN PVOID InputBuffer,
172 IN OUT PLONG InputLength,
173 IN OUT PLONG OutputLength);
174
175 typedef struct _CAB_CODEC
176 {
177 PCABINET_CODEC_UNCOMPRESS Uncompress;
178 z_stream ZStream;
179 // Other CODEC-related structures
180 } CAB_CODEC, *PCAB_CODEC;
181
182
183 /* RAW codec */
184
185 /*
186 * FUNCTION: Uncompresses data in a buffer
187 * ARGUMENTS:
188 * OutputBuffer = Pointer to buffer to place uncompressed data
189 * InputBuffer = Pointer to buffer with data to be uncompressed
190 * InputLength = Length of input buffer before, and amount consumed after
191 * Negative to indicate that this is not the start of a new block
192 * OutputLength = Length of output buffer before, amount filled after
193 * Negative to indicate that this is not the end of the block
194 */
195 ULONG
RawCodecUncompress(IN OUT PCAB_CODEC Codec,OUT PVOID OutputBuffer,IN PVOID InputBuffer,IN OUT PLONG InputLength,IN OUT PLONG OutputLength)196 RawCodecUncompress(
197 IN OUT PCAB_CODEC Codec,
198 OUT PVOID OutputBuffer,
199 IN PVOID InputBuffer,
200 IN OUT PLONG InputLength,
201 IN OUT PLONG OutputLength)
202 {
203 LONG Len = min(abs(*InputLength), abs(*OutputLength));
204
205 memcpy(OutputBuffer, InputBuffer, Len);
206 *InputLength = *OutputLength = Len;
207
208 return CS_SUCCESS;
209 }
210
211 static CAB_CODEC RawCodec =
212 {
213 RawCodecUncompress, {0}
214 };
215
216 /* MSZIP codec */
217
218 #define MSZIP_MAGIC 0x4B43
219
220 /*
221 * FUNCTION: Uncompresses data in a buffer
222 * ARGUMENTS:
223 * OutputBuffer = Pointer to buffer to place uncompressed data
224 * InputBuffer = Pointer to buffer with data to be uncompressed
225 * InputLength = Length of input buffer before, and amount consumed after
226 * Negative to indicate that this is not the start of a new block
227 * OutputLength = Length of output buffer before, amount filled after
228 * Negative to indicate that this is not the end of the block
229 */
230 ULONG
MSZipCodecUncompress(IN OUT PCAB_CODEC Codec,OUT PVOID OutputBuffer,IN PVOID InputBuffer,IN OUT PLONG InputLength,IN OUT PLONG OutputLength)231 MSZipCodecUncompress(
232 IN OUT PCAB_CODEC Codec,
233 OUT PVOID OutputBuffer,
234 IN PVOID InputBuffer,
235 IN OUT PLONG InputLength,
236 IN OUT PLONG OutputLength)
237 {
238 USHORT Magic;
239 INT Status;
240
241 DPRINT("MSZipCodecUncompress(OutputBuffer = %x, InputBuffer = %x, "
242 "InputLength = %d, OutputLength = %d)\n", OutputBuffer,
243 InputBuffer, *InputLength, *OutputLength);
244
245 if (*InputLength > 0)
246 {
247 Magic = *(PUSHORT)InputBuffer;
248
249 if (Magic != MSZIP_MAGIC)
250 {
251 DPRINT("Bad MSZIP block header magic (0x%X)\n", Magic);
252 return CS_BADSTREAM;
253 }
254
255 Codec->ZStream.next_in = (PUCHAR)InputBuffer + 2;
256 Codec->ZStream.avail_in = *InputLength - 2;
257 Codec->ZStream.next_out = (PUCHAR)OutputBuffer;
258 Codec->ZStream.avail_out = abs(*OutputLength);
259
260 /* WindowBits is passed < 0 to tell that there is no zlib header.
261 * Note that in this case inflate *requires* an extra "dummy" byte
262 * after the compressed stream in order to complete decompression and
263 * return Z_STREAM_END.
264 */
265 Status = inflateInit2(&Codec->ZStream, -MAX_WBITS);
266 if (Status != Z_OK)
267 {
268 DPRINT("inflateInit2() returned (%d)\n", Status);
269 return CS_BADSTREAM;
270 }
271 Codec->ZStream.total_in = 2;
272 }
273 else
274 {
275 Codec->ZStream.avail_in = -*InputLength;
276 Codec->ZStream.next_in = (PUCHAR)InputBuffer;
277 Codec->ZStream.next_out = (PUCHAR)OutputBuffer;
278 Codec->ZStream.avail_out = abs(*OutputLength);
279 Codec->ZStream.total_in = 0;
280 }
281
282 Codec->ZStream.total_out = 0;
283 Status = inflate(&Codec->ZStream, Z_SYNC_FLUSH);
284 if (Status != Z_OK && Status != Z_STREAM_END)
285 {
286 DPRINT("inflate() returned (%d) (%s)\n", Status, Codec->ZStream.msg);
287 if (Status == Z_MEM_ERROR)
288 return CS_NOMEMORY;
289 return CS_BADSTREAM;
290 }
291
292 if (*OutputLength > 0)
293 {
294 Status = inflateEnd(&Codec->ZStream);
295 if (Status != Z_OK)
296 {
297 DPRINT("inflateEnd() returned (%d)\n", Status);
298 return CS_BADSTREAM;
299 }
300 }
301
302 *InputLength = Codec->ZStream.total_in;
303 *OutputLength = Codec->ZStream.total_out;
304
305 return CS_SUCCESS;
306 }
307
308 static CAB_CODEC MSZipCodec =
309 {
310 MSZipCodecUncompress, {0}
311 };
312
313
314 /* Memory functions */
315
316 voidpf
MSZipAlloc(voidpf opaque,uInt items,uInt size)317 MSZipAlloc(voidpf opaque, uInt items, uInt size)
318 {
319 return (voidpf)RtlAllocateHeap(ProcessHeap, 0, items * size);
320 }
321
322 void
MSZipFree(voidpf opaque,voidpf address)323 MSZipFree(voidpf opaque, voidpf address)
324 {
325 RtlFreeHeap(ProcessHeap, 0, address);
326 }
327
328 static BOOL
ConvertSystemTimeToFileTime(CONST SYSTEMTIME * lpSystemTime,LPFILETIME lpFileTime)329 ConvertSystemTimeToFileTime(CONST SYSTEMTIME *lpSystemTime,
330 LPFILETIME lpFileTime)
331 {
332 TIME_FIELDS TimeFields;
333 LARGE_INTEGER liTime;
334
335 TimeFields.Year = lpSystemTime->wYear;
336 TimeFields.Month = lpSystemTime->wMonth;
337 TimeFields.Day = lpSystemTime->wDay;
338 TimeFields.Hour = lpSystemTime->wHour;
339 TimeFields.Minute = lpSystemTime->wMinute;
340 TimeFields.Second = lpSystemTime->wSecond;
341 TimeFields.Milliseconds = lpSystemTime->wMilliseconds;
342
343 if (RtlTimeFieldsToTime(&TimeFields, &liTime))
344 {
345 lpFileTime->dwLowDateTime = liTime.u.LowPart;
346 lpFileTime->dwHighDateTime = liTime.u.HighPart;
347 return TRUE;
348 }
349
350 return FALSE;
351 }
352
353 static BOOL
ConvertDosDateTimeToFileTime(WORD wFatDate,WORD wFatTime,LPFILETIME lpFileTime)354 ConvertDosDateTimeToFileTime(WORD wFatDate,
355 WORD wFatTime,
356 LPFILETIME lpFileTime)
357 {
358 PDOSTIME pdtime = (PDOSTIME)&wFatTime;
359 PDOSDATE pddate = (PDOSDATE)&wFatDate;
360 SYSTEMTIME SystemTime;
361
362 if (lpFileTime == NULL)
363 return FALSE;
364
365 SystemTime.wMilliseconds = 0;
366 SystemTime.wSecond = pdtime->Second;
367 SystemTime.wMinute = pdtime->Minute;
368 SystemTime.wHour = pdtime->Hour;
369
370 SystemTime.wDay = pddate->Day;
371 SystemTime.wMonth = pddate->Month;
372 SystemTime.wYear = 1980 + pddate->Year;
373
374 ConvertSystemTimeToFileTime(&SystemTime, lpFileTime);
375
376 return TRUE;
377 }
378
379 /*
380 * FUNCTION: Returns a pointer to file name
381 * ARGUMENTS:
382 * Path = Pointer to string with pathname
383 * RETURNS:
384 * Pointer to filename
385 */
386 static PWCHAR
GetFileName(PWCHAR Path)387 GetFileName(PWCHAR Path)
388 {
389 ULONG i, j;
390
391 j = i = 0;
392
393 while (Path[i++])
394 {
395 if (Path[i - 1] == L'\\')
396 j = i;
397 }
398
399 return Path + j;
400 }
401
402 /*
403 * FUNCTION: Removes a file name from a path
404 * ARGUMENTS:
405 * Path = Pointer to string with path
406 */
407 static VOID
RemoveFileName(PWCHAR Path)408 RemoveFileName(PWCHAR Path)
409 {
410 PWCHAR FileName;
411 DWORD i;
412
413 i = 0;
414 FileName = GetFileName(Path + i);
415
416 if (FileName != Path + i && FileName[-1] == L'\\')
417 FileName--;
418
419 if (FileName == Path + i && FileName[0] == L'\\')
420 FileName++;
421
422 FileName[0] = 0;
423 }
424
425 /*
426 * FUNCTION: Sets attributes on a file
427 * ARGUMENTS:
428 * File = Pointer to CFFILE node for file
429 * RETURNS:
430 * Status of operation
431 */
432 static BOOL
SetAttributesOnFile(PCFFILE File,HANDLE hFile)433 SetAttributesOnFile(PCFFILE File,
434 HANDLE hFile)
435 {
436 FILE_BASIC_INFORMATION FileBasic;
437 IO_STATUS_BLOCK IoStatusBlock;
438 NTSTATUS NtStatus;
439 ULONG Attributes = 0;
440
441 if (File->Attributes & CAB_ATTRIB_READONLY)
442 Attributes |= FILE_ATTRIBUTE_READONLY;
443
444 if (File->Attributes & CAB_ATTRIB_HIDDEN)
445 Attributes |= FILE_ATTRIBUTE_HIDDEN;
446
447 if (File->Attributes & CAB_ATTRIB_SYSTEM)
448 Attributes |= FILE_ATTRIBUTE_SYSTEM;
449
450 if (File->Attributes & CAB_ATTRIB_DIRECTORY)
451 Attributes |= FILE_ATTRIBUTE_DIRECTORY;
452
453 if (File->Attributes & CAB_ATTRIB_ARCHIVE)
454 Attributes |= FILE_ATTRIBUTE_ARCHIVE;
455
456 NtStatus = NtQueryInformationFile(hFile,
457 &IoStatusBlock,
458 &FileBasic,
459 sizeof(FILE_BASIC_INFORMATION),
460 FileBasicInformation);
461 if (!NT_SUCCESS(NtStatus))
462 {
463 DPRINT("NtQueryInformationFile() failed (%x)\n", NtStatus);
464 }
465 else
466 {
467 FileBasic.FileAttributes = Attributes;
468
469 NtStatus = NtSetInformationFile(hFile,
470 &IoStatusBlock,
471 &FileBasic,
472 sizeof(FILE_BASIC_INFORMATION),
473 FileBasicInformation);
474 if (!NT_SUCCESS(NtStatus))
475 {
476 DPRINT("NtSetInformationFile() failed (%x)\n", NtStatus);
477 }
478 }
479
480 return NT_SUCCESS(NtStatus);
481 }
482
483 /*
484 * FUNCTION: Closes the current cabinet
485 * RETURNS:
486 * Status of operation
487 */
488 static ULONG
CloseCabinet(IN PCABINET_CONTEXT CabinetContext)489 CloseCabinet(
490 IN PCABINET_CONTEXT CabinetContext)
491 {
492 if (CabinetContext->FileBuffer)
493 {
494 NtUnmapViewOfSection(NtCurrentProcess(), CabinetContext->FileBuffer);
495 NtClose(CabinetContext->FileSectionHandle);
496 NtClose(CabinetContext->FileHandle);
497 CabinetContext->FileBuffer = NULL;
498 }
499
500 return 0;
501 }
502
503 /*
504 * FUNCTION: Initialize archiver
505 */
506 VOID
CabinetInitialize(IN OUT PCABINET_CONTEXT CabinetContext)507 CabinetInitialize(
508 IN OUT PCABINET_CONTEXT CabinetContext)
509 {
510 RtlZeroMemory(CabinetContext, sizeof(*CabinetContext));
511
512 CabinetContext->FileOpen = FALSE;
513 wcscpy(CabinetContext->DestPath, L"");
514
515 CabinetContext->CodecSelected = FALSE;
516 CabinetSelectCodec(CabinetContext, CAB_CODEC_RAW);
517
518 CabinetContext->OverwriteHandler = NULL;
519 CabinetContext->ExtractHandler = NULL;
520 CabinetContext->DiskChangeHandler = NULL;
521
522 CabinetContext->FolderUncompSize = 0;
523 CabinetContext->BytesLeftInBlock = 0;
524 CabinetContext->CabinetReserved = 0;
525 CabinetContext->FolderReserved = 0;
526 CabinetContext->DataReserved = 0;
527 CabinetContext->CabinetReservedArea = NULL;
528 CabinetContext->LastFileOffset = 0;
529 }
530
531 /*
532 * FUNCTION: Cleanup archiver
533 */
534 VOID
CabinetCleanup(IN OUT PCABINET_CONTEXT CabinetContext)535 CabinetCleanup(
536 IN OUT PCABINET_CONTEXT CabinetContext)
537 {
538 CabinetClose(CabinetContext);
539 }
540
541 /*
542 * FUNCTION: Normalizes a path
543 * ARGUMENTS:
544 * Path = Pointer to string with pathname
545 * Length = Number of characters in Path
546 * RETURNS:
547 * TRUE if there was enough room in Path, or FALSE
548 */
549 static BOOL
CabinetNormalizePath(PWCHAR Path,ULONG Length)550 CabinetNormalizePath(PWCHAR Path,
551 ULONG Length)
552 {
553 ULONG n;
554 BOOL Ok;
555
556 n = wcslen(Path);
557 Ok = (n + 1) < Length;
558
559 if (n != 0 && Path[n - 1] != L'\\' && Ok)
560 {
561 Path[n] = L'\\';
562 Path[n + 1] = 0;
563 }
564
565 return Ok;
566 }
567
568 /*
569 * FUNCTION: Returns pointer to cabinet file name
570 * RETURNS:
571 * Pointer to string with name of cabinet
572 */
573 PCWSTR
CabinetGetCabinetName(IN PCABINET_CONTEXT CabinetContext)574 CabinetGetCabinetName(
575 IN PCABINET_CONTEXT CabinetContext)
576 {
577 return CabinetContext->CabinetName;
578 }
579
580 /*
581 * FUNCTION: Sets cabinet file name
582 * ARGUMENTS:
583 * FileName = Pointer to string with name of cabinet
584 */
585 VOID
CabinetSetCabinetName(IN PCABINET_CONTEXT CabinetContext,IN PCWSTR FileName)586 CabinetSetCabinetName(
587 IN PCABINET_CONTEXT CabinetContext,
588 IN PCWSTR FileName)
589 {
590 wcscpy(CabinetContext->CabinetName, FileName);
591 }
592
593 /*
594 * FUNCTION: Sets destination path
595 * ARGUMENTS:
596 * DestinationPath = Pointer to string with name of destination path
597 */
598 VOID
CabinetSetDestinationPath(IN PCABINET_CONTEXT CabinetContext,IN PCWSTR DestinationPath)599 CabinetSetDestinationPath(
600 IN PCABINET_CONTEXT CabinetContext,
601 IN PCWSTR DestinationPath)
602 {
603 wcscpy(CabinetContext->DestPath, DestinationPath);
604
605 if (wcslen(CabinetContext->DestPath) > 0)
606 CabinetNormalizePath(CabinetContext->DestPath, MAX_PATH);
607 }
608
609 /*
610 * FUNCTION: Returns destination path
611 * RETURNS:
612 * Pointer to string with name of destination path
613 */
614 PCWSTR
CabinetGetDestinationPath(IN PCABINET_CONTEXT CabinetContext)615 CabinetGetDestinationPath(
616 IN PCABINET_CONTEXT CabinetContext)
617 {
618 return CabinetContext->DestPath;
619 }
620
621 /*
622 * FUNCTION: Opens a cabinet file
623 * RETURNS:
624 * Status of operation
625 */
626 ULONG
CabinetOpen(IN OUT PCABINET_CONTEXT CabinetContext)627 CabinetOpen(
628 IN OUT PCABINET_CONTEXT CabinetContext)
629 {
630 PUCHAR Buffer;
631 UNICODE_STRING ustring;
632 ANSI_STRING astring;
633
634 OBJECT_ATTRIBUTES ObjectAttributes;
635 IO_STATUS_BLOCK IoStatusBlock;
636 UNICODE_STRING FileName;
637 USHORT StringLength;
638 NTSTATUS NtStatus;
639
640 if (CabinetContext->FileOpen)
641 {
642 /* Cabinet file already opened */
643 DPRINT("CabinetOpen returning SUCCESS\n");
644 return CAB_STATUS_SUCCESS;
645 }
646
647 RtlInitUnicodeString(&FileName, CabinetContext->CabinetName);
648
649 InitializeObjectAttributes(&ObjectAttributes,
650 &FileName,
651 OBJ_CASE_INSENSITIVE,
652 NULL, NULL);
653
654 NtStatus = NtOpenFile(&CabinetContext->FileHandle,
655 GENERIC_READ | SYNCHRONIZE,
656 &ObjectAttributes,
657 &IoStatusBlock,
658 FILE_SHARE_READ,
659 FILE_SYNCHRONOUS_IO_NONALERT);
660
661 if (!NT_SUCCESS(NtStatus))
662 {
663 DPRINT1("Cannot open file (%S) (%x)\n", CabinetContext->CabinetName, NtStatus);
664 return CAB_STATUS_CANNOT_OPEN;
665 }
666
667 CabinetContext->FileOpen = TRUE;
668
669 NtStatus = NtCreateSection(&CabinetContext->FileSectionHandle,
670 SECTION_ALL_ACCESS,
671 0, 0,
672 PAGE_READONLY,
673 SEC_COMMIT,
674 CabinetContext->FileHandle);
675
676 if (!NT_SUCCESS(NtStatus))
677 {
678 DPRINT1("NtCreateSection failed for %ls: %x\n", CabinetContext->CabinetName, NtStatus);
679 return CAB_STATUS_NOMEMORY;
680 }
681
682 CabinetContext->FileBuffer = 0;
683 CabinetContext->FileSize = 0;
684
685 NtStatus = NtMapViewOfSection(CabinetContext->FileSectionHandle,
686 NtCurrentProcess(),
687 (PVOID*)&CabinetContext->FileBuffer,
688 0, 0, 0,
689 &CabinetContext->FileSize,
690 ViewUnmap,
691 0,
692 PAGE_READONLY);
693
694 if (!NT_SUCCESS(NtStatus))
695 {
696 DPRINT1("NtMapViewOfSection failed: %x\n", NtStatus);
697 return CAB_STATUS_NOMEMORY;
698 }
699
700 DPRINT("Cabinet file %S opened and mapped to %x\n",
701 CabinetContext->CabinetName, CabinetContext->FileBuffer);
702 CabinetContext->PCABHeader = (PCFHEADER)CabinetContext->FileBuffer;
703
704 /* Check header */
705 if (CabinetContext->FileSize <= sizeof(CFHEADER) ||
706 CabinetContext->PCABHeader->Signature != CAB_SIGNATURE ||
707 CabinetContext->PCABHeader->Version != CAB_VERSION ||
708 CabinetContext->PCABHeader->FolderCount == 0 ||
709 CabinetContext->PCABHeader->FileCount == 0 ||
710 CabinetContext->PCABHeader->FileTableOffset < sizeof(CFHEADER))
711 {
712 CloseCabinet(CabinetContext);
713 DPRINT1("File has invalid header\n");
714 return CAB_STATUS_INVALID_CAB;
715 }
716
717 Buffer = (PUCHAR)(CabinetContext->PCABHeader + 1);
718
719 /* Read/skip any reserved bytes */
720 if (CabinetContext->PCABHeader->Flags & CAB_FLAG_RESERVE)
721 {
722 CabinetContext->CabinetReserved = *(PUSHORT)Buffer;
723 Buffer += 2;
724 CabinetContext->FolderReserved = *Buffer;
725 Buffer++;
726 CabinetContext->DataReserved = *Buffer;
727 Buffer++;
728
729 if (CabinetContext->CabinetReserved > 0)
730 {
731 CabinetContext->CabinetReservedArea = Buffer;
732 Buffer += CabinetContext->CabinetReserved;
733 }
734 }
735
736 if (CabinetContext->PCABHeader->Flags & CAB_FLAG_HASPREV)
737 {
738 /* The previous cabinet file is in
739 the same directory as the current */
740 wcscpy(CabinetContext->CabinetPrev, CabinetContext->CabinetName);
741 RemoveFileName(CabinetContext->CabinetPrev);
742 CabinetNormalizePath(CabinetContext->CabinetPrev, sizeof(CabinetContext->CabinetPrev));
743 RtlInitAnsiString(&astring, (LPSTR)Buffer);
744
745 /* Initialize ustring with the remaining buffer */
746 StringLength = (USHORT)wcslen(CabinetContext->CabinetPrev) * sizeof(WCHAR);
747 ustring.Buffer = CabinetContext->CabinetPrev + StringLength;
748 ustring.MaximumLength = sizeof(CabinetContext->CabinetPrev) - StringLength;
749 ustring.Length = 0;
750 RtlAnsiStringToUnicodeString(&ustring, &astring, FALSE);
751 Buffer += astring.Length + 1;
752
753 /* Read label of prev disk */
754 RtlInitAnsiString(&astring, (LPSTR)Buffer);
755 ustring.Length = 0;
756 ustring.Buffer = CabinetContext->DiskPrev;
757 ustring.MaximumLength = sizeof(CabinetContext->DiskPrev);
758 RtlAnsiStringToUnicodeString(&ustring, &astring, FALSE);
759 Buffer += astring.Length + 1;
760 }
761 else
762 {
763 wcscpy(CabinetContext->CabinetPrev, L"");
764 wcscpy(CabinetContext->DiskPrev, L"");
765 }
766
767 if (CabinetContext->PCABHeader->Flags & CAB_FLAG_HASNEXT)
768 {
769 /* The next cabinet file is in
770 the same directory as the previous */
771 wcscpy(CabinetContext->CabinetNext, CabinetContext->CabinetName);
772 RemoveFileName(CabinetContext->CabinetNext);
773 CabinetNormalizePath(CabinetContext->CabinetNext, 256);
774 RtlInitAnsiString(&astring, (LPSTR)Buffer);
775
776 /* Initialize ustring with the remaining buffer */
777 StringLength = (USHORT)wcslen(CabinetContext->CabinetNext) * sizeof(WCHAR);
778 ustring.Buffer = CabinetContext->CabinetNext + StringLength;
779 ustring.MaximumLength = sizeof(CabinetContext->CabinetNext) - StringLength;
780 ustring.Length = 0;
781 RtlAnsiStringToUnicodeString(&ustring, &astring, FALSE);
782 Buffer += astring.Length + 1;
783
784 /* Read label of next disk */
785 RtlInitAnsiString(&astring, (LPSTR)Buffer);
786 ustring.Length = 0;
787 ustring.Buffer = CabinetContext->DiskNext;
788 ustring.MaximumLength = sizeof(CabinetContext->DiskNext);
789 RtlAnsiStringToUnicodeString(&ustring, &astring, FALSE);
790 Buffer += astring.Length + 1;
791 }
792 else
793 {
794 wcscpy(CabinetContext->CabinetNext, L"");
795 wcscpy(CabinetContext->DiskNext, L"");
796 }
797 CabinetContext->CabinetFolders = (PCFFOLDER)Buffer;
798
799 DPRINT("CabinetOpen returning SUCCESS\n");
800 return CAB_STATUS_SUCCESS;
801 }
802
803 /*
804 * FUNCTION: Closes the cabinet file
805 */
806 VOID
CabinetClose(IN OUT PCABINET_CONTEXT CabinetContext)807 CabinetClose(
808 IN OUT PCABINET_CONTEXT CabinetContext)
809 {
810 if (!CabinetContext->FileOpen)
811 return;
812
813 CloseCabinet(CabinetContext);
814 CabinetContext->FileOpen = FALSE;
815 }
816
817 /*
818 * FUNCTION: Finds the first file in the cabinet that matches a search criteria
819 * ARGUMENTS:
820 * FileName = Pointer to search criteria
821 * Search = Pointer to search structure
822 * RETURNS:
823 * Status of operation
824 */
825 ULONG
CabinetFindFirst(IN PCABINET_CONTEXT CabinetContext,IN PCWSTR FileName,IN OUT PCAB_SEARCH Search)826 CabinetFindFirst(
827 IN PCABINET_CONTEXT CabinetContext,
828 IN PCWSTR FileName,
829 IN OUT PCAB_SEARCH Search)
830 {
831 DPRINT("CabinetFindFirst(FileName = %S)\n", FileName);
832 wcsncpy(Search->Search, FileName, MAX_PATH);
833 wcsncpy(Search->Cabinet, CabinetContext->CabinetName, MAX_PATH);
834 Search->File = 0;
835 return CabinetFindNext(CabinetContext, Search);
836 }
837
838 /*
839 * FUNCTION: Finds next file in the cabinet that matches a search criteria
840 * ARGUMENTS:
841 * Search = Pointer to search structure
842 * RETURNS:
843 * Status of operation
844 */
845 ULONG
CabinetFindNext(IN PCABINET_CONTEXT CabinetContext,IN OUT PCAB_SEARCH Search)846 CabinetFindNext(
847 IN PCABINET_CONTEXT CabinetContext,
848 IN OUT PCAB_SEARCH Search)
849 {
850 PCFFILE Prev;
851 ANSI_STRING AnsiString;
852 UNICODE_STRING UnicodeString;
853 WCHAR FileName[MAX_PATH];
854
855 if (wcscmp(Search->Cabinet, CabinetContext->CabinetName) != 0)
856 {
857 /* restart search of cabinet has changed since last find */
858 Search->File = 0;
859 }
860
861 if (!Search->File)
862 {
863 /* starting new search or cabinet */
864 Search->File = (PCFFILE)(CabinetContext->FileBuffer + CabinetContext->PCABHeader->FileTableOffset);
865 Search->Index = 0;
866 Prev = 0;
867 }
868 else
869 Prev = Search->File;
870
871 while (TRUE)
872 {
873 /* look at each file in the archive and see if we found a match */
874 if (Search->File->FolderIndex == 0xFFFD ||
875 Search->File->FolderIndex == 0xFFFF)
876 {
877 /* skip files continued from previous cab */
878 DPRINT("Skipping file (%s): FileOffset (0x%X), "
879 "LastFileOffset (0x%X)\n", (char *)(Search->File + 1),
880 Search->File->FileOffset, CabinetContext->LastFileOffset);
881 }
882 else
883 {
884 // FIXME: check for match against search criteria
885 if (Search->File != Prev)
886 {
887 if (Prev == NULL || Search->File->FolderIndex != Prev->FolderIndex)
888 {
889 Search->CFData = NULL;
890 Search->Offset = 0;
891 }
892
893 /* don't match the file we started with */
894 if (wcscmp(Search->Search, L"*") == 0)
895 {
896 /* take any file */
897 break;
898 }
899 else
900 {
901 /* otherwise, try to match the exact file name */
902 RtlInitAnsiString(&AnsiString, Search->File->FileName);
903 UnicodeString.Buffer = FileName;
904 UnicodeString.Buffer[0] = 0;
905 UnicodeString.Length = 0;
906 UnicodeString.MaximumLength = sizeof(FileName);
907 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
908 if (wcscmp(Search->Search, UnicodeString.Buffer) == 0)
909 break;
910 }
911 }
912 }
913
914 /* if we make it here we found no match, so move to the next file */
915 Search->Index++;
916 if (Search->Index >= CabinetContext->PCABHeader->FileCount)
917 {
918 /* we have reached the end of this cabinet */
919 DPRINT("End of cabinet reached\n");
920 return CAB_STATUS_NOFILE;
921 }
922 else
923 Search->File = (PCFFILE)(strchr((char *)(Search->File + 1), 0) + 1);
924 }
925
926 DPRINT("Found file %s\n", Search->File->FileName);
927 return CAB_STATUS_SUCCESS;
928 }
929
930 /*
931 * FUNCTION: Finds the next file in the cabinet that matches a search criteria
932 * ARGUMENTS:
933 * FileName = Pointer to search criteria
934 * Search = Pointer to search structure
935 * RETURNS:
936 * Status of operation
937 */
938 ULONG
CabinetFindNextFileSequential(IN PCABINET_CONTEXT CabinetContext,IN PCWSTR FileName,IN OUT PCAB_SEARCH Search)939 CabinetFindNextFileSequential(
940 IN PCABINET_CONTEXT CabinetContext,
941 IN PCWSTR FileName,
942 IN OUT PCAB_SEARCH Search)
943 {
944 DPRINT("CabinetFindNextFileSequential(FileName = %S)\n", FileName);
945 wcsncpy(Search->Search, FileName, MAX_PATH);
946 return CabinetFindNext(CabinetContext, Search);
947 }
948
949 #if 0
950 int
951 Validate(VOID)
952 {
953 return (int)RtlValidateHeap(ProcessHeap, 0, 0);
954 }
955 #endif
956
957 /*
958 * FUNCTION: Extracts a file from the cabinet
959 * ARGUMENTS:
960 * Search = Pointer to PCAB_SEARCH structure used to locate the file
961 * RETURNS
962 * Status of operation
963 */
964 ULONG
CabinetExtractFile(IN PCABINET_CONTEXT CabinetContext,IN PCAB_SEARCH Search)965 CabinetExtractFile(
966 IN PCABINET_CONTEXT CabinetContext,
967 IN PCAB_SEARCH Search)
968 {
969 ULONG Size; // remaining file bytes to decompress
970 ULONG CurrentOffset; // current uncompressed offset within the folder
971 PUCHAR CurrentBuffer; // current pointer to compressed data in the block
972 LONG RemainingBlock; // remaining comp data in the block
973 HANDLE DestFile;
974 HANDLE DestFileSection;
975 PVOID DestFileBuffer; // mapped view of dest file
976 PVOID CurrentDestBuffer; // pointer to the current position in the dest view
977 PCFDATA CFData; // current data block
978 ULONG Status;
979 FILETIME FileTime;
980 WCHAR DestName[MAX_PATH];
981 NTSTATUS NtStatus;
982 UNICODE_STRING UnicodeString;
983 ANSI_STRING AnsiString;
984 IO_STATUS_BLOCK IoStatusBlock;
985 OBJECT_ATTRIBUTES ObjectAttributes;
986 FILE_BASIC_INFORMATION FileBasic;
987 PCFFOLDER CurrentFolder;
988 LARGE_INTEGER MaxDestFileSize;
989 LONG InputLength, OutputLength;
990 SIZE_T StringLength;
991 char Chunk[512];
992
993 if (wcscmp(Search->Cabinet, CabinetContext->CabinetName) != 0)
994 {
995 /* the file is not in the current cabinet */
996 DPRINT("File is not in this cabinet (%S != %S)\n",
997 Search->Cabinet, CabinetContext->CabinetName);
998 return CAB_STATUS_NOFILE;
999 }
1000
1001 /* look up the folder that the file specifies */
1002 if (Search->File->FolderIndex == 0xFFFD ||
1003 Search->File->FolderIndex == 0xFFFF)
1004 {
1005 /* folder is continued from previous cabinet,
1006 that shouldn't happen here */
1007 return CAB_STATUS_NOFILE;
1008 }
1009 else if (Search->File->FolderIndex == 0xFFFE)
1010 {
1011 /* folder is the last in this cabinet and continues into next */
1012 CurrentFolder = &CabinetContext->CabinetFolders[CabinetContext->PCABHeader->FolderCount - 1];
1013 }
1014 else
1015 {
1016 /* folder is completely contained within this cabinet */
1017 CurrentFolder = &CabinetContext->CabinetFolders[Search->File->FolderIndex];
1018 }
1019
1020 switch (CurrentFolder->CompressionType & CAB_COMP_MASK)
1021 {
1022 case CAB_COMP_NONE:
1023 CabinetSelectCodec(CabinetContext, CAB_CODEC_RAW);
1024 break;
1025 case CAB_COMP_MSZIP:
1026 CabinetSelectCodec(CabinetContext, CAB_CODEC_MSZIP);
1027 break;
1028 default:
1029 return CAB_STATUS_UNSUPPCOMP;
1030 }
1031
1032 DPRINT("Extracting file at uncompressed offset (0x%X) Size (%d bytes)\n",
1033 (UINT)Search->File->FileOffset, (UINT)Search->File->FileSize);
1034
1035 if (CabinetContext->CreateFileHandler)
1036 {
1037 /* Call create context */
1038 CurrentDestBuffer = CabinetContext->CreateFileHandler(CabinetContext, Search->File->FileSize);
1039 if (!CurrentDestBuffer)
1040 {
1041 DPRINT1("CreateFileHandler() failed\n");
1042 return CAB_STATUS_CANNOT_CREATE;
1043 }
1044 }
1045 else
1046 {
1047 RtlInitAnsiString(&AnsiString, Search->File->FileName);
1048 wcscpy(DestName, CabinetContext->DestPath);
1049 StringLength = wcslen(DestName);
1050 UnicodeString.MaximumLength = sizeof(DestName) - (USHORT)StringLength * sizeof(WCHAR);
1051 UnicodeString.Buffer = DestName + StringLength;
1052 UnicodeString.Length = 0;
1053 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
1054
1055 /* Create destination file, fail if it already exists */
1056 RtlInitUnicodeString(&UnicodeString, DestName);
1057
1058 InitializeObjectAttributes(&ObjectAttributes,
1059 &UnicodeString,
1060 OBJ_CASE_INSENSITIVE,
1061 NULL, NULL);
1062
1063 NtStatus = NtCreateFile(&DestFile,
1064 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
1065 &ObjectAttributes,
1066 &IoStatusBlock,
1067 NULL,
1068 FILE_ATTRIBUTE_NORMAL,
1069 0,
1070 FILE_CREATE,
1071 FILE_SYNCHRONOUS_IO_NONALERT,
1072 NULL, 0);
1073
1074 if (!NT_SUCCESS(NtStatus))
1075 {
1076 DPRINT("NtCreateFile() failed (%S) (%x)\n", DestName, NtStatus);
1077
1078 /* If file exists, ask to overwrite file */
1079 if (CabinetContext->OverwriteHandler == NULL ||
1080 CabinetContext->OverwriteHandler(CabinetContext, Search->File, DestName))
1081 {
1082 /* Create destination file, overwrite if it already exists */
1083 NtStatus = NtCreateFile(&DestFile,
1084 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
1085 &ObjectAttributes,
1086 &IoStatusBlock,
1087 NULL,
1088 FILE_ATTRIBUTE_NORMAL,
1089 0,
1090 FILE_OVERWRITE,
1091 FILE_SYNCHRONOUS_IO_ALERT,
1092 NULL, 0);
1093
1094 if (!NT_SUCCESS(NtStatus))
1095 {
1096 DPRINT1("NtCreateFile() failed (%S) (%x)\n", DestName, NtStatus);
1097 return CAB_STATUS_CANNOT_CREATE;
1098 }
1099 }
1100 else
1101 {
1102 DPRINT1("File (%S) exists\n", DestName);
1103 return CAB_STATUS_FILE_EXISTS;
1104 }
1105 }
1106
1107 if (!ConvertDosDateTimeToFileTime(Search->File->FileDate,
1108 Search->File->FileTime,
1109 &FileTime))
1110 {
1111 DPRINT1("DosDateTimeToFileTime() failed\n");
1112 Status = CAB_STATUS_CANNOT_WRITE;
1113 goto CloseDestFile;
1114 }
1115
1116 NtStatus = NtQueryInformationFile(DestFile,
1117 &IoStatusBlock,
1118 &FileBasic,
1119 sizeof(FILE_BASIC_INFORMATION),
1120 FileBasicInformation);
1121 if (!NT_SUCCESS(NtStatus))
1122 {
1123 DPRINT("NtQueryInformationFile() failed (%x)\n", NtStatus);
1124 }
1125 else
1126 {
1127 memcpy(&FileBasic.LastAccessTime, &FileTime, sizeof(FILETIME));
1128
1129 NtStatus = NtSetInformationFile(DestFile,
1130 &IoStatusBlock,
1131 &FileBasic,
1132 sizeof(FILE_BASIC_INFORMATION),
1133 FileBasicInformation);
1134 if (!NT_SUCCESS(NtStatus))
1135 {
1136 DPRINT("NtSetInformationFile() failed (%x)\n", NtStatus);
1137 }
1138 }
1139
1140 SetAttributesOnFile(Search->File, DestFile);
1141
1142 /* Nothing more to do for 0 sized files */
1143 if (Search->File->FileSize == 0)
1144 {
1145 Status = CAB_STATUS_SUCCESS;
1146 goto CloseDestFile;
1147 }
1148
1149 MaxDestFileSize.QuadPart = Search->File->FileSize;
1150 NtStatus = NtCreateSection(&DestFileSection,
1151 SECTION_ALL_ACCESS,
1152 0,
1153 &MaxDestFileSize,
1154 PAGE_READWRITE,
1155 SEC_COMMIT,
1156 DestFile);
1157
1158 if (!NT_SUCCESS(NtStatus))
1159 {
1160 DPRINT1("NtCreateSection failed for %ls: %x\n", DestName, NtStatus);
1161 Status = CAB_STATUS_NOMEMORY;
1162 goto CloseDestFile;
1163 }
1164
1165 DestFileBuffer = 0;
1166 CabinetContext->DestFileSize = 0;
1167 NtStatus = NtMapViewOfSection(DestFileSection,
1168 NtCurrentProcess(),
1169 &DestFileBuffer,
1170 0, 0, 0,
1171 &CabinetContext->DestFileSize,
1172 ViewUnmap,
1173 0,
1174 PAGE_READWRITE);
1175
1176 if (!NT_SUCCESS(NtStatus))
1177 {
1178 DPRINT1("NtMapViewOfSection failed: %x\n", NtStatus);
1179 Status = CAB_STATUS_NOMEMORY;
1180 goto CloseDestFileSection;
1181 }
1182
1183 CurrentDestBuffer = DestFileBuffer;
1184 }
1185
1186 /* Call extract event handler */
1187 if (CabinetContext->ExtractHandler != NULL)
1188 CabinetContext->ExtractHandler(CabinetContext, Search->File, DestName);
1189
1190 if (Search->CFData)
1191 CFData = Search->CFData;
1192 else
1193 CFData = (PCFDATA)(CabinetContext->CabinetFolders[Search->File->FolderIndex].DataOffset + CabinetContext->FileBuffer);
1194
1195 CurrentOffset = Search->Offset;
1196 while (CurrentOffset + CFData->UncompSize <= Search->File->FileOffset)
1197 {
1198 /* walk the data blocks until we reach
1199 the one containing the start of the file */
1200 CurrentOffset += CFData->UncompSize;
1201 CFData = (PCFDATA)((char *)(CFData + 1) + CabinetContext->DataReserved + CFData->CompSize);
1202 }
1203
1204 Search->CFData = CFData;
1205 Search->Offset = CurrentOffset;
1206
1207 /* now decompress and discard any data in
1208 the block before the start of the file */
1209
1210 /* start of comp data */
1211 CurrentBuffer = ((unsigned char *)(CFData + 1)) + CabinetContext->DataReserved;
1212 RemainingBlock = CFData->CompSize;
1213 InputLength = RemainingBlock;
1214
1215 while (CurrentOffset < Search->File->FileOffset)
1216 {
1217 /* compute remaining uncomp bytes to start
1218 of file, bounded by size of chunk */
1219 OutputLength = Search->File->FileOffset - CurrentOffset;
1220 if (OutputLength > (LONG)sizeof(Chunk))
1221 OutputLength = sizeof(Chunk);
1222
1223 /* negate to signal NOT end of block */
1224 OutputLength = -OutputLength;
1225
1226 CabinetContext->Codec->Uncompress(CabinetContext->Codec,
1227 Chunk,
1228 CurrentBuffer,
1229 &InputLength,
1230 &OutputLength);
1231
1232 /* add the uncomp bytes extracted to current folder offset */
1233 CurrentOffset += OutputLength;
1234 /* add comp bytes consumed to CurrentBuffer */
1235 CurrentBuffer += InputLength;
1236 /* subtract bytes consumed from bytes remaining in block */
1237 RemainingBlock -= InputLength;
1238 /* neg for resume decompression of the same block */
1239 InputLength = -RemainingBlock;
1240 }
1241
1242 /* now CurrentBuffer points to the first comp byte
1243 of the file, so we can begin decompressing */
1244
1245 /* Size = remaining uncomp bytes of the file to decompress */
1246 Size = Search->File->FileSize;
1247 while (Size > 0)
1248 {
1249 OutputLength = Size;
1250 DPRINT("Decompressing block at %x with RemainingBlock = %d, Size = %d\n",
1251 CurrentBuffer, RemainingBlock, Size);
1252
1253 Status = CabinetContext->Codec->Uncompress(CabinetContext->Codec,
1254 CurrentDestBuffer,
1255 CurrentBuffer,
1256 &InputLength,
1257 &OutputLength);
1258 if (Status != CS_SUCCESS)
1259 {
1260 DPRINT("Cannot uncompress block\n");
1261 if (Status == CS_NOMEMORY)
1262 Status = CAB_STATUS_NOMEMORY;
1263 else
1264 Status = CAB_STATUS_INVALID_CAB;
1265 goto UnmapDestFile;
1266 }
1267
1268 /* advance dest buffer by bytes produced */
1269 CurrentDestBuffer = (PVOID)((ULONG_PTR)CurrentDestBuffer + OutputLength);
1270 /* advance src buffer by bytes consumed */
1271 CurrentBuffer += InputLength;
1272 /* reduce remaining file bytes by bytes produced */
1273 Size -= OutputLength;
1274 /* reduce remaining block size by bytes consumed */
1275 RemainingBlock -= InputLength;
1276 if (Size > 0 && RemainingBlock == 0)
1277 {
1278 /* used up this block, move on to the next */
1279 DPRINT("Out of block data\n");
1280 CFData = (PCFDATA)CurrentBuffer;
1281 RemainingBlock = CFData->CompSize;
1282 CurrentBuffer = (unsigned char *)(CFData + 1) + CabinetContext->DataReserved;
1283 InputLength = RemainingBlock;
1284 }
1285 }
1286
1287 Status = CAB_STATUS_SUCCESS;
1288
1289 UnmapDestFile:
1290 if (!CabinetContext->CreateFileHandler)
1291 NtUnmapViewOfSection(NtCurrentProcess(), DestFileBuffer);
1292
1293 CloseDestFileSection:
1294 if (!CabinetContext->CreateFileHandler)
1295 NtClose(DestFileSection);
1296
1297 CloseDestFile:
1298 if (!CabinetContext->CreateFileHandler)
1299 NtClose(DestFile);
1300
1301 return Status;
1302 }
1303
1304 /*
1305 * FUNCTION: Selects codec engine to use
1306 * ARGUMENTS:
1307 * Id = Codec identifier
1308 */
1309 VOID
CabinetSelectCodec(IN PCABINET_CONTEXT CabinetContext,IN ULONG Id)1310 CabinetSelectCodec(
1311 IN PCABINET_CONTEXT CabinetContext,
1312 IN ULONG Id)
1313 {
1314 if (CabinetContext->CodecSelected)
1315 {
1316 if (Id == CabinetContext->CodecId)
1317 return;
1318
1319 CabinetContext->CodecSelected = FALSE;
1320 }
1321
1322 switch (Id)
1323 {
1324 case CAB_CODEC_RAW:
1325 {
1326 CabinetContext->Codec = &RawCodec;
1327 break;
1328 }
1329
1330 case CAB_CODEC_MSZIP:
1331 {
1332 CabinetContext->Codec = &MSZipCodec;
1333 CabinetContext->Codec->ZStream.zalloc = MSZipAlloc;
1334 CabinetContext->Codec->ZStream.zfree = MSZipFree;
1335 CabinetContext->Codec->ZStream.opaque = (voidpf)0;
1336 break;
1337 }
1338
1339 default:
1340 return;
1341 }
1342
1343 CabinetContext->CodecId = Id;
1344 CabinetContext->CodecSelected = TRUE;
1345 }
1346
1347 /*
1348 * FUNCTION: Set event handlers
1349 * ARGUMENTS:
1350 * Overwrite = Handler called when a file is to be overwritten
1351 * Extract = Handler called when a file is to be extracted
1352 * DiskChange = Handler called when changing the disk
1353 */
1354 VOID
CabinetSetEventHandlers(IN PCABINET_CONTEXT CabinetContext,IN PCABINET_OVERWRITE Overwrite,IN PCABINET_EXTRACT Extract,IN PCABINET_DISK_CHANGE DiskChange,IN PCABINET_CREATE_FILE CreateFile)1355 CabinetSetEventHandlers(
1356 IN PCABINET_CONTEXT CabinetContext,
1357 IN PCABINET_OVERWRITE Overwrite,
1358 IN PCABINET_EXTRACT Extract,
1359 IN PCABINET_DISK_CHANGE DiskChange,
1360 IN PCABINET_CREATE_FILE CreateFile)
1361 {
1362 CabinetContext->OverwriteHandler = Overwrite;
1363 CabinetContext->ExtractHandler = Extract;
1364 CabinetContext->DiskChangeHandler = DiskChange;
1365 CabinetContext->CreateFileHandler = CreateFile;
1366 }
1367
1368 /*
1369 * FUNCTION: Get pointer to cabinet reserved area. NULL if none
1370 */
1371 PVOID
CabinetGetCabinetReservedArea(IN PCABINET_CONTEXT CabinetContext,OUT PULONG Size)1372 CabinetGetCabinetReservedArea(
1373 IN PCABINET_CONTEXT CabinetContext,
1374 OUT PULONG Size)
1375 {
1376 if (CabinetContext->CabinetReservedArea != NULL)
1377 {
1378 if (Size != NULL)
1379 {
1380 *Size = CabinetContext->CabinetReserved;
1381 }
1382
1383 return CabinetContext->CabinetReservedArea;
1384 }
1385 else
1386 {
1387 if (Size != NULL)
1388 {
1389 *Size = 0;
1390 }
1391
1392 return NULL;
1393 }
1394 }
1395