Using FUTIMENS instead of FUTIMES (#34271)

* test added

* rearranging order for if statements

* reducing thread sleep time and reverting millisecond test change

* adding comment

* removing comment, adding tick equality check, failing if not able to create file with non-zero nano or milli second

* correcting test for hfs system

* NanoSeconds -> Nanoseconds, Millisec -> milliseconds
HFs assert converted to false
This commit is contained in:
Anirudh Agnihotry 2019-01-02 15:12:21 -08:00 коммит произвёл Alexis Christoforides
Родитель 61bbac188e
Коммит 862b6c67d0
2 изменённых файлов: 107 добавлений и 79 удалений

Просмотреть файл

@ -1314,22 +1314,21 @@ int32_t SystemNative_CopyFile(intptr_t sourceFd, intptr_t destinationFd)
while ((ret = fstat_(inFd, &sourceStat)) < 0 && errno == EINTR);
if (ret == 0)
{
#if HAVE_FUTIMES
struct timeval origTimes[2];
origTimes[0].tv_sec = sourceStat.st_atime;
origTimes[0].tv_usec = ST_ATIME_NSEC(&sourceStat) / 1000;
origTimes[1].tv_sec = sourceStat.st_mtime;
origTimes[1].tv_usec = ST_MTIME_NSEC(&sourceStat) / 1000;
while ((ret = futimes(outFd, origTimes)) < 0 && errno == EINTR);
#elif HAVE_FUTIMENS
// futimes is not a POSIX function, and not available on Android,
// but futimens is
#if HAVE_FUTIMENS
// futimens is prefered because it has a higher resolution.
struct timespec origTimes[2];
origTimes[0].tv_sec = (time_t)sourceStat.st_atime;
origTimes[0].tv_nsec = ST_ATIME_NSEC(&sourceStat);
origTimes[1].tv_sec = (time_t)sourceStat.st_mtime;
origTimes[1].tv_nsec = ST_MTIME_NSEC(&sourceStat);
while ((ret = futimens(outFd, origTimes)) < 0 && errno == EINTR);
#elif HAVE_FUTIMES
struct timeval origTimes[2];
origTimes[0].tv_sec = sourceStat.st_atime;
origTimes[0].tv_usec = ST_ATIME_NSEC(&sourceStat) / 1000;
origTimes[1].tv_sec = sourceStat.st_mtime;
origTimes[1].tv_usec = ST_MTIME_NSEC(&sourceStat) / 1000;
while ((ret = futimes(outFd, origTimes)) < 0 && errno == EINTR);
#endif
}
if (ret != 0)

Просмотреть файл

@ -18,6 +18,48 @@ namespace System.IO.Tests
return new FileInfo(path);
}
private static bool HasNonZeroNanoseconds(DateTime dt) => dt.Ticks % 10 != 0;
public FileInfo GetNonZeroMilliseconds()
{
FileInfo fileinfo = new FileInfo(GetTestFilePath());
for (int i = 0; i < 5; i++)
{
fileinfo.Create().Dispose();
if (fileinfo.LastWriteTime.Millisecond != 0)
break;
// This case should only happen 1/1000 times, unless the OS/Filesystem does
// not support millisecond granularity.
// If it's 1/1000, or low granularity, this may help:
Thread.Sleep(1234);
}
Assert.NotEqual(0, fileinfo.LastWriteTime.Millisecond);
return fileinfo;
}
public FileInfo GetNonZeroNanoseconds()
{
FileInfo fileinfo = new FileInfo(GetTestFilePath());
for (int i = 0; i < 5; i++)
{
fileinfo.Create().Dispose();
if (HasNonZeroNanoseconds(fileinfo.LastWriteTime))
break;
// This case should only happen 1/10 times, unless the OS/Filesystem does
// not support nanosecond granularity.
// If it's 1/10, or low granularity, this may help:
Thread.Sleep(123);
}
Assert.True(HasNonZeroNanoseconds(fileinfo.LastWriteTime), "Tests failed to create a file with non-zero nanoseconds.");
return fileinfo;
}
public override FileInfo GetMissingItem() => new FileInfo(GetTestFilePath());
public override string GetItemPath(FileInfo item) => item.FullName;
@ -70,25 +112,64 @@ namespace System.IO.Tests
[ConditionalFact(nameof(isNotHFS))]
public void CopyToMillisecondPresent()
{
FileInfo input = new FileInfo(GetTestFilePath());
for (int i = 0; i < 5; i++)
{
input.Create().Dispose();
if (input.LastWriteTime.Millisecond != 0)
break;
// This case should only happen 1/1000 times, unless the OS/Filesystem does
// not support millisecond granularity.
// If it's 1/1000, or low granularity, this may help:
Thread.Sleep(1234);
}
FileInfo input = GetNonZeroMilliseconds();
FileInfo output = new FileInfo(Path.Combine(GetTestFilePath(), input.Name));
Assert.Equal(0, output.LastWriteTime.Millisecond);
output.Directory.Create();
output = input.CopyTo(output.FullName, true);
Assert.NotEqual(0, input.LastWriteTime.Millisecond);
Assert.Equal(input.LastWriteTime.Millisecond, output.LastWriteTime.Millisecond);
Assert.NotEqual(0, output.LastWriteTime.Millisecond);
}
[ConditionalFact(nameof(isNotHFS))]
public void CopyToNanosecondsPresent()
{
FileInfo input = GetNonZeroNanoseconds();
FileInfo output = new FileInfo(Path.Combine(GetTestFilePath(), input.Name));
output.Directory.Create();
output = input.CopyTo(output.FullName, true);
Assert.Equal(input.LastWriteTime.Ticks, output.LastWriteTime.Ticks);
Assert.True(HasNonZeroNanoseconds(output.LastWriteTime));
}
[ConditionalFact(nameof(isHFS))]
public void CopyToNanosecondsPresent_HFS()
{
FileInfo input = new FileInfo(GetTestFilePath());
input.Create().Dispose();
FileInfo output = new FileInfo(Path.Combine(GetTestFilePath(), input.Name));
output.Directory.Create();
output = input.CopyTo(output.FullName, true);
Assert.Equal(input.LastWriteTime.Ticks, output.LastWriteTime.Ticks);
Assert.False(HasNonZeroNanoseconds(output.LastWriteTime));
}
[ConditionalFact(nameof(isHFS))]
public void MoveToMillisecondPresent_HFS()
{
FileInfo input = new FileInfo(GetTestFilePath());
input.Create().Dispose();
string dest = Path.Combine(input.DirectoryName, GetTestFileName());
input.MoveTo(dest);
FileInfo output = new FileInfo(dest);
Assert.Equal(0, output.LastWriteTime.Millisecond);
}
[ConditionalFact(nameof(isNotHFS))]
public void MoveToMillisecondPresent()
{
FileInfo input = GetNonZeroMilliseconds();
string dest = Path.Combine(input.DirectoryName, GetTestFileName());
input.MoveTo(dest);
FileInfo output = new FileInfo(dest);
Assert.NotEqual(0, output.LastWriteTime.Millisecond);
}
@ -100,61 +181,10 @@ namespace System.IO.Tests
FileInfo output = new FileInfo(Path.Combine(GetTestFilePath(), input.Name));
output.Directory.Create();
output = input.CopyTo(output.FullName, true);
Assert.Equal(0, input.LastWriteTime.Millisecond);
Assert.Equal(input.LastWriteTime.Millisecond, output.LastWriteTime.Millisecond);
Assert.Equal(0, output.LastWriteTime.Millisecond);
}
[Fact]
public void CopyToMillisecondPresent()
{
FileInfo input = new FileInfo(Path.Combine(TestDirectory, GetTestFileName()));
input.Create().Dispose();
string driveFormat = new DriveInfo(input.DirectoryName).DriveFormat;
if (!driveFormat.Equals(HFS, StringComparison.InvariantCultureIgnoreCase))
{
for (int i = 0; i < 5; i++)
{
if (input.LastWriteTime.Millisecond != 0)
break;
// This case should only happen 1/1000 times, unless the OS/Filesystem does
// not support millisecond granularity.
// If it's 1/1000, or low granularity, this may help:
Thread.Sleep(1234);
input = new FileInfo(Path.Combine(TestDirectory, GetTestFileName()));
input.Create().Dispose();
}
FileInfo output = new FileInfo(Path.Combine(TestDirectory, GetTestFileName(), input.Name));
Assert.Equal(0, output.LastWriteTime.Millisecond);
output.Directory.Create();
output = input.CopyTo(output.FullName, true);
Assert.NotEqual(0, input.LastWriteTime.Millisecond);
Assert.NotEqual(0, output.LastWriteTime.Millisecond);
}
}
[Fact]
[PlatformSpecific(TestPlatforms.OSX)]
public void CopyToMillisecondPresent_HFS()
{
FileInfo input = new FileInfo(Path.Combine(TestDirectory, GetTestFileName()));
input.Create().Dispose();
FileInfo output = new FileInfo(Path.Combine(TestDirectory, GetTestFileName(), input.Name));
string driveFormat = new DriveInfo(input.DirectoryName).DriveFormat;
if (driveFormat.Equals(HFS, StringComparison.InvariantCultureIgnoreCase))
{
output.Directory.Create();
output = input.CopyTo(output.FullName, true);
Assert.Equal(0, input.LastWriteTime.Millisecond);
Assert.Equal(0, output.LastWriteTime.Millisecond);
}
}
[Fact]
public void DeleteAfterEnumerate_TimesStillSet()
{
@ -190,8 +220,7 @@ namespace System.IO.Tests
Assert.InRange(fi.CreationTimeUtc, before, fi.LastWriteTimeUtc);
}
[Fact]
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotInAppContainer))] // Can't read root in appcontainer
[PlatformSpecific(TestPlatforms.Windows)]
public void PageFileHasTimes()
{