Skip to content

Use hardlinks for portable aliases without renaming originals#6308

Open
Trenly wants to merge 3 commits into
microsoft:masterfrom
Trenly:HardlinkAliases
Open

Use hardlinks for portable aliases without renaming originals#6308
Trenly wants to merge 3 commits into
microsoft:masterfrom
Trenly:HardlinkAliases

Conversation

@Trenly

@Trenly Trenly commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

📖 Description

This PR updates portable alias handling to preserve original executable names and use hardlink aliases instead of renaming files.

What changed

  • Added filesystem hardlink support:
    • CreateHardlink(...) in src/AppInstallerSharedLib/Public/winget/Filesystem.h
    • implementation in src/AppInstallerSharedLib/Filesystem.cpp
  • Added PortableFileType::Hardlink and hardlink entry creation in:
    • src/AppInstallerCommonCore/Public/winget/PortableFileEntry.h
  • Updated portable flow in src/AppInstallerCLICore/Workflows/PortableFlow.cpp to:
    • keep original executable filenames unchanged
    • create hardlink aliases for --rename, Commands, and PortableCommandAlias
    • place archive nested hardlinks next to their corresponding original executable
    • keep symlink targets pointing to the original executable
    • warn when --rename is used for archive portables (ignored)
  • Updated src/AppInstallerCLICore/PortableInstaller.cpp to:
    • install/verify/remove hardlink entries
    • keep strict symlink target verification
    • reconstruct ARP-backed expected state so alias hardlinks are tracked and removed during uninstall
    • avoid duplicate alias-added output
  • Updated E2E tests:
    • src/AppInstallerCLIE2ETests/InstallCommand.cs
    • src/AppInstallerCLIE2ETests/UninstallCommand.cs
  • Updated release notes in doc/ReleaseNotes.md.

User-visible behavior

  • Portable originals are no longer renamed to satisfy aliases.
  • Alias names are provided through hardlinks.
  • Alias commands continue to work in non-symlinked scenarios because executable aliases exist in the install directory.

🔗 References

🔍 Validation

  • Added/updated E2E coverage for install/uninstall hardlink behavior and symlink target expectations.
  • Local manual validation pending.

✅ Checklist

📋 Issue Type

  • Bug fix
  • Feature
  • Task

Created with assistance from GitHub Copilot.

@github-actions

This comment has been minimized.

Trenly and others added 2 commits June 20, 2026 21:36
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Trenly Trenly force-pushed the HardlinkAliases branch from 65b9528 to e42e642 Compare June 21, 2026 02:36
@Trenly Trenly marked this pull request as ready for review June 21, 2026 02:41
@Trenly Trenly requested a review from a team as a code owner June 21, 2026 02:41
@Trenly

Trenly commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

This implementation is based largely in part on #6270. I believe the approach of creating the hardlinks next to the original executables instead of as a fallback within the symlink flow has the following benefits:

  • The hardlink as an alias will exist regardless of if the package is added to path or symlinked. This has the benefit of not depending on the symlink flow at all, reducing potential points of failure.
  • The hardlink is placed in the same directory as the executable - avoiding any concerns about same-volume restrictions
  • In non-symlinked installations, the package directory is added to path, the hardlink ensures the alias will be available
  • When ArchiveBinariesDependOnPath is set, the symlink creation is never attempted - this approach ensures the alias is created as the logic does not depend on the symlink flow
  • Hardlink creation is directly tracked as part of the install process, ensuring proper cleanup during uninstall

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

Labels

None yet

Projects

None yet

1 participant