/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

1 dpavlin 4 /*
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