diff options
author | Руслан Ижбулатов <lrn1986@gmail.com> | 2020-01-19 14:21:33 +0000 |
---|---|---|
committer | Руслан Ижбулатов <lrn1986@gmail.com> | 2020-01-30 01:27:53 +0000 |
commit | 4fec9af198420720f0385e2e39fb52b1862a1b3f (patch) | |
tree | 26790548f69d494ed2ff6f0bdd1b0d40b4f929bb | |
parent | 0d3d3e1d8410a202940946fc971dec743695a8e9 (diff) | |
download | glib-4fec9af198420720f0385e2e39fb52b1862a1b3f.tar.gz |
W32: support nanoseconds in stat timestamps
Expand our private statbuf structure with st_mtim, st_atim and st_ctim
fields, which are structs that contain tv_sec and tv_nsec fields,
representing a timestamp with 1-second precision (same value as st_mtime, st_atime
and st_ctime) and a fraction of a second (in nanoseconds) that adds nanosecond
precision to the timestamp.
Because FILEETIME only has 100ns precision, this won't be very precise,
but it's better than nothing.
The private _g_win32_filetime_to_unix_time() function is modified
to also return the nanoseconds-remainder along with the seconds timestamp.
The timestamp struct that we're using is named gtimespec to ensure that
it doesn't clash with any existing timespec structs (MinGW-w64 has one,
MSVC doesn't).
-rw-r--r-- | gio/glocalfileinfo.c | 9 | ||||
-rw-r--r-- | glib/gstdio.c | 33 | ||||
-rw-r--r-- | glib/gstdioprivate.h | 14 |
3 files changed, 37 insertions, 19 deletions
diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c index 52455672a..866ff8db3 100644 --- a/gio/glocalfileinfo.c +++ b/gio/glocalfileinfo.c @@ -126,7 +126,7 @@ _g_local_file_info_create_etag (GLocalFileStat *statbuf) sec = statbuf->st_mtime; #if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC) usec = statbuf->st_mtimensec / 1000; -#elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) +#elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) || defined (G_OS_WIN32) usec = statbuf->st_mtim.tv_nsec / 1000; #else usec = 0; @@ -1004,14 +1004,14 @@ set_info_from_stat (GFileInfo *info, _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED, statbuf->st_mtime); #if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC) _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_USEC, statbuf->st_mtimensec / 1000); -#elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) +#elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) || defined (G_OS_WIN32) _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_USEC, statbuf->st_mtim.tv_nsec / 1000); #endif _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS, statbuf->st_atime); #if defined (HAVE_STRUCT_STAT_ST_ATIMENSEC) _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_USEC, statbuf->st_atimensec / 1000); -#elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC) +#elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC) || defined (G_OS_WIN32) _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_USEC, statbuf->st_atim.tv_nsec / 1000); #endif @@ -1040,7 +1040,8 @@ set_info_from_stat (GFileInfo *info, #elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIM) _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtim); #elif defined (G_OS_WIN32) - _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_ctime); + _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_ctim.tv_sec); + _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC, statbuf->st_ctim.tv_nsec / 1000); #endif if (_g_file_attribute_matcher_matches_id (attribute_matcher, diff --git a/glib/gstdio.c b/glib/gstdio.c index d950d2d54..4d6404884 100644 --- a/glib/gstdio.c +++ b/glib/gstdio.c @@ -168,7 +168,8 @@ _g_win32_fix_mode (wchar_t *mode) * of a signed 64-bit integer (can be negative). */ static gint64 -_g_win32_filetime_to_unix_time (FILETIME *ft) +_g_win32_filetime_to_unix_time (const FILETIME *ft, + gint32 *nsec) { gint64 result; /* 1 unit of FILETIME is 100ns */ @@ -179,7 +180,12 @@ _g_win32_filetime_to_unix_time (FILETIME *ft) const gint64 filetime_unix_epoch_offset = 116444736000000000; result = ((gint64) ft->dwLowDateTime) | (((gint64) ft->dwHighDateTime) << 32); - return (result - filetime_unix_epoch_offset) / hundreds_of_usec_per_sec; + result -= filetime_unix_epoch_offset; + + if (nsec) + *nsec = (result % hundreds_of_usec_per_sec) * 100; + + return result / hundreds_of_usec_per_sec; } # ifdef _MSC_VER @@ -206,10 +212,10 @@ _g_win32_filetime_to_unix_time (FILETIME *ft) * Tries to reproduce the behaviour and quirks of MS C runtime stat(). */ static int -_g_win32_fill_statbuf_from_handle_info (const wchar_t *filename, - const wchar_t *filename_target, - BY_HANDLE_FILE_INFORMATION *handle_info, - struct __stat64 *statbuf) +_g_win32_fill_statbuf_from_handle_info (const wchar_t *filename, + const wchar_t *filename_target, + const BY_HANDLE_FILE_INFORMATION *handle_info, + struct __stat64 *statbuf) { wchar_t drive_letter_w = 0; size_t drive_letter_size = MB_CUR_MAX; @@ -291,9 +297,9 @@ _g_win32_fill_statbuf_from_handle_info (const wchar_t *filename, statbuf->st_nlink = handle_info->nNumberOfLinks; statbuf->st_uid = statbuf->st_gid = 0; statbuf->st_size = (((guint64) handle_info->nFileSizeHigh) << 32) | handle_info->nFileSizeLow; - statbuf->st_ctime = _g_win32_filetime_to_unix_time (&handle_info->ftCreationTime); - statbuf->st_mtime = _g_win32_filetime_to_unix_time (&handle_info->ftLastWriteTime); - statbuf->st_atime = _g_win32_filetime_to_unix_time (&handle_info->ftLastAccessTime); + statbuf->st_ctime = _g_win32_filetime_to_unix_time (&handle_info->ftCreationTime, NULL); + statbuf->st_mtime = _g_win32_filetime_to_unix_time (&handle_info->ftLastWriteTime, NULL); + statbuf->st_atime = _g_win32_filetime_to_unix_time (&handle_info->ftLastAccessTime, NULL); return 0; } @@ -320,9 +326,12 @@ _g_win32_fill_privatestat (const struct __stat64 *statbuf, buf->reparse_tag = reparse_tag; - buf->st_ctime = statbuf->st_ctime; - buf->st_atime = statbuf->st_atime; - buf->st_mtime = statbuf->st_mtime; + buf->st_ctim.tv_sec = _g_win32_filetime_to_unix_time (&handle_info->ftCreationTime, &buf->st_ctim.tv_nsec); + buf->st_mtim.tv_sec = _g_win32_filetime_to_unix_time (&handle_info->ftLastWriteTime, &buf->st_mtim.tv_nsec); + buf->st_atim.tv_sec = _g_win32_filetime_to_unix_time (&handle_info->ftLastAccessTime, &buf->st_atim.tv_nsec); + buf->st_ctime = buf->st_ctim.tv_sec; + buf->st_mtime = buf->st_mtim.tv_sec; + buf->st_atime = buf->st_atim.tv_sec; } /* Read the link data from a symlink/mountpoint represented diff --git a/glib/gstdioprivate.h b/glib/gstdioprivate.h index 71565388a..5583cdd3e 100644 --- a/glib/gstdioprivate.h +++ b/glib/gstdioprivate.h @@ -23,6 +23,11 @@ G_BEGIN_DECLS #if defined (G_OS_WIN32) +typedef struct _gtimespec { + guint64 tv_sec; + guint32 tv_nsec; +} gtimespec; + struct _GWin32PrivateStat { guint32 volume_serial; @@ -38,9 +43,12 @@ struct _GWin32PrivateStat guint16 st_gid; guint32 st_nlink; guint64 st_size; - guint64 st_ctime; - guint64 st_atime; - guint64 st_mtime; + gint64 st_ctime; + gint64 st_atime; + gint64 st_mtime; + gtimespec st_ctim; + gtimespec st_atim; + gtimespec st_mtim; }; typedef struct _GWin32PrivateStat GWin32PrivateStat; |