3 * Copyright (C) 2002 Florin Malita <mali@go.ro>
5 * This file is part of LUFS, a free userspace filesystem implementation.
6 * See http://lufs.sourceforge.net/ for updates.
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.
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.
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
30 #include <lufs/proto.h>
36 static char root_dir[]="/";
37 static char current_dir[]=".";
41 unsigned long res = 0;
44 for(i = 0; i < strlen(name); i++)
46 res = 0x21413 * (res + name[i]);
48 return res % NBUCKETS;
52 delete_dir(struct directory *d){
53 struct list_head *p, *tmp;
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);
74 lu_cache_create(struct list_head *cfg){
75 struct dir_cache *cache;
79 TRACE("creating dir cache...");
81 if(!(cache = malloc(sizeof(struct dir_cache))))
84 memset(cache, 0, sizeof(struct dir_cache));
86 for(i = 0; i < NBUCKETS; i++)
87 INIT_LIST_HEAD(&cache->buckets[i]);
89 pthread_mutex_init(&cache->lock, NULL);
92 if((c = lu_opt_getchar(cfg, "LUFSD", "DirCacheTTL")) && atoi(c))
94 if((c = lu_opt_getchar(cfg, "MOUNT", "dir_cache_ttl")) && atoi(c))
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);
103 TRACE("entries: %d, ttl: %d", cache->entries, cache->ttl);
109 lu_cache_destroy(struct dir_cache *cache){
110 struct list_head *p, *tmp;
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));
122 static struct directory*
123 search(struct dir_cache *cache, char *dir){
124 struct list_head *p, *tmp;
130 TRACE("search %s in bucket %u, size=%u", dir, hsh, cache->lengths[hsh]);
132 list_for_each_safe(p, tmp, &cache->buckets[hsh]){
133 d = list_entry(p, struct directory, d_list);
135 if(time(NULL) - d->d_stamp >= cache->ttl){
136 TRACE("%s expired...", d->d_name);
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);
147 TRACE("dir not found");
152 lu_cache_lookup(struct dir_cache *cache, char *dir, char *file, struct lufs_fattr *fattr, char *link, int buflen){
158 TRACE("looking up %s in dir %s", file, dir);
160 pthread_mutex_lock(&cache->lock);
162 if(!(d = search(cache, dir)))
165 list_for_each(p, &d->d_entries){
166 de = list_entry(p, struct direntry, e_list);
167 if(!strcmp(file, de->e_name)){
170 memcpy(fattr, &de->e_attr, sizeof(struct lufs_fattr));
173 if(snprintf(link, buflen, "%s", de->e_link) >= buflen){
174 WARN("link too long!");
187 TRACE("file not found!");
190 pthread_mutex_unlock(&cache->lock);
195 shrink(struct dir_cache *cache, int hsh){
196 struct directory *dir;
198 TRACE("shrinking bucket %u, len=%u", hsh, cache->lengths[hsh]);
200 if(list_empty(&cache->buckets[hsh]))
203 dir = list_entry(cache->buckets[hsh].prev, struct directory, d_list);
205 TRACE("deleting dir %s", dir->d_name);
208 cache->lengths[hsh]--;
212 check_dir(struct directory *d){
213 struct list_head *p, *tmp;
215 struct lufs_fattr dummy;
216 int dot = 0, dotdot = 0;
218 memset(&dummy, 0, sizeof(struct lufs_fattr));
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);
226 list_for_each_safe(p, tmp, &d->d_entries){
227 e = list_entry(p, struct direntry, e_list);
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);
237 if(!strcmp(e->e_name, "..")){
238 TRACE("'..' entry found");
239 list_del(&e->e_list);
241 list_add(&e->e_list, &d->d_entries);
243 list_add(&e->e_list, d->d_entries.next);
250 lu_cache_add2dir(d, ".", NULL, &dummy);
253 lu_cache_add2dir(d, "..", NULL, &dummy);
255 }while((!dot) || (!dotdot));
260 lu_cache_add_dir(struct dir_cache *cache, struct directory *d){
261 struct directory *dir;
264 hsh = hash(d->d_name);
266 TRACE("adding dir %s to bucket %i", d->d_name, hsh);
270 pthread_mutex_lock(&cache->lock);
272 if((dir = search(cache, d->d_name))){
273 TRACE("directory already in cache, deleting...");
275 cache->lengths[hsh]--;
278 d->d_stamp = time(NULL);
280 list_add(&d->d_list, &cache->buckets[hsh]);
281 cache->lengths[hsh]++;
283 while(cache->lengths[hsh] > cache->entries)
286 pthread_mutex_unlock(&cache->lock);
292 lu_cache_readdir(struct dir_cache *cache, char *dir, int offset, char *buf, int buflen){
297 unsigned len = 0, off = 0;
299 TRACE("reading directory %s", dir);
301 pthread_mutex_lock(&cache->lock);
303 if(!(d = search(cache, dir)))
308 list_for_each(p, &d->d_entries){
310 de = list_entry(p, struct direntry, e_list);
311 slen = strlen(de->e_name);
313 if(len + slen + 2 >= buflen){
314 TRACE("buffer filled up");
318 strcat(buf, de->e_name);
327 d->d_stamp = time(NULL);
332 pthread_mutex_unlock(&cache->lock);
338 lu_cache_lookup_file(struct dir_cache *cache, char *file, struct lufs_fattr *fattr, char *link, int buflen){
343 if(!(sep = strrchr(file, '/'))){
344 WARN("separator not present!");
360 TRACE("dir: %s, file: %s", dir, file);
362 res = lu_cache_lookup(cache, dir, file, fattr, link, buflen);
369 lu_cache_invalidate(struct dir_cache *cache, char *file){
373 if(!(sep = strrchr(file, '/'))){
374 WARN("separator not present!");
385 TRACE("invalidating dir %s", dir);
387 pthread_mutex_lock(&cache->lock);
389 if(!(d = search(cache, dir))){
391 pthread_mutex_unlock(&cache->lock);
397 pthread_mutex_unlock(&cache->lock);
404 lu_cache_mkdir(char *dir){
405 struct directory *res;
407 TRACE("create dir %s", dir);
409 if(!(res = malloc(sizeof(struct directory)))){
414 memset(res, 0, sizeof(struct directory));
416 if(!(res->d_name = malloc(strlen(dir) + 1))){
422 INIT_LIST_HEAD(&res->d_entries);
423 res->d_stamp = time(NULL);
424 strcpy(res->d_name, dir);
430 lu_cache_add2dir(struct directory *d, char *fname, char *link, struct lufs_fattr *fattr){
433 TRACE("adding %s->%s to %s", fname, link, d->d_name);
435 if(!(de = malloc(sizeof(struct direntry))))
439 if(!(de->e_name = malloc(strlen(fname) + 1)))
444 de->e_link = malloc(strlen(link) + 1);
446 de->e_link = malloc(2);
451 memcpy(&de->e_attr, fattr, sizeof(struct lufs_fattr));
452 strcpy(de->e_name, fname);
454 strcpy(de->e_link, link);
456 strcpy(de->e_link, "");
458 list_add_tail(&de->e_list, &d->d_entries);
472 lu_cache_killdir(struct directory *d){
473 struct list_head *p, *tmp;
478 list_for_each_safe(p, tmp, &d->d_entries){
479 de = list_entry(p, struct direntry, e_list);
480 list_del(&de->e_list);