Correctly implement can_trash by actually looking for a trash dir, not

2008-03-11  Alexander Larsson  <alexl@redhat.com>

        * glocalfile.c:
        * glocalfileinfo.[ch]:
	Correctly implement can_trash by actually
	looking for a trash dir, not just assuming
	one exists.


svn path=/trunk/; revision=6679
This commit is contained in:
Alexander Larsson 2008-03-11 14:48:28 +00:00 committed by Alexander Larsson
parent 15f3867833
commit c5a10d2650
4 changed files with 91 additions and 3 deletions

View File

@ -1,3 +1,11 @@
2008-03-11 Alexander Larsson <alexl@redhat.com>
* glocalfile.c:
* glocalfileinfo.[ch]:
Correctly implement can_trash by actually
looking for a trash dir, not just assuming
one exists.
2008-03-10 Matthias Clasen <mclasen@redhat.com>
* === Released 2.16.1 ===

View File

@ -1576,6 +1576,79 @@ escape_trash_name (char *name)
return g_string_free (str, FALSE);
}
gboolean
_g_local_file_has_trash_dir (const char *dirname, dev_t dir_dev)
{
static gsize home_dev = 0;
char *topdir, *globaldir, *trashdir, *tmpname;
uid_t uid;
char uid_str[32];
struct stat global_stat, trash_stat;
gboolean res;
int statres;
if (g_once_init_enter (&home_dev))
{
gsize setup_value = 0;
struct stat home_stat;
g_stat (g_get_home_dir (), &home_stat);
setup_value = home_stat.st_dev;
g_once_init_leave (&home_dev, setup_value);
}
/* Assume we can trash to the home */
if (dir_dev == (dev_t)home_dev)
return TRUE;
topdir = find_mountpoint_for (dirname, dir_dev);
if (topdir == NULL)
return FALSE;
globaldir = g_build_filename (topdir, ".Trash", NULL);
statres = g_lstat (globaldir, &global_stat);
if (g_lstat (globaldir, &global_stat) == 0 &&
S_ISDIR (global_stat.st_mode) &&
(global_stat.st_mode & S_ISVTX) != 0)
{
/* got a toplevel sysadmin created dir, assume we
* can trash to it (we should be able to create a dir)
* This fails for the FAT case where the ownership of
* that dir would be wrong though..
*/
g_free (globaldir);
g_free (topdir);
return TRUE;
}
g_free (globaldir);
/* No global trash dir, or it failed the tests, fall back to $topdir/.Trash-$uid */
uid = geteuid ();
g_snprintf (uid_str, sizeof (uid_str), "%lu", (unsigned long) uid);
tmpname = g_strdup_printf (".Trash-%s", uid_str);
trashdir = g_build_filename (topdir, tmpname, NULL);
g_free (tmpname);
if (g_lstat (trashdir, &trash_stat) == 0)
{
g_free (topdir);
g_free (trashdir);
return
S_ISDIR (trash_stat.st_mode) &&
trash_stat.st_uid == uid;
}
g_free (trashdir);
/* User specific trash didn't exist, can we create it? */
res = g_access (topdir, W_OK) == 0;
g_free (topdir);
return res;
}
static gboolean
g_local_file_trash (GFile *file,
GCancellable *cancellable,

View File

@ -781,6 +781,7 @@ _g_local_file_info_get_parent_info (const char *dir,
parent_info->writable = FALSE;
parent_info->is_sticky = FALSE;
parent_info->has_trash_dir = FALSE;
parent_info->device = 0;
if (g_file_attribute_matcher_matches (attribute_matcher, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME) ||
@ -806,6 +807,10 @@ _g_local_file_info_get_parent_info (const char *dir,
#endif
parent_info->owner = statbuf.st_uid;
parent_info->device = statbuf.st_dev;
/* No need to find trash dir if its not writable anyway */
if (parent_info->writable &&
g_file_attribute_matcher_matches (attribute_matcher, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH))
parent_info->has_trash_dir = _g_local_file_has_trash_dir (dir, statbuf.st_dev);
}
}
}
@ -863,10 +868,9 @@ get_access_rights (GFileAttributeMatcher *attribute_matcher,
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE,
writable);
/* TODO: This means we can move it, but we should also look for a trash dir */
if (g_file_attribute_matcher_matches (attribute_matcher, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH))
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH,
writable);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH,
writable && parent_info->has_trash_dir);
}
}

View File

@ -35,10 +35,13 @@ G_BEGIN_DECLS
typedef struct {
gboolean writable;
gboolean is_sticky;
gboolean has_trash_dir;
int owner;
dev_t device;
} GLocalParentFileInfo;
gboolean _g_local_file_has_trash_dir (const char *dirname,
dev_t dir_dev);
void _g_local_file_info_get_parent_info (const char *dir,
GFileAttributeMatcher *attribute_matcher,
GLocalParentFileInfo *parent_info);