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).
This commit is contained in:
Руслан Ижбулатов 2020-01-19 14:21:33 +00:00
parent 0d3d3e1d84
commit 4fec9af198
3 changed files with 37 additions and 19 deletions

View File

@ -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,

View File

@ -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

View File

@ -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;