ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

cabinet.c
Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT:   See COPYING in the top level directory
00003  * PROJECT:     ReactOS text-mode setup
00004  * FILE:        subsys/system/usetup/cabinet.c
00005  * PURPOSE:     Cabinet routines
00006  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
00007  * REVISIONS:
00008  *   CSH 15/08-2003 Created
00009  */
00010 
00011 #include "usetup.h"
00012 
00013 #define NDEBUG
00014 #include <debug.h>
00015 
00016 #define SEEK_BEGIN    0
00017 #define SEEK_CURRENT  1
00018 #ifndef SEEK_END
00019 #define SEEK_END      2
00020 #endif
00021 
00022 typedef struct _DOSTIME
00023 {
00024     WORD Second:5;
00025     WORD Minute:6;
00026     WORD Hour:5;
00027 } DOSTIME, *PDOSTIME;
00028 
00029 
00030 typedef struct _DOSDATE
00031 {
00032     WORD Day:5;
00033     WORD Month:4;
00034     WORD Year:5;
00035 } DOSDATE, *PDOSDATE;
00036 
00037 static WCHAR CabinetName[256];          // Filename of current cabinet
00038 static WCHAR CabinetPrev[256];          // Filename of previous cabinet
00039 static WCHAR DiskPrev[256];             // Label of cabinet in file CabinetPrev
00040 static WCHAR CabinetNext[256];          // Filename of next cabinet
00041 static WCHAR DiskNext[256];             // Label of cabinet in file CabinetNext
00042 static ULONG FolderUncompSize = 0;      // Uncompressed size of folder
00043 static ULONG BytesLeftInBlock = 0;      // Number of bytes left in current block
00044 static WCHAR DestPath[MAX_PATH];
00045 static HANDLE FileHandle;
00046 static HANDLE FileSectionHandle;
00047 static PUCHAR FileBuffer;
00048 static SIZE_T DestFileSize;
00049 static SIZE_T FileSize;
00050 static BOOL FileOpen = FALSE;
00051 static PCFHEADER PCABHeader;
00052 static PCFFOLDER CabinetFolders;
00053 static ULONG CabinetReserved = 0;
00054 static ULONG FolderReserved = 0;
00055 static ULONG DataReserved = 0;
00056 static ULONG CodecId;
00057 static PCABINET_CODEC_UNCOMPRESS CodecUncompress = NULL;
00058 static BOOL CodecSelected = FALSE;
00059 static ULONG LastFileOffset = 0;    // Uncompressed offset of last extracted file
00060 static PCABINET_OVERWRITE OverwriteHandler = NULL;
00061 static PCABINET_EXTRACT ExtractHandler = NULL;
00062 static PCABINET_DISK_CHANGE DiskChangeHandler = NULL;
00063 static z_stream ZStream;
00064 static PVOID CabinetReservedArea = NULL;
00065 
00066 
00067 /* Needed by zlib, but we don't want the dependency on msvcrt.dll */
00068 void *__cdecl
00069 malloc(size_t size)
00070 {
00071     return RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, size);
00072 }
00073 
00074 void __cdecl
00075 free(void *ptr)
00076 {
00077     RtlFreeHeap(ProcessHeap, 0, ptr);
00078 }
00079 
00080 void *__cdecl
00081 calloc(size_t nmemb, size_t size)
00082 {
00083     return (void *)RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, nmemb * size);
00084 }
00085 
00086 /* RAW codec */
00087 
00088 /*
00089  * FUNCTION: Uncompresses data in a buffer
00090  * ARGUMENTS:
00091  *     OutputBuffer = Pointer to buffer to place uncompressed data
00092  *     InputBuffer  = Pointer to buffer with data to be uncompressed
00093  *     InputLength  = Length of input buffer before, and amount consumed after
00094  *                    Negative to indicate that this is not the start of a new block
00095  *     OutputLength = Length of output buffer before, amount filled after
00096  *                    Negative to indicate that this is not the end of the block
00097  */
00098 ULONG
00099 RawCodecUncompress(PVOID OutputBuffer,
00100                    PVOID InputBuffer,
00101                    PLONG InputLength,
00102                    PLONG OutputLength)
00103 {
00104     LONG Len = min(abs(*InputLength), abs(*OutputLength));
00105 
00106     memcpy(OutputBuffer, InputBuffer, Len);
00107     *InputLength = *OutputLength = Len;
00108 
00109     return CS_SUCCESS;
00110 }
00111 
00112 /* MSZIP codec */
00113 
00114 /*
00115  * FUNCTION: Uncompresses data in a buffer
00116  * ARGUMENTS:
00117  *     OutputBuffer = Pointer to buffer to place uncompressed data
00118  *     InputBuffer  = Pointer to buffer with data to be uncompressed
00119  *     InputLength  = Length of input buffer before, and amount consumed after
00120  *                    Negative to indicate that this is not the start of a new block
00121  *     OutputLength = Length of output buffer before, amount filled after
00122  *                    Negative to indicate that this is not the end of the block
00123  */
00124 ULONG
00125 MSZipCodecUncompress(PVOID OutputBuffer,
00126                      PVOID InputBuffer,
00127                      PLONG InputLength,
00128                      PLONG OutputLength)
00129 {
00130     USHORT Magic;
00131     INT Status;
00132 
00133     DPRINT("MSZipCodecUncompress(OutputBuffer = %x, InputBuffer = %x, "
00134            "InputLength = %d, OutputLength = %d)\n", OutputBuffer,
00135            InputBuffer, *InputLength, *OutputLength);
00136     if (*InputLength > 0)
00137     {
00138         Magic = *(PUSHORT)InputBuffer;
00139 
00140         if (Magic != MSZIP_MAGIC)
00141         {
00142             DPRINT("Bad MSZIP block header magic (0x%X)\n", Magic);
00143             return CS_BADSTREAM;
00144         }
00145 
00146         ZStream.next_in = (PUCHAR)InputBuffer + 2;
00147         ZStream.avail_in = *InputLength - 2;
00148         ZStream.next_out = (PUCHAR)OutputBuffer;
00149         ZStream.avail_out = abs(*OutputLength);
00150 
00151         /* WindowBits is passed < 0 to tell that there is no zlib header.
00152          * Note that in this case inflate *requires* an extra "dummy" byte
00153          * after the compressed stream in order to complete decompression and
00154          * return Z_STREAM_END.
00155          */
00156         Status = inflateInit2(&ZStream, -MAX_WBITS);
00157         if (Status != Z_OK)
00158         {
00159             DPRINT("inflateInit2() returned (%d)\n", Status);
00160             return CS_BADSTREAM;
00161         }
00162         ZStream.total_in = 2;
00163     }
00164     else
00165     {
00166         ZStream.avail_in = -*InputLength;
00167         ZStream.next_in = (PUCHAR)InputBuffer;
00168         ZStream.next_out = (PUCHAR)OutputBuffer;
00169         ZStream.avail_out = abs(*OutputLength);
00170         ZStream.total_in = 0;
00171     }
00172 
00173     ZStream.total_out = 0;
00174     Status = inflate(&ZStream, Z_SYNC_FLUSH);
00175     if (Status != Z_OK && Status != Z_STREAM_END)
00176     {
00177         DPRINT("inflate() returned (%d) (%s)\n", Status, ZStream.msg);
00178         if (Status == Z_MEM_ERROR)
00179             return CS_NOMEMORY;
00180         return CS_BADSTREAM;
00181     }
00182 
00183     if (*OutputLength > 0)
00184     {
00185         Status = inflateEnd(&ZStream);
00186         if (Status != Z_OK)
00187         {
00188             DPRINT("inflateEnd() returned (%d)\n", Status);
00189             return CS_BADSTREAM;
00190         }
00191     }
00192 
00193     *OutputLength = ZStream.total_out;
00194     *InputLength = ZStream.total_in;
00195 
00196     return CS_SUCCESS;
00197 }
00198 
00199 /* Memory functions */
00200 
00201 voidpf
00202 MSZipAlloc(voidpf opaque, uInt items, uInt size)
00203 {
00204     return (voidpf)RtlAllocateHeap(ProcessHeap, 0, items * size);
00205 }
00206 
00207 void
00208 MSZipFree(voidpf opaque, voidpf address)
00209 {
00210     RtlFreeHeap(ProcessHeap, 0, address);
00211 }
00212 
00213 static BOOL
00214 ConvertSystemTimeToFileTime(CONST SYSTEMTIME *lpSystemTime,
00215                             LPFILETIME lpFileTime)
00216 {
00217     TIME_FIELDS TimeFields;
00218     LARGE_INTEGER liTime;
00219 
00220     TimeFields.Year = lpSystemTime->wYear;
00221     TimeFields.Month = lpSystemTime->wMonth;
00222     TimeFields.Day = lpSystemTime->wDay;
00223     TimeFields.Hour = lpSystemTime->wHour;
00224     TimeFields.Minute = lpSystemTime->wMinute;
00225     TimeFields.Second = lpSystemTime->wSecond;
00226     TimeFields.Milliseconds = lpSystemTime->wMilliseconds;
00227 
00228     if (RtlTimeFieldsToTime(&TimeFields, &liTime))
00229     {
00230         lpFileTime->dwLowDateTime = liTime.u.LowPart;
00231         lpFileTime->dwHighDateTime = liTime.u.HighPart;
00232         return TRUE;
00233     }
00234 
00235     return FALSE;
00236 }
00237 
00238 static BOOL
00239 ConvertDosDateTimeToFileTime(WORD wFatDate,
00240                              WORD wFatTime,
00241                              LPFILETIME lpFileTime)
00242 {
00243     PDOSTIME pdtime = (PDOSTIME)&wFatTime;
00244     PDOSDATE pddate = (PDOSDATE)&wFatDate;
00245     SYSTEMTIME SystemTime;
00246 
00247     if (lpFileTime == NULL)
00248         return FALSE;
00249 
00250     SystemTime.wMilliseconds = 0;
00251     SystemTime.wSecond = pdtime->Second;
00252     SystemTime.wMinute = pdtime->Minute;
00253     SystemTime.wHour = pdtime->Hour;
00254 
00255     SystemTime.wDay = pddate->Day;
00256     SystemTime.wMonth = pddate->Month;
00257     SystemTime.wYear = 1980 + pddate->Year;
00258 
00259     ConvertSystemTimeToFileTime(&SystemTime, lpFileTime);
00260 
00261     return TRUE;
00262 }
00263 
00264 /*
00265  * FUNCTION: Returns a pointer to file name
00266  * ARGUMENTS:
00267  *     Path = Pointer to string with pathname
00268  * RETURNS:
00269  *     Pointer to filename
00270  */
00271 static PWCHAR
00272 GetFileName(PWCHAR Path)
00273 {
00274     ULONG i, j;
00275 
00276     j = i = 0;
00277 
00278     while (Path[i++])
00279     {
00280         if (Path[i - 1] == L'\\')
00281             j = i;
00282     }
00283 
00284     return Path + j;
00285 }
00286 
00287 /*
00288  * FUNCTION: Removes a file name from a path
00289  * ARGUMENTS:
00290  *     Path = Pointer to string with path
00291  */
00292 static VOID
00293 RemoveFileName(PWCHAR Path)
00294 {
00295     PWCHAR FileName;
00296     DWORD i;
00297 
00298     i = 0;
00299     FileName = GetFileName(Path + i);
00300 
00301     if (FileName != Path + i && FileName[-1] == L'\\')
00302         FileName--;
00303 
00304     if (FileName == Path + i && FileName[0] == L'\\')
00305         FileName++;
00306 
00307     FileName[0] = 0;
00308 }
00309 
00310 /*
00311  * FUNCTION: Sets attributes on a file
00312  * ARGUMENTS:
00313  *      File = Pointer to CFFILE node for file
00314  * RETURNS:
00315  *     Status of operation
00316  */
00317 static BOOL
00318 SetAttributesOnFile(PCFFILE File,
00319                     HANDLE hFile)
00320 {
00321     FILE_BASIC_INFORMATION FileBasic;
00322     IO_STATUS_BLOCK IoStatusBlock;
00323     NTSTATUS NtStatus;
00324     ULONG Attributes = 0;
00325 
00326     if (File->Attributes & CAB_ATTRIB_READONLY)
00327         Attributes |= FILE_ATTRIBUTE_READONLY;
00328 
00329     if (File->Attributes & CAB_ATTRIB_HIDDEN)
00330         Attributes |= FILE_ATTRIBUTE_HIDDEN;
00331 
00332     if (File->Attributes & CAB_ATTRIB_SYSTEM)
00333         Attributes |= FILE_ATTRIBUTE_SYSTEM;
00334 
00335     if (File->Attributes & CAB_ATTRIB_DIRECTORY)
00336         Attributes |= FILE_ATTRIBUTE_DIRECTORY;
00337 
00338     if (File->Attributes & CAB_ATTRIB_ARCHIVE)
00339         Attributes |= FILE_ATTRIBUTE_ARCHIVE;
00340 
00341     NtStatus = NtQueryInformationFile(hFile,
00342                                       &IoStatusBlock,
00343                                       &FileBasic,
00344                                       sizeof(FILE_BASIC_INFORMATION),
00345                                       FileBasicInformation);
00346     if (!NT_SUCCESS(NtStatus))
00347     {
00348         DPRINT("NtQueryInformationFile() failed (%x)\n", NtStatus);
00349     }
00350     else
00351     {
00352         FileBasic.FileAttributes = Attributes;
00353 
00354         NtStatus = NtSetInformationFile(hFile,
00355                                         &IoStatusBlock,
00356                                         &FileBasic,
00357                                         sizeof(FILE_BASIC_INFORMATION),
00358                                         FileBasicInformation);
00359         if (!NT_SUCCESS(NtStatus))
00360         {
00361             DPRINT("NtSetInformationFile() failed (%x)\n", NtStatus);
00362         }
00363     }
00364 
00365     return NT_SUCCESS(NtStatus);
00366 }
00367 
00368 /*
00369  * FUNCTION: Closes the current cabinet
00370  * RETURNS:
00371  *     Status of operation
00372  */
00373 static ULONG
00374 CloseCabinet(VOID)
00375 {
00376     if (FileBuffer)
00377     {
00378         NtUnmapViewOfSection(NtCurrentProcess(), FileBuffer);
00379         NtClose(FileSectionHandle);
00380         NtClose(FileHandle);
00381         FileBuffer = NULL;
00382     }
00383 
00384     return 0;
00385 }
00386 
00387 /*
00388  * FUNCTION: Initialize archiver
00389  */
00390 VOID
00391 CabinetInitialize(VOID)
00392 {
00393     ZStream.zalloc = MSZipAlloc;
00394     ZStream.zfree = MSZipFree;
00395     ZStream.opaque = (voidpf)0;
00396 
00397     FileOpen = FALSE;
00398     wcscpy(DestPath, L"");
00399 
00400     CodecId = CAB_CODEC_RAW;
00401     CodecSelected = TRUE;
00402 
00403     FolderUncompSize = 0;
00404     BytesLeftInBlock = 0;
00405     CabinetReserved = 0;
00406     FolderReserved = 0;
00407     DataReserved = 0;
00408     CabinetReservedArea = NULL;
00409     LastFileOffset = 0;
00410 }
00411 
00412 /*
00413  * FUNCTION: Cleanup archiver
00414  */
00415 VOID
00416 CabinetCleanup(VOID)
00417 {
00418     CabinetClose();
00419 }
00420 
00421 /*
00422  * FUNCTION: Normalizes a path
00423  * ARGUMENTS:
00424  *     Path   = Pointer to string with pathname
00425  *     Length = Number of characters in Path
00426  * RETURNS:
00427  *     TRUE if there was enough room in Path, or FALSE
00428  */
00429 BOOL
00430 CabinetNormalizePath(PWCHAR Path,
00431                      ULONG Length)
00432 {
00433     ULONG n;
00434     BOOL Ok;
00435 
00436     n = wcslen(Path);
00437     Ok = (n + 1) < Length;
00438 
00439     if (n != 0 && Path[n - 1] != L'\\' && Ok)
00440     {
00441         Path[n] = L'\\';
00442         Path[n + 1] = 0;
00443     }
00444 
00445     return Ok;
00446 }
00447 
00448 /*
00449  * FUNCTION: Returns pointer to cabinet file name
00450  * RETURNS:
00451  *     Pointer to string with name of cabinet
00452  */
00453 PWCHAR
00454 CabinetGetCabinetName(VOID)
00455 {
00456     return CabinetName;
00457 }
00458 
00459 /*
00460  * FUNCTION: Sets cabinet file name
00461  * ARGUMENTS:
00462  *     FileName = Pointer to string with name of cabinet
00463  */
00464 VOID
00465 CabinetSetCabinetName(PWCHAR FileName)
00466 {
00467     wcscpy(CabinetName, FileName);
00468 }
00469 
00470 /*
00471  * FUNCTION: Sets destination path
00472  * ARGUMENTS:
00473  *    DestinationPath = Pointer to string with name of destination path
00474  */
00475 VOID
00476 CabinetSetDestinationPath(PWCHAR DestinationPath)
00477 {
00478     wcscpy(DestPath, DestinationPath);
00479 
00480     if (wcslen(DestPath) > 0)
00481         CabinetNormalizePath(DestPath, MAX_PATH);
00482 }
00483 
00484 /*
00485  * FUNCTION: Returns destination path
00486  * RETURNS:
00487  *    Pointer to string with name of destination path
00488  */
00489 PWCHAR
00490 CabinetGetDestinationPath(VOID)
00491 {
00492     return DestPath;
00493 }
00494 
00495 /*
00496  * FUNCTION: Opens a cabinet file
00497  * RETURNS:
00498  *     Status of operation
00499  */
00500 ULONG
00501 CabinetOpen(VOID)
00502 {
00503     PUCHAR Buffer;
00504     UNICODE_STRING ustring;
00505     ANSI_STRING astring;
00506 
00507     if (!FileOpen)
00508     {
00509         OBJECT_ATTRIBUTES ObjectAttributes;
00510         IO_STATUS_BLOCK IoStatusBlock;
00511         UNICODE_STRING FileName;
00512         NTSTATUS NtStatus;
00513 
00514         RtlInitUnicodeString(&FileName, CabinetName);
00515 
00516         InitializeObjectAttributes(&ObjectAttributes,
00517                                    &FileName,
00518                                    OBJ_CASE_INSENSITIVE,
00519                                    NULL, NULL);
00520 
00521         NtStatus = NtOpenFile(&FileHandle,
00522                               GENERIC_READ | SYNCHRONIZE,
00523                               &ObjectAttributes,
00524                               &IoStatusBlock,
00525                               FILE_SHARE_READ,
00526                               FILE_SYNCHRONOUS_IO_NONALERT);
00527 
00528         if (!NT_SUCCESS(NtStatus))
00529         {
00530             DPRINT("Cannot open file (%S) (%x)\n", CabinetName, NtStatus);
00531             return CAB_STATUS_CANNOT_OPEN;
00532         }
00533 
00534         FileOpen = TRUE;
00535 
00536         NtStatus = NtCreateSection(&FileSectionHandle,
00537                                    SECTION_ALL_ACCESS,
00538                                    0, 0,
00539                                    PAGE_READONLY,
00540                                    SEC_COMMIT,
00541                                    FileHandle);
00542 
00543         if (!NT_SUCCESS(NtStatus))
00544         {
00545             DPRINT("NtCreateSection failed: %x\n", NtStatus);
00546             return CAB_STATUS_NOMEMORY;
00547         }
00548 
00549         FileBuffer = 0;
00550         FileSize = 0;
00551 
00552         NtStatus = NtMapViewOfSection(FileSectionHandle,
00553                                       NtCurrentProcess(),
00554                                       (PVOID *)&FileBuffer,
00555                                       0, 0, 0,
00556                                       &FileSize,
00557                                       ViewUnmap,
00558                                       0,
00559                                       PAGE_READONLY);
00560 
00561         if (!NT_SUCCESS(NtStatus))
00562         {
00563             DPRINT("NtMapViewOfSection failed: %x\n", NtStatus);
00564             return CAB_STATUS_NOMEMORY;
00565         }
00566 
00567         DPRINT("Cabinet file %S opened and mapped to %x\n", CabinetName, FileBuffer);
00568         PCABHeader = (PCFHEADER) FileBuffer;
00569 
00570         /* Check header */
00571         if (FileSize <= sizeof(CFHEADER) ||
00572             PCABHeader->Signature != CAB_SIGNATURE ||
00573             PCABHeader->Version != CAB_VERSION ||
00574             PCABHeader->FolderCount == 0 ||
00575             PCABHeader->FileCount == 0 ||
00576             PCABHeader->FileTableOffset < sizeof(CFHEADER))
00577         {
00578             CloseCabinet();
00579             DPRINT("File has invalid header\n");
00580             return CAB_STATUS_INVALID_CAB;
00581         }
00582 
00583         Buffer = (PUCHAR)(PCABHeader + 1);
00584 
00585         /* Read/skip any reserved bytes */
00586         if (PCABHeader->Flags & CAB_FLAG_RESERVE)
00587         {
00588             CabinetReserved = *(PUSHORT)Buffer;
00589             Buffer += 2;
00590             FolderReserved = *Buffer;
00591             Buffer++;
00592             DataReserved = *Buffer;
00593             Buffer++;
00594 
00595             if (CabinetReserved > 0)
00596             {
00597                 CabinetReservedArea = Buffer;
00598                 Buffer += CabinetReserved;
00599             }
00600         }
00601 
00602         if (PCABHeader->Flags & CAB_FLAG_HASPREV)
00603         {
00604             /* The previous cabinet file is in
00605                the same directory as the current */
00606             wcscpy(CabinetPrev, CabinetName);
00607             RemoveFileName(CabinetPrev);
00608             CabinetNormalizePath(CabinetPrev, 256);
00609             RtlInitAnsiString(&astring, (LPSTR)Buffer);
00610             ustring.Length = wcslen(CabinetPrev);
00611             ustring.Buffer = CabinetPrev + ustring.Length;
00612             ustring.MaximumLength = sizeof(CabinetPrev) - ustring.Length;
00613             RtlAnsiStringToUnicodeString(&ustring, &astring, FALSE);
00614             Buffer += astring.Length + 1;
00615 
00616             /* Read label of prev disk */
00617             RtlInitAnsiString(&astring, (LPSTR)Buffer);
00618             ustring.Length = 0;
00619             ustring.Buffer = DiskPrev;
00620             ustring.MaximumLength = sizeof(DiskPrev);
00621             RtlAnsiStringToUnicodeString(&ustring, &astring, FALSE);
00622             Buffer += astring.Length + 1;
00623         }
00624         else
00625         {
00626             wcscpy(CabinetPrev, L"");
00627             wcscpy(DiskPrev, L"");
00628         }
00629 
00630         if (PCABHeader->Flags & CAB_FLAG_HASNEXT)
00631         {
00632             /* The next cabinet file is in
00633                the same directory as the previous */
00634             wcscpy(CabinetNext, CabinetName);
00635             RemoveFileName(CabinetNext);
00636             CabinetNormalizePath(CabinetNext, 256);
00637             RtlInitAnsiString(&astring, (LPSTR)Buffer);
00638             ustring.Length = wcslen(CabinetNext);
00639             ustring.Buffer = CabinetNext + ustring.Length;
00640             ustring.MaximumLength = sizeof(CabinetNext) - ustring.Length;
00641             RtlAnsiStringToUnicodeString(&ustring, &astring, FALSE);
00642             Buffer += astring.Length + 1;
00643 
00644             /* Read label of next disk */
00645             RtlInitAnsiString(&astring, (LPSTR)Buffer);
00646             ustring.Length = 0;
00647             ustring.Buffer = DiskNext;
00648             ustring.MaximumLength = sizeof(DiskNext);
00649             RtlAnsiStringToUnicodeString(&ustring, &astring, FALSE);
00650             Buffer += astring.Length + 1;
00651         }
00652         else
00653         {
00654             wcscpy(CabinetNext, L"");
00655             wcscpy(DiskNext, L"");
00656         }
00657         CabinetFolders = (PCFFOLDER)Buffer;
00658     }
00659 
00660     DPRINT("CabinetOpen returning SUCCESS\n");
00661     return CAB_STATUS_SUCCESS;
00662 }
00663 
00664 /*
00665  * FUNCTION: Closes the cabinet file
00666  */
00667 VOID
00668 CabinetClose(VOID)
00669 {
00670     if (FileOpen)
00671     {
00672         CloseCabinet();
00673         FileOpen = FALSE;
00674     }
00675 }
00676 
00677 /*
00678  * FUNCTION: Finds the first file in the cabinet that matches a search criteria
00679  * ARGUMENTS:
00680  *     FileName = Pointer to search criteria
00681  *     Search   = Pointer to search structure
00682  * RETURNS:
00683  *     Status of operation
00684  */
00685 ULONG
00686 CabinetFindFirst(PWCHAR FileName,
00687                  PCAB_SEARCH Search)
00688 {
00689     DPRINT("CabinetFindFirst( FileName = %S )\n", FileName);
00690     wcsncpy(Search->Search, FileName, MAX_PATH);
00691     wcsncpy(Search->Cabinet, CabinetName, MAX_PATH);
00692     Search->File = 0;
00693     return CabinetFindNext(Search);
00694 }
00695 
00696 /*
00697  * FUNCTION: Finds the next file in the cabinet that matches a search criteria
00698  * ARGUMENTS:
00699  *     FileName = Pointer to search criteria
00700  *     Search   = Pointer to search structure
00701  * RETURNS:
00702  *     Status of operation
00703  */
00704 ULONG
00705 CabinetFindNextFileSequential(PWCHAR FileName,
00706                               PCAB_SEARCH Search)
00707 {
00708     DPRINT("CabinetFindNextFileSequential( FileName = %S )\n", FileName);
00709     wcsncpy(Search->Search, FileName, MAX_PATH);
00710     return CabinetFindNext(Search);
00711 }
00712 
00713 /*
00714  * FUNCTION: Finds next file in the cabinet that matches a search criteria
00715  * ARGUMENTS:
00716  *     Search = Pointer to search structure
00717  * RETURNS:
00718  *     Status of operation
00719  */
00720 ULONG
00721 CabinetFindNext(PCAB_SEARCH Search)
00722 {
00723     PCFFILE Prev;
00724     ANSI_STRING AnsiString;
00725     UNICODE_STRING UnicodeString;
00726     WCHAR FileName[MAX_PATH];
00727 
00728     if (wcscmp(Search->Cabinet, CabinetName) != 0)
00729     {
00730         /* restart search of cabinet has changed since last find */
00731         Search->File = 0;
00732     }
00733 
00734     if (!Search->File)
00735     {
00736         /* starting new search or cabinet */
00737         Search->File = (PCFFILE)(FileBuffer + PCABHeader->FileTableOffset);
00738         Search->Index = 0;
00739         Prev = 0;
00740     }
00741     else
00742         Prev = Search->File;
00743 
00744     while (TRUE)
00745     {
00746         /* look at each file in the archive and see if we found a match */
00747         if (Search->File->FolderIndex == 0xFFFD ||
00748             Search->File->FolderIndex == 0xFFFF)
00749         {
00750             /* skip files continued from previous cab */
00751             DPRINT("Skipping file (%s): FileOffset (0x%X), "
00752                    "LastFileOffset (0x%X)\n", (char *)(Search->File + 1),
00753                    Search->File->FileOffset, LastFileOffset);
00754         }
00755         else
00756         {
00757             // FIXME: check for match against search criteria
00758             if (Search->File != Prev)
00759             {
00760                 if (Prev == NULL || Search->File->FolderIndex != Prev->FolderIndex)
00761                 {
00762                     Search->CFData = NULL;
00763                     Search->Offset = 0;
00764                 }
00765                 
00766                 /* don't match the file we started with */
00767                 if (wcscmp(Search->Search, L"*") == 0)
00768                 {
00769                     /* take any file */
00770                     break;
00771                 }
00772                 else
00773                 {
00774                     /* otherwise, try to match the exact file name */
00775                     RtlInitAnsiString(&AnsiString, Search->File->FileName);
00776                     UnicodeString.Buffer = FileName;
00777                     UnicodeString.Buffer[0] = 0;
00778                     UnicodeString.Length = 0;
00779                     UnicodeString.MaximumLength = sizeof(FileName);
00780                     RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
00781                     if (wcscmp(Search->Search, UnicodeString.Buffer) == 0)
00782                         break;
00783                 }
00784             }
00785         }
00786 
00787         /* if we make it here we found no match, so move to the next file */
00788         Search->Index++;
00789         if (Search->Index >= PCABHeader->FileCount)
00790         {
00791             /* we have reached the end of this cabinet */
00792             DPRINT("End of cabinet reached\n");
00793             return CAB_STATUS_NOFILE;
00794         }
00795         else
00796             Search->File = (PCFFILE)(strchr((char *)(Search->File + 1), 0) + 1);
00797     }
00798 
00799     DPRINT("Found file %s\n", Search->File->FileName);
00800     return CAB_STATUS_SUCCESS;
00801 }
00802 
00803 #if 0
00804 int
00805 Validate()
00806 {
00807     return (int)RtlValidateHeap(ProcessHeap, 0, 0);
00808 }
00809 #endif
00810 
00811 /*
00812  * FUNCTION: Extracts a file from the cabinet
00813  * ARGUMENTS:
00814  *     Search = Pointer to PCAB_SEARCH structure used to locate the file
00815  * RETURNS
00816  *     Status of operation
00817  */
00818 ULONG
00819 CabinetExtractFile(PCAB_SEARCH Search)
00820 {
00821     ULONG Size;                 // remaining file bytes to decompress
00822     ULONG CurrentOffset;        // current uncompressed offset within the folder
00823     PUCHAR CurrentBuffer;       // current pointer to compressed data in the block
00824     LONG RemainingBlock;        // remaining comp data in the block
00825     HANDLE DestFile;
00826     HANDLE DestFileSection;
00827     PVOID DestFileBuffer;       // mapped view of dest file
00828     PVOID CurrentDestBuffer;    // pointer to the current position in the dest view
00829     PCFDATA CFData;             // current data block
00830     ULONG Status;
00831     FILETIME FileTime;
00832     WCHAR DestName[MAX_PATH];
00833     NTSTATUS NtStatus;
00834     UNICODE_STRING UnicodeString;
00835     ANSI_STRING AnsiString;
00836     IO_STATUS_BLOCK IoStatusBlock;
00837     OBJECT_ATTRIBUTES ObjectAttributes;
00838     FILE_BASIC_INFORMATION FileBasic;
00839     PCFFOLDER CurrentFolder;
00840     LARGE_INTEGER MaxDestFileSize;
00841     LONG InputLength, OutputLength;
00842     char Junk[512];
00843 
00844     if (wcscmp(Search->Cabinet, CabinetName) != 0)
00845     {
00846         /* the file is not in the current cabinet */
00847         DPRINT("File is not in this cabinet (%S != %S)\n",
00848                Search->Cabinet, CabinetName);
00849         return CAB_STATUS_NOFILE;
00850     }
00851 
00852     /* look up the folder that the file specifies */
00853     if (Search->File->FolderIndex == 0xFFFD ||
00854         Search->File->FolderIndex == 0xFFFF)
00855     {
00856         /* folder is continued from previous cabinet,
00857            that shouldn't happen here */
00858         return CAB_STATUS_NOFILE;
00859     }
00860     else if (Search->File->FolderIndex == 0xFFFE)
00861     {
00862         /* folder is the last in this cabinet and continues into next */
00863         CurrentFolder = &CabinetFolders[PCABHeader->FolderCount - 1];
00864     }
00865     else
00866     {
00867         /* folder is completely contained within this cabinet */
00868         CurrentFolder = &CabinetFolders[Search->File->FolderIndex];
00869     }
00870 
00871     switch (CurrentFolder->CompressionType & CAB_COMP_MASK)
00872     {
00873         case CAB_COMP_NONE:
00874             CabinetSelectCodec(CAB_CODEC_RAW);
00875             break;
00876         case CAB_COMP_MSZIP:
00877             CabinetSelectCodec(CAB_CODEC_MSZIP);
00878             break;
00879         default:
00880             return CAB_STATUS_UNSUPPCOMP;
00881     }
00882 
00883     DPRINT("Extracting file at uncompressed offset (0x%X) Size (%d bytes)\n",
00884            (UINT)Search->File->FileOffset, (UINT)Search->File->FileSize);
00885 
00886     RtlInitAnsiString(&AnsiString, Search->File->FileName);
00887     wcscpy(DestName, DestPath);
00888     UnicodeString.MaximumLength = sizeof(DestName) - wcslen(DestName) * sizeof(WCHAR);
00889     UnicodeString.Buffer = DestName + wcslen(DestName);
00890     UnicodeString.Length = 0;
00891     RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
00892 
00893     /* Create destination file, fail if it already exists */
00894     RtlInitUnicodeString(&UnicodeString, DestName);
00895 
00896     InitializeObjectAttributes(&ObjectAttributes,
00897                                &UnicodeString,
00898                                OBJ_CASE_INSENSITIVE,
00899                                NULL, NULL);
00900 
00901     NtStatus = NtCreateFile(&DestFile,
00902                             GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
00903                             &ObjectAttributes,
00904                             &IoStatusBlock,
00905                             NULL,
00906                             FILE_ATTRIBUTE_NORMAL,
00907                             0,
00908                             FILE_CREATE,
00909                             FILE_SYNCHRONOUS_IO_NONALERT,
00910                             NULL, 0);
00911 
00912     if (!NT_SUCCESS(NtStatus))
00913     {
00914         DPRINT("NtCreateFile() failed (%S) (%x)\n", DestName, NtStatus);
00915 
00916         /* If file exists, ask to overwrite file */
00917         if (OverwriteHandler == NULL || OverwriteHandler(Search->File, DestName))
00918         {
00919             /* Create destination file, overwrite if it already exists */
00920             NtStatus = NtCreateFile(&DestFile,
00921                                     GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
00922                                     &ObjectAttributes,
00923                                     &IoStatusBlock,
00924                                     NULL,
00925                                     FILE_ATTRIBUTE_NORMAL,
00926                                     0,
00927                                     FILE_OVERWRITE,
00928                                     FILE_SYNCHRONOUS_IO_ALERT,
00929                                     NULL, 0);
00930 
00931             if (!NT_SUCCESS(NtStatus))
00932             {
00933                 DPRINT("NtCreateFile() failed (%S) (%x)\n", DestName, NtStatus);
00934                 return CAB_STATUS_CANNOT_CREATE;
00935             }
00936         }
00937         else
00938         {
00939             DPRINT("File (%S) exists\n", DestName);
00940             return CAB_STATUS_FILE_EXISTS;
00941         }
00942     }
00943 
00944     MaxDestFileSize.QuadPart = Search->File->FileSize;
00945     NtStatus = NtCreateSection(&DestFileSection,
00946                                SECTION_ALL_ACCESS,
00947                                0,
00948                                &MaxDestFileSize,
00949                                PAGE_READWRITE,
00950                                SEC_COMMIT,
00951                                DestFile);
00952 
00953     if (!NT_SUCCESS(NtStatus))
00954     {
00955         DPRINT("NtCreateSection failed: %x\n", NtStatus);
00956         Status = CAB_STATUS_NOMEMORY;
00957         goto CloseDestFile;
00958     }
00959 
00960     DestFileBuffer = 0;
00961     DestFileSize = 0;
00962     NtStatus = NtMapViewOfSection(DestFileSection,
00963                                   NtCurrentProcess(),
00964                                   &DestFileBuffer,
00965                                   0, 0, 0,
00966                                   &DestFileSize,
00967                                   ViewUnmap,
00968                                   0,
00969                                   PAGE_READWRITE);
00970 
00971     if (!NT_SUCCESS(NtStatus))
00972     {
00973         DPRINT("NtMapViewOfSection failed: %x\n", NtStatus);
00974         Status = CAB_STATUS_NOMEMORY;
00975         goto CloseDestFileSection;
00976     }
00977 
00978     CurrentDestBuffer = DestFileBuffer;
00979     if (!ConvertDosDateTimeToFileTime(Search->File->FileDate,
00980                                       Search->File->FileTime,
00981                                       &FileTime))
00982     {
00983         DPRINT("DosDateTimeToFileTime() failed\n");
00984         Status = CAB_STATUS_CANNOT_WRITE;
00985         goto UnmapDestFile;
00986     }
00987 
00988     NtStatus = NtQueryInformationFile(DestFile,
00989                                       &IoStatusBlock,
00990                                       &FileBasic,
00991                                       sizeof(FILE_BASIC_INFORMATION),
00992                                       FileBasicInformation);
00993     if (!NT_SUCCESS(NtStatus))
00994     {
00995         DPRINT("NtQueryInformationFile() failed (%x)\n", NtStatus);
00996     }
00997     else
00998     {
00999         memcpy(&FileBasic.LastAccessTime, &FileTime, sizeof(FILETIME));
01000 
01001         NtStatus = NtSetInformationFile(DestFile,
01002                                         &IoStatusBlock,
01003                                         &FileBasic,
01004                                         sizeof(FILE_BASIC_INFORMATION),
01005                                         FileBasicInformation);
01006         if (!NT_SUCCESS(NtStatus))
01007         {
01008             DPRINT("NtSetInformationFile() failed (%x)\n", NtStatus);
01009         }
01010     }
01011 
01012     SetAttributesOnFile(Search->File, DestFile);
01013 
01014     /* Call extract event handler */
01015     if (ExtractHandler != NULL)
01016     {
01017         ExtractHandler(Search->File, DestName);
01018     }
01019 
01020     if (Search->CFData)
01021         CFData = Search->CFData;
01022     else
01023         CFData = (PCFDATA)(CabinetFolders[Search->File->FolderIndex].DataOffset + FileBuffer);
01024 
01025     CurrentOffset = Search->Offset;
01026     while (CurrentOffset + CFData->UncompSize <= Search->File->FileOffset)
01027     {
01028         /* walk the data blocks until we reach
01029            the one containing the start of the file */
01030         CurrentOffset += CFData->UncompSize;
01031         CFData = (PCFDATA)((char *)(CFData + 1) + DataReserved + CFData->CompSize);
01032     }
01033     
01034     Search->CFData = CFData;
01035     Search->Offset = CurrentOffset;
01036 
01037     /* now decompress and discard any data in
01038        the block before the start of the file */
01039 
01040     /* start of comp data */
01041     CurrentBuffer = ((unsigned char *)(CFData + 1)) + DataReserved;
01042     RemainingBlock = CFData->CompSize;
01043     InputLength = RemainingBlock;
01044 
01045     while (CurrentOffset < Search->File->FileOffset)
01046     {
01047         /* compute remaining uncomp bytes to start
01048            of file, bounded by sizeof junk */
01049         OutputLength = Search->File->FileOffset - CurrentOffset;
01050         if (OutputLength > (LONG)sizeof(Junk))
01051             OutputLength = sizeof (Junk);
01052 
01053         /* negate to signal NOT end of block */
01054         OutputLength = -OutputLength;
01055         CodecUncompress(Junk, CurrentBuffer, &InputLength, &OutputLength);
01056         /* add the uncomp bytes extracted to current folder offset */
01057         CurrentOffset += OutputLength;
01058         /* add comp bytes consumed to CurrentBuffer */
01059         CurrentBuffer += InputLength;
01060         /* subtract bytes consumed from bytes remaining in block */
01061         RemainingBlock -= InputLength;
01062         /* neg for resume decompression of the same block */
01063         InputLength = -RemainingBlock;
01064     }
01065 
01066     /* now CurrentBuffer points to the first comp byte
01067        of the file, so we can begin decompressing */
01068 
01069     /* Size = remaining uncomp bytes of the file to decompress */
01070     Size = Search->File->FileSize;
01071     while (Size > 0)
01072     {
01073         OutputLength = Size;
01074         DPRINT("Decompressing block at %x with RemainingBlock = %d, Size = %d\n",
01075                CurrentBuffer, RemainingBlock, Size);
01076 
01077         Status = CodecUncompress(CurrentDestBuffer,
01078                                  CurrentBuffer,
01079                                  &InputLength,
01080                                  &OutputLength);
01081 
01082         if (Status != CS_SUCCESS)
01083         {
01084             DPRINT("Cannot uncompress block\n");
01085             if (Status == CS_NOMEMORY)
01086                 Status = CAB_STATUS_NOMEMORY;
01087             Status = CAB_STATUS_INVALID_CAB;
01088             goto UnmapDestFile;
01089         }
01090 
01091         /* advance dest buffer by bytes produced */
01092         CurrentDestBuffer = (PVOID)((ULONG_PTR)CurrentDestBuffer + OutputLength);
01093         /* advance src buffer by bytes consumed */
01094         CurrentBuffer += InputLength;
01095         /* reduce remaining file bytes by bytes produced */
01096         Size -= OutputLength;
01097         /* reduce remaining block size by bytes consumed */
01098         RemainingBlock -= InputLength;
01099         if (RemainingBlock == 0)
01100         {
01101             /* used up this block, move on to the next */
01102             DPRINT("Out of block data\n");
01103             CFData = (PCFDATA)CurrentBuffer;
01104             RemainingBlock = CFData->CompSize;
01105             CurrentBuffer = (unsigned char *)(CFData + 1) + DataReserved;
01106             InputLength = RemainingBlock;
01107         }
01108     }
01109 
01110     Status = CAB_STATUS_SUCCESS;
01111 
01112 UnmapDestFile:
01113     NtUnmapViewOfSection(NtCurrentProcess(), DestFileBuffer);
01114 
01115 CloseDestFileSection:
01116     NtClose(DestFileSection);
01117 
01118 CloseDestFile:
01119     NtClose(DestFile);
01120 
01121     return Status;
01122 }
01123 
01124 /*
01125  * FUNCTION: Selects codec engine to use
01126  * ARGUMENTS:
01127  *     Id = Codec identifier
01128  */
01129 VOID
01130 CabinetSelectCodec(ULONG Id)
01131 {
01132     if (CodecSelected)
01133     {
01134         if (Id == CodecId)
01135             return;
01136 
01137         CodecSelected = FALSE;
01138     }
01139 
01140     switch (Id)
01141     {
01142         case CAB_CODEC_RAW:
01143             CodecUncompress = RawCodecUncompress;
01144             break;
01145         case CAB_CODEC_MSZIP:
01146             CodecUncompress = MSZipCodecUncompress;
01147             break;
01148         default:
01149             return;
01150     }
01151 
01152     CodecId = Id;
01153     CodecSelected = TRUE;
01154 }
01155 
01156 /*
01157  * FUNCTION: Set event handlers
01158  * ARGUMENTS:
01159  *     Overwrite = Handler called when a file is to be overwritten
01160  *     Extract = Handler called when a file is to be extracted
01161  *     DiskChange = Handler called when changing the disk
01162  */
01163 VOID
01164 CabinetSetEventHandlers(PCABINET_OVERWRITE Overwrite,
01165                         PCABINET_EXTRACT Extract,
01166                         PCABINET_DISK_CHANGE DiskChange)
01167 {
01168     OverwriteHandler = Overwrite;
01169     ExtractHandler = Extract;
01170     DiskChangeHandler = DiskChange;
01171 }
01172 
01173 /*
01174  * FUNCTION: Get pointer to cabinet reserved area. NULL if none
01175  */
01176 PVOID
01177 CabinetGetCabinetReservedArea(PULONG Size)
01178 {
01179     if (CabinetReservedArea != NULL)
01180     {
01181         if (Size != NULL)
01182         {
01183             *Size = CabinetReserved;
01184         }
01185 
01186         return CabinetReservedArea;
01187     }
01188     else
01189     {
01190         if (Size != NULL)
01191         {
01192             *Size = 0;
01193         }
01194 
01195         return NULL;
01196     }
01197 }

Generated on Sun May 27 2012 04:17:57 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.