internal const int FILE_FLAG_OVERLAPPED = 0x40000000;
internal const int FILE_LIST_DIRECTORY = 0x0001;
- }
+ internal const int FILE_WRITE_ATTRIBUTES = 0x100;
+ }
}
}
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 string GetItemPath(T item);
public DateTimeKind Kind => Item3;
}
- [Fact]
- public void SettingUpdatesProperties()
+ private void SettingUpdatesPropertiesCore(T item)
{
- T item = GetExistingItem();
-
Assert.All(TimeFunctions(requiresRoundtripping: true), (function) =>
{
// Checking that milliseconds are not dropped after setter.
}
[Fact]
+ public void SettingUpdatesProperties()
+ {
+ T item = GetExistingItem();
+ 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);
+ }
+
+ [Fact]
public void CanGetAllTimesAfterCreation()
{
DateTime beforeTime = DateTime.UtcNow.AddSeconds(-3);
{
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;
public override IEnumerable<TimeFunction> TimeFunctions(bool requiresRoundtripping = false)
{
{
public class DirectoryInfo_GetSetTimes : InfoGetSetTimes<DirectoryInfo>
{
- 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());
{
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;
}
{
public class FileInfo_GetSetTimes : InfoGetSetTimes<FileInfo>
{
- 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);
}
}
}
- 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)
+ if (fullPath.Length == PathInternal.GetRootLength(fullPath.AsSpan()) && fullPath[1] == Path.VolumeSeparatorChar)
{
// intentionally not fullpath, most upstack public APIs expose this as path.
throw new ArgumentException(SR.Arg_PathIsVolume, "path");
SafeFileHandle handle = Interop.Kernel32.CreateFile(
fullPath,
- Interop.Kernel32.GenericOperations.GENERIC_WRITE,
+ Interop.Kernel32.FileOperations.FILE_WRITE_ATTRIBUTES,
FileShare.ReadWrite | FileShare.Delete,
FileMode.Open,
asDirectory ? Interop.Kernel32.FileOperations.FILE_FLAG_BACKUP_SEMANTICS : 0);
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()
{