Fix building on newer Linux systems (particularly Fedora 13)
[reactos.git] / reactos / tools / cabman / cabinet.cxx
index 1a10458..5d834a9 100755 (executable)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#if defined(__FreeBSD__) || defined(__APPLE__)
+#if !defined(WIN32)
+# include <dirent.h>
 # include <sys/stat.h>
-#endif // __FreeBSD__
+# include <sys/types.h>
+#endif
 #include "cabinet.h"
 #include "raw.h"
 #include "mszip.h"
@@ -61,7 +63,7 @@ static bool _ReadFileData(FILEHANDLE handle, void* buffer, ULONG size, PULONG by
 #ifndef CAB_READ_ONLY
 
 #if 0
-#ifdef DBG
+#if DBG
 
 void DumpBuffer(void* Buffer, ULONG Size)
 {
@@ -78,13 +80,13 @@ void DumpBuffer(void* Buffer, ULONG Size)
         NULL);                          // No attribute template
     if (FileHandle == INVALID_HANDLE_VALUE)
     {
-        DPRINT(MID_TRACE, ("ERROR OPENING '%lu'.\n", (ULONG)GetLastError()));
+        DPRINT(MID_TRACE, ("ERROR OPENING '%u'.\n", (UINT)GetLastError()));
         return;
     }
 
     if (!WriteFile(FileHandle, Buffer, Size, &BytesWritten, NULL))
     {
-        DPRINT(MID_TRACE, ("ERROR WRITING '%lu'.\n", (ULONG)GetLastError()));
+        DPRINT(MID_TRACE, ("ERROR WRITING '%u'.\n", (UINT)GetLastError()));
     }
 
     CloseFile(FileHandle);
@@ -113,7 +115,7 @@ CCFDATAStorage::~CCFDATAStorage()
 }
 
 
-ULONG CCFDATAStorage::Create(char* FileName)
+ULONG CCFDATAStorage::Create(const char* FileName)
 /*
  * FUNCTION: Creates the file
  * ARGUMENTS:
@@ -142,7 +144,7 @@ ULONG CCFDATAStorage::Create(char* FileName)
         NULL);                          // No attribute template
     if (FileHandle == INVALID_HANDLE_VALUE)
     {
-        DPRINT(MID_TRACE, ("ERROR '%lu'.\n", (ULONG)GetLastError()));
+        DPRINT(MID_TRACE, ("ERROR '%u'.\n", (UINT)GetLastError()));
         return CAB_STATUS_CANNOT_CREATE;
     }
 #else /* !WIN32 */
@@ -152,7 +154,7 @@ ULONG CCFDATAStorage::Create(char* FileName)
         /*
     FileHandle = fopen(FullName, "w+b");
     if (FileHandle == NULL) {
-        DPRINT(MID_TRACE, ("ERROR '%lu'.\n", (ULONG)errno));
+        DPRINT(MID_TRACE, ("ERROR '%i'.\n", errno));
         return CAB_STATUS_CANNOT_CREATE;
     }
         */
