summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorРуслан Ижбулатов <lrn1986@gmail.com>2020-01-19 14:21:33 +0000
committerРуслан Ижбулатов <lrn1986@gmail.com>2020-01-30 01:27:53 +0000
commit4fec9af198420720f0385e2e39fb52b1862a1b3f (patch)
tree26790548f69d494ed2ff6f0bdd1b0d40b4f929bb
parent0d3d3e1d8410a202940946fc971dec743695a8e9 (diff)
downloadglib-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.c9
-rw-r--r--glib/gstdio.c33
-rw-r--r--glib/gstdioprivate.h14
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;