From 70193adc891cd59b0379bef9dd5627ac222ba954 Mon Sep 17 00:00:00 2001 From: Mark Jansen Date: Sat, 12 Sep 2020 16:21:34 +0200 Subject: [PATCH] [CABMAN] Add commandline support for creating a cab with folders CORE-17230 --- sdk/tools/cabman/cabinet.cxx | 77 +++++++++++++++++++++--------------- sdk/tools/cabman/cabinet.h | 14 ++++--- sdk/tools/cabman/cabman.cxx | 25 +++++++++--- sdk/tools/cabman/dfp.cxx | 8 ++-- 4 files changed, 78 insertions(+), 46 deletions(-) diff --git a/sdk/tools/cabman/cabinet.cxx b/sdk/tools/cabman/cabinet.cxx index 175efef918a..29f9975b6fe 100644 --- a/sdk/tools/cabman/cabinet.cxx +++ b/sdk/tools/cabman/cabinet.cxx @@ -155,7 +155,7 @@ void CCabinet::ConvertPath(std::string& Path) } -const char* CCabinet::GetFileName(const char* Path) +std::string CCabinet::GetFileName(const std::string& Path) /* * FUNCTION: Returns a pointer to file name * ARGUMENTS: @@ -172,7 +172,7 @@ const char* CCabinet::GetFileName(const char* Path) if (IsSeparator(Path [i - 1])) j = i; - return Path + j; + return Path.c_str() + j; } @@ -225,7 +225,7 @@ void CCabinet::SetDestinationPath(const char* DestinationPath) NormalizePath(DestPath); } -ULONG CCabinet::AddSearchCriteria(const char* SearchCriteria) +ULONG CCabinet::AddSearchCriteria(const std::string& SearchCriteria, const std::string& TargetFolder) /* * FUNCTION: Adds a criteria to the search criteria list * ARGUMENTS: @@ -248,6 +248,7 @@ ULONG CCabinet::AddSearchCriteria(const char* SearchCriteria) // Set the actual criteria string Criteria->Search = SearchCriteria; + Criteria->TargetFolder = TargetFolder; return CAB_STATUS_SUCCESS; } @@ -274,6 +275,16 @@ bool CCabinet::HasSearchCriteria() return !CriteriaList.empty(); } +std::string CCabinet::CreateCabFilename(PCFFILE_NODE Node) +{ + std::string fname = GetFileName(Node->FileName); + if (!Node->TargetFolder.empty()) + { + fname = Node->TargetFolder + fname; + } + return fname; +} + bool CCabinet::SetCompressionCodec(const char* CodecName) /* * FUNCTION: Selects the codec to use for compression @@ -591,6 +602,7 @@ ULONG CCabinet::FindNext(PCAB_SEARCH Search) for (PSEARCH_CRITERIA Criteria : CriteriaList) { + // FIXME: We could handle path\filename here if (MatchFileNamePattern((*Search->Next)->FileName.c_str(), Criteria->Search.c_str())) { bFound = true; @@ -1202,7 +1214,7 @@ ULONG CCabinet::WriteFileToScratchStorage(PCFFILE_NODE FileNode) SourceFile = fopen(FileNode->FileName.c_str(), "rb"); if (SourceFile == NULL) { - DPRINT(MID_TRACE, ("File not found (%s).\n", FileNode->FileName.c_str())); + DPRINT(MID_TRACE, ("File not found (%s).\n", FileNode->FileNameOnDisk.c_str())); return CAB_STATUS_NOFILE; } @@ -1227,7 +1239,7 @@ ULONG CCabinet::WriteFileToScratchStorage(PCFFILE_NODE FileNode) CurrentFolderNode->Commit = true; PrevCabinetNumber = CurrentDiskNumber; - Size = sizeof(CFFILE) + (ULONG)strlen(GetFileName(FileNode->FileName.c_str())) + 1; + Size = sizeof(CFFILE) + (ULONG)CreateCabFilename(FileNode).length() + 1; CABHeader.FileTableOffset += Size; TotalFileSize += Size; DiskSize += Size; @@ -1500,7 +1512,7 @@ ULONG CCabinet::CloseCabinet() } -ULONG CCabinet::AddFile(char* FileName) +ULONG CCabinet::AddFile(const std::string& FileName, const std::string& TargetFolder) /* * FUNCTION: Adds a file to the current disk * ARGUMENTS: @@ -1534,6 +1546,9 @@ ULONG CCabinet::AddFile(char* FileName) FileNode->FolderNode = CurrentFolderNode; FileNode->FileName = NewFileName; + FileNode->TargetFolder = TargetFolder; + if (FileNode->TargetFolder.length() > 0 && FileNode->TargetFolder[FileNode->TargetFolder.length() - 1] != '\\') + FileNode->TargetFolder += '\\'; /* FIXME: Check for and handle large files (>= 2GB) */ FileNode->File.FileSize = GetSizeOfFile(SrcFile); @@ -1569,9 +1584,6 @@ bool CCabinet::CreateSimpleCabinet() */ { bool bRet = false; - const char* pszFile; - char szFilePath[PATH_MAX]; - char szFile[PATH_MAX]; ULONG Status; #if defined(_WIN32) @@ -1595,26 +1607,25 @@ bool CCabinet::CreateSimpleCabinet() for (PSEARCH_CRITERIA Criteria : CriteriaList) { // Store the file path with a trailing slash in szFilePath - ConvertPath(Criteria->Search); - pszFile = strrchr(Criteria->Search.c_str(), DIR_SEPARATOR_CHAR); + std::string szSearchPath = Criteria->Search; + ConvertPath(szSearchPath); + auto sep = szSearchPath.find_last_of(DIR_SEPARATOR_CHAR); + std::string szFilePath; + std::string pszFile; - if(pszFile) + if (sep != std::string::npos) { - // Set the pointer to the start of the file name, not the slash - pszFile++; + pszFile = szSearchPath.substr(sep + 1); // We want the filename, not the dir separator! - strncpy(szFilePath, Criteria->Search.c_str(), pszFile - Criteria->Search.c_str()); - szFilePath[pszFile - Criteria->Search.c_str()] = 0; + szFilePath = szSearchPath.substr(0, sep + 1); } else { - pszFile = Criteria->Search.c_str(); + pszFile = Criteria->Search; -#if defined(_WIN32) - szFilePath[0] = 0; -#else +#if !defined(_WIN32) // needed for opendir() - strcpy(szFilePath, "./"); + szFilePath = "./"; #endif } @@ -1633,10 +1644,10 @@ bool CCabinet::CreateSimpleCabinet() { if(!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - strcpy(szFile, szFilePath); - strcat(szFile, FindFileData.cFileName); + std::string szFile = szFilePath; + szFile += FindFileData.cFileName; - Status = AddFile(szFile); + Status = AddFile(szFile, Criteria->TargetFolder); if(Status != CAB_STATUS_SUCCESS) { @@ -1651,22 +1662,22 @@ bool CCabinet::CreateSimpleCabinet() 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); + dirp = opendir(szFilePath.c_str()); if(dirp) { while( (dp = readdir(dirp)) ) { - strcpy(szFile, szFilePath); - strcat(szFile, dp->d_name); + std::string szFile = szFilePath; + szFile += dp->d_name; - if(stat(szFile, &stbuf) == 0) + if(stat(szFile.c_str(), &stbuf) == 0) { if(stbuf.st_mode != S_IFDIR) { - if(MatchFileNamePattern(dp->d_name, pszFile)) + if(MatchFileNamePattern(dp->d_name, pszFile.c_str())) { - Status = AddFile(szFile); + Status = AddFile(szFile, Criteria->TargetFolder); if(Status != CAB_STATUS_SUCCESS) { @@ -1890,6 +1901,7 @@ ULONG CCabinet::LocateFile(const char* FileName, for (PCFFILE_NODE Node : FileList) { + // FIXME: We could handle path\filename here if (strcasecmp(FileName, Node->FileName.c_str()) == 0) { CurrentFolderNode = LocateFolderNode(Node->File.FileControlID); @@ -2011,6 +2023,7 @@ ULONG CCabinet::ReadFileTable() Status = ReadString(Buf, PATH_MAX); if (Status != CAB_STATUS_SUCCESS) return Status; + // FIXME: We could split up folder\file.txt here File->FileName = Buf; DPRINT(MAX_TRACE, ("Found file '%s' at uncompressed offset (0x%X). Size (%u bytes) ControlId (0x%X).\n", @@ -2195,7 +2208,7 @@ void CCabinet::DestroyDeletedFileNodes() DPRINT(MAX_TRACE, ("Deleting file node: '%s'\n", CurNode->FileName.c_str())); - TotalFileSize -= (sizeof(CFFILE) + (ULONG)strlen(GetFileName(CurNode->FileName.c_str())) + 1); + TotalFileSize -= (sizeof(CFFILE) + (ULONG)CreateCabFilename(CurNode).length() + 1); delete CurNode; } @@ -2669,7 +2682,7 @@ ULONG CCabinet::WriteFileEntries() return CAB_STATUS_CANNOT_WRITE; } - std::string fname = GetFileName(File->FileName.c_str()); + std::string fname = CreateCabFilename(File); if (fwrite(fname.c_str(), fname.length() + 1, 1, FileHandle) < 1) { DPRINT(MIN_TRACE, ("Cannot write to file.\n")); diff --git a/sdk/tools/cabman/cabinet.h b/sdk/tools/cabman/cabinet.h index 0940436d975..1697588bbfc 100644 --- a/sdk/tools/cabman/cabinet.h +++ b/sdk/tools/cabman/cabinet.h @@ -227,6 +227,7 @@ typedef struct _CFFILE_NODE { CFFILE File = { 0 }; std::string FileName; + std::string TargetFolder; PCFDATA_NODE DataBlock = nullptr; // First data block of file. NULL if not known bool Commit = false; // true if the file data should be committed bool Delete = false; // true if marked for deletion @@ -235,7 +236,8 @@ typedef struct _CFFILE_NODE typedef struct _SEARCH_CRITERIA { - std::string Search; // The actual search criteria + std::string Search; // The actual search criteria + std::string TargetFolder; // The filename will be TargetFolder\file } SEARCH_CRITERIA, *PSEARCH_CRITERIA; typedef struct _CAB_SEARCH @@ -311,8 +313,8 @@ public: bool IsSeparator(char Char); /* Replaces \ or / with the one used be the host environment */ void ConvertPath(std::string& Path); - /* Returns a pointer to the filename part of a fully qualified filename */ - const char* GetFileName(const char* Path); + /* Returns the filename part of a fully qualified filename */ + std::string GetFileName(const std::string& Path); /* Normalizes a path */ void NormalizePath(std::string& Path); /* Returns name of cabinet file */ @@ -342,12 +344,14 @@ public: /* 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(const char* SearchCriteria); + ULONG AddSearchCriteria(const std::string& SearchCriteria, const std::string& TargetFolder); /* Destroys the search criteria list */ void DestroySearchCriteria(); /* Returns whether we have search criteria */ bool HasSearchCriteria(); + std::string CreateCabFilename(PCFFILE_NODE Node); + #ifndef CAB_READ_ONLY /* Creates a simple cabinet based on the search criteria data */ bool CreateSimpleCabinet(); @@ -370,7 +374,7 @@ public: /* Closes the current cabinet */ ULONG CloseCabinet(); /* Adds a file to the current disk */ - ULONG AddFile(char* FileName); + ULONG AddFile(const std::string& FileName, const std::string& TargetFolder); /* Sets the maximum size of the current disk */ void SetMaxDiskSize(ULONG Size); #endif /* CAB_READ_ONLY */ diff --git a/sdk/tools/cabman/cabman.cxx b/sdk/tools/cabman/cabman.cxx index 0dd0ceaab1d..d258b534e79 100644 --- a/sdk/tools/cabman/cabman.cxx +++ b/sdk/tools/cabman/cabman.cxx @@ -193,7 +193,7 @@ void CCABManager::Usage() printf("ReactOS Cabinet Manager\n\n"); printf("CABMAN [-D | -E] [-A] [-L dir] cabinet [filename ...]\n"); printf("CABMAN [-M mode] -C dirfile [-I] [-RC file] [-P dir]\n"); - printf("CABMAN [-M mode] -S cabinet filename [...]\n"); + printf("CABMAN [-M mode] -S cabinet filename [-F folder] [filename] [...]\n"); printf(" cabinet Cabinet file.\n"); printf(" filename Name of the file to add to or extract from the cabinet.\n"); printf(" Wild cards and multiple filenames\n"); @@ -206,6 +206,7 @@ void CCABManager::Usage() printf(" -C Create cabinet.\n"); printf(" -D Display cabinet directory.\n"); printf(" -E Extract files from cabinet.\n"); + printf(" -F Put the files from the next 'filename' filter in the cab in folder\filename.\n"); 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"); @@ -233,7 +234,7 @@ bool CCABManager::ParseCmdline(int argc, char* argv[]) int i; bool ShowUsage; bool FoundCabinet = false; - + std::string NextFolder; ShowUsage = (argc < 2); for (i = 1; i < argc; i++) @@ -262,6 +263,19 @@ bool CCABManager::ParseCmdline(int argc, char* argv[]) Mode = CM_MODE_EXTRACT; break; + case 'f': + case 'F': + if (argv[i][2] == 0) + { + i++; + NextFolder = argv[i]; + } + else + { + NextFolder = argv[i] + 2; + } + break; + case 'i': case 'I': InfFileOnly = true; @@ -374,7 +388,8 @@ bool CCABManager::ParseCmdline(int argc, char* argv[]) else if(FoundCabinet) { // For creating simple cabinets, displaying or extracting them, add the argument as a search criteria - AddSearchCriteria(argv[i]); + AddSearchCriteria(argv[i], NextFolder); + NextFolder.clear(); } else { @@ -618,7 +633,7 @@ void CCABManager::OnExtract(PCFFILE File, { if (Verbose) { - printf("Extracting %s\n", GetFileName(FileName)); + printf("Extracting %s\n", GetFileName(FileName).c_str()); } } @@ -651,7 +666,7 @@ void CCABManager::OnAdd(PCFFILE File, { if (Verbose) { - printf("Adding %s\n", GetFileName(FileName)); + printf("Adding %s\n", GetFileName(FileName).c_str()); } } diff --git a/sdk/tools/cabman/dfp.cxx b/sdk/tools/cabman/dfp.cxx index b6b4335e59a..575b48f0816 100644 --- a/sdk/tools/cabman/dfp.cxx +++ b/sdk/tools/cabman/dfp.cxx @@ -6,7 +6,7 @@ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) * Colin Finck * NOTES: The directive file format is similar to the - * directive file format used by Microsoft's MAKECAB + * directive file format used by Microsoft's MAKECAB (But not entirely compatible!) * REVISIONS: * CSH 21/03-2001 Created * CSH 15/08-2003 Made it portable @@ -1123,17 +1123,17 @@ ULONG CDFParser::PerformFileCopy() DPRINT(MID_TRACE, ("Adding file: '%s' destination: '%s'.\n", SrcName, DstName)); - Status = AddFile(SrcName); + Status = AddFile(SrcName, std::string()); if (Status == CAB_STATUS_CANNOT_OPEN) { strcpy(SrcName, FileRelativePath.c_str()); strcat(SrcName, BaseFilename); - Status = AddFile(SrcName); + Status = AddFile(SrcName, std::string()); } switch (Status) { case CAB_STATUS_SUCCESS: - sprintf(InfLine, "%s=%s", GetFileName(SrcName), DstName); + sprintf(InfLine, "%s=%s", GetFileName(SrcName).c_str(), DstName); WriteInfLine(InfLine); break;