Added enhancements from Sergei which he attached to #241.
[midnight-commander.git] / vfs / gc.c
blob8da894618a46f5ffc1aa9a8b6260f94d4b4d0620
1 /* Virtual File System garbage collection code
2 Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
4 Written by: 1995 Miguel de Icaza
5 1995 Jakub Jelinek
6 1998 Pavel Machek
7 2003 Pavel Roskin
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public License
11 as published by the Free Software Foundation; either version 2 of
12 the License, or (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU Library General Public License for more details.
19 You should have received a copy of the GNU Library General Public
20 License along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
23 #include <config.h>
25 #include <stdio.h>
26 #include <stdlib.h> /* For atol() */
27 #include <stdarg.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <sys/types.h>
31 #include <signal.h>
32 #include <ctype.h> /* is_digit() */
34 #include <mhl/string.h>
36 #include "../src/global.h"
37 #include "../src/tty.h" /* enable/disable interrupt key */
38 #include "../src/wtools.h" /* message() */
39 #include "../src/main.h" /* print_vfs_message */
40 #include "utilvfs.h"
41 #include "vfs-impl.h"
42 #include "gc.h"
43 #include "vfs.h"
45 #include "../src/panel.h" /* get_current_panel() */
46 #include "../src/layout.h" /* get_current_type() */
49 int vfs_timeout = 60; /* VFS timeout in seconds */
51 static struct vfs_stamping *stamps;
54 static void
55 vfs_addstamp (struct vfs_class *v, vfsid id)
57 if (!(v->flags & VFSF_LOCAL) && id != NULL) {
58 struct vfs_stamping *stamp;
59 struct vfs_stamping *last_stamp = NULL;
61 for (stamp = stamps; stamp != NULL; stamp = stamp->next) {
62 if (stamp->v == v && stamp->id == id) {
63 gettimeofday (&(stamp->time), NULL);
64 return;
66 last_stamp = stamp;
68 stamp = g_new (struct vfs_stamping, 1);
69 stamp->v = v;
70 stamp->id = id;
72 gettimeofday (&(stamp->time), NULL);
73 stamp->next = 0;
75 if (stamps) {
76 /* Add to the end */
77 last_stamp->next = stamp;
78 } else {
79 /* Add first element */
80 stamps = stamp;
86 void
87 vfs_stamp (struct vfs_class *v, vfsid id)
89 struct vfs_stamping *stamp;
91 for (stamp = stamps; stamp != NULL; stamp = stamp->next)
92 if (stamp->v == v && stamp->id == id) {
93 gettimeofday (&(stamp->time), NULL);
94 return;
99 void
100 vfs_rmstamp (struct vfs_class *v, vfsid id)
102 struct vfs_stamping *stamp, *st1;
104 for (stamp = stamps, st1 = NULL; stamp != NULL;
105 st1 = stamp, stamp = stamp->next)
106 if (stamp->v == v && stamp->id == id) {
107 if (st1 == NULL) {
108 stamps = stamp->next;
109 } else {
110 st1->next = stamp->next;
112 g_free (stamp);
114 return;
119 /* Find VFS id for given directory name */
120 vfsid
121 vfs_getid (struct vfs_class *vclass, const char *dir)
123 char *dir1;
124 vfsid id = NULL;
126 /* append slash if needed */
127 dir1 = mhl_str_dir_plus_file (dir, "");
128 if (vclass->getid)
129 id = (*vclass->getid) (vclass, dir1);
131 g_free (dir1);
132 return id;
136 static void
137 vfs_stamp_path (char *path)
139 struct vfs_class *vfs;
140 vfsid id;
142 vfs = vfs_get_class (path);
143 id = vfs_getid (vfs, path);
144 vfs_addstamp (vfs, id);
149 * Create a new timestamp item by VFS class and VFS id.
151 void
152 vfs_stamp_create (struct vfs_class *oldvfs, vfsid oldvfsid)
154 struct vfs_class *nvfs, *n2vfs, *n3vfs;
155 vfsid nvfsid, n2vfsid, n3vfsid;
157 /* There are three directories we have to take care of: current_dir,
158 current_panel->cwd and other_panel->cwd. Athough most of the time either
159 current_dir and current_panel->cwd or current_dir and other_panel->cwd are the
160 same, it's possible that all three are different -- Norbert */
162 if (!current_panel)
163 return;
165 nvfs = vfs_get_class (vfs_get_current_dir ());
166 nvfsid = vfs_getid (nvfs, vfs_get_current_dir ());
167 vfs_rmstamp (nvfs, nvfsid);
169 if ((nvfs == oldvfs && nvfsid == oldvfsid) || oldvfsid == NULL) {
170 return;
173 if (get_current_type () == view_listing) {
174 n2vfs = vfs_get_class (current_panel->cwd);
175 n2vfsid = vfs_getid (n2vfs, current_panel->cwd);
176 if (n2vfs == oldvfs && n2vfsid == oldvfsid)
177 return;
178 } else {
179 n2vfs = NULL;
180 n2vfsid = NULL;
183 if (get_other_type () == view_listing) {
184 n3vfs = vfs_get_class (other_panel->cwd);
185 n3vfsid = vfs_getid (n3vfs, other_panel->cwd);
186 if (n3vfs == oldvfs && n3vfsid == oldvfsid)
187 return;
188 } else {
189 n3vfs = NULL;
190 n3vfsid = NULL;
193 if (!oldvfs->nothingisopen || !(*oldvfs->nothingisopen) (oldvfsid))
194 return;
196 vfs_addstamp (oldvfs, oldvfsid);
200 void
201 vfs_add_current_stamps (void)
203 vfs_stamp_path (vfs_get_current_dir ());
205 if (current_panel) {
206 if (get_current_type () == view_listing)
207 vfs_stamp_path (current_panel->cwd);
210 if (other_panel) {
211 if (get_other_type () == view_listing)
212 vfs_stamp_path (other_panel->cwd);
217 /* Compare two timeval structures. Return 0 is t1 is less than t2. */
218 static inline int
219 timeoutcmp (struct timeval *t1, struct timeval *t2)
221 return ((t1->tv_sec < t2->tv_sec)
222 || ((t1->tv_sec == t2->tv_sec)
223 && (t1->tv_usec <= t2->tv_usec)));
227 /* This is called from timeout handler with now = 0, or can be called
228 with now = 1 to force freeing all filesystems that are not in use */
229 void
230 vfs_expire (int now)
232 static int locked = 0;
233 struct timeval time;
234 struct vfs_stamping *stamp, *st;
236 /* Avoid recursive invocation, e.g. when one of the free functions
237 calls message */
238 if (locked)
239 return;
240 locked = 1;
242 gettimeofday (&time, NULL);
243 time.tv_sec -= vfs_timeout;
245 for (stamp = stamps; stamp != NULL;) {
246 if (now || (timeoutcmp (&stamp->time, &time))) {
247 st = stamp->next;
248 if (stamp->v->free)
249 (*stamp->v->free) (stamp->id);
250 vfs_rmstamp (stamp->v, stamp->id);
251 stamp = st;
252 } else
253 stamp = stamp->next;
255 locked = 0;
260 * Return the number of seconds remaining to the vfs timeout.
261 * FIXME: The code should be improved to actually return the number of
262 * seconds until the next item times out.
265 vfs_timeouts ()
267 return stamps ? 10 : 0;
271 void
272 vfs_timeout_handler (void)
274 vfs_expire (0);
278 void
279 vfs_release_path (const char *dir)
281 struct vfs_class *oldvfs;
282 vfsid oldvfsid;
284 oldvfs = vfs_get_class (dir);
285 oldvfsid = vfs_getid (oldvfs, dir);
286 vfs_stamp_create (oldvfs, oldvfsid);
290 /* Free all data */
291 void
292 vfs_gc_done (void)
294 struct vfs_stamping *stamp, *st;
296 for (stamp = stamps, stamps = 0; stamp != NULL;) {
297 if (stamp->v->free)
298 (*stamp->v->free) (stamp->id);
299 st = stamp->next;
300 g_free (stamp);
301 stamp = st;
304 if (stamps)
305 vfs_rmstamp (stamps->v, stamps->id);