As the name indicates, the method @option{nextcloud} allows you to
access OwnCloud or NextCloud hosted files and directories. Like the
@option{gdrive} method, your credentials must be populated in your
-@command{Online Accounts} application outside Emacs. The method
+@command{Online Accounts} application outside Emacs. The method
supports port numbers.
@item @option{sftp}
Alternatively, set the user option @code{tramp-auto-save-directory}
to direct all auto saves to that location.
+@vindex tramp-allow-unsafe-temporary-files
+Per default, @value{tramp} asks for confirmation if a
+@samp{root}-owned backup or auto-save remote file has to be written to
+your local temporary directory. If you want to suppress this
+confirmation question, set user option
+@code{tramp-allow-unsafe-temporary-files} to @code{t}.
+
@node Keeping files encrypted
@section Protect remote files by encryption
Ad-hoc proxies can take patterns @code{%h} or @code{%u} like in
@code{tramp-default-proxies-alist}. The following file name expands
-to user @code{root} on host @code{remotehost}, starting with an
-@option{ssh} session on host @code{remotehost}:
+to user @samp{root} on host @samp{remotehost}, starting with an
+@option{ssh} session on host @samp{remotehost}:
@samp{@value{prefix}ssh@value{postfixhop}%h|su@value{postfixhop}remotehost@value{postfix}}.
On the other hand, if a trailing hop does not specify a host name,
-the host name of the previous hop is reused. Therefore, the following
+the host name of the previous hop is reused. Therefore, the following
file name is equivalent to the previous example:
@samp{@value{prefix}ssh@value{postfixhop}remotehost|su@value{postfixhop}@value{postfix}}.
@end lisp
Since @value{tramp} traverses subdirectories starting with the
-root-directory, it is most likely sufficient to make the
+root directory, it is most likely sufficient to make the
@code{default-directory} of the process buffer as the root directory.
** Windows
+++
-*** New option 'delete-window-choose-selected'.
+*** New user option 'delete-window-choose-selected'.
This allows to choose a frame's selected window after deleting the
previously selected one.
buffer to a file under the "/tmp/" directory. This is useful, if (in
rare cases) Tramp blocks Emacs, and we need further debug information.
++++
+*** Writing sensitive auto-save or backup files to the local temporary
+directory must be confirmed. In order to suppress this confirmation,
+set user option 'tramp-allow-unsafe-temporary-files' to t.
+
** Tempo
---
;; process key retrieved by `tramp-get-process' (the main connection
;; process). Other processes could reuse these properties, avoiding
;; recomputation when a new asynchronous process is created by
-;; `make-process'. Examples are "remote-path" or "device" (tramp-adb.el).
+;; `make-process'. Examples are "remote-path",
+;; "unsafe-temporary-file" or "device" (tramp-adb.el).
;;; Code:
;; don't save either, because all other properties might
;; depend on the login name, and we want to give the
;; possibility to use another login name later on. Key
- ;; "started" exists for the "ftp" method only, which must be
+ ;; "started" exists for the "ftp" method only, which must not
;; be kept persistent.
(maphash
(lambda (key value)
- (if (and (tramp-file-name-p key) value
+ (if (and (tramp-file-name-p key) (hash-table-p value)
(not (string-equal
(tramp-file-name-method key) tramp-archive-method))
(not (tramp-file-name-localname key))
;; cache the result for the session only. Otherwise, the
;; result is cached persistently.
(if (memq 'tramp-own-remote-path tramp-remote-path)
- (tramp-get-process vec)
- vec)
+ (tramp-get-process vec) vec)
"remote-path"
(let* ((remote-path (copy-tree tramp-remote-path))
(elt1 (memq 'tramp-default-remote-path remote-path))
(and (file-directory-p (file-name-directory filename))
(file-writable-p (file-name-directory filename)))))))
+(defcustom tramp-allow-unsafe-temporary-files nil
+ "Whether root-owned auto-save or backup files can be written to \"/tmp\"."
+ :version "28.1"
+ :type 'boolean)
+
(defun tramp-handle-find-backup-file-name (filename)
"Like `find-backup-file-name' for Tramp files."
(with-parsed-tramp-file-name filename nil
(tramp-make-tramp-file-name v (cdr x))
(cdr x))))
tramp-backup-directory-alist)
- backup-directory-alist)))
- (tramp-run-real-handler #'find-backup-file-name (list filename)))))
+ backup-directory-alist))
+ (uid (tramp-compat-file-attribute-user-id
+ (file-attributes filename 'integer)))
+ result)
+ (prog1 ;; Run plain `find-backup-file-name'.
+ (setq result
+ (tramp-run-real-handler
+ #'find-backup-file-name (list filename)))
+ ;; Protect against security hole.
+ (when (and (natnump uid) (zerop uid)
+ (file-in-directory-p (car result) temporary-file-directory)
+ (not tramp-allow-unsafe-temporary-files)
+ (not (with-tramp-connection-property
+ (tramp-get-process v) "unsafe-temporary-file"
+ (yes-or-no-p
+ (concat
+ "Backup file on local temporary directory, "
+ "do you want to continue? ")))))
+ (tramp-error v 'file-error "Unsafe backup file name"))))))
(defun tramp-handle-insert-directory
(filename switches &optional wildcard full-directory-p)
"Like `make-auto-save-file-name' for Tramp files.
Returns a file name in `tramp-auto-save-directory' for autosaving
this file, if that variable is non-nil."
- (when (stringp tramp-auto-save-directory)
- (setq tramp-auto-save-directory
- (expand-file-name tramp-auto-save-directory)))
- ;; Create directory.
- (unless (or (null tramp-auto-save-directory)
- (file-exists-p tramp-auto-save-directory))
- (make-directory tramp-auto-save-directory t))
-
- (let ((system-type
- (if (and (stringp tramp-auto-save-directory)
- (tramp-tramp-file-p tramp-auto-save-directory))
- 'not-windows
- system-type))
- (auto-save-file-name-transforms
- (if (null tramp-auto-save-directory)
- auto-save-file-name-transforms))
- (buffer-file-name
- (if (null tramp-auto-save-directory)
- buffer-file-name
- (expand-file-name
- (tramp-subst-strs-in-string
- '(("_" . "|")
- ("/" . "_a")
- (":" . "_b")
- ("|" . "__")
- ("[" . "_l")
- ("]" . "_r"))
- (tramp-compat-file-name-unquote (buffer-file-name)))
- tramp-auto-save-directory))))
- ;; Run plain `make-auto-save-file-name'.
- (tramp-run-real-handler #'make-auto-save-file-name nil)))
+ (with-parsed-tramp-file-name buffer-file-name nil
+ (when (stringp tramp-auto-save-directory)
+ (setq tramp-auto-save-directory
+ (expand-file-name tramp-auto-save-directory)))
+ ;; Create directory.
+ (unless (or (null tramp-auto-save-directory)
+ (file-exists-p tramp-auto-save-directory))
+ (make-directory tramp-auto-save-directory t))
+
+ (let ((system-type
+ (if (and (stringp tramp-auto-save-directory)
+ (tramp-tramp-file-p tramp-auto-save-directory))
+ 'not-windows
+ system-type))
+ (auto-save-file-name-transforms
+ (if (null tramp-auto-save-directory)
+ auto-save-file-name-transforms))
+ (uid (tramp-compat-file-attribute-user-id
+ (file-attributes buffer-file-name 'integer)))
+ (buffer-file-name
+ (if (null tramp-auto-save-directory)
+ buffer-file-name
+ (expand-file-name
+ (tramp-subst-strs-in-string
+ '(("_" . "|")
+ ("/" . "_a")
+ (":" . "_b")
+ ("|" . "__")
+ ("[" . "_l")
+ ("]" . "_r"))
+ (tramp-compat-file-name-unquote (buffer-file-name)))
+ tramp-auto-save-directory)))
+ result)
+ (prog1 ;; Run plain `make-auto-save-file-name'.
+ (setq result (tramp-run-real-handler #'make-auto-save-file-name nil))
+ ;; Protect against security hole.
+ (when (and (natnump uid) (zerop uid)
+ (file-in-directory-p result temporary-file-directory)
+ (not tramp-allow-unsafe-temporary-files)
+ (not (with-tramp-connection-property
+ (tramp-get-process v) "unsafe-temporary-file"
+ (yes-or-no-p
+ (concat
+ "Autosave file on local temporary directory, "
+ "do you want to continue? ")))))
+ (tramp-error v 'file-error "Unsafe autosave file name"))))))
(defun tramp-subst-strs-in-string (alist string)
"Replace all occurrences of the string FROM with TO in STRING.
"%s %f sec"
,message (float-time (time-subtract (current-time) start))))))
+;; `always' is introduced with Emacs 28.1.
+(defalias 'tramp--test-always
+ (if (fboundp 'always)
+ #'always
+ (lambda (&rest _arguments)
+ "Do nothing and return t.
+This function accepts any number of ARGUMENTS, but ignores them.
+Also see `ignore'."
+ t)))
+
(ert-deftest tramp-test00-availability ()
"Test availability of Tramp functions."
:expected-result (if (tramp--test-enabled) :passed :failed)
tramp--test-messages))))))))
;; Do not overwrite if excluded.
- (cl-letf (((symbol-function #'y-or-n-p) (lambda (_prompt) t))
+ (cl-letf (((symbol-function #'y-or-n-p) #'tramp--test-always)
;; Ange-FTP.
- ((symbol-function 'yes-or-no-p) (lambda (_prompt) t)))
+ ((symbol-function 'yes-or-no-p) #'tramp--test-always))
(write-region "foo" nil tmp-name nil nil nil 'mustbenew))
;; `mustbenew' is passed to Tramp since Emacs 26.1.
(when (tramp--test-emacs26-p)
(should-error
(make-symbolic-link tmp-name1 tmp-name2 0)
:type 'file-already-exists)))
- (cl-letf (((symbol-function #'yes-or-no-p) (lambda (_prompt) t)))
+ (cl-letf (((symbol-function #'yes-or-no-p) #'tramp--test-always))
(make-symbolic-link tmp-name1 tmp-name2 0)
(should
(string-equal
(should-error
(add-name-to-file tmp-name1 tmp-name2 0)
:type 'file-already-exists))
- (cl-letf (((symbol-function #'yes-or-no-p) (lambda (_prompt) t)))
+ (cl-letf (((symbol-function #'yes-or-no-p) #'tramp--test-always))
(add-name-to-file tmp-name1 tmp-name2 0)
(should (file-regular-p tmp-name2)))
(add-name-to-file tmp-name1 tmp-name2 'ok-if-already-exists)
If UNSTABLE is non-nil, the test is tagged as `:unstable'."
(declare (indent 1))
;; `make-process' supports file name handlers since Emacs 27.
- (when (let ((file-name-handler-alist '(("" . (lambda (&rest _) t)))))
+ (when (let ((file-name-handler-alist '(("" . #'tramp--test-always))))
(ignore-errors (make-process :file-handler t)))
`(ert-deftest ,(intern (concat (symbol-name test) "-direct-async")) ()
,docstring
;; `file-truename' does it by side-effect. Suppress
;; `tramp--test-enabled', in order to keep the connection.
;; Suppress "Process ... finished" messages.
- (cl-letf (((symbol-function #'tramp--test-enabled) (lambda nil t))
+ (cl-letf (((symbol-function #'tramp--test-enabled) #'tramp--test-always)
((symbol-function #'internal-default-process-sentinel)
#'ignore))
(file-truename tramp-test-temporary-file-directory)
("]" . "_r"))
(tramp-compat-file-name-unquote tmp-name1)))
tmp-name2)))
- (should (file-directory-p tmp-name2))))))
+ (should (file-directory-p tmp-name2)))))
+
+ ;; Create temporary file. This shall check for sensible
+ ;; files, owned by root.
+ (let ((tramp-auto-save-directory temporary-file-directory)
+ tramp-allow-unsafe-temporary-files)
+ (write-region "foo" nil tmp-name1)
+ (when (zerop (or (tramp-compat-file-attribute-user-id
+ (file-attributes tmp-name1))
+ tramp-unknown-id-integer))
+ (with-temp-buffer
+ (setq buffer-file-name tmp-name1)
+ (tramp-cleanup-connection
+ tramp-test-vec 'keep-debug 'keep-password)
+ (let ((tramp-allow-unsafe-temporary-files t))
+ (should (stringp (make-auto-save-file-name))))
+ (tramp-cleanup-connection
+ tramp-test-vec 'keep-debug 'keep-password)
+ (cl-letf (((symbol-function #'yes-or-no-p) #'ignore))
+ (should-error
+ (make-auto-save-file-name)
+ :type 'file-error))
+ (tramp-cleanup-connection
+ tramp-test-vec 'keep-debug 'keep-password)
+ (cl-letf (((symbol-function #'yes-or-no-p)
+ #'tramp--test-always))
+ (should (stringp (make-auto-save-file-name))))))))
;; Cleanup.
(ignore-errors (delete-file tmp-name1))
- (ignore-errors (delete-directory tmp-name2 'recursive))))))
+ (ignore-errors (delete-directory tmp-name2 'recursive))
+ (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)))))
(ert-deftest tramp-test38-find-backup-file-name ()
"Check `find-backup-file-name'."
(should (file-directory-p tmp-name2))))
;; Cleanup.
- (ignore-errors (delete-directory tmp-name2 'recursive))))))
+ (ignore-errors (delete-directory tmp-name2 'recursive)))
+
+ (unwind-protect
+ ;; Create temporary file. This shall check for sensible
+ ;; files, owned by root.
+ (let ((backup-directory-alist `(("." . ,temporary-file-directory)))
+ tramp-allow-unsafe-temporary-files
+ tramp-backup-directory-alist)
+ (write-region "foo" nil tmp-name1)
+ (when (zerop (or (tramp-compat-file-attribute-user-id
+ (file-attributes tmp-name1))
+ tramp-unknown-id-integer))
+ (tramp-cleanup-connection
+ tramp-test-vec 'keep-debug 'keep-password)
+ (let ((tramp-allow-unsafe-temporary-files t))
+ (should (stringp (car (find-backup-file-name tmp-name1)))))
+ (tramp-cleanup-connection
+ tramp-test-vec 'keep-debug 'keep-password)
+ (cl-letf (((symbol-function #'yes-or-no-p) #'ignore))
+ (should-error
+ (find-backup-file-name tmp-name1)
+ :type 'file-error))
+ (tramp-cleanup-connection
+ tramp-test-vec 'keep-debug 'keep-password)
+ (cl-letf (((symbol-function #'yes-or-no-p)
+ #'tramp--test-always))
+ (should (stringp (car (find-backup-file-name tmp-name1)))))))
+
+ ;; Cleanup.
+ (ignore-errors (delete-file tmp-name1))
+ (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)))))
;; The functions were introduced in Emacs 26.1.
(ert-deftest tramp-test39-make-nearby-temp-file ()