[PlatformSpecific(TestPlatforms.AnyUnix)] // Expected WatcherChangeTypes are different based on OS
public void Unix_File_Move_To_Same_Directory()
{
- FileMove_SameDirectory(WatcherChangeTypes.Created | WatcherChangeTypes.Deleted);
+ FileMove_SameDirectory(WatcherChangeTypes.Renamed);
}
[Fact]
[PlatformSpecific(TestPlatforms.OSX)] // Expected WatcherChangeTypes are different based on OS
public void OSX_File_Move_To_Different_Watched_Directory()
{
- FileMove_DifferentWatchedDirectory(WatcherChangeTypes.Changed);
+ FileMove_DifferentWatchedDirectory(0);
}
[Fact]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Expected WatcherChangeTypes are different based on OS
public void Unix_File_Move_In_Nested_Directory(bool includeSubdirectories)
{
- FileMove_NestedDirectory(includeSubdirectories ? WatcherChangeTypes.Created | WatcherChangeTypes.Deleted : 0, includeSubdirectories);
+ FileMove_NestedDirectory(includeSubdirectories ? WatcherChangeTypes.Renamed : 0, includeSubdirectories);
}
[Fact]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Expected WatcherChangeTypes are different based on OS
public void Unix_File_Move_With_Set_NotifyFilter()
{
- FileMove_WithNotifyFilter(WatcherChangeTypes.Deleted);
+ FileMove_WithNotifyFilter(WatcherChangeTypes.Renamed);
}
#region Test Helpers
{
// The desired behavior for Move(source, dest) is to not overwrite the destination file
// if it exists. Since rename(source, dest) will replace the file at 'dest' if it exists,
- // link/unlink are used instead. However, if the source path and the dest path refer to
- // the same file, then do a rename rather than a link and an unlink. This is important
- // for case-insensitive file systems (e.g. renaming a file in a way that just changes casing),
- // so that we support changing the casing in the naming of the file. If this fails in any
- // way (e.g. source file doesn't exist, dest file doesn't exist, rename fails, etc.), we
- // just fall back to trying the link/unlink approach and generating any exceptional messages
- // from there as necessary.
- //
- // Rename is also appropriate for overwrite=true with same source/dest file
+ // link/unlink are used instead. Rename is more efficient than link/unlink on file systems
+ // where hard links are not supported (such as FAT). Therefore, given that source file exists,
+ // rename is used in 2 cases: when dest file does not exist or when source path and dest
+ // path refer to the same file (on the same device). This is important for case-insensitive
+ // file systems (e.g. renaming a file in a way that just changes casing), so that we support
+ // changing the casing in the naming of the file. If this fails in any way (e.g. source file
+ // doesn't exist, dest file doesn't exist, rename fails, etc.), we just fall back to trying the
+ // link/unlink approach and generating any exceptional messages from there as necessary.
Interop.Sys.FileStatus sourceStat, destStat;
if (Interop.Sys.LStat(sourceFullPath, out sourceStat) == 0 && // source file exists
- Interop.Sys.LStat(destFullPath, out destStat) == 0 && // dest file exists
- sourceStat.Dev == destStat.Dev && // source and dest are on the same device
- sourceStat.Ino == destStat.Ino && // and source and dest are the same file on that device
+ (Interop.Sys.LStat(destFullPath, out destStat) != 0 || // dest file does not exist
+ sourceStat.Ino == destStat.Ino) && // source and dest are the same file on that device
Interop.Sys.Rename(sourceFullPath, destFullPath) == 0) // try the rename
{
// Renamed successfully.