http://prdownloads.sourceforge.net/lufs/lufs-0.9.6.tar.gz?download
[lufs.git] / filesystems / gnetfs / vtree.c
1 #include <unistd.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <time.h>
5
6 #include <sys/types.h>
7
8 #include <lufs/proto.h>
9 #include <lufs/fs.h>
10
11 #include "list.h"
12 #include "vtree.h"
13
14
15 struct vtree*
16 lu_vtree_create(struct lufs_fattr *root_fattr){
17     struct vtree *vt;
18
19     TRACE("creating vtree...");
20
21     if(!(vt = malloc(sizeof(struct vtree))))
22         return NULL;
23
24     memset(vt, 0, sizeof(struct vtree));
25
26     INIT_LIST_HEAD(&vt->root.children);
27     memcpy(&vt->root.fattr, root_fattr, sizeof(struct lufs_fattr));
28     
29     vt->root.vtree = vt;
30     vt->root.name = "/";
31
32     vt->root.stamp = time(NULL);
33     
34     return vt;
35 }
36
37 void
38 lu_vtree_delete(struct ventry *ve){
39     struct list_head *p, *tmp;
40
41     list_for_each_safe(p, tmp, &ve->children)
42         lu_vtree_delete(list_entry(p, struct ventry, list));
43
44     TRACE("deleting %s", ve->name);
45
46     ve->vtree->entries--;
47     list_del(&ve->list);
48
49     free(ve->name);
50     if(ve->link)
51         free(ve->link);
52
53     free(ve);
54 }
55
56 void
57 lu_vtree_destroy(struct vtree *vt){
58     struct list_head *p, *tmp;
59
60     TRACE("deleting tree");
61
62     list_for_each_safe(p, tmp, &vt->root.children)
63         lu_vtree_delete(list_entry(p, struct ventry, list));
64
65     free(vt);
66 }
67
68 struct ventry*
69 lu_vtree_search(struct ventry *ve, char *name){
70     struct list_head *p;    
71     char *sep;
72
73     TRACE("searching for %s in %s", name, ve->name);
74     
75     do{
76         if((sep = strchr(name, '/'))){
77             *sep = 0;
78         }
79
80         TRACE("scanning for %s in %s", name, ve->name);
81
82         list_for_each(p, &ve->children){
83             if(!strcmp(name, list_entry(p, struct ventry, list)->name)){
84                 TRACE("portion found: %s", list_entry(p, struct ventry, list)->name);
85                 ve = list_entry(p, struct ventry, list);
86                 break;
87             }
88         }
89
90         if(strcmp(name, ve->name)){
91             TRACE("portion not found");
92             return NULL;
93         }
94
95         if(sep)
96             *sep = '/';
97
98         name = sep + 1;
99
100     }while(sep);
101
102     TRACE("entry found");
103
104     return ve;
105 }
106
107 struct ventry*
108 lu_vtree_find(struct vtree *vt, char *entry){
109
110     TRACE("entry: %s", entry);
111
112     if(*entry != '/'){
113         TRACE("entry is not an absolute path");
114         return NULL;
115     }
116
117     if(!strcmp(entry, "/"))
118         return &vt->root;
119     
120     return lu_vtree_search(&vt->root, entry + 1);
121 }
122
123 int
124 lu_vtree_add(struct vtree *vt, char *dir, char *name, char *link, struct lufs_fattr *fattr, void *private){
125     struct ventry *ve, *new;
126
127     TRACE("add %s to %s", name, dir);
128
129     if(!(ve = lu_vtree_find(vt, dir)))
130         return -1;
131
132     if(!(new = lu_vtree_search(ve, name))){
133         TRACE("allocating new entry");
134
135         if(!(new = malloc(sizeof(struct ventry))))
136             return -1;
137
138         memset(new, 0, sizeof(struct ventry));
139         
140         INIT_LIST_HEAD(&new->children);
141         new->vtree = vt;
142
143         vt->entries++;
144         list_add_tail(&new->list, &ve->children);
145     }else{
146         TRACE("emtry already in tree");
147
148         free(new->name);
149         if(new->link)
150             free(new->link);
151     }
152
153     if(!(new->name = malloc(strlen(name) + 1)))
154         goto fail_entry;
155
156     if(link && !(new->link = malloc(strlen(link) + 1)))
157         goto fail_name;
158
159     strcpy(new->name, name);
160     if(link)
161         strcpy(new->link, link);
162     
163     memcpy(&new->fattr, fattr, sizeof(struct lufs_fattr));
164
165     new->private = private;
166     new->stamp = time(NULL);
167
168     return 0;
169
170   fail_name:
171     free(new->name);
172   fail_entry:
173     vt->entries--;
174     list_del(&new->list);
175     free(new);
176     return -1;
177 }
178
179 int
180 lu_vtree_lookup(struct vtree *vt, char *file, struct lufs_fattr *fattr, char *link, int buflen, void **private){
181     struct ventry *ve;
182
183     TRACE("looking up %s", file);
184
185     if(*file != '/'){
186         TRACE("we need an absolute path here...");
187         return -1;
188     }
189
190     if(!strcmp(file, "/"))
191         ve = &vt->root;
192     else 
193         if(!(ve = lu_vtree_search(&vt->root, file + 1)))
194             return -1;
195     
196     TRACE("file found");
197
198     memcpy(fattr, &ve->fattr, sizeof(struct lufs_fattr));
199     if(link){
200         if(ve->link){
201             if(snprintf(link, buflen, "%s", ve->link) >= buflen){
202                 WARN("link too long!");
203                 link[buflen - 1] = 0;
204             }
205         }else{
206             link[0] = 0;
207         }
208     }
209
210     if(private)
211         *private = ve->private;
212     
213     return 0;
214 }
215
216 int
217 lu_vtree_readdir(struct vtree *vt, char *dir, int offset, char *buf, int buflen){
218     struct ventry *ve, *e;
219     struct list_head *p;
220     unsigned slen, off = 0, len = 0;
221
222     TRACE("reading directory %s", dir);
223
224     if(*dir != '/'){
225         TRACE("we need an absolute path here...");
226         return -1;
227     }
228
229     if(!strcmp(dir, "/"))
230         ve = &vt->root;
231     else 
232         if(!(ve = lu_vtree_search(&vt->root, dir + 1)))
233             return -1;
234
235     TRACE("directory found");
236
237     buf[0] = 0;
238
239     list_for_each(p, &ve->children){
240         if(off >= offset){
241             e = list_entry(p, struct ventry, list);
242             slen = strlen(e->name);
243
244             if(len + slen + 2 >= buflen){
245                 TRACE("buffer filled up");
246                 break;
247             }
248
249             strcat(buf, e->name);
250             strcat(buf, "\n");
251
252             len += slen + 1;
253         }
254
255         off++;
256     }
257
258     return len;
259 }
260