Skip to content

fix: set mtimes to extraction time after extracting Electron zips - #1940

Draft
claude[bot] wants to merge 1 commit into
mainfrom
fix/zero-dated-zip-mtimes
Draft

fix: set mtimes to extraction time after extracting Electron zips#1940
claude[bot] wants to merge 1 commit into
mainfrom
fix/zero-dated-zip-mtimes

Conversation

@claude

@claude claude Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Requested by Erick Zhao, Samuel Attard · Slack thread

  • I have read the contribution documentation for this project.
  • I agree to follow the code of conduct that this project follows, as appropriate.
  • The changes are appropriately documented (if applicable).
  • The changes have sufficient test coverage (if applicable).
  • The testsuite passes successfully on my local machine (if applicable). (The new unzip.spec.ts test, build, and lint pass locally; suites requiring Electron binary downloads could not run in the sandboxed environment used to prepare this PR.)

Summarize your changes:

Before: Apps packaged with @electron/packager >= 20.0.1 (and Forge 8.0.0-alpha.9+) have every file dated 1980-01-01, visible in Explorer and breaking installer/updater/backup expectations. Electron's dist zips zero-date every entry to the DOS epoch, and the Rust-based @electron-internal/extract-zip faithfully restores archive mtimes — unlike the old JS extract-zip, which ignored them and left files stamped with the extraction time.

After: Extracted files get the packaging time, matching packager 18 and every earlier release. The extractor itself is unchanged — per maintainer discussion, restoring archive mtimes is its correct behavior, so the normalization belongs in packager.

How: After extract() completes in extractElectronZip (src/unzip.ts) — the single choke point all packaging flows go through — a small sequential walker (fs.promises.readdir with withFileTypes) recursively sets atime/mtime of every extracted file and directory to the current time, using lutimes for symlinks so link targets aren't touched. Additionally, the two fs.cp EXDEV fallbacks in src/platform.ts now pass preserveTimestamps: true, so cross-device staging behaves the same as the rename fast path. That asymmetry is why the bug appeared Windows-only: same-volume rename (typical on Windows) preserved the 1980 mtimes, while cross-device cp (typical on Linux, temp dir on a different mount) reset them as a side effect.

The new test extracts a committed fixture zip whose entries are DOS-epoch-dated and asserts the extracted files' mtimes are recent; it fails against the previous unzip.ts (files dated exactly 1980-01-01T00:00:00Z) and passes with this change.

Affected versions: @electron/packager >= 20.0.1 and Forge 8.0.0-alpha.9+.

Fixes #1939


Generated by Claude Code

Electron's dist zips have every entry's timestamp zeroed to the DOS epoch
(1980-01-01). The Rust-based extractor used since v20.0.1 faithfully
restores archive mtimes, so packaged apps ended up with every file dated
1980. Reset timestamps to the extraction time after extracting, matching
the observable behavior of packager 18 and earlier, and preserve
timestamps in the EXDEV copy fallbacks so both staging paths behave like
rename.
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.

Created and Modified dates are zero (1980-01-01T00:00:00Z) for all files in a packaged app on Windows

1 participant