-
Notifications
You must be signed in to change notification settings - Fork 17.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
proposal: os: add Copy #56172
Comments
Would the new file have the same FileMode bits as the existing one? Would the API be atomic? For example, what would happen if a read or write operation fails halfway through? Would we leave a broken file behind? Existing APIs like Would we attempt to use a hard link if the operating system and filesystem support it? If those are true, it's the most efficient way to make a duplicate of a file, as the contents are not read and written entirely. cc @stapelberg given his experience with https://pkg.go.dev/github.com/google/renameio |
@mvdan Thanks for the questions, according to my current implementation, which based on the above github search seems to be also the most common one, the answers are:
These bahaviours seem to be what the
|
What about FICLONE? Shouldn't it attempt to use that? If not, why not? |
Personally I think that's a missed opportunity - copying files within the same filesystem is quite common, and you already pointed to one such example, |
A hard link creates two names for the same underlying file — mutations through the second link also affect the contents of the first. I would find that behavior very surprising in |
Right, of course. I've used hard links in a few projects of mine and that restriction was fine with me in those cases, but I agree it's surprising behavior for a "copy". Then I guess I want a different API, like "file clone". |
Implementing the proposed semantics using the Per https://man7.org/linux/man-pages/man2/ioctl_ficlonerange.2.html:
|
Here's an example: git-lfs, which is written in Go, started trying to use |
Should it create missing directories? ISTM this is a convenience function, so if it exists at all, it should be convenient. I also think the name should be |
+1 for adding +1 also for not making it atomic for consistency with +1 for using copy-on-write where available, but not hard links.
Nit: you should handle the error that |
One note on the sample implementation above: if Also, should it return the number of bytes that were copied like By the way, "The new file would have the same FileMode bits." is not entirely true. If the dest file already exists, then its current bits will be preserved. (This is the same as what |
Thanks for all the great questions, here are my answers. For those that I have no idea, added to the unsettled questions at the top of this issue: Q: Should it create missing directories? Q: Should the name be Q: Implementation should handle the error that
Without idempotence, we'd need to liter every return of error with Q: If src and dst refer to the same file, it empties the file. Either it should be a no-op or an error. (cp considers it an error.) Q: Should it return the number of bytes that were copied like io.Copy does? |
+1 to the name CopyFile. +1 to not creating parent directories. A duplicate Close call is fine; you simply ignore the second error (inside the defer) because the first error is handled. This is a rather common pattern that we can easily figure out when it comes to the code review, and it shouldn't need discussion here. I don't think we should return the size. A few more points popped to mind this morning as I mulled over this issue: If the destination already exists, we should probably only overwrite the file if it's a regular file. If it's something else, like a directory or a named pipe, we should return an error. If the source is not a regular file, I similarly think we should return an error immediately. For directories because we won't support a "recursive copy". For other file types, because lots could go wrong. For example, copying from a named pipe file could hang forever, and it would rarely make sense anyway. Put another way, I think CopyFile should only work with regular files. If the source file has read-only permission bits and the destination does not exist, CopyFile should presumably succeed. Note that this would require creating the file with read-write permission bits, doing the copy, then calling Chmod to set it to read-only after. |
I agree that “whichever cp does is probably best” is a good approach in general for implementing the proposed function, but I for one would appreciate getting rid of the extra |
Note that a version of this, This doesn't mean we can't accept this somewhat different proposal, I just wanted to note the history. |
|
I think that's ok as a starting point, but we should be careful not to overspecify it so that we can perhaps relax that restriction in the future. (I could see some use-cases for, say, allowing |
A fileutils package would be more useful, something like github.com/hacdias/fileutils. Of course whether or not this belongs in the standard library or not is another question. |
Hope to provide file copy api
|
I think this is now a duplicate of #62484. |
It's a little different than os.CopyFS because you can do |
Closing as dup of #62484. There may be a place for a system-specific file copying function, but it doesn't seem that the os package is the right place for that. The os package mostly aims at being a system-independent file management layer. |
I propose adding the function
os.Copy(dst, src string)
that does the exact same thing as thecp
command.This function would help simplify these codes in Go itself:
go/src/cmd/go/internal/modcmd/vendor.go
Line 293 in be9e244
go/src/cmd/cgo/out.go
Line 261 in 8d3631f
In the wild, there are 91k results for the search https://github.com/search?p=4&q=os.create+%22io.copy%22&type=Code , and one-tenth of them are copying files.
This implies that this function would help 10k codes out there.
Tentative implementation:
Unsettled questions:
Copy
orCopyFile
?File.Close()
in a clean manner withoutdefer
?The text was updated successfully, but these errors were encountered: