1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-11-23 07:19:15 +00:00

Further fixes while testing tramp-crypt

* doc/misc/tramp.texi (External methods): Remove experimental note
for rclone.
(Keeping files encrypted): Mark file encryption as experimental.

* lisp/net/tramp-adb.el (tramp-adb-file-name-handler-alist):
Use `tramp-handle-file-truename'.
(tramp-adb-handle-file-truename): Remove.

* lisp/net/tramp-crypt.el (tramp-crypt-file-name-handler-alist):
Add `file-writable-p'.
(tramp-crypt-send-command): Return t if no error.
(tramp-crypt-do-encrypt-or-decrypt-file-name)
(tramp-crypt-do-encrypt-or-decrypt-file): Raise an error if it fails.
(tramp-crypt-do-copy-or-rename-file): Flush file properties also
when copying a directory.
(tramp-crypt-handle-file-writable-p): New defun.
(tramp-crypt-handle-insert-directory): Check for library
`text-property-search'.

* lisp/net/tramp-gvfs.el (tramp-gvfs-handle-set-file-uid-gid):
Rename from `tramp-gvfs-set-file-uid-gid'.

* lisp/net/tramp-sh.el (tramp-sh-handle-file-truename):
Use `tramp-handle-file-truename' as fallback.

* lisp/net/tramp.el (tramp-handle-file-truename):
Let-bind `tramp-crypt-enabled' to nil.
(tramp-handle-write-region): Set also file ownership.

* test/lisp/net/tramp-tests.el (tramp-test17-insert-directory):
Skip if needed.
This commit is contained in:
Michael Albinus 2020-06-12 20:17:02 +02:00
parent 54efe18959
commit 459bd56f46
7 changed files with 96 additions and 215 deletions

View File

@ -1185,9 +1185,6 @@ for accessing the system storage, you shall prefer this.
@ref{GVFS-based methods} for example, methods @option{gdrive} and
@option{nextcloud}.
@strong{Note}: The @option{rclone} method is experimental, don't use
it in production systems!
@end table
@ -1732,6 +1729,7 @@ Convenience method to access vagrant boxes. It is often used in
multi-hop file names like
@file{@value{prefix}vagrant@value{postfixhop}box|sudo@value{postfixhop}box@value{postfix}/path/to/file},
where @samp{box} is the name of the vagrant box.
@end table
@ -2655,6 +2653,9 @@ to direct all auto saves to that location.
@section Protect remote files by encryption
@cindex Encrypt remote directories
@strong{Note}: File encryption in @value{tramp} is experimental, don't
use it in production systems!
Sometimes, it is desirable to protect files located on remote
directories, like cloud storages. In order to do this, you might
instruct @value{tramp} to encrypt all files copied to a given remote

View File

