Author: cfinck
Date: Tue Feb 5 01:48:42 2008
New Revision: 32127
URL:
http://svn.reactos.org/svn/reactos?rev=32127&view=rev
Log:
- Add a function MatchFileNamePattern for matching a file against a pattern (imported from
Busybox under GPL2 or later license, heavily modified for our purposes, more information
in the function comments)
- Add support for multiple search criterias, which are actually checked.
This makes it possible to pass parameters like "*.rbuild *.txt" to the cabman
command line for adding, displaying and extracting files in a cabinet.
- Overhaul CreateSimpleCabinet, make it able to add multiple files to the cabinet using
the new search criteria functions.
- Fix some comments and indentation here and there.
Modified:
trunk/reactos/tools/cabman/cabinet.cxx
trunk/reactos/tools/cabman/cabinet.h
trunk/reactos/tools/cabman/cabman.h
trunk/reactos/tools/cabman/dfp.cxx
trunk/reactos/tools/cabman/main.cxx
Modified: trunk/reactos/tools/cabman/cabinet.cxx
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/tools/cabman/cabinet.cxx?r…
==============================================================================
--- trunk/reactos/tools/cabman/cabinet.cxx (original)
+++ trunk/reactos/tools/cabman/cabinet.cxx Tue Feb 5 01:48:42 2008
@@ -18,6 +18,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#if !defined(WIN32)
+# include <dirent.h>
+#endif
#if defined(__FreeBSD__) || defined(__APPLE__)
# include <sys/stat.h>
#endif // __FreeBSD__
@@ -315,10 +318,12 @@
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;
@@ -509,6 +514,82 @@
ConvertPath(DestPath, false);
if (strlen(DestPath) > 0)
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)
@@ -821,19 +902,16 @@
}
-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);
}
@@ -848,6 +926,8 @@
* Status of operation
*/
{
+ bool bFound = false;
+ PSEARCH_CRITERIA Criteria;
ULONG Status;
if (RestartSearch)
@@ -867,7 +947,32 @@
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)
{
@@ -1960,6 +2065,151 @@
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
+ pszFile = strrchr(Criteria->Search, '/');
+ if(!pszFile)
+ pszFile = strrchr(Criteria->Search, '\\');
+
+ if(pszFile)
+ {
+ strncpy(szFilePath, Criteria->Search, pszFile - Criteria->Search + 1);
+ szFilePath[pszFile - Criteria->Search + 1] = 0;
+ }
+ else
+ szFilePath[0] = 0;
+
+#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
+ if(szFilePath[0] == 0)
+ strcpy(szFilePath, "./");
+
+ 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)
+ {
+ // As we added "./" to szFilePath above, szFile might
contain "./test.txt" now and Criteria->Search "test.txt".
+ // Therefore they won't match using MatchFileNamePattern. By
using pszFile here, we can avoid this problem.
+ if(szFile[0] == '.' && szFile[1] == '/')
+ pszFile = szFile + 2;
+ else
+ pszFile = szFile;
+
+ if(MatchFileNamePattern(pszFile, Criteria->Search))
+ {
+ 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)
/*
@@ -2509,8 +2759,6 @@
void CCabinet::DestroyFileNodes()
/*
* FUNCTION: Destroys file nodes
- * ARGUMENTS:
- * FolderNode = Pointer to folder node
*/
{
PCFFILE_NODE PrevNode;
@@ -2641,8 +2889,8 @@
ULONG CCabinet::ComputeChecksum(void* Buffer,
- ULONG Size,
- ULONG Seed)
+ ULONG Size,
+ ULONG Seed)
/*
* FUNCTION: Computes checksum for data block
* ARGUMENTS:
@@ -2700,8 +2948,8 @@
ULONG CCabinet::ReadBlock(void* Buffer,
- ULONG Size,
- PULONG BytesRead)
+ ULONG Size,
+ PULONG BytesRead)
/*
* FUNCTION: Read a block of data from file
* ARGUMENTS:
@@ -2716,6 +2964,67 @@
if (!ReadFileData(FileHandle, Buffer, Size, BytesRead))
return CAB_STATUS_INVALID_CAB;
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&am…
+ */
+{
+ 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
Modified: trunk/reactos/tools/cabman/cabinet.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/tools/cabman/cabinet.h?rev…
==============================================================================
--- trunk/reactos/tools/cabman/cabinet.h (original)
+++ trunk/reactos/tools/cabman/cabinet.h Tue Feb 5 01:48:42 2008
@@ -224,13 +224,18 @@
PCFFOLDER_NODE FolderNode; // Folder this file belong to
} CFFILE_NODE, *PCFFILE_NODE;
+typedef struct _SEARCH_CRITERIA
+{
+ struct _SEARCH_CRITERIA *Next; // Pointer to next search criteria
+ struct _SEARCH_CRITERIA *Prev; // Pointer to previous search criteria
+ char* Search; // The actual search criteria
+} SEARCH_CRITERIA, *PSEARCH_CRITERIA;
typedef struct _CAB_SEARCH
{
- char Search[MAX_PATH]; // Search criteria
- PCFFILE_NODE Next; // Pointer to next node
- PCFFILE File; // Pointer to current CFFILE
- char* FileName; // Current filename
+ PCFFILE_NODE Next; // Pointer to next node
+ PCFFILE File; // Pointer to current CFFILE
+ char* FileName; // Current filename
} CAB_SEARCH, *PCAB_SEARCH;
@@ -345,16 +350,25 @@
/* Closes the current open cabinet file */
void Close();
/* Locates the first file in the current cabinet file that matches a search criteria
*/
- ULONG FindFirst(char* FileName, PCAB_SEARCH Search);
+ ULONG FindFirst(PCAB_SEARCH Search);
/* Locates the next file in the current cabinet file */
ULONG FindNext(PCAB_SEARCH Search);
/* Extracts a file from the current cabinet file */
ULONG ExtractFile(char* FileName);
/* Select codec engine to use */
void SelectCodec(LONG Id);
- /* Returns if a codec engine is selected */
+ /* Returns whether a codec engine is selected */
bool IsCodecSelected();
+ /* Adds a search criteria for adding files to a simple cabinet, displaying files in a
cabinet or extracting them */
+ ULONG AddSearchCriteria(char* SearchCriteria);
+ /* Destroys the search criteria list */
+ void DestroySearchCriteria();
+ /* Returns whether we have search criteria */
+ bool HasSearchCriteria();
+
#ifndef CAB_READ_ONLY
+ /* Creates a simple cabinet based on the search criteria data */
+ bool CreateSimpleCabinet();
/* Sets the codec to use for compression (based on a string value) */
bool SetCompressionCodec(char* CodecName);
/* Creates a new cabinet file */
@@ -412,6 +426,7 @@
void DestroyDeletedFolderNodes();
ULONG ComputeChecksum(void* Buffer, ULONG Size, ULONG Seed);
ULONG ReadBlock(void* Buffer, ULONG Size, PULONG BytesRead);
+ bool MatchFileNamePattern(char* FileName, char* Pattern);
#ifndef CAB_READ_ONLY
ULONG InitCabinetHeader();
ULONG WriteCabinetHeader(bool MoreDisks);
@@ -455,6 +470,8 @@
PCFDATA_NODE CurrentDataNode;
PCFFILE_NODE FileListHead;
PCFFILE_NODE FileListTail;
+ PSEARCH_CRITERIA CriteriaListHead;
+ PSEARCH_CRITERIA CriteriaListTail;
CCABCodec *Codec;
LONG CodecId;
bool CodecSelected;
Modified: trunk/reactos/tools/cabman/cabman.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/tools/cabman/cabman.h?rev=…
==============================================================================
--- trunk/reactos/tools/cabman/cabman.h (original)
+++ trunk/reactos/tools/cabman/cabman.h Tue Feb 5 01:48:42 2008
@@ -27,7 +27,6 @@
private:
void Usage();
bool CreateCabinet();
- bool CreateSimpleCabinet();
bool DisplayCabinet();
bool ExtractFromCabinet();
/* Event handlers */
@@ -39,7 +38,6 @@
bool ProcessAll;
ULONG Mode;
bool PromptOnOverwrite;
- char Location[MAX_PATH];
char FileName[MAX_PATH];
};
Modified: trunk/reactos/tools/cabman/dfp.cxx
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/tools/cabman/dfp.cxx?rev=3…
==============================================================================
--- trunk/reactos/tools/cabman/dfp.cxx (original)
+++ trunk/reactos/tools/cabman/dfp.cxx Tue Feb 5 01:48:42 2008
@@ -391,7 +391,7 @@
if (!InfFileOnly)
{
- printf("\nWriting cabinet. This may take a while...\n\n");
+ printf("\nWriting cabinet. This may take a while...\n\n");
if (DiskCreated)
{
Modified: trunk/reactos/tools/cabman/main.cxx
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/tools/cabman/main.cxx?rev=…
==============================================================================
--- trunk/reactos/tools/cabman/main.cxx (original)
+++ trunk/reactos/tools/cabman/main.cxx Tue Feb 5 01:48:42 2008
@@ -172,6 +172,7 @@
ProcessAll = false;
InfFileOnly = false;
Mode = CM_MODE_DISPLAY;
+ FileName[0] = 0;
}
@@ -190,8 +191,8 @@
{
printf("ReactOS Cabinet Manager\n\n");
printf("CABMAN [-D | -E] [-A] [-L dir] cabinet [filename ...]\n");
- printf("CABMAN -C dirfile [-I] [-RC file] [-P dir]\n");
- printf("CABMAN -S cabinet filename\n");
+ printf("CABMAN [-M mode] -C dirfile [-I] [-RC file] [-P dir]\n");
+ printf("CABMAN [-M mode] -S cabinet filename ...\n");
printf(" cabinet Cabinet file.\n");
printf(" filename Name of the file to extract from the cabinet.\n");
printf(" Wild cards and multiple filenames\n");
@@ -207,7 +208,7 @@
printf(" -I Don't create the cabinet, only the .inf file.\n");
printf(" -L dir Location to place extracted or generated files\n");
printf(" (default is current directory).\n");
- printf(" -M Specify the compression method to use\n");
+ printf(" -M mode Specify the compression method to use:\n");
printf(" raw - No compression\n");
printf(" mszip - MsZip compression (default)\n");
printf(" -N Don't create the .inf file, only the cabinet.\n");
@@ -351,10 +352,23 @@
}
else
{
- if ((FoundCabinet) || (Mode == CM_MODE_CREATE))
- {
- /* FIXME: There may be many of these if Mode != CM_MODE_CREATE */
- strcpy(FileName, argv[i]);
+ if(Mode == CM_MODE_CREATE)
+ {
+ if(FileName[0])
+ {
+ printf("You may only specify one directive file!\n");
+ return false;
+ }
+ else
+ {
+ // For creating cabinets, this argument is the path to the directive
file
+ strcpy(FileName, argv[i]);
+ }
+ }
+ else if(FoundCabinet)
+ {
+ // For creating simple cabinets, displaying or extracting them, add the
argument as a search criteria
+ AddSearchCriteria(argv[i]);
}
else
{
@@ -366,14 +380,21 @@
if (ShowUsage)
{
- Usage();
- return false;
+ Usage();
+ return false;
}
// Select MsZip by default for creating cabinets
if( (Mode == CM_MODE_CREATE || Mode == CM_MODE_CREATE_SIMPLE) &&
!IsCodecSelected() )
SelectCodec(CAB_CODEC_MSZIP);
+ // Search criteria (= the filename argument) is necessary for creating a simple
cabinet
+ if( Mode == CM_MODE_CREATE_SIMPLE && !HasSearchCriteria())
+ {
+ printf("You have to enter input file names!\n");
+ return false;
+ }
+
return true;
}
@@ -396,43 +417,6 @@
return (Status == CAB_STATUS_SUCCESS ? true : false);
}
-
-
-bool CCABManager::CreateSimpleCabinet()
-/*
- * FUNCTION: Create cabinet
- */
-{
- ULONG Status;
-
- Status = NewCabinet();
- if (Status != CAB_STATUS_SUCCESS)
- {
- DPRINT(MIN_TRACE, ("Cannot create cabinet (%u).\n", (UINT)Status));
- return false;
- }
-
- Status = AddFile(FileName);
- if (Status != CAB_STATUS_SUCCESS)
- {
- DPRINT(MIN_TRACE, ("Cannot add file to cabinet (%u).\n",
(UINT)Status));
- return false;
- }
-
- 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));
- return false;
- }
-
- CloseCabinet();
-
- return true;
-}
-
bool CCABManager::DisplayCabinet()
/*
@@ -448,7 +432,7 @@
{
printf("Cabinet %s\n\n", GetCabinetName());
- if (FindFirst("", &Search) == CAB_STATUS_SUCCESS)
+ if (FindFirst(&Search) == CAB_STATUS_SUCCESS)
{
do
{
@@ -466,6 +450,8 @@
}
} while (FindNext(&Search) == CAB_STATUS_SUCCESS);
}
+
+ DestroySearchCriteria();
if (FileCount > 0) {
if (FileCount == 1)
@@ -503,6 +489,7 @@
* FUNCTION: Extract file(s) from cabinet
*/
{
+ bool bRet = true;
CAB_SEARCH Search;
ULONG Status;
@@ -510,34 +497,46 @@
{
printf("Cabinet %s\n\n", GetCabinetName());
- if (FindFirst("", &Search) == CAB_STATUS_SUCCESS)
+ if (FindFirst(&Search) == CAB_STATUS_SUCCESS)
{
do
{
- switch (Status = ExtractFile(Search.FileName)) {
+ switch (Status = ExtractFile(Search.FileName))
+ {
case CAB_STATUS_SUCCESS:
break;
case CAB_STATUS_INVALID_CAB:
printf("Cabinet contains errors.\n");
- return false;
+ bRet = false;
+ break;
case CAB_STATUS_UNSUPPCOMP:
printf("Cabinet uses unsupported compression
type.\n");
- return false;
+ bRet = false;
+ break;
case CAB_STATUS_CANNOT_WRITE:
printf("You've run out of free space on the destination
volume or the volume is damaged.\n");
- return false;
+ bRet = false;
+ break;
default:
printf("Unspecified error code (%u).\n",
(UINT)Status);
- return false;
+ bRet = false;
+ break;
}
+
+ if(!bRet)
+ break;
} while (FindNext(&Search) == CAB_STATUS_SUCCESS);
+
+ DestroySearchCriteria();
}
- return true;
- } else
+
+ return bRet;
+ }
+ else
printf("Cannot open file: %s.\n", GetCabinetName());
return false;
@@ -555,19 +554,15 @@
{
case CM_MODE_CREATE:
return CreateCabinet();
- break;
case CM_MODE_DISPLAY:
return DisplayCabinet();
- break;
case CM_MODE_EXTRACT:
return ExtractFromCabinet();
- break;
case CM_MODE_CREATE_SIMPLE:
return CreateSimpleCabinet();
- break;
default:
break;