From 3bd5aa34046ef02ed0e8e04aa5e464a5a10bb042 Mon Sep 17 00:00:00 2001 From: Li-Yu Yu Date: Fri, 28 Mar 2025 21:16:29 +0000 Subject: [PATCH 1/2] Check regular file for sparse support after opening A regular file may be created by the open call. Checking after opening allows sparseFileSupport even if dstFileName does not already exist. --- programs/fileio.c | 23 +++++++++++------------ programs/util.c | 10 ++++++++++ programs/util.h | 1 + 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index dc7636949..b1303a2ad 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -585,8 +585,6 @@ FIO_openDstFile(FIO_ctx_t* fCtx, FIO_prefs_t* const prefs, const char* srcFileName, const char* dstFileName, const int mode) { - int isDstRegFile; - if (prefs->testMode) return NULL; /* do not open file in test mode */ assert(dstFileName != NULL); @@ -606,16 +604,7 @@ FIO_openDstFile(FIO_ctx_t* fCtx, FIO_prefs_t* const prefs, return NULL; } - isDstRegFile = UTIL_isRegularFile(dstFileName); /* invoke once */ - if (prefs->sparseFileSupport == 1) { - prefs->sparseFileSupport = ZSTD_SPARSE_DEFAULT; - if (!isDstRegFile) { - prefs->sparseFileSupport = 0; - DISPLAYLEVEL(4, "Sparse File Support is disabled when output is not a file \n"); - } - } - - if (isDstRegFile) { + if (UTIL_isRegularFile(dstFileName)) { /* Check if destination file already exists */ #if !defined(_WIN32) /* this test does not work on Windows : @@ -658,6 +647,16 @@ FIO_openDstFile(FIO_ctx_t* fCtx, FIO_prefs_t* const prefs, f = fdopen(fd, "wb"); } #endif + + if (prefs->sparseFileSupport == 1) { + prefs->sparseFileSupport = ZSTD_SPARSE_DEFAULT; + /* Check regular file after opening with O_CREAT */ + if (!UTIL_isFdRegularFile(fd)) { + prefs->sparseFileSupport = 0; + DISPLAYLEVEL(4, "Sparse File Support is disabled when output is not a file \n"); + } + } + if (f == NULL) { if (UTIL_isFileDescriptorPipe(dstFileName)) { DISPLAYLEVEL(1, "zstd: error: no output specified (use -o or -c). \n"); diff --git a/programs/util.c b/programs/util.c index 94c40cc95..850bcacd2 100644 --- a/programs/util.c +++ b/programs/util.c @@ -197,6 +197,16 @@ int UTIL_stat(const char* filename, stat_t* statbuf) return UTIL_fstat(-1, filename, statbuf); } +int UTIL_isFdRegularFile(int fd) +{ + stat_t statbuf; + int ret; + UTIL_TRACE_CALL("UTIL_isFdRegularFile(%d)", fd); + ret = UTIL_fstat(fd, "", &statbuf) && UTIL_isRegularFileStat(&statbuf); + UTIL_TRACE_RET(ret); + return ret; +} + int UTIL_isRegularFile(const char* infilename) { stat_t statbuf; diff --git a/programs/util.h b/programs/util.h index 427bcf441..65e12633a 100644 --- a/programs/util.h +++ b/programs/util.h @@ -184,6 +184,7 @@ int UTIL_fchmod(const int fd, char const* filename, const stat_t* statbuf, mode_ * compute the needed information. */ +int UTIL_isFdRegularFile(int fd); int UTIL_isRegularFile(const char* infilename); int UTIL_isDirectory(const char* infilename); int UTIL_isSameFile(const char* file1, const char* file2); From 2a12bbaf909136ea28f2206441a10b0837c60325 Mon Sep 17 00:00:00 2001 From: Li-Yu Yu Date: Fri, 28 Mar 2025 21:45:47 +0000 Subject: [PATCH 2/2] Update cli-tests/file-stat tests --- programs/fileio.c | 6 ++++-- programs/util.c | 2 +- .../compress-file-to-dir-without-write-perm.sh.stderr.exact | 2 ++ ...sh.stderr.exact => compress-file-to-file.sh.stderr.glob} | 4 ++++ ...h.stderr.exact => compress-stdin-to-file.sh.stderr.glob} | 4 ++++ ....stderr.exact => decompress-file-to-file.sh.stderr.glob} | 4 ++++ ...stderr.exact => decompress-stdin-to-file.sh.stderr.glob} | 4 ++++ 7 files changed, 23 insertions(+), 3 deletions(-) rename tests/cli-tests/file-stat/{compress-file-to-file.sh.stderr.exact => compress-file-to-file.sh.stderr.glob} (91%) rename tests/cli-tests/file-stat/{compress-stdin-to-file.sh.stderr.exact => compress-stdin-to-file.sh.stderr.glob} (86%) rename tests/cli-tests/file-stat/{decompress-file-to-file.sh.stderr.exact => decompress-file-to-file.sh.stderr.glob} (90%) rename tests/cli-tests/file-stat/{decompress-stdin-to-file.sh.stderr.exact => decompress-stdin-to-file.sh.stderr.glob} (84%) diff --git a/programs/fileio.c b/programs/fileio.c index b1303a2ad..77f3d35f9 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -630,6 +630,7 @@ FIO_openDstFile(FIO_ctx_t* fCtx, FIO_prefs_t* const prefs, } { + int isDstRegFile; #if defined(_WIN32) /* Windows requires opening the file as a "binary" file to avoid * mangling. This macro doesn't exist on unix. */ @@ -648,10 +649,11 @@ FIO_openDstFile(FIO_ctx_t* fCtx, FIO_prefs_t* const prefs, } #endif + /* Check regular file after opening with O_CREAT */ + isDstRegFile = UTIL_isFdRegularFile(fd); if (prefs->sparseFileSupport == 1) { prefs->sparseFileSupport = ZSTD_SPARSE_DEFAULT; - /* Check regular file after opening with O_CREAT */ - if (!UTIL_isFdRegularFile(fd)) { + if (!isDstRegFile) { prefs->sparseFileSupport = 0; DISPLAYLEVEL(4, "Sparse File Support is disabled when output is not a file \n"); } diff --git a/programs/util.c b/programs/util.c index 850bcacd2..d11f13cfd 100644 --- a/programs/util.c +++ b/programs/util.c @@ -202,7 +202,7 @@ int UTIL_isFdRegularFile(int fd) stat_t statbuf; int ret; UTIL_TRACE_CALL("UTIL_isFdRegularFile(%d)", fd); - ret = UTIL_fstat(fd, "", &statbuf) && UTIL_isRegularFileStat(&statbuf); + ret = fd >= 0 && UTIL_fstat(fd, "", &statbuf) && UTIL_isRegularFileStat(&statbuf); UTIL_TRACE_RET(ret); return ret; } diff --git a/tests/cli-tests/file-stat/compress-file-to-dir-without-write-perm.sh.stderr.exact b/tests/cli-tests/file-stat/compress-file-to-dir-without-write-perm.sh.stderr.exact index 9f254f8c2..05d91ffc9 100644 --- a/tests/cli-tests/file-stat/compress-file-to-dir-without-write-perm.sh.stderr.exact +++ b/tests/cli-tests/file-stat/compress-file-to-dir-without-write-perm.sh.stderr.exact @@ -22,6 +22,8 @@ Trace:FileStat: > UTIL_isRegularFile(out/file.zst) Trace:FileStat: > UTIL_stat(-1, out/file.zst) Trace:FileStat: < 0 Trace:FileStat: < 0 +Trace:FileStat: > UTIL_isFdRegularFile(-1) +Trace:FileStat: < 0 Trace:FileStat: > UTIL_isFileDescriptorPipe(out/file.zst) Trace:FileStat: < 0 zstd: out/file.zst: Permission denied 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.glob similarity index 91% rename from tests/cli-tests/file-stat/compress-file-to-file.sh.stderr.exact rename to tests/cli-tests/file-stat/compress-file-to-file.sh.stderr.glob index 32d248ee5..17a677deb 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.glob @@ -22,6 +22,10 @@ Trace:FileStat: > UTIL_isRegularFile(file.zst) Trace:FileStat: > UTIL_stat(-1, file.zst) Trace:FileStat: < 0 Trace:FileStat: < 0 +Trace:FileStat: > UTIL_isFdRegularFile(*) +Trace:FileStat: > UTIL_stat(*, ) +Trace:FileStat: < 1 +Trace:FileStat: < 1 Trace:FileStat: > UTIL_isRegularFile(file.zst) Trace:FileStat: > UTIL_stat(-1, file.zst) 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.glob similarity index 86% rename from tests/cli-tests/file-stat/compress-stdin-to-file.sh.stderr.exact rename to tests/cli-tests/file-stat/compress-stdin-to-file.sh.stderr.glob index 9183c4674..38732cbe9 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.glob @@ -14,6 +14,10 @@ Trace:FileStat: > UTIL_isRegularFile(file.zst) Trace:FileStat: > UTIL_stat(-1, file.zst) Trace:FileStat: < 0 Trace:FileStat: < 0 +Trace:FileStat: > UTIL_isFdRegularFile(*) +Trace:FileStat: > UTIL_stat(*, ) +Trace:FileStat: < 1 +Trace:FileStat: < 1 Trace:FileStat: > UTIL_isRegularFile(file.zst) Trace:FileStat: > UTIL_stat(-1, file.zst) Trace:FileStat: < 1 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.glob similarity index 90% rename from tests/cli-tests/file-stat/decompress-file-to-file.sh.stderr.exact rename to tests/cli-tests/file-stat/decompress-file-to-file.sh.stderr.glob index ad3a0deb8..ce194dfb3 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.glob @@ -22,6 +22,10 @@ Trace:FileStat: > UTIL_isRegularFile(file) Trace:FileStat: > UTIL_stat(-1, file) Trace:FileStat: < 0 Trace:FileStat: < 0 +Trace:FileStat: > UTIL_isFdRegularFile(*) +Trace:FileStat: > UTIL_stat(*, ) +Trace:FileStat: < 1 +Trace:FileStat: < 1 Trace:FileStat: > UTIL_isRegularFile(file) Trace:FileStat: > UTIL_stat(-1, file) Trace:FileStat: < 1 diff --git a/tests/cli-tests/file-stat/decompress-stdin-to-file.sh.stderr.exact b/tests/cli-tests/file-stat/decompress-stdin-to-file.sh.stderr.glob similarity index 84% rename from tests/cli-tests/file-stat/decompress-stdin-to-file.sh.stderr.exact rename to tests/cli-tests/file-stat/decompress-stdin-to-file.sh.stderr.glob index 716a7ac7b..9eb920883 100644 --- a/tests/cli-tests/file-stat/decompress-stdin-to-file.sh.stderr.exact +++ b/tests/cli-tests/file-stat/decompress-stdin-to-file.sh.stderr.glob @@ -14,6 +14,10 @@ Trace:FileStat: > UTIL_isRegularFile(file) Trace:FileStat: > UTIL_stat(-1, file) Trace:FileStat: < 0 Trace:FileStat: < 0 +Trace:FileStat: > UTIL_isFdRegularFile(*) +Trace:FileStat: > UTIL_stat(*, ) +Trace:FileStat: < 1 +Trace:FileStat: < 1 Trace:FileStat: > UTIL_isRegularFile(file) Trace:FileStat: > UTIL_stat(-1, file) Trace:FileStat: < 1