diff options
| author | Philipp Stephani | 2020-12-13 17:13:50 +0100 |
|---|---|---|
| committer | Philipp Stephani | 2020-12-13 17:17:21 +0100 |
| commit | fe50a8b9ba79b4ac14a3a352d8bf84eaee4f2122 (patch) | |
| tree | 0b0b990f0f49f2ad652c2506caa7e5b15add75a3 | |
| parent | 897b8561cdc856fb40b2a3c6f29230849aaf4a34 (diff) | |
| download | emacs-fe50a8b9ba79b4ac14a3a352d8bf84eaee4f2122.tar.gz emacs-fe50a8b9ba79b4ac14a3a352d8bf84eaee4f2122.zip | |
Byte compilation: handle case where the output file is a mountpoint.
See Bug#44631. While testing for a readonly output directory has
slightly different semantics, in practice they should cover cases
where Emacs is sandboxed and can only write to the destination file,
not its directory.
* lisp/emacs-lisp/bytecomp.el (byte-compile-file): Handle the case
where the output directory is not writable.
* test/lisp/emacs-lisp/bytecomp-tests.el
(bytecomp-tests--not-writable-directory)
(bytecomp-tests--dest-mountpoint): New unit tests.
| -rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 14 | ||||
| -rw-r--r-- | test/lisp/emacs-lisp/bytecomp-tests.el | 69 |
2 files changed, 82 insertions, 1 deletions
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 51accc08654..e23bb9f5e6e 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el | |||
| @@ -1963,7 +1963,11 @@ See also `emacs-lisp-byte-compile-and-load'." | |||
| 1963 | (insert "\n") ; aaah, unix. | 1963 | (insert "\n") ; aaah, unix. |
| 1964 | (cond | 1964 | (cond |
| 1965 | ((null target-file) nil) ;We only wanted the warnings! | 1965 | ((null target-file) nil) ;We only wanted the warnings! |
| 1966 | ((file-writable-p target-file) | 1966 | ((and (file-writable-p target-file) |
| 1967 | ;; We attempt to create a temporary file in the | ||
| 1968 | ;; target directory, so the target directory must be | ||
| 1969 | ;; writable. | ||
| 1970 | (file-writable-p (file-name-directory target-file))) | ||
| 1967 | ;; We must disable any code conversion here. | 1971 | ;; We must disable any code conversion here. |
| 1968 | (let* ((coding-system-for-write 'no-conversion) | 1972 | (let* ((coding-system-for-write 'no-conversion) |
| 1969 | ;; Write to a tempfile so that if another Emacs | 1973 | ;; Write to a tempfile so that if another Emacs |
| @@ -1992,6 +1996,14 @@ See also `emacs-lisp-byte-compile-and-load'." | |||
| 1992 | ;; deleting target-file before writing it. | 1996 | ;; deleting target-file before writing it. |
| 1993 | (rename-file tempfile target-file t)) | 1997 | (rename-file tempfile target-file t)) |
| 1994 | (or noninteractive (message "Wrote %s" target-file))) | 1998 | (or noninteractive (message "Wrote %s" target-file))) |
| 1999 | ((file-writable-p target-file) | ||
| 2000 | ;; In case the target directory isn't writable (see e.g. Bug#44631), | ||
| 2001 | ;; try writing to the output file directly. We must disable any | ||
| 2002 | ;; code conversion here. | ||
| 2003 | (let ((coding-system-for-write 'no-conversion)) | ||
| 2004 | (with-file-modes (logand (default-file-modes) #o666) | ||
| 2005 | (write-region (point-min) (point-max) target-file nil 1))) | ||
| 2006 | (or noninteractive (message "Wrote %s" target-file))) | ||
| 1995 | (t | 2007 | (t |
| 1996 | ;; This is just to give a better error message than write-region | 2008 | ;; This is just to give a better error message than write-region |
| 1997 | (let ((exists (file-exists-p target-file))) | 2009 | (let ((exists (file-exists-p target-file))) |
diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el b/test/lisp/emacs-lisp/bytecomp-tests.el index 8fa4d278f11..c2a3e3ba117 100644 --- a/test/lisp/emacs-lisp/bytecomp-tests.el +++ b/test/lisp/emacs-lisp/bytecomp-tests.el | |||
| @@ -947,6 +947,75 @@ literals (Bug#20852)." | |||
| 947 | '((suspicious set-buffer)) | 947 | '((suspicious set-buffer)) |
| 948 | "Warning: Use .with-current-buffer. rather than")) | 948 | "Warning: Use .with-current-buffer. rather than")) |
| 949 | 949 | ||
| 950 | (ert-deftest bytecomp-tests--not-writable-directory () | ||
| 951 | "Test that byte compilation works if the output directory isn't | ||
| 952 | writable (Bug#44631)." | ||
| 953 | (let ((directory (make-temp-file "bytecomp-tests-" :directory))) | ||
| 954 | (unwind-protect | ||
| 955 | (let* ((input-file (expand-file-name "test.el" directory)) | ||
| 956 | (output-file (expand-file-name "test.elc" directory)) | ||
| 957 | (byte-compile-dest-file-function | ||
| 958 | (lambda (_) output-file)) | ||
| 959 | (byte-compile-error-on-warn t)) | ||
| 960 | (write-region "" nil input-file nil nil nil 'excl) | ||
| 961 | (write-region "" nil output-file nil nil nil 'excl) | ||
| 962 | (set-file-modes input-file #o400) | ||
| 963 | (set-file-modes output-file #o200) | ||
| 964 | (set-file-modes directory #o500) | ||
| 965 | (should (byte-compile-file input-file)) | ||
| 966 | (should (file-regular-p output-file)) | ||
| 967 | (should (cl-plusp (file-attribute-size | ||
| 968 | (file-attributes output-file))))) | ||
| 969 | (with-demoted-errors "Error cleaning up directory: %s" | ||
| 970 | (set-file-modes directory #o700) | ||
| 971 | (delete-directory directory :recursive))))) | ||
| 972 | |||
| 973 | (ert-deftest bytecomp-tests--dest-mountpoint () | ||
| 974 | "Test that byte compilation works if the destination file is a | ||
| 975 | mountpoint (Bug#44631)." | ||
| 976 | (let ((bwrap (executable-find "bwrap")) | ||
| 977 | (emacs (expand-file-name invocation-name invocation-directory))) | ||
| 978 | (skip-unless bwrap) | ||
| 979 | (skip-unless (file-executable-p bwrap)) | ||
| 980 | (skip-unless (not (file-remote-p bwrap))) | ||
| 981 | (skip-unless (file-executable-p emacs)) | ||
| 982 | (skip-unless (not (file-remote-p emacs))) | ||
| 983 | (let ((directory (make-temp-file "bytecomp-tests-" :directory))) | ||
| 984 | (unwind-protect | ||
| 985 | (let* ((input-file (expand-file-name "test.el" directory)) | ||
| 986 | (output-file (expand-file-name "test.elc" directory)) | ||
| 987 | (unquoted-file (file-name-unquote output-file)) | ||
| 988 | (byte-compile-dest-file-function | ||
| 989 | (lambda (_) output-file)) | ||
| 990 | (byte-compile-error-on-warn t)) | ||
| 991 | (should-not (file-remote-p input-file)) | ||
| 992 | (should-not (file-remote-p output-file)) | ||
| 993 | (write-region "" nil input-file nil nil nil 'excl) | ||
| 994 | (write-region "" nil output-file nil nil nil 'excl) | ||
| 995 | (set-file-modes input-file #o400) | ||
| 996 | (set-file-modes output-file #o200) | ||
| 997 | (set-file-modes directory #o500) | ||
| 998 | (with-temp-buffer | ||
| 999 | (let ((status (call-process | ||
| 1000 | bwrap nil t nil | ||
| 1001 | "--ro-bind" "/" "/" | ||
| 1002 | "--bind" unquoted-file unquoted-file | ||
| 1003 | emacs "--quick" "--batch" "--load=bytecomp" | ||
| 1004 | (format "--eval=%S" | ||
| 1005 | `(setq byte-compile-dest-file-function | ||
| 1006 | (lambda (_) ,output-file) | ||
| 1007 | byte-compile-error-on-warn t)) | ||
| 1008 | "--funcall=batch-byte-compile" input-file))) | ||
| 1009 | (unless (eql status 0) | ||
| 1010 | (ert-fail `((status . ,status) | ||
| 1011 | (output . ,(buffer-string))))))) | ||
| 1012 | (should (file-regular-p output-file)) | ||
| 1013 | (should (cl-plusp (file-attribute-size | ||
| 1014 | (file-attributes output-file))))) | ||
| 1015 | (with-demoted-errors "Error cleaning up directory: %s" | ||
| 1016 | (set-file-modes directory #o700) | ||
| 1017 | (delete-directory directory :recursive)))))) | ||
| 1018 | |||
| 950 | ;; Local Variables: | 1019 | ;; Local Variables: |
| 951 | ;; no-byte-compile: t | 1020 | ;; no-byte-compile: t |
| 952 | ;; End: | 1021 | ;; End: |