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,
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) ||
#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);
}
}
}
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);
}
}