[glib/wip/pwithnall/statx: 3/4] glocalfileinfo: Add statx() support




commit 614edc6b0a67cef7a5d159e5d16547be890d91f8
Author: Andre Miranda <andre42m gmail com>
Date:   Fri Aug 14 16:04:37 2020 +0100

    glocalfileinfo: Add statx() support
    
    This currently just implements the same functionality as the existing
    `stat()`/`fstat()`/`fstatat()`/`lstat()` calls, although where a reduced
    field set is requested it may return faster.
    
    Helps: #1970

 gio/glocalfileinfo.h               | 124 +++++++++++++++++++++++++++++++++++++
 gio/glocalfileoutputstream.c       |   5 ++
 gio/tests/thumbnail-verification.c |   5 ++
 meson.build                        |  17 +++++
 4 files changed, 151 insertions(+)
---
diff --git a/gio/glocalfileinfo.h b/gio/glocalfileinfo.h
index 9d744d6d4..f2beb70cd 100644
--- a/gio/glocalfileinfo.h
+++ b/gio/glocalfileinfo.h
@@ -21,6 +21,11 @@
 #ifndef __G_LOCAL_FILE_INFO_H__
 #define __G_LOCAL_FILE_INFO_H__
 
+/* Needed for statx() */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
 #include <fcntl.h>
 #include <gio/gfileinfo.h>
 #include <gio/gfile.h>
@@ -30,6 +35,10 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#ifdef HAVE_STATX
+#include <sys/sysmacros.h>
+#endif
+
 G_BEGIN_DECLS
 
 typedef struct
@@ -44,6 +53,119 @@ typedef struct
   GDestroyNotify free_extra_data;
 } GLocalParentFileInfo;
 
+#ifdef HAVE_STATX
+#define GLocalFileStat struct statx
+
+typedef enum
+{
+  G_LOCAL_FILE_STAT_FIELD_TYPE = STATX_TYPE,
+  G_LOCAL_FILE_STAT_FIELD_MODE = STATX_MODE,
+  G_LOCAL_FILE_STAT_FIELD_NLINK = STATX_NLINK,
+  G_LOCAL_FILE_STAT_FIELD_UID = STATX_UID,
+  G_LOCAL_FILE_STAT_FIELD_GID = STATX_GID,
+  G_LOCAL_FILE_STAT_FIELD_ATIME = STATX_ATIME,
+  G_LOCAL_FILE_STAT_FIELD_MTIME = STATX_MTIME,
+  G_LOCAL_FILE_STAT_FIELD_CTIME = STATX_CTIME,
+  G_LOCAL_FILE_STAT_FIELD_INO = STATX_INO,
+  G_LOCAL_FILE_STAT_FIELD_SIZE = STATX_SIZE,
+  G_LOCAL_FILE_STAT_FIELD_BLOCKS = STATX_BLOCKS,
+  G_LOCAL_FILE_STAT_FIELD_BTIME = STATX_BTIME,
+} GLocalFileStatField;
+
+#define G_LOCAL_FILE_STAT_FIELD_BASIC_STATS STATX_BASIC_STATS
+#define G_LOCAL_FILE_STAT_FIELD_ALL STATX_ALL
+
+static inline int
+g_local_file_statx (int                  dirfd,
+                    const char          *pathname,
+                    int                  flags,
+                    GLocalFileStatField  mask,
+                    GLocalFileStatField  mask_required,
+                    GLocalFileStat      *stat_buf)
+{
+  int retval;
+
+  /* Allow the caller to set mask_required==G_LOCAL_FILE_STAT_FIELD_ALL as a
+   * shortcut for saying it’s equal to @mask. */
+  mask_required &= mask;
+
+  retval = statx (dirfd, pathname, flags, mask, stat_buf);
+  if (retval == 0 && (stat_buf->stx_mask & mask_required) != mask_required)
+    {
+      /* Not all required fields could be returned. */
+      errno = ERANGE;
+      return -1;
+    }
+
+  return retval;
+}
+
+static inline int
+g_local_file_fstat (int                  fd,
+                    GLocalFileStatField  mask,
+                    GLocalFileStatField  mask_required,
+                    GLocalFileStat      *stat_buf)
+{
+  return g_local_file_statx (fd, "", AT_EMPTY_PATH, mask, mask_required, stat_buf);
+}
+
+static inline int
+g_local_file_fstatat (int                  fd,
+                      const char          *path,
+                      int                  flags,
+                      GLocalFileStatField  mask,
+                      GLocalFileStatField  mask_required,
+                      GLocalFileStat      *stat_buf)
+{
+  return g_local_file_statx (fd, path, flags, mask, mask_required, stat_buf);
+}
+
+static inline int
+g_local_file_lstat (const char          *path,
+                    GLocalFileStatField  mask,
+                    GLocalFileStatField  mask_required,
+                    GLocalFileStat      *stat_buf)
+{
+  return g_local_file_statx (AT_FDCWD, path,
+                             AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | AT_STATX_SYNC_AS_STAT,
+                             mask, mask_required, stat_buf);
+}
+
+static inline int
+g_local_file_stat (const char          *path,
+                   GLocalFileStatField  mask,
+                   GLocalFileStatField  mask_required,
+                   GLocalFileStat      *stat_buf)
+{
+  return g_local_file_statx (AT_FDCWD, path,
+                             AT_NO_AUTOMOUNT | AT_STATX_SYNC_AS_STAT,
+                             mask, mask_required, stat_buf);
+}
+
+inline static gboolean _g_stat_has_field  (const GLocalFileStat *buf, GLocalFileStatField field) { return 
buf->stx_mask & field; }
+
+inline static guint16 _g_stat_mode        (const GLocalFileStat *buf) { return buf->stx_mode; }
+inline static guint32 _g_stat_nlink       (const GLocalFileStat *buf) { return buf->stx_nlink; }
+inline static dev_t   _g_stat_dev         (const GLocalFileStat *buf) { return makedev (buf->stx_dev_major, 
buf->stx_dev_minor); }
+inline static guint64 _g_stat_ino         (const GLocalFileStat *buf) { return buf->stx_ino; }
+inline static guint64 _g_stat_size        (const GLocalFileStat *buf) { return buf->stx_size; }
+
+inline static guint32 _g_stat_uid         (const GLocalFileStat *buf) { return buf->stx_uid; }
+inline static guint32 _g_stat_gid         (const GLocalFileStat *buf) { return buf->stx_gid; }
+inline static dev_t   _g_stat_rdev        (const GLocalFileStat *buf) { return makedev (buf->stx_rdev_major, 
buf->stx_rdev_minor); }
+inline static guint32 _g_stat_blksize     (const GLocalFileStat *buf) { return buf->stx_blksize; }
+
+inline static guint64 _g_stat_blocks      (const GLocalFileStat *buf) { return buf->stx_blocks; }
+
+inline static gint64  _g_stat_atime       (const GLocalFileStat *buf) { return buf->stx_atime.tv_sec; }
+inline static gint64  _g_stat_ctime       (const GLocalFileStat *buf) { return buf->stx_ctime.tv_sec; }
+inline static gint64  _g_stat_mtime       (const GLocalFileStat *buf) { return buf->stx_mtime.tv_sec; }
+inline static guint32 _g_stat_atim_nsec   (const GLocalFileStat *buf) { return buf->stx_atime.tv_nsec; }
+inline static guint32 _g_stat_ctim_nsec   (const GLocalFileStat *buf) { return buf->stx_ctime.tv_nsec; }
+inline static guint32 _g_stat_mtim_nsec   (const GLocalFileStat *buf) { return buf->stx_mtime.tv_nsec; }
+
+#else  /* if !HAVE_STATX */
+
 #ifdef G_OS_WIN32
 /* We want 64-bit file size, file ID and symlink support */
 #define GLocalFileStat GWin32PrivateStat
