From c7bd6a41ab8ffef602884c8a9298bbba8faee0e2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 1 Oct 2018 14:04:00 -0700 Subject: [PATCH] zstd -d -f do no longer erase destination file when source file does not exist (#1082) --- programs/fileio.c | 138 +++++++++++++++++++++++++-------------------- tests/playTests.sh | 2 +- 2 files changed, 77 insertions(+), 63 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index e1903ce5..a2c4ded1 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1792,11 +1792,72 @@ static int FIO_decompressFrames(dRess_t ress, FILE* srcFile, return 0; } +/** FIO_decompressDstFile() : + open `dstFileName`, + or path-through if ress.dstFile is already != 0, + then start decompression process (FIO_decompressFrames()). + @return : 0 : OK + 1 : operation aborted +*/ +static int FIO_decompressDstFile(dRess_t ress, FILE* srcFile, + const char* dstFileName, const char* srcFileName) +{ + int result; + stat_t statbuf; + int transfer_permissions = 0; + int releaseDstFile = 0; + + if (ress.dstFile == NULL) { + releaseDstFile = 1; + + ress.dstFile = FIO_openDstFile(dstFileName); + if (ress.dstFile==0) return 1; + + /* Must only be added after FIO_openDstFile() succeeds. + * Otherwise we may delete the destination file if it already exists, + * and the user presses Ctrl-C when asked if they wish to overwrite. + */ + addHandler(dstFileName); + + if ( strcmp(srcFileName, stdinmark) /* special case : don't transfer permissions from stdin */ + && UTIL_getFileStat(srcFileName, &statbuf) ) + transfer_permissions = 1; + } + + + result = FIO_decompressFrames(ress, srcFile, dstFileName, srcFileName); + + if (releaseDstFile) { + FILE* const dstFile = ress.dstFile; + clearHandler(); + ress.dstFile = NULL; + if (fclose(dstFile)) { + DISPLAYLEVEL(1, "zstd: %s: %s \n", dstFileName, strerror(errno)); + result = 1; + } + + if ( (result != 0) /* operation failure */ + && strcmp(dstFileName, nulmark) /* special case : don't remove() /dev/null (#316) */ + && strcmp(dstFileName, stdoutmark) /* special case : don't remove() stdout */ + ) { + FIO_remove(dstFileName); /* remove decompression artefact; note: don't do anything special if remove() fails */ + } else { /* operation success */ + if ( strcmp(dstFileName, stdoutmark) /* special case : don't chmod stdout */ + && strcmp(dstFileName, nulmark) /* special case : don't chmod /dev/null */ + && transfer_permissions ) /* file permissions correctly extracted from src */ + UTIL_setFileStat(dstFileName, &statbuf); /* transfer file permissions from src into dst */ + } + signal(SIGINT, SIG_DFL); + } + + return result; +} + /** FIO_decompressSrcFile() : - Decompression `srcFileName` into `ress.dstFile` + Open `srcFileName`, transfer control to decompressDstFile() @return : 0 : OK - 1 : operation not started + 1 : error */ static int FIO_decompressSrcFile(dRess_t ress, const char* dstFileName, const char* srcFileName) { @@ -1812,15 +1873,15 @@ static int FIO_decompressSrcFile(dRess_t ress, const char* dstFileName, const ch if (srcFile==NULL) return 1; ress.srcBufferLoaded = 0; - result = FIO_decompressFrames(ress, srcFile, dstFileName, srcFileName); + result = FIO_decompressDstFile(ress, srcFile, dstFileName, srcFileName); /* Close file */ if (fclose(srcFile)) { DISPLAYLEVEL(1, "zstd: %s: %s \n", srcFileName, strerror(errno)); /* error should not happen */ return 1; } - if ( g_removeSrcFile /* --rm */ - && (result==0) /* decompression successful */ + if ( g_removeSrcFile /* --rm */ + && (result==0) /* decompression successful */ && strcmp(srcFileName, stdinmark) ) /* not stdin */ { /* We must clear the handler, since after this point calling it would * delete both the source and destination files. @@ -1835,60 +1896,13 @@ static int FIO_decompressSrcFile(dRess_t ress, const char* dstFileName, const ch } -/** FIO_decompressFile_extRess() : - decompress `srcFileName` into `dstFileName` - @return : 0 : OK - 1 : operation aborted (src not available, dst already taken, etc.) -*/ -static int FIO_decompressDstFile(dRess_t ress, - const char* dstFileName, const char* srcFileName) -{ - int result; - stat_t statbuf; - int stat_result = 0; - - ress.dstFile = FIO_openDstFile(dstFileName); - if (ress.dstFile==0) return 1; - /* Must ony be added after FIO_openDstFile() succeeds. - * Otherwise we may delete the destination file if at already exists, and - * the user presses Ctrl-C when asked if they wish to overwrite. - */ - addHandler(dstFileName); - - if ( strcmp(srcFileName, stdinmark) - && UTIL_getFileStat(srcFileName, &statbuf) ) - stat_result = 1; - result = FIO_decompressSrcFile(ress, dstFileName, srcFileName); - clearHandler(); - - if (fclose(ress.dstFile)) { - DISPLAYLEVEL(1, "zstd: %s: %s \n", dstFileName, strerror(errno)); - result = 1; - } - - if ( (result != 0) /* operation failure */ - && strcmp(dstFileName, nulmark) /* special case : don't remove() /dev/null (#316) */ - && strcmp(dstFileName, stdoutmark) ) /* special case : don't remove() stdout */ - FIO_remove(dstFileName); /* remove decompression artefact; note don't do anything special if remove() fails */ - else { /* operation success */ - if ( strcmp(dstFileName, stdoutmark) /* special case : don't chmod stdout */ - && strcmp(dstFileName, nulmark) /* special case : don't chmod /dev/null */ - && stat_result ) /* file permissions correctly extracted from src */ - UTIL_setFileStat(dstFileName, &statbuf); /* transfer file permissions from src into dst */ - } - - signal(SIGINT, SIG_DFL); - - return result; -} - int FIO_decompressFilename(const char* dstFileName, const char* srcFileName, const char* dictFileName) { dRess_t const ress = FIO_createDResources(dictFileName); - int const decodingError = FIO_decompressDstFile(ress, dstFileName, srcFileName); + int const decodingError = FIO_decompressSrcFile(ress, dstFileName, srcFileName); FIO_freeDResources(ress); return decodingError; @@ -1963,12 +1977,12 @@ FIO_determineDstName(const char* srcFileName) } -int FIO_decompressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles, - const char* outFileName, - const char* dictFileName) +int +FIO_decompressMultipleFilenames(const char* srcNamesTable[], unsigned nbFiles, + const char* outFileName, + const char* dictFileName) { - int skippedFiles = 0; - int missingFiles = 0; + int error = 0; dRess_t ress = FIO_createDResources(dictFileName); if (outFileName) { @@ -1976,7 +1990,7 @@ int FIO_decompressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles ress.dstFile = FIO_openDstFile(outFileName); if (ress.dstFile == 0) EXM_THROW(71, "cannot open %s", outFileName); for (u=0; u