From: David De La Harpe Golden <david@harpegolden.net>
To: submit@emacsbugs.donarmstrong.com
Subject: bug#973: Support for moving files to freedesktop.org-style trashcan.
Date: Sat, 13 Sep 2008 04:42:13 +0100 [thread overview]
Message-ID: <48CB3695.9020708@harpegolden.net> (raw)
[-- Attachment #1: Type: text/plain, Size: 852 bytes --]
Package: emacs
Version: 23.0.60
Severity: normal
Tags: patch
delete-by-moving-to-trash was recently introduced, but doesn't
really work as expected for typical gnu+linux desktop users, and I had
some procrastination to do, so...
Attached patch adds basic support for moving files to a fd.o-style
trashcan, as used in KDE/GNOME/XFCE/etc. and documented at:
http://www.freedesktop.org/wiki/Specifications/trash-spec
Unlike "Microsoft Windows? -> use Windows Recycle Bin" or "MacOSX? ->
use MacOSX trash can", one maybe can't say "GNU/Linux/BSD? -> use
freedesktop-style Trash", so whether the freedesktop-style trashcan
should be preferred over the simple emacs fallback "trash-directory"
scheme is decided a bit roughly.
Maybe a move-file-to-trash-scheme should just be a user-visible
customisation.
... I hate trashcans anyway.
[-- Attachment #2: move-file-to-trash-freedesktop_r1.diff --]
[-- Type: text/x-patch, Size: 7475 bytes --]
Index: lisp/files.el
===================================================================
RCS file: /sources/emacs/emacs/lisp/files.el,v
retrieving revision 1.995
diff -U 8 -r1.995 files.el
--- lisp/files.el 2 Sep 2008 16:10:44 -0000 1.995
+++ lisp/files.el 13 Sep 2008 03:05:31 -0000
@@ -5793,24 +5793,165 @@
not defined. Relative paths are interpreted relative to `default-directory'.
See also `delete-by-moving-to-trash'."
:type 'directory
:group 'auto-save
:version "23.1")
(declare-function system-move-file-to-trash "w32fns.c" (filename))
+(defun move-file-to-trash-freedesktop (filename)
+ "Attempt to move file/dir to trash the freedesktop.org way (like e.g. GNOME,
+KDE and XFCE desktop environment trash facilities). Usually called automatically
+by `move-file-to-trash'.
+
+Only moves to 'home trash', per-volume trash storage areas are never used, as
+permitted by freedesktop.org trash-spec 0.7."
+
+ (interactive "fMove file to trash: ")
+ (let* ((saved-default-file-modes (default-file-modes))
+ (xdg-data-home-dir (directory-file-name (expand-file-name
+ (or (getenv "XDG_DATA_HOME")
+ "~/.local/share"))))
+ (trash-dir (concat xdg-data-home-dir "/Trash"))
+ (trash-files-dir (concat trash-dir "/files"))
+ (trash-info-dir (concat trash-dir "/info"))
+ (fn (directory-file-name (expand-file-name filename)))
+ (fn-nondir (file-name-nondirectory fn)))
+
+ ;; trash-spec 0.7 says to check if we have permissions to
+ ;; delete before attempting to delete.
+ (unless (file-writable-p (directory-file-name (file-name-directory fn)))
+ (error "Cannot move file `%s' to Trash, insufficient permissions" filename))
+
+ ;; stop processing if fn is same or parent directory of trash-dir.
+ (when (or (string-match fn trash-files-dir)
+ (string-match fn trash-info-dir)
+ (string-match fn trash-dir))
+ (error "Filename `%s' is same or parent directory of Trash."
+ filename))
+
+ ;; ensure trash directory exists, using appropriate permissions if creating it.
+ (set-default-file-modes #o700)
+ (make-directory trash-files-dir t)
+ (make-directory trash-info-dir t)
+ (set-default-file-modes saved-default-file-modes)
+
+ ;; try to move to trash with associated .trashinfo undo information
+ (save-excursion
+ (with-temp-buffer
+ (set-buffer-file-coding-system 'utf-8-unix)
+ ;; url-encode path, though allow literal "/" for path separators.
+ ;; trash-spec 0.7 is slightly confusing on that point. At time of writing,
+ ;; KDE Konqueror accepts both literal and %2f-encoded slashes, XFCE Thunar
+ ;; only literal slashes.
+ ;; Using / makes .trashinfo files much more readable, and while / is a
+ ;; reserved character in url components, it is a valid separator in urls,
+ ;; so the intent was likely to allow it.
+ ;; yes, this is lifted from url-hexify-string
+ ;; but don't want to pull in url/*.el , and it's not quite the same due to /
+ (insert "[Trash Info]\n"
+ "Path=" (mapconcat
+ (lambda (byte)
+ (if (memq byte
+ '(?/ ?a ?b ?c ?d ?e ?f ?g ?h ?i ?j
+ ?k ?l ?m ?n ?o ?p ?q ?r ?s ?t
+ ?u ?v ?w ?x ?y ?z ?A ?B ?C ?D
+ ?E ?F ?G ?H ?I ?J ?K ?L ?M ?N
+ ?O ?P ?Q ?R ?S ?T ?U ?V ?W ?X
+ ?Y ?Z ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7
+ ?8 ?9 ?- ?_ ?. ?! ?~ ?* ?' ?\( ?\)))
+ (char-to-string byte)
+ (format "%%%02x" byte)))
+ (if (multibyte-string-p fn)
+ (encode-coding-string fn 'utf-8)
+ fn)
+ "")
+ "\nDeletionDate=" (format-time-string "%Y-%m-%dT%T") "\n")
+ (let* ((maxtries 5)
+ (tries maxtries)
+ (success nil)
+ (base-fn (expand-file-name fn-nondir trash-files-dir))
+ (new-fn base-fn)
+ (info-fn (concat new-fn ".trashinfo")))
+ ;; attempt to make .trashinfo file, retries up to 5
+ ;; times (arbitrarily chosen, spec just says "pick
+ ;; another filename"). .trashinfo file opened o_excl _is_
+ ;; lock as per trash-spec 0.7 (even if that can be a
+ ;; problem on old NFS versions...)
+ (while (and (not success) (> tries 0))
+ ;; make new-fn unique.
+ ;; Unfortunately, contemporary file managers with fd.o trashcan support
+ ;; do not like emacs backup file naming scheme here (as used in default emacs
+ ;; trash implementation) - see bug 4381 in XFCE Thunar bug tracker,
+ ;; bug 170956 in KDE Konqueror bug tracker.
+ ;; (let ((version-control t))
+ ;; (setq new-fn (car (find-backup-file-name base-fn))))
+ (when (< tries maxtries)
+ (setq new-fn (make-temp-name (concat base-fn "_"))))
+ (setq info-fn (concat (expand-file-name (file-name-nondirectory new-fn)
+ trash-info-dir)
+ ".trashinfo"))
+ (unless (condition-case nil
+ (progn
+ (write-region nil nil info-fn nil 'quiet info-fn 'excl)
+ (setq success t))
+ (file-already-exists nil))
+ (setq tries (- tries 1))
+ (sleep-for 0.1)))
+ (unless success (error "Failed to lock Trash for filename `%s'" filename))
+ ;; Finally... if we've got this far, let's
+ ;; try to actually move the file to the trashcan.
+ (let ((delete-by-moving-to-trash nil))
+ (rename-file fn new-fn)))))))
+
+(defvar move-file-to-trash--freedesktop-p-memo nil)
+(defun move-file-to-trash--freedesktop-p ()
+ "Guess if the system should be considered freedesktop.org -oid
+for `move-file-to-trash' purposes. Only used in absence of
+overriding `system-move-file-to-trash' "
+ ;; presumably constant throughout an emacs session.
+ (or move-file-to-trash--freedesktop-p-memo
+ (setq move-file-to-trash--freedesktop-p-memo
+ (if (and
+ ;; assume macosx and windows folk are going to want their own
+ ;; trashcans even though people might sometimes compile
+ ;; and run freedesktop.org apps on them.
+ (not (eq system-type 'darwin))
+ (not (eq system-type 'windows))
+ (or
+ ;; dead giveaway.
+ (file-exists-p "~/.local/share/Trash")
+ (getenv "XDG_DATA_HOME")
+ (getenv "XDG_CONFIG_HOME")
+ (getenv "XDG_DATA_DIRS")
+ (getenv "XDG_CONFIG_DIRS")
+ (getenv "XDG_CACHE_HOME")
+ (file-exists-p "/etc/xdg")
+ (file-exists-p "~/.local")
+ (file-exists-p "~/.config")))
+ t
+ nil))))
+
(defun move-file-to-trash (filename)
"Move file (or directory) name FILENAME to the trash.
This function is called by `delete-file' and `delete-directory' when
`delete-by-moving-to-trash' is non-nil. On platforms that define
`system-move-file-to-trash', that function is used to move FILENAME to the
-system trash, otherwise FILENAME is moved to `trash-directory'.
+system trash, otherwise on systems that appear to be using a
+freedesktop.org compliant trashcan `move-file-to-trash-freedesktop'
+is used (and bound to `system-move-file-to-trash'), otherwise
+FILENAME is moved to `trash-directory'.
Returns nil on success."
(interactive "fMove file to trash: ")
+ (unless (fboundp 'system-move-file-to-trash)
+ (when (move-file-to-trash--freedesktop-p)
+ (fset 'system-move-file-to-trash
+ (lambda (filename)
+ (move-file-to-trash-freedesktop filename)))))
(cond
((fboundp 'system-move-file-to-trash)
(system-move-file-to-trash filename))
(t
(let* ((trash-dir (expand-file-name trash-directory))
(fn (directory-file-name (expand-file-name filename)))
(fn-nondir (file-name-nondirectory fn))
(new-fn (expand-file-name fn-nondir trash-dir)))
[-- Attachment #3: ChangeLog.move-file-to-trash-freedesktop_r1 --]
[-- Type: text/plain, Size: 176 bytes --]
2008-09-13 David De La Harpe Golden <david@harpegolden.net>
* files.el: Add basic support for moving files to freedesktop.org
Trash cans (as used by KDE/GNOME/XFCE/etc.).
next reply other threads:[~2008-09-13 3:42 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <87skhl0x8h.fsf@stupidchicken.com>
2008-09-13 3:42 ` David De La Harpe Golden [this message]
2009-06-28 5:05 ` bug#973: marked as done (Support for moving files to freedesktop.org-style trashcan.) Emacs bug Tracking System
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=48CB3695.9020708@harpegolden.net \
--to=david@harpegolden.net \
--cc=973@emacsbugs.donarmstrong.com \
--cc=submit@emacsbugs.donarmstrong.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.