Repository navigation
mv: create cross-device directory entries relative to the destination descriptor - #14971
abendrothj wants to merge 6 commits into
Conversation
d0cf9fe to
f3fc847
Compare
f3fc847 to
e3fda2a
Compare
Merging this PR will improve performance by 12.06%1 warning, 1 note
Performance Changes
Tip Curious why performance improved? Comment Comparing Footnotes
|
|
GNU testsuite comparison: |
e3fda2a to
8d392d1
Compare
|
Opened #14991. |
8d392d1 to
5e3cb57
Compare
5e3cb57 to
42731bd
Compare
|
this is quite a large patch, can we make it smaller? |
42731bd to
7e5ee68
Compare
|
Smaller now: it reuses |
b125862 to
b3b9dde
Compare
52022fc to
6903ee6
Compare
6903ee6 to
1f527e4
Compare
Move the temporary name and renameat logic of replace_link into DirFd::replace_entry_at, which creates the entry through a callback relative to the directory, so other callers can replace entries the same way. The parent is now opened with DirFd::open_anchor, so ln -sf and cp -sf replacing an entry in a directory with write and search but no read permission work, as they do with GNU, instead of failing with EACCES.
Create fifos, sockets and device nodes relative to an open directory. nix and rustix do not provide mknodat on Apple targets, so this calls libc directly.
d767c93 to
4d87582
Compare
|
Trimmed a bit more: the fakeroot test moved into |
A cross-device move of a socket or device node went through the regular file copy, which removed the destination and then failed to open the source. A fifo also removed the destination before creating the new one, and lost its mode. Fifos, sockets and device nodes are now created with their mode and ownership in a private directory next to the destination and renamed over it, so the destination is kept if the node cannot be created, and the ownership and mode cannot land on another file linked over the destination name meanwhile. The private directory is made 0700 by name right after it is created, before it is opened, without changing the umask; the check after the open rejects a directory moved there in between. As for regular files, setuid and setgid are dropped when the ownership cannot be kept. Fixes uutils#13145
Sockets and device nodes inside a directory moved across devices went through the regular file copy, which cannot open them, so the move failed. Fifos were recreated with mode 0666 minus the umask. Recreate all of them with copy_special_file, which keeps the mode.
A caller creating a file can then keep writing through the descriptor it opened. Also make link_at public, for creating links relative to an open directory, and add DirFd::open_subdir_anchor, which opens a subdirectory without following a symlink and, where the platform allows, without needing read permission, for creating entries in it.
When a directory move falls back to copying across filesystems, each destination entry was created by joining a path, and regular files went through fs::copy. A symlink that appeared in the destination while the copy was running was followed, so the content went wherever it pointed. Hold each destination directory open, search-only where possible, and create files, subdirectories, symlinks, special files and hard links relative to it without following symlinks. An entry that appears at a name is replaced through DirFd::replace_entry_at. Regular files share copy_file_data with the single file fallback, which sets ownership and mode through the descriptor. The names of each source directory are read before descending, so only one descriptor stays open per level. util/check-libc-interposition.sh now also checks a cross-device mv under fakeroot, so the ownership change stays visible to LD_PRELOAD wrappers. Closes uutils#14991
4d87582 to
e4aae21
Compare
Based on #15123; only the last two commits are new here (+412/−96).
When a directory move falls back to copying across filesystems, each destination entry was created by joining a path, and regular files went through
fs::copy. A symlink that appeared in the destination during the copy was followed, so content went wherever it pointed.Each destination directory is now held open (search-only where possible), and files, subdirectories, symlinks, special files and hard links are created relative to it without following symlinks. An entry that shows up at a name is replaced through
DirFd::replace_entry_at. Regular files sharecopy_file_datawith the single-file fallback, which sets ownership and mode on the open descriptor, using libcfchownso fakeroot still works;util/check-libc-interposition.shnow checks this for mv. Source directory names are read before descending, so one descriptor stays open per level.Still by path: directory ownership, symlink xattrs, the hard link source, and the final directory xattr reopen. Run on macOS and Linux. On Debian GNU/Hurd the mv tests fail only where main does (the new ones are Linux-only), and a cross-device move of a 0640 FIFO, alone or in a directory, keeps its mode as with GNU 9.10. AIX is only cross-checked with clippy.
Closes #14991