Ignore symbolic links unless --force specified

This commit is contained in:
Sean Purcell
2017-03-23 11:52:09 -07:00
parent 042ba122ae
commit 680e4e0953
6 changed files with 66 additions and 17 deletions
+32 -9
View File
@@ -1,6 +1,6 @@
/** /**
* util.h - utility functions * util.h - utility functions
* *
* Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
* All rights reserved. * All rights reserved.
* *
@@ -228,6 +228,20 @@ UTIL_STATIC U32 UTIL_isDirectory(const char* infilename)
return 0; return 0;
} }
UTIL_STATIC U32 UTIL_isLink(const char* infilename)
{
#if defined(_WIN32)
/* no symlinks on windows */
(void)infilename;
#else
int r;
stat_t statbuf;
r = lstat(infilename, &statbuf);
if (!r && S_ISLNK(statbuf.st_mode)) return 1;
#endif
return 0;
}
UTIL_STATIC U64 UTIL_getFileSize(const char* infilename) UTIL_STATIC U64 UTIL_getFileSize(const char* infilename)
{ {
@@ -271,11 +285,10 @@ UTIL_STATIC void *UTIL_realloc(void *ptr, size_t size)
return NULL; return NULL;
} }
#ifdef _WIN32 #ifdef _WIN32
# define UTIL_HAS_CREATEFILELIST # define UTIL_HAS_CREATEFILELIST
UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd) UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks)
{ {
char* path; char* path;
int dirLength, fnameLength, pathLength, nbFiles = 0; int dirLength, fnameLength, pathLength, nbFiles = 0;
@@ -311,7 +324,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_
if (strcmp (cFile.cFileName, "..") == 0 || if (strcmp (cFile.cFileName, "..") == 0 ||
strcmp (cFile.cFileName, ".") == 0) continue; strcmp (cFile.cFileName, ".") == 0) continue;
nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd); /* Recursively call "UTIL_prepareFileList" with the new path. */ nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd, followLinks); /* Recursively call "UTIL_prepareFileList" with the new path. */
if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; } if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; }
} }
else if ((cFile.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || (cFile.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) || (cFile.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED)) { else if ((cFile.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || (cFile.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) || (cFile.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED)) {
@@ -339,7 +352,11 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_
# include <dirent.h> /* opendir, readdir */ # include <dirent.h> /* opendir, readdir */
# include <string.h> /* strerror, memcpy */ # include <string.h> /* strerror, memcpy */
UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd) static int g_displayLevel;
#define UTIL_DISPLAY(...) fprintf(stderr, __VA_ARGS__)
#define UTIL_DISPLAYLEVEL(l, ...) { if (g_displayLevel>=l) { UTIL_DISPLAY(__VA_ARGS__); } }
UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks)
{ {
DIR *dir; DIR *dir;
struct dirent *entry; struct dirent *entry;
@@ -360,13 +377,19 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_
path = (char*) malloc(dirLength + fnameLength + 2); path = (char*) malloc(dirLength + fnameLength + 2);
if (!path) { closedir(dir); return 0; } if (!path) { closedir(dir); return 0; }
memcpy(path, dirName, dirLength); memcpy(path, dirName, dirLength);
path[dirLength] = '/'; path[dirLength] = '/';
memcpy(path+dirLength+1, entry->d_name, fnameLength); memcpy(path+dirLength+1, entry->d_name, fnameLength);
pathLength = dirLength+1+fnameLength; pathLength = dirLength+1+fnameLength;
path[pathLength] = 0; path[pathLength] = 0;
if (!followLinks && UTIL_isLink(path)) {
UTIL_DISPLAYLEVEL(2, "Warning : %s is a symbolic link, ignoring\n", path);
continue;
}
if (UTIL_isDirectory(path)) { if (UTIL_isDirectory(path)) {
nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd); /* Recursively call "UTIL_prepareFileList" with the new path. */ nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd, followLinks); /* Recursively call "UTIL_prepareFileList" with the new path. */
if (*bufStart == NULL) { free(path); closedir(dir); return 0; } if (*bufStart == NULL) { free(path); closedir(dir); return 0; }
} else { } else {
if (*bufStart + *pos + pathLength >= *bufEnd) { if (*bufStart + *pos + pathLength >= *bufEnd) {
@@ -396,7 +419,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_
#else #else
UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd) UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks)
{ {
(void)bufStart; (void)bufEnd; (void)pos; (void)bufStart; (void)bufEnd; (void)pos;
fprintf(stderr, "Directory %s ignored (compiled without _WIN32 or _POSIX_C_SOURCE)\n", dirName); fprintf(stderr, "Directory %s ignored (compiled without _WIN32 or _POSIX_C_SOURCE)\n", dirName);
@@ -411,7 +434,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_
* After finishing usage of the list the structures should be freed with UTIL_freeFileList(params: return value, allocatedBuffer) * After finishing usage of the list the structures should be freed with UTIL_freeFileList(params: return value, allocatedBuffer)
* In case of error UTIL_createFileList returns NULL and UTIL_freeFileList should not be called. * In case of error UTIL_createFileList returns NULL and UTIL_freeFileList should not be called.
*/ */
UTIL_STATIC const char** UTIL_createFileList(const char **inputNames, unsigned inputNamesNb, char** allocatedBuffer, unsigned* allocatedNamesNb) UTIL_STATIC const char** UTIL_createFileList(const char **inputNames, unsigned inputNamesNb, char** allocatedBuffer, unsigned* allocatedNamesNb, int followLinks)
{ {
size_t pos; size_t pos;
unsigned i, nbFiles; unsigned i, nbFiles;
@@ -436,7 +459,7 @@ UTIL_STATIC const char** UTIL_createFileList(const char **inputNames, unsigned i
nbFiles++; nbFiles++;
} }
} else { } else {
nbFiles += UTIL_prepareFileList(inputNames[i], &buf, &pos, &bufend); nbFiles += UTIL_prepareFileList(inputNames[i], &buf, &pos, &bufend, followLinks);
if (buf == NULL) return NULL; if (buf == NULL) return NULL;
} } } }
+2 -2
View File
@@ -1,5 +1,5 @@
. .
.TH "ZSTD" "1" "March 2017" "zstd 1.1.4" "User Commands" .TH "ZSTD" "1" "March 2017" "zstd 1.1.5" "User Commands"
. .
.SH "NAME" .SH "NAME"
\fBzstd\fR \- zstd, unzstd, zstdcat \- Compress or decompress \.zst files \fBzstd\fR \- zstd, unzstd, zstdcat \- Compress or decompress \.zst files
@@ -110,7 +110,7 @@ save result into \fBfile\fR (only possible with a single INPUT\-FILE)
. .
.TP .TP
\fB\-f\fR, \fB\-\-force\fR \fB\-f\fR, \fB\-\-force\fR
overwrite output without prompting overwrite output without prompting, and (de)compress symbolic links
. .
.TP .TP
\fB\-c\fR, \fB\-\-stdout\fR \fB\-c\fR, \fB\-\-stdout\fR
+1 -1
View File
@@ -108,7 +108,7 @@ the last one takes effect.
* `-o file`: * `-o file`:
save result into `file` (only possible with a single INPUT-FILE) save result into `file` (only possible with a single INPUT-FILE)
* `-f`, `--force`: * `-f`, `--force`:
overwrite output without prompting overwrite output without prompting, and (de)compress symbolic links
* `-c`, `--stdout`: * `-c`, `--stdout`:
force write to standard output, even if it is the console force write to standard output, even if it is the console
* `--[no-]sparse`: * `--[no-]sparse`:
+17 -4
View File
@@ -99,7 +99,7 @@ static int usage(const char* programName)
#endif #endif
DISPLAY( " -D file: use `file` as Dictionary \n"); DISPLAY( " -D file: use `file` as Dictionary \n");
DISPLAY( " -o file: result stored into `file` (only if 1 input file) \n"); DISPLAY( " -o file: result stored into `file` (only if 1 input file) \n");
DISPLAY( " -f : overwrite output without prompting \n"); DISPLAY( " -f : overwrite output without prompting and (de)compress links \n");
DISPLAY( "--rm : remove source file(s) after successful de/compression \n"); DISPLAY( "--rm : remove source file(s) after successful de/compression \n");
DISPLAY( " -k : preserve source file(s) (default) \n"); DISPLAY( " -k : preserve source file(s) (default) \n");
DISPLAY( " -h/-H : display help/long help and exit\n"); DISPLAY( " -h/-H : display help/long help and exit\n");
@@ -270,6 +270,7 @@ int main(int argCount, const char* argv[])
{ {
int argNb, int argNb,
forceStdout=0, forceStdout=0,
followLinks=0,
main_pause=0, main_pause=0,
nextEntryIsDictionary=0, nextEntryIsDictionary=0,
operationResult=0, operationResult=0,
@@ -357,7 +358,7 @@ int main(int argCount, const char* argv[])
if (!strcmp(argument, "--compress")) { operation=zom_compress; continue; } if (!strcmp(argument, "--compress")) { operation=zom_compress; continue; }
if (!strcmp(argument, "--decompress")) { operation=zom_decompress; continue; } if (!strcmp(argument, "--decompress")) { operation=zom_decompress; continue; }
if (!strcmp(argument, "--uncompress")) { operation=zom_decompress; continue; } if (!strcmp(argument, "--uncompress")) { operation=zom_decompress; continue; }
if (!strcmp(argument, "--force")) { FIO_overwriteMode(); continue; } if (!strcmp(argument, "--force")) { FIO_overwriteMode(); forceStdout=1; followLinks=1; continue; }
if (!strcmp(argument, "--version")) { g_displayOut=stdout; DISPLAY(WELCOME_MESSAGE); CLEAN_RETURN(0); } if (!strcmp(argument, "--version")) { g_displayOut=stdout; DISPLAY(WELCOME_MESSAGE); CLEAN_RETURN(0); }
if (!strcmp(argument, "--help")) { g_displayOut=stdout; CLEAN_RETURN(usage_advanced(programName)); } if (!strcmp(argument, "--help")) { g_displayOut=stdout; CLEAN_RETURN(usage_advanced(programName)); }
if (!strcmp(argument, "--verbose")) { g_displayLevel++; continue; } if (!strcmp(argument, "--verbose")) { g_displayLevel++; continue; }
@@ -445,7 +446,7 @@ int main(int argCount, const char* argv[])
case 'D': nextEntryIsDictionary = 1; lastCommand = 1; argument++; break; case 'D': nextEntryIsDictionary = 1; lastCommand = 1; argument++; break;
/* Overwrite */ /* Overwrite */
case 'f': FIO_overwriteMode(); forceStdout=1; argument++; break; case 'f': FIO_overwriteMode(); forceStdout=1; followLinks=1; argument++; break;
/* Verbose mode */ /* Verbose mode */
case 'v': g_displayLevel++; argument++; break; case 'v': g_displayLevel++; argument++; break;
@@ -581,9 +582,21 @@ int main(int argCount, const char* argv[])
DISPLAYLEVEL(4, "PLATFORM_POSIX_VERSION defined: %ldL\n", (long) PLATFORM_POSIX_VERSION); DISPLAYLEVEL(4, "PLATFORM_POSIX_VERSION defined: %ldL\n", (long) PLATFORM_POSIX_VERSION);
#endif #endif
if (!followLinks) {
unsigned u;
for (u=0, fileNamesNb=0; u<filenameIdx; u++) {
if (UTIL_isLink(filenameTable[u])) {
DISPLAYLEVEL(2, "Warning : %s is a symbolic link, ignoring\n", filenameTable[u]);
} else {
filenameTable[fileNamesNb++] = filenameTable[u];
}
}
filenameIdx = fileNamesNb;
}
#ifdef UTIL_HAS_CREATEFILELIST #ifdef UTIL_HAS_CREATEFILELIST
if (recursive) { /* at this stage, filenameTable is a list of paths, which can contain both files and directories */ if (recursive) { /* at this stage, filenameTable is a list of paths, which can contain both files and directories */
extendedFileList = UTIL_createFileList(filenameTable, filenameIdx, &fileNamesBuf, &fileNamesNb); extendedFileList = UTIL_createFileList(filenameTable, filenameIdx, &fileNamesBuf, &fileNamesNb, followLinks);
if (extendedFileList) { if (extendedFileList) {
unsigned u; unsigned u;
for (u=0; u<fileNamesNb; u++) DISPLAYLEVEL(4, "%u %s\n", u, extendedFileList[u]); for (u=0; u<fileNamesNb; u++) DISPLAYLEVEL(4, "%u %s\n", u, extendedFileList[u]);
+13
View File
@@ -169,6 +169,19 @@ $ECHO "$ECHO foo | $ZSTD > /dev/full"
$ECHO foo | $ZSTD > /dev/full && die "write error not detected!" $ECHO foo | $ZSTD > /dev/full && die "write error not detected!"
$ECHO "$ECHO foo | $ZSTD | $ZSTD -d > /dev/full" $ECHO "$ECHO foo | $ZSTD | $ZSTD -d > /dev/full"
$ECHO foo | $ZSTD | $ZSTD -d > /dev/full && die "write error not detected!" $ECHO foo | $ZSTD | $ZSTD -d > /dev/full && die "write error not detected!"
$ECHO "\n**** symbolic link test **** "
rm -f hello.tmp world.tmp hello.tmp.zst world.tmp.zst
$ECHO "hello world" > hello.tmp
ln -s hello.tmp world.tmp
$ZSTD world.tmp hello.tmp
ls hello.tmp.zst || die "regular file should have been compressed!"
ls world.tmp.zst && die "symbolic link should not have been compressed!"
$ZSTD world.tmp hello.tmp -f
ls world.tmp.zst || die "symbol link should have been compressed with --force"
rm -f hello.tmp world.tmp hello.tmp.zst world.tmp.zst
fi fi
+1 -1
View File
@@ -982,7 +982,7 @@ int main(int argCount, char** argv)
#ifdef UTIL_HAS_CREATEFILELIST #ifdef UTIL_HAS_CREATEFILELIST
if (recursive) { if (recursive) {
fileNamesTable = UTIL_createFileList(filenameTable, filenameIdx, &fileNamesBuf, &fileNamesNb); fileNamesTable = UTIL_createFileList(filenameTable, filenameIdx, &fileNamesBuf, &fileNamesNb, 1);
if (fileNamesTable) { if (fileNamesTable) {
unsigned u; unsigned u;
for (u=0; u<fileNamesNb; u++) DISPLAYLEVEL(4, "%u %s\n", u, fileNamesTable[u]); for (u=0; u<fileNamesNb; u++) DISPLAYLEVEL(4, "%u %s\n", u, fileNamesTable[u]);