Skip to content

Commit 3975094

Browse files
committed
Support sub-second file time-stamps on MS-Windows
* nt/inc/sys/stat.h (struct stat): New members for nsec part of file times. * lib-src/ntlib.c (convert_time): * src/w32.c (convert_time): Accept an additional argument TIME_NSEC and set it to the sub-second part of time. All callers changed.
1 parent 9df2074 commit 3975094

File tree

3 files changed

+65
-24
lines changed

3 files changed

+65
-24
lines changed

lib-src/ntlib.c

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
3030
#include <direct.h>
3131
#include <sys/types.h>
3232
#include <sys/stat.h>
33+
#include <math.h>
3334
#include <errno.h>
3435
#include <ctype.h>
3536
#include <sys/timeb.h>
@@ -256,7 +257,7 @@ static long double utc_base;
256257
static int init = 0;
257258

258259
static time_t
259-
convert_time (FILETIME ft)
260+
convert_time (FILETIME ft, int *time_nsec)
260261
{
261262
long double ret;
262263

@@ -266,7 +267,8 @@ convert_time (FILETIME ft)
266267
ret = (long double) ft.dwHighDateTime
267268
* 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
268269
ret -= utc_base;
269-
return (time_t) (ret * 1e-7L);
270+
*time_nsec = (int) fmodl (ret, 1.0e7L) * 100;
271+
return (time_t) (ret * 1.0e-7L);
270272
}
271273

272274
static int
@@ -373,11 +375,19 @@ stat (const char * path, struct stat * buf)
373375
buf->st_size += wfd.nFileSizeLow;
374376

375377
/* Convert timestamps to Unix format. */
376-
buf->st_mtime = convert_time (wfd.ftLastWriteTime);
377-
buf->st_atime = convert_time (wfd.ftLastAccessTime);
378-
if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
379-
buf->st_ctime = convert_time (wfd.ftCreationTime);
380-
if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
378+
buf->st_mtime = convert_time (wfd.ftLastWriteTime, &buf->st_mtimensec);
379+
buf->st_atime = convert_time (wfd.ftLastAccessTime, &buf->st_atimensec);
380+
if (buf->st_atime == 0)
381+
{
382+
buf->st_atime = buf->st_mtime;
383+
buf->st_atimensec = buf->st_mtimensec;
384+
}
385+
buf->st_ctime = convert_time (wfd.ftCreationTime, &buf->st_ctimensec);
386+
if (buf->st_ctime == 0)
387+
{
388+
buf->st_ctime = buf->st_mtime;
389+
buf->st_ctimensec = buf->st_mtimensec;
390+
}
381391

382392
/* determine rwx permissions */
383393
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
@@ -473,11 +483,19 @@ fstat (int desc, struct stat * buf)
473483
buf->st_size += info.nFileSizeLow;
474484

475485
/* Convert timestamps to Unix format. */
476-
buf->st_mtime = convert_time (info.ftLastWriteTime);
477-
buf->st_atime = convert_time (info.ftLastAccessTime);
478-
if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
479-
buf->st_ctime = convert_time (info.ftCreationTime);
480-
if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
486+
buf->st_mtime = convert_time (info.ftLastWriteTime, &buf->st_mtimensec);
487+
buf->st_atime = convert_time (info.ftLastAccessTime, &buf->st_atimensec);
488+
if (buf->st_atime == 0)
489+
{
490+
buf->st_atime = buf->st_mtime;
491+
buf->st_atimensec = buf->st_mtimensec;
492+
}
493+
buf->st_ctime = convert_time (info.ftCreationTime, &buf->st_ctimensec);
494+
if (buf->st_ctime == 0)
495+
{
496+
buf->st_ctime = buf->st_mtime;
497+
buf->st_ctimensec = buf->st_mtimensec;
498+
}
481499

482500
/* determine rwx permissions */
483501
if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)

nt/inc/sys/stat.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ struct stat {
108108
time_t st_ctime;
109109
char st_uname[260];
110110
char st_gname[260];
111+
int st_atimensec;
112+
int st_mtimensec;
113+
int st_ctimensec;
111114
};
112115

113116
/* These are here to avoid compiler warnings when using wchar.h. */

src/w32.c

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5076,9 +5076,10 @@ initialize_utc_base (void)
50765076
}
50775077

50785078
static time_t
5079-
convert_time (FILETIME ft)
5079+
convert_time (FILETIME ft, int *time_nsec)
50805080
{
50815081
ULONGLONG tmp;
5082+
time_t time_sec;
50825083

50835084
if (!init)
50845085
{
@@ -5090,7 +5091,10 @@ convert_time (FILETIME ft)
50905091
return 0;
50915092

50925093
FILETIME_TO_U64 (tmp, ft);
5093-
return (time_t) ((tmp - utc_base) / 10000000L);
5094+
tmp -= utc_base;
5095+
time_sec = (time_t) (tmp / 10000000L);
5096+
*time_nsec = (tmp - (ULONGLONG) time_sec * 10000000L) * 100L;
5097+
return time_sec;
50945098
}
50955099

50965100
static void
@@ -5707,11 +5711,19 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
57075711
buf->st_nlink = nlinks;
57085712

57095713
/* Convert timestamps to Unix format. */
5710-
buf->st_mtime = convert_time (wtime);
5711-
buf->st_atime = convert_time (atime);
5712-
if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5713-
buf->st_ctime = convert_time (ctime);
5714-
if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5714+
buf->st_mtime = convert_time (wtime, &buf->st_mtimensec);
5715+
buf->st_atime = convert_time (atime, &buf->st_atimensec);
5716+
if (buf->st_atime == 0)
5717+
{
5718+
buf->st_atime = buf->st_mtime;
5719+
buf->st_atimensec = buf->st_mtimensec;
5720+
}
5721+
buf->st_ctime = convert_time (ctime, &buf->st_ctimensec);
5722+
if (buf->st_ctime == 0)
5723+
{
5724+
buf->st_ctime = buf->st_mtime;
5725+
buf->st_ctimensec = buf->st_mtimensec;
5726+
}
57155727

57165728
/* determine rwx permissions */
57175729
if (is_a_symlink && !follow_symlinks)
@@ -5853,11 +5865,19 @@ fstat (int desc, struct stat * buf)
58535865
buf->st_size += info.nFileSizeLow;
58545866

58555867
/* Convert timestamps to Unix format. */
5856-
buf->st_mtime = convert_time (info.ftLastWriteTime);
5857-
buf->st_atime = convert_time (info.ftLastAccessTime);
5858-
if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5859-
buf->st_ctime = convert_time (info.ftCreationTime);
5860-
if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5868+
buf->st_mtime = convert_time (info.ftLastWriteTime, &buf->st_mtimensec);
5869+
buf->st_atime = convert_time (info.ftLastAccessTime, &buf->st_atimensec);
5870+
if (buf->st_atime == 0)
5871+
{
5872+
buf->st_atime = buf->st_mtime;
5873+
buf->st_atimensec = buf->st_mtimensec;
5874+
}
5875+
buf->st_ctime = convert_time (info.ftCreationTime, &buf->st_ctimensec);
5876+
if (buf->st_ctime == 0)
5877+
{
5878+
buf->st_ctime = buf->st_mtime;
5879+
buf->st_ctimensec = buf->st_mtimensec;
5880+
}
58615881

58625882
/* determine rwx permissions */
58635883
if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)

0 commit comments

Comments
 (0)