From 1fb10ba831bc01cc19427be5eb02021cfa8d2dca Mon Sep 17 00:00:00 2001 From: "W. Felix Handte" Date: Mon, 8 Mar 2021 17:49:20 -0500 Subject: [PATCH] Don't Block Removing File on Being Able to Read It `open()`'s mode bits are only applied to files that are created by the call. If the output file already exists, but is not readable, the `fopen()` would fail, preventing us from removing it, which would mean that the file would not end up with the correct permission bits. It's not clear to me why the `fopen()` is there at all. `UTIL_isRegularFile()` should be sufficient, AFAICT. --- programs/fileio.c | 29 +++++++++++++---------------- tests/playTests.sh | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index a16315306..790c10b87 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -669,7 +669,6 @@ FIO_openDstFile(FIO_ctx_t* fCtx, FIO_prefs_t* const prefs, if (UTIL_isRegularFile(dstFileName)) { /* Check if destination file already exists */ - FILE* const fCheck = fopen( dstFileName, "rb" ); #if !defined(_WIN32) /* this test does not work on Windows : * `NUL` and `nul` are detected as regular files */ @@ -678,22 +677,20 @@ FIO_openDstFile(FIO_ctx_t* fCtx, FIO_prefs_t* const prefs, dstFileName); } #endif - if (fCheck != NULL) { /* dst file exists, authorization prompt */ - fclose(fCheck); - if (!prefs->overwrite) { - if (g_display_prefs.displayLevel <= 1) { - /* No interaction possible */ - DISPLAY("zstd: %s already exists; not overwritten \n", - dstFileName); - return NULL; - } - DISPLAY("zstd: %s already exists; ", dstFileName); - if (UTIL_requireUserConfirmation("overwrite (y/n) ? ", "Not overwritten \n", "yY", fCtx->hasStdinInput)) - return NULL; + if (!prefs->overwrite) { + if (g_display_prefs.displayLevel <= 1) { + /* No interaction possible */ + DISPLAY("zstd: %s already exists; not overwritten \n", + dstFileName); + return NULL; } - /* need to unlink */ - FIO_removeFile(dstFileName); - } } + DISPLAY("zstd: %s already exists; ", dstFileName); + if (UTIL_requireUserConfirmation("overwrite (y/n) ? ", "Not overwritten \n", "yY", fCtx->hasStdinInput)) + return NULL; + } + /* need to unlink */ + FIO_removeFile(dstFileName); + } { const int fd = open(dstFileName, O_WRONLY|O_CREAT|O_TRUNC, mode); FILE* f = NULL; diff --git a/tests/playTests.sh b/tests/playTests.sh index 358b6b512..869b4445e 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -513,6 +513,21 @@ if [ "$isWindows" = false ] ; then rm -f tmp1.zst tmp2.zst tmp1.out tmp2.out + println "test : check permissions on pre-existing output file in compression " + chmod 0600 tmp1 + touch tmp1.zst + chmod 0400 tmp1.zst + zstd -f tmp1 -o tmp1.zst + assertFilePermissions tmp1.zst 600 + println "test : check permissions on pre-existing output file in decompression " + chmod 0400 tmp1.zst + touch tmp1.out + chmod 0200 tmp1.out + zstd -f -d tmp1.zst -o tmp1.out + assertFilePermissions tmp1.out 400 + + rm -f tmp1.zst tmp1.out + umask 0666 chmod 0666 tmp1 tmp2 -- 2.47.2