private unsafe void SetAccessOrWriteTime(string path, DateTimeOffset time, bool isAccessTime) { // force a refresh so that we have an up-to-date times for values not being overwritten _fileStatusInitialized = -1; EnsureStatInitialized(path); // we use utimes()/utimensat() to set the accessTime and writeTime Interop.Sys.TimeSpec *buf = stackalloc Interop.Sys.TimeSpec[2]; long seconds = time.ToUnixTimeSeconds(); const long TicksPerMillisecond = 10000; const long TicksPerSecond = TicksPerMillisecond * 1000; long nanoseconds = (time.UtcDateTime.Ticks - DateTimeOffset.UnixEpoch.Ticks - seconds * TicksPerSecond) * NanosecondsPerTick; if (isAccessTime) { buf[0].TvSec = seconds; buf[0].TvNsec = nanoseconds; buf[1].TvSec = _fileStatus.MTime; buf[1].TvNsec = _fileStatus.MTimeNsec; } else { buf[0].TvSec = _fileStatus.ATime; buf[0].TvNsec = _fileStatus.ATimeNsec; buf[1].TvSec = seconds; buf[1].TvNsec = nanoseconds; } Interop.CheckIo(Interop.Sys.UTimensat(path, buf), path, InitiallyDirectory); _fileStatusInitialized = -1; }
private unsafe void SetAccessOrWriteTimeCore(string path, DateTimeOffset time, bool isAccessTime, bool checkCreationTime) { // This api is used to set creation time on non OSX platforms, and as a fallback for OSX platforms. // The reason why we use it to set 'creation time' is the below comment: // Unix provides APIs to update the last access time (atime) and last modification time (mtime). // There is no API to update the CreationTime. // Some platforms (e.g. Linux) don't store a creation time. On those platforms, the creation time // is synthesized as the oldest of last status change time (ctime) and last modification time (mtime). // We update the LastWriteTime (mtime). // This triggers a metadata change for FileSystemWatcher NotifyFilters.CreationTime. // Updating the mtime, causes the ctime to be set to 'now'. So, on platforms that don't store a // CreationTime, GetCreationTime will return the value that was previously set (when that value // wasn't in the future). // force a refresh so that we have an up-to-date times for values not being overwritten InvalidateCaches(); EnsureCachesInitialized(path); // we use utimes()/utimensat() to set the accessTime and writeTime Interop.Sys.TimeSpec *buf = stackalloc Interop.Sys.TimeSpec[2]; long seconds = time.ToUnixTimeSeconds(); long nanoseconds = UnixTimeSecondsToNanoseconds(time, seconds); #if TARGET_BROWSER buf[0].TvSec = seconds; buf[0].TvNsec = nanoseconds; buf[1].TvSec = seconds; buf[1].TvNsec = nanoseconds; #else if (isAccessTime) { buf[0].TvSec = seconds; buf[0].TvNsec = nanoseconds; buf[1].TvSec = _fileCache.MTime; buf[1].TvNsec = _fileCache.MTimeNsec; } else { buf[0].TvSec = _fileCache.ATime; buf[0].TvNsec = _fileCache.ATimeNsec; buf[1].TvSec = seconds; buf[1].TvNsec = nanoseconds; } #endif Interop.CheckIo(Interop.Sys.UTimensat(path, buf), path, InitiallyDirectory); // On OSX-like platforms, when the modification time is less than the creation time (including // when the modification time is already less than but access time is being set), the creation // time is set to the modification time due to the api we're currently using; this is not // desirable behaviour since it is inconsistent with windows behaviour and is not logical to // the programmer (ie. we'd have to document it), so these api calls revert the creation time // when it shouldn't be set (since we're setting modification time and access time here). // checkCreationTime is only true on OSX-like platforms. // allowFallbackToLastWriteTime is ignored on non OSX-like platforms. bool updateCreationTime = checkCreationTime && (_fileCache.Flags & Interop.Sys.FileStatusFlags.HasBirthTime) != 0 && (buf[1].TvSec < _fileCache.BirthTime || (buf[1].TvSec == _fileCache.BirthTime && buf[1].TvNsec < _fileCache.BirthTimeNsec)); InvalidateCaches(); if (updateCreationTime) { Interop.Error error = SetCreationTimeCore(path, _fileCache.BirthTime, _fileCache.BirthTimeNsec); if (error != Interop.Error.SUCCESS && error != Interop.Error.ENOTSUP) { Interop.CheckIo(error, path, InitiallyDirectory); } } }