lisp/gnus/shr.el: (shr-tag-dl, shr-tag-dt, shr-tag-dd): Add support for <dl>, <dt...
[bpt/emacs.git] / lisp / net / tramp-cache.el
CommitLineData
00d6fd04
MA
1;;; tramp-cache.el --- file information caching for Tramp
2
ab422c4d 3;; Copyright (C) 2000, 2005-2013 Free Software Foundation, Inc.
00d6fd04
MA
4
5;; Author: Daniel Pittman <daniel@inanna.danann.net>
6;; Michael Albinus <michael.albinus@gmx.de>
7;; Keywords: comm, processes
bd78fa1d 8;; Package: tramp
00d6fd04
MA
9
10;; This file is part of GNU Emacs.
11
874a927a 12;; GNU Emacs is free software: you can redistribute it and/or modify
00d6fd04 13;; it under the terms of the GNU General Public License as published by
874a927a
GM
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
00d6fd04
MA
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
874a927a 23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
00d6fd04
MA
24
25;;; Commentary:
26
27;; An implementation of information caching for remote files.
28
29;; Each connection, identified by a vector [method user host
30;; localname] or by a process, has a unique cache. We distinguish 3
31;; kind of caches, depending on the key:
32;;
33;; - localname is NIL. This are reusable properties. Examples:
34;; "remote-shell" identifies the POSIX shell to be called on the
35;; remote host, or "perl" is the command to be called on the remote
2c68ca0e 36;; host when starting a Perl script. These properties are saved in
00d6fd04
MA
37;; the file `tramp-persistency-file-name'.
38;;
39;; - localname is a string. This are temporary properties, which are
40;; related to the file localname is referring to. Examples:
41;; "file-exists-p" is t or nile, depending on the file existence, or
42;; "file-attributes" caches the result of the function
43;; `file-attributes'.
44;;
45;; - The key is a process. This are temporary properties related to
46;; an open connection. Examples: "scripts" keeps shell script
47;; definitions already sent to the remote shell, "last-cmd-time" is
48;; the time stamp a command has been sent to the remote process.
49
50;;; Code:
51
0f34aa77
MA
52(require 'tramp)
53(autoload 'time-stamp-string "time-stamp")
00d6fd04
MA
54
55;;; -- Cache --
56
0f34aa77 57;;;###tramp-autoload
00d6fd04
MA
58(defvar tramp-cache-data (make-hash-table :test 'equal)
59 "Hash table for remote files properties.")
60
61addbc2
MA
61;;;###tramp-autoload
62(defcustom tramp-connection-properties nil
63 "List of static connection properties.
64Every entry has the form (REGEXP PROPERTY VALUE). The regexp
65matches remote file names. It can be nil. PROPERTY is a string,
66and VALUE the corresponding value. They are used, if there is no
67matching entry in for PROPERTY in `tramp-cache-data'."
68 :group 'tramp
69 :version "24.4"
70 :type '(repeat (list (choice :tag "File Name regexp" regexp (const nil))
71 (choice :tag " Property" string)
72 (choice :tag " Value" sexp))))
73
00d6fd04
MA
74(defcustom tramp-persistency-file-name
75 (cond
76 ;; GNU Emacs.
d68b0220
MA
77 ((and (fboundp 'locate-user-emacs-file))
78 (expand-file-name (tramp-compat-funcall 'locate-user-emacs-file "tramp")))
00d6fd04
MA
79 ((and (boundp 'user-emacs-directory)
80 (stringp (symbol-value 'user-emacs-directory))
81 (file-directory-p (symbol-value 'user-emacs-directory)))
82 (expand-file-name "tramp" (symbol-value 'user-emacs-directory)))
83 ((and (not (featurep 'xemacs)) (file-directory-p "~/.emacs.d/"))
84 "~/.emacs.d/tramp")
85 ;; XEmacs.
86 ((and (boundp 'user-init-directory)
87 (stringp (symbol-value 'user-init-directory))
88 (file-directory-p (symbol-value 'user-init-directory)))
89 (expand-file-name "tramp" (symbol-value 'user-init-directory)))
90 ((and (featurep 'xemacs) (file-directory-p "~/.xemacs/"))
91 "~/.xemacs/tramp")
92 ;; For users without `~/.emacs.d/' or `~/.xemacs/'.
93 (t "~/.tramp"))
94 "File which keeps connection history for Tramp connections."
95 :group 'tramp
96 :type 'file)
97
7c3404ec
MA
98(defvar tramp-cache-data-changed nil
99 "Whether persistent cache data have been changed.")
100
81ed22e4
MA
101(defun tramp-get-hash-table (key)
102 "Returns the hash table for KEY.
103If it doesn't exist yet, it is created and initialized with
104matching entries of `tramp-connection-properties'."
105 (or (gethash key tramp-cache-data)
106 (let ((hash
107 (puthash key (make-hash-table :test 'equal) tramp-cache-data)))
108 (when (vectorp key)
109 (dolist (elt tramp-connection-properties)
110 (when (string-match
111 (or (nth 0 elt) "")
112 (tramp-make-tramp-file-name
113 (aref key 0) (aref key 1) (aref key 2) nil))
114 (tramp-set-connection-property key (nth 1 elt) (nth 2 elt)))))
115 hash)))
116
0f34aa77 117;;;###tramp-autoload
81ed22e4
MA
118(defun tramp-get-file-property (key file property default)
119 "Get the PROPERTY of FILE from the cache context of KEY.
00d6fd04
MA
120Returns DEFAULT if not set."
121 ;; Unify localname.
81ed22e4
MA
122 (setq key (copy-sequence key))
123 (aset key 3 (tramp-run-real-handler 'directory-file-name (list file)))
124 (let* ((hash (tramp-get-hash-table key))
d5b5c94a
MA
125 (value (when (hash-table-p hash) (gethash property hash))))
126 (if
127 ;; We take the value only if there is any, and
4bc3c53d 128 ;; `remote-file-name-inhibit-cache' indicates that it is still
d5b5c94a
MA
129 ;; valid. Otherwise, DEFAULT is set.
130 (and (consp value)
4bc3c53d
MA
131 (or (null remote-file-name-inhibit-cache)
132 (and (integerp remote-file-name-inhibit-cache)
133 (<=
134 (tramp-time-diff (current-time) (car value))
135 remote-file-name-inhibit-cache))
136 (and (consp remote-file-name-inhibit-cache)
d5b5c94a 137 (tramp-time-less-p
4bc3c53d 138 remote-file-name-inhibit-cache (car value)))))
d5b5c94a
MA
139 (setq value (cdr value))
140 (setq value default))
141
81ed22e4 142 (tramp-message key 8 "%s %s %s" file property value)
4bc3c53d
MA
143 (when (>= tramp-verbose 10)
144 (let* ((var (intern (concat "tramp-cache-get-count-" property)))
145 (val (or (ignore-errors (symbol-value var)) 0)))
146 (set var (1+ val))))
00d6fd04
MA
147 value))
148
0f34aa77 149;;;###tramp-autoload
81ed22e4
MA
150(defun tramp-set-file-property (key file property value)
151 "Set the PROPERTY of FILE to VALUE, in the cache context of KEY.
00d6fd04
MA
152Returns VALUE."
153 ;; Unify localname.
81ed22e4
MA
154 (setq key (copy-sequence key))
155 (aset key 3 (tramp-run-real-handler 'directory-file-name (list file)))
156 (let ((hash (tramp-get-hash-table key)))
d5b5c94a
MA
157 ;; We put the timestamp there.
158 (puthash property (cons (current-time) value) hash)
81ed22e4 159 (tramp-message key 8 "%s %s %s" file property value)
4bc3c53d
MA
160 (when (>= tramp-verbose 10)
161 (let* ((var (intern (concat "tramp-cache-set-count-" property)))
162 (val (or (ignore-errors (symbol-value var)) 0)))
163 (set var (1+ val))))
00d6fd04
MA
164 value))
165
0f34aa77 166;;;###tramp-autoload
81ed22e4
MA
167(defun tramp-flush-file-property (key file)
168 "Remove all properties of FILE in the cache context of KEY."
d0c8fc8a 169 ;; Remove file property of symlinks.
81ed22e4 170 (let ((truename (tramp-get-file-property key file "file-truename" nil)))
d0c8fc8a
MA
171 (when (and (stringp truename)
172 (not (string-equal file truename)))
81ed22e4 173 (tramp-flush-file-property key truename)))
00d6fd04 174 ;; Unify localname.
81ed22e4
MA
175 (setq key (copy-sequence key))
176 (aset key 3 (tramp-run-real-handler 'directory-file-name (list file)))
177 (tramp-message key 8 "%s" file)
178 (remhash key tramp-cache-data))
00d6fd04 179
0f34aa77 180;;;###tramp-autoload
81ed22e4
MA
181(defun tramp-flush-directory-property (key directory)
182 "Remove all properties of DIRECTORY in the cache context of KEY.
00d6fd04 183Remove also properties of all files in subdirectories."
87bdd2c7
MA
184 (let ((directory (tramp-run-real-handler
185 'directory-file-name (list directory))))
81ed22e4 186 (tramp-message key 8 "%s" directory)
00d6fd04 187 (maphash
4f91a816 188 (lambda (key value)
065ec2c7
MA
189 (when (and (stringp (tramp-file-name-localname key))
190 (string-match directory (tramp-file-name-localname key)))
191 (remhash key tramp-cache-data)))
00d6fd04
MA
192 tramp-cache-data)))
193
00d6fd04 194;; Reverting or killing a buffer should also flush file properties.
a7580c1c
MA
195;; They could have been changed outside Tramp. In eshell, "ls" would
196;; not show proper directory contents when a file has been copied or
197;; deleted before.
00d6fd04 198(defun tramp-flush-file-function ()
06207091 199 "Flush all Tramp cache properties from `buffer-file-name'."
a7580c1c
MA
200 (let ((bfn (if (stringp (buffer-file-name))
201 (buffer-file-name)
202 default-directory)))
203 (when (tramp-tramp-file-p bfn)
0f34aa77 204 (with-parsed-tramp-file-name bfn nil
00d6fd04
MA
205 (tramp-flush-file-property v localname)))))
206
207(add-hook 'before-revert-hook 'tramp-flush-file-function)
a7580c1c 208(add-hook 'eshell-pre-command-hook 'tramp-flush-file-function)
00d6fd04
MA
209(add-hook 'kill-buffer-hook 'tramp-flush-file-function)
210(add-hook 'tramp-cache-unload-hook
4f91a816 211 (lambda ()
065ec2c7
MA
212 (remove-hook 'before-revert-hook
213 'tramp-flush-file-function)
214 (remove-hook 'eshell-pre-command-hook
215 'tramp-flush-file-function)
216 (remove-hook 'kill-buffer-hook
217 'tramp-flush-file-function)))
00d6fd04
MA
218
219;;; -- Properties --
220
0f34aa77 221;;;###tramp-autoload
00d6fd04
MA
222(defun tramp-get-connection-property (key property default)
223 "Get the named PROPERTY for the connection.
224KEY identifies the connection, it is either a process or a vector.
225If the value is not set for the connection, returns DEFAULT."
226 ;; Unify key by removing localname from vector. Work with a copy in
227 ;; order to avoid side effects.
228 (when (vectorp key)
229 (setq key (copy-sequence key))
230 (aset key 3 nil))
81ed22e4
MA
231 (let* ((hash (tramp-get-hash-table key))
232 (value (if (hash-table-p hash)
233 (gethash property hash default)
234 default)))
00d6fd04
MA
235 (tramp-message key 7 "%s %s" property value)
236 value))
237
0f34aa77 238;;;###tramp-autoload
00d6fd04
MA
239(defun tramp-set-connection-property (key property value)
240 "Set the named PROPERTY of a connection to VALUE.
241KEY identifies the connection, it is either a process or a vector.
242PROPERTY is set persistent when KEY is a vector."
243 ;; Unify key by removing localname from vector. Work with a copy in
244 ;; order to avoid side effects.
245 (when (vectorp key)
246 (setq key (copy-sequence key))
247 (aset key 3 nil))
81ed22e4 248 (let ((hash (tramp-get-hash-table key)))
00d6fd04 249 (puthash property value hash)
7c3404ec 250 (setq tramp-cache-data-changed t)
03c1ad43 251 (tramp-message key 7 "%s %s" property value)
00d6fd04
MA
252 value))
253
81ed22e4
MA
254;;;###tramp-autoload
255(defun tramp-connection-property-p (key property)
256 "Check whether named PROPERTY of a connection is defined.
257KEY identifies the connection, it is either a process or a vector."
258 (not (eq (tramp-get-connection-property key property 'undef) 'undef)))
259
0f34aa77 260;;;###tramp-autoload
1a0b96d3 261(defun tramp-flush-connection-property (key)
00d6fd04 262 "Remove all properties identified by KEY.
1a0b96d3 263KEY identifies the connection, it is either a process or a vector."
00d6fd04
MA
264 ;; Unify key by removing localname from vector. Work with a copy in
265 ;; order to avoid side effects.
266 (when (vectorp key)
267 (setq key (copy-sequence key))
268 (aset key 3 nil))
e946faaf
MA
269 (tramp-message
270 key 7 "%s %s" key
674a9263
MA
271 (let ((hash (gethash key tramp-cache-data))
272 properties)
81ed22e4
MA
273 (when (hash-table-p hash)
274 (maphash (lambda (x y) (add-to-list 'properties x 'append)) hash))
e946faaf 275 properties))
7c3404ec 276 (setq tramp-cache-data-changed t)
00d6fd04
MA
277 (remhash key tramp-cache-data))
278
0f34aa77 279;;;###tramp-autoload
726f0272 280(defun tramp-cache-print (table)
b08104a0 281 "Print hash table TABLE."
726f0272
MA
282 (when (hash-table-p table)
283 (let (result)
284 (maphash
4f91a816 285 (lambda (key value)
065ec2c7
MA
286 (let ((tmp (format
287 "(%s %s)"
288 (if (processp key)
289 (prin1-to-string (prin1-to-string key))
290 (prin1-to-string key))
291 (if (hash-table-p value)
292 (tramp-cache-print value)
293 (if (bufferp value)
294 (prin1-to-string (prin1-to-string value))
295 (prin1-to-string value))))))
296 (setq result (if result (concat result " " tmp) tmp))))
726f0272
MA
297 table)
298 result)))
299
0f34aa77 300;;;###tramp-autoload
b08104a0
MA
301(defun tramp-list-connections ()
302 "Return a list of all known connection vectors according to `tramp-cache'."
726f0272
MA
303 (let (result)
304 (maphash
4f91a816 305 (lambda (key value)
065ec2c7
MA
306 (when (and (vectorp key) (null (aref key 3)))
307 (add-to-list 'result key)))
726f0272
MA
308 tramp-cache-data)
309 result))
310
00d6fd04 311(defun tramp-dump-connection-properties ()
b08104a0 312 "Write persistent connection properties into file `tramp-persistency-file-name'."
00d6fd04 313 ;; We shouldn't fail, otherwise (X)Emacs might not be able to be closed.
03c1ad43
MA
314 (ignore-errors
315 (when (and (hash-table-p tramp-cache-data)
316 (not (zerop (hash-table-count tramp-cache-data)))
317 tramp-cache-data-changed
318 (stringp tramp-persistency-file-name))
2fe4b125
MA
319 (let ((cache (copy-hash-table tramp-cache-data))
320 print-length print-level)
a5509865
MA
321 ;; Remove temporary data. If there is the key "login-as", we
322 ;; don't save either, because all other properties might
323 ;; depend on the login name, and we want to give the
324 ;; possibility to use another login name later on.
03c1ad43 325 (maphash
4f91a816 326 (lambda (key value)
a5509865
MA
327 (if (and (vectorp key)
328 (not (tramp-file-name-localname key))
329 (not (gethash "login-as" value)))
065ec2c7
MA
330 (progn
331 (remhash "process-name" value)
332 (remhash "process-buffer" value)
333 (remhash "first-password-request" value))
334 (remhash key cache)))
03c1ad43
MA
335 cache)
336 ;; Dump it.
337 (with-temp-buffer
338 (insert
339 ";; -*- emacs-lisp -*-"
340 ;; `time-stamp-string' might not exist in all (X)Emacs flavors.
341 (condition-case nil
342 (progn
343 (format
344 " <%s %s>\n"
345 (time-stamp-string "%02y/%02m/%02d %02H:%02M:%02S")
346 tramp-persistency-file-name))
347 (error "\n"))
348 ";; Tramp connection history. Don't change this file.\n"
349 ";; You can delete it, forcing Tramp to reapply the checks.\n\n"
350 (with-output-to-string
351 (pp (read (format "(%s)" (tramp-cache-print cache))))))
352 (write-region
353 (point-min) (point-max) tramp-persistency-file-name))))))
00d6fd04 354
845fc5e5
JB
355(unless noninteractive
356 (add-hook 'kill-emacs-hook 'tramp-dump-connection-properties))
00d6fd04 357(add-hook 'tramp-cache-unload-hook
4f91a816 358 (lambda ()
065ec2c7
MA
359 (remove-hook 'kill-emacs-hook
360 'tramp-dump-connection-properties)))
00d6fd04 361
8fca3921 362;;;###tramp-autoload
00d6fd04
MA
363(defun tramp-parse-connection-properties (method)
364 "Return a list of (user host) tuples allowed to access for METHOD.
365This function is added always in `tramp-get-completion-function'
06207091 366for all methods. Resulting data are derived from connection history."
00d6fd04
MA
367 (let (res)
368 (maphash
4f91a816 369 (lambda (key value)
065ec2c7
MA
370 (if (and (vectorp key)
371 (string-equal method (tramp-file-name-method key))
372 (not (tramp-file-name-localname key)))
373 (push (list (tramp-file-name-user key)
374 (tramp-file-name-host key))
375 res)))
00d6fd04
MA
376 tramp-cache-data)
377 res))
378
27e813fe 379;; Read persistent connection history.
8a4438b6 380(when (and (stringp tramp-persistency-file-name)
065ec2c7
MA
381 (zerop (hash-table-count tramp-cache-data))
382 ;; When "emacs -Q" has been called, both variables are nil.
383 ;; We do not load the persistency file then, in order to
384 ;; have a clean test environment.
09388e76
MA
385 (or (and (boundp 'init-file-user) (symbol-value 'init-file-user))
386 (and (boundp 'site-run-file) (symbol-value 'site-run-file))))
00d6fd04
MA
387 (condition-case err
388 (with-temp-buffer
389 (insert-file-contents tramp-persistency-file-name)
390 (let ((list (read (current-buffer)))
391 element key item)
392 (while (setq element (pop list))
393 (setq key (pop element))
394 (while (setq item (pop element))
81ed22e4
MA
395 ;; We set only values which are not contained in
396 ;; `tramp-connection-properties'. The cache is
397 ;; initialized properly by side effect.
398 (unless (tramp-connection-property-p key (car item))
399 (tramp-set-connection-property key (pop item) (car item))))))
7c3404ec 400 (setq tramp-cache-data-changed nil))
00d6fd04
MA
401 (file-error
402 ;; Most likely because the file doesn't exist yet. No message.
403 (clrhash tramp-cache-data))
404 (error
405 ;; File is corrupted.
8a4438b6
MA
406 (message "Tramp persistency file '%s' is corrupted: %s"
407 tramp-persistency-file-name (error-message-string err))
00d6fd04
MA
408 (clrhash tramp-cache-data))))
409
0f34aa77
MA
410(add-hook 'tramp-unload-hook
411 (lambda ()
412 (unload-feature 'tramp-cache 'force)))
413
00d6fd04
MA
414(provide 'tramp-cache)
415
416;;; tramp-cache.el ends here