Skip to content

fix: skip reparse points during -r on Windows - #4860

Closed
Nmd-sketch wants to merge 1 commit into
meta:devfrom
Nmd-sketch:fix/windows-reparse-point
Closed

Nmd-sketch wants to merge 1 commit into
meta:devfrom
Nmd-sketch:fix/windows-reparse-point

Conversation

@Nmd-sketch

Copy link
Copy Markdown
Contributor

UTIL_isLink always returned 0 on non-POSIX platforms, and the Windows branch of UTIL_prepareFileList() had no reparse-point guard. As a result -r traversed junctions and symlinks found inside the input tree, combined with --rm this compressed and deleted files located outside the directory the user passed.

Added a _WIN32 branch to UTIL_isLink() querying GetFileAttributesA(), with the FILE_ATTRIBUTE_REPARSE_POINT test applied only when the lookup succeeds. Such entries are skipped in UTIL_prepareFileList() unless --follow-links is set, mirroring the POSIX branch, including its level-2 warning. Covered by a new playTests.sh test asserting that a junction (Windows) or symlink (POSIX) pointing outside the tree is left untouched by -r --rm

What and why
Fixes #4853.

After the fix the junction is skipped with
Warning : tree\link is a symbolic link, ignoring. Mirroring the existing POSIX behavior;
--follow-links still opts back into the traversal. The Windows path now costs one extra
GetFileAttributesA per listed entry, matching the per-entry lstat the POSIX branch has always done.

The new playTests.sh case creates a junction (Windows) or symlink (POSIX) pointing outside
the tree and asserts -r --rm leaves the outside file untouched. Verified both ways locally. Fails
without the fix (outside file compressed, original deleted by --rm), passes with it. Full CTest
suite passes.

Checklist

  • I searched open pull requests and issues: this problem is not already being addressed.
  • Bug fix: it comes with a reproducer or a test that fails without the fix.
  • Performance change: numbers from repeated runs are included, with CPU, compiler, flags and data.
    A gain in one configuration is not a general gain: see the Performance section of CONTRIBUTING.md.
  • I stated below whether AI or other automated tools were used.

Tools used

AI coding agent (Local LLM harness) was used to analyze the issue, draft the fix and write the tests.
All work was human-directed and reviewed and the failing-without-the-fix verification was done
locally on Windows with MSVC 2022. The issue report itself also disclosed AI-assisted analysis.

UTIL_isLink always returned 0 on non-POSIX platforms, and the Windows
branch of UTIL_prepareFileList() had no reparse-point guard. As a
result -r traversed junctions and symlinks found inside the input tree,
combined with --rm this compressed and deleted files located outside
the directory the user passed.

Added a _WIN32 branch to UTIL_isLink() querying GetFileAttributesA(),
with the FILE_ATTRIBUTE_REPARSE_POINT test applied only when the
lookup succeeds. Such entries are skipped in UTIL_prepareFileList()
unless --follow-links is set, mirroring the POSIX branch, including
its level-2 warning. Covered by a new playTests.sh test asserting
that a junction (Windows) or symlink (POSIX) pointing outside the tree
is left untouched by -r --rm
@Cyan4973

Cyan4973 commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

Thanks for the fix and the test. #4905 builds on it: it keeps your test (you are credited as co-author), and restricts the check to symbolic links and junctions, because FILE_ATTRIBUTE_REPARSE_POINT alone also matches OneDrive placeholders and deduplicated files, which zstd would then skip even when they are named on the command line. Closing in favor of #4905.

@Cyan4973 Cyan4973 closed this Nov 8, 2026
opensource-fork-sync Bot pushed a commit to cla7aye15I4nd/opensource-meta__zstd that referenced this pull request Nov 8, 2026
The CLI does not follow symbolic links by default (only -f does), but on
Windows UTIL_isLink() always returned 0, and the recursive directory walk
entered symbolic links and junctions like ordinary directories. -r could
then compress, and with --rm delete, files outside the given directory.

Treat name surrogate reparse points, i.e. symbolic links and junctions,
as links, like lstat() does on POSIX. Other reparse points, such as
OneDrive placeholders or deduplicated files, remain regular files and
directories.

Fixes meta#4853. The test comes from meta#4860.

Co-authored-by: Nmd-sketch <revusarlic@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Windows: zstd -r follows directory junctions and symlinks, so -r --rm deletes files outside the given folder

2 participants