diff options
author | Iain Lane <iainl@gnome.org> | 2018-07-16 16:31:10 +0100 |
---|---|---|
committer | Iain Lane <iainl@gnome.org> | 2018-07-16 16:31:44 +0100 |
commit | 3ba9e4b5ba16b7ed2c2f9d513f02cd828ae50cb6 (patch) | |
tree | 6fb0a2cb5fdc7ab499153b0e272d79c3b97cbdb0 | |
parent | 8d2d0a8aa134189daf2f5cd31a97cc8e517080bf (diff) | |
download | glib-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.c | 19 |
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; |