Open Forgind opened 1 year ago
Tagging subscribers to this area: @dotnet/area-system-io See info in area-owners.md if you want to be subscribed.
Author: | Forgind |
---|---|
Assignees: | - |
Labels: | `area-System.IO` |
Milestone: | - |
Small repro:
namespace symlink_copy;
class Program
{
static void Main(string[] args)
{
// clean-up previous run
File.Delete("foo");
File.Delete("linkToFoo");
File.WriteAllText("foo", "This is foo's content");
File.CreateSymbolicLink("linkToFoo", "foo");
ReadAllText("foo");
ReadAllText("linkToFoo");
// now, copy bar to linkToFoo.
File.Create("bar").Dispose();
File.Copy("bar", "linkToFoo", overwrite: true);
// print again
ReadAllText("foo");
ReadAllText("linkToFoo");
}
static void ReadAllText(string path)
{
Console.WriteLine($"{path}'s content: " + File.ReadAllText(path));
}
}
Note: File.Move
does not replace link's target.
Note that this is the same behavior as cp
command in linux without --remove-destination
https://stackoverflow.com/q/9371222/863980 (and probably the underlying syscalls?). If it was intentional (which seems likely), then overload solution sounds better. cc @tmds
Yes, the behavior is intentional.
Note that with .NET 7 on Linux, File.Copy will perform copy-on-write clones on file systems that support it (like Btrfs or XFS). That matches the behavior that is desired here: avoid copying the data. (PR: https://github.com/dotnet/runtime/pull/59695)
Does that mean the behaviour becomes filesystem dependent?
The functional behavior is the same. The performance is better on file systems that support the copy-on-write clone because we avoid copying the data.
Yes, the functional behavior is the same on macOS. Output of @Jozkee's program on osx-arm64 is also:
foo's content: This is foo's content
linkToFoo's content: This is foo's content
foo's content:
linkToFoo's content:
Description
See https://github.com/dotnet/msbuild/issues/8273
It appears that when passed a symlink, File.Copy overwrites the file at the other end of the symlink rather than overwriting the symlink. Is this intentional behavior? If so, perhaps there should be an overload that just overwrites the symlink?
Reproduction Steps
(From the issue above)
hard-links
symbolic-links
In both cases file
newtonsoft.json\13.0.1\lib\netstandard2.0\Newtonsoft.Json.dll
is silently replaced withnewtonsoft.json\13.0.2\lib\net6.0\Newtonsoft.Json.dll
:Expected behavior
Files in the NuGet cache remain untouched.
Actual behavior
Files in a NuGet package are silently replaced with files from another version.
Regression?
No response
Known Workarounds
Delete the file before calling Copy
Configuration
No response
Other information
No response