@@ -189,7 +191,7 @@ ULONG CCFDATAStorage::Truncate()
  */
 {
 #if defined(WIN32)
-    if (!SetFilePointer(FileHandle, 0, NULL, FILE_BEGIN))
+    if( SetFilePointer(FileHandle, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER )
         return CAB_STATUS_FAILURE;
     if (!SetEndOfFile(FileHandle))
         return CAB_STATUS_FAILURE;
@@ -198,7 +200,7 @@ ULONG CCFDATAStorage::Truncate()
     FileHandle = tmpfile();
     if (FileHandle == NULL)
     {
-        DPRINT(MID_TRACE, ("ERROR '%lu'.\n", (ULONG)errno));
+        DPRINT(MID_TRACE, ("ERROR '%i'.\n", errno));
         return CAB_STATUS_FAILURE;
     }
 #endif
@@ -231,10 +233,10 @@ ULONG CCFDATAStorage::Seek(LONG Position)
  */
 {
 #if defined(WIN32)
-    if (SetFilePointer(FileHandle,
-        Position,
-        NULL,
-        FILE_BEGIN) == 0xFFFFFFFF)
+    ifSetFilePointer(FileHandle,
+                       Position,
+                       NULL,
+                       FILE_BEGIN) == INVALID_SET_FILE_POINTER )
         return CAB_STATUS_FAILURE;
     else
         return CAB_STATUS_SUCCESS;
@@ -315,10 +317,12 @@ CCabinet::CCabinet()
     CabinetReservedFileBuffer = NULL;
     CabinetReservedFileSize = 0;
 
-    FolderListHead = NULL;
-    FolderListTail = NULL;
-    FileListHead   = NULL;
-    FileListTail   = NULL;
+    FolderListHead   = NULL;
+    FolderListTail   = NULL;
+    FileListHead     = NULL;
+    FileListTail     = NULL;
+    CriteriaListHead = NULL;
+    CriteriaListTail = NULL;
 
     Codec          = NULL;
     CodecId        = -1;
@@ -370,10 +374,10 @@ bool CCabinet::IsSeparator(char Char)
 
 char* CCabinet::ConvertPath(char* Path, bool Allocate)
 /*
- * FUNCTION: Replaces \ or / with the one used be the host environment
+ * FUNCTION: Replaces \ or / with the one used by the host environment
  * ARGUMENTS:
  *     Path     = Pointer to string with pathname
- *     Allocate = Specifies wther to allocate memory for the new
+ *     Allocate = Specifies whether to allocate memory for the new
  *                string or to change the existing buffer
  * RETURNS:
  *     Pointer to new path
@@ -511,6 +515,82 @@ void CCabinet::SetDestinationPath(char* DestinationPath)
         NormalizePath(DestPath, MAX_PATH);
 }
 
+ULONG CCabinet::AddSearchCriteria(char* SearchCriteria)
+/*
+ * FUNCTION: Adds a criteria to the search criteria list
+ * ARGUMENTS:
+ *     SearchCriteria = String with the search criteria to add
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PSEARCH_CRITERIA Criteria;
+
+    // Add the criteria to the list of search criteria
+    Criteria = (PSEARCH_CRITERIA)AllocateMemory(sizeof(SEARCH_CRITERIA));
+    if(!Criteria)
+    {
+        DPRINT(MIN_TRACE, ("Insufficient memory.\n"));
+        return CAB_STATUS_NOMEMORY;
+    }
+
+    Criteria->Prev = CriteriaListTail;
+    Criteria->Next = NULL;
+
+    if(CriteriaListTail)
+        CriteriaListTail->Next = Criteria;
+    else
+        CriteriaListHead = Criteria;
+
+    CriteriaListTail = Criteria;
+
+    // Set the actual criteria string
+    Criteria->Search = (char*)AllocateMemory(strlen(SearchCriteria) + 1);
+    if (!Criteria->Search)
+    {
+        DPRINT(MIN_TRACE, ("Insufficient memory.\n"));
+        return CAB_STATUS_NOMEMORY;
+    }
+
+    strcpy(Criteria->Search, SearchCriteria);
+
+    return CAB_STATUS_SUCCESS;
+}
+
+void CCabinet::DestroySearchCriteria()
+/*
+ * FUNCTION: Destroys the list with the search criteria
+ */
+{
+    PSEARCH_CRITERIA Criteria;
+    PSEARCH_CRITERIA NextCriteria;
+
+    Criteria = CriteriaListHead;
+
+    while(Criteria)
+    {
+        NextCriteria = Criteria->Next;
+
+        FreeMemory(Criteria->Search);
+        FreeMemory(Criteria);
+
+        Criteria = NextCriteria;
+    }
+
+    CriteriaListHead = NULL;
+    CriteriaListTail = NULL;
+}
+
+bool CCabinet::HasSearchCriteria()
+/*
+ * FUNCTION: Returns whether we have search criteria
+ * RETURNS:
+ *    Whether we have search criteria or not.
+ */
+{
+    return (CriteriaListHead != NULL);
+}
+
 bool CCabinet::SetCompressionCodec(char* CodecName)
 /*
  * FUNCTION: Selects the codec to use for compression
@@ -679,7 +759,7 @@ ULONG CCabinet::Open()
         if ((Status = ReadBlock(&CABHeader, sizeof(CFHEADER), &BytesRead))
             != CAB_STATUS_SUCCESS)
         {
-            DPRINT(MIN_TRACE, ("Cannot read from file (%lu).\n", (ULONG)Status));
+            DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
             return CAB_STATUS_INVALID_CAB;
         }
 
@@ -704,7 +784,7 @@ ULONG CCabinet::Open()
             if ((Status = ReadBlock(&Size, sizeof(ULONG), &BytesRead))
                 != CAB_STATUS_SUCCESS)
             {
-                DPRINT(MIN_TRACE, ("Cannot read from file (%lu).\n", (ULONG)Status));
+                DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
                 return CAB_STATUS_INVALID_CAB;
             }
             CabinetReserved = Size & 0xFFFF;
@@ -712,10 +792,9 @@ ULONG CCabinet::Open()
             DataReserved    = (Size >> 24) & 0xFF;
 
 #if defined(WIN32)
-            SetFilePointer(FileHandle, CabinetReserved, NULL, FILE_CURRENT);
-            if (GetLastError() != NO_ERROR)
+            if (SetFilePointer(FileHandle, CabinetReserved, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
             {
-                DPRINT(MIN_TRACE, ("SetFilePointer() failed.\n"));
+                DPRINT(MIN_TRACE, ("SetFilePointer() failed, error code is %u.\n", (UINT)GetLastError()));
                 return CAB_STATUS_FAILURE;
             }
 #else
@@ -779,7 +858,7 @@ ULONG CCabinet::Open()
             if ((Status = ReadBlock(&FolderNode->Folder,
                 sizeof(CFFOLDER), &BytesRead)) != CAB_STATUS_SUCCESS)
             {
-                DPRINT(MIN_TRACE, ("Cannot read from file (%lu).\n", (ULONG)Status));
+                DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
                 return CAB_STATUS_INVALID_CAB;
             }
         }
@@ -788,7 +867,7 @@ ULONG CCabinet::Open()
         Status = ReadFileTable();
         if (Status != CAB_STATUS_SUCCESS)
         {
-            DPRINT(MIN_TRACE, ("ReadFileTable() failed (%lu).\n", (ULONG)Status));
+            DPRINT(MIN_TRACE, ("ReadFileTable() failed (%u).\n", (UINT)Status));
             return Status;
         }
 
@@ -799,7 +878,7 @@ ULONG CCabinet::Open()
             Status = ReadDataBlocks(FolderNode);
             if (Status != CAB_STATUS_SUCCESS)
             {
-                DPRINT(MIN_TRACE, ("ReadDataBlocks() failed (%lu).\n", (ULONG)Status));
+                DPRINT(MIN_TRACE, ("ReadDataBlocks() failed (%u).\n", (UINT)Status));
                 return Status;
             }
             FolderNode = FolderNode->Next;
@@ -822,19 +901,16 @@ void CCabinet::Close()
 }
 
 
-ULONG CCabinet::FindFirst(char* FileName,
-                             PCAB_SEARCH Search)
+ULONG CCabinet::FindFirst(PCAB_SEARCH Search)
 /*
  * FUNCTION: Finds the first file in the cabinet that matches a search criteria
  * ARGUMENTS:
- *     FileName = Pointer to search criteria
  *     Search   = Pointer to search structure
  * RETURNS:
  *     Status of operation
  */
 {
     RestartSearch = false;
-    strncpy(Search->Search, FileName, MAX_PATH);
     Search->Next = FileListHead;
     return FindNext(Search);
 }
@@ -849,6 +925,8 @@ ULONG CCabinet::FindNext(PCAB_SEARCH Search)
  *     Status of operation
  */
 {
+    bool bFound = false;
+    PSEARCH_CRITERIA Criteria;
     ULONG Status;
 
     if (RestartSearch)
@@ -860,15 +938,40 @@ ULONG CCabinet::FindNext(PCAB_SEARCH Search)
             (Search->Next->File.FileControlID > CAB_FILE_MAX_FOLDER) &&
             (Search->Next->File.FileOffset <= LastFileOffset))
         {
-            DPRINT(MAX_TRACE, ("Skipping file (%s)  FileOffset (0x%lX)  LastFileOffset (0x%lX).\n",
-                Search->Next->FileName, Search->Next->File.FileOffset, LastFileOffset));
+            DPRINT(MAX_TRACE, ("Skipping file (%s)  FileOffset (0x%X)  LastFileOffset (0x%X).\n",
+                Search->Next->FileName, (UINT)Search->Next->File.FileOffset, (UINT)LastFileOffset));
             Search->Next = Search->Next->Next;
         }
 
         RestartSearch = false;
     }
 
-    /* FIXME: Check search criteria */
+    /* Check each search criteria against each file */
+    while(Search->Next)
+    {
+        // Some features (like displaying cabinets) don't require search criteria, so we can just break here.
+        // If a feature requires it, handle this in the ParseCmdline() function in "main.cxx".
+        if(!CriteriaListHead)
+            break;
+
+        Criteria = CriteriaListHead;
+
+        while(Criteria)
+        {
+            if(MatchFileNamePattern(Search->Next->FileName, Criteria->Search))
+            {
+                bFound = true;
+                break;
+            }
+
+            Criteria = Criteria->Next;
+        }
+
+        if(bFound)
+            break;
+
+        Search->Next = Search->Next->Next;
+    }
 
     if (!Search->Next)
     {
@@ -917,8 +1020,8 @@ ULONG CCabinet::ExtractFile(char* FileName)
     ULONG BytesToWrite;
     ULONG TotalBytesRead;
     ULONG CurrentOffset;
-    unsigned char* Buffer;
-    unsigned char* CurrentBuffer;
+    PUCHAR Buffer;
+    PUCHAR CurrentBuffer;
     FILEHANDLE DestFile;
     PCFFILE_NODE File;
     CFDATA CFData;
@@ -927,13 +1030,13 @@ ULONG CCabinet::ExtractFile(char* FileName)
 #if defined(WIN32)
     FILETIME FileTime;
 #endif
-    char DestName[MAX_PATH];
-    char TempName[MAX_PATH];
+    CHAR DestName[MAX_PATH];
+    CHAR TempName[MAX_PATH];
 
     Status = LocateFile(FileName, &File);
     if (Status != CAB_STATUS_SUCCESS)
     {
-        DPRINT(MID_TRACE, ("Cannot locate file (%lu).\n", (ULONG)Status));
+        DPRINT(MID_TRACE, ("Cannot locate file (%u).\n", (UINT)Status));
         return Status;
     }
 
@@ -953,11 +1056,11 @@ ULONG CCabinet::ExtractFile(char* FileName)
             return CAB_STATUS_UNSUPPCOMP;
     }
 
-    DPRINT(MAX_TRACE, ("Extracting file at uncompressed offset (0x%lX)  Size (%lu bytes)  AO (0x%lX)  UO (0x%lX).\n",
-        (ULONG)File->File.FileOffset,
-        (ULONG)File->File.FileSize,
-        (ULONG)File->DataBlock->AbsoluteOffset,
-        (ULONG)File->DataBlock->UncompOffset));
+    DPRINT(MAX_TRACE, ("Extracting file at uncompressed offset (0x%X)  Size (%u bytes)  AO (0x%X)  UO (0x%X).\n",
+        (UINT)File->File.FileOffset,
+        (UINT)File->File.FileSize,
+        (UINT)File->DataBlock->AbsoluteOffset,
+        (UINT)File->DataBlock->UncompOffset));
 
     strcpy(DestName, DestPath);
     strcat(DestName, FileName);
@@ -1022,7 +1125,7 @@ ULONG CCabinet::ExtractFile(char* FileName)
     if (!DosDateTimeToFileTime(File->File.FileDate, File->File.FileTime, &FileTime))
     {
         CloseFile(DestFile);
-        DPRINT(MIN_TRACE, ("DosDateTimeToFileTime() failed (%lu).\n", GetLastError()));
+        DPRINT(MIN_TRACE, ("DosDateTimeToFileTime() failed (%u).\n", (UINT)GetLastError()));
         return CAB_STATUS_CANNOT_WRITE;
     }
 
@@ -1030,9 +1133,9 @@ ULONG CCabinet::ExtractFile(char* FileName)
 #else
     //DPRINT(MIN_TRACE, ("FIXME: DosDateTimeToFileTime\n"));
 #endif
-    SetAttributesOnFile(File);
+    SetAttributesOnFile(DestName, File->File.Attributes);
 
-    Buffer = (unsigned char*)AllocateMemory(CAB_BLOCKSIZE + 12); // This should be enough
+    Buffer = (PUCHAR)AllocateMemory(CAB_BLOCKSIZE + 12); // This should be enough
     if (!Buffer)
     {
         CloseFile(DestFile);
@@ -1049,9 +1152,9 @@ ULONG CCabinet::ExtractFile(char* FileName)
         File->DataBlock->AbsoluteOffset,
         NULL,
         FILE_BEGIN);
-    if (GetLastError() != NO_ERROR)
+    if (Offset == INVALID_SET_FILE_POINTER)
     {
-        DPRINT(MIN_TRACE, ("SetFilePointer() failed.\n"));
+        DPRINT(MIN_TRACE, ("SetFilePointer() failed, error code is %u.\n", (UINT)GetLastError()));
         return CAB_STATUS_INVALID_CAB;
     }
 #else
@@ -1074,47 +1177,47 @@ ULONG CCabinet::ExtractFile(char* FileName)
     {
         do
         {
-            DPRINT(MAX_TRACE, ("CO (0x%lX)    ReuseBlock (%lu)    Offset (0x%lX)   Size (%ld)  BytesLeftInBlock (%ld)\n",
-                File->DataBlock->UncompOffset, (ULONG)ReuseBlock, Offset, Size,
-                BytesLeftInBlock));
+            DPRINT(MAX_TRACE, ("CO (0x%X)    ReuseBlock (%u)    Offset (0x%X)   Size (%d)  BytesLeftInBlock (%d)\n",
+                (UINT)File->DataBlock->UncompOffset, (UINT)ReuseBlock, (UINT)Offset, (UINT)Size,
+                (UINT)BytesLeftInBlock));
 
             if (/*(CurrentDataNode != File->DataBlock) &&*/ (!ReuseBlock) || (BytesLeftInBlock <= 0))
             {
-                DPRINT(MAX_TRACE, ("Filling buffer. ReuseBlock (%lu)\n", (ULONG)ReuseBlock));
+                DPRINT(MAX_TRACE, ("Filling buffer. ReuseBlock (%u)\n", (UINT)ReuseBlock));
 
                 CurrentBuffer  = Buffer;
                 TotalBytesRead = 0;
                 do
                 {
-                    DPRINT(MAX_TRACE, ("Size (%lu bytes).\n", Size));
+                    DPRINT(MAX_TRACE, ("Size (%u bytes).\n", (UINT)Size));
 
                     if (((Status = ReadBlock(&CFData, sizeof(CFDATA), &BytesRead)) !=
                         CAB_STATUS_SUCCESS) || (BytesRead != sizeof(CFDATA)))
                     {
                         CloseFile(DestFile);
                         FreeMemory(Buffer);
-                        DPRINT(MIN_TRACE, ("Cannot read from file (%lu).\n", (ULONG)Status));
+                        DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
                         return CAB_STATUS_INVALID_CAB;
                     }
 
-                    DPRINT(MAX_TRACE, ("Data block: Checksum (0x%lX)  CompSize (%lu bytes)  UncompSize (%lu bytes)\n",
-                        (ULONG)CFData.Checksum,
-                        (ULONG)CFData.CompSize,
-                        (ULONG)CFData.UncompSize));
+                    DPRINT(MAX_TRACE, ("Data block: Checksum (0x%X)  CompSize (%u bytes)  UncompSize (%u bytes)\n",
+                        (UINT)CFData.Checksum,
+                        CFData.CompSize,
+                        CFData.UncompSize));
 
                     ASSERT(CFData.CompSize <= CAB_BLOCKSIZE + 12);
 
                     BytesToRead = CFData.CompSize;
 
                     DPRINT(MAX_TRACE, ("Read: (0x%lX,0x%lX).\n",
-                        (_W64 unsigned long)CurrentBuffer, (_W64 unsigned long)Buffer));
+                        (unsigned long)CurrentBuffer, (unsigned long)Buffer));
 
                     if (((Status = ReadBlock(CurrentBuffer, BytesToRead, &BytesRead)) !=
                         CAB_STATUS_SUCCESS) || (BytesToRead != BytesRead))
                     {
                         CloseFile(DestFile);
                         FreeMemory(Buffer);
-                        DPRINT(MIN_TRACE, ("Cannot read from file (%lu).\n", (ULONG)Status));
+                        DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
                         return CAB_STATUS_INVALID_CAB;
                     }
 
@@ -1162,7 +1265,7 @@ ULONG CCabinet::ExtractFile(char* FileName)
                         Status = LocateFile(TempName, &File);
                         if (Status == CAB_STATUS_NOFILE)
                         {
-                            DPRINT(MID_TRACE, ("Cannot locate file (%lu).\n", (ULONG)Status));
+                            DPRINT(MID_TRACE, ("Cannot locate file (%u).\n", (UINT)Status));
                             return Status;
                         }
 
@@ -1171,13 +1274,12 @@ ULONG CCabinet::ExtractFile(char* FileName)
 
                         /* Search to start of file */
 #if defined(WIN32)
-                        SetFilePointer(FileHandle,
-                            File->DataBlock->AbsoluteOffset,
-                            NULL,
-                            FILE_BEGIN);
-                        if (GetLastError() != NO_ERROR)
+                        if( SetFilePointer(FileHandle,
+                                           File->DataBlock->AbsoluteOffset,
+                                           NULL,
+                                           FILE_BEGIN) == INVALID_SET_FILE_POINTER )
                         {
-                            DPRINT(MIN_TRACE, ("SetFilePointer() failed.\n"));
+                            DPRINT(MIN_TRACE, ("SetFilePointer() failed, error code is %u.\n", (UINT)GetLastError()));
                             return CAB_STATUS_INVALID_CAB;
                         }
 #else
@@ -1188,11 +1290,11 @@ ULONG CCabinet::ExtractFile(char* FileName)
                         }
 #endif
 
-                        DPRINT(MAX_TRACE, ("Continuing extraction of file at uncompressed offset (0x%lX)  Size (%lu bytes)  AO (0x%lX)  UO (0x%lX).\n",
-                            (ULONG)File->File.FileOffset,
-                            (ULONG)File->File.FileSize,
-                            (ULONG)File->DataBlock->AbsoluteOffset,
-                            (ULONG)File->DataBlock->UncompOffset));
+                        DPRINT(MAX_TRACE, ("Continuing extraction of file at uncompressed offset (0x%X)  Size (%u bytes)  AO (0x%X)  UO (0x%X).\n",
+                            (UINT)File->File.FileOffset,
+                            (UINT)File->File.FileSize,
+                            (UINT)File->DataBlock->AbsoluteOffset,
+                            (UINT)File->DataBlock->UncompOffset));
 
                         CurrentDataNode = File->DataBlock;
                         ReuseBlock = true;
@@ -1201,7 +1303,7 @@ ULONG CCabinet::ExtractFile(char* FileName)
                     }
                 } while (CFData.UncompSize == 0);
 
