Skip to content

Fix cp -f, cp -p, chown -RP, chmod -R -P#20

Open
kelp wants to merge 1 commit intomainfrom
fix/cp-chown-chmod-audit
Open

Fix cp -f, cp -p, chown -RP, chmod -R -P#20
kelp wants to merge 1 commit intomainfrom
fix/cp-chown-chmod-audit

Conversation

@kelp
Copy link
Copy Markdown
Owner

@kelp kelp commented Mar 30, 2026

Summary

  • cp -f: Only unlink destination when it cannot be opened for writing. Writable destinations are overwritten in place via truncate+write, preserving hard links and inodes. Previously, -f unconditionally unlinked the destination, severing hard links even when unnecessary.
  • cp -p: Add fchown call to copyFileWithAttributes to preserve source uid/gid on the copy. EPERM is silently ignored for non-root users, matching GNU behavior.
  • chown -RP: Use lstat instead of stat at the entry of chownRecursive when -P is active (or when neither -H nor -L is set). This prevents following a cmdline symlink-to-directory and incorrectly recursing into the target.
  • chmod -R -P: Skip symlinks encountered during recursive traversal instead of applying chmod through them to the target file. GNU chmod silently skips symlinks during -R.

Test plan

  • New unit test: cp: -f should not unlink writable destination (preserves hard links) — creates a hard link to dest, copies with -f, verifies inode preserved
  • New unit test: cp: -p should preserve group ownership via chown — copies with -p, verifies gid matches
  • New privileged test: chown -RP should not follow cmdline symlink to directory — creates symlink to dir, runs chown -RP with verbose, verifies target dir contents not in output (skipped without fakeroot)
  • New unit test: chmod: -R -P should not follow symlinks during traversal — creates symlink to outside file, runs chmod -R -P, verifies outside file mode unchanged
  • Full test suite: no regressions (38 pre-existing failures unchanged, 4 new tests added, 3 pass, 1 skipped)

cp -f: Only unlink destination when it cannot be opened for
writing. Writable destinations are overwritten in place,
preserving hard links and inodes.

cp -p: Add fchown call to copyFileWithAttributes to preserve
source uid/gid. EPERM silently ignored for non-root.

chown -RP: Use lstat instead of stat at chownRecursive entry
so a cmdline symlink-to-directory is not followed.

chmod -R -P: Skip symlinks during recursive traversal instead
of applying chmod through them to the target.
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