@@ -201,6 +323,8 @@ inline static guint32   _g_stat_ctim_nsec (const GLocalFileStat *buf) { return b
 inline static guint32   _g_stat_mtim_nsec (const GLocalFileStat *buf) { return buf->st_mtim.tv_nsec; }
 #endif
 
+#endif  /* !HAVE_STATX */
+
 #define G_LOCAL_FILE_INFO_NOSTAT_ATTRIBUTES \
     G_FILE_ATTRIBUTE_STANDARD_NAME "," \
     G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," \
diff --git a/gio/glocalfileoutputstream.c b/gio/glocalfileoutputstream.c
index aa018a062..a09ee0805 100644
--- a/gio/glocalfileoutputstream.c
+++ b/gio/glocalfileoutputstream.c
@@ -18,6 +18,11 @@
  * Author: Alexander Larsson <alexl redhat com>
  */
 
+/* Needed for statx() */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
 #include "config.h"
 
 #include <sys/types.h>
diff --git a/gio/tests/thumbnail-verification.c b/gio/tests/thumbnail-verification.c
index d50638fe7..f439c8b06 100644
--- a/gio/tests/thumbnail-verification.c
+++ b/gio/tests/thumbnail-verification.c
@@ -99,12 +99,17 @@ test_validity (void)
       thumbnail_path = g_test_get_filename (G_TEST_DIST, "thumbnails",
                                             tests[i].filename, NULL);
       file_uri = g_strconcat ("file:///tmp/", tests[i].filename, NULL);
+#ifdef HAVE_STATX
+      stat_buf.stx_mtime.tv_sec = tests[i].mtime;
+      stat_buf.stx_size = tests[i].size;
+#else
 #ifdef G_OS_WIN32
       stat_buf.st_mtim.tv_sec = tests[i].mtime;
 #else
       stat_buf.st_mtime = tests[i].mtime;
 #endif
       stat_buf.st_size = tests[i].size;
+#endif
 
       result = thumbnail_verify (thumbnail_path, file_uri, &stat_buf);
 
diff --git a/meson.build b/meson.build
index 9a0293120..19ac186e6 100644
--- a/meson.build
+++ b/meson.build
@@ -328,6 +328,23 @@ if cc.has_header('linux/netlink.h')
   glib_conf.set('HAVE_NETLINK', 1)
 endif
 
+# Is statx() supported? Android systems don’t reliably support it as of August 2020.
+statx_code = '''
+  #ifndef _GNU_SOURCE
+  #define _GNU_SOURCE
+  #endif
+  #include <sys/stat.h>
+  #include <fcntl.h>
+  int main (void)
+  {
+    struct statx stat_buf;
+    return statx (AT_FDCWD, "/", AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS | STATX_BTIME, &stat_buf);
+  }
+  '''
+if host_system != 'android' and cc.compiles(statx_code, name : 'statx() test')
+  glib_conf.set('HAVE_STATX', 1)
+endif
+
 if glib_conf.has('HAVE_LOCALE_H')
   if cc.has_header_symbol('locale.h', 'LC_MESSAGES')
     glib_conf.set('HAVE_LC_MESSAGES', 1)


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