From 0382076af716e78f86a764475eece59a8eeb6272 Mon Sep 17 00:00:00 2001 From: "W. Felix Handte" Date: Tue, 17 Jan 2023 14:50:31 -0800 Subject: [PATCH] Re-Use `stat_t` in `FIO_compressFilename_srcFile()` --- programs/fileio.c | 40 +++++++++++-------- programs/util.c | 36 +++++++++++++++-- programs/util.h | 1 + .../compress-file-to-file.sh.stderr.exact | 6 +-- .../compress-file-to-stdout.sh.stderr.exact | 6 +-- .../compress-stdin-to-file.sh.stderr.exact | 4 -- .../compress-stdin-to-stdout.sh.stderr.exact | 4 -- .../decompress-file-to-file.sh.stderr.exact | 2 + .../decompress-file-to-stdout.sh.stderr.exact | 2 + 9 files changed, 67 insertions(+), 34 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 2067cfcda..0e1345596 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -662,23 +662,23 @@ FIO_openDstFile(FIO_ctx_t* fCtx, FIO_prefs_t* const prefs, * @return : loaded size * if fileName==NULL, returns 0 and a NULL pointer */ -static size_t FIO_createDictBuffer(void** bufferPtr, const char* fileName, FIO_prefs_t* const prefs) +static size_t FIO_createDictBuffer(void** bufferPtr, const char* fileName, FIO_prefs_t* const prefs, stat_t* dictFileStat) { FILE* fileHandle; U64 fileSize; - stat_t statbuf; assert(bufferPtr != NULL); + assert(dictFileStat != NULL); *bufferPtr = NULL; if (fileName == NULL) return 0; DISPLAYLEVEL(4,"Loading %s as dictionary \n", fileName); - if (!UTIL_stat(fileName, &statbuf)) { + if (!UTIL_stat(fileName, dictFileStat)) { EXM_THROW(31, "Stat failed on dictionary file %s: %s", fileName, strerror(errno)); } - if (!UTIL_isRegularFileStat(&statbuf)) { + if (!UTIL_isRegularFileStat(dictFileStat)) { EXM_THROW(32, "Dictionary %s must be a regular file.", fileName); } @@ -688,7 +688,7 @@ static size_t FIO_createDictBuffer(void** bufferPtr, const char* fileName, FIO_p EXM_THROW(33, "Couldn't open dictionary %s: %s", fileName, strerror(errno)); } - fileSize = UTIL_getFileSizeStat(&statbuf); + fileSize = UTIL_getFileSizeStat(dictFileStat); { size_t const dictSizeMax = prefs->patchFromMode ? prefs->memLimit : DICTSIZE_MAX; if (fileSize > dictSizeMax) { @@ -869,6 +869,7 @@ typedef struct { void* dictBuffer; size_t dictBufferSize; const char* dictFileName; + stat_t dictFileStat; ZSTD_CStream* cctx; WritePoolCtx_t *writeCtx; ReadPoolCtx_t *readCtx; @@ -927,7 +928,7 @@ static cRess_t FIO_createCResources(FIO_prefs_t* const prefs, unsigned long long const ssSize = (unsigned long long)prefs->streamSrcSize; FIO_adjustParamsForPatchFromMode(prefs, &comprParams, UTIL_getFileSize(dictFileName), ssSize > 0 ? ssSize : maxSrcFileSize, cLevel); } - ress.dictBufferSize = FIO_createDictBuffer(&ress.dictBuffer, dictFileName, prefs); /* works with dictFileName==NULL */ + ress.dictBufferSize = FIO_createDictBuffer(&ress.dictBuffer, dictFileName, prefs, &ress.dictFileStat); /* works with dictFileName==NULL */ ress.writeCtx = AIO_WritePool_create(prefs, ZSTD_CStreamOutSize()); ress.readCtx = AIO_ReadPool_create(prefs, ZSTD_CStreamInSize()); @@ -1712,16 +1713,22 @@ FIO_compressFilename_srcFile(FIO_ctx_t* const fCtx, stat_t srcFileStat; DISPLAYLEVEL(6, "FIO_compressFilename_srcFile: %s \n", srcFileName); - /* ensure src is not a directory */ - if (UTIL_isDirectory(srcFileName)) { - DISPLAYLEVEL(1, "zstd: %s is a directory -- ignored \n", srcFileName); - return 1; - } + if (strcmp(srcFileName, stdinmark)) { + if (UTIL_stat(srcFileName, &srcFileStat)) { + /* failure to stat at all is handled during opening */ - /* ensure src is not the same as dict (if present) */ - if (ress.dictFileName != NULL && UTIL_isSameFile(srcFileName, ress.dictFileName)) { - DISPLAYLEVEL(1, "zstd: cannot use %s as an input file and dictionary \n", srcFileName); - return 1; + /* ensure src is not a directory */ + if (UTIL_isDirectoryStat(&srcFileStat)) { + DISPLAYLEVEL(1, "zstd: %s is a directory -- ignored \n", srcFileName); + return 1; + } + + /* ensure src is not the same as dict (if present) */ + if (ress.dictFileName != NULL && UTIL_isSameFileStat(srcFileName, ress.dictFileName, &srcFileStat, &ress.dictFileStat)) { + DISPLAYLEVEL(1, "zstd: cannot use %s as an input file and dictionary \n", srcFileName); + return 1; + } + } } /* Check if "srcFile" is compressed. Only done if --exclude-compressed flag is used @@ -1998,7 +2005,8 @@ static dRess_t FIO_createDResources(FIO_prefs_t* const prefs, const char* dictFi /* dictionary */ { void* dictBuffer; - size_t const dictBufferSize = FIO_createDictBuffer(&dictBuffer, dictFileName, prefs); + stat_t statbuf; + size_t const dictBufferSize = FIO_createDictBuffer(&dictBuffer, dictFileName, prefs, &statbuf); CHECK( ZSTD_DCtx_reset(ress.dctx, ZSTD_reset_session_only) ); CHECK( ZSTD_DCtx_loadDictionary(ress.dctx, dictBuffer, dictBufferSize) ); free(dictBuffer); diff --git a/programs/util.c b/programs/util.c index 21d7d3b46..7402b75d2 100644 --- a/programs/util.c +++ b/programs/util.c @@ -272,11 +272,15 @@ int UTIL_isDirectory(const char* infilename) int UTIL_isDirectoryStat(const stat_t* statbuf) { + int ret; + UTIL_TRACE_CALL("UTIL_isDirectoryStat()"); #if defined(_MSC_VER) - return (statbuf->st_mode & _S_IFDIR) != 0; + ret = (statbuf->st_mode & _S_IFDIR) != 0; #else - return S_ISDIR(statbuf->st_mode) != 0; + ret = S_ISDIR(statbuf->st_mode) != 0; #endif + UTIL_TRACE_RET(ret); + return ret; } int UTIL_compareStr(const void *p1, const void *p2) { @@ -299,8 +303,32 @@ int UTIL_isSameFile(const char* fName1, const char* fName2) stat_t file2Stat; ret = UTIL_stat(fName1, &file1Stat) && UTIL_stat(fName2, &file2Stat) - && (file1Stat.st_dev == file2Stat.st_dev) - && (file1Stat.st_ino == file2Stat.st_ino); + && UTIL_isSameFileStat(fName1, fName2, &file1Stat, &file2Stat); + } +#endif + UTIL_TRACE_RET(ret); + return ret; +} + +int UTIL_isSameFileStat( + const char* fName1, const char* fName2, + const stat_t* file1Stat, const stat_t* file2Stat) +{ + int ret; + assert(fName1 != NULL); assert(fName2 != NULL); + UTIL_TRACE_CALL("UTIL_isSameFileStat(%s, %s)", fName1, fName2); +#if defined(_MSC_VER) || defined(_WIN32) + /* note : Visual does not support file identification by inode. + * inode does not work on Windows, even with a posix layer, like msys2. + * The following work-around is limited to detecting exact name repetition only, + * aka `filename` is considered different from `subdir/../filename` */ + (void)file1Stat; + (void)file2Stat; + ret = !strcmp(fName1, fName2); +#else + { + ret = (file1Stat->st_dev == file2Stat->st_dev) + && (file1Stat->st_ino == file2Stat->st_ino); } #endif UTIL_TRACE_RET(ret); diff --git a/programs/util.h b/programs/util.h index 88ee1bad1..4ec54137d 100644 --- a/programs/util.h +++ b/programs/util.h @@ -171,6 +171,7 @@ int UTIL_chmod(char const* filename, const stat_t* statbuf, mode_t permissions); int UTIL_isRegularFile(const char* infilename); int UTIL_isDirectory(const char* infilename); int UTIL_isSameFile(const char* file1, const char* file2); +int UTIL_isSameFileStat(const char* file1, const char* file2, const stat_t* file1Stat, const stat_t* file2Stat); int UTIL_isCompressedFile(const char* infilename, const char *extensionList[]); int UTIL_isLink(const char* infilename); int UTIL_isFIFO(const char* infilename); diff --git a/tests/cli-tests/file-stat/compress-file-to-file.sh.stderr.exact b/tests/cli-tests/file-stat/compress-file-to-file.sh.stderr.exact index 7297894c7..873233633 100644 --- a/tests/cli-tests/file-stat/compress-file-to-file.sh.stderr.exact +++ b/tests/cli-tests/file-stat/compress-file-to-file.sh.stderr.exact @@ -6,9 +6,9 @@ Trace:FileStat: > UTIL_getFileSize(file) Trace:FileStat: > UTIL_stat(file) Trace:FileStat: < 1 Trace:FileStat: < 65537 -Trace:FileStat: > UTIL_isDirectory(file) -Trace:FileStat: > UTIL_stat(file) -Trace:FileStat: < 1 +Trace:FileStat: > UTIL_stat(file) +Trace:FileStat: < 1 +Trace:FileStat: > UTIL_isDirectoryStat() Trace:FileStat: < 0 Trace:FileStat: > UTIL_stat(file) Trace:FileStat: < 1 diff --git a/tests/cli-tests/file-stat/compress-file-to-stdout.sh.stderr.exact b/tests/cli-tests/file-stat/compress-file-to-stdout.sh.stderr.exact index e01922f84..e86c4eae3 100644 --- a/tests/cli-tests/file-stat/compress-file-to-stdout.sh.stderr.exact +++ b/tests/cli-tests/file-stat/compress-file-to-stdout.sh.stderr.exact @@ -6,9 +6,9 @@ Trace:FileStat: > UTIL_getFileSize(file) Trace:FileStat: > UTIL_stat(file) Trace:FileStat: < 1 Trace:FileStat: < 65537 -Trace:FileStat: > UTIL_isDirectory(file) -Trace:FileStat: > UTIL_stat(file) -Trace:FileStat: < 1 +Trace:FileStat: > UTIL_stat(file) +Trace:FileStat: < 1 +Trace:FileStat: > UTIL_isDirectoryStat() Trace:FileStat: < 0 Trace:FileStat: > UTIL_stat(file) Trace:FileStat: < 1 diff --git a/tests/cli-tests/file-stat/compress-stdin-to-file.sh.stderr.exact b/tests/cli-tests/file-stat/compress-stdin-to-file.sh.stderr.exact index dce9005f4..00afd97c3 100644 --- a/tests/cli-tests/file-stat/compress-stdin-to-file.sh.stderr.exact +++ b/tests/cli-tests/file-stat/compress-stdin-to-file.sh.stderr.exact @@ -6,10 +6,6 @@ Trace:FileStat: > UTIL_getFileSize(/*stdin*\) Trace:FileStat: > UTIL_stat(/*stdin*\) Trace:FileStat: < 0 Trace:FileStat: < -1 -Trace:FileStat: > UTIL_isDirectory(/*stdin*\) -Trace:FileStat: > UTIL_stat(/*stdin*\) -Trace:FileStat: < 0 -Trace:FileStat: < 0 Trace:FileStat: > UTIL_isSameFile(/*stdin*\, file.zst) Trace:FileStat: > UTIL_stat(/*stdin*\) Trace:FileStat: < 0 diff --git a/tests/cli-tests/file-stat/compress-stdin-to-stdout.sh.stderr.exact b/tests/cli-tests/file-stat/compress-stdin-to-stdout.sh.stderr.exact index d47bdcf09..2e44511d8 100644 --- a/tests/cli-tests/file-stat/compress-stdin-to-stdout.sh.stderr.exact +++ b/tests/cli-tests/file-stat/compress-stdin-to-stdout.sh.stderr.exact @@ -6,10 +6,6 @@ Trace:FileStat: > UTIL_getFileSize(/*stdin*\) Trace:FileStat: > UTIL_stat(/*stdin*\) Trace:FileStat: < 0 Trace:FileStat: < -1 -Trace:FileStat: > UTIL_isDirectory(/*stdin*\) -Trace:FileStat: > UTIL_stat(/*stdin*\) -Trace:FileStat: < 0 -Trace:FileStat: < 0 Trace:FileStat: > UTIL_isRegularFile(/*stdout*\) Trace:FileStat: > UTIL_stat(/*stdout*\) Trace:FileStat: < 0 diff --git a/tests/cli-tests/file-stat/decompress-file-to-file.sh.stderr.exact b/tests/cli-tests/file-stat/decompress-file-to-file.sh.stderr.exact index 2af60eb43..53c3333eb 100644 --- a/tests/cli-tests/file-stat/decompress-file-to-file.sh.stderr.exact +++ b/tests/cli-tests/file-stat/decompress-file-to-file.sh.stderr.exact @@ -7,6 +7,8 @@ Trace:FileStat: < 0 Trace:FileStat: > UTIL_isDirectory(file.zst) Trace:FileStat: > UTIL_stat(file.zst) Trace:FileStat: < 1 +Trace:FileStat: > UTIL_isDirectoryStat() +Trace:FileStat: < 0 Trace:FileStat: < 0 Trace:FileStat: > UTIL_stat(file.zst) Trace:FileStat: < 1 diff --git a/tests/cli-tests/file-stat/decompress-file-to-stdout.sh.stderr.exact b/tests/cli-tests/file-stat/decompress-file-to-stdout.sh.stderr.exact index 87fc5e97c..bbf66506b 100644 --- a/tests/cli-tests/file-stat/decompress-file-to-stdout.sh.stderr.exact +++ b/tests/cli-tests/file-stat/decompress-file-to-stdout.sh.stderr.exact @@ -5,6 +5,8 @@ Trace:FileStat: < 0 Trace:FileStat: > UTIL_isDirectory(file.zst) Trace:FileStat: > UTIL_stat(file.zst) Trace:FileStat: < 1 +Trace:FileStat: > UTIL_isDirectoryStat() +Trace:FileStat: < 0 Trace:FileStat: < 0 Trace:FileStat: > UTIL_stat(file.zst) Trace:FileStat: < 1