diff --git a/programs/util.c b/programs/util.c index 652530b1223..d4d009a3643 100644 --- a/programs/util.c +++ b/programs/util.c @@ -503,6 +503,16 @@ int UTIL_isLink(const char* infilename) return 1; } } +#elif defined(_WIN32) + { + DWORD attributes; + attributes = GetFileAttributesA(infilename); + if (attributes != INVALID_FILE_ATTRIBUTES && + (attributes & FILE_ATTRIBUTE_REPARSE_POINT)) { + UTIL_TRACE_RET(1); + return 1; + } + } #endif (void)infilename; UTIL_TRACE_RET(0); @@ -942,6 +952,11 @@ static int UTIL_prepareFileList(const char* dirName, memcpy(path+dirLength+1, cFile.cFileName, fnameLength); pathLength = dirLength+1+fnameLength; path[pathLength] = 0; + if (!followLinks && UTIL_isLink(path)) { + UTIL_DISPLAYLEVEL(2, "Warning : %s is a symbolic link, ignoring\n", path); + free(path); + continue; + } if (cFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if ( strcmp (cFile.cFileName, "..") == 0 || strcmp (cFile.cFileName, ".") == 0 ) diff --git a/tests/playTests.sh b/tests/playTests.sh index 44bc82b5610..9f315f6eac4 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -443,6 +443,34 @@ mkdir -p tmpEmptyDir zstd -r tmpEmptyDir rm -rf tmpEmptyDir +println "test : directory links are not followed by -r" +# remove leftovers of a previous failed run +if [ "$isWindows" = true ]; then cmd //c "rmdir tmpLinkDir\tmpLink" 2> /dev/null || :; fi +rm -rf tmpLinkDir tmpOutside tmpStdErr +mkdir -p tmpLinkDir tmpOutside +echo "inner" > tmpLinkDir/tmpInner +echo "victim" > tmpOutside/tmpVictim +if [ "$isWindows" = true ]; then + # junctions don't require the privileges that symlinks do + (cd tmpLinkDir && cmd //c "mklink /J tmpLink ..\tmpOutside") +else + ln -s ../tmpOutside tmpLinkDir/tmpLink +fi +zstd -r --rm tmpLinkDir 2> tmpStdErr +# remove the link before asserting, so a failing test never leaves a live +# link behind for the later "rm -rf tmp*" cleanups to encounter +if [ "$isWindows" = true ]; then + cmd //c "rmdir tmpLinkDir\tmpLink" +else + rm -f tmpLinkDir/tmpLink +fi +$GREP "symbolic link" tmpStdErr +test -f tmpLinkDir/tmpInner.zst # file inside the tree was compressed +test ! -f tmpLinkDir/tmpInner # ... and removed (--rm) +test -f tmpOutside/tmpVictim # file outside the tree was left untouched +test ! -f tmpOutside/tmpVictim.zst # ... not compressed through the link +rm -rf tmpLinkDir tmpOutside tmpStdErr + println "\n===> file removal" zstd -f --rm tmp