Skip to content

Pass the link type when unpacking a symlink - #481

Open
PerryLink wants to merge 1 commit into
electron:mainfrom
PerryLink:fix/unpack-symlink-type
Open

PerryLink wants to merge 1 commit into
electron:mainfrom
PerryLink:fix/unpack-symlink-type

Conversation

@PerryLink

Copy link
Copy Markdown

What

createSymlink() recreates unpacked links without telling Windows what the link points at:

await fs.symlink(link, path.join(`${dest}.unpacked`, filepath))

On Windows an untyped symlink is created as a file link, so a packaged symlink to a
directory becomes a link that can never be entered as a directory — and creating a directory
symlink at all requires Developer Mode or elevation, so on a normal account unpacking aborts with

Error: Could not create symlinks for unpacked assets. On Windows, consider activating Developer Mode...
    at createSymlink (src/disk.ts:456)
    at writeFileListToStream (src/disk.ts:253)

The change

  • read the link target's kind from the archive header (filesystem.getFile(...)), because the
    target does not have to be unpacked itself;
  • pass that type to fs.symlink;
  • when a directory link still fails with EPERM, fall back to a junction, the only directory
    link an unprivileged Windows user can create;
  • point the recreated link at the copy inside .unpacked rather than back at the packaged source.

One test is added: pack a directory symlink with --unpack, extract, and assert that the extracted
entry is a symlink whose stat is a directory, whose payload reads back, and whose realpath stays
inside .unpacked.

Verification

Windows 11, non-elevated, Developer Mode off:

  • before: the EPERM error above, from both extractAll() and the CLI
    (asar p app app.asar --unpack "*");
  • after: .unpacked/var is a symbolic link, stat says directory, file.txt inside it reads back,
    and realpath is inside .unpacked.

Full suite: 196 passed / 7 failed before, 197 passed / 6 failed after — the only difference is the
new test, and the remaining 6 failures are identical on the unmodified tree. oxfmt --check and
oxlint are clean.

The elevated type: 'dir' branch is not exercised on this machine (non-elevated), so the junction
fallback is what the test covers; file symlinks still need elevation and are out of scope here.

@PerryLink
PerryLink requested a review from a team as a code owner October 18, 2026 04:01

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant