Merge from emacs-23; up to 2010-06-10T05:17:21Z!rgm@gnu.org.
[bpt/emacs.git] / lisp / files.el
index 43b31cb..72cfc89 100644 (file)
@@ -635,22 +635,22 @@ the value of `default-directory'."
   "Value of the CDPATH environment variable, as a list.
 Not actually set up until the first time you use it.")
 
-(defun parse-colon-path (cd-path)
+(defun parse-colon-path (search-path)
   "Explode a search path into a list of directory names.
 Directories are separated by occurrences of `path-separator'
 \(which is colon in GNU and GNU-like systems)."
   ;; We could use split-string here.
-  (and cd-path
+  (and search-path
        (let (cd-list (cd-start 0) cd-colon)
-        (setq cd-path (concat cd-path path-separator))
-        (while (setq cd-colon (string-match path-separator cd-path cd-start))
+        (setq search-path (concat search-path path-separator))
+        (while (setq cd-colon (string-match path-separator search-path cd-start))
           (setq cd-list
                 (nconc cd-list
                        (list (if (= cd-start cd-colon)
                                   nil
                                (substitute-in-file-name
                                 (file-name-as-directory
-                                 (substring cd-path cd-start cd-colon)))))))
+                                 (substring search-path cd-start cd-colon)))))))
           (setq cd-start (+ cd-colon 1)))
         cd-list)))
 
@@ -681,26 +681,37 @@ that list of directories (separated by occurrences of
 `path-separator') when resolving a relative directory name.
 The path separator is colon in GNU and GNU-like systems."
   (interactive
-   (list (read-directory-name "Change default directory: "
-                        default-directory default-directory
-                        (and (member cd-path '(nil ("./")))
-                             (null (getenv "CDPATH"))))))
-  (if (file-name-absolute-p dir)
-      (cd-absolute (expand-file-name dir))
-    (if (null cd-path)
-       (let ((trypath (parse-colon-path (getenv "CDPATH"))))
-         (setq cd-path (or trypath (list "./")))))
-    (if (not (catch 'found
-              (mapc
-               (function (lambda (x)
-                           (let ((f (expand-file-name (concat x dir))))
-                             (if (file-directory-p f)
-                                 (progn
-                                   (cd-absolute f)
-                                   (throw 'found t))))))
-               cd-path)
-              nil))
-       (error "No such directory found via CDPATH environment variable"))))
+   (list
+    ;; FIXME: There's a subtle bug in the completion below.  Seems linked
+    ;; to a fundamental difficulty of implementing `predicate' correctly.
+    ;; The manifestation is that TAB may list non-directories in the case where
+    ;; those files also correspond to valid directories (if your cd-path is (A/
+    ;; B/) and you have A/a a file and B/a a directory, then both `a' and `a/'
+    ;; will be listed as valid completions).
+    ;; This is because `a' (listed because of A/a) is indeed a valid choice
+    ;; (which will lead to the use of B/a).
+    (minibuffer-with-setup-hook
+        (lambda ()
+          (setq minibuffer-completion-table
+                (apply-partially #'locate-file-completion-table
+                                 cd-path nil))
+          (setq minibuffer-completion-predicate
+                (lambda (dir)
+                  (locate-file dir cd-path nil
+                               (lambda (f) (and (file-directory-p f) 'dir-ok))))))
+      (unless cd-path
+        (setq cd-path (or (parse-colon-path (getenv "CDPATH"))
+                          (list "./"))))
+      (read-directory-name "Change default directory: "
+                           default-directory default-directory
+                           t))))
+  (unless cd-path
+    (setq cd-path (or (parse-colon-path (getenv "CDPATH"))
+                      (list "./"))))
+  (cd-absolute
+   (or (locate-file dir cd-path nil
+                    (lambda (f) (and (file-directory-p f) 'dir-ok)))
+       (error "No such directory found via CDPATH environment variable"))))
 
 (defun load-file (file)
   "Load the Lisp file named FILE."
@@ -720,9 +731,12 @@ If SUFFIXES is non-nil, it should be a list of suffixes to append to
 file name when searching.  If SUFFIXES is nil, it is equivalent to '(\"\").
 Use '(\"/\") to disable PATH search, but still try the suffixes in SUFFIXES.
 If non-nil, PREDICATE is used instead of `file-readable-p'.
+
+This function will normally skip directories, so if you want it to find
+directories, make sure the PREDICATE function returns `dir-ok' for them.
+
 PREDICATE can also be an integer to pass to the `access' system call,
 in which case file-name handlers are ignored.  This usage is deprecated.
-
 For compatibility, PREDICATE can also be one of the symbols
 `executable', `readable', `writable', or `exists', or a list of
 one or more of those symbols."
@@ -852,11 +866,10 @@ and return the directory.  Return nil if not found."
   ;; `name' in /home or in /.
   (setq file (abbreviate-file-name file))
   (let ((root nil)
-        (prev-file file)
         ;; `user' is not initialized outside the loop because
         ;; `file' may not exist, so we may have to walk up part of the
-        ;; hierarchy before we find the "initial UID".
-        (user nil)
+        ;; hierarchy before we find the "initial UID".  Note: currently unused
+        ;; (user nil)
         try)
     (while (not (or root
                     (null file)
@@ -873,8 +886,7 @@ and return the directory.  Return nil if not found."
                     (string-match locate-dominating-stop-dir-regexp file)))
       (setq try (file-exists-p (expand-file-name name file)))
       (cond (try (setq root file))
-            ((equal file (setq prev-file file
-                               file (file-name-directory
+            ((equal file (setq file (file-name-directory
                                      (directory-file-name file))))
              (setq file nil))))
     root))
@@ -944,10 +956,10 @@ reasonable to let-bind this variable to a value less then the
 time period between two checks.
 Example:
 
-  \(defun display-time-file-nonempty-p \(file)
-    \(let \(\(remote-file-name-inhibit-cache \(- display-time-interval 5)))
-      \(and \(file-exists-p file)
-           \(< 0 \(nth 7 \(file-attributes \(file-chase-links file)))))))"
+  (defun display-time-file-nonempty-p (file)
+    (let ((remote-file-name-inhibit-cache (- display-time-interval 5)))
+      (and (file-exists-p file)
+           (< 0 (nth 7 (file-attributes (file-chase-links file)))))))"
   :group 'files
   :version "24.1"
   :type `(choice
@@ -969,7 +981,8 @@ accessible."
       nil)))
 
 (defun file-truename (filename &optional counter prev-dirs)
-  "Return the truename of FILENAME, which should be absolute.
+  "Return the truename of FILENAME.
+If FILENAME is not absolute, first expands it against `default-directory'.
 The truename of a file name is found by chasing symbolic links
 both at the level of the file and at the level of the directories
 containing it, until no links are left at any level.
@@ -1125,6 +1138,37 @@ it means chase no more than that many links and then stop."
        (setq count (1+ count))))
     newname))
 
