* puresize.h (BASE_PURESIZE): Increase to 1470000.
[bpt/emacs.git] / lisp / files.el
index 1528b38..11249a4 100644 (file)
@@ -29,6 +29,8 @@
 
 ;;; Code:
 
+(eval-when-compile (require 'cl))
+
 (defvar font-lock-keywords)
 
 (defgroup backup nil
@@ -193,6 +195,7 @@ If the buffer is visiting a new file, the value is nil.")
          (or (getenv "TMPDIR") (getenv "TMP") (getenv "TEMP") "/tmp"))))
   "The directory for writing temporary files."
   :group 'files
+  :initialize 'custom-initialize-delay
   :type 'directory)
 
 (defcustom small-temporary-file-directory
@@ -202,10 +205,11 @@ If non-nil, this directory is used instead of `temporary-file-directory'
 by programs that create small temporary files.  This is for systems that
 have fast storage with limited space, such as a RAM disk."
   :group 'files
+  :initialize 'custom-initialize-delay
   :type '(choice (const nil) directory))
 
 ;; The system null device. (Should reference NULL_DEVICE from C.)
-(defvar null-device "/dev/null" "The system null device.")
+(defvar null-device (purecopy "/dev/null") "The system null device.")
 
 (declare-function msdos-long-file-names "msdos.c")
 (declare-function w32-long-file-name "w32proc.c")
@@ -218,15 +222,17 @@ have fast storage with limited space, such as a RAM disk."
 
 (defvar file-name-invalid-regexp
   (cond ((and (eq system-type 'ms-dos) (not (msdos-long-file-names)))
+        (purecopy
         (concat "^\\([^A-Z[-`a-z]\\|..+\\)?:\\|" ; colon except after drive
                 "[+, ;=|<>\"?*]\\|\\[\\|\\]\\|"  ; invalid characters
                 "[\000-\037]\\|"                 ; control characters
                 "\\(/\\.\\.?[^/]\\)\\|"          ; leading dots
-                "\\(/[^/.]+\\.[^/.]*\\.\\)"))    ; more than a single dot
+                "\\(/[^/.]+\\.[^/.]*\\.\\)")))   ; more than a single dot
        ((memq system-type '(ms-dos windows-nt cygwin))
+        (purecopy
         (concat "^\\([^A-Z[-`a-z]\\|..+\\)?:\\|" ; colon except after drive
-                "[|<>\"?*\000-\037]"))           ; invalid characters
-       (t "[\000]"))
+                "[|<>\"?*\000-\037]")))                  ; invalid characters
+       (t (purecopy "[\000]")))
   "Regexp recognizing file names which aren't allowed by the filesystem.")
 
 (defcustom file-precious-flag nil
@@ -383,6 +389,7 @@ ignored."
   :group 'auto-save
   :type '(repeat (list (string :tag "Regexp") (string :tag "Replacement")
                                           (boolean :tag "Uniquify")))
