/[fuse_dbi]/fuse/cvs/lufis/dircache.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /fuse/cvs/lufis/dircache.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (show annotations)
Wed Aug 4 11:36:44 2004 UTC (19 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 9922 byte(s)
import current CVS of fuse

1 /*
2 * dircache.c
3 * Copyright (C) 2002 Florin Malita <mali@go.ro>
4 *
5 * This file is part of LUFS, a free userspace filesystem implementation.
6 * See http://lufs.sourceforge.net/ for updates.
7 *
8 * LUFS is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * LUFS is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <pthread.h>
27
28 #include <sys/stat.h>
29
30 #include <lufs/proto.h>
31 #include <lufs/fs.h>
32
33 #include "list.h"
34 #include "dircache.h"
35
36 static char root_dir[]="/";
37 static char current_dir[]=".";
38
39 static unsigned long
40 hash(char *name){
41 unsigned long res = 0;
42 unsigned int i;
43
44 for(i = 0; i < strlen(name); i++)
45 if(name[i] != '/')
46 res = 0x21413 * (res + name[i]);
47
48 return res % NBUCKETS;
49 }
50
51 static void
52 delete_dir(struct directory *d){
53 struct list_head *p, *tmp;
54 struct direntry *de;
55
56 TRACE("in");
57 list_for_each_safe(p, tmp, &d->d_entries){
58 de = list_entry(p, struct direntry, e_list);
59 list_del(&de->e_list);
60 free(de->e_name);
61 if(de->e_link)
62 free(de->e_link);
63 free(de);
64 }
65
66 list_del(&d->d_list);
67 free(d->d_name);
68 free(d);
69
70 TRACE("out");
71 }
72
73 struct dir_cache*
74 lu_cache_create(struct list_head *cfg){
75 struct dir_cache *cache;
76 int i;
77 const char *c;
78
79 TRACE("creating dir cache...");
80
81 if(!(cache = malloc(sizeof(struct dir_cache))))
82 return NULL;
83
84 memset(cache, 0, sizeof(struct dir_cache));
85
86 for(i = 0; i < NBUCKETS; i++)
87 INIT_LIST_HEAD(&cache->buckets[i]);
88
89 pthread_mutex_init(&cache->lock, NULL);
90
91 cache->ttl = DEF_TTL;
92 if((c = lu_opt_getchar(cfg, "LUFSD", "DirCacheTTL")) && atoi(c))
93 cache->ttl = atoi(c);
94 if((c = lu_opt_getchar(cfg, "MOUNT", "dir_cache_ttl")) && atoi(c))
95 cache->ttl = atoi(c);
96
97 cache->entries = DEF_NENTRIES;
98 if((c = lu_opt_getchar(cfg, "LUFSD", "DirCacheEntries")) && atoi(c))
99 cache->entries = atoi(c);
100 if((c = lu_opt_getchar(cfg, "MOUNT", "dir_cache_entries")) && atoi(c))
101 cache->entries = atoi(c);
102
103 TRACE("entries: %d, ttl: %d", cache->entries, cache->ttl);
104
105 return cache;
106 }
107
108 void
109 lu_cache_destroy(struct dir_cache *cache){
110 struct list_head *p, *tmp;
111 int i;
112
113 for(i = 0; i < NBUCKETS; i++){
114 list_for_each_safe(p, tmp, &cache->buckets[i]){
115 delete_dir(list_entry(p, struct directory, d_list));
116 }
117 }
118
119 free(cache);
120 }
121
122 static struct directory*
123 search(struct dir_cache *cache, char *dir){
124 struct list_head *p, *tmp;
125 struct directory *d;
126 int hsh;
127
128 hsh = hash(dir);
129
130 TRACE("search %s in bucket %u, size=%u", dir, hsh, cache->lengths[hsh]);
131
132 list_for_each_safe(p, tmp, &cache->buckets[hsh]){
133 d = list_entry(p, struct directory, d_list);
134
135 if(time(NULL) - d->d_stamp >= (unsigned long) cache->ttl){
136 TRACE("%s expired...", d->d_name);
137 delete_dir(d);
138 cache->lengths[hsh]--;
139 TRACE("directory deleted");
140 }else if(!strcmp(dir, d->d_name)){
141 TRACE("%s found", dir);
142 d->d_stamp = time(NULL);
143 return d;
144 }
145 }
146
147 TRACE("dir not found");
148 return NULL;
149 }
150
151 int
152 lu_cache_lookup(struct dir_cache *cache, char *dir, char *file, struct lufs_fattr *fattr, char *link, int buflen){
153 struct directory *d;
154 struct direntry *de;
155 struct list_head *p;
156 int res = -1;
157
158 TRACE("looking up %s in dir %s", file, dir);
159
160 pthread_mutex_lock(&cache->lock);
161
162 if(!(d = search(cache, dir)))
163 goto out;
164
165 list_for_each(p, &d->d_entries){
166 de = list_entry(p, struct direntry, e_list);
167 if(!strcmp(file, de->e_name)){
168 TRACE("file found");
169
170 memcpy(fattr, &de->e_attr, sizeof(struct lufs_fattr));
171 if(link){
172 if(de->e_link){
173 if(snprintf(link, buflen, "%s", de->e_link) >= buflen){
174 WARN("link too long!");
175 link[buflen - 1] =0;
176 }
177 }else{
178 link[0] = 0;
179 }
180 }
181
182 res = 0;
183 goto out;
184 }
185 }
186
187 TRACE("file not found!");
188
189 out:
190 pthread_mutex_unlock(&cache->lock);
191 return res;
192 }
193
194 static void
195 shrink(struct dir_cache *cache, int hsh){
196 struct directory *dir;
197
198 TRACE("shrinking bucket %u, len=%u", hsh, cache->lengths[hsh]);
199
200 if(list_empty(&cache->buckets[hsh]))
201 return;
202
203 dir = list_entry(cache->buckets[hsh].prev, struct directory, d_list);
204
205 TRACE("deleting dir %s", dir->d_name);
206
207 delete_dir(dir);
208 cache->lengths[hsh]--;
209 }
210
211 static void
212 check_dir(struct directory *d){
213 struct list_head *p, *tmp;
214 struct direntry *e;
215 struct lufs_fattr dummy;
216 int dot = 0, dotdot = 0;
217
218 memset(&dummy, 0, sizeof(struct lufs_fattr));
219 dummy.f_nlink = 1;
220 dummy.f_uid = dummy.f_gid = 1;
221 dummy.f_mode = S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP;
222 dummy.f_mtime = dummy.f_atime = dummy.f_ctime = time(NULL);
223 dummy.f_size = 512;
224
225 do{
226 list_for_each_safe(p, tmp, &d->d_entries){
227 e = list_entry(p, struct direntry, e_list);
228
229 if(!strcmp(e->e_name, ".")){
230 TRACE("'.' entry found");
231 list_del(&e->e_list);
232 list_add(&e->e_list, &d->d_entries);
233 dot = 1;
234 continue;
235 }
236
237 if(!strcmp(e->e_name, "..")){
238 TRACE("'..' entry found");
239 list_del(&e->e_list);
240 if(!dot)
241 list_add(&e->e_list, &d->d_entries);
242 else
243 list_add(&e->e_list, d->d_entries.next);
244
245 dotdot = 1;
246 }
247 }
248
249 if(!dot)
250 lu_cache_add2dir(d, ".", NULL, &dummy);
251
252 if(!dotdot)
253 lu_cache_add2dir(d, "..", NULL, &dummy);
254
255 }while((!dot) || (!dotdot));
256
257 }
258
259 void
260 lu_cache_add_dir(struct dir_cache *cache, struct directory *d){
261 struct directory *dir;
262 int hsh;
263
264 hsh = hash(d->d_name);
265
266 TRACE("adding dir %s to bucket %i", d->d_name, hsh);
267
268 check_dir(d);
269
270 pthread_mutex_lock(&cache->lock);
271
272 if((dir = search(cache, d->d_name))){
273 TRACE("directory already in cache, deleting...");
274 delete_dir(dir);
275 cache->lengths[hsh]--;
276 }
277
278 d->d_stamp = time(NULL);
279
280 list_add(&d->d_list, &cache->buckets[hsh]);
281 cache->lengths[hsh]++;
282
283 while(cache->lengths[hsh] > cache->entries)
284 shrink(cache, hsh);
285
286 pthread_mutex_unlock(&cache->lock);
287
288 TRACE("out");
289 }
290
291 int lu_cache_readdir(struct dir_cache *cache, char *dir,
292 fuse_dirh_t h, fuse_dirfil_t filler)
293 {
294 struct directory *d;
295 struct direntry *de;
296 struct list_head *p;
297 int res = -1;
298
299 TRACE("reading directory %s", dir);
300
301 pthread_mutex_lock(&cache->lock);
302
303 if(!(d = search(cache, dir)))
304 goto out;
305
306 list_for_each(p, &d->d_entries){
307 de = list_entry(p, struct direntry, e_list);
308 filler(h, de->e_name, 0);
309 }
310
311 d->d_stamp = time(NULL);
312
313 res = 0;
314
315 out:
316 pthread_mutex_unlock(&cache->lock);
317 TRACE("out");
318 return res;
319 }
320
321 int
322 lu_cache_lookup_file(struct dir_cache *cache, char *file, struct lufs_fattr *fattr, char *link, int buflen){
323 int res;
324
325 char *sep, *dir;
326
327 if(!(sep = strrchr(file, '/'))){
328 WARN("separator not present!");
329 return -1;
330 }
331
332 *sep = 0;
333
334 if(sep == file)
335 dir = root_dir;
336 else
337 dir = file;
338
339 if(*(sep+1))
340 file = sep + 1;
341 else
342 file = current_dir;
343
344 TRACE("dir: %s, file: %s", dir, file);
345
346 res = lu_cache_lookup(cache, dir, file, fattr, link, buflen);
347 *sep = '/';
348
349 return res;
350 }
351
352 int
353 lu_cache_invalidate(struct dir_cache *cache, char *file){
354 struct directory *d;
355 char *sep, *dir;
356
357 if(!(sep = strrchr(file, '/'))){
358 WARN("separator not present!");
359 return -1;
360 }
361
362 *sep = 0;
363
364 if(sep == file)
365 dir = root_dir;
366 else
367 dir = file;
368
369 TRACE("invalidating dir %s", dir);
370
371 pthread_mutex_lock(&cache->lock);
372
373 if(!(d = search(cache, dir))){
374 *sep = '/';
375 pthread_mutex_unlock(&cache->lock);
376 return -1;
377 }
378
379 d->d_stamp = 0;
380
381 pthread_mutex_unlock(&cache->lock);
382 *sep = '/';
383
384 return 0;
385 }
386
387 struct directory*
388 lu_cache_mkdir(char *dir){
389 struct directory *res;
390
391 TRACE("create dir %s", dir);
392
393 if(!(res = malloc(sizeof(struct directory)))){
394 WARN("out of mem!");
395 return NULL;
396 }
397
398 memset(res, 0, sizeof(struct directory));
399
400 if(!(res->d_name = malloc(strlen(dir) + 1))){
401 WARN("out of mem!");
402 free(res);
403 return NULL;
404 }
405
406 INIT_LIST_HEAD(&res->d_entries);
407 res->d_stamp = time(NULL);
408 strcpy(res->d_name, dir);
409
410 return res;
411 }
412
413 int
414 lu_cache_add2dir(struct directory *d, char *fname, char *link, struct lufs_fattr *fattr){
415 struct direntry *de;
416
417 TRACE("adding %s->%s to %s", fname, link, d->d_name);
418
419 if(!(de = malloc(sizeof(struct direntry))))
420 goto fail;
421
422
423 if(!(de->e_name = malloc(strlen(fname) + 1)))
424 goto fail_de;
425
426
427 if(link)
428 de->e_link = malloc(strlen(link) + 1);
429 else
430 de->e_link = malloc(2);
431
432 if(!de->e_link)
433 goto fail_ename;
434
435 memcpy(&de->e_attr, fattr, sizeof(struct lufs_fattr));
436 strcpy(de->e_name, fname);
437 if(link)
438 strcpy(de->e_link, link);
439 else
440 strcpy(de->e_link, "");
441
442 list_add_tail(&de->e_list, &d->d_entries);
443
444 return 0;
445
446 fail_ename:
447 free(de->e_name);
448 fail_de:
449 free(de);
450 fail:
451 WARN("out of mem!");
452 return -1;
453 }
454
455 void
456 lu_cache_killdir(struct directory *d){
457 struct list_head *p, *tmp;
458 struct direntry *de;
459
460 TRACE("in");
461
462 list_for_each_safe(p, tmp, &d->d_entries){
463 de = list_entry(p, struct direntry, e_list);
464 list_del(&de->e_list);
465 free(de->e_name);
466 if(de->e_link)
467 free(de->e_link);
468 free(de);
469 }
470
471 free(d->d_name);
472 free(d);
473
474 }

  ViewVC Help
Powered by ViewVC 1.1.26