fix: create resolvable symlinks on Windows#5
Merged
Conversation
Symlinks extracted on Windows were never resolvable, which broke consumers that open files through the link chain inside the darwin Electron zip (e.g. Electron Framework.framework/Electron Framework). Two bugs in make_symlink: - The archive's POSIX-style target was passed verbatim to CreateSymbolicLink, but NTFS reparse points don't treat '/' as a separator. Rewrite '/' to '\' before creating the link, matching what Node's fs.symlink does. - symlink_file succeeds even when the target is a directory (it just creates an untraversable file-type link), so the symlink_dir fallback was dead code. Decide the link type up front instead: verify_symlink_target now returns the resolved target path, and a windows-only helper follows any remaining hops (pending links from the archive, then the on-disk tree) to check whether it is a directory. Unresolvable targets default to file-type, which is no worse than a dangling link. The new framework fixture mirrors the macOS bundle shape (file link crossing a directory link) and the test runs on Windows whenever the symlink privilege is available.
erickzhao
approved these changes
Jun 5, 2026
|
🎉 This PR is included in version 1.0.2 🎉 The release is available on: Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Symlinks created during extraction on Windows were never resolvable. Any consumer that opens a file through a link chain — like electron/fuses reading
Electron.app/Contents/Frameworks/Electron Framework.framework/Electron Frameworkout of the darwin Electron zip — gotENOENT(see the Windows CI failure on electron/fuses#120).Why
Two bugs in
make_symlinkon Windows:Versions/Current/Electron Framework), and Rust's std passes them verbatim toCreateSymbolicLink. NTFS reparse-point resolution does not treat/as a separator, so the link never resolves. Node'sfs.symlinkrewrites/to\for exactly this reason, which is why the original JS extract-zip worked.symlink_file(...).or_else(symlink_dir(...))never falls back, becausesymlink_filesucceeds even when the target is a directory — it just creates a file-type link that Windows refuses to traverse as a path component. SoVersions/Current -> Acame out untraversable.How
/to\in the target before creating the link.verify_symlink_targetnow returns the resolved target path, and a Windows-only helper follows any remaining hops (pending links from this archive first, then the on-disk tree) to determine whether the target is a directory. Unresolvable targets (dangling, loops) default to file-type — no worse than a dangling link, and never an escape since the path was already verified to stay insidedir.No change to the validation logic itself; the security boundary check is untouched.
Testing
frameworkfixture mirroring the macOS bundle shape: a file link that crosses a directory link, with the links ordered before the file to exercise the pending-link map.x86_64-pc-windows-msvc; full suite (52 tests) green on macOS.