@ -136,7 +136,7 @@ It is used for TCP/IP devices."
(file-selinux-context . tramp-handle-file-selinux-context)
(file-symlink-p . tramp-handle-file-symlink-p)
(file-system-info . tramp-adb-handle-file-system-info)
(file-truename . tramp-adb-handle-file-truename)
(file-truename . tramp-handle-file-truename)
(file-writable-p . tramp-adb-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.
@ -227,104 +227,6 @@ ARGUMENTS to pass to the OPERATION."
(string-to-number (match-string 2))))
(* 1024 (string-to-number (match-string 3)))))))))
;; This is derived from `tramp-sh-handle-file-truename'. Maybe the
;; code could be shared?
(defun tramp-adb-handle-file-truename (filename)
"Like `file-truename' for Tramp files."
;; Preserve trailing "/".
(funcall
(if (directory-name-p filename) #'file-name-as-directory #'identity)
;; Quote properly.
(funcall
(if (tramp-compat-file-name-quoted-p filename)
#'tramp-compat-file-name-quote #'identity)
(with-parsed-tramp-file-name
(tramp-compat-file-name-unquote (expand-file-name filename)) nil
(tramp-make-tramp-file-name
v
(with-tramp-file-property v localname "file-truename"
(let (result) ; result steps in reverse order
(tramp-message v 4 "Finding true name for `%s'" filename)
(let* ((steps (split-string localname "/" 'omit))
(localnamedir (tramp-run-real-handler
'file-name-as-directory (list localname)))
(is-dir (string= localname localnamedir))
(thisstep nil)
(numchase 0)
;; Don't make the following value larger than
;; necessary. People expect an error message in a
;; timely fashion when something is wrong; otherwise
;; they might think that Emacs is hung. Of course,
;; correctness has to come first.
(numchase-limit 20)
symlink-target)
(while (and steps (< numchase numchase-limit))
(setq thisstep (pop steps))
(tramp-message
v 5 "Check %s"
(string-join
(append '("") (reverse result) (list thisstep)) "/"))
(setq symlink-target
(tramp-compat-file-attribute-type
(file-attributes
(tramp-make-tramp-file-name
v
(string-join
(append
'("") (reverse result) (list thisstep)) "/")))))
(cond ((string= "." thisstep)
(tramp-message v 5 "Ignoring step `.'"))
((string= ".." thisstep)
(tramp-message v 5 "Processing step `..'")
(pop result))
((stringp symlink-target)
;; It's a symlink, follow it.
(tramp-message v 5 "Follow symlink to %s" symlink-target)
(setq numchase (1+ numchase))
(when (file-name-absolute-p symlink-target)
(setq result nil))
;; If the symlink was absolute, we'll get a string
;; like "/user@host:/some/target"; extract the
;; "/some/target" part from it.
(when (tramp-tramp-file-p symlink-target)
(unless (tramp-equal-remote filename symlink-target)
(tramp-error
v 'file-error
"Symlink target `%s' on wrong host" symlink-target))
(setq symlink-target localname))
(setq steps
(append (split-string symlink-target "/" 'omit)
steps)))
(t
;; It's a file.
(setq result (cons thisstep result)))))
(when (>= numchase numchase-limit)
(tramp-error
v 'file-error
"Maximum number (%d) of symlinks exceeded" numchase-limit))
(setq result (reverse result))
;; Combine list to form string.
(setq result
(if result
(string-join (cons "" result) "/")
"/"))
(when (and is-dir (or (string-empty-p result)
(not (string= (substring result -1) "/"))))
(setq result (concat result "/"))))
;; Detect cycle.
(when (and (file-symlink-p filename)
(string-equal result localname))
(tramp-error
v 'file-error
"Apparent cycle of symbolic links for %s" filename))
;; If the resulting localname looks remote, we must quote it
;; for security reasons.
(when (file-remote-p result)
(setq result (tramp-compat-file-name-quote result 'top)))
(tramp-message v 4 "True name of `%s' is `%s'" localname result)
result)))))))
(defun tramp-adb-handle-file-attributes (filename &optional id-format)
"Like `file-attributes' for Tramp files."
(unless id-format (setq id-format 'integer))

View File

@ -24,7 +24,7 @@
;;; Commentary:
;; Access functions for crypted remote files. It uses encfs to
;; encrypt/ decrypt the files on a remote directory. A remote
;; encrypt / decrypt the files on a remote directory. A remote
;; directory, which shall include crypted files, must be declared in
;; `tramp-crypt-directories' via command `tramp-crypt-add-directory'.
;; All files in that directory, including all subdirectories, are
@ -189,8 +189,8 @@ If NAME doesn't belong to a crypted remote directory, retun nil."
(file-selinux-context . ignore)
(file-symlink-p . tramp-handle-file-symlink-p)
(file-system-info . tramp-crypt-handle-file-system-info)
;; (file-truename . tramp-crypt-handle-file-truename)
;; (file-writable-p . ignore)
;; `file-truename' performed by default handler.
(file-writable-p . tramp-crypt-handle-file-writable-p)
(find-backup-file-name . tramp-handle-find-backup-file-name)
;; `get-file-buffer' performed by default handler.
(insert-directory . tramp-crypt-handle-insert-directory)
@ -351,7 +351,7 @@ connection if a previous connection has died for some reason."
(defun tramp-crypt-send-command (vec &rest args)
"Send encfsctl command to connection VEC.
ARGS are the arguments."
ARGS are the arguments. It returns t if ran successful, and nil otherwise."
(tramp-crypt-maybe-open-connection vec)
(with-current-buffer (tramp-get-connection-buffer vec)
(erase-buffer))
@ -380,11 +380,12 @@ ARGS are the arguments."
;; Save the password.
(ignore-errors
(and (functionp tramp-password-save-function)
(funcall tramp-password-save-function)))))))
(funcall tramp-password-save-function)))
t))))
(defun tramp-crypt-do-encrypt-or-decrypt-file-name (op name)
"Return encrypted/ decrypted NAME if NAME belongs to a crypted directory.
OP must be `encrypt' or `decrypt'.
"Return encrypted / decrypted NAME if NAME belongs to a crypted directory.
OP must be `encrypt' or `decrypt'. Raise an error if this fails.
Otherwise, return NAME."
(if-let ((tramp-crypt-enabled t)
(dir (tramp-crypt-file-name-p name))
@ -399,9 +400,12 @@ Otherwise, return NAME."
(unless (string-equal localname "/")
(with-tramp-file-property
crypt-vec localname (concat (symbol-name op) "-file-name")
(tramp-crypt-send-command
crypt-vec (if (eq op 'encrypt) "encode" "decode")
(tramp-compat-temporary-file-directory) localname)
(unless (tramp-crypt-send-command
crypt-vec (if (eq op 'encrypt) "encode" "decode")
(tramp-compat-temporary-file-directory) localname)
(tramp-error
crypt-vec "%s of file name %s failed."
(if (eq op 'encrypt) "Encoding" "Decoding") name))
(with-current-buffer (tramp-get-connection-buffer crypt-vec)
(goto-char (point-min))
(buffer-substring (point-min) (point-at-eol)))))))
@ -419,9 +423,10 @@ Otherwise, return NAME."
(tramp-crypt-do-encrypt-or-decrypt-file-name 'decrypt name))
(defun tramp-crypt-do-encrypt-or-decrypt-file (op root infile outfile)
"Encrypt/ decrypt file INFILE to OUTFILE according to crypted directory ROOT.
"Encrypt / decrypt file INFILE to OUTFILE according to crypted directory ROOT.
Both files must be local files. OP must be `encrypt' or `decrypt'.
If OP ist `decrypt', the basename of INFILE must be an encrypted file name."
If OP ist `decrypt', the basename of INFILE must be an encrypted file name.
Raise an error if this fails."
(when-let ((tramp-crypt-enabled t)
(dir (tramp-crypt-file-name-p root))
(crypt-vec (tramp-crypt-dissect-file-name dir)))
@ -429,10 +434,13 @@ If OP ist `decrypt', the basename of INFILE must be an encrypted file name."
(if (eq op 'decrypt) 'binary coding-system-for-read))
(coding-system-for-write
(if (eq op 'encrypt) 'binary coding-system-for-write)))
(tramp-crypt-send-command
crypt-vec "cat" (and (eq op 'encrypt) "--reverse")
(file-name-directory infile)
(concat "/" (file-name-nondirectory infile)))
(unless (tramp-crypt-send-command
crypt-vec "cat" (and (eq op 'encrypt) "--reverse")
(file-name-directory infile)
(concat "/" (file-name-nondirectory infile)))
(tramp-error
crypt-vec "%s of file %s failed."
(if (eq op 'encrypt) "Encrypting" "Decrypting") infile))
(with-current-buffer (tramp-get-connection-buffer crypt-vec)
(write-region nil nil outfile)))))
@ -520,16 +528,17 @@ absolute file names."
(error "Unknown operation `%s', must be `copy' or `rename'" op))
(setq filename (file-truename filename))
(if (file-directory-p filename)
(progn
(copy-directory filename newname keep-date t)
(when (eq op 'rename) (delete-directory filename 'recursive)))
(let ((t1 (tramp-crypt-file-name-p filename))
(t2 (tramp-crypt-file-name-p newname))
(encrypt-filename (tramp-crypt-encrypt-file-name filename))
(encrypt-newname (tramp-crypt-encrypt-file-name newname))
(msg-operation (if (eq op 'copy) "Copying" "Renaming")))
(let ((t1 (tramp-crypt-file-name-p filename))
(t2 (tramp-crypt-file-name-p newname))
(encrypt-filename (tramp-crypt-encrypt-file-name filename))
(encrypt-newname (tramp-crypt-encrypt-file-name newname))
(msg-operation (if (eq op 'copy) "Copying" "Renaming")))
(if (file-directory-p filename)
(progn
(copy-directory filename newname keep-date t)
(when (eq op 'rename)
(delete-directory filename 'recursive)))
(with-parsed-tramp-file-name (if t1 filename newname) nil
(unless (file-exists-p filename)
@ -581,15 +590,15 @@ absolute file names."
(rename-file filename tmpfile1 t))
(tramp-crypt-encrypt-file t2 tmpfile1 tmpfile2)
(rename-file tmpfile2 encrypt-newname ok-if-already-exists)))
(delete-directory tmpdir 'recursive)))
(delete-directory tmpdir 'recursive))))))
(when (and t1 (eq op 'rename))
(with-parsed-tramp-file-name filename v1
(tramp-flush-file-properties v1 v1-localname)))
(when (and t1 (eq op 'rename))
(with-parsed-tramp-file-name filename v1
(tramp-flush-file-properties v1 v1-localname)))
(when t2
(with-parsed-tramp-file-name newname v2
(tramp-flush-file-properties v2 v2-localname))))))))
(when t2
(with-parsed-tramp-file-name newname v2
(tramp-flush-file-properties v2 v2-localname)))))
(defun tramp-crypt-handle-copy-file
(filename newname &optional ok-if-already-exists keep-date
@ -692,28 +701,35 @@ absolute file names."
;; #'file-system-info.
'file-system-info (list (tramp-crypt-encrypt-file-name filename))))
(defun tramp-crypt-handle-file-writable-p (filename)
"Like `file-writable-p' for Tramp files."
(let (tramp-crypt-enabled)
(file-writable-p (tramp-crypt-encrypt-file-name filename))))
(defun tramp-crypt-handle-insert-directory
(filename switches &optional wildcard full-directory-p)
"Like `insert-directory' for Tramp files."
(let (tramp-crypt-enabled)
(tramp-handle-insert-directory
(tramp-crypt-encrypt-file-name filename)
switches wildcard full-directory-p)
(let* ((filename (file-name-as-directory filename))
(enc (tramp-crypt-encrypt-file-name filename))
match string)
(goto-char (point-min))
(while (setq match (text-property-search-forward 'dired-filename t t))
(setq string
(buffer-substring
(prop-match-beginning match) (prop-match-end match))
string (if (file-name-absolute-p string)
(tramp-crypt-decrypt-file-name string)
(substring
(tramp-crypt-decrypt-file-name (concat enc string))
(length filename))))
(delete-region (prop-match-beginning match) (prop-match-end match))
(insert (propertize string 'dired-filename t))))))
;; This package has been added to Emacs 27.1.
(when (load "text-property-search" 'noerror 'nomessage)
(let (tramp-crypt-enabled)
(tramp-handle-insert-directory
(tramp-crypt-encrypt-file-name filename)
switches wildcard full-directory-p)
(let* ((filename (file-name-as-directory filename))
(enc (tramp-crypt-encrypt-file-name filename))
match string)
(goto-char (point-min))
(while (setq match (text-property-search-forward 'dired-filename t t))
(setq string
(buffer-substring
(prop-match-beginning match) (prop-match-end match))
string (if (file-name-absolute-p string)
(tramp-crypt-decrypt-file-name string)
(substring
(tramp-crypt-decrypt-file-name (concat enc string))
(length filename))))
(delete-region (prop-match-beginning match) (prop-match-end match))
(insert (propertize string 'dired-filename t)))))))
(defun tramp-crypt-handle-make-directory (dir &optional parents)
"Like `make-directory' for Tramp files."

View File

@ -1589,7 +1589,7 @@ If FILE-SYSTEM is non-nil, return file system attributes."
(current-time)
time)))))
(defun tramp-gvfs-set-file-uid-gid (filename &optional uid gid)
(defun tramp-gvfs-handle-set-file-uid-gid (filename &optional uid gid)
"Like `tramp-set-file-uid-gid' for Tramp files."
(with-parsed-tramp-file-name filename nil
(tramp-flush-file-properties v localname)

View File

@ -1153,59 +1153,9 @@ component is used as the target of the symlink."
(tramp-shell-quote-argument localname)))))
;; Do it yourself.
(t (let ((steps (split-string localname "/" 'omit))
(thisstep nil)
(numchase 0)
;; Don't make the following value larger than
;; necessary. People expect an error message in a
;; timely fashion when something is wrong;
;; otherwise they might think that Emacs is hung.
;; Of course, correctness has to come first.
(numchase-limit 20)
symlink-target)
(while (and steps (< numchase numchase-limit))
(setq thisstep (pop steps))
(tramp-message
v 5 "Check %s"
(string-join
(append '("") (reverse result) (list thisstep)) "/"))
(setq symlink-target
(tramp-compat-file-attribute-type
(file-attributes
(tramp-make-tramp-file-name
v
(string-join
(append
'("") (reverse result) (list thisstep)) "/")
'nohop))))
(cond ((string= "." thisstep)
(tramp-message v 5 "Ignoring step `.'"))
((string= ".." thisstep)
(tramp-message v 5 "Processing step `..'")
(pop result))
((stringp symlink-target)
;; It's a symlink, follow it.
(tramp-message
v 5 "Follow symlink to %s" symlink-target)
(setq numchase (1+ numchase))
(when (file-name-absolute-p symlink-target)
(setq result nil))
(setq steps
(append
(split-string symlink-target "/" 'omit)
steps)))
(t
;; It's a file.
(setq result (cons thisstep result)))))
(when (>= numchase numchase-limit)
(tramp-error
v 'file-error
"Maximum number (%d) of symlinks exceeded" numchase-limit))
(setq result (reverse result)
;; Combine list to form string.
result
(if result (string-join (cons "" result) "/") "/"))
(when (string-empty-p result) (setq result "/")))))
(t (setq
result
(tramp-file-local-name (tramp-handle-file-truename filename)))))
;; Detect cycle.
(when (and (file-symlink-p filename)

View File

@ -3381,6 +3381,8 @@ User is always nil."
;; something is wrong; otherwise they might think that Emacs
;; is hung. Of course, correctness has to come first.
(numchase-limit 20)
;; Unquoting could enable encryption.
tramp-crypt-enabled
symlink-target)
(with-parsed-tramp-file-name result v1
;; We cache only the localname.
@ -3900,7 +3902,11 @@ of."
(let ((tmpfile (tramp-compat-make-temp-file filename))
(modes (tramp-default-file-modes
filename (and (eq mustbenew 'excl) 'nofollow))))
filename (and (eq mustbenew 'excl) 'nofollow)))
(uid (tramp-compat-file-attribute-user-id
(file-attributes filename 'integer)))
(gid (tramp-compat-file-attribute-group-id
(file-attributes filename 'integer))))
(when (and append (file-exists-p filename))
(copy-file filename tmpfile 'ok))
;; The permissions of the temporary file should be set. If
@ -3919,15 +3925,18 @@ of."
(error
(delete-file tmpfile)
(tramp-error
v 'file-error "Couldn't write region to `%s'" filename))))
v 'file-error "Couldn't write region to `%s'" filename)))
(tramp-flush-file-properties v localname)
(tramp-flush-file-properties v localname)
;; Set file modification time.
(when (or (eq visit t) (stringp visit))
(set-visited-file-modtime
(tramp-compat-file-attribute-modification-time
(file-attributes filename))))
;; Set file modification time.
(when (or (eq visit t) (stringp visit))
(set-visited-file-modtime
(tramp-compat-file-attribute-modification-time
(file-attributes filename))))
;; Set the ownership.
(tramp-set-file-uid-gid filename uid gid))
;; The end.
(when (and (null noninteractive)

View File

@ -2925,6 +2925,9 @@ This tests also `file-directory-p' and `file-accessible-directory-p'."
;; (this is performed by `dired'). If FULL is nil, it shows just
;; one file. So we refrain from testing.
(skip-unless (not (tramp--test-ange-ftp-p)))
;; `insert-directory' of crypted remote directories works only since
;; Emacs 27.1.
(skip-unless (or (not (tramp--test-crypt-p)) (tramp--test-emacs27-p)))
(dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
(let* ((tmp-name1