]> git.ipfire.org Git - thirdparty/zstd.git/commitdiff
[zstdcli] Refuse to overwrite input file
authorNick Terrell <terrelln@fb.com>
Tue, 18 Dec 2018 23:29:54 +0000 (15:29 -0800)
committerNick Terrell <terrelln@fb.com>
Tue, 18 Dec 2018 23:29:54 +0000 (15:29 -0800)
Compare the input and output files by their inode number and
refuse to open the output file if the input file is the same.

This doesn't work when (de)compressing multiple files to a single
file, but that is a very uncommon use case, mostly used for
benchmarking by me.

Fixes #1422.

programs/fileio.c
tests/playTests.sh

index 5016294f81131999177c666376ad234b25236e11..c415ea67efb622f4025338e188bc6b60307cbf39 100644 (file)
@@ -404,7 +404,7 @@ static FILE* FIO_openSrcFile(const char* srcFileName)
 /** FIO_openDstFile() :
  *  condition : `dstFileName` must be non-NULL.
  * @result : FILE* to `dstFileName`, or NULL if it fails */
-static FILE* FIO_openDstFile(const char* dstFileName)
+static FILE* FIO_openDstFile(const char* srcFileName, const char* dstFileName)
 {
     assert(dstFileName != NULL);
     if (!strcmp (dstFileName, stdoutmark)) {
@@ -416,6 +416,16 @@ static FILE* FIO_openDstFile(const char* dstFileName)
         }
         return stdout;
     }
+    if (srcFileName != NULL) {
+        stat_t srcStat;
+        stat_t dstStat;
+        if (UTIL_getFileStat(srcFileName, &srcStat) && UTIL_getFileStat(dstFileName, &dstStat)) {
+            if (srcStat.st_ino == dstStat.st_ino) {
+                DISPLAYLEVEL(1, "zstd: Refusing to open a output file which will overwrite the input file \n");
+                return NULL;
+            }
+        }
+    }
 
     if (g_sparseFileSupport == 1) {
         g_sparseFileSupport = ZSTD_SPARSE_DEFAULT;
@@ -1114,7 +1124,7 @@ static int FIO_compressFilename_dstFile(cRess_t ress,
     if (ress.dstFile == NULL) {
         closeDstFile = 1;
         DISPLAYLEVEL(6, "FIO_compressFilename_dstFile: opening dst: %s", dstFileName);
-        ress.dstFile = FIO_openDstFile(dstFileName);
+        ress.dstFile = FIO_openDstFile(srcFileName, dstFileName);
         if (ress.dstFile==NULL) return 1;  /* could not open dstFileName */
         /* Must only be added after FIO_openDstFile() succeeds.
          * Otherwise we may delete the destination file if it already exists,
@@ -1264,7 +1274,7 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile
     assert(outFileName != NULL || suffix != NULL);
 
     if (outFileName != NULL) {   /* output into a single destination (stdout typically) */
-        ress.dstFile = FIO_openDstFile(outFileName);
+        ress.dstFile = FIO_openDstFile(NULL, outFileName);
         if (ress.dstFile == NULL) {  /* could not open outFileName */
             error = 1;
         } else {
@@ -1880,7 +1890,7 @@ static int FIO_decompressDstFile(dRess_t ress, FILE* srcFile,
     if (ress.dstFile == NULL) {
         releaseDstFile = 1;
 
-        ress.dstFile = FIO_openDstFile(dstFileName);
+        ress.dstFile = FIO_openDstFile(srcFileName, dstFileName);
         if (ress.dstFile==0) return 1;
 
         /* Must only be added after FIO_openDstFile() succeeds.
@@ -2057,7 +2067,7 @@ FIO_decompressMultipleFilenames(const char* srcNamesTable[], unsigned nbFiles,
 
     if (outFileName) {
         unsigned u;
-        ress.dstFile = FIO_openDstFile(outFileName);
+        ress.dstFile = FIO_openDstFile(NULL, outFileName);
         if (ress.dstFile == 0) EXM_THROW(71, "cannot open %s", outFileName);
         for (u=0; u<nbFiles; u++)
             error |= FIO_decompressSrcFile(ress, outFileName, srcNamesTable[u]);
index 7758f46e938230e9d085a4a33df9f1ff606e2ba3..b861391eb8e64ae0aee0c2592dec2d56d3ce6129 100755 (executable)
@@ -183,6 +183,9 @@ $ECHO "test: --no-progress flag"
 $ZSTD tmpro -c --no-progress | $ZSTD -d -o "$INTOVOID" --no-progress
 $ZSTD tmpro -cv --no-progress | $ZSTD -dv -o "$INTOVOID" --no-progress
 rm -f tmpro tmpro.zst
+$ECHO "test: overwrite input file (must fail)"
+$ZSTD tmp -fo tmp && die "zstd overwrote the input file"
+$ZSTD tmp.zst -dfo tmp.zst && die "zstd overwrote the input file"
 
 
 $ECHO "test : file removal"