-                DPRINT(MAX_TRACE, ("TotalBytesRead (%lu).\n", TotalBytesRead));
+                DPRINT(MAX_TRACE, ("TotalBytesRead (%u).\n", (UINT)TotalBytesRead));
 
                 Status = Codec->Uncompress(OutputBuffer, Buffer, TotalBytesRead, &BytesToWrite);
                 if (Status != CS_SUCCESS)
@@ -1216,8 +1318,8 @@ ULONG CCabinet::ExtractFile(char* FileName)
 
                 if (BytesToWrite != CFData.UncompSize)
                 {
-                    DPRINT(MID_TRACE, ("BytesToWrite (%lu) != CFData.UncompSize (%d)\n",
-                        BytesToWrite, CFData.UncompSize));
+                    DPRINT(MID_TRACE, ("BytesToWrite (%u) != CFData.UncompSize (%d)\n",
+                        (UINT)BytesToWrite, CFData.UncompSize));
                     return CAB_STATUS_INVALID_CAB;
                 }
 
@@ -1225,20 +1327,19 @@ ULONG CCabinet::ExtractFile(char* FileName)
             }
             else
             {
-                DPRINT(MAX_TRACE, ("Using same buffer. ReuseBlock (%lu)\n", (ULONG)ReuseBlock));
+                DPRINT(MAX_TRACE, ("Using same buffer. ReuseBlock (%u)\n", (UINT)ReuseBlock));
 
                 BytesToWrite = BytesLeftInBlock;
 
-                DPRINT(MAX_TRACE, ("Seeking to absolute offset 0x%lX.\n",
-                    CurrentDataNode->AbsoluteOffset + sizeof(CFDATA) +
-                    CurrentDataNode->Data.CompSize));
+                DPRINT(MAX_TRACE, ("Seeking to absolute offset 0x%X.\n",
+                    (UINT)(CurrentDataNode->AbsoluteOffset + sizeof(CFDATA) + CurrentDataNode->Data.CompSize)));
 
                 if (((Status = ReadBlock(&CFData, sizeof(CFDATA), &BytesRead)) !=
                     CAB_STATUS_SUCCESS) || (BytesRead != sizeof(CFDATA)))
                 {
                     CloseFile(DestFile);
                     FreeMemory(Buffer);
-                    DPRINT(MIN_TRACE, ("Cannot read from file (%lu).\n", (ULONG)Status));
+                    DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
                     return CAB_STATUS_INVALID_CAB;
                 }
 
@@ -1247,14 +1348,13 @@ ULONG CCabinet::ExtractFile(char* FileName)
 
                 /* Go to next data block */
 #if defined(WIN32)
-                SetFilePointer(FileHandle,
-                    CurrentDataNode->AbsoluteOffset + sizeof(CFDATA) +
-                    CurrentDataNode->Data.CompSize,
-                    NULL,
-                    FILE_BEGIN);
-                if (GetLastError() != NO_ERROR)
+                if( SetFilePointer(FileHandle,
+                                   CurrentDataNode->AbsoluteOffset + sizeof(CFDATA) +
+                                   CurrentDataNode->Data.CompSize,
+                                   NULL,
+                                   FILE_BEGIN) == INVALID_SET_FILE_POINTER )
                 {
-                    DPRINT(MIN_TRACE, ("SetFilePointer() failed.\n"));
+                    DPRINT(MIN_TRACE, ("SetFilePointer() failed, error code is %u.\n", (UINT)GetLastError()));
                     return CAB_STATUS_INVALID_CAB;
                 }
 #else
@@ -1279,22 +1379,22 @@ ULONG CCabinet::ExtractFile(char* FileName)
             if (Size < BytesToWrite)
                 BytesToWrite = Size;
 
-            DPRINT(MAX_TRACE, ("Offset (0x%lX)  CurrentOffset (0x%lX)  ToWrite (%lu)  Skipped (%lu)(%lu)  Size (%lu).\n",
-                (ULONG)Offset,
-                (ULONG)CurrentOffset,
-                (ULONG)BytesToWrite,
-                (ULONG)BytesSkipped, (ULONG)Skip,
-                (ULONG)Size));
+            DPRINT(MAX_TRACE, ("Offset (0x%X)  CurrentOffset (0x%X)  ToWrite (%u)  Skipped (%u)(%u)  Size (%u).\n",
+                (UINT)Offset,
+                (UINT)CurrentOffset,
+                (UINT)BytesToWrite,
+                (UINT)BytesSkipped, (UINT)Skip,
+                (UINT)Size));
 
 #if defined(WIN32)
-            if (!WriteFile(DestFile, (void*)((unsigned long *)OutputBuffer + BytesSkipped),
+            if (!WriteFile(DestFile, (void*)((PUCHAR)OutputBuffer + BytesSkipped),
                 BytesToWrite, (LPDWORD)&BytesWritten, NULL) ||
                 (BytesToWrite != BytesWritten))
             {
-                        DPRINT(MIN_TRACE, ("Status 0x%lX.\n", GetLastError()));
+                        DPRINT(MIN_TRACE, ("Status 0x%X.\n", (UINT)GetLastError()));
 #else
             BytesWritten = BytesToWrite;
-            if (fwrite((void*)((unsigned long *)OutputBuffer + BytesSkipped),
+            if (fwrite((void*)((PUCHAR)OutputBuffer + BytesSkipped),
                 BytesToWrite, 1, DestFile) < 1)
             {
 #endif
@@ -1588,13 +1688,12 @@ ULONG CCabinet::WriteFileToScratchStorage(PCFFILE_NODE FileNode)
 
             if (!ReadFileData(SourceFile, CurrentIBuffer, BytesToRead, &BytesRead) || (BytesToRead != BytesRead))
             {
-                DPRINT(MIN_TRACE, ("Cannot read from file. BytesToRead (%lu)  BytesRead (%lu)  CurrentIBufferSize (%lu).\n",
-                    BytesToRead, BytesRead, CurrentIBufferSize));
+                DPRINT(MIN_TRACE, ("Cannot read from file. BytesToRead (%u)  BytesRead (%u)  CurrentIBufferSize (%u).\n",
+                    (UINT)BytesToRead, (UINT)BytesRead, (UINT)CurrentIBufferSize));
                 return CAB_STATUS_INVALID_CAB;
             }
 
-            *(unsigned char**)&CurrentIBuffer += BytesRead;
-
+            CurrentIBuffer = (unsigned char*)CurrentIBuffer + BytesRead;
             CurrentIBufferSize += (USHORT)BytesRead;
 
             if (CurrentIBufferSize == CAB_BLOCKSIZE)
@@ -1673,8 +1772,8 @@ ULONG CCabinet::WriteDisk(ULONG MoreDisks)
                 ContinueFile = true;
                 CreateNewDisk = false;
 
-                DPRINT(MAX_TRACE, ("First on new disk. CurrentIBufferSize (%lu)  CurrentOBufferSize (%lu).\n",
-                    CurrentIBufferSize, CurrentOBufferSize));
+                DPRINT(MAX_TRACE, ("First on new disk. CurrentIBufferSize (%u)  CurrentOBufferSize (%u).\n",
+                    (UINT)CurrentIBufferSize, (UINT)CurrentOBufferSize));
 
                 if ((CurrentIBufferSize > 0) || (CurrentOBufferSize > 0))
                 {
@@ -1955,15 +2054,170 @@ ULONG CCabinet::AddFile(char* FileName)
         return CAB_STATUS_CANNOT_READ;
     }
 
-    GetFileTimes(SrcFile, FileNode);
+    if (GetFileTimes(SrcFile, FileNode) != CAB_STATUS_SUCCESS)
+    {
+        DPRINT(MIN_TRACE, ("Cannot read file times.\n"));
+        FreeMemory(NewFileName);
+        return CAB_STATUS_CANNOT_READ;
+    }
 
-    GetAttributesOnFile(FileNode);
+    if (GetAttributesOnFile(FileNode) != CAB_STATUS_SUCCESS)
+    {
+        DPRINT(MIN_TRACE, ("Cannot read file attributes.\n"));
+        FreeMemory(NewFileName);
+        return CAB_STATUS_CANNOT_READ;
+    }
 
     CloseFile(SrcFile);
 
     return CAB_STATUS_SUCCESS;
 }
 
+bool CCabinet::CreateSimpleCabinet()
+/*
+ * FUNCTION: Create a simple cabinet based on the files in the criteria list
+ */
+{
+    bool bRet = false;
+    char* pszFile;
+    char szFilePath[MAX_PATH];
+    char szFile[MAX_PATH];
+    PSEARCH_CRITERIA Criteria;
+    ULONG Status;
+
+#if defined(WIN32)
+    HANDLE hFind;
+    WIN32_FIND_DATA FindFileData;
+#else
+    DIR* dirp;
+    struct dirent* dp;
+    struct stat stbuf;
+#endif
+
+    // Initialize a new cabinet
+    Status = NewCabinet();
+    if (Status != CAB_STATUS_SUCCESS)
+    {
+        DPRINT(MIN_TRACE, ("Cannot create cabinet (%u).\n", (UINT)Status));
+        goto cleanup;
+    }
+
+    // Add each file in the criteria list
+    Criteria = CriteriaListHead;
+
+    while(Criteria)
+    {
+        // Store the file path with a trailing slash in szFilePath
+        ConvertPath(Criteria->Search, false);
+        pszFile = strrchr(Criteria->Search, DIR_SEPARATOR_CHAR);
+
+        if(pszFile)
+        {
+            // Set the pointer to the start of the file name, not the slash
+            pszFile++;
+
+            strncpy(szFilePath, Criteria->Search, pszFile - Criteria->Search);
+            szFilePath[pszFile - Criteria->Search] = 0;
+        }
+        else
+        {
+            pszFile = Criteria->Search;
+
+#if defined(WIN32)
+            szFilePath[0] = 0;
+#else
+            // needed for opendir()
+            strcpy(szFilePath, "./");
+#endif
+        }
+
+#if defined(WIN32)
+        // Windows: Use the easy FindFirstFile/FindNextFile API for getting all files and checking them against the pattern
+        hFind = FindFirstFile(Criteria->Search, &FindFileData);
+
+        // Don't stop if a search criteria is not found
+        if(hFind == INVALID_HANDLE_VALUE && GetLastError() != ERROR_FILE_NOT_FOUND)
+        {
+            DPRINT(MIN_TRACE, ("FindFirstFile failed, Criteria: %s, error code is %u\n", Criteria->Search, (UINT)GetLastError()));
+            goto cleanup;
+        }
+
+        do
+        {
+            if(!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+            {
+                strcpy(szFile, szFilePath);
+                strcat(szFile, FindFileData.cFileName);
+
+                Status = AddFile(szFile);
+
+                if(Status != CAB_STATUS_SUCCESS)
+                {
+                    DPRINT(MIN_TRACE, ("Cannot add file to cabinet (%u).\n", (UINT)Status));
+                    goto cleanup;
+                }
+            }
+        }
+        while(FindNextFile(hFind, &FindFileData));
+
+        FindClose(hFind);
+#else
+        // 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
+        dirp = opendir(szFilePath);
+
+        if(dirp)
+        {
+            while( (dp = readdir(dirp)) )
+            {
+                strcpy(szFile, szFilePath);
+                strcat(szFile, dp->d_name);
+
+                if(stat(szFile, &stbuf) == 0)
+                {
+                    if(stbuf.st_mode != S_IFDIR)
+                    {
+                        if(MatchFileNamePattern(dp->d_name, pszFile))
+                        {
+                            Status = AddFile(szFile);
+
+                            if(Status != CAB_STATUS_SUCCESS)
+                            {
+                                DPRINT(MIN_TRACE, ("Cannot add file to cabinet (%u).\n", (UINT)Status));
+                                goto cleanup;
+                            }
+                        }
+                    }
+                }
+                else
+                {
+                    DPRINT(MIN_TRACE, ("stat failed, error code is %i\n", errno));
+                    goto cleanup;
+                }
+            }
+
+            closedir(dirp);
+        }
+#endif
+
+        Criteria = Criteria->Next;
+    }
+
+    Status = WriteDisk(false);
+    if (Status == CAB_STATUS_SUCCESS)
+        Status = CloseDisk();
+    if (Status != CAB_STATUS_SUCCESS)
+    {
+        DPRINT(MIN_TRACE, ("Cannot write disk (%u).\n", (UINT)Status));
+        goto cleanup;
+    }
+
+    CloseCabinet();
+    bRet = true;
+
+cleanup:
+    DestroySearchCriteria();
+    return bRet;
+}
 
 void CCabinet::SetMaxDiskSize(ULONG Size)
 /*
@@ -2105,18 +2359,18 @@ ULONG CCabinet::GetAbsoluteOffset(PCFFILE_NODE File)
 {
     PCFDATA_NODE Node;
 
-    DPRINT(MAX_TRACE, ("FileName '%s'  FileOffset (0x%lX)  FileSize (%lu).\n",
+    DPRINT(MAX_TRACE, ("FileName '%s'  FileOffset (0x%X)  FileSize (%u).\n",
         File->FileName,
-        (ULONG)File->File.FileOffset,
-        (ULONG)File->File.FileSize));
+        (UINT)File->File.FileOffset,
+        (UINT)File->File.FileSize));
 
     Node = CurrentFolderNode->DataListHead;
     while (Node != NULL)
     {
-        DPRINT(MAX_TRACE, ("GetAbsoluteOffset(): Comparing (0x%lX, 0x%lX) (%lu).\n",
-            (ULONG)Node->UncompOffset,
-            (ULONG)Node->UncompOffset + Node->Data.UncompSize,
-            (ULONG)Node->Data.UncompSize));
+        DPRINT(MAX_TRACE, ("GetAbsoluteOffset(): Comparing (0x%X, 0x%X) (%u).\n",
+            (UINT)Node->UncompOffset,
+            (UINT)(Node->UncompOffset + Node->Data.UncompSize),
+            (UINT)Node->Data.UncompSize));
 
         /* Node->Data.UncompSize will be 0 if the block is split
            (ie. it is the last block in this cabinet) */
@@ -2136,7 +2390,7 @@ ULONG CCabinet::GetAbsoluteOffset(PCFFILE_NODE File)
 
 
 ULONG CCabinet::LocateFile(char* FileName,
-                              PCFFILE_NODE *File)
+                           PCFFILE_NODE *File)
 /*
  * FUNCTION: Locates a file in the cabinet
  * ARGUMENTS:
@@ -2161,8 +2415,8 @@ ULONG CCabinet::LocateFile(char* FileName,
             CurrentFolderNode = LocateFolderNode(Node->File.FileControlID);
             if (!CurrentFolderNode)
             {
-                DPRINT(MID_TRACE, ("Folder with index number (%lu) not found.\n",
-                    (ULONG)Node->File.FileControlID));
+                DPRINT(MID_TRACE, ("Folder with index number (%u) not found.\n",
+                    Node->File.FileControlID));
                 return CAB_STATUS_INVALID_CAB;
             }
 
@@ -2180,7 +2434,7 @@ ULONG CCabinet::LocateFile(char* FileName,
 }
 
 
-ULONG CCabinet::ReadString(char* String, ULONG MaxLength)
+ULONG CCabinet::ReadString(char* String, LONG MaxLength)
 /*
  * FUNCTION: Reads a NULL-terminated string from the cabinet
  * ARGUMENTS:
@@ -2191,58 +2445,51 @@ ULONG CCabinet::ReadString(char* String, ULONG MaxLength)
  */
 {
     ULONG BytesRead;
-    ULONG Offset;
     ULONG Status;
-    ULONG Size;
+    LONG Size;
     bool Found;
 
-    Offset = 0;
     Found  = false;
-    do
-    {
-        Size = ((Offset + 32) <= MaxLength)? 32 : MaxLength - Offset;
 
-        if (Size == 0)
-        {
-            DPRINT(MIN_TRACE, ("Too long a filename.\n"));
-            return CAB_STATUS_INVALID_CAB;
-        }
-
-        Status = ReadBlock(&String[Offset], Size, &BytesRead);
-        if ((Status != CAB_STATUS_SUCCESS) || (BytesRead != Size))
-        {
-            DPRINT(MIN_TRACE, ("Cannot read from file (%lu).\n", (ULONG)Status));
-            return CAB_STATUS_INVALID_CAB;
-        }
+    Status = ReadBlock(String, MaxLength, &BytesRead);
+    if (Status != CAB_STATUS_SUCCESS)
+    {
+        DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
+        return CAB_STATUS_INVALID_CAB;
+    }
 
-        for (Size = Offset; Size < Offset + BytesRead; Size++)
+    // Find the terminating NULL character
+    for (Size = 0; Size < MaxLength; Size++)
+    {
+        if (String[Size] == '\0')
         {
-            if (String[Size] == '\0')
-            {
-                Found = true;
-                break;
-            }
+            Found = true;
+            break;
         }
+    }
 
-        Offset += BytesRead;
+    if (!Found)
+    {
+        DPRINT(MIN_TRACE, ("Filename in the cabinet file is too long.\n"));
+        return CAB_STATUS_INVALID_CAB;
+    }
 
-    } while (!Found);
+    // Compute the offset of the next CFFILE.
+    // 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.
+    // + 1 to skip the terminating NULL character as well.
+    Size = -(MaxLength - Size) + 1;
 
-    /* Back up some bytes */
-    Size = (BytesRead - Size) - 1;
 #if defined(WIN32)
-    SetLastError(NO_ERROR);
-    (ULONG)SetFilePointer(FileHandle,
-        -(LONG)Size,
-        NULL,
-        FILE_CURRENT);
-    if (GetLastError() != NO_ERROR)
+    if( SetFilePointer(FileHandle,
+                       (LONG)Size,
+                       NULL,
+                       FILE_CURRENT) == INVALID_SET_FILE_POINTER )
     {
-        DPRINT(MIN_TRACE, ("SetFilePointer() failed.\n"));
+        DPRINT(MIN_TRACE, ("SetFilePointer() failed, error code is %u.\n", (UINT)GetLastError()));
         return CAB_STATUS_INVALID_CAB;
     }
 #else
-    if (fseek(FileHandle, (off_t)(-(LONG)Size), SEEK_CUR) != 0)
+    if (fseek(FileHandle, (off_t)Size, SEEK_CUR) != 0)
     {
         DPRINT(MIN_TRACE, ("fseek() failed.\n"));
         return CAB_STATUS_INVALID_CAB;
@@ -2264,20 +2511,17 @@ ULONG CCabinet::ReadFileTable()
     ULONG BytesRead;
     PCFFILE_NODE File;
 
-    DPRINT(MAX_TRACE, ("Reading file table at absolute offset (0x%lX).\n",
-        CABHeader.FileTableOffset));
+    DPRINT(MAX_TRACE, ("Reading file table at absolute offset (0x%X).\n",
+        (UINT)CABHeader.FileTableOffset));
 
     /* Seek to file table */
 #if defined(WIN32)
-    SetLastError(NO_ERROR);
-    SetFilePointer(FileHandle,
-        CABHeader.FileTableOffset,
-        NULL,
-        FILE_BEGIN);
-    if (GetLastError() != NO_ERROR)
+    if( SetFilePointer(FileHandle,
+                       CABHeader.FileTableOffset,
+                       NULL,
+                       FILE_BEGIN) == INVALID_SET_FILE_POINTER )
     {
-        DPRINT(MIN_TRACE, ("SetFilePointer() failed.\n"));
-        DPRINT(MIN_TRACE, ("Error: %lu\n", GetLastError()));
+        DPRINT(MIN_TRACE, ("SetFilePointer() failed, error code is %u.\n", (UINT)GetLastError()));
         return CAB_STATUS_INVALID_CAB;
     }
 #else
@@ -2300,7 +2544,7 @@ ULONG CCabinet::ReadFileTable()
         if ((Status = ReadBlock(&File->File, sizeof(CFFILE),
             &BytesRead)) != CAB_STATUS_SUCCESS)
         {
-            DPRINT(MIN_TRACE, ("Cannot read from file (%lu).\n", (ULONG)Status));
+            DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
             return CAB_STATUS_INVALID_CAB;
         }
 
@@ -2316,11 +2560,11 @@ ULONG CCabinet::ReadFileTable()
         if (Status != CAB_STATUS_SUCCESS)
             return Status;
 
-        DPRINT(MAX_TRACE, ("Found file '%s' at uncompressed offset (0x%lX).  Size (%lu bytes)  ControlId (0x%lX).\n",
+        DPRINT(MAX_TRACE, ("Found file '%s' at uncompressed offset (0x%X).  Size (%u bytes)  ControlId (0x%X).\n",
             File->FileName,
-            (ULONG)File->File.FileOffset,
-            (ULONG)File->File.FileSize,
-            (ULONG)File->File.FileControlID));
+            (UINT)File->File.FileOffset,
+            (UINT)File->File.FileSize,
+            File->File.FileControlID));
 
     }
     return CAB_STATUS_SUCCESS;
@@ -2343,8 +2587,8 @@ ULONG CCabinet::ReadDataBlocks(PCFFOLDER_NODE FolderNode)
     ULONG Status;
     ULONG i;
 
-    DPRINT(MAX_TRACE, ("Reading data blocks for folder (%lu)  at absolute offset (0x%lX).\n",
-        FolderNode->Index, FolderNode->Folder.DataOffset));
+    DPRINT(MAX_TRACE, ("Reading data blocks for folder (%u)  at absolute offset (0x%X).\n",
+        (UINT)FolderNode->Index, (UINT)FolderNode->Folder.DataOffset));
 
     AbsoluteOffset = FolderNode->Folder.DataOffset;
     UncompOffset   = FolderNode->UncompOffset;
@@ -2360,14 +2604,12 @@ ULONG CCabinet::ReadDataBlocks(PCFFOLDER_NODE FolderNode)
 
         /* Seek to data block */
 #if defined(WIN32)
-        SetLastError(NO_ERROR);
-        SetFilePointer(FileHandle,
-            AbsoluteOffset,
-            NULL,
-            FILE_BEGIN);
-        if (GetLastError() != NO_ERROR)
-        {
-            DPRINT(MIN_TRACE, ("SetFilePointer() failed.\n"));
+        if( SetFilePointer(FileHandle,
+                           AbsoluteOffset,
+                           NULL,
+                           FILE_BEGIN) == INVALID_SET_FILE_POINTER )
+        {
+            DPRINT(MIN_TRACE, ("SetFilePointer() failed, error code is %u.\n", (UINT)GetLastError()));
             return CAB_STATUS_INVALID_CAB;
         }
 #else
@@ -2381,16 +2623,16 @@ ULONG CCabinet::ReadDataBlocks(PCFFOLDER_NODE FolderNode)
         if ((Status = ReadBlock(&Node->Data, sizeof(CFDATA),
             &BytesRead)) != CAB_STATUS_SUCCESS)
         {
-            DPRINT(MIN_TRACE, ("Cannot read from file (%lu).\n", (ULONG)Status));
+            DPRINT(MIN_TRACE, ("Cannot read from file (%u).\n", (UINT)Status));
             return CAB_STATUS_INVALID_CAB;
         }
 
-        DPRINT(MAX_TRACE, ("AbsOffset (0x%lX)  UncompOffset (0x%lX)  Checksum (0x%lX)  CompSize (%lu)  UncompSize (%lu).\n",
-            (ULONG)AbsoluteOffset,
-            (ULONG)UncompOffset,
-            (ULONG)Node->Data.Checksum,
-            (ULONG)Node->Data.CompSize,
-            (ULONG)Node->Data.UncompSize));
+        DPRINT(MAX_TRACE, ("AbsOffset (0x%X)  UncompOffset (0x%X)  Checksum (0x%X)  CompSize (%u)  UncompSize (%u).\n",
+            (UINT)AbsoluteOffset,
+            (UINT)UncompOffset,
+            (UINT)Node->Data.Checksum,
+            Node->Data.CompSize,
+            Node->Data.UncompSize));
 
         Node->AbsoluteOffset = AbsoluteOffset;
         Node->UncompOffset   = UncompOffset;
@@ -2520,8 +2762,6 @@ void CCabinet::DestroyDataNodes(PCFFOLDER_NODE FolderNode)
 void CCabinet::DestroyFileNodes()
 /*
  * FUNCTION: Destroys file nodes
- * ARGUMENTS:
- *     FolderNode = Pointer to folder node
  */
 {
     PCFFILE_NODE PrevNode;
@@ -2652,8 +2892,8 @@ void CCabinet::DestroyDeletedFolderNodes()
 
 
 ULONG CCabinet::ComputeChecksum(void* Buffer,
-                                   ULONG Size,
-                                   ULONG Seed)
+                                ULONG Size,
+                                ULONG Seed)
 /*
  * FUNCTION: Computes checksum for data block
  * ARGUMENTS:
@@ -2672,7 +2912,7 @@ ULONG CCabinet::ComputeChecksum(void* Buffer,
     /* FIXME: Doesn't seem to be correct. EXTRACT.EXE
        won't accept checksums computed by this routine */
 
-    DPRINT(MIN_TRACE, ("Checksumming buffer (0x%p)  Size (%lu)\n", Buffer, Size));
+    DPRINT(MIN_TRACE, ("Checksumming buffer (0x%p)  Size (%u)\n", Buffer, (UINT)Size));
 
     UlongCount = Size / 4;              // Number of ULONGs
     Checksum   = Seed;                  // Init checksum
@@ -2711,8 +2951,8 @@ ULONG CCabinet::ComputeChecksum(void* Buffer,
 
 
 ULONG CCabinet::ReadBlock(void* Buffer,
-                             ULONG Size,
-                             PULONG BytesRead)
+                          ULONG Size,
+                          PULONG BytesRead)
 /*
  * FUNCTION: Read a block of data from file
  * ARGUMENTS:
@@ -2729,6 +2969,67 @@ ULONG CCabinet::ReadBlock(void* Buffer,
     return CAB_STATUS_SUCCESS;
 }
 
+bool CCabinet::MatchFileNamePattern(char* FileName, char* Pattern)
+/*
+ * FUNCTION: Matches a wildcard character pattern against a file
+ * ARGUMENTS:
+ *     FileName = The file name to check
+ *     Pattern  = The pattern
+ * RETURNS:
+ *     Whether the pattern matches the file
+ *
+ * COPYRIGHT:
+ *     This function is based on Busybox code, Copyright (C) 1998 by Erik Andersen, released under GPL2 or any later version.
+ *     Adapted from code written by Ingo Wilken.
+ *     Original location: http://www.busybox.net/cgi-bin/viewcvs.cgi/trunk/busybox/utility.c?rev=5&view=markup
+ */
+{
+    char* retryPattern = NULL;
+    char* retryFileName = NULL;
+    char  ch;
+
+    while (*FileName || *Pattern)
+    {
+        ch = *Pattern++;
+
+        switch (ch)
+        {
+            case '*':
+                retryPattern = Pattern;
+                retryFileName = FileName;
+                break;
+
+            case '?':  
+                if (*FileName++ == '\0')
+                    return false;
+
+                break;
+
+            default:
+                if (*FileName == ch)
+                {
+                    if (*FileName)
+                        FileName++;
+                    break;
+                }
+
+                if (*FileName)
+                {
+                    Pattern = retryPattern;
+                    FileName = ++retryFileName;
+                    break;
+                }
+
+                return false;
+        }
+
+        if (!Pattern)
+            return false;
+    }
+
+    return true;
+}
+
 #ifndef CAB_READ_ONLY
 
 ULONG CCabinet::InitCabinetHeader()
@@ -3024,8 +3325,8 @@ ULONG CCabinet::WriteFolderEntries()
     {
         if (FolderNode->Commit)
         {
-            DPRINT(MAX_TRACE, ("Writing folder entry. CompressionType (0x%X)  DataBlockCount (%d)  DataOffset (0x%lX).\n",
-                FolderNode->Folder.CompressionType, FolderNode->Folder.DataBlockCount, FolderNode->Folder.DataOffset));
+            DPRINT(MAX_TRACE, ("Writing folder entry. CompressionType (0x%X)  DataBlockCount (%d)  DataOffset (0x%X).\n",
+                FolderNode->Folder.CompressionType, FolderNode->Folder.DataBlockCount, (UINT)FolderNode->Folder.DataOffset));
 
 #if defined(WIN32)
             if (!WriteFile(FileHandle,
@@ -3086,8 +3387,8 @@ ULONG CCabinet::WriteFileEntries()
                 SetCont = true;
             }
 
-            DPRINT(MAX_TRACE, ("Writing file entry. FileControlID (0x%X)  FileOffset (0x%lX)  FileSize (%lu)  FileName (%s).\n",
-                File->File.FileControlID, File->File.FileOffset, File->File.FileSize, File->FileName));
+            DPRINT(MAX_TRACE, ("Writing file entry. FileControlID (0x%X)  FileOffset (0x%X)  FileSize (%u)  FileName (%s).\n",
+                File->File.FileControlID, (UINT)File->File.FileOffset, (UINT)File->File.FileSize, File->FileName));
 
 #if defined(WIN32)
             if (!WriteFile(FileHandle,
@@ -3154,8 +3455,8 @@ ULONG CCabinet::CommitDataBlocks(PCFFOLDER_NODE FolderNode)
 
     while (DataNode != NULL)
     {
-        DPRINT(MAX_TRACE, ("Reading block at (0x%lX)  CompSize (%d)  UncompSize (%d).\n",
-            DataNode->ScratchFilePosition,
+        DPRINT(MAX_TRACE, ("Reading block at (0x%X)  CompSize (%u)  UncompSize (%u).\n",
+            (UINT)DataNode->ScratchFilePosition,
             DataNode->Data.CompSize,
             DataNode->Data.UncompSize));
 
@@ -3165,7 +3466,7 @@ ULONG CCabinet::CommitDataBlocks(PCFFOLDER_NODE FolderNode)
         Status = ScratchFile->ReadBlock(&DataNode->Data, InputBuffer, &BytesRead);
         if (Status != CAB_STATUS_SUCCESS)
         {
-            DPRINT(MIN_TRACE, ("Cannot read from scratch file (%lu).\n", (ULONG)Status));
+            DPRINT(MIN_TRACE, ("Cannot read from scratch file (%u).\n", (UINT)Status));
             return Status;
         }
 
@@ -3225,8 +3526,8 @@ ULONG CCabinet::WriteDataBlock()
             CurrentIBufferSize,
             &TotalCompSize);
 
-        DPRINT(MAX_TRACE, ("Block compressed. CurrentIBufferSize (%lu)  TotalCompSize(%lu).\n",
-            CurrentIBufferSize, TotalCompSize));
+        DPRINT(MAX_TRACE, ("Block compressed. CurrentIBufferSize (%u)  TotalCompSize(%u).\n",
+            (UINT)CurrentIBufferSize, (UINT)TotalCompSize));
 
         CurrentOBuffer     = OutputBuffer;
         CurrentOBufferSize = TotalCompSize;
@@ -3265,10 +3566,10 @@ ULONG CCabinet::WriteDataBlock()
     // FIXME: MAKECAB.EXE does not like this checksum algorithm
     //DataNode->Data.Checksum = ComputeChecksum(CurrentOBuffer, DataNode->Data.CompSize, 0);
 
-    DPRINT(MAX_TRACE, ("Writing block. Checksum (0x%lX)  CompSize (%lu)  UncompSize (%lu).\n",
-        (ULONG)DataNode->Data.Checksum,
-        (ULONG)DataNode->Data.CompSize,
-        (ULONG)DataNode->Data.UncompSize));
+    DPRINT(MAX_TRACE, ("Writing block. Checksum (0x%X)  CompSize (%u)  UncompSize (%u).\n",
+        (UINT)DataNode->Data.Checksum,
+        DataNode->Data.CompSize,
+        DataNode->Data.UncompSize));
 
     Status = ScratchFile->WriteBlock(&DataNode->Data,
         CurrentOBuffer, &BytesWritten);
@@ -3280,8 +3581,8 @@ ULONG CCabinet::WriteDataBlock()
     CurrentFolderNode->TotalFolderSize += (BytesWritten + sizeof(CFDATA));
     CurrentFolderNode->Folder.DataBlockCount++;
 
-    *(unsigned char**)&CurrentOBuffer += DataNode->Data.CompSize;
-    CurrentOBufferSize     -= DataNode->Data.CompSize;
+    CurrentOBuffer = (unsigned char*)CurrentOBuffer + DataNode->Data.CompSize;
+    CurrentOBufferSize -= DataNode->Data.CompSize;
 
     LastBlockStart += DataNode->Data.UncompSize;
 
@@ -3354,7 +3655,8 @@ ULONG CCabinet::GetFileTimes(FILEHANDLE FileHandle, PCFFILE_NODE File)
         strcpy(buf, File->FileName);
     else
     {
-        getcwd(buf, sizeof(buf));
+        if (!getcwd(buf, sizeof(buf)))
+            return CAB_STATUS_CANNOT_READ;
         strcat(buf, DIR_SEPARATOR_STRING);
         strcat(buf, File->FileName);
     }
@@ -3384,20 +3686,10 @@ ULONG CCabinet::GetAttributesOnFile(PCFFILE_NODE File)
     if (Attributes == -1)
         return CAB_STATUS_CANNOT_READ;
 
-    if (Attributes & FILE_ATTRIBUTE_READONLY)
-        File->File.Attributes |= CAB_ATTRIB_READONLY;
-
-    if (Attributes & FILE_ATTRIBUTE_HIDDEN)
-        File->File.Attributes |= CAB_ATTRIB_HIDDEN;
-
-    if (Attributes & FILE_ATTRIBUTE_SYSTEM)
-        File->File.Attributes |= CAB_ATTRIB_SYSTEM;
-
-    if (Attributes & FILE_ATTRIBUTE_DIRECTORY)
-        File->File.Attributes |= CAB_ATTRIB_DIRECTORY;
-
-    if (Attributes & FILE_ATTRIBUTE_ARCHIVE)
-        File->File.Attributes |= CAB_ATTRIB_ARCHIVE;
+    // 0x37 = READONLY | HIDDEN | SYSTEM | DIRECTORY | ARCHIVE
+    // The IDs for these attributes are the same in the CAB file and under Windows
+    // If the file has any other attributes, strip them off by the logical AND.
+    File->File.Attributes = (USHORT)(Attributes & 0x37);
 #else
     struct stat stbuf;
     char buf[MAX_PATH];
@@ -3407,7 +3699,8 @@ ULONG CCabinet::GetAttributesOnFile(PCFFILE_NODE File)
         strcpy(buf, File->FileName);
     else
     {
-        getcwd(buf, sizeof(buf));
+        if (!getcwd(buf, sizeof(buf)))
+            return CAB_STATUS_CANNOT_READ;
         strcat(buf, DIR_SEPARATOR_STRING);
         strcat(buf, File->FileName);
     }
@@ -3431,34 +3724,21 @@ ULONG CCabinet::GetAttributesOnFile(PCFFILE_NODE File)
 }
 
 
-ULONG CCabinet::SetAttributesOnFile(PCFFILE_NODE File)
+ULONG CCabinet::SetAttributesOnFile(char* FileName, USHORT FileAttributes)
 /*
  * FUNCTION: Sets attributes on a file
  * ARGUMENTS:
- *      File = Pointer to CFFILE node for file
+ *      FileName       = File name with path
+ *      FileAttributes = Attributes of that file
  * RETURNS:
  *     Status of operation
  */
 {
 #if defined(WIN32)
-    ULONG Attributes = 0;
-
-    if (File->File.Attributes & CAB_ATTRIB_READONLY)
-        Attributes |= FILE_ATTRIBUTE_READONLY;
-
-    if (File->File.Attributes & CAB_ATTRIB_HIDDEN)
-        Attributes |= FILE_ATTRIBUTE_HIDDEN;
-
-    if (File->File.Attributes & CAB_ATTRIB_SYSTEM)
-        Attributes |= FILE_ATTRIBUTE_SYSTEM;
-
-    if (File->File.Attributes & CAB_ATTRIB_DIRECTORY)
-        Attributes |= FILE_ATTRIBUTE_DIRECTORY;
-
-    if (File->File.Attributes & CAB_ATTRIB_ARCHIVE)
-        Attributes |= FILE_ATTRIBUTE_ARCHIVE;
-
-    SetFileAttributes(File->FileName, Attributes);
+    // 0x37 = READONLY | HIDDEN | SYSTEM | DIRECTORY | ARCHIVE
+    // The IDs for these attributes are the same in the CAB file and under Windows
+    // If the file has any other attributes, strip them off by the logical AND.
+    SetFileAttributes(FileName, (DWORD)(FileAttributes & 0x37));
 
     return CAB_STATUS_SUCCESS;
 #else