Skip to content

Conversation

@Elias-elastisys
Copy link

Adds a check to see if the destination file in the rename function is a symlink and in that case fall back to the same copy step as when the rename fails. Since os.Rename overrides the symlink.

Fixes #2155

@mikefarah mikefarah requested a review from Copilot January 20, 2026 23:48
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds symlink handling to the file rename utility to prevent os.Rename from overriding symlinks. When the destination is a symlink, the code now falls back to copying file contents instead of renaming, preserving the symlink.

Changes:

  • Modified tryRenameFile to detect symlinks and use copy instead of rename
  • Added comprehensive test coverage for symlink handling

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
pkg/yqlib/file_utils.go Added symlink detection before rename and fallback to copy operation
pkg/yqlib/write_in_place_handler_test.go Added test case verifying symlink preservation during write-in-place operations

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

if copyError := copyFileContents(from, to); copyError != nil {
return fmt.Errorf("failed copying from %v to %v: %w", from, to, copyError)
}
tryRemoveTempFile(from)
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The symlink copy path doesn't return after success, which means execution will fall through to the os.Rename call on line 17. Add return nil after tryRemoveTempFile(from) to prevent attempting rename after successful copy.

Suggested change
tryRemoveTempFile(from)
tryRemoveTempFile(from)
return nil

Copilot uses AI. Check for mistakes.
if info, err := os.Lstat(to); err == nil && info.Mode()&os.ModeSymlink != 0 {
log.Debug("Target file is symlink, skipping rename and attempting to copy contents")

if copyError := copyFileContents(from, to); copyError != nil {
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using copyFileContents will overwrite the symlink with a regular file since os.Create replaces the file. To preserve the symlink, the code should follow the symlink to copy contents to the target file. Use os.Stat to resolve the symlink path, then copy to the resolved destination.

Copilot uses AI. Check for mistakes.
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.

Inplace flag overwrites symlinks with file contents when data file and /tmp are on the same partition

1 participant