Commit | Line | Data |
---|---|---|
00d6fd04 MA |
1 | ;;; tramp-cache.el --- file information caching for Tramp |
2 | ||
7540f029 | 3 | ;; Copyright (C) 2000, 2005, 2006, 2007, 2008, 2009, |
5df4f04c | 4 | ;; 2010, 2011 Free Software Foundation, Inc. |
00d6fd04 MA |
5 | |
6 | ;; Author: Daniel Pittman <daniel@inanna.danann.net> | |
7 | ;; Michael Albinus <michael.albinus@gmx.de> | |
8 | ;; Keywords: comm, processes | |
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 | |
36 | ;; host, when starting a Perl script. These properties are saved in | |
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 | ||
52 | ;; Pacify byte-compiler. | |
53 | (eval-when-compile | |
54 | (require 'cl) | |
55 | (autoload 'tramp-message "tramp") | |
56 | (autoload 'tramp-tramp-file-p "tramp") | |
57 | ;; We cannot autoload macro `with-parsed-tramp-file-name', it | |
58 | ;; results in problems of byte-compiled code. | |
59 | (autoload 'tramp-dissect-file-name "tramp") | |
60 | (autoload 'tramp-file-name-method "tramp") | |
61 | (autoload 'tramp-file-name-user "tramp") | |
62 | (autoload 'tramp-file-name-host "tramp") | |
63 | (autoload 'tramp-file-name-localname "tramp") | |
18288ba7 | 64 | (autoload 'tramp-run-real-handler "tramp") |
d5b5c94a | 65 | (autoload 'tramp-time-less-p "tramp") |
00d6fd04 MA |
66 | (autoload 'time-stamp-string "time-stamp")) |
67 | ||
68 | ;;; -- Cache -- | |
69 | ||
70 | (defvar tramp-cache-data (make-hash-table :test 'equal) | |
71 | "Hash table for remote files properties.") | |
72 | ||
afae3a37 | 73 | (defvar tramp-cache-inhibit-cache nil |
d5b5c94a MA |
74 | "Inhibit cache read access, when `t'. |
75 | `nil' means to accept cache entries unconditionally. If the | |
76 | value is a timestamp (as returned by `current-time'), cache | |
77 | entries are not used when they have been written before this | |
78 | time.") | |
afae3a37 | 79 | |
00d6fd04 MA |
80 | (defcustom tramp-persistency-file-name |
81 | (cond | |
82 | ;; GNU Emacs. | |
83 | ((and (boundp 'user-emacs-directory) | |
84 | (stringp (symbol-value 'user-emacs-directory)) | |
85 | (file-directory-p (symbol-value 'user-emacs-directory))) | |
86 | (expand-file-name "tramp" (symbol-value 'user-emacs-directory))) | |
87 | ((and (not (featurep 'xemacs)) (file-directory-p "~/.emacs.d/")) | |
88 | "~/.emacs.d/tramp") | |
89 | ;; XEmacs. | |
90 | ((and (boundp 'user-init-directory) | |
91 | (stringp (symbol-value 'user-init-directory)) | |
92 | (file-directory-p (symbol-value 'user-init-directory))) | |
93 | (expand-file-name "tramp" (symbol-value 'user-init-directory))) | |
94 | ((and (featurep 'xemacs) (file-directory-p "~/.xemacs/")) | |
95 | "~/.xemacs/tramp") | |
96 | ;; For users without `~/.emacs.d/' or `~/.xemacs/'. | |
97 | (t "~/.tramp")) | |
98 | "File which keeps connection history for Tramp connections." | |
99 | :group 'tramp | |
100 | :type 'file) | |
101 | ||
7c3404ec MA |
102 | (defvar tramp-cache-data-changed nil |
103 | "Whether persistent cache data have been changed.") | |
104 | ||
00d6fd04 MA |
105 | (defun tramp-get-file-property (vec file property default) |
106 | "Get the PROPERTY of FILE from the cache context of VEC. | |
107 | Returns DEFAULT if not set." | |
108 | ;; Unify localname. | |
109 | (setq vec (copy-sequence vec)) | |
87bdd2c7 | 110 | (aset vec 3 (tramp-run-real-handler 'directory-file-name (list file))) |
00d6fd04 MA |
111 | (let* ((hash (or (gethash vec tramp-cache-data) |
112 | (puthash vec (make-hash-table :test 'equal) | |
113 | tramp-cache-data))) | |
d5b5c94a MA |
114 | (value (when (hash-table-p hash) (gethash property hash)))) |
115 | (if | |
116 | ;; We take the value only if there is any, and | |
117 | ;; `tramp-cache-inhibit-cache' indicates that it is still | |
118 | ;; valid. Otherwise, DEFAULT is set. | |
119 | (and (consp value) | |
120 | (or (null tramp-cache-inhibit-cache) | |
121 | (and (consp tramp-cache-inhibit-cache) | |
122 | (tramp-time-less-p | |
123 | tramp-cache-inhibit-cache (car value))))) | |
124 | (setq value (cdr value)) | |
125 | (setq value default)) | |
126 | ||
127 | (if (consp tramp-cache-inhibit-cache) | |
128 | (tramp-message vec 1 "%s %s %s" file property value)) | |
00d6fd04 MA |
129 | (tramp-message vec 8 "%s %s %s" file property value) |
130 | value)) | |
131 | ||
132 | (defun tramp-set-file-property (vec file property value) | |
133 | "Set the PROPERTY of FILE to VALUE, in the cache context of VEC. | |
134 | Returns VALUE." | |
135 | ;; Unify localname. | |
136 | (setq vec (copy-sequence vec)) | |
87bdd2c7 | 137 | (aset vec 3 (tramp-run-real-handler 'directory-file-name (list file))) |
00d6fd04 MA |
138 | (let ((hash (or (gethash vec tramp-cache-data) |
139 | (puthash vec (make-hash-table :test 'equal) | |
140 | tramp-cache-data)))) | |
d5b5c94a MA |
141 | ;; We put the timestamp there. |
142 | (puthash property (cons (current-time) value) hash) | |
00d6fd04 MA |
143 | (tramp-message vec 8 "%s %s %s" file property value) |
144 | value)) | |
145 | ||
146 | (defun tramp-flush-file-property (vec file) | |
147 | "Remove all properties of FILE in the cache context of VEC." | |
148 | ;; Unify localname. | |
149 | (setq vec (copy-sequence vec)) | |
87bdd2c7 | 150 | (aset vec 3 (tramp-run-real-handler 'directory-file-name (list file))) |
00d6fd04 MA |
151 | (tramp-message vec 8 "%s" file) |
152 | (remhash vec tramp-cache-data)) | |
153 | ||
154 | (defun tramp-flush-directory-property (vec directory) | |
155 | "Remove all properties of DIRECTORY in the cache context of VEC. | |
156 | Remove also properties of all files in subdirectories." | |
87bdd2c7 MA |
157 | (let ((directory (tramp-run-real-handler |
158 | 'directory-file-name (list directory)))) | |
00d6fd04 MA |
159 | (tramp-message vec 8 "%s" directory) |
160 | (maphash | |
161 | '(lambda (key value) | |
5ec2288f | 162 | (when (and (stringp (tramp-file-name-localname key)) |
00d6fd04 MA |
163 | (string-match directory (tramp-file-name-localname key))) |
164 | (remhash key tramp-cache-data))) | |
165 | tramp-cache-data))) | |
166 | ||
00d6fd04 | 167 | ;; Reverting or killing a buffer should also flush file properties. |
a7580c1c MA |
168 | ;; They could have been changed outside Tramp. In eshell, "ls" would |
169 | ;; not show proper directory contents when a file has been copied or | |
170 | ;; deleted before. | |
00d6fd04 | 171 | (defun tramp-flush-file-function () |
06207091 | 172 | "Flush all Tramp cache properties from `buffer-file-name'." |
a7580c1c MA |
173 | (let ((bfn (if (stringp (buffer-file-name)) |
174 | (buffer-file-name) | |
175 | default-directory))) | |
176 | (when (tramp-tramp-file-p bfn) | |
00d6fd04 MA |
177 | (let* ((v (tramp-dissect-file-name bfn)) |
178 | (localname (tramp-file-name-localname v))) | |
179 | (tramp-flush-file-property v localname))))) | |
180 | ||
181 | (add-hook 'before-revert-hook 'tramp-flush-file-function) | |
a7580c1c | 182 | (add-hook 'eshell-pre-command-hook 'tramp-flush-file-function) |
00d6fd04 MA |
183 | (add-hook 'kill-buffer-hook 'tramp-flush-file-function) |
184 | (add-hook 'tramp-cache-unload-hook | |
185 | '(lambda () | |
186 | (remove-hook 'before-revert-hook | |
187 | 'tramp-flush-file-function) | |
a7580c1c MA |
188 | (remove-hook 'eshell-pre-command-hook |
189 | 'tramp-flush-file-function) | |
00d6fd04 MA |
190 | (remove-hook 'kill-buffer-hook |
191 | 'tramp-flush-file-function))) | |
192 | ||
193 | ;;; -- Properties -- | |
194 | ||
195 | (defun tramp-get-connection-property (key property default) | |
196 | "Get the named PROPERTY for the connection. | |
197 | KEY identifies the connection, it is either a process or a vector. | |
198 | If the value is not set for the connection, returns DEFAULT." | |
199 | ;; Unify key by removing localname from vector. Work with a copy in | |
200 | ;; order to avoid side effects. | |
201 | (when (vectorp key) | |
202 | (setq key (copy-sequence key)) | |
203 | (aset key 3 nil)) | |
204 | (let* ((hash (gethash key tramp-cache-data)) | |
205 | (value (if (hash-table-p hash) | |
afae3a37 MA |
206 | (gethash property hash default) |
207 | default))) | |
00d6fd04 MA |
208 | (tramp-message key 7 "%s %s" property value) |
209 | value)) | |
210 | ||
211 | (defun tramp-set-connection-property (key property value) | |
212 | "Set the named PROPERTY of a connection to VALUE. | |
213 | KEY identifies the connection, it is either a process or a vector. | |
214 | PROPERTY is set persistent when KEY is a vector." | |
215 | ;; Unify key by removing localname from vector. Work with a copy in | |
216 | ;; order to avoid side effects. | |
217 | (when (vectorp key) | |
218 | (setq key (copy-sequence key)) | |
219 | (aset key 3 nil)) | |
220 | (let ((hash (or (gethash key tramp-cache-data) | |
221 | (puthash key (make-hash-table :test 'equal) | |
222 | tramp-cache-data)))) | |
223 | (puthash property value hash) | |
7c3404ec | 224 | (setq tramp-cache-data-changed t) |
00d6fd04 MA |
225 | ;; This function is called also during initialization of |
226 |