Author: benny
Date: 2007-01-13 18:15:10 +0000 (Sat, 13 Jan 2007)
New Revision: 24381
Modified:
thunar/trunk/ChangeLog
thunar/trunk/configure.in.in
thunar/trunk/thunar-vfs/thunar-vfs-io-trash.c
thunar/trunk/thunar-vfs/thunar-vfs-io-trash.h
thunar/trunk/thunar-vfs/thunar-vfs-volume.c
Log:
2007-01-13 Benedikt Meurer <[EMAIL PROTECTED]>
* configure.in.in, thunar-vfs/thunar-vfs-io-trash.{c,h}: Add support
for $top_dir-Trashes, as described in the Desktop Trash Specifica-
tion. Bug #2132.
* thunar-vfs/thunar-vfs-volume.c(thunar_vfs_volume_changed): Rescan
the active mount points whenever a volume changes.
Modified: thunar/trunk/ChangeLog
===================================================================
--- thunar/trunk/ChangeLog 2007-01-12 23:32:33 UTC (rev 24380)
+++ thunar/trunk/ChangeLog 2007-01-13 18:15:10 UTC (rev 24381)
@@ -1,3 +1,11 @@
+2007-01-13 Benedikt Meurer <[EMAIL PROTECTED]>
+
+ * configure.in.in, thunar-vfs/thunar-vfs-io-trash.{c,h}: Add support
+ for $top_dir-Trashes, as described in the Desktop Trash Specifica-
+ tion. Bug #2132.
+ * thunar-vfs/thunar-vfs-volume.c(thunar_vfs_volume_changed): Rescan
+ the active mount points whenever a volume changes.
+
2007-01-12 Benedikt Meurer <[EMAIL PROTECTED]>
* thunar-vfs/thunar-vfs-io-local-xfer.c(tvilx_copy_regular): Drop
Modified: thunar/trunk/configure.in.in
===================================================================
--- thunar/trunk/configure.in.in 2007-01-12 23:32:33 UTC (rev 24380)
+++ thunar/trunk/configure.in.in 2007-01-13 18:15:10 UTC (rev 24381)
@@ -104,8 +104,8 @@
AC_CHECK_HEADERS([ctype.h dirent.h errno.h fcntl.h fnmatch.h fstab.h grp.h \
limits.h locale.h math.h memory.h mntent.h paths.h pwd.h \
regex.h sched.h setjmp.h signal.h stdarg.h stdlib.h \
- string.h sys/xattr.h sys/extattr.h sys/cdio.h sys/mman.h \
- sys/mount.h sys/param.h sys/resource.h sys/stat.h \
+ string.h syslog.h sys/xattr.h sys/extattr.h sys/cdio.h \
+ sys/mman.h sys/mount.h sys/param.h sys/resource.h sys/stat.h
\
sys/statfs.h sys/statvfs.h sys/time.h sys/ucred.h sys/uio.h \
sys/vfs.h sys/wait.h time.h wchar.h wctype.h])
@@ -113,11 +113,11 @@
dnl *** Check for standard functions ***
dnl ************************************
AC_FUNC_MMAP()
-AC_CHECK_FUNCS([attropen extattr_get_fd fgetxattr futimes getdents getfsspec
getfsstat \
- lchmod localeconv localtime_r mbrtowc mkdtemp mkfifo \
+AC_CHECK_FUNCS([attropen extattr_get_fd fgetxattr futimes getdents getfsspec \
+ getfsstat lchmod localeconv localtime_r mbrtowc mkdtemp mkfifo
\
posix_madvise pread pwrite readdir_r sched_yield setgroupent \
setmntent setpassent setpriority statfs statvfs statvfs1 \
- strcoll strlcpy strptime symlink])
+ strcoll strlcpy strptime symlink syslog])
dnl ******************************************
dnl *** Linux/glibc specified work-arounds ***
@@ -136,6 +136,15 @@
AC_MSG_RESULT([no])
])
+dnl **************************************************************
+dnl *** Check for f_mntonname in statfs (trash implementation) ***
+dnl **************************************************************
+AC_CHECK_MEMBERS([struct statfs.f_mntonname],,,
+[
+#include <sys/param.h>
+#include <sys/mount.h>
+])
+
dnl ******************************
dnl *** Check for i18n support ***
dnl ******************************
Modified: thunar/trunk/thunar-vfs/thunar-vfs-io-trash.c
===================================================================
--- thunar/trunk/thunar-vfs/thunar-vfs-io-trash.c 2007-01-12 23:32:33 UTC
(rev 24380)
+++ thunar/trunk/thunar-vfs/thunar-vfs-io-trash.c 2007-01-13 18:15:10 UTC
(rev 24381)
@@ -1,6 +1,6 @@
/* $Id$ */
/*-
- * Copyright (c) 2006 Benedikt Meurer <[EMAIL PROTECTED]>
+ * Copyright (c) 2006-2007 Benedikt Meurer <[EMAIL PROTECTED]>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -22,6 +22,12 @@
#include <config.h>
#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
@@ -45,6 +51,9 @@
#ifdef HAVE_STRING_H
#include <string.h>
#endif
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
@@ -60,10 +69,11 @@
#include <thunar-vfs/thunar-vfs-private.h>
#include <thunar-vfs/thunar-vfs-alias.h>
-/* Use g_open(), g_remove(), g_lstat(), and g_unlink() on win32 */
+/* Use g_mkdir(), g_open(), g_remove(), g_lstat(), and g_unlink() on win32 */
#if defined(G_OS_WIN32)
#include <glib/gstdio.h>
#else
+#define g_mkdir(path, mode) (mkdir ((path), (mode)))
#define g_open(path, flags, mode) (open ((path), (flags), (mode)))
#define g_remove(path) (remove ((path)))
#define g_lstat(path, statb) (lstat ((path), (statb)))
@@ -72,10 +82,15 @@
-static inline gchar *tvit_resolve_original_path (guint trash_id,
- const gchar
*original_path_escaped,
- const gchar *relative_path,
- GError **error)
G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+static inline gboolean tvit_initialize_trash_dir (const gchar *trash_dir)
G_GNUC_WARN_UNUSED_RESULT;
+static void tvit_rescan_mount_points (void);
+static inline gchar *tvit_resolve_original_path (guint trash_id,
+ const gchar
*original_path_escaped,
+ const gchar
*relative_path,
+ GError **error)
G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+static guint tvit_resolve_trash_dir_to_id (const gchar *trash_dir)
G_GNUC_WARN_UNUSED_RESULT;
+static gchar *tvit_trash_dir_for_mount_point (const gchar *top_dir,
+ gboolean create)
G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
@@ -92,14 +107,288 @@
static ThunarVfsIOTrash *_thunar_vfs_io_trashes;
static guint _thunar_vfs_io_n_trashes;
-/* TRUE if trashes were scanned already */
-static gint _thunar_vfs_io_trash_timer_id = -1;
+/* the trash rescan timer id */
+static guint _thunar_vfs_io_trash_timer_id;
+/* the device of the home folder */
+static dev_t _thunar_vfs_io_trash_homedev;
+
/* the trash subsystem lock */
G_LOCK_DEFINE_STATIC (_thunar_vfs_io_trash);
+static inline gboolean
+tvit_initialize_trash_dir (const gchar *trash_dir)
+{
+ const gchar *name;
+ struct stat statb;
+ gboolean result = FALSE;
+ gchar *files_dir;
+ gchar *info_dir;
+ gchar *basename;
+ gchar *dirname;
+ GDir *dp;
+
+ /* try to create the directory with the appropriate permissions */
+ if (G_LIKELY (g_mkdir (trash_dir, 0700) == 0))
+ {
+ /* check if the trash dir is usable */
+ if (G_LIKELY (g_lstat (trash_dir, &statb) == 0))
+ {
+ /* the trash_dir must be owned by user now, with rwx for user only */
+ if (G_LIKELY (statb.st_uid == getuid () && (statb.st_mode & 0777) ==
0700))
+ {
+ /* we want to be smart, and we need to be smarter
+ * than file systems like msdosfs, which translate
+ * for example ".Trash-200" to "trash-20", which
+ * we don't want to support, so be sure the
+ * directory now contains an entry with our name.
+ */
+ dirname = g_path_get_dirname (trash_dir);
+ dp = g_dir_open (dirname, 0, NULL);
+ if (G_LIKELY (dp != NULL))
+ {
+ /* determine the basename to look for */
+ basename = g_path_get_basename (trash_dir);
+ do
+ {
+ /* compare the next entry */
+ name = g_dir_read_name (dp);
+ if (G_LIKELY (name != NULL))
+ result = (strcmp (name, basename) == 0);
+ }
+ while (name != NULL && !result);
+ g_free (basename);
+ }
+ g_free (dirname);
+
+ /* check if the entry was present */
+ if (G_LIKELY (result))
+ {
+ /* create the infos and files directories */
+ info_dir = g_build_filename (trash_dir, "info", NULL);
+ files_dir = g_build_filename (trash_dir, "files", NULL);
+ result = (g_mkdir (info_dir, 0700) == 0 && g_mkdir
(files_dir, 0700) == 0);
+ g_free (files_dir);
+ g_free (info_dir);
+ }
+ }
+
+ if (G_UNLIKELY (!result))
+ {
+ /* Not good, e.g. USB key. Delete the trash directory again.
+ * I'm paranoid, it would be better to find a solution that
allows
+ * to trash directly onto the USB key, but I don't see how that
would
+ * pass the security checks. It would also make the USB key
appears as
+ * empty when it's in fact full...
+ *
+ * Thanks to the KDE guys for this tip!
+ */
+ rmdir (trash_dir);
+ }
+ }
+ }
+
+ return result;
+}
+
+
+
+static void
+tvit_rescan_mount_points (void)
+{
+ ExoMountPoint *mount_point;
+ GSList *mount_points;
+ GSList *lp;
+ gchar *trash_dir;
+ guint trash_id;
+
+ /* determine the currently active mount points */
+ mount_points = exo_mount_point_list_active (NULL);
+ for (lp = mount_points; lp != NULL; lp = lp->next)
+ {
+ /* skip pseudo file systems as we won't find trash directories
+ * there, and of course skip read-only file systems, as we
+ * cannot trash to them anyway...
+ */
+ mount_point = (ExoMountPoint *) lp->data;
+ if (strncmp (mount_point->device, "/dev/", 5) == 0
+ && (mount_point->flags & EXO_MOUNT_POINT_READ_ONLY) == 0)
+ {
+ /* lookup the trash directory for this mount point */
+ trash_dir = tvit_trash_dir_for_mount_point (mount_point->folder,
FALSE);
+ if (G_UNLIKELY (trash_dir != NULL))
+ {
+ /* check if the trash dir was already registered */
+ trash_id = tvit_resolve_trash_dir_to_id (trash_dir);
+ if (G_UNLIKELY (trash_id == 0))
+ {
+ /* allocate space for the new trash directory */
+ trash_id = _thunar_vfs_io_n_trashes++;
+ _thunar_vfs_io_trashes = g_renew (ThunarVfsIOTrash,
+ _thunar_vfs_io_trashes,
+ _thunar_vfs_io_n_trashes);
+
+ /* register the new trash directory */
+ _thunar_vfs_io_trashes[trash_id].top_dir = g_strdup
(mount_point->folder);
+ _thunar_vfs_io_trashes[trash_id].trash_dir = trash_dir;
+ _thunar_vfs_io_trashes[trash_id].mtime = (time_t) -1;
+ }
+ else
+ {
+ /* cleanup */
+ g_free (trash_dir);
+ }
+ }
+ }
+ exo_mount_point_free (mount_point);
+ }
+ g_slist_free (mount_points);
+}
+
+
+
+static inline gchar*
+tvit_resolve_original_path (guint trash_id,
+ const gchar *original_path_escaped,
+ const gchar *relative_path,
+ GError **error)
+{
+ gchar *original_path_unescaped;
+ gchar *absolute_path = NULL;
+ gchar *top_dir;
+
+ /* unescape the path according to RFC 2396 */
+ original_path_unescaped = _thunar_vfs_unescape_rfc2396_string
(original_path_escaped, -1, "/", FALSE, error);
+ if (G_UNLIKELY (original_path_unescaped == NULL))
+ return NULL;
+
+ /* check if we have a relative path here */
+ if (!g_path_is_absolute (original_path_unescaped))
+ {
+ /* determine the toplevel directory for the trash-id */
+ top_dir = _thunar_vfs_io_trash_get_top_dir (trash_id, error);
+ if (G_LIKELY (top_dir != NULL))
+ absolute_path = g_build_filename (top_dir, original_path_unescaped,
relative_path, NULL);
+ g_free (original_path_unescaped);
+ g_free (top_dir);
+ }
+ else
+ {
+ /* generate the absolute with the relative part */
+ absolute_path = g_build_filename (original_path_unescaped,
relative_path, NULL);
+ g_free (original_path_unescaped);
+ }
+
+ return absolute_path;
+}
+
+
+
+static guint
+tvit_resolve_trash_dir_to_id (const gchar *trash_dir)
+{
+ guint id;
+
+ for (id = 1; id < _thunar_vfs_io_n_trashes; ++id)
+ if (strcmp (_thunar_vfs_io_trashes[id].trash_dir, trash_dir) == 0)
+ return id;
+
+ /* fallback to home trash! */
+ return 0;
+}
+
+
+
+static gchar*
+tvit_trash_dir_for_mount_point (const gchar *top_dir,
+ gboolean create)
+{
+ struct stat statb;
+ gchar *trash_dir;
+ gchar *dir;
+ uid_t uid;
+
+ /* determine our UID */
+ uid = getuid ();
+
+ /* try with $top_dir/.Trash directory first (created by the administrator) */
+ dir = g_build_filename (top_dir, ".Trash", NULL);
+ if (g_lstat (dir, &statb) == 0)
+ {
+ /* must be a directory owned by root with sticky bit and wx for 'others'
*/
+ if (statb.st_uid == 0 && S_ISDIR (statb.st_mode) && (statb.st_mode &
(S_ISVTX | S_IWOTH | S_IXOTH)) == (S_ISVTX | S_IWOTH | S_IXOTH))
+ {
+ /* check if $top_dir/.Trash/$uid exists */
+ trash_dir = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%u", dir,
(guint) uid);
+ if (g_lstat (trash_dir, &statb) == 0)
+ {
+ /* must be a directory owned by user with rwx only for user */
+ if (statb.st_uid == uid && S_ISDIR (statb.st_mode) &&
(statb.st_mode & 0777) == 0700)
+ {
+use_trash_dir: /* release the root dir */
+ g_free (dir);
+
+ /* jap, that's our trash directory then */
+ return trash_dir;
+ }
+ else
+ {
+#ifdef HAVE_SYSLOG
+ /* the specification says the system administrator SHOULD be
informed, and so we do */
+ syslog (LOG_PID | LOG_USER | LOG_WARNING, "Trash directory
%s exists, but didn't pass the security checks, can't use it", trash_dir);
+#endif
+ }
+ }
+ else if (create && errno == ENOENT && tvit_initialize_trash_dir
(trash_dir))
+ {
+ /* jap, successfully created */
+ goto use_trash_dir;
+ }
+ g_free (trash_dir);
+ }
+ else
+ {
+#ifdef HAVE_SYSLOG
+ /* the specification says the system administrator SHOULD be
informed, and so we do */
+ syslog (LOG_PID | LOG_USER | LOG_WARNING, "Root trash directory %s
exists, but didn't pass the security checks, can't use it", dir);
+#endif
+ }
+ }
+ g_free (dir);
+
+ /* try with $top_dir/.Trash-$uid instead */
+ trash_dir = g_strdup_printf ("%s" G_DIR_SEPARATOR_S ".Trash-%u", top_dir,
(guint) uid);
+ if (g_lstat (trash_dir, &statb) == 0)
+ {
+ /* must be a directory owned by user with rwx only for user */
+ if (statb.st_uid == uid && S_ISDIR (statb.st_mode) && (statb.st_mode &
0777) == 0700)
+ {
+ /* jap, found it */
+ return trash_dir;
+ }
+ else
+ {
+#ifdef HAVE_SYSLOG
+ /* the specification says the system administrator SHOULD be
informed, and so we do */
+ syslog (LOG_PID | LOG_USER | LOG_WARNING, "Trash directory %s
exists, but didn't pass the security checks, can't use it", trash_dir);
+#endif
+ }
+ }
+ else if (create && errno == ENOENT && tvit_initialize_trash_dir (trash_dir))
+ {
+ /* jap, found it */
+ return trash_dir;
+ }
+ g_free (trash_dir);
+
+ /* no usable trash dir */
+ return NULL;
+}
+
+
+
/**
* _thunar_vfs_io_trash_scan:
*
@@ -110,7 +399,7 @@
_thunar_vfs_io_trash_scan (void)
{
/* scan the trash if not already done */
- if (G_UNLIKELY (_thunar_vfs_io_trash_timer_id < 0))
+ if (G_UNLIKELY (_thunar_vfs_io_trash_timer_id == 0))
_thunar_vfs_io_trash_rescan ();
}
@@ -138,8 +427,11 @@
G_LOCK (_thunar_vfs_io_trash);
/* check if we already scheduled the trash scan timer */
- if (G_UNLIKELY (_thunar_vfs_io_trash_timer_id < 0))
+ if (G_UNLIKELY (_thunar_vfs_io_trash_timer_id == 0))
{
+ /* initially scan the active mount points */
+ tvit_rescan_mount_points ();
+
/* schedule a timer to regularly scan the trash directories */
_thunar_vfs_io_trash_timer_id = g_timeout_add (5 * 1000, (GSourceFunc)
_thunar_vfs_io_trash_rescan, NULL);
}
@@ -178,6 +470,23 @@
/**
+ * _thunar_vfs_io_trash_rescan_mounts:
+ *
+ * Rescans all currently mounted devices to see if a new trash directory
+ * is available on one of the active mount points. This method is called
+ * by the #ThunarVfsVolume<!---->s whenever a change is noticed.
+ **/
+void
+_thunar_vfs_io_trash_rescan_mounts (void)
+{
+ G_LOCK (_thunar_vfs_io_trash);
+ tvit_rescan_mount_points ();
+ G_UNLOCK (_thunar_vfs_io_trash);
+}
+
+
+
+/**
* _thunar_vfs_io_trash_get_top_dir:
* @trash_id : the id of the trash, whose absolute toplevel directory to
return.
* @error : return location for errors or %NULL.
@@ -272,43 +581,6 @@
-static inline gchar*
-tvit_resolve_original_path (guint trash_id,
- const gchar *original_path_escaped,
- const gchar *relative_path,
- GError **error)
-{
- gchar *original_path_unescaped;
- gchar *absolute_path = NULL;
- gchar *top_dir;
-
- /* unescape the path according to RFC 2396 */
- original_path_unescaped = _thunar_vfs_unescape_rfc2396_string
(original_path_escaped, -1, "/", FALSE, error);
- if (G_UNLIKELY (original_path_unescaped == NULL))
- return NULL;
-
- /* check if we have a relative path here */
- if (!g_path_is_absolute (original_path_unescaped))
- {
- /* determine the toplevel directory for the trash-id */
- top_dir = _thunar_vfs_io_trash_get_top_dir (trash_id, error);
- if (G_LIKELY (top_dir != NULL))
- absolute_path = g_build_filename (top_dir, original_path_unescaped,
relative_path, NULL);
- g_free (original_path_unescaped);
- g_free (top_dir);
- }
- else
- {
- /* generate the absolute with the relative part */
- absolute_path = g_build_filename (original_path_unescaped,
relative_path, NULL);
- g_free (original_path_unescaped);
- }
-
- return absolute_path;
-}
-
-
-
/**
* _thunar_vfs_io_trash_get_trash_info:
* @path : a valid trash:-URI, which is not the trash root
path.
@@ -413,30 +685,103 @@
{
const gchar *original_name = thunar_vfs_path_get_name (original_path);
struct stat statb;
+ gchar absolute_path[THUNAR_VFS_PATH_MAXSTRLEN];
gchar deletion_date[128];
- gchar info_file[THUNAR_VFS_PATH_MAXSTRLEN];
+ gchar *mount_point = NULL;
+ gchar *trash_dir = NULL;
gchar *original_uri;
gchar *info_dir;
gchar *content;
+ guint trash_id = 0;
+ guint n;
gint fd;
- gint n;
_thunar_vfs_return_val_if_fail (_thunar_vfs_path_is_local (original_path),
FALSE);
_thunar_vfs_return_val_if_fail (error == NULL || *error == NULL, FALSE);
_thunar_vfs_return_val_if_fail (trash_id_return != NULL, FALSE);
_thunar_vfs_return_val_if_fail (file_id_return != NULL, FALSE);
- /* we are currently limited to the home trash */
+ /* determine the absolute path of the original file */
+ if (thunar_vfs_path_to_string (original_path, absolute_path, sizeof
(absolute_path), error) < 0)
+ return FALSE;
+
+ /* acquire the trash lock */
G_LOCK (_thunar_vfs_io_trash);
- info_dir = g_build_filename (_thunar_vfs_io_trashes[0].trash_dir, "info",
NULL);
+
+ /* check if this is file should be trashed to the home trash (also done if
stat fails) */
+ if (g_lstat (absolute_path, &statb) == 0 && statb.st_dev !=
_thunar_vfs_io_trash_homedev)
+ {
+ /* determine the mount point for the original file which is
+ * about to be deleted, and from the mount point we try to
+ * resolve the ID of the responsible trash directory.
+ */
+#if defined(HAVE_STATFS) && defined(HAVE_STRUCT_STATFS_F_MNTONNAME)
+ /* this is rather easy on BSDs (surprise)... */
+ struct statfs statfsb;
+ if (statfs (absolute_path, &statfsb) == 0)
+ mount_point = g_strdup (statfsb.f_mntonname);
+#else
+ /* ...and really messy otherwise (surprise!) */
+ GSList *mount_points, *lp;
+ dev_t dev = statb.st_dev;
+
+ /* check if any of the mount points matches (really should) */
+ mount_points = exo_mount_point_list_active (NULL);
+ for (lp = mount_points; lp != NULL; lp = lp->next)
+ {
+ /* stat this mount point, and check if it's the device we're
searching */
+ if (stat (((ExoMountPoint *) lp->data)->folder, &statb) == 0 &&
(statb.st_dev == dev))
+ {
+ /* got it, remember the folder of the mount point */
+ mount_point = g_strdup (((ExoMountPoint *) lp->data)->folder);
+ break;
+ }
+ }
+ g_slist_foreach (mount_points, (GFunc) exo_mount_point_free, NULL);
+ g_slist_free (mount_points);
+#endif
+
+ /* check if we have a mount point */
+ if (G_LIKELY (mount_point != NULL))
+ {
+ /* determine the trash directory for the mount point,
+ * creating the directory if it does not already exists
+ */
+ trash_dir = tvit_trash_dir_for_mount_point (mount_point, TRUE);
+ if (G_LIKELY (trash_dir != NULL))
+ trash_id = tvit_resolve_trash_dir_to_id (trash_dir);
+ }
+
+ /* check if rescanning might help */
+ if (trash_dir != NULL && trash_id == 0)
+ {
+ /* maybe we need to rescan the mount points */
+ tvit_rescan_mount_points ();
+
+ /* try to lookup the trash-id again */
+ trash_id = tvit_resolve_trash_dir_to_id (trash_dir);
+ }
+
+ /* cleanup */
+ g_free (mount_point);
+ g_free (trash_dir);
+ }
+
+ /* validate the trash-id to ensure we won't crash */
+ _thunar_vfs_assert (trash_id < _thunar_vfs_io_n_trashes);
+
+ /* determine the info sub directory for this trash */
+ info_dir = g_build_filename (_thunar_vfs_io_trashes[trash_id].trash_dir,
"info", NULL);
+
+ /* release the trash lock */
G_UNLOCK (_thunar_vfs_io_trash);
/* generate a unique file-id */
- g_snprintf (info_file, sizeof (info_file), "%s" G_DIR_SEPARATOR_S
"%s.trashinfo", info_dir, original_name);
+ g_snprintf (absolute_path, sizeof (absolute_path), "%s" G_DIR_SEPARATOR_S
"%s.trashinfo", info_dir, original_name);
for (n = 1;; ++n)
{
/* exclusively create the .trashinfo file */
- fd = g_open (info_file, O_CREAT | O_EXCL | O_WRONLY, 0600);
+ fd = g_open (absolute_path, O_CREAT | O_EXCL | O_WRONLY, 0600);
if (G_LIKELY (fd >= 0))
break;
@@ -455,7 +800,7 @@
if (G_UNLIKELY (errno != EEXIST))
{
err0: /* spit out a useful error message */
- content = g_filename_display_name (info_file);
+ content = g_filename_display_name (absolute_path);
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_IO, _("Failed to open
\"%s\" for writing"), content);
g_free (content);
err1:
@@ -464,14 +809,14 @@
}
/* generate a new unique .trashinfo file name and try again */
- g_snprintf (info_file, sizeof (info_file), "%s" G_DIR_SEPARATOR_S
"%s$%d.trashinfo", info_dir, original_name, n);
+ g_snprintf (absolute_path, sizeof (absolute_path), "%s"
G_DIR_SEPARATOR_S "%s$%u.trashinfo", info_dir, original_name, n);
}
/* stat the file to get the deletion date from the filesystem (NFS, ...) */
if (fstat (fd, &statb) < 0)
{
err2: /* should not happen */
- g_unlink (info_file);
+ g_unlink (absolute_path);
close (fd);
goto err0;
}
@@ -493,11 +838,11 @@
}
/* strip off the .trashinfo from the info_file */
- info_file[strlen (info_file) - (sizeof (".trashinfo") - 1)] = '\0';
+ absolute_path[strlen (absolute_path) - (sizeof (".trashinfo") - 1)] = '\0';
/* return the file-id and trash-id */
- *file_id_return = g_path_get_basename (info_file);
- *trash_id_return = 0;
+ *file_id_return = g_path_get_basename (absolute_path);
+ *trash_id_return = trash_id;
/* cleanup */
g_free (content);
@@ -1287,6 +1632,11 @@
}
else
{
+ /* unconditionally scan for trash directories to notice new
+ * (hot-plugged) trash directories on removable drives and media.
+ */
+ _thunar_vfs_io_trash_rescan_mounts ();
+
/* unconditionally rescan the trash directories */
_thunar_vfs_io_trash_rescan ();
@@ -1344,10 +1694,20 @@
void
_thunar_vfs_io_trash_init (void)
{
+ const gchar *home_dir;
+ struct stat statb;
+
+ /* determine the home folder path */
+ home_dir = g_get_home_dir ();
+
+ /* determine the device of the home folder */
+ if (stat (home_dir, &statb) == 0)
+ _thunar_vfs_io_trash_homedev = statb.st_dev;
+
/* setup the home trash */
_thunar_vfs_io_n_trashes = 1;
_thunar_vfs_io_trashes = g_new (ThunarVfsIOTrash, 1);
- _thunar_vfs_io_trashes->top_dir = g_strdup (g_get_home_dir ());
+ _thunar_vfs_io_trashes->top_dir = g_strdup (home_dir);
_thunar_vfs_io_trashes->trash_dir = g_build_filename (g_get_user_data_dir
(), "Trash", NULL);
_thunar_vfs_io_trashes->mtime = 0;
_thunar_vfs_io_trashes->empty = TRUE;
@@ -1364,11 +1724,11 @@
_thunar_vfs_io_trash_shutdown (void)
{
/* check if we have a pending trash rescan timer */
- if (G_LIKELY (_thunar_vfs_io_trash_timer_id >= 0))
+ if (G_LIKELY (_thunar_vfs_io_trash_timer_id != 0))
{
/* kill the pending trash rescan timer */
g_source_remove (_thunar_vfs_io_trash_timer_id);
- _thunar_vfs_io_trash_timer_id = -1;
+ _thunar_vfs_io_trash_timer_id = 0;
}
/* free the active trashes */
Modified: thunar/trunk/thunar-vfs/thunar-vfs-io-trash.h
===================================================================
--- thunar/trunk/thunar-vfs/thunar-vfs-io-trash.h 2007-01-12 23:32:33 UTC
(rev 24380)
+++ thunar/trunk/thunar-vfs/thunar-vfs-io-trash.h 2007-01-13 18:15:10 UTC
(rev 24381)
@@ -32,6 +32,7 @@
void _thunar_vfs_io_trash_scan (void) G_GNUC_INTERNAL;
gboolean _thunar_vfs_io_trash_rescan (void) G_GNUC_INTERNAL;
+void _thunar_vfs_io_trash_rescan_mounts (void) G_GNUC_INTERNAL;
gchar *_thunar_vfs_io_trash_get_top_dir (guint
trash_id,
GError
**error) G_GNUC_INTERNAL G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
Modified: thunar/trunk/thunar-vfs/thunar-vfs-volume.c
===================================================================
--- thunar/trunk/thunar-vfs/thunar-vfs-volume.c 2007-01-12 23:32:33 UTC (rev
24380)
+++ thunar/trunk/thunar-vfs/thunar-vfs-volume.c 2007-01-13 18:15:10 UTC (rev
24381)
@@ -23,6 +23,7 @@
#endif
#include <thunar-vfs/thunar-vfs-enum-types.h>
+#include <thunar-vfs/thunar-vfs-io-trash.h>
#include <thunar-vfs/thunar-vfs-private.h>
#include <thunar-vfs/thunar-vfs-volume-private.h>
#include <thunar-vfs/thunar-vfs-alias.h>
@@ -673,6 +674,11 @@
{
g_return_if_fail (THUNAR_VFS_IS_VOLUME (volume));
g_signal_emit (G_OBJECT (volume), volume_signals[CHANGED], 0);
+
+ /* rescan the mount points for the trash subsystem,
+ * as we may have a volume with a new trash dir now.
+ */
+ _thunar_vfs_io_trash_rescan_mounts ();
}
_______________________________________________
Xfce4-commits mailing list
[email protected]
http://foo-projects.org/mailman/listinfo/xfce4-commits