From 0feee5b670c66ce6e60851820ecda84722c88f60 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Wed, 28 Jun 2023 17:32:25 +0100 Subject: [PATCH 1/3] glocalfileinfo: Fix incorrect use of struct statx.st_mtimensec on Android MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `GLocalFileStat` is a platform-specific abstraction around `struct stat` or `struct statx`. If `struct statx` is available, it will use that by preference as it has more features. `glocalfileinfo.c` was, in some places, incorrectly accessing the fields of `GLocalFileStat` directly rather than through its `_g_stat_*()` getters. While it correctly accounted for the platform-specific differences between `st_mtimensec` and `st_mtim.tv_nsec`, it hadn’t been updated to deal with `stx_mtime`. On Android, `st_mtimensec` is defined as a fallback for `st_mtim.tv_nsec` (even though it doesn’t need to be). This caused GLib to take the `st_mtimensec` code path rather than the `stx_mtime` code path, and hence try to dereference `st_mtim` in a `struct statx`. Fix that by correctly using the `_g_stat_*()` getters consistently. Signed-off-by: Philip Withnall Fixes: #3039 --- gio/glocalfileinfo.c | 39 ++++----------------------------------- gio/glocalfileinfo.h | 4 ++++ 2 files changed, 8 insertions(+), 35 deletions(-) diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c index bccad04b9..dc027e4dc 100644 --- a/gio/glocalfileinfo.c +++ b/gio/glocalfileinfo.c @@ -131,23 +131,9 @@ _g_local_file_info_create_etag (GLocalFileStat *statbuf) g_return_val_if_fail (_g_stat_has_field (statbuf, G_LOCAL_FILE_STAT_FIELD_MTIME), NULL); -#if defined (G_OS_WIN32) - sec = statbuf->st_mtim.tv_sec; - usec = statbuf->st_mtim.tv_nsec / 1000; - nsec = statbuf->st_mtim.tv_nsec; -#else sec = _g_stat_mtime (statbuf); -#if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC) - usec = statbuf->st_mtimensec / 1000; - nsec = statbuf->st_mtimensec; -#elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) usec = _g_stat_mtim_nsec (statbuf) / 1000; nsec = _g_stat_mtim_nsec (statbuf); -#else - usec = 0; - nsec = 0; -#endif -#endif return g_strdup_printf ("%lu:%lu:%lu", sec, usec, nsec); } @@ -1036,33 +1022,21 @@ set_info_from_stat (GFileInfo *info, #endif + _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED, _g_stat_mtime (statbuf)); + _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_USEC, _g_stat_mtim_nsec (statbuf) / 1000); + _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_NSEC, _g_stat_mtim_nsec (statbuf)); + #if defined (G_OS_WIN32) - _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED, statbuf->st_mtim.tv_sec); - _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_USEC, statbuf->st_mtim.tv_nsec / 1000); - _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_NSEC, statbuf->st_mtim.tv_nsec); _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS, statbuf->st_atim.tv_sec); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_USEC, statbuf->st_atim.tv_nsec / 1000); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_NSEC, statbuf->st_atim.tv_nsec); #else - _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED, _g_stat_mtime (statbuf)); -#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); - _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_NSEC, statbuf->st_mtimensec); -#elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) - _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_USEC, _g_stat_mtim_nsec (statbuf) / 1000); - _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_NSEC, _g_stat_mtim_nsec (statbuf)); -#endif if (_g_stat_has_field (statbuf, G_LOCAL_FILE_STAT_FIELD_ATIME)) { _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS, _g_stat_atime (statbuf)); -#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); - _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_NSEC, statbuf->st_atimensec); -#elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC) _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_USEC, _g_stat_atim_nsec (statbuf) / 1000); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_NSEC, _g_stat_atim_nsec (statbuf)); -#endif } #endif @@ -1073,14 +1047,9 @@ set_info_from_stat (GFileInfo *info, * Thank you, Microsoft! */ _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED, _g_stat_ctime (statbuf)); -#if defined (HAVE_STRUCT_STAT_ST_CTIMENSEC) - _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_USEC, statbuf->st_ctimensec / 1000); - _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_NSEC, statbuf->st_ctimensec); -#elif defined (HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC) _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_USEC, _g_stat_ctim_nsec (statbuf) / 1000); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_NSEC, _g_stat_ctim_nsec (statbuf)); #endif -#endif #if defined (HAVE_STATX) if (_g_stat_has_field (statbuf, G_LOCAL_FILE_STAT_FIELD_BTIME)) diff --git a/gio/glocalfileinfo.h b/gio/glocalfileinfo.h index 830122c3f..729d0d3a7 100644 --- a/gio/glocalfileinfo.h +++ b/gio/glocalfileinfo.h @@ -328,6 +328,10 @@ inline static time_t _g_stat_mtime (const GLocalFileStat *buf) { return b inline static guint32 _g_stat_atim_nsec (const GLocalFileStat *buf) { return buf->st_atim.tv_nsec; } inline static guint32 _g_stat_ctim_nsec (const GLocalFileStat *buf) { return buf->st_ctim.tv_nsec; } inline static guint32 _g_stat_mtim_nsec (const GLocalFileStat *buf) { return buf->st_mtim.tv_nsec; } +#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC) +inline static guint32 _g_stat_atim_nsec (const GLocalFileStat *buf) { return buf->st_atimensec; } +inline static guint32 _g_stat_ctim_nsec (const GLocalFileStat *buf) { return buf->st_ctimensec; } +inline static guint32 _g_stat_mtim_nsec (const GLocalFileStat *buf) { return buf->st_mtimensec; } #else inline static guint32 _g_stat_atim_nsec (const GLocalFileStat *buf) { return 0; } inline static guint32 _g_stat_ctim_nsec (const GLocalFileStat *buf) { return 0; } From 4a9c00fa942b1b760cd2bfa3874d4b80e7c1a62a Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Wed, 28 Jun 2023 17:49:45 +0100 Subject: [PATCH 2/3] glocalfileinfo: Delete some redundant code `_g_stat_has_field (statbuf, G_LOCAL_FILE_STAT_FIELD_ATIME)` will always return `TRUE` on Windows (since it uses a basic `struct stat`), so the platform-inspecific code is equivalent to the Windows-specific code. Signed-off-by: Philip Withnall --- gio/glocalfileinfo.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c index dc027e4dc..7c2524e8d 100644 --- a/gio/glocalfileinfo.c +++ b/gio/glocalfileinfo.c @@ -1026,19 +1026,12 @@ set_info_from_stat (GFileInfo *info, _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_USEC, _g_stat_mtim_nsec (statbuf) / 1000); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_NSEC, _g_stat_mtim_nsec (statbuf)); -#if defined (G_OS_WIN32) - _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS, statbuf->st_atim.tv_sec); - _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_USEC, statbuf->st_atim.tv_nsec / 1000); - _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_NSEC, statbuf->st_atim.tv_nsec); -#else - if (_g_stat_has_field (statbuf, G_LOCAL_FILE_STAT_FIELD_ATIME)) { _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS, _g_stat_atime (statbuf)); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_USEC, _g_stat_atim_nsec (statbuf) / 1000); _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_NSEC, _g_stat_atim_nsec (statbuf)); } -#endif #ifndef G_OS_WIN32 /* Microsoft uses st_ctime for file creation time, From f3baa03b4861d3d214fc289ca512e88fd36119eb Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Thu, 29 Jun 2023 17:36:40 +0200 Subject: [PATCH 3/3] glocalfileinfo: Fix GLocalFileStat getters on MinGW x86 For some reason, `time_t` is defined as being 32 bits wide on that platform, which causes truncation of the timestamps from `struct stat`. Avoid that problem by consistently using a 64-bit return value from the `struct stat` accessors. Helps: #3039 --- gio/glocalfileinfo.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gio/glocalfileinfo.h b/gio/glocalfileinfo.h index 729d0d3a7..b098b1980 100644 --- a/gio/glocalfileinfo.h +++ b/gio/glocalfileinfo.h @@ -316,13 +316,13 @@ inline static blkcnt_t _g_stat_blocks (const GLocalFileStat *buf) { return b #endif #ifndef G_OS_WIN32 -inline static time_t _g_stat_atime (const GLocalFileStat *buf) { return buf->st_atime; } -inline static time_t _g_stat_ctime (const GLocalFileStat *buf) { return buf->st_ctime; } -inline static time_t _g_stat_mtime (const GLocalFileStat *buf) { return buf->st_mtime; } +inline static guint64 _g_stat_atime (const GLocalFileStat *buf) { return buf->st_atime; } +inline static guint64 _g_stat_ctime (const GLocalFileStat *buf) { return buf->st_ctime; } +inline static guint64 _g_stat_mtime (const GLocalFileStat *buf) { return buf->st_mtime; } #else -inline static time_t _g_stat_atime (const GLocalFileStat *buf) { return buf->st_atim.tv_sec; } -inline static time_t _g_stat_ctime (const GLocalFileStat *buf) { return buf->st_ctim.tv_sec; } -inline static time_t _g_stat_mtime (const GLocalFileStat *buf) { return buf->st_mtim.tv_sec; } +inline static guint64 _g_stat_atime (const GLocalFileStat *buf) { return buf->st_atim.tv_sec; } +inline static guint64 _g_stat_ctime (const GLocalFileStat *buf) { return buf->st_ctim.tv_sec; } +inline static guint64 _g_stat_mtime (const GLocalFileStat *buf) { return buf->st_mtim.tv_sec; } #endif #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) || defined(G_OS_WIN32) inline static guint32 _g_stat_atim_nsec (const GLocalFileStat *buf) { return buf->st_atim.tv_nsec; }