-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Expand file tree
/
Copy pathFileStatus.SetTimes.OSX.cs
More file actions
73 lines (61 loc) · 3.35 KB
/
FileStatus.SetTimes.OSX.cs
File metadata and controls
73 lines (61 loc) · 3.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace System.IO
{
internal partial struct FileStatus
{
internal void SetCreationTime(string path, DateTimeOffset time, bool asDirectory)
=> SetCreationTime(handle: null, path, time, asDirectory);
internal void SetCreationTime(SafeFileHandle handle, DateTimeOffset time, bool asDirectory)
=> SetCreationTime(handle, handle.Path, time, asDirectory);
private void SetCreationTime(SafeFileHandle? handle, string? path, DateTimeOffset time, bool asDirectory)
{
// Either `handle` or `path` must not be null
Debug.Assert(handle is not null || path is not null);
// Try to set the attribute on the file system entry using setattrlist,
// if we get ENOTSUP then it means that "The volume does not support
// setattrlist()", so we fall back to the method used on other unix
// platforms, otherwise we throw an error if we get one, or invalidate
// the cache if successful because otherwise it has invalid information.
// Note: the unix fallback implementation doesn't have a test as we are
// yet to determine which volume types it can fail on, so modify with
// great care.
long seconds = time.ToUnixTimeSeconds();
long nanoseconds = UnixTimeSecondsToNanoseconds(time, seconds);
Interop.Error error = SetCreationTimeCore(handle, path, seconds, nanoseconds);
if (error == Interop.Error.SUCCESS)
{
InvalidateCaches();
}
else if (error == Interop.Error.ENOTSUP)
{
SetAccessOrWriteTimeCore(handle, path, time, isAccessTime: false, checkCreationTime: false, asDirectory);
}
else
{
Interop.CheckIo(error, path, asDirectory);
}
}
private static unsafe Interop.Error SetCreationTimeCore(SafeFileHandle? handle, string? path, long seconds, long nanoseconds)
{
Debug.Assert(handle is not null || path is not null);
Interop.Sys.TimeSpec timeSpec = default;
timeSpec.TvSec = seconds;
timeSpec.TvNsec = nanoseconds;
Interop.libc.AttrList attrList = default;
attrList.bitmapCount = Interop.libc.AttrList.ATTR_BIT_MAP_COUNT;
attrList.commonAttr = Interop.libc.AttrList.ATTR_CMN_CRTIME;
int result = handle is not null
? Interop.libc.fsetattrlist(handle, &attrList, &timeSpec, sizeof(Interop.Sys.TimeSpec), new CULong(Interop.libc.FSOPT_NOFOLLOW))
: Interop.libc.setattrlist(path!, &attrList, &timeSpec, sizeof(Interop.Sys.TimeSpec), new CULong(Interop.libc.FSOPT_NOFOLLOW));
return result == 0 ?
Interop.Error.SUCCESS :
Interop.Sys.GetLastErrorInfo().Error;
}
private void SetAccessOrWriteTime(SafeFileHandle? handle, string? path, DateTimeOffset time, bool isAccessTime, bool asDirectory) =>
SetAccessOrWriteTimeCore(handle, path, time, isAccessTime, checkCreationTime: true, asDirectory);
}
}