Repository navigation
Conversation
clonefile(2) says "Cloning directories with these functions is strongly discouraged. Use copyfile(3) to clone directories instead." Apple's DTS says why: cloning a directory holds off every change to it until the clone is done, which on a large directory, or one the system uses, can stall the system, and in the worst case panic the kernel: - https://developer.apple.com/forums/thread/784446 - https://developer.apple.com/forums/thread/818372 So a directory is now cloned with copyfile(COPYFILE_CLONE | COPYFILE_RECURSIVE), which clones each file. What it does not do as clonefile did is made up for: - It copies into `to` if it exists, so the clone is made next to it and moved there with renamex_np(RENAME_EXCL), which fails if it exists, and leaves `to` never half made. - It fails on FIFOs and sockets, so a callback makes FIFOs anew and leaves sockets and devices out, as beside what is ignored already. - It makes symbolic links after setting their directory's modification time, so the times are set again once it is done. - It falls back to copying on another volume, so that fails, as before. - It follows a symbolic link given to it, so entries that are not directories are cloned without COPYFILE_RECURSIVE. A file gone while the directory is cloned is left out. The fork is no longer one moment of the directory: what is written to it meanwhile may be in the fork or not, each file by itself, as the manual page now says.
On Linux, cp -a makes sockets anew, so the test of forking deep in the directory failed there.
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 clonefile(2) man page says, under LIMITATIONS:
The man page doesn't say why, but Apple's DTS does:
fsfork clones the directory an agent works in, often with
target/ornode_modulesin it, so it is the case this warns about.Change
fsfork/darwin.rsclones withcopyfile(COPYFILE_CLONE | COPYFILE_RECURSIVE), and makes up for what it does not do asclonefiledid:copyfiletoif it exists.<to>.<pid>.partand moved totowithrenamex_np(RENAME_EXCL), so it fails iftoexists (fork numbering relies on that), andtois never half madeclone_entriesalready did beside what is ignoredclonefiledidCOPYFILE_RECURSIVEA file deleted while the directory is being cloned is left out rather than failing the fork.
README and fsfork(1) say what changed, including that a fork is no longer one moment of the directory.
Trade-offs
clonefileon a directory gave a point-in-time copy of the whole tree. Now, what is written to the directory while it is forked may be in the fork or not, each file by itself. The fork and its base are still the same, as the fork is cloned from the base.target/(6,838 entries, 386 MB),fsfork --no-ignoretakes 2.1 s instead of 0.18 s, as Apple's "~10×" says..<name>.<pid>.partnext to it, which--prunedoesn't remove.Elliott says directory
clonefileis fine on a hierarchy the app controls. The base is that (hidden, and nothing writes to it), so cloning the fork from the base withclonefilewould win back half the time. I left that out to keep to the man page; say if you want it.Testing
cargo test: all pass, with a new test,copies_fifos_links_and_modification_times_deep_in_the_directory, which checks:.partis left behindcargo clippy --all-targets: clean.