diff --git a/programs/util.c b/programs/util.c index 3988295d..caadf40e 100644 --- a/programs/util.c +++ b/programs/util.c @@ -163,6 +163,235 @@ U64 UTIL_getTotalFileSize(const char* const * const fileNamesTable, unsigned nbF return error ? UTIL_FILESIZE_UNKNOWN : total; } + +int UTIL_readLineFromFile(char* buf, size_t len, FILE* file) { + if (feof(file)) { + UTIL_DISPLAYLEVEL(1, "[ERROR] end of file reached and need to read\n"); + return -1; + } + UTIL_DISPLAY("[TRACE] read line\n"); + + char* fgetsCheck = fgets(buf, len, file); + + if(fgetsCheck == NULL || fgetsCheck != buf) { + UTIL_DISPLAYLEVEL(1, "[ERROR][UTIL_readLineFromFile] fgets has a problem check: %s buf: %s \n", + fgetsCheck == NULL ? "NULL" : fgetsCheck, buf); + return -1; + } + + UTIL_DISPLAY("[TRACE] length of Line: %d\n" , (int)strlen(buf)); + return (int) strlen(buf)-1; /* -1 to ignore '\n' character */ +} + +/* Warning: inputFileSize should be less than or equal buf capacity and buf should be initialized*/ +static int readFromFile(char* buf, size_t inputFileSize, const char* inputFileName) { + + if(!buf) { + UTIL_DISPLAYLEVEL(1, "[ERROR][UTIL_readFileNamesTableFromFile] Can't create buffer.\n"); + return -1; + } + + UTIL_DISPLAY("[TRACE] open file\n"); + FILE* inputFile = fopen(inputFileName, "r"); + int nbFiles = -1; + + if(!inputFile) { + UTIL_DISPLAYLEVEL(1, "[ERROR][UTIL_readFileNamesTableFromFile] Can't open file to read input file names.\n"); + return -1; + } + + unsigned pos = 0; + for(nbFiles=0; !feof(inputFile) ; ) { + if(UTIL_readLineFromFile(buf+pos, inputFileSize, inputFile) > 0) { + int len = (int) strlen(buf+pos); + buf[pos+len-1] = '\0'; /* replace '\n' with '\0'*/ + UTIL_DISPLAY("[TRACE] line: %s\n", buf+pos); + pos += len; + ++nbFiles; + } + else + UTIL_DISPLAY("[TRACE] ignored line: %s", buf+pos); + } + + fclose(inputFile); + + if(pos > inputFileSize) return -1; + + return nbFiles; +} + +/*Note: buf is not freed in case function successfully created table because filesTable->fileNames[0] = buf*/ +FileNamesTable* +UTIL_createFileNamesTable_fromFileName(const char* inputFileName) { + + UTIL_DISPLAY("file check\n"); + if(!UTIL_fileExist(inputFileName) || !UTIL_isRegularFile(inputFileName)) + return NULL; + + UTIL_DISPLAY("[TRACE] start function readFileNamesTableFromFile\n"); + U64 inputFileSize = UTIL_getFileSize(inputFileName) + 1; /* (+1) to add '\0' at the end of last filename */ + + if(inputFileSize > MAX_FILE_OF_FILE_NAMES_SIZE) + return NULL; + + char* buf = (char*) malloc(inputFileSize * sizeof(char)); + if(!buf) { + UTIL_DISPLAYLEVEL(1, "[ERROR][UTIL_readFileNamesTableFromFile] Can't create buffer.\n"); + return NULL; + } + + int nbFiles = readFromFile(buf, inputFileSize, inputFileName); + + if(nbFiles <= 0) { + free(buf); + return NULL; + } + + UTIL_DISPLAY("[TRACE] file closed with %d read lines\n", nbFiles); + + FileNamesTable* filesTable = (FileNamesTable*) malloc(sizeof(FileNamesTable)); + if(!filesTable) { + free(buf); + UTIL_DISPLAYLEVEL(1, "[ERROR][UTIL_readFileNamesTableFromFile] Can't create table for files.\n"); + return NULL; + } + + filesTable->tableSize = nbFiles; + filesTable->fileNames = (const char**) malloc((nbFiles+1) * sizeof(char*)); + + UTIL_DISPLAY("[TRACE] Start migration\n"); + + size_t i = 0, pos = 0; + for(i = 0, pos = 0; i < nbFiles; ++i) { + filesTable->fileNames[i] = buf+pos; + UTIL_DISPLAY("[TRACE] file %zu: %s\n", i, filesTable->fileNames[i]); + pos += strlen(buf+pos)+1; + } + + UTIL_DISPLAY("[TRACE] migration done\n"); + + + UTIL_DISPLAY("[TRACE] pos %zu inputFileSize %lu\n", pos, inputFileSize); + if(pos > inputFileSize){ + UTIL_freeFileNamesTable(filesTable); + if(buf) free(buf); + return NULL; + } + + filesTable->buf = buf; + UTIL_DISPLAY("[TRACE] finished reading\n"); + + return filesTable; +} + +void UTIL_freeFileNamesTable(FileNamesTable* table) { + if(table) { + if(table->fileNames) { + if(table->buf) + free(table->buf); + free(table->fileNames); + } + free(table); + } +} + +static size_t getTotalTableSize(FileNamesTable* table) { + size_t i = 0, totalSize = 0; + for(i = 0 ; i < table->tableSize && table->fileNames[i] ; ++i) { + totalSize += strlen(table->fileNames[i]) + 1; /* +1 to add '\0' at the end of each fileName */ + } + + return totalSize; +} + +FileNamesTable* +UTIL_concatenateTwoTables(FileNamesTable* table1, FileNamesTable* table2) { + UTIL_DISPLAY("[TRACE] Start concatenation\n"); + unsigned newTableIdx = 0, idx1 = 0, idx2 = 0; + size_t i = 0; + + FileNamesTable* newTable = (FileNamesTable*) malloc(sizeof(FileNamesTable)); + + if(!newTable) { + UTIL_DISPLAYLEVEL(1, "[ERROR][UTIL_concatenateTwoTables] Can't create new table for concatenation output.\n"); + return NULL; + } + + int newTotalTableSize = getTotalTableSize(table1) + getTotalTableSize(table2); + UTIL_DISPLAY("[TRACE] buf total size is: %d\n", newTotalTableSize); + + char* buf = (char*) malloc(newTotalTableSize * sizeof(char)); + if(!buf) { + UTIL_freeFileNamesTable(newTable); + UTIL_DISPLAYLEVEL(1, "[ERROR][UTIL_concatenateTwoTables] Can't create buf for concatenation output.\n"); + return NULL; + } + + for(i = 0; i < newTotalTableSize ; ++i) buf[i] = '\0'; + + newTable->tableSize = table1->tableSize + table2->tableSize; + newTable->fileNames = (const char **) malloc(newTable->tableSize * sizeof(char*)); + + if(!newTable->fileNames) { + UTIL_freeFileNamesTable(newTable); + if(buf) free(buf); + UTIL_DISPLAYLEVEL(1, "[ERROR][UTIL_concatenateTwoTables] Can't create new table for concatenation output.\n"); + return NULL; + } + + for (i = 0; i < newTable->tableSize; ++i) + newTable->fileNames[i] = NULL; + + UTIL_DISPLAY("[TRACE] add table1 concatenation of size %zu\n", table1->tableSize); + size_t pos = 0; + for( ; idx1 < table1->tableSize && table1->fileNames[idx1] && pos < newTotalTableSize; ++idx1, ++newTableIdx) { + size_t curLen = strlen(table1->fileNames[idx1]); + memcpy(buf+pos, table1->fileNames[idx1], curLen); + newTable->fileNames[newTableIdx] = buf+pos; + pos += curLen+1; + } + + UTIL_DISPLAY("[TRACE] table1 actual size %u\n", idx1); + + UTIL_DISPLAY("[TRACE] add table2 concatenation of size %zu\n", table2->tableSize); + for( ; idx2 < table2->tableSize && table2->fileNames[idx2] && pos < newTotalTableSize ; ++idx2, ++newTableIdx) { + size_t curLen = strlen(table2->fileNames[idx2]); + memcpy(buf+pos, table2->fileNames[idx2], curLen); + newTable->fileNames[newTableIdx] = buf+pos; + pos += curLen+1; + } + + if(pos > newTotalTableSize) { + UTIL_freeFileNamesTable(newTable); + if(buf) free(buf); + return NULL; + } + + UTIL_DISPLAY("[TRACE] table2 actual size %u\n", idx2); + UTIL_DISPLAY("[TRACE] new table actual size %u\n", newTableIdx); + + assert(newTableIdx == newTable->tableSize || newTable->fileNames[newTableIdx] == NULL); + + UTIL_DISPLAY("[TRACE] table1:\n"); + for(idx1 = 0 ; idx1 < table1->tableSize && table1->fileNames[idx1] ; ++idx1) + UTIL_DISPLAY("[TRACE] %u %s\n", idx1, table1->fileNames[idx1]); + + UTIL_DISPLAY("[TRACE] table2:\n"); + for(idx2 = 0 ; idx2 < table2->tableSize && table2->fileNames[idx2] ; ++idx2) + UTIL_DISPLAY("[TRACE] %u %s\n", idx2, table2->fileNames[idx2]); + + UTIL_DISPLAY("[TRACE] new table:\n"); + for(newTableIdx = 0; newTableIdx < newTable->tableSize && newTable->fileNames[newTableIdx] ; ++newTableIdx) + UTIL_DISPLAY("[TRACE] %u %s\n", newTableIdx, newTable->fileNames[newTableIdx]); + + UTIL_freeFileNamesTable(table1); + UTIL_freeFileNamesTable(table2); + UTIL_DISPLAY("[TRACE] concatenation finished\n"); + + newTable->buf = buf; + return newTable; +} + #ifdef _WIN32 int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks) { diff --git a/programs/util.h b/programs/util.h index 0080b63c..33a6d6de 100644 --- a/programs/util.h +++ b/programs/util.h @@ -90,7 +90,7 @@ extern "C" { * Constants ***************************************/ #define LIST_SIZE_INCREASE (8*1024) - +#define MAX_FILE_OF_FILE_NAMES_SIZE (1<<20)*50 /*-**************************************** * Compiler specifics @@ -140,6 +140,40 @@ U32 UTIL_isLink(const char* infilename); U64 UTIL_getFileSize(const char* infilename); U64 UTIL_getTotalFileSize(const char* const * const fileNamesTable, unsigned nbFiles); +/*! UTIL_readLineFromFile(char* buf, size_t len, File* file): + * @return : int. size next line in file or -1 in case of file ends + * function reads next line in the file + * Will also modify `*file`, advancing it to position where it stopped reading. + */ +int UTIL_readLineFromFile(char* buf, size_t len, FILE* file); + +/*Note: tableSize is denotes the total capacity of table*/ +typedef struct +{ + const char** fileNames; + char* buf; + size_t tableSize; +} FileNamesTable; + +/*! UTIL_readFileNamesTableFromFile(const char* inputFileName) : + * @return : char** the fileNamesTable or NULL in case of not regular file or file doesn't exist. + * reads fileNamesTable from input fileName. + * Note: inputFileSize should be less than or equal 50MB + */ +FileNamesTable* UTIL_createFileNamesTable_fromFileName(const char* inputFileName); + +/*! UTIL_freeFileNamesTable(FileNamesTable* table) : + * This function takes an buffered based table and frees it. + * @return : void. + */ +void UTIL_freeFileNamesTable(FileNamesTable* table); + +/*! UTIL_concatenateTwoTables(FileNamesTable* table1,FileNamesTable* table2): + * takes table1, its maxSize, table2 and its maxSize, free them and returns its concatenation. + * @return : FileNamesTable* concatenation of two tables + * note table1 and table2 will be freed + */ +FileNamesTable* UTIL_concatenateTwoTables(FileNamesTable* table1, FileNamesTable* table2); /* * A modified version of realloc(). diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 98df728a..e8e17fff 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -565,6 +565,7 @@ int main(int argCount, const char* argv[]) nextArgumentIsMaxDict = 0, nextArgumentIsDictID = 0, nextArgumentsAreFiles = 0, + isTableBufferBased = 0, nextEntryIsDictionary = 0, operationResult = 0, separateFiles = 0, @@ -582,7 +583,9 @@ int main(int argCount, const char* argv[]) int cLevelLast = -1000000000; unsigned recursive = 0; unsigned memLimit = 0; - const char** filenameTable = (const char**)malloc(argCount * sizeof(const char*)); /* argCount >= 1 */ + unsigned filenameTableSize = argCount; + const char** filenameTable = (const char**)malloc(filenameTableSize * sizeof(const char*)); /* argCount >= 1 */ + char* tableBuf = NULL; unsigned filenameIdx = 0; const char* programName = argv[0]; const char* outFileName = NULL; @@ -791,6 +794,66 @@ int main(int argCount, const char* argv[]) continue; } #endif + + if (longCommandWArg(&argument, "--file=")) { + DISPLAYLEVEL(4, "[TRACE] argument catched\n"); + const char* fileName = argument; + DISPLAYLEVEL(4, "[TRACE] fileName: %s\n", fileName); + if(!UTIL_fileExist(fileName) || !UTIL_isRegularFile(fileName)){ + DISPLAYLEVEL(1, "[ERROR] wrong fileName: %s\n", fileName); + CLEAN_RETURN(badusage(programName)); + } + + DISPLAYLEVEL(4, "[TRACE] call read function\n"); + FileNamesTable* extendedTable = UTIL_createFileNamesTable_fromFileName(fileName); + if(!extendedTable) { + CLEAN_RETURN(badusage(programName)); + } + + DISPLAYLEVEL(4, "[TRACE] call read function is finished\n"); + DISPLAYLEVEL(4, "[TRACE] extendedFileNamesTable:\n"); + size_t extendedTableSize = extendedTable->tableSize; + const char ** extendedFileNamesTable = extendedTable->fileNames; + + int i = 0; + for(i = 0; i < extendedTableSize; ++i) + printf("%s\n",extendedFileNamesTable[i]); + + DISPLAYLEVEL(4, "[TRACE] call concatenation function\n"); + DISPLAYLEVEL(4, "[TRACE] filenameidx: %d\n", filenameIdx); + + for(i = filenameIdx; i < filenameTableSize ; ++i) + filenameTable[i] = NULL; + + FileNamesTable* curTable = (FileNamesTable*) malloc(sizeof(FileNamesTable)); + if(!curTable) { + UTIL_freeFileNamesTable(extendedTable); + CLEAN_RETURN(badusage(programName)); + } + + curTable->fileNames = filenameTable; + curTable->tableSize = filenameTableSize; + curTable->buf = tableBuf; + + FileNamesTable* concatenatedTables = UTIL_concatenateTwoTables(curTable, extendedTable); + if(!concatenatedTables) { + UTIL_freeFileNamesTable(curTable); + UTIL_freeFileNamesTable(extendedTable); + CLEAN_RETURN(badusage(programName)); + } + + filenameTable = concatenatedTables->fileNames; + filenameTableSize = concatenatedTables->tableSize; + tableBuf = concatenatedTables->buf; + + filenameIdx += extendedTableSize; + free(concatenatedTables); + isTableBufferBased = 1; + + DISPLAYLEVEL(1, "[TRACE] call concatenation function is finished\n"); + + continue; + } /* fall-through, will trigger bad_usage() later on */ } @@ -1193,6 +1256,13 @@ int main(int argCount, const char* argv[]) _end: FIO_freePreferences(prefs); + if(filenameTable) { + if(isTableBufferBased && tableBuf){ + free(tableBuf); + } + } + + if (main_pause) waitEnter(); #ifdef UTIL_HAS_CREATEFILELIST if (extendedFileList)