diff options
| author | Paul Eggert | 2017-08-26 18:36:38 -0700 |
|---|---|---|
| committer | Paul Eggert | 2017-08-26 18:36:38 -0700 |
| commit | e8001d4c27e1e33c83b9994aac4d5fc3feada2da (patch) | |
| tree | 6910256d7cf7723aa1b3f7ab7779b91627ba52f6 /lisp | |
| parent | 937d9d7f60460edb1d3f978151599fddcbba2214 (diff) | |
| download | emacs-e8001d4c27e1e33c83b9994aac4d5fc3feada2da.tar.gz emacs-e8001d4c27e1e33c83b9994aac4d5fc3feada2da.zip | |
Do not munge contents of local symbolic links
This lets Emacs deal with arbitrary local symlinks without
mishandling their contents (Bug#28156). For example,
(progn (shell-command "ln -fs '~' 'x'") (rename-file "x" "/tmp/x"))
now consistently creates a symbolic link from '/tmp/x' to '~'.
Formerly, it did that only if the working directory was on the
same filesystem as /tmp; otherwise, it expanded the '~' to
the user's home directory.
* lisp/dired.el (dired-get-filename): Use files--name-absolute-system-p
instead of rolling our own code.
* lisp/files.el (files--name-absolute-system-p): New function.
(file-truename, file-chase-links): Use it to avoid mishandling
symlink contents that begin with ~.
(copy-directory, move-file-to-trash):
Use concat rather than expand-file-name, to avoid mishandling
symlink contents that begin with ~.
* src/fileio.c (Fmake_symbolic_link): Do not expand leading "~" in the
target unless interactive. Strip leading "/:" if interactive.
(emacs_readlinkat): Do not prepend "/:" to the link target if
it starts with "/" and contains ":" before NUL.
* test/src/fileio-tests.el (try-link): Rename from try-char,
and accept a string instead of a char. All uses changed.
(fileio-tests--symlink-failure): Also test leading ~, and "/:",
to test the new behavior.
Diffstat (limited to 'lisp')
| -rw-r--r-- | lisp/dired.el | 5 | ||||
| -rw-r--r-- | lisp/files.el | 31 |
2 files changed, 22 insertions, 14 deletions
diff --git a/lisp/dired.el b/lisp/dired.el index 0455f3d1378..ff62183f091 100644 --- a/lisp/dired.el +++ b/lisp/dired.el | |||
| @@ -2332,10 +2332,7 @@ Otherwise, an error occurs in these cases." | |||
| 2332 | (if (and enable-multibyte-characters | 2332 | (if (and enable-multibyte-characters |
| 2333 | (not (multibyte-string-p file))) | 2333 | (not (multibyte-string-p file))) |
| 2334 | (setq file (string-to-multibyte file))))) | 2334 | (setq file (string-to-multibyte file))))) |
| 2335 | (and file (file-name-absolute-p file) | 2335 | (and file (files--name-absolute-system-p file) |
| 2336 | ;; A relative file name can start with ~. | ||
| 2337 | ;; Don't treat it as absolute in this context. | ||
| 2338 | (not (eq (aref file 0) ?~)) | ||
| 2339 | (setq already-absolute t)) | 2336 | (setq already-absolute t)) |
| 2340 | (cond | 2337 | (cond |
| 2341 | ((null file) | 2338 | ((null file) |
diff --git a/lisp/files.el b/lisp/files.el index ca3b055d7a6..872fc46e87a 100644 --- a/lisp/files.el +++ b/lisp/files.el | |||
| @@ -1146,6 +1146,13 @@ accessible." | |||
| 1146 | (funcall handler 'file-local-copy file) | 1146 | (funcall handler 'file-local-copy file) |
| 1147 | nil))) | 1147 | nil))) |
| 1148 | 1148 | ||
| 1149 | (defun files--name-absolute-system-p (file) | ||
| 1150 | "Return non-nil if FILE is an absolute name to the operating system. | ||
| 1151 | This is like `file-name-absolute-p', except that it returns nil for | ||
| 1152 | names beginning with `~'." | ||
| 1153 | (and (file-name-absolute-p file) | ||
| 1154 | (not (eq (aref file 0) ?~)))) | ||
| 1155 | |||
| 1149 | (defun file-truename (filename &optional counter prev-dirs) | 1156 | (defun file-truename (filename &optional counter prev-dirs) |
| 1150 | "Return the truename of FILENAME. | 1157 | "Return the truename of FILENAME. |
| 1151 | If FILENAME is not absolute, first expands it against `default-directory'. | 1158 | If FILENAME is not absolute, first expands it against `default-directory'. |
| @@ -1247,9 +1254,9 @@ containing it, until no links are left at any level. | |||
| 1247 | ;; since target might look like foo/../bar where foo | 1254 | ;; since target might look like foo/../bar where foo |
| 1248 | ;; is itself a link. Instead, we handle . and .. above. | 1255 | ;; is itself a link. Instead, we handle . and .. above. |
| 1249 | (setq filename | 1256 | (setq filename |
| 1250 | (if (file-name-absolute-p target) | 1257 | (concat (if (files--name-absolute-system-p target) |
| 1251 | target | 1258 | "/:" dir) |
| 1252 | (concat dir target)) | 1259 | target) |
| 1253 | done nil) | 1260 | done nil) |
| 1254 | ;; No, we are done! | 1261 | ;; No, we are done! |
| 1255 | (setq done t)))))))) | 1262 | (setq done t)))))))) |
| @@ -1284,7 +1291,10 @@ it means chase no more than that many links and then stop." | |||
| 1284 | (directory-file-name (file-name-directory newname)))) | 1291 | (directory-file-name (file-name-directory newname)))) |
| 1285 | ;; Now find the parent of that dir. | 1292 | ;; Now find the parent of that dir. |
| 1286 | (setq newname (file-name-directory newname))) | 1293 | (setq newname (file-name-directory newname))) |
| 1287 | (setq newname (expand-file-name tem (file-name-directory newname))) | 1294 | (setq newname (concat (if (files--name-absolute-system-p tem) |
| 1295 | "/:" | ||
| 1296 | (file-name-directory newname)) | ||
| 1297 | tem)) | ||
| 1288 | (setq count (1+ count)))) | 1298 | (setq count (1+ count)))) |
| 1289 | newname)) | 1299 | newname)) |
| 1290 | 1300 | ||
| @@ -5504,10 +5514,10 @@ directly into NEWNAME instead." | |||
| 5504 | ;; If NEWNAME is an existing directory and COPY-CONTENTS | 5514 | ;; If NEWNAME is an existing directory and COPY-CONTENTS |
| 5505 | ;; is nil, copy into NEWNAME/[DIRECTORY-BASENAME]. | 5515 | ;; is nil, copy into NEWNAME/[DIRECTORY-BASENAME]. |
| 5506 | ((not copy-contents) | 5516 | ((not copy-contents) |
| 5507 | (setq newname (expand-file-name | 5517 | (setq newname (concat |
| 5518 | (file-name-as-directory newname) | ||
| 5508 | (file-name-nondirectory | 5519 | (file-name-nondirectory |
| 5509 | (directory-file-name directory)) | 5520 | (directory-file-name directory)))) |
| 5510 | newname)) | ||
| 5511 | (and (file-exists-p newname) | 5521 | (and (file-exists-p newname) |
| 5512 | (not (file-directory-p newname)) | 5522 | (not (file-directory-p newname)) |
| 5513 | (error "Cannot overwrite non-directory %s with a directory" | 5523 | (error "Cannot overwrite non-directory %s with a directory" |
| @@ -5519,7 +5529,8 @@ directly into NEWNAME instead." | |||
| 5519 | ;; We do not want to copy "." and "..". | 5529 | ;; We do not want to copy "." and "..". |
| 5520 | (directory-files directory 'full | 5530 | (directory-files directory 'full |
| 5521 | directory-files-no-dot-files-regexp)) | 5531 | directory-files-no-dot-files-regexp)) |
| 5522 | (let ((target (expand-file-name (file-name-nondirectory file) newname)) | 5532 | (let ((target (concat (file-name-as-directory newname) |
| 5533 | (file-name-nondirectory file))) | ||
| 5523 | (filetype (car (file-attributes file)))) | 5534 | (filetype (car (file-attributes file)))) |
| 5524 | (cond | 5535 | (cond |
| 5525 | ((eq filetype t) ; Directory but not a symlink. | 5536 | ((eq filetype t) ; Directory but not a symlink. |
| @@ -7149,8 +7160,8 @@ Otherwise, trash FILENAME using the freedesktop.org conventions, | |||
| 7149 | ;; If `trash-directory' is non-nil, move the file there. | 7160 | ;; If `trash-directory' is non-nil, move the file there. |
| 7150 | (let* ((trash-dir (expand-file-name trash-directory)) | 7161 | (let* ((trash-dir (expand-file-name trash-directory)) |
| 7151 | (fn (directory-file-name (expand-file-name filename))) | 7162 | (fn (directory-file-name (expand-file-name filename))) |
| 7152 | (new-fn (expand-file-name (file-name-nondirectory fn) | 7163 | (new-fn (concat (file-name-as-directory trash-dir) |
| 7153 | trash-dir))) | 7164 | (file-name-nondirectory fn)))) |
| 7154 | ;; We can't trash a parent directory of trash-directory. | 7165 | ;; We can't trash a parent directory of trash-directory. |
| 7155 | (if (string-prefix-p fn trash-dir) | 7166 | (if (string-prefix-p fn trash-dir) |
| 7156 | (error "Trash directory `%s' is a subdirectory of `%s'" | 7167 | (error "Trash directory `%s' is a subdirectory of `%s'" |