summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Withnall <philip@tecnocode.co.uk>2024-10-01 15:45:04 +0000
committerPhilip Withnall <philip@tecnocode.co.uk>2024-10-01 15:45:04 +0000
commitf6d7878a544f7de234713f20ec66fb32442b889b (patch)
tree95b826e990ed314a0fd368a28f50f1c3f6811cd7
parent2b5d3b5831fb027ca041130bf91779ed7e5c9bf0 (diff)
parentab51ed0521d16227a0496c972ddc0bbcd5c9cd74 (diff)
Merge branch 'speed-up-query-exists' into 'main'
gio: Add a query_exists vfunc to GFile See merge request GNOME/glib!4272
-rw-r--r--gio/gfile.c15
-rw-r--r--gio/gfile.h4
-rw-r--r--gio/glocalfile.c14
-rw-r--r--gio/gresourcefile.c10
-rw-r--r--meson.build1
5 files changed, 41 insertions, 3 deletions
diff --git a/gio/gfile.c b/gio/gfile.c
index 5ac73c03e..6f104459f 100644
--- a/gio/gfile.c
+++ b/gio/gfile.c
@@ -1192,8 +1192,11 @@ g_file_enumerate_children_finish (GFile *file,
* @cancellable: (nullable): optional #GCancellable object,
* %NULL to ignore
*
- * Utility function to check if a particular file exists. This is
- * implemented using g_file_query_info() and as such does blocking I/O.
+ * Utility function to check if a particular file exists.
+ *
+ * The fallback implementation of this API is using [method@Gio.File.query_info]
+ * and therefore may do blocking I/O. To asynchronously query the existence
+ * of a file, use [method@Gio.File.query_info_async].
*
* Note that in many cases it is [racy to first check for file existence](https://en.wikipedia.org/wiki/Time_of_check_to_time_of_use)
* and then execute something based on the outcome of that, because the
@@ -1222,9 +1225,15 @@ gboolean
g_file_query_exists (GFile *file,
GCancellable *cancellable)
{
+ GFileIface *iface;
GFileInfo *info;
- g_return_val_if_fail (G_IS_FILE(file), FALSE);
+ g_return_val_if_fail (G_IS_FILE (file), FALSE);
+
+ iface = G_FILE_GET_IFACE (file);
+
+ if (iface->query_exists)
+ return iface->query_exists (file, cancellable);
info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE,
G_FILE_QUERY_INFO_NONE, cancellable, NULL);
diff --git a/gio/gfile.h b/gio/gfile.h
index d49c3b36c..74e50db83 100644
--- a/gio/gfile.h
+++ b/gio/gfile.h
@@ -148,6 +148,7 @@ typedef struct _GFileIface GFileIface;
* @measure_disk_usage: Recursively measures the disk usage of @file. Since 2.38
* @measure_disk_usage_async: Asynchronously recursively measures the disk usage of @file. Since 2.38
* @measure_disk_usage_finish: Finishes an asynchronous recursive measurement of the disk usage of @file. Since 2.38
+ * @query_exists: Queries whether a file exists. Since 2.84
*
* An interface for writing VFS file handles.
**/
@@ -598,6 +599,9 @@ struct _GFileIface
guint64 *num_dirs,
guint64 *num_files,
GError **error);
+
+ gboolean (* query_exists) (GFile *file,
+ GCancellable *cancellable);
};
GIO_AVAILABLE_IN_ALL
diff --git a/gio/glocalfile.c b/gio/glocalfile.c
index ac918d25e..7c02cc36e 100644
--- a/gio/glocalfile.c
+++ b/gio/glocalfile.c
@@ -1259,6 +1259,17 @@ g_local_file_query_info (GFile *file,
return info;
}
+#ifdef HAVE_FACCESSAT
+static gboolean
+g_local_file_query_exists (GFile *file,
+ GCancellable *cancellable)
+{
+ GLocalFile *local = G_LOCAL_FILE (file);
+
+ return faccessat (0, local->filename, F_OK, AT_EACCESS | AT_SYMLINK_NOFOLLOW) == 0;
+}
+#endif
+
static GFileAttributeInfoList *
g_local_file_query_settable_attributes (GFile *file,
GCancellable *cancellable,
@@ -3142,6 +3153,9 @@ g_local_file_file_iface_init (GFileIface *iface)
iface->monitor_dir = g_local_file_monitor_dir;
iface->monitor_file = g_local_file_monitor_file;
iface->measure_disk_usage = g_local_file_measure_disk_usage;
+#ifdef HAVE_FACCESSAT
+ iface->query_exists = g_local_file_query_exists;
+#endif
iface->supports_thread_contexts = TRUE;
}
diff --git a/gio/gresourcefile.c b/gio/gresourcefile.c
index 5b772d94b..da1f368e5 100644
--- a/gio/gresourcefile.c
+++ b/gio/gresourcefile.c
@@ -657,6 +657,15 @@ g_resource_file_set_display_name (GFile *file,
return NULL;
}
+static gboolean
+g_resource_file_query_exists (GFile *file,
+ GCancellable *cancellable)
+{
+ GResourceFile *resource = G_RESOURCE_FILE (file);
+
+ return g_resources_get_info (resource->path, 0, NULL, NULL, NULL);
+}
+
static void
g_resource_file_file_iface_init (GFileIface *iface)
{
@@ -683,6 +692,7 @@ g_resource_file_file_iface_init (GFileIface *iface)
iface->query_writable_namespaces = g_resource_file_query_writable_namespaces;
iface->read_fn = g_resource_file_read;
iface->monitor_file = g_resource_file_monitor_file;
+ iface->query_exists = g_resource_file_query_exists;
iface->supports_thread_contexts = TRUE;
}
diff --git a/meson.build b/meson.build
index 5f7870d1f..748831ac5 100644
--- a/meson.build
+++ b/meson.build
@@ -683,6 +683,7 @@ functions = [
'endmntent',
'endservent',
'epoll_create1',
+ 'faccessat',
'fallocate',
'fchmod',
'fchown',