+  :initialize 'custom-initialize-delay
   :version "21.1")
 
 (defcustom save-abbrevs t
@@ -493,6 +500,7 @@ a -*- line.
 The command \\[normal-mode], when used interactively,
 always obeys file local variable specifications and the -*- line,
 and ignores this variable."
+  :risky t
   :type '(choice (const :tag "Query Unsafe" t)
                 (const :tag "Safe Only" :safe)
                 (const :tag "Do all" :all)
@@ -514,6 +522,7 @@ specified in a -*- line.")
 The value can be t, nil or something else.
 A value of t means obey `eval' variables.
 A value of nil means ignore them; anything else means query."
+  :risky t
   :type '(choice (const :tag "Obey" t)
                 (const :tag "Ignore" nil)
                 (other :tag "Query" other))
@@ -641,7 +650,12 @@ Directories are separated by occurrences of `path-separator'
   ;; Put the name into directory syntax now,
   ;; because otherwise expand-file-name may give some bad results.
   (setq dir (file-name-as-directory dir))
-  (setq dir (abbreviate-file-name (expand-file-name dir)))
+  ;; We used to additionally call abbreviate-file-name here, for an
+  ;; unknown reason.  Problem is that most buffers are setup
+  ;; without going through cd-absolute and don't call
+  ;; abbreviate-file-name on their default-directory, so the few that
+  ;; do end up using a superficially different directory.
+  (setq dir (expand-file-name dir))
   (if (not (file-directory-p dir))
       (if (file-exists-p dir)
          (error "%s is not a directory" dir)
@@ -649,7 +663,7 @@ Directories are separated by occurrences of `path-separator'
     (unless (file-executable-p dir)
       (error "Cannot cd to %s:  Permission denied" dir))
     (setq default-directory dir)
-    (set (make-local-variable 'list-buffers-directory) dir)))
+    (setq list-buffers-directory dir)))
 
 (defun cd (dir)
   "Make DIR become the current buffer's default directory.
@@ -714,24 +728,36 @@ one or more of those symbols."
 
 (defun locate-file-completion-table (dirs suffixes string pred action)
   "Do completion for file names passed to `locate-file'."
-  (if (file-name-absolute-p string)
-      (let ((read-file-name-predicate pred))
-        (read-file-name-internal string nil action))
+  (cond
+   ((file-name-absolute-p string)
+    ;; FIXME: maybe we should use completion-file-name-table instead,
+    ;; tho at least for `load', the arg is passed through
+    ;; substitute-in-file-name for historical reasons.
+    (read-file-name-internal string pred action))
+   ((eq (car-safe action) 'boundaries)
+    (let ((suffix (cdr action)))
+      (list* 'boundaries
+             (length (file-name-directory string))
+             (let ((x (file-name-directory suffix)))
+               (if x (1- (length x)) (length suffix))))))
+   (t
     (let ((names nil)
          (suffix (concat (regexp-opt suffixes t) "\\'"))
-         (string-dir (file-name-directory string)))
+         (string-dir (file-name-directory string))
+          (string-file (file-name-nondirectory string)))
       (dolist (dir dirs)
        (unless dir
          (setq dir default-directory))
        (if string-dir (setq dir (expand-file-name string-dir dir)))
        (when (file-directory-p dir)
          (dolist (file (file-name-all-completions
-                        (file-name-nondirectory string) dir))
-           (add-to-list 'names (if string-dir (concat string-dir file) file))
+                        string-file dir))
+           (push file names)
            (when (string-match suffix file)
              (setq file (substring file 0 (match-beginning 0)))
-             (push (if string-dir (concat string-dir file) file) names)))))
-      (complete-with-action action names string pred))))
+              (push file names)))))
+      (completion-table-with-context
+       string-dir names string-file pred action)))))
 
 (defun locate-file-completion (string path-and-suffixes action)
   "Do completion for file names passed to `locate-file'.
@@ -742,7 +768,7 @@ PATH-AND-SUFFIXES is a pair of lists, (DIRECTORIES . SUFFIXES)."
 (make-obsolete 'locate-file-completion 'locate-file-completion-table "23.1")
 
 (defvar locate-dominating-stop-dir-regexp
-  "\\`\\(?:[\\/][\\/][^\\/]+[\\/]\\|/\\(?:net\\|afs\\|\\.\\.\\.\\)/\\)\\'"
+  (purecopy "\\`\\(?:[\\/][\\/][^\\/]+[\\/]\\|/\\(?:net\\|afs\\|\\.\\.\\.\\)/\\)\\'")
   "Regexp of directory names which stop the search in `locate-dominating-file'.
 Any directory whose name matches this regexp will be treated like
 a kind of root directory by `locate-dominating-file' which will stop its search
@@ -830,10 +856,12 @@ Return nil if COMMAND is not found anywhere in `exec-path'."
 
 (defun load-library (library)
   "Load the Emacs Lisp library named LIBRARY.
-This is one of two interfaces (the other being `load-file') to the underlying
-function `load'.  The library actually loaded is searched for in `load-path'
-with or without the `load-suffixes' (as well as `load-file-rep-suffixes').
-See Info node `(emacs)Lisp Libraries' for more details."
+This is an interface to the function `load'.  LIBRARY is searched
+for in `load-path', both with and without `load-suffixes' (as
+well as `load-file-rep-suffixes').
+
+See Info node `(emacs)Lisp Libraries' for more details.
+See `load-file' for a different interface to `load'."
   (interactive
    (list (completing-read "Load library: "
                          (apply-partially 'locate-file-completion-table
@@ -1358,7 +1386,8 @@ expand wildcards (if any) and visit multiple files."
 Like \\[find-file], but only allow a file that exists, and do not allow
 file names with wildcards."
    (interactive (nbutlast (find-file-read-args "Find existing file: " t)))
-   (if (and (not (interactive-p)) (not (file-exists-p filename)))
+   (if (and (not (called-interactively-p 'interactive))
+           (not (file-exists-p filename)))
        (error "%s does not exist" filename)
      (find-file filename)
      (current-buffer)))
@@ -1467,18 +1496,29 @@ killed."
           t)))
   (unless (run-hook-with-args-until-failure 'kill-buffer-query-functions)
     (error "Aborted"))
-  (when (and (buffer-modified-p) (buffer-file-name))
-    (if (yes-or-no-p (format "Buffer %s is modified; kill anyway? "
-                            (buffer-name)))
-       (unless (yes-or-no-p "Kill and replace the buffer without saving it? ")
-         (error "Aborted"))
-      (save-buffer)))
+  (when (and (buffer-modified-p) buffer-file-name)
+    (if (yes-or-no-p (format "Buffer %s is modified; save it first? "
+                             (buffer-name)))
+        (save-buffer)
+      (unless (yes-or-no-p "Kill and replace the buffer without saving it? ")
+        (error "Aborted"))))
   (let ((obuf (current-buffer))
        (ofile buffer-file-name)
        (onum buffer-file-number)
        (odir dired-directory)
        (otrue buffer-file-truename)
        (oname (buffer-name)))
+    ;; Run `kill-buffer-hook' here.  It needs to happen before
+    ;; variables like `buffer-file-name' etc are set to nil below,
+    ;; because some of the hooks that could be invoked
+    ;; (e.g., `save-place-to-alist') depend on those variables.
+    ;;
+    ;; Note that `kill-buffer-hook' is not what queries whether to
+    ;; save a modified buffer visiting a file.  Rather, `kill-buffer'
+    ;; asks that itself.  Thus, there's no need to temporarily do
+    ;; `(set-buffer-modified-p nil)' before running this hook.
+    (run-hooks 'kill-buffer-hook)
+    ;; Okay, now we can end-of-life the old buffer.
     (if (get-buffer " **lose**")
        (kill-buffer " **lose**"))
     (rename-buffer " **lose**")
@@ -1506,8 +1546,8 @@ killed."
        (rename-buffer oname)))
     (unless (eq (current-buffer) obuf)
       (with-current-buffer obuf
-       ;; We already asked; don't ask again.
-       (let ((kill-buffer-query-functions))
+       ;; We already ran these; don't run them again.
+       (let (kill-buffer-query-functions kill-buffer-hook)
          (kill-buffer obuf))))))
 \f
 (defun create-file-buffer (filename)
@@ -1567,7 +1607,7 @@ home directory is a root directory) and removes automounter prefixes
       (or abbreviated-home-dir
          (setq abbreviated-home-dir
                (let ((abbreviated-home-dir "$foo"))
-                 (concat "^" (abbreviate-file-name (expand-file-name "~"))
+                 (concat "\\`" (abbreviate-file-name (expand-file-name "~"))
                          "\\(/\\|\\'\\)"))))
 
       ;; If FILENAME starts with the abbreviated homedir,
@@ -1578,9 +1618,7 @@ home directory is a root directory) and removes automounter prefixes
                         (= (aref filename 0) ?/)))
               ;; MS-DOS root directories can come with a drive letter;
               ;; Novell Netware allows drive letters beyond `Z:'.
-              (not (and (or (eq system-type 'ms-dos)
-                            (eq system-type 'cygwin)
-                            (eq system-type 'windows-nt))
+              (not (and (memq system-type '(ms-dos windows-nt cygwin))
                         (save-match-data
                           (string-match "^[a-zA-`]:/$" filename)))))
          (setq filename
@@ -1607,8 +1645,7 @@ If there is no such live buffer, return nil."
           (when (and buf (funcall predicate buf)) buf))
         (let ((list (buffer-list)) found)
           (while (and (not found) list)
-            (save-excursion
-              (set-buffer (car list))
+            (with-current-buffer (car list)
               (if (and buffer-file-name
                        (string= buffer-file-truename truename)
                        (funcall predicate (current-buffer)))
@@ -2096,7 +2133,7 @@ not set local variables (though we do notice a mode specified with -*-.)
 or from Lisp without specifying the optional argument FIND-FILE;
 in that case, this function acts as if `enable-local-variables' were t."
   (interactive)
-  (funcall (or default-major-mode 'fundamental-mode))
+  (funcall (or (default-value 'major-mode) 'fundamental-mode))
   (let ((enable-local-variables (or (not find-file) enable-local-variables)))
     (report-errors "File mode specification error: %s"
       (set-auto-mode))
@@ -2142,6 +2179,7 @@ since only a single case-insensitive search through the alist is made."
      ("\\.dtx\\'" . doctex-mode)
      ("\\.org\\'" . org-mode)
      ("\\.el\\'" . emacs-lisp-mode)
+     ("Project\\.ede\\'" . emacs-lisp-mode)
      ("\\.\\(scm\\|stk\\|ss\\|sch\\)\\'" . scheme-mode)
      ("\\.l\\'" . lisp-mode)
      ("\\.li?sp\\'" . lisp-mode)
@@ -2149,13 +2187,14 @@ since only a single case-insensitive search through the alist is made."
      ("\\.for\\'" . fortran-mode)
      ("\\.p\\'" . pascal-mode)
      ("\\.pas\\'" . pascal-mode)
+     ("\\.\\(dpr\\|DPR\\)\\'" . delphi-mode)
      ("\\.ad[abs]\\'" . ada-mode)
      ("\\.ad[bs].dg\\'" . ada-mode)
      ("\\.\\([pP]\\([Llm]\\|erl\\|od\\)\\|al\\)\\'" . perl-mode)
      ("Imakefile\\'" . makefile-imake-mode)
      ("Makeppfile\\(?:\\.mk\\)?\\'" . makefile-makepp-mode) ; Put this before .mk
      ("\\.makepp\\'" . makefile-makepp-mode)
-     ,@(if (memq system-type '(berkeley-unix next-mach darwin))
+     ,@(if (memq system-type '(berkeley-unix darwin))
           '(("\\.mk\\'" . makefile-bsdmake-mode)
             ("GNUmakefile\\'" . makefile-gmake-mode)
             ("[Mm]akefile\\'" . makefile-bsdmake-mode))
@@ -2200,6 +2239,7 @@ since only a single case-insensitive search through the alist is made."
      ("\\.f9[05]\\'" . f90-mode)
      ("\\.indent\\.pro\\'" . fundamental-mode) ; to avoid idlwave-mode
      ("\\.\\(pro\\|PRO\\)\\'" . idlwave-mode)
+     ("\\.srt\\'" . srecode-template-mode)
      ("\\.prolog\\'" . prolog-mode)
      ("\\.tar\\'" . tar-mode)
      ;; The list of archive file extensions should be in sync with
@@ -2221,7 +2261,7 @@ ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\)\\'" . archive-mode)
      ("\\.x[ms]l\\'" . xml-mode)
      ("\\.dtd\\'" . sgml-mode)
      ("\\.ds\\(ss\\)?l\\'" . dsssl-mode)
-     ("\\.js\\'" . java-mode)          ; javascript-mode would be better
+     ("\\.js\\'" . js-mode)            ; javascript-mode would be better
      ("\\.[ds]?v\\'" . verilog-mode)
      ;; .emacs or .gnus or .viper following a directory delimiter in
      ;; Unix, MSDOG or VMS syntax.
@@ -2304,6 +2344,7 @@ appear in `auto-coding-alist' with `no-conversion' coding system.
 See also `interpreter-mode-alist', which detects executable script modes
 based on the interpreters they specify to run,
 and `magic-mode-alist', which determines modes based on file contents.")
+(put 'auto-mode-alist 'risky-local-variable t)
 
 (defun conf-mode-maybe ()
   "Select Conf mode or XML mode according to start of file."
@@ -2320,7 +2361,7 @@ and `magic-mode-alist', which determines modes based on file contents.")
   ;; and pike-mode) are added through autoload directives in that
   ;; file.  That way is discouraged since it spreads out the
   ;; definition of the initial value.
-  (mapc
+  (mapcar
    (lambda (l)
      (cons (purecopy (car l)) (cdr l)))
    '(("perl" . perl-mode)
@@ -2365,7 +2406,7 @@ of a script, mode MODE is enabled.
 
 See also `auto-mode-alist'.")
 
-(defvar inhibit-first-line-modes-regexps '("\\.tar\\'" "\\.tgz\\'")
+(defvar inhibit-first-line-modes-regexps (mapcar 'purecopy '("\\.tar\\'" "\\.tgz\\'"))
   "List of regexps; if one matches a file name, don't look for `-*-'.")
 
 (defvar inhibit-first-line-modes-suffixes nil
@@ -2397,6 +2438,7 @@ If FUNCTION is nil, then it is not called.  (That is a way of saying
 
 (defvar magic-fallback-mode-alist
   `((image-type-auto-detected-p . image-mode)
+    ("\\(PK00\\)?[P]K\003\004" . archive-mode) ; zip
     ;; The < comes before the groups (but the first) to reduce backtracking.
     ;; TODO: UTF-16 <?xml may be preceded by a BOM 0xff 0xfe or 0xfe 0xff.
     ;; We use [ \t\r\n] instead of `\\s ' to make regex overflow less likely.
@@ -2639,6 +2681,7 @@ Otherwise, return nil; point may be changed."
   '(ignored-local-variables safe-local-variable-values
     file-local-variables-alist dir-local-variables-alist)
   "Variables to be ignored in a file's local variable spec.")
+(put 'ignored-local-variables 'risky-local-variable t)
 
 (defvar hack-local-variables-hook nil
   "Normal hook run after processing a file's local variables specs.
@@ -2649,14 +2692,18 @@ in order to initialize other data structure based on them.")
   "List variable-value pairs that are considered safe.
 Each element is a cons cell (VAR . VAL), where VAR is a variable
 symbol and VAL is a value that is considered safe."
+  :risky t
   :group 'find-file
   :type 'alist)
 
-(defcustom safe-local-eval-forms '((add-hook 'write-file-hooks 'time-stamp))
+(defcustom safe-local-eval-forms
+  '((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
 they appear in an `eval' local variable specification, without first
 asking you for confirmation."
+  :risky t
   :group 'find-file
   :version "22.2"
   :type '(repeat sexp))
@@ -2664,63 +2711,34 @@ asking you for confirmation."
 ;; Risky local variables:
 (mapc (lambda (var) (put var 'risky-local-variable t))
       '(after-load-alist
-       auto-mode-alist
        buffer-auto-save-file-name
        buffer-file-name
        buffer-file-truename
        buffer-undo-list
-       dabbrev-case-fold-search
-       dabbrev-case-replace
        debugger
        default-text-properties
-       display-time-string
-       enable-local-eval
-       enable-local-variables
        eval
        exec-directory
        exec-path
        file-name-handler-alist
-       font-lock-defaults
-       format-alist
        frame-title-format
        global-mode-string
        header-line-format
        icon-title-format
-       ignored-local-variables
-       imenu--index-alist
-       imenu-generic-expression
        inhibit-quit
-       input-method-alist
        load-path
        max-lisp-eval-depth
        max-specpdl-size
-       minor-mode-alist
        minor-mode-map-alist
        minor-mode-overriding-map-alist
-       mode-line-buffer-identification
        mode-line-format
-       mode-line-client
-       mode-line-modes
-       mode-line-modified
-       mode-line-mule-info
-       mode-line-position
-       mode-line-process
-       mode-line-remote
        mode-name
-       outline-level
        overriding-local-map
        overriding-terminal-local-map
-       parse-time-rules
        process-environment
-       rmail-output-file-alist
-       safe-local-variable-values
-       safe-local-eval-forms
-       save-some-buffers-action-alist
-       special-display-buffer-names
        standard-input
        standard-output
-       unread-command-events
-       vc-mode))
+       unread-command-events))
 
 ;; Safe local variables:
 ;;
@@ -3189,7 +3207,12 @@ already the major mode."
                                     "-mode"))))
           (unless (eq (indirect-function mode)
                       (indirect-function major-mode))
-            (funcall mode))))
+            (if (memq mode minor-mode-list)
+                ;; A minor mode must be passed an argument.
+                ;; Otherwise, if the user enables the minor mode in a
+                ;; major mode hook, this would toggle it off.
+                (funcall mode 1)
+              (funcall mode)))))
        ((eq var 'eval)
         (save-excursion (eval val)))
        (t
@@ -4377,7 +4400,7 @@ This requires the external program `diff' to be in your `exec-path'."
           (recursive-edit))
         ;; Return nil to ask about BUF again.
         nil)
-     "view this buffer")
+     ,(purecopy "view this buffer"))
     (?d ,(lambda (buf)
            (if (null (buffer-file-name buf))
                (message "Not applicable: no file")
@@ -4390,8 +4413,9 @@ This requires the external program `diff' to be in your `exec-path'."
                (recursive-edit)))
            ;; Return nil to ask about BUF again.
            nil)
-       "view changes in this buffer"))
+       ,(purecopy "view changes in this buffer")))
   "ACTION-ALIST argument used in call to `map-y-or-n-p'.")
+(put 'save-some-buffers-action-alist 'risky-local-variable t)
 
 (defvar buffer-save-without-query nil
   "Non-nil means `save-some-buffers' should save this buffer without asking.")
@@ -4611,6 +4635,97 @@ this happens by default."
          (while create-list
            (make-directory-internal (car create-list))
            (setq create-list (cdr create-list))))))))
+
+(defconst directory-files-no-dot-files-regexp
+  "^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*"
+  "Regexp of file names excluging \".\" an \"..\".")
+
+(defun delete-directory (directory &optional recursive)
+  "Delete the directory named DIRECTORY.  Does not follow symlinks.
+If RECURSIVE is non-nil, all files in DIRECTORY are deleted as well."
+  (interactive
+   (let ((dir (expand-file-name
+              (read-file-name
+               "Delete directory: "
+               default-directory default-directory nil nil))))
+     (list dir
+          (if (directory-files dir nil directory-files-no-dot-files-regexp)
+              (y-or-n-p
+               (format "Directory `%s' is not empty, really delete? " dir))
+            nil))))
+  ;; If default-directory is a remote directory, make sure we find its
+  ;; delete-directory handler.
+  (setq directory (directory-file-name (expand-file-name directory)))
+  (let ((handler (find-file-name-handler directory 'delete-directory)))
+    (if handler
+       (funcall handler 'delete-directory directory recursive)
+      (if (and recursive (not (file-symlink-p directory)))
+         (mapc
+          (lambda (file)
+            ;; This test is equivalent to
+            ;; (and (file-directory-p fn) (not (file-symlink-p fn)))
+            ;; but more efficient
+            (if (eq t (car (file-attributes file)))
+                (delete-directory file recursive)
+              (delete-file file)))
+          ;; We do not want to delete "." and "..".
+          (directory-files
+           directory 'full directory-files-no-dot-files-regexp)))
+      (delete-directory-internal directory))))
+
+(defun copy-directory (directory newname &optional keep-time parents)
+  "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.
+
+The third arg KEEP-TIME non-nil means give the output files the same
+last-modified time as the old ones.  (This works on only some systems.)
+
+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."
+  (interactive
+   (let ((dir (read-directory-name
+              "Copy directory: " default-directory default-directory t nil)))
+     (list dir
+          (read-file-name
+           (format "Copy directory %s to: " dir)
+           default-directory default-directory nil nil)
+          current-prefix-arg t)))
+  ;; 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)
+                    (find-file-name-handler newname 'copy-directory))))
+    (if handler
+       (funcall handler 'copy-directory directory newname keep-time parents)
+
+      ;; Compute target name.
+      (setq directory (directory-file-name (expand-file-name directory))
+           newname   (directory-file-name (expand-file-name newname)))
+      (if (and (file-directory-p newname)
+              (not (string-equal (file-name-nondirectory directory)
+                                 (file-name-nondirectory newname))))
+         (setq newname
+               (expand-file-name (file-name-nondirectory directory) newname)))
+      (if (not (file-directory-p newname)) (make-directory newname parents))
+
+      ;; Copy recursively.
+      (mapc
+       (lambda (file)
+        (if (file-directory-p file)
+            (copy-directory file newname keep-time parents)
+          (copy-file file newname t keep-time)))
+       ;; We do not want to delete "." and "..".
+       (directory-files        directory 'full directory-files-no-dot-files-regexp))
+
+      ;; Set directory attributes.
+      (set-file-modes newname (file-modes directory))
+      (if keep-time
+         (set-file-times newname (nth 5 (file-attributes directory)))))))
 \f
 (put 'revert-buffer-function 'permanent-local t)
 (defvar revert-buffer-function nil
@@ -4723,7 +4838,7 @@ non-nil, it is called instead of rereading visited file contents."
                                        file-name)))
               (run-hooks 'before-revert-hook)
               ;; If file was backed up but has changed since,
-              ;; we shd make another backup.
+              ;; we should make another backup.
               (and (not auto-save-p)
                    (not (verify-visited-file-modtime (current-buffer)))
                    (setq buffer-backed-up nil))
@@ -5005,7 +5120,7 @@ With prefix argument ARG, turn auto-saving on if positive, else off."
                 (or (not buffer-auto-save-file-name)
                     ;; If auto-save is off because buffer has shrunk,
                     ;; then toggling should turn it on.
-                    (= buffer-saved-size -1))
+                    (< buffer-saved-size 0))
               (or (eq arg t) (listp arg) (and (integerp arg) (> arg 0))))
             (if (and buffer-file-name auto-save-visited-file-name
                      (not buffer-read-only))
@@ -5013,9 +5128,9 @@ With prefix argument ARG, turn auto-saving on if positive, else off."
               (make-auto-save-file-name))))
   ;; If -1 was stored here, to temporarily turn off saving,
   ;; turn it back on.
-  (and (= buffer-saved-size -1)
+  (and (< buffer-saved-size 0)
        (setq buffer-saved-size 0))
-  (if (interactive-p)
+  (if (called-interactively-p 'interactive)
       (message "Auto-save %s (in this buffer)"
               (if buffer-auto-save-file-name "on" "off")))
   buffer-auto-save-file-name)
@@ -5384,22 +5499,20 @@ fail.  It returns also nil when DIR is a remote directory.
 
 This function calls `file-system-info' if it is available, or invokes the
 program specified by `directory-free-space-program' if that is non-nil."
-  (when (not (file-remote-p dir))
+  (unless (file-remote-p dir)
     ;; Try to find the number of free blocks.  Non-Posix systems don't
     ;; always have df, but might have an equivalent system call.
     (if (fboundp 'file-system-info)
        (let ((fsinfo (file-system-info dir)))
          (if fsinfo
              (format "%.0f" (/ (nth 2 fsinfo) 1024))))
+      (setq dir (expand-file-name dir))
       (save-match-data
        (with-temp-buffer
          (when (and directory-free-space-program
-                    (let ((default-directory
-                            (if (and (not (file-remote-p default-directory))
-                                     (file-directory-p default-directory)
-                                     (file-readable-p default-directory))
-                                default-directory
-                              (expand-file-name "~/"))))
+                    ;; Avoid failure if the default directory does
+                    ;; not exist (Bug#2631, Bug#3911).
+                    (let ((default-directory "/"))
                       (eq (call-process directory-free-space-program
                                         nil t nil
                                         directory-free-space-args