Skip to content

chown, chgrp: use the descriptor walk for -R on all safe_traversal platforms - #15128

Draft
abendrothj wants to merge 6 commits into
uutils:mainfrom
abendrothj:chown-fd-walk-all-platforms
Draft

abendrothj wants to merge 6 commits into
uutils:mainfrom
abendrothj:chown-fd-walk-all-platforms

Conversation

@abendrothj

@abendrothj abendrothj commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Outside Linux, chown -R/chgrp -R used walkdir. With -L, a symlink back to an ancestor gave "Too many levels of symbolic links" and exit 1, while GNU 9.12 exits 0.

The descriptor walk now runs wherever safe_traversal is built, which since #15030 is everywhere but Redox; that's named once, by a has_safe_traversal cfg alias. Outside Linux, --from is still changed by name; that's #15129. Linux behaviour doesn't change. test_chown_symlink_cycles and test_chown_symlink_two_links_same_dir now expect the same result everywhere. Run on macOS, Linux and Debian GNU/Hurd (on Hurd, the tests that fail also fail on main); FreeBSD and AIX are only cross-checked with clippy (AIX with libc 0.2.189, see #15083).

Based on #15127.

Part of #15027

Copilot AI balanced review requested due to automatic review settings October 6, 2026 07:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@codspeed

codspeed Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

⚠️ 25 benchmarks spent significant time in system calls

System calls cannot be consistently instrumented, so they are not included in the measure, which understates the real cost. Please switch to the Walltime instrument to accurately measure system calls.

Measurement and system calls

✅ 26 untouched benchmarks
⏩ 429 skipped benchmarks1


Comparing abendrothj:chown-fd-walk-all-platforms (32e99d1) with main (6292c03)

Open in CodSpeed

Footnotes

  1. 429 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@abendrothj
abendrothj marked this pull request as draft October 7, 2026 00:21
@abendrothj
abendrothj force-pushed the chown-fd-walk-all-platforms branch 3 times, most recently from bd252b4 to fa126c0 Compare October 7, 2026 08:02
--from was checked on a stat of the name and the change was then made
by name, so a rename landing in between changed a file that never had
the required owner.

On Linux, hold the file open with O_PATH, check that it is the one that
was stat'd and still passes --from, and change it through that
descriptor with fchownat(AT_EMPTY_PATH). This covers operands and -R
entries. A file found replaced is left alone; as with GNU, that fails
without a message, and -v reports the change that was not made.
On Linux, a directory operand was changed through a descriptor opened
for reading, and when that open failed it was skipped without a
message. Change it by name then, or through an O_PATH descriptor with
--from, as for any other file. Under -R it is still left alone and the
failure to read it reported, as with GNU.
Under -R -H, a symlink met in the tree was stat'd itself, while the
change went to the file it points to. --from was judged on, and -v
reported, the link's owner. Use the target's, as GNU does.
With -R on Linux, a change below the operand that failed was reported
without the "failed to change" line that -v adds for the operand and
on other platforms.
With -h, `-R -H` and `-R -L` did not descend into a symlinked directory
operand, and `-R -L -h` changed the files that symlinks in the tree
point to rather than the links. As GNU does, follow such a symlink to
descend and to judge --from, and change the link itself.
The descriptor-based -R walk ran only on Linux; other platforms used
walkdir, which stops at a symlink loop under -L with an error where GNU
just skips the directory already being visited. Use the descriptor walk
wherever safe_traversal is available, keeping walkdir for Redox. Outside
Linux, --from entries are still changed by name.

safe_traversal's platforms are named once, by a has_safe_traversal cfg
alias in uucore's build script.
@abendrothj
abendrothj force-pushed the chown-fd-walk-all-platforms branch from fa126c0 to 32e99d1 Compare October 12, 2026 11:38

This branch has not been deployed

No deployments
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.

2 participants