summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIain Lane <iainl@gnome.org>2018-07-16 16:31:10 +0100
committerIain Lane <iainl@gnome.org>2018-07-16 16:31:44 +0100
commit3ba9e4b5ba16b7ed2c2f9d513f02cd828ae50cb6 (patch)
tree6fb0a2cb5fdc7ab499153b0e272d79c3b97cbdb0
parent8d2d0a8aa134189daf2f5cd31a97cc8e517080bf (diff)
downloadglib-fix-overlayfs-trashing-1027.tar.gz
Fix trashing on overlayfsfix-overlayfs-trashing-1027
In order to determine whether to trash a file to the home directory, we compare its st_dev to our home directory's st_dev field. This is the wrong thing to do on overlayfs when deleting files, because st_dev contains the ID of the filesystem providing the file (which can be the lower or upper filesystem), but directories always return the ID of the overlayfs. Thus the comparison fails and we are unable to trash the file. Fix this by checking st_dev of the parent directory when we are deleting a file. Fixes #1027.
-rw-r--r--gio/glocalfile.c19
1 files changed, 19 insertions, 0 deletions
diff --git a/gio/glocalfile.c b/gio/glocalfile.c
index 354ac7c8c..c9b6c2009 100644
--- a/gio/glocalfile.c
+++ b/gio/glocalfile.c
@@ -1908,6 +1908,7 @@ g_local_file_trash (GFile *file,
char *original_name, *original_name_escaped;
int i;
char *data;
+ char *path;
gboolean is_homedir_trash;
char *delete_time = NULL;
int fd;
@@ -1932,6 +1933,24 @@ g_local_file_trash (GFile *file,
is_homedir_trash = FALSE;
trashdir = NULL;
+
+ /* On overlayfs, a file's st_dev will be different to the home directory's.
+ * We still want to create our trash directory under the home directory, so
+ * instead we should stat the directory that the file we're deleting is in as
+ * this will have the same st_dev.
+ */
+ if (!S_ISDIR (file_stat.st_mode))
+ {
+ path = g_path_get_dirname (local->filename);
+ /* If the parent is a symlink to a different device then it might have
+ * st_dev equal to the home directory's, in which case we will end up
+ * trying to rename across a filesystem boundary, which doesn't work. So
+ * we use g_stat here instead of g_lstat, to know where the symlink
+ * points to. */
+ g_stat (path, &file_stat);
+ g_free (path);
+ }
+
if (file_stat.st_dev == home_stat.st_dev)
{
is_homedir_trash = TRUE;