From c3f0469b2bc341ae7068529d2bad68b97da07306 Mon Sep 17 00:00:00 2001 From: Vladimir Panteleev Date: Wed, 16 Mar 2016 20:57:49 +0000 Subject: [PATCH] fix Issue 15803 - std.file should support sub-second file time precision on POSIX --- std/file.d | 65 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/std/file.d b/std/file.d index 5b68aff34..c4eb20d7e 100644 --- a/std/file.d +++ b/std/file.d @@ -822,6 +822,28 @@ unittest } +// Reads a time field from a stat_t with full precision. +version(Posix) +private SysTime statTimeToStdTime(char which)(ref stat_t statbuf) +{ + auto unixTime = mixin(`statbuf.st_` ~ which ~ `time`); + long stdTime = unixTimeToStdTime(unixTime); + + static if (is(typeof(mixin(`statbuf.st_` ~ which ~ `tim`)))) + stdTime += mixin(`statbuf.st_` ~ which ~ `tim.tv_nsec`) / 100; + else + static if (is(typeof(mixin(`statbuf.st_` ~ which ~ `timensec`)))) + stdTime += mixin(`statbuf.st_` ~ which ~ `timensec`) / 100; + else + static if (is(typeof(mixin(`statbuf.st_` ~ which ~ `time_nsec`)))) + stdTime += mixin(`statbuf.st_` ~ which ~ `time_nsec`) / 100; + else + static if (is(typeof(mixin(`statbuf.__st_` ~ which ~ `timensec`)))) + stdTime += mixin(`statbuf.__st_` ~ which ~ `timensec`) / 100; + + return SysTime(stdTime); +} + /++ Get the access and modified times of file or folder $(D name). @@ -863,8 +885,8 @@ void getTimes(R)(R name, string names = null; cenforce(trustedStat(namez, statbuf) == 0, names, namez); - accessTime = SysTime(unixTimeToStdTime(statbuf.st_atime)); - modificationTime = SysTime(unixTimeToStdTime(statbuf.st_mtime)); + accessTime = statTimeToStdTime!'a'(statbuf); + modificationTime = statTimeToStdTime!'m'(statbuf); } } @@ -1217,7 +1239,7 @@ SysTime timeLastModified(R)(R name) string names = null; cenforce(trustedStat(namez, statbuf) == 0, names, namez); - return SysTime(unixTimeToStdTime(statbuf.st_mtime)); + return statTimeToStdTime!'m'(statbuf); } } @@ -1288,7 +1310,7 @@ SysTime timeLastModified(R)(R name, SysTime returnIfMissing) return trustedStat(namez, statbuf) != 0 ? returnIfMissing : - SysTime(unixTimeToStdTime(statbuf.st_mtime)); + statTimeToStdTime!'m'(statbuf); } } @@ -1312,6 +1334,35 @@ unittest } +// Tests sub-second precision of querying file times. +// Should pass on most modern systems running on modern filesystems. +// Exceptions: +// - FreeBSD, where one would need to first set the +// vfs.timestamp_precision sysctl to a value greater than zero. +// - OS X, where the native filesystem (HFS+) stores filesystem +// timestamps with 1-second precision. +version (FreeBSD) {} else +version (OSX) {} else +unittest +{ + import core.thread; + + if(exists(deleteme)) + remove(deleteme); + + SysTime lastTime; + foreach (n; 0..3) + { + write(deleteme, "a"); + auto time = timeLastModified(deleteme); + remove(deleteme); + assert(time != lastTime); + lastTime = time; + Thread.sleep(10.msecs); + } +} + + /** * Determine whether the given file (or directory) exists. * Params: @@ -2844,21 +2895,21 @@ else version(Posix) { _ensureStatDone(); - return SysTime(unixTimeToStdTime(_statBuf.st_ctime)); + return statTimeToStdTime!'c'(_statBuf); } @property SysTime timeLastAccessed() { _ensureStatDone(); - return SysTime(unixTimeToStdTime(_statBuf.st_ctime)); + return statTimeToStdTime!'a'(_statBuf); } @property SysTime timeLastModified() { _ensureStatDone(); - return SysTime(unixTimeToStdTime(_statBuf.st_mtime)); + return statTimeToStdTime!'m'(_statBuf); } @property uint attributes()