Skip to content

Archive the target directory when a download path is a symlink - #475

Open
RaphaelFakhri wants to merge 1 commit into
kernel:mainfrom
RaphaelFakhri:fix/archive-symlinked-dir
Open

RaphaelFakhri wants to merge 1 commit into
kernel:mainfrom
RaphaelFakhri:fix/archive-symlinked-dir

Conversation

@RaphaelFakhri

@RaphaelFakhri RaphaelFakhri commented Oct 18, 2026 •

Copy link
Copy Markdown

Checklist

Summary

GET /fs/download_dir_zip and GET /fs/download_dir_zstd check the path with os.Stat, which follows symlinks, so a symlink to a directory passes the "is a directory" check. ziputil.ZipDir and zstdutil.TarZstdDir then walk it with filepath.Walk, which does not descend into a symlinked root. The response is a 200 with an empty archive.

This change resolves the source directory with filepath.EvalSymlinks before walking, in both archivers. Symlinks inside the directory are still archived as links.

Tests

  • TestZipDirFollowsSymlinkedRoot and TestTarZstdDirFollowsSymlinkedRoot archive a directory through a symlink and check that its file is in the archive. Both fail without the fix.
  • go test -race ./lib/ziputil ./lib/zstdutil
  • go test -race ./cmd/api/api -run 'Zip|Zstd|Download|Upload'
  • go vet ./lib/ziputil ./lib/zstdutil ./cmd/api/...

Note

Low Risk
Localized bug fix in archive helpers with regression tests; symlink-in-archive behavior is unchanged.

Overview
Fixes empty zip/tar.zst downloads when the requested path is a symlink to a directory: API checks use os.Stat (follows the link), but filepath.Walk does not enter a symlinked root, so archives were built with no entries.

ZipDir and TarZstdDir now call filepath.EvalSymlinks on the source path before walking, so the real directory is archived. Symlinks inside the tree are unchanged (still stored as links).

Adds TestZipDirFollowsSymlinkedRoot and TestTarZstdDirFollowsSymlinkedRoot to cover archiving through a symlinked root.

Reviewed by Cursor Bugbot for commit a6fb8a7. Bugbot is set up for automated code reviews on this repo. Configure here.

GET /fs/download_dir_zip and /fs/download_dir_zstd stat the path with
os.Stat, so a symlink to a directory passes the directory check. The
archivers then walk it with filepath.Walk, which does not descend into a
symlinked root, and return an empty archive with a 200 status.

Resolve the source directory with filepath.EvalSymlinks before walking.
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