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 Xfce4-commits@xfce.org http://foo-projects.org/mailman/listinfo/xfce4-commits