[glib/wip/oholy/glocalfile-x-gvfs-trash-cache] glocalfile: Add x-gvfs-notrash cache




commit a4065a7a94ba3bf856426bde18f5372d1be9bff5
Author: Ondrej Holy <oholy redhat com>
Date:   Thu Nov 5 09:31:11 2020 +0100

    glocalfile: Add x-gvfs-notrash cache
    
    The g_unix_mount_get function is called each time when querying info, or
    enumerating dir. It seems that it causes performance issues in some cases
    on some platforms for certain g_unix_mount_get implementations, see
    GNOME/glib!1707. The g_unix_mount_get call was introduced by the commit
    4602a5e and commit 4602a5e, which are needed to set the access::can-trash
    attribute now. Let's use the already existing mount cache to improve the
    performance in this case.

 gio/glocalfile.c | 72 +++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 45 insertions(+), 27 deletions(-)
---
diff --git a/gio/glocalfile.c b/gio/glocalfile.c
index a35368c71..3419fdf27 100644
--- a/gio/glocalfile.c
+++ b/gio/glocalfile.c
@@ -111,6 +111,7 @@ G_DEFINE_TYPE_WITH_CODE (GLocalFile, g_local_file, G_TYPE_OBJECT,
                                                g_local_file_file_iface_init))
 
 static char *find_mountpoint_for (const char *file, dev_t dev, gboolean resolve_basename_symlink);
+static gboolean ignore_trash_mount (GUnixMountEntry *mount);
 
 #ifndef G_OS_WIN32
 static gboolean is_remote_fs_type (const gchar *fsname);
@@ -742,7 +743,8 @@ static GHashTable *mount_info_hash = NULL;
 static guint64 mount_info_hash_cache_time = 0;
 
 typedef enum {
-  MOUNT_INFO_READONLY = 1<<0
+  MOUNT_INFO_READONLY = 1 << 0,
+  MOUNT_INFO_IGNORE_TRASH = 1 << 1
 } MountInfo;
 
 static gboolean
@@ -758,12 +760,11 @@ device_hash (gconstpointer v)
   return (guint) *(dev_t *)v;
 }
 
-static void
-get_mount_info (GFileInfo             *fs_info,
-               const char            *path,
-               GFileAttributeMatcher *matcher)
+static guint
+get_mount_info_internal (const char *path,
+                         gboolean is_topdir,
+                         dev_t path_dev)
 {
-  GStatBuf buf;
   gboolean got_info;
   gpointer info_as_ptr;
   guint mount_info;
@@ -772,9 +773,6 @@ get_mount_info (GFileInfo             *fs_info,
   GUnixMountEntry *mount;
   guint64 cache_time;
 
-  if (g_lstat (path, &buf) != 0)
-    return;
-
   G_LOCK (mount_info_hash);
 
   if (mount_info_hash == NULL)
@@ -786,7 +784,7 @@ get_mount_info (GFileInfo             *fs_info,
     g_hash_table_remove_all (mount_info_hash);
   
   got_info = g_hash_table_lookup_extended (mount_info_hash,
-                                          &buf.st_dev,
+                                           &path_dev,
                                           NULL,
                                           &info_as_ptr);
   
@@ -798,7 +796,11 @@ get_mount_info (GFileInfo             *fs_info,
     {
       mount_info = 0;
 
-      mountpoint = find_mountpoint_for (path, buf.st_dev, FALSE);
+      if (is_topdir)
+        mountpoint = g_strdup (path);
+      else
+        mountpoint = find_mountpoint_for (path, path_dev, FALSE);
+
       if (mountpoint == NULL)
        mountpoint = g_strdup ("/");
 
@@ -808,20 +810,42 @@ get_mount_info (GFileInfo             *fs_info,
          if (g_unix_mount_is_readonly (mount))
            mount_info |= MOUNT_INFO_READONLY;
          
+          if (ignore_trash_mount (mount))
+            mount_info |= MOUNT_INFO_IGNORE_TRASH;
+
          g_unix_mount_free (mount);
        }
+      else
+        {
+          mount_info |= MOUNT_INFO_IGNORE_TRASH;
+        }
 
       g_free (mountpoint);
 
       dev = g_new0 (dev_t, 1);
-      *dev = buf.st_dev;
-      
+      *dev = path_dev;
+
       G_LOCK (mount_info_hash);
       mount_info_hash_cache_time = cache_time;
       g_hash_table_insert (mount_info_hash, dev, GUINT_TO_POINTER (mount_info));
       G_UNLOCK (mount_info_hash);
     }
 
+  return mount_info;
+}
+
+static void
+get_mount_info (GFileInfo             *fs_info,
+                const char            *path,
+                GFileAttributeMatcher *matcher)
+{
+  guint mount_info;
+  GStatBuf buf;
+
+  if (g_lstat (path, &buf) != 0)
+    return;
+
+  mount_info = get_mount_info_internal (path, FALSE, buf.st_dev);
   if (mount_info & MOUNT_INFO_READONLY)
     g_file_info_set_attribute_boolean (fs_info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, TRUE);
 }
@@ -1802,21 +1826,15 @@ ignore_trash_mount (GUnixMountEntry *mount)
 }
 
 static gboolean
-ignore_trash_path (const gchar *topdir)
+ignore_trash_path (const gchar *topdir, dev_t dir_dev)
 {
-  GUnixMountEntry *mount;
-  gboolean retval = TRUE;
-
-  mount = g_unix_mount_at (topdir, NULL);
-  if (mount == NULL)
-    goto out;
-
-  retval = ignore_trash_mount (mount);
+  MountInfo mount_info;
 
- out:
-  g_clear_pointer (&mount, g_unix_mount_free);
+  mount_info = get_mount_info_internal (topdir, TRUE, dir_dev);
+  if (mount_info & MOUNT_INFO_IGNORE_TRASH)
+    return TRUE;
 
-  return retval;
+  return FALSE;
 }
 
 gboolean
@@ -1858,7 +1876,7 @@ _g_local_file_has_trash_dir (const char *dirname, dev_t dir_dev)
   if (topdir == NULL)
     return FALSE;
 
-  if (ignore_trash_path (topdir))
+  if (ignore_trash_path (topdir, dir_dev))
     {
       g_free (topdir);
 
@@ -2051,7 +2069,7 @@ g_local_file_trash (GFile         *file,
          return FALSE;
        }
 
-      if (ignore_trash_path (topdir))
+      if (ignore_trash_path (topdir, file_stat.st_dev))
         {
           g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
                        _("Trashing on system internal mounts is not supported"));


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