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