summaryrefslogtreecommitdiff
path: root/gio/glocalfile.c
diff options
context:
space:
mode:
authorOndrej Holy <oholy@redhat.com>2018-09-13 17:33:59 +0200
committerOndrej Holy <oholy@redhat.com>2018-10-17 12:42:04 +0200
commit0f5017fb701b221846f04fa610c8429bbaa49136 (patch)
treed299a6691313bcbce75bdf6f4eb5fdc9d9649b7d /gio/glocalfile.c
parent035975da099dc5f4e06d02af4d593c8cf22a2234 (diff)
downloadglib-0f5017fb701b221846f04fa610c8429bbaa49136.tar.gz
glocalfile: Fix access::can-trash if parent is symlink
G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH can be set to a wrong value if its parent dir is a symlink. This is because the find_mountpoint_for() function tries to find mountpoint for a filepath and expands symlinks only in parent dirs. But in this case the path is already parent dir and needs to be expanded first... Closes: https://gitlab.gnome.org/GNOME/glib/issues/1522
Diffstat (limited to 'gio/glocalfile.c')
-rw-r--r--gio/glocalfile.c104
1 files changed, 65 insertions, 39 deletions
diff --git a/gio/glocalfile.c b/gio/glocalfile.c
index 30fa2281c..33b5ba3da 100644
--- a/gio/glocalfile.c
+++ b/gio/glocalfile.c
@@ -109,7 +109,7 @@ G_DEFINE_TYPE_WITH_CODE (GLocalFile, g_local_file, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_FILE,
g_local_file_file_iface_init))
-static char *find_mountpoint_for (const char *file, dev_t dev);
+static char *find_mountpoint_for (const char *file, dev_t dev, gboolean resolve_basename_symlink);
static void
g_local_file_finalize (GObject *object)
@@ -791,7 +791,7 @@ get_mount_info (GFileInfo *fs_info,
{
mount_info = 0;
- mountpoint = find_mountpoint_for (path, buf.st_dev);
+ mountpoint = find_mountpoint_for (path, buf.st_dev, FALSE);
if (mountpoint == NULL)
mountpoint = g_strdup ("/");
@@ -886,7 +886,7 @@ get_volume_for_path (const char *path)
}
static char *
-find_mountpoint_for (const char *file, dev_t dev)
+find_mountpoint_for (const char *file, dev_t dev, gboolean resolve_basename_symlink)
{
wchar_t *wpath;
char *utf8_path;
@@ -1132,7 +1132,7 @@ g_local_file_find_enclosing_mount (GFile *file,
if (g_lstat (local->filename, &buf) != 0)
goto error;
- mountpoint = find_mountpoint_for (local->filename, buf.st_dev);
+ mountpoint = find_mountpoint_for (local->filename, buf.st_dev, FALSE);
if (mountpoint == NULL)
goto error;
@@ -1584,12 +1584,51 @@ expand_symlink (const char *link)
}
static char *
-get_parent (const char *path,
- dev_t *parent_dev)
+expand_symlinks (const char *path,
+ dev_t *dev)
{
- char *parent, *tmp;
- GStatBuf parent_stat;
+ char *tmp, *target;
+ GStatBuf target_stat;
int num_recursions;
+
+ target = g_strdup (path);
+
+ num_recursions = 0;
+ do
+ {
+ if (g_lstat (target, &target_stat) != 0)
+ {
+ g_free (target);
+ return NULL;
+ }
+
+ if (S_ISLNK (target_stat.st_mode))
+ {
+ tmp = target;
+ target = expand_symlink (target);
+ g_free (tmp);
+ }
+
+ num_recursions++;
+ if (num_recursions > 12)
+ {
+ g_free (target);
+ return NULL;
+ }
+ }
+ while (S_ISLNK (target_stat.st_mode));
+
+ if (dev)
+ *dev = target_stat.st_dev;
+
+ return target;
+}
+
+static char *
+get_parent (const char *path,
+ dev_t *parent_dev)
+{
+ char *parent, *res;
char *path_copy;
path_copy = strip_trailing_slashes (path);
@@ -1604,32 +1643,10 @@ get_parent (const char *path,
}
g_free (path_copy);
- num_recursions = 0;
- do {
- if (g_lstat (parent, &parent_stat) != 0)
- {
- g_free (parent);
- return NULL;
- }
-
- if (S_ISLNK (parent_stat.st_mode))
- {
- tmp = parent;
- parent = expand_symlink (parent);
- g_free (tmp);
- }
-
- num_recursions++;
- if (num_recursions > 12)
- {
- g_free (parent);
- return NULL;
- }
- } while (S_ISLNK (parent_stat.st_mode));
+ res = expand_symlinks (parent, parent_dev);
+ g_free (parent);
- *parent_dev = parent_stat.st_dev;
-
- return parent;
+ return res;
}
static char *
@@ -1656,13 +1673,22 @@ expand_all_symlinks (const char *path)
}
static char *
-find_mountpoint_for (const char *file,
- dev_t dev)
+find_mountpoint_for (const char *file,
+ dev_t dev,
+ gboolean resolve_basename_symlink)
{
char *dir, *parent;
dev_t dir_dev, parent_dev;
- dir = g_strdup (file);
+ if (resolve_basename_symlink)
+ {
+ dir = expand_symlinks (file, NULL);
+ if (dir == NULL)
+ return g_strdup (file);
+ }
+ else
+ dir = g_strdup (file);
+
dir_dev = dev;
while (1)
@@ -1693,7 +1719,7 @@ _g_local_file_find_topdir_for (const char *file)
if (dir == NULL)
return NULL;
- mountpoint = find_mountpoint_for (dir, dir_dev);
+ mountpoint = find_mountpoint_for (dir, dir_dev, TRUE);
g_free (dir);
return mountpoint;
@@ -1789,7 +1815,7 @@ _g_local_file_has_trash_dir (const char *dirname, dev_t dir_dev)
if (dir_dev == home_dev)
return TRUE;
- topdir = find_mountpoint_for (dirname, dir_dev);
+ topdir = find_mountpoint_for (dirname, dir_dev, TRUE);
if (topdir == NULL)
return FALSE;
@@ -1856,7 +1882,7 @@ _g_local_file_is_lost_found_dir (const char *path, dev_t path_dev)
if (!g_str_has_suffix (path, "/lost+found"))
goto out;
- mount_dir = find_mountpoint_for (path, path_dev);
+ mount_dir = find_mountpoint_for (path, path_dev, FALSE);
if (mount_dir == NULL)
goto out;