Patch the file a symlinked source names - #845
Merged
Merged
Conversation
The applier rewrites the whole file through a temporary and swaps it in with File.Replace, which on Linux and macOS is a rename. A rename replaces the name it is given, so for a source reached through a symlink - a worktree, a shared checkout, a vendored copy - the link itself was replaced by a regular file: the link stopped being one, and the file it named still held the snapshot that had failed. Every later run reported the same snapshot again, against source the compiler was still reading from the target. The link is followed before anything else, so the lock, the mutex, the read and the swap all name the file that actually holds the source. Two links to one file get the same lock as a side effect. The rename also leaves the temporary's permissions on the file. A source that was executable, or group writable, came back as whatever this process's umask said, so the destination's mode is carried onto the temporary first. Windows keeps the destination's ACLs across a Replace and needs none of this. Both tests are Unix only: a symlink needs elevation on Windows and a file mode is not a thing it has. The two behaviours behind them were confirmed against rename(2) directly.
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.
The applier rewrites the whole file through a temporary and swaps it in with
File.Replace, which on Linux and macOS is a rename. A rename replaces the name it is
given, so for a source reached through a symlink - a worktree, a shared checkout, a
vendored copy - the link itself was replaced by a regular file: the link stopped
being one, and the file it named still held the snapshot that had failed. Every
later run reported the same snapshot again, against source the compiler was still
reading from the target.
The link is followed before anything else, so the lock, the mutex, the read and the
swap all name the file that actually holds the source. Two links to one file get the
same lock as a side effect.
The rename also leaves the temporary's permissions on the file. A source that was
executable, or group writable, came back as whatever this process's umask said, so
the destination's mode is carried onto the temporary first. Windows keeps the
destination's ACLs across a Replace and needs none of this.
Both tests are Unix only: a symlink needs elevation on Windows and a file mode is
not a thing it has. The two behaviours behind them were confirmed against rename(2)
directly.