+;; A handy function to display file sizes in human-readable form.
+;; See http://en.wikipedia.org/wiki/Kibibyte for the reference.
+(defun file-size-human-readable (file-size &optional flavor)
+  "Produce a string showing FILE-SIZE in human-readable form.
+
+Optional second argument FLAVOR controls the units and the display format:
+
+ If FLAVOR is nil or omitted, each kilobyte is 1024 bytes and the produced
+    suffixes are \"k\", \"M\", \"G\", \"T\", etc.
+ If FLAVOR is `si', each kilobyte is 1000 bytes and the produced suffixes
+    are \"k\", \"M\", \"G\", \"T\", etc.
+ If FLAVOR is `iec', each kilobyte is 1024 bytes and the produced suffixes
+    are \"KiB\", \"MiB\", \"GiB\", \"TiB\", etc."
+  (let ((power (if (or (null flavor) (eq flavor 'iec))
+                  1024.0
+                1000.0))
+       (post-fixes
+        ;; none, kilo, mega, giga, tera, peta, exa, zetta, yotta
+        (list "" "k" "M" "G" "T" "P" "E" "Z" "Y")))
+    (while (and (>= file-size power) (cdr post-fixes))
+      (setq file-size (/ file-size power)
+           post-fixes (cdr post-fixes)))
+    (format (if (> (mod file-size 1.0) 0.05)
+               "%.1f%s%s"
+             "%.0f%s%s")
+           file-size
+           (if (and (eq flavor 'iec) (string= (car post-fixes) "k"))
+               "K"
+             (car post-fixes))
+           (if (eq flavor 'iec) "iB" ""))))
+
 (defun make-temp-file (prefix &optional dir-flag suffix)
   "Create a temporary file.
 The returned file name (created by appending some random characters at the end
@@ -1322,7 +1366,7 @@ its documentation for additional customization information."
   (interactive "BDisplay buffer in other frame: ")
   (let ((pop-up-frames t)
        same-window-buffer-names same-window-regexps
-        (old-window (selected-window))
+        ;;(old-window (selected-window))
        new-window)
     (setq new-window (display-buffer buffer t))
     ;; This may have been here in order to prevent the new frame from hiding
@@ -1529,6 +1573,8 @@ expand wildcards (if any) and replace the file with multiple files."
       (other-window 1)
       (find-alternate-file filename wildcards))))
 
+(defvar kill-buffer-hook)  ; from buffer.c
+
 (defun find-alternate-file (filename &optional wildcards)
   "Find file FILENAME, select its buffer, kill previous buffer.
 If the current buffer now contains an empty file that you just visited
@@ -1879,8 +1925,8 @@ the various files."
                           (not nonexistent)
                           ;; It is confusing to ask whether to visit
                           ;; non-literally if they have the file in
-                          ;; hexl-mode.
-                          (not (eq major-mode 'hexl-mode)))
+                          ;; hexl-mode or image-mode.
+                          (not (memq major-mode '(hexl-mode image-mode))))
                  (if (buffer-modified-p)
                      (if (y-or-n-p
                           (format
@@ -2027,7 +2073,7 @@ This function ensures that none of these modifications will take place."
         (inhibit-file-name-operation 'insert-file-contents))
     (unwind-protect
          (progn
-           (fset 'find-buffer-file-type (lambda (filename) t))
+           (fset 'find-buffer-file-type (lambda (_filename) t))
            (insert-file-contents filename visit beg end replace))
       (if find-buffer-file-type-function
          (fset 'find-buffer-file-type find-buffer-file-type-function)
@@ -2058,7 +2104,8 @@ Don't call it from programs!  Use `insert-file-contents-literally' instead.
 
 (defvar find-file-literally nil
   "Non-nil if this buffer was made by `find-file-literally' or equivalent.
-This is a permanent local.")
+This has the `permanent-local' property, which takes effect if you
+make the variable buffer-local.")
 (put 'find-file-literally 'permanent-local t)
 
 (defun find-file-literally (filename)
@@ -2084,10 +2131,8 @@ the file contents into it using `insert-file-contents-literally'."
          (confirm-nonexistent-file-or-buffer))))
   (switch-to-buffer (find-file-noselect filename nil t)))
 \f
-(defvar after-find-file-from-revert-buffer nil)
-
 (defun after-find-file (&optional error warn noauto
-                                 after-find-file-from-revert-buffer
+                                 _after-find-file-from-revert-buffer
                                  nomodes)
   "Called after finding a file and by the default revert function.
 Sets buffer mode, parses local variables.
@@ -2095,8 +2140,8 @@ Optional args ERROR, WARN, and NOAUTO: ERROR non-nil means there was an
 error in reading the file.  WARN non-nil means warn if there
 exists an auto-save file more recent than the visited file.
 NOAUTO means don't mess with auto-save mode.
-Fourth arg AFTER-FIND-FILE-FROM-REVERT-BUFFER non-nil
- means this call was from `revert-buffer'.
+Fourth arg AFTER-FIND-FILE-FROM-REVERT-BUFFER is ignored
+\(see `revert-buffer-in-progress-p' for similar functionality).
 Fifth arg NOMODES non-nil means don't alter the file's modes.
 Finishes by calling the functions in `find-file-hook'
 unless NOMODES is non-nil."
@@ -2137,7 +2182,7 @@ unless NOMODES is non-nil."
        (message "%s" msg)
        (or not-serious (sit-for 1 t))))
     (when (and auto-save-default (not noauto))
-      (auto-save-mode t)))
+      (auto-save-mode 1)))
   ;; Make people do a little extra work (C-x C-q)
   ;; before altering a backup file.
   (when (backup-file-name-p buffer-file-name)
@@ -2341,6 +2386,7 @@ ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\|7Z\\)\\'" . archive-mode)
      ("\\.dtd\\'" . sgml-mode)
      ("\\.ds\\(ss\\)?l\\'" . dsssl-mode)
      ("\\.js\\'" . js-mode)            ; javascript-mode would be better
+     ("\\.json\\'" . js-mode)
      ("\\.[ds]?vh?\\'" . verilog-mode)
      ;; .emacs or .gnus or .viper following a directory delimiter in
      ;; Unix, MSDOG or VMS syntax.
@@ -2646,7 +2692,7 @@ we don't actually set it to the same mode the buffer already has."
                                           (min (point-max)
                                                (+ (point-min) magic-mode-regexp-match-limit)))
                         (assoc-default nil magic-mode-alist
-                                       (lambda (re dummy)
+                                       (lambda (re _dummy)
                                          (if (functionp re)
                                              (funcall re)
                                            (looking-at re)))))))
@@ -2699,7 +2745,7 @@ we don't actually set it to the same mode the buffer already has."
                                           (min (point-max)
                                                (+ (point-min) magic-mode-regexp-match-limit)))
                         (assoc-default nil magic-fallback-mode-alist
-                                       (lambda (re dummy)
+                                       (lambda (re _dummy)
                                          (if (functionp re)
                                              (funcall re)
                                            (looking-at re)))))))
@@ -2791,7 +2837,9 @@ symbol and VAL is a value that is considered safe."
   :type 'alist)
 
 (defcustom safe-local-eval-forms
-  '((add-hook 'write-file-functions 'time-stamp)
+  ;; This should be here at least as long as Emacs supports write-file-hooks.
+  '((add-hook 'write-file-hooks 'time-stamp)
+    (add-hook 'write-file-functions 'time-stamp)
     (add-hook 'before-save-hook 'time-stamp))
   "Expressions that are considered safe in an `eval:' local variable.
 Add expressions to this list if you want Emacs to evaluate them, when
@@ -2799,7 +2847,7 @@ they appear in an `eval' local variable specification, without first
 asking you for confirmation."
   :risky t
   :group 'find-file
-  :version "22.2"
+  :version "24.1"                      ; added write-file-hooks
   :type '(repeat sexp))
 
 ;; Risky local variables:
@@ -2851,18 +2899,19 @@ asking you for confirmation."
 ;;
 ;; For variables defined in the C source code the declaration should go here:
 
-(mapc (lambda (pair)
-       (put (car pair) 'safe-local-variable (cdr pair)))
-      '((buffer-read-only        . booleanp)   ;; C source code
-       (default-directory       . stringp)    ;; C source code
-       (fill-column             . integerp)   ;; C source code
-       (indent-tabs-mode        . booleanp)   ;; C source code
-       (left-margin             . integerp)   ;; C source code
-       (no-update-autoloads     . booleanp)
-       (tab-width               . integerp)   ;; C source code
-       (truncate-lines          . booleanp)   ;; C source code
-       (word-wrap               . booleanp) ;; C source code
-       (bidi-display-reordering . booleanp))) ;; C source code
+(dolist (pair
+        '((buffer-read-only        . booleanp) ;; C source code
+          (default-directory       . stringp)  ;; C source code
+          (fill-column             . integerp) ;; C source code
+          (indent-tabs-mode        . booleanp) ;; C source code
+          (left-margin             . integerp) ;; C source code
+          (no-update-autoloads     . booleanp)
+          (lexical-binding      . booleanp)      ;; C source code
+          (tab-width               . integerp)   ;; C source code
+          (truncate-lines          . booleanp)   ;; C source code
+          (word-wrap               . booleanp)   ;; C source code
+          (bidi-display-reordering . booleanp))) ;; C source code
+  (put (car pair) 'safe-local-variable (cdr pair)))
 
 (put 'bidi-paragraph-direction 'safe-local-variable
      (lambda (v) (memq v '(nil right-to-left left-to-right))))
@@ -2902,8 +2951,8 @@ variable to set.")
 ALL-VARS is the list of all variables to be set up.
 UNSAFE-VARS is the list of those that aren't marked as safe or risky.
 RISKY-VARS is the list of those that are marked as risky.
-DIR-NAME is a directory name if these settings come from
-directory-local variables, or nil otherwise."
+If these settings come from directory-local variables, then
+DIR-NAME is the name of the associated directory.  Otherwise it is nil."
   (if noninteractive
       nil
     (save-window-excursion
@@ -3045,8 +3094,8 @@ VARIABLES is the alist of variable-value settings.  This alist is
  `enable-local-eval', `enable-local-variables', and (if necessary)
  user interaction.  The results are added to
  `file-local-variables-alist', without applying them.
-DIR-NAME is a directory name if these settings come from
- directory-local variables, or nil otherwise."
+If these settings come from directory-local variables, then
+DIR-NAME is the name of the associated directory.  Otherwise it is nil."
   ;; Find those variables that we may want to save to
   ;; `safe-local-variable-values'.
   (let (all-vars risky-vars unsafe-vars)
@@ -3221,7 +3270,7 @@ It is safe if any of these conditions are met:
              ;; can't assure us that the value is safe.
              (with-demoted-errors (funcall safep val))))))
 
-(defun risky-local-variable-p (sym &optional ignored)
+(defun risky-local-variable-p (sym &optional _ignored)
   "Non-nil if SYM could be dangerous as a file-local variable.
 It is dangerous if either of these conditions are met:
 
@@ -3330,11 +3379,11 @@ Each element in this list has the form (DIR CLASS MTIME).
 DIR is the name of the directory.
 CLASS is the name of a variable class (a symbol).
 MTIME is the recorded modification time of the directory-local
- variables file associated with this entry.  This time is a list
- of two integers (the same format as `file-attributes'), and is
- used to test whether the cache entry is still valid.
- Alternatively, MTIME can be nil, which means the entry is always
- considered valid.")
+variables file associated with this entry.  This time is a list
+of two integers (the same format as `file-attributes'), and is
+used to test whether the cache entry is still valid.
+Alternatively, MTIME can be nil, which means the entry is always
+considered valid.")
 
 (defsubst dir-locals-get-class-variables (class)
   "Return the variable list for CLASS."
@@ -3377,8 +3426,19 @@ Return the new variables list."
                                  (cdr entry) root variables))))
              ((or (not key)
                   (derived-mode-p key))
-              (setq variables (dir-locals-collect-mode-variables
-                               (cdr entry) variables))))))
+              (let* ((alist (cdr entry))
+                     (subdirs (assq 'subdirs alist)))
+                (if (or (not subdirs)
+                        (progn
+                          (setq alist (delq subdirs alist))
+                          (cdr-safe subdirs))
+                        ;; TODO someone might want to extend this to allow
+                        ;; integer values for subdir, where N means
+                        ;; variables apply to this directory and N levels
+                        ;; below it (0 == nil).
+                        (equal root default-directory))
+                    (setq variables (dir-locals-collect-mode-variables
+                                     alist variables))))))))
       (error
        ;; The file's content might be invalid (e.g. have a merge conflict), but
        ;; that shouldn't prevent the user from opening the file.
@@ -3443,13 +3503,20 @@ across different environments and users.")
 (defun dir-locals-find-file (file)
   "Find the directory-local variables for FILE.
 This searches upward in the directory tree from FILE.
-If the directory root of FILE has been registered in
- `dir-locals-directory-cache' and the directory-local variables
- file has not been modified, return the matching entry in
- `dir-locals-directory-cache'.
-Otherwise, if a directory-local variables file is found, return
- the file name.
-Otherwise, return nil."
+It stops at the first directory that has been registered in
+`dir-locals-directory-cache' or contains a `dir-locals-file'.
+If it finds an entry in the cache, it checks that it is valid.
+A cache entry with no modification time element (normally, one that
+has been assigned directly using `dir-locals-set-directory-class', not
+set from a file) is always valid.
+A cache entry based on a `dir-locals-file' is valid if the modification
+time stored in the cache matches the current file modification time.
+If not, the cache entry is cleared so that the file will be re-read.
+
+This function returns either nil (no directory local variables found),
+or the matching entry from `dir-locals-directory-cache' (a list),
+or the full path to the `dir-locals-file' (a string) in the case
+of no valid cache entry."
   (setq file (expand-file-name file))
   (let* ((dir-locals-file-name
          (if (eq system-type 'ms-dos)
@@ -3458,8 +3525,8 @@ Otherwise, return nil."
         (locals-file (locate-dominating-file file dir-locals-file-name))
         (dir-elt nil))
     ;; `locate-dominating-file' may have abbreviated the name.
-    (when locals-file
-      (setq locals-file (expand-file-name dir-locals-file-name locals-file)))
+    (if locals-file
+       (setq locals-file (expand-file-name dir-locals-file-name locals-file)))
     ;; Find the best cached value in `dir-locals-directory-cache'.
     (dolist (elt dir-locals-directory-cache)
       (when (and (eq t (compare-strings file nil (length (car elt))
@@ -3468,23 +3535,32 @@ Otherwise, return nil."
                                              '(windows-nt cygwin ms-dos))))
                 (> (length (car elt)) (length (car dir-elt))))
        (setq dir-elt elt)))
-    (let ((use-cache (and dir-elt
-                         (or (null locals-file)
-                             (<= (length (file-name-directory locals-file))
-                                 (length (car dir-elt)))))))
-      (if use-cache
-         ;; Check the validity of the cache.
-         (if (and (file-readable-p (car dir-elt))
-                  (or (null  (nth 2 dir-elt))
+    (if (and dir-elt
+            (or (null locals-file)
+                (<= (length (file-name-directory locals-file))
+                    (length (car dir-elt)))))
+       ;; Found a potential cache entry.  Check validity.
+       ;; A cache entry with no MTIME is assumed to always be valid
+       ;; (ie, set directly, not from a dir-locals file).
+       ;; Note, we don't bother to check that there is a matching class
+       ;; element in dir-locals-class-alist, since that's done by
+       ;; dir-locals-set-directory-class.
+       (if (or (null (nth 2 dir-elt))
+               (let ((cached-file (expand-file-name dir-locals-file-name
+                                                    (car dir-elt))))
+                 (and (file-readable-p cached-file)
                       (equal (nth 2 dir-elt)
-                             (nth 5 (file-attributes (car dir-elt))))))
-             ;; This cache entry is OK.
-             dir-elt
-           ;; This cache entry is invalid; clear it.
-           (setq dir-locals-directory-cache
-                 (delq dir-elt dir-locals-directory-cache))
-           locals-file)
-       locals-file))))
+                             (nth 5 (file-attributes cached-file))))))
+           ;; This cache entry is OK.
+           dir-elt
+         ;; This cache entry is invalid; clear it.
+         (setq dir-locals-directory-cache
+               (delq dir-elt dir-locals-directory-cache))
+         ;; Return the first existing dir-locals file.  Might be the same
+         ;; as dir-elt's, might not (eg latter might have been deleted).
+         locals-file)
+      ;; No cache entry.
+      locals-file)))
 
 (defun dir-locals-read-from-file (file)
   "Load a variables FILE and register a new class and instance.
@@ -3514,10 +3590,8 @@ and `file-local-variables-alist', without applying them."
          (dir-name nil))
       (cond
        ((stringp variables-file)
-       (setq dir-name (if (buffer-file-name)
-                           (file-name-directory (buffer-file-name))
-                         default-directory))
-       (setq class (dir-locals-read-from-file variables-file)))
+       (setq dir-name (file-name-directory variables-file)
+             class (dir-locals-read-from-file variables-file)))
        ((consp variables-file)
        (setq dir-name (nth 0 variables-file))
        (setq class (nth 1 variables-file))))
@@ -3826,7 +3900,9 @@ BACKUPNAME is the backup file name, which is the old file renamed."
        (set-file-selinux-context to-name context)))
 
 (defvar file-name-version-regexp
-  "\\(?:~\\|\\.~[-[:alnum:]:#@^._]+~\\)"
+  "\\(?:~\\|\\.~[-[:alnum:]:#@^._]+\\(?:~[[:digit:]]+\\)?~\\)"
+  ;; The last ~[[:digit]]+ matches relative versions in git,
+  ;; e.g. `foo.js.~HEAD~1~'.
   "Regular expression matching the backup/version part of a file name.
 Used by `file-name-sans-versions'.")
 
@@ -3850,11 +3926,17 @@ See also `file-name-version-regexp'."
   (let ((handler (find-file-name-handler file 'file-ownership-preserved-p)))
     (if handler
        (funcall handler 'file-ownership-preserved-p file)
-      (let ((attributes (file-attributes file)))
+      (let ((attributes (file-attributes file 'integer)))
        ;; Return t if the file doesn't exist, since it's true that no
        ;; information would be lost by an (attempted) delete and create.
        (or (null attributes)
-           (= (nth 2 attributes) (user-uid)))))))
+           (= (nth 2 attributes) (user-uid))
+           ;; Files created on Windows by Administrator (RID=500)
+           ;; have the Administrators group (RID=544) recorded as
+           ;; their owner.  Rewriting them will still preserve the
+           ;; owner.
+           (and (eq system-type 'windows-nt)
+                (= (user-uid) 500) (= (nth 2 attributes) 544)))))))
 
 (defun file-name-sans-extension (filename)
   "Return FILENAME sans final \"extension\".
@@ -4555,6 +4637,9 @@ You can answer `y' to save, `n' not to save, `C-r' to look at the
 buffer in question with `view-buffer' before deciding or `d' to
 view the differences using `diff-buffer-with-file'.
 
+This command first saves any buffers where `buffer-save-without-query' is
+non-nil, without asking.
+
 Optional argument (the prefix) non-nil means save all with no questions.
 Optional second argument PRED determines which buffers are considered:
 If PRED is nil, all the file-visiting buffers are considered.
@@ -4566,14 +4651,14 @@ See `save-some-buffers-action-alist' if you want to
 change the additional actions you can take on files."
   (interactive "P")
   (save-window-excursion
-    (let* (queried some-automatic
+    (let* (queried autosaved-buffers
           files-done abbrevs-done)
       (dolist (buffer (buffer-list))
        ;; First save any buffers that we're supposed to save unconditionally.
        ;; That way the following code won't ask about them.
        (with-current-buffer buffer
          (when (and buffer-save-without-query (buffer-modified-p))
-           (setq some-automatic t)
+           (push (buffer-name) autosaved-buffers)
            (save-buffer))))
       ;; Ask about those buffers that merit it,
       ;; and record the number thus saved.
@@ -4619,9 +4704,15 @@ change the additional actions you can take on files."
             (setq abbrevs-changed nil)
             (setq abbrevs-done t)))
       (or queried (> files-done 0) abbrevs-done
-         (message (if some-automatic
-                      "(Some special files were saved without asking)"
-                    "(No files need saving)"))))))
+         (cond
+          ((null autosaved-buffers)
+           (message "(No files need saving)"))
+          ((= (length autosaved-buffers) 1)
+           (message "(Saved %s)" (car autosaved-buffers)))
+          (t
+           (message "(Saved %d files: %s)"
+                    (length autosaved-buffers)
+                    (mapconcat 'identity autosaved-buffers ", "))))))))
 \f
 (defun not-modified (&optional arg)
   "Mark current buffer as unmodified, not needing to be saved.
@@ -4780,7 +4871,7 @@ given.  With a prefix argument, TRASH is nil."
    (let* ((trashing (and delete-by-moving-to-trash
                         (null current-prefix-arg)))
          (dir (expand-file-name
-               (read-file-name
+               (read-directory-name
                 (if trashing
                     "Move directory to trash: "
                   "Delete directory: ")
@@ -4826,10 +4917,8 @@ given.  With a prefix argument, TRASH is nil."
                 directory 'full directory-files-no-dot-files-regexp)))
       (delete-directory-internal directory)))))
 
-(defun copy-directory (directory newname &optional keep-time parents)
+(defun copy-directory (directory newname &optional keep-time parents copy-contents)
   "Copy DIRECTORY to NEWNAME.  Both args must be strings.
-If NEWNAME names an existing directory, copy DIRECTORY as subdirectory there.
-
 This function always sets the file modes of the output files to match
 the corresponding input file.
 
@@ -4840,15 +4929,20 @@ A prefix arg makes KEEP-TIME non-nil.
 
 Noninteractively, the last argument PARENTS says whether to
 create parent directories if they don't exist.  Interactively,
-this happens by default."
+this happens by default.
+
+If NEWNAME names an existing directory, copy DIRECTORY as a
+subdirectory there.  However, if called from Lisp with a non-nil
+optional argument COPY-CONTENTS, copy the contents of DIRECTORY
+directly into NEWNAME instead."
   (interactive
    (let ((dir (read-directory-name
               "Copy directory: " default-directory default-directory t nil)))
      (list dir
-          (read-file-name
+          (read-directory-name
            (format "Copy directory %s to: " dir)
            default-directory default-directory nil nil)
-          current-prefix-arg t)))
+          current-prefix-arg t nil)))
   ;; If default-directory is a remote directory, make sure we find its
   ;; copy-directory handler.
   (let ((handler (or (find-file-name-handler directory 'copy-directory)
@@ -4860,21 +4954,22 @@ this happens by default."
       (setq directory (directory-file-name (expand-file-name directory))
            newname   (directory-file-name (expand-file-name newname)))
 
-      (if (not (file-directory-p newname))
-         ;; If NEWNAME is not an existing directory, create it; that
-         ;; is where we will copy the files of DIRECTORY.
-         (make-directory newname parents)
-       ;; If NEWNAME is an existing directory, we will copy into
-       ;; NEWNAME/[DIRECTORY-BASENAME].
-       (setq newname (expand-file-name
-                      (file-name-nondirectory
-                       (directory-file-name directory))
-                      newname))
-       (and (file-exists-p newname)
-            (not (file-directory-p newname))
-            (error "Cannot overwrite non-directory %s with a directory"
-                   newname))
-       (make-directory newname t))
+      (cond ((not (file-directory-p newname))
+            ;; If NEWNAME is not an existing directory, create it;
+            ;; that is where we will copy the files of DIRECTORY.
+            (make-directory newname parents))
+           ;; If NEWNAME is an existing directory and COPY-CONTENTS
+           ;; is nil, copy into NEWNAME/[DIRECTORY-BASENAME].
+           ((not copy-contents)
+            (setq newname (expand-file-name
+                           (file-name-nondirectory
+                            (directory-file-name directory))
+                           newname))
+            (and (file-exists-p newname)
+                 (not (file-directory-p newname))
+                 (error "Cannot overwrite non-directory %s with a directory"
+                        newname))
+            (make-directory newname t)))
 
       ;; Copy recursively.
       (dolist (file
@@ -4939,6 +5034,10 @@ hook functions.
 If `revert-buffer-function' is used to override the normal revert
 mechanism, this hook is not used.")
 
+(defvar revert-buffer-in-progress-p nil
+  "Non-nil if a `revert-buffer' operation is in progress, nil otherwise.
+This is true even if a `revert-buffer-function' is being used.")
+
 (defvar revert-buffer-internal-hook)
 
 (defun revert-buffer (&optional ignore-auto noconfirm preserve-modes)
@@ -4961,7 +5060,7 @@ sake of backward compatibility.  IGNORE-AUTO is optional, defaulting
 to nil.
 
 Optional second argument NOCONFIRM means don't ask for confirmation
-at all.  \(The variable `revert-without-query' offers another way to
+at all.  (The variable `revert-without-query' offers another way to
 revert buffers without querying for confirmation.)
 
 Optional third argument PRESERVE-MODES non-nil means don't alter
@@ -4981,10 +5080,12 @@ non-nil, it is called instead of rereading visited file contents."
   ;; interface, but leaving the programmatic interface the same.
   (interactive (list (not current-prefix-arg)))
   (if revert-buffer-function
-      (funcall revert-buffer-function ignore-auto noconfirm)
+      (let ((revert-buffer-in-progress-p t))
+        (funcall revert-buffer-function ignore-auto noconfirm))
     (with-current-buffer (or (buffer-base-buffer (current-buffer))
                             (current-buffer))
-      (let* ((auto-save-p (and (not ignore-auto)
+      (let* ((revert-buffer-in-progress-p t)
+             (auto-save-p (and (not ignore-auto)
                               (recent-auto-save-p)
                               buffer-auto-save-file-name
                               (file-readable-p buffer-auto-save-file-name)
@@ -5075,7 +5176,7 @@ non-nil, it is called instead of rereading visited file contents."
                 ;; have changed the truename.
                 (setq buffer-file-truename
                       (abbreviate-file-name (file-truename buffer-file-name)))
-                (after-find-file nil nil t t preserve-modes)
+                (after-find-file nil nil t nil preserve-modes)
                 ;; Run after-revert-hook as it was before we reverted.
                 (setq-default revert-buffer-internal-hook global-hook)
                 (if local-hook
@@ -5543,7 +5644,7 @@ Prefix arg (second arg if noninteractive) means supply -l switch to `ls'.
 Actions controlled by variables `list-directory-brief-switches'
 and `list-directory-verbose-switches'."
   (interactive (let ((pfx current-prefix-arg))
-                (list (read-file-name (if pfx "List directory (verbose): "
+                (list (read-directory-name (if pfx "List directory (verbose): "
                                         "List directory (brief): ")
                                       nil default-directory nil)
                       pfx)))
@@ -5802,6 +5903,9 @@ normally equivalent short `-D' option is just passed on to
                                  (file-name-directory file)
                                (file-name-directory (expand-file-name file))))
                            (pattern (file-name-nondirectory file)))
+                       ;; NB since switches is passed to the shell, be
+                       ;; careful of malicious values, eg "-l;reboot".
+                       ;; See eg dired-safe-switches-p.
                        (call-process
                         shell-file-name nil t nil
                         "-c"
@@ -6074,8 +6178,8 @@ With prefix ARG, silently save all file-visiting buffers, then kill."
                    (setq active t))
               (setq processes (cdr processes)))
             (or (not active)
-                (list-processes t)
-                (yes-or-no-p "Active processes exist; kill them and exit anyway? "))))
+                (progn (list-processes t)
+                       (yes-or-no-p "Active processes exist; kill them and exit anyway? ")))))
        ;; Query the user for other things, perhaps.
        (run-hook-with-args-until-failure 'kill-emacs-query-functions)
        (or (null confirm-kill-emacs)