[glib: 1/5] W32: support nanoseconds in stat timestamps



commit 4fec9af198420720f0385e2e39fb52b1862a1b3f
Author: Руслан Ижбулатов <lrn1986 gmail com>
Date:   Sun Jan 19 14:21:33 2020 +0000

    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).

 gio/glocalfileinfo.c |  9 +++++----
 glib/gstdio.c        | 33 +++++++++++++++++++++------------
 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;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]