From 7233bb140b70f81df02fa559de358d2f9880fa9b Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Thu, 9 Dec 2021 15:29:55 -0700 Subject: [PATCH 1/3] fix datetime --- .../Windows/Kernel32/Interop.FileOperations.cs | 3 ++- .../tests/Base/BaseGetSetTimes.cs | 16 ++++++++++++++-- .../tests/Directory/GetSetTimes.cs | 4 +++- .../tests/DirectoryInfo/GetSetTimes.cs | 4 +++- .../tests/File/GetSetTimes.cs | 10 ++++++++-- .../tests/FileInfo/GetSetTimes.cs | 8 +++++++- .../src/System/IO/FileSystem.Windows.cs | 6 +++--- 7 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FileOperations.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FileOperations.cs index cc4896c1c52e48..c43b4fd19d21d2 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FileOperations.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FileOperations.cs @@ -23,7 +23,8 @@ internal static partial class FileOperations internal const int FILE_FLAG_OVERLAPPED = 0x40000000; internal const int FILE_LIST_DIRECTORY = 0x0001; - } + internal const int FILE_WRITE_ATTRIBUTES = 0x100; + } } } diff --git a/src/libraries/System.IO.FileSystem/tests/Base/BaseGetSetTimes.cs b/src/libraries/System.IO.FileSystem/tests/Base/BaseGetSetTimes.cs index 23c627033b1c6f..04dbdc832de11c 100644 --- a/src/libraries/System.IO.FileSystem/tests/Base/BaseGetSetTimes.cs +++ b/src/libraries/System.IO.FileSystem/tests/Base/BaseGetSetTimes.cs @@ -21,7 +21,9 @@ public abstract class BaseGetSetTimes : FileSystemTest protected static bool LowTemporalResolution => PlatformDetection.IsBrowser || isHFS; protected static bool HighTemporalResolution => !LowTemporalResolution; - protected abstract T GetExistingItem(); + protected abstract bool CanBeReadOnly { get; } + + protected abstract T GetExistingItem(bool readOnly = false); protected abstract T GetMissingItem(); protected abstract T CreateSymlink(string path, string pathToTarget); @@ -84,6 +86,16 @@ public void SettingUpdatesProperties() SettingUpdatesPropertiesCore(item); } + [Fact] + public void SettingUpdatesPropertiesWhenReadOnly() + { + if (!CanBeReadOnly) + return; // directories can't be read only, so automatic pass + + T item = GetExistingItem(readOnly: true); + SettingUpdatesPropertiesCore(item); + } + [ConditionalTheory(typeof(MountHelper), nameof(MountHelper.CanCreateSymbolicLinks))] [PlatformSpecific(~TestPlatforms.Browser)] // Browser is excluded as it doesn't support symlinks [InlineData(false)] @@ -164,7 +176,7 @@ public void SettingUpdatesPropertiesAfterAnother() TimeFunction function1 = functions.x; TimeFunction function2 = functions.y; bool reverse = functions.reverse; - + // Checking that milliseconds are not dropped after setter. DateTime dt1 = new DateTime(2002, 12, 1, 12, 3, 3, LowTemporalResolution ? 0 : 321, DateTimeKind.Utc); DateTime dt2 = new DateTime(2001, 12, 1, 12, 3, 3, LowTemporalResolution ? 0 : 321, DateTimeKind.Utc); diff --git a/src/libraries/System.IO.FileSystem/tests/Directory/GetSetTimes.cs b/src/libraries/System.IO.FileSystem/tests/Directory/GetSetTimes.cs index 698fbd1d67ce08..c71832b8f76eb9 100644 --- a/src/libraries/System.IO.FileSystem/tests/Directory/GetSetTimes.cs +++ b/src/libraries/System.IO.FileSystem/tests/Directory/GetSetTimes.cs @@ -7,7 +7,9 @@ namespace System.IO.Tests { public class Directory_GetSetTimes : StaticGetSetTimes { - protected override string GetExistingItem() => Directory.CreateDirectory(GetTestFilePath()).FullName; + protected override bool CanBeReadOnly => false; + + protected override string GetExistingItem(bool _) => Directory.CreateDirectory(GetTestFilePath()).FullName; protected override string CreateSymlink(string path, string pathToTarget) => Directory.CreateSymbolicLink(path, pathToTarget).FullName; diff --git a/src/libraries/System.IO.FileSystem/tests/DirectoryInfo/GetSetTimes.cs b/src/libraries/System.IO.FileSystem/tests/DirectoryInfo/GetSetTimes.cs index 795a8750e49bf2..7a52964f4c5af2 100644 --- a/src/libraries/System.IO.FileSystem/tests/DirectoryInfo/GetSetTimes.cs +++ b/src/libraries/System.IO.FileSystem/tests/DirectoryInfo/GetSetTimes.cs @@ -7,7 +7,9 @@ namespace System.IO.Tests { public class DirectoryInfo_GetSetTimes : InfoGetSetTimes { - protected override DirectoryInfo GetExistingItem() => Directory.CreateDirectory(GetTestFilePath()); + protected override bool CanBeReadOnly => false; + + protected override DirectoryInfo GetExistingItem(bool _) => Directory.CreateDirectory(GetTestFilePath()); protected override DirectoryInfo GetMissingItem() => new DirectoryInfo(GetTestFilePath()); diff --git a/src/libraries/System.IO.FileSystem/tests/File/GetSetTimes.cs b/src/libraries/System.IO.FileSystem/tests/File/GetSetTimes.cs index 50dcf0990a0eb6..18d93465e3a3a3 100644 --- a/src/libraries/System.IO.FileSystem/tests/File/GetSetTimes.cs +++ b/src/libraries/System.IO.FileSystem/tests/File/GetSetTimes.cs @@ -11,14 +11,20 @@ namespace System.IO.Tests { public class File_GetSetTimes : StaticGetSetTimes { + protected override bool CanBeReadOnly => true; + // OSX has the limitation of setting upto 2262-04-11T23:47:16 (long.Max) date. // 32bit Unix has time_t up to ~ 2038. private static bool SupportsLongMaxDateTime => PlatformDetection.IsWindows || (!PlatformDetection.Is32BitProcess && !PlatformDetection.IsOSXLike); - protected override string GetExistingItem() + protected override string GetExistingItem(bool readOnly = false) { string path = GetTestFilePath(); File.Create(path).Dispose(); + + if (readOnly) + File.SetAttributes(path, FileAttributes.ReadOnly); + return path; } @@ -120,7 +126,7 @@ public void PageFileHasTimes() }); } } - + [Fact] public void SetLastWriteTimeTicks() { diff --git a/src/libraries/System.IO.FileSystem/tests/FileInfo/GetSetTimes.cs b/src/libraries/System.IO.FileSystem/tests/FileInfo/GetSetTimes.cs index 0559edc669e5d0..0e13733e31b7a3 100644 --- a/src/libraries/System.IO.FileSystem/tests/FileInfo/GetSetTimes.cs +++ b/src/libraries/System.IO.FileSystem/tests/FileInfo/GetSetTimes.cs @@ -10,10 +10,16 @@ namespace System.IO.Tests { public class FileInfo_GetSetTimes : InfoGetSetTimes { - protected override FileInfo GetExistingItem() + protected override bool CanBeReadOnly => true; + + protected override FileInfo GetExistingItem(bool readOnly = false) { string path = GetTestFilePath(); File.Create(path).Dispose(); + + if (readOnly) + File.SetAttributes(path, FileAttributes.ReadOnly); + return new FileInfo(path); } diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs index 4e90b98a03fd74..f25847557a1226 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs @@ -182,7 +182,7 @@ public static void MoveFile(string sourceFullPath, string destFullPath, bool ove } } - private static SafeFileHandle OpenHandle(string fullPath, bool asDirectory) + private static SafeFileHandle OpenHandleToWriteAttributes(string fullPath, bool asDirectory) { string root = fullPath.Substring(0, PathInternal.GetRootLength(fullPath.AsSpan())); if (root == fullPath && root[1] == Path.VolumeSeparatorChar) @@ -199,7 +199,7 @@ private static SafeFileHandle OpenHandle(string fullPath, bool asDirectory) SafeFileHandle handle = Interop.Kernel32.CreateFile( fullPath, - Interop.Kernel32.GenericOperations.GENERIC_WRITE, + Interop.Kernel32.FileOperations.FILE_WRITE_ATTRIBUTES, FileShare.ReadWrite | FileShare.Delete, FileMode.Open, dwFlagsAndAttributes); @@ -425,7 +425,7 @@ private static unsafe void SetFileTime( long changeTime = -1, uint fileAttributes = 0) { - using (SafeFileHandle handle = OpenHandle(fullPath, asDirectory)) + using (SafeFileHandle handle = OpenHandleToWriteAttributes(fullPath, asDirectory)) { var basicInfo = new Interop.Kernel32.FILE_BASIC_INFO() { From d2c53b45233046f0c923dbb4e3320517042df547 Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Fri, 10 Dec 2021 10:18:50 -0700 Subject: [PATCH 2/3] ws --- src/libraries/System.IO.FileSystem/tests/File/GetSetTimes.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.IO.FileSystem/tests/File/GetSetTimes.cs b/src/libraries/System.IO.FileSystem/tests/File/GetSetTimes.cs index 18d93465e3a3a3..596a830649daec 100644 --- a/src/libraries/System.IO.FileSystem/tests/File/GetSetTimes.cs +++ b/src/libraries/System.IO.FileSystem/tests/File/GetSetTimes.cs @@ -126,7 +126,7 @@ public void PageFileHasTimes() }); } } - + [Fact] public void SetLastWriteTimeTicks() { From 463f536157a8f3c095b449dab020ff360a6245c1 Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Fri, 10 Dec 2021 11:42:53 -0700 Subject: [PATCH 3/3] CR feedback --- .../System.IO.FileSystem/tests/Base/BaseGetSetTimes.cs | 2 ++ src/libraries/System.IO.FileSystem/tests/File/GetSetTimes.cs | 2 ++ .../System.IO.FileSystem/tests/FileInfo/GetSetTimes.cs | 2 ++ .../System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs | 3 +-- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.IO.FileSystem/tests/Base/BaseGetSetTimes.cs b/src/libraries/System.IO.FileSystem/tests/Base/BaseGetSetTimes.cs index 04dbdc832de11c..c694a53161981f 100644 --- a/src/libraries/System.IO.FileSystem/tests/Base/BaseGetSetTimes.cs +++ b/src/libraries/System.IO.FileSystem/tests/Base/BaseGetSetTimes.cs @@ -90,7 +90,9 @@ public void SettingUpdatesProperties() public void SettingUpdatesPropertiesWhenReadOnly() { if (!CanBeReadOnly) + { return; // directories can't be read only, so automatic pass + } T item = GetExistingItem(readOnly: true); SettingUpdatesPropertiesCore(item); diff --git a/src/libraries/System.IO.FileSystem/tests/File/GetSetTimes.cs b/src/libraries/System.IO.FileSystem/tests/File/GetSetTimes.cs index 596a830649daec..936b7021ac2794 100644 --- a/src/libraries/System.IO.FileSystem/tests/File/GetSetTimes.cs +++ b/src/libraries/System.IO.FileSystem/tests/File/GetSetTimes.cs @@ -23,7 +23,9 @@ protected override string GetExistingItem(bool readOnly = false) File.Create(path).Dispose(); if (readOnly) + { File.SetAttributes(path, FileAttributes.ReadOnly); + } return path; } diff --git a/src/libraries/System.IO.FileSystem/tests/FileInfo/GetSetTimes.cs b/src/libraries/System.IO.FileSystem/tests/FileInfo/GetSetTimes.cs index 0e13733e31b7a3..78c2781eac6613 100644 --- a/src/libraries/System.IO.FileSystem/tests/FileInfo/GetSetTimes.cs +++ b/src/libraries/System.IO.FileSystem/tests/FileInfo/GetSetTimes.cs @@ -18,7 +18,9 @@ protected override FileInfo GetExistingItem(bool readOnly = false) File.Create(path).Dispose(); if (readOnly) + { File.SetAttributes(path, FileAttributes.ReadOnly); + } return new FileInfo(path); } diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs index f25847557a1226..3436a7f1428f60 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs @@ -184,8 +184,7 @@ public static void MoveFile(string sourceFullPath, string destFullPath, bool ove private static SafeFileHandle OpenHandleToWriteAttributes(string fullPath, bool asDirectory) { - string root = fullPath.Substring(0, PathInternal.GetRootLength(fullPath.AsSpan())); - if (root == fullPath && root[1] == Path.VolumeSeparatorChar) + if (fullPath.Length == PathInternal.GetRootLength(fullPath) && fullPath[1] == Path.VolumeSeparatorChar) { // intentionally not fullpath, most upstack public APIs expose this as path. throw new ArgumentException(SR.Arg_PathIsVolume, "path");