mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-08 18:36:17 +01:00
Merge branch 'fix-overlayfs-trashing-1027' into 'master'
Fix trashing on overlayfs Closes #1027 See merge request GNOME/glib!182
This commit is contained in:
commit
4a77dd6799
@ -1677,20 +1677,16 @@ find_mountpoint_for (const char *file,
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
_g_local_file_find_topdir_for_internal (const char *file, dev_t file_dev)
|
||||
char *
|
||||
_g_local_file_find_topdir_for (const char *file)
|
||||
{
|
||||
char *dir;
|
||||
char *mountpoint = NULL;
|
||||
dev_t dir_dev;
|
||||
|
||||
dir = get_parent (file, &dir_dev);
|
||||
if (dir == NULL || dir_dev != file_dev)
|
||||
{
|
||||
g_free (dir);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
if (dir == NULL)
|
||||
return NULL;
|
||||
|
||||
mountpoint = find_mountpoint_for (dir, dir_dev);
|
||||
g_free (dir);
|
||||
@ -1698,17 +1694,6 @@ _g_local_file_find_topdir_for_internal (const char *file, dev_t file_dev)
|
||||
return mountpoint;
|
||||
}
|
||||
|
||||
char *
|
||||
_g_local_file_find_topdir_for (const char *file)
|
||||
{
|
||||
GStatBuf file_stat;
|
||||
|
||||
if (g_lstat (file, &file_stat) != 0)
|
||||
return NULL;
|
||||
|
||||
return _g_local_file_find_topdir_for_internal (file, file_stat.st_dev);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_unique_filename (const char *basename,
|
||||
int id)
|
||||
@ -1908,6 +1893,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 +1918,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;
|
||||
@ -1962,8 +1966,7 @@ g_local_file_trash (GFile *file,
|
||||
uid = geteuid ();
|
||||
g_snprintf (uid_str, sizeof (uid_str), "%lu", (unsigned long)uid);
|
||||
|
||||
topdir = _g_local_file_find_topdir_for_internal (local->filename,
|
||||
file_stat.st_dev);
|
||||
topdir = _g_local_file_find_topdir_for (local->filename);
|
||||
if (topdir == NULL)
|
||||
{
|
||||
g_set_io_error (error,
|
||||
|
@ -924,13 +924,9 @@ get_access_rights (GFileAttributeMatcher *attribute_matcher,
|
||||
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE,
|
||||
writable);
|
||||
|
||||
/* Trashing is supported only if the parent device is the same */
|
||||
if (_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH))
|
||||
_g_file_info_set_attribute_boolean_by_id (info,
|
||||
G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH,
|
||||
writable &&
|
||||
parent_info->has_trash_dir &&
|
||||
parent_info->device == statbuf->st_dev);
|
||||
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH,
|
||||
writable && parent_info->has_trash_dir);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,23 +35,26 @@ test_trash_not_supported (void)
|
||||
GFileInfo *info;
|
||||
GError *error = NULL;
|
||||
gboolean ret;
|
||||
GStatBuf file_stat, home_stat;
|
||||
gchar *parent_dirname;
|
||||
GStatBuf parent_stat, home_stat;
|
||||
|
||||
/* The test assumes that tmp file is located on system internal mount. */
|
||||
file = g_file_new_tmp ("test-trashXXXXXX", &stream, &error);
|
||||
parent_dirname = g_path_get_dirname (g_file_peek_path (file));
|
||||
g_assert_no_error (error);
|
||||
g_assert_cmpint (g_lstat (g_file_peek_path (file), &file_stat), ==, 0);
|
||||
g_test_message ("File: %s (dev: %" G_GUINT64_FORMAT ")",
|
||||
g_file_peek_path (file), (guint64) file_stat.st_dev);
|
||||
g_assert_cmpint (g_stat (parent_dirname, &parent_stat), ==, 0);
|
||||
g_test_message ("File: %s (parent st_dev: %" G_GUINT64_FORMAT ")",
|
||||
g_file_peek_path (file), (guint64) parent_stat.st_dev);
|
||||
|
||||
g_assert_cmpint (g_stat (g_get_home_dir (), &home_stat), ==, 0);
|
||||
g_test_message ("Home: %s (dev: %" G_GUINT64_FORMAT ")",
|
||||
g_test_message ("Home: %s (st_dev: %" G_GUINT64_FORMAT ")",
|
||||
g_get_home_dir (), (guint64) home_stat.st_dev);
|
||||
|
||||
if (file_stat.st_dev == home_stat.st_dev)
|
||||
if (parent_stat.st_dev == home_stat.st_dev)
|
||||
{
|
||||
g_test_skip ("The file has to be on another filesystem than the home trash to run this test");
|
||||
|
||||
g_free (parent_dirname);
|
||||
g_object_unref (stream);
|
||||
g_object_unref (file);
|
||||
|
||||
@ -85,6 +88,7 @@ test_trash_not_supported (void)
|
||||
g_io_stream_close (G_IO_STREAM (stream), NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_free (parent_dirname);
|
||||
g_object_unref (info);
|
||||
g_object_unref (stream);
|
||||
g_object_unref (file);
|
||||
|
Loading…
Reference in New Issue
Block a user