1 2277c5d7 2004-03-21 devnull #include <u.h>
2 2277c5d7 2004-03-21 devnull #include <libc.h>
3 2277c5d7 2004-03-21 devnull #include <fcall.h>
4 2277c5d7 2004-03-21 devnull #include <thread.h>
5 2277c5d7 2004-03-21 devnull #include <9p.h>
8 2277c5d7 2004-03-21 devnull * To avoid deadlock, the following rules must be followed.
9 2277c5d7 2004-03-21 devnull * Always lock child then parent, never parent then child.
10 2277c5d7 2004-03-21 devnull * If holding the free file lock, do not lock any Files.
12 2277c5d7 2004-03-21 devnull struct Filelist {
14 2277c5d7 2004-03-21 devnull Filelist *link;
17 2277c5d7 2004-03-21 devnull static QLock filelk;
18 2277c5d7 2004-03-21 devnull static File *freefilelist;
20 2277c5d7 2004-03-21 devnull static File*
21 2277c5d7 2004-03-21 devnull allocfile(void)
23 2277c5d7 2004-03-21 devnull int i, a;
25 2277c5d7 2004-03-21 devnull enum { N = 16 };
27 2277c5d7 2004-03-21 devnull qlock(&filelk);
28 2277c5d7 2004-03-21 devnull if(freefilelist == nil){
29 2277c5d7 2004-03-21 devnull f = emalloc9p(N*sizeof(*f));
30 2277c5d7 2004-03-21 devnull for(i=0; i<N-1; i++)
31 2277c5d7 2004-03-21 devnull f[i].aux = &f[i+1];
32 2277c5d7 2004-03-21 devnull f[N-1].aux = nil;
33 2277c5d7 2004-03-21 devnull f[0].allocd = 1;
34 2277c5d7 2004-03-21 devnull freefilelist = f;
37 2277c5d7 2004-03-21 devnull f = freefilelist;
38 2277c5d7 2004-03-21 devnull freefilelist = f->aux;
39 2277c5d7 2004-03-21 devnull qunlock(&filelk);
41 2277c5d7 2004-03-21 devnull a = f->allocd;
42 2277c5d7 2004-03-21 devnull memset(f, 0, sizeof *f);
43 2277c5d7 2004-03-21 devnull f->allocd = a;
44 2277c5d7 2004-03-21 devnull return f;
47 2277c5d7 2004-03-21 devnull static void
48 2277c5d7 2004-03-21 devnull freefile(File *f)
50 2277c5d7 2004-03-21 devnull Filelist *fl, *flnext;
52 2277c5d7 2004-03-21 devnull for(fl=f->filelist; fl; fl=flnext){
53 2277c5d7 2004-03-21 devnull flnext = fl->link;
54 2277c5d7 2004-03-21 devnull assert(fl->f == nil);
55 2277c5d7 2004-03-21 devnull free(fl);
58 2277c5d7 2004-03-21 devnull free(f->dir.name);
59 2277c5d7 2004-03-21 devnull free(f->dir.uid);
60 2277c5d7 2004-03-21 devnull free(f->dir.gid);
61 2277c5d7 2004-03-21 devnull free(f->dir.muid);
62 2277c5d7 2004-03-21 devnull qlock(&filelk);
63 2277c5d7 2004-03-21 devnull assert(f->ref.ref == 0);
64 2277c5d7 2004-03-21 devnull f->aux = freefilelist;
65 2277c5d7 2004-03-21 devnull freefilelist = f;
66 2277c5d7 2004-03-21 devnull qunlock(&filelk);
70 2277c5d7 2004-03-21 devnull closefile(File *f)
72 2277c5d7 2004-03-21 devnull if(decref(&f->ref) == 0){
73 2277c5d7 2004-03-21 devnull f->tree->destroy(f);
74 2277c5d7 2004-03-21 devnull freefile(f);
78 2277c5d7 2004-03-21 devnull static void
79 2277c5d7 2004-03-21 devnull nop(File *f)
85 2277c5d7 2004-03-21 devnull removefile(File *f)
87 2277c5d7 2004-03-21 devnull File *fp;
88 2277c5d7 2004-03-21 devnull Filelist *fl;
90 2277c5d7 2004-03-21 devnull fp = f->parent;
91 2277c5d7 2004-03-21 devnull if(fp == nil){
92 2277c5d7 2004-03-21 devnull werrstr("no parent");
93 2277c5d7 2004-03-21 devnull closefile(f);
94 2277c5d7 2004-03-21 devnull return -1;
97 2277c5d7 2004-03-21 devnull if(fp == f){
98 2277c5d7 2004-03-21 devnull werrstr("cannot remove root");
99 2277c5d7 2004-03-21 devnull closefile(f);
100 2277c5d7 2004-03-21 devnull return -1;
103 2277c5d7 2004-03-21 devnull wlock(&fp->rwlock);
104 2277c5d7 2004-03-21 devnull wlock(&f->rwlock);
105 2277c5d7 2004-03-21 devnull if(f->nchild != 0){
106 2277c5d7 2004-03-21 devnull werrstr("has children");
107 2277c5d7 2004-03-21 devnull wunlock(&f->rwlock);
108 2277c5d7 2004-03-21 devnull wunlock(&fp->rwlock);
109 2277c5d7 2004-03-21 devnull closefile(f);
110 2277c5d7 2004-03-21 devnull return -1;
113 2277c5d7 2004-03-21 devnull if(f->parent != fp){
114 2277c5d7 2004-03-21 devnull werrstr("parent changed underfoot");
115 2277c5d7 2004-03-21 devnull wunlock(&f->rwlock);
116 2277c5d7 2004-03-21 devnull wunlock(&fp->rwlock);
117 2277c5d7 2004-03-21 devnull closefile(f);
118 2277c5d7 2004-03-21 devnull return -1;
121 2277c5d7 2004-03-21 devnull for(fl=fp->filelist; fl; fl=fl->link)
122 2277c5d7 2004-03-21 devnull if(fl->f == f)
124 2277c5d7 2004-03-21 devnull assert(fl != nil && fl->f == f);
126 2277c5d7 2004-03-21 devnull fl->f = nil;
127 2277c5d7 2004-03-21 devnull fp->nchild--;
128 2277c5d7 2004-03-21 devnull f->parent = nil;
129 2277c5d7 2004-03-21 devnull wunlock(&fp->rwlock);
130 2277c5d7 2004-03-21 devnull wunlock(&f->rwlock);
132 2277c5d7 2004-03-21 devnull closefile(fp); /* reference from child */
133 2277c5d7 2004-03-21 devnull closefile(f); /* reference from tree */
134 2277c5d7 2004-03-21 devnull closefile(f);
135 2277c5d7 2004-03-21 devnull return 0;
139 2277c5d7 2004-03-21 devnull createfile(File *fp, char *name, char *uid, ulong perm, void *aux)
141 2277c5d7 2004-03-21 devnull File *f;
142 2277c5d7 2004-03-21 devnull Filelist *fl, *freel;
143 2277c5d7 2004-03-21 devnull Tree *t;
145 2277c5d7 2004-03-21 devnull if((fp->dir.qid.type&QTDIR) == 0){
146 2277c5d7 2004-03-21 devnull werrstr("create in non-directory");
147 2277c5d7 2004-03-21 devnull return nil;
150 2277c5d7 2004-03-21 devnull freel = nil;
151 2277c5d7 2004-03-21 devnull wlock(&fp->rwlock);
152 2277c5d7 2004-03-21 devnull for(fl=fp->filelist; fl; fl=fl->link){
153 2277c5d7 2004-03-21 devnull if(fl->f == nil)
154 2277c5d7 2004-03-21 devnull freel = fl;
155 2277c5d7 2004-03-21 devnull else if(strcmp(fl->f->dir.name, name) == 0){
156 2277c5d7 2004-03-21 devnull wunlock(&fp->rwlock);
157 2277c5d7 2004-03-21 devnull werrstr("file already exists");
158 2277c5d7 2004-03-21 devnull return nil;
162 2277c5d7 2004-03-21 devnull if(freel == nil){
163 2277c5d7 2004-03-21 devnull freel = emalloc9p(sizeof *freel);
164 2277c5d7 2004-03-21 devnull freel->link = fp->filelist;
165 2277c5d7 2004-03-21 devnull fp->filelist = freel;
168 2277c5d7 2004-03-21 devnull f = allocfile();
169 2277c5d7 2004-03-21 devnull f->dir.name = estrdup9p(name);
170 2277c5d7 2004-03-21 devnull f->dir.uid = estrdup9p(uid ? uid : fp->dir.uid);
171 2277c5d7 2004-03-21 devnull f->dir.gid = estrdup9p(fp->dir.gid);
172 2277c5d7 2004-03-21 devnull f->dir.muid = estrdup9p(uid ? uid : "unknown");
173 2277c5d7 2004-03-21 devnull f->aux = aux;
174 2277c5d7 2004-03-21 devnull f->dir.mode = perm;
176 2277c5d7 2004-03-21 devnull t = fp->tree;
177 2277c5d7 2004-03-21 devnull lock(&t->genlock);
178 2277c5d7 2004-03-21 devnull f->dir.qid.path = t->qidgen++;
179 2277c5d7 2004-03-21 devnull unlock(&t->genlock);
180 2277c5d7 2004-03-21 devnull if(perm & DMDIR)
181 2277c5d7 2004-03-21 devnull f->dir.qid.type |= QTDIR;
182 2277c5d7 2004-03-21 devnull if(perm & DMAPPEND)
183 2277c5d7 2004-03-21 devnull f->dir.qid.type |= QTAPPEND;
184 2277c5d7 2004-03-21 devnull if(perm & DMEXCL)
185 2277c5d7 2004-03-21 devnull f->dir.qid.type |= QTEXCL;
187 2277c5d7 2004-03-21 devnull f->dir.mode = perm;
188 2277c5d7 2004-03-21 devnull f->dir.atime = f->dir.mtime = time(0);
189 2277c5d7 2004-03-21 devnull f->dir.length = 0;
190 2277c5d7 2004-03-21 devnull f->parent = fp;
191 2277c5d7 2004-03-21 devnull incref(&fp->ref);
192 2277c5d7 2004-03-21 devnull f->tree = fp->tree;
194 2277c5d7 2004-03-21 devnull incref(&f->ref); /* being returned */
195 2277c5d7 2004-03-21 devnull incref(&f->ref); /* for the tree */
196 2277c5d7 2004-03-21 devnull freel->f = f;
197 2277c5d7 2004-03-21 devnull fp->nchild++;
198 2277c5d7 2004-03-21 devnull wunlock(&fp->rwlock);
200 2277c5d7 2004-03-21 devnull return f;
203 2277c5d7 2004-03-21 devnull static File*
204 2277c5d7 2004-03-21 devnull walkfile1(File *dir, char *elem)
206 2277c5d7 2004-03-21 devnull File *fp;
207 2277c5d7 2004-03-21 devnull Filelist *fl;
209 2277c5d7 2004-03-21 devnull rlock(&dir->rwlock);
210 2277c5d7 2004-03-21 devnull if(strcmp(elem, "..") == 0){
211 2277c5d7 2004-03-21 devnull fp = dir->parent;
212 2277c5d7 2004-03-21 devnull incref(&fp->ref);
213 2277c5d7 2004-03-21 devnull runlock(&dir->rwlock);
214 2277c5d7 2004-03-21 devnull closefile(dir);
215 2277c5d7 2004-03-21 devnull return fp;
218 2277c5d7 2004-03-21 devnull fp = nil;
219 2277c5d7 2004-03-21 devnull for(fl=dir->filelist; fl; fl=fl->link)
220 2277c5d7 2004-03-21 devnull if(fl->f && strcmp(fl->f->dir.name, elem)==0){
221 2277c5d7 2004-03-21 devnull fp = fl->f;
222 2277c5d7 2004-03-21 devnull incref(&fp->ref);
226 2277c5d7 2004-03-21 devnull runlock(&dir->rwlock);
227 2277c5d7 2004-03-21 devnull closefile(dir);
228 2277c5d7 2004-03-21 devnull return fp;
232 2277c5d7 2004-03-21 devnull walkfile(File *f, char *path)
234 2277c5d7 2004-03-21 devnull char *os, *s, *nexts;
236 2277c5d7 2004-03-21 devnull if(strchr(path, '/') == nil)
237 2277c5d7 2004-03-21 devnull return walkfile1(f, path); /* avoid malloc */
239 2277c5d7 2004-03-21 devnull os = s = estrdup9p(path);
240 2277c5d7 2004-03-21 devnull for(; *s; s=nexts){
241 2277c5d7 2004-03-21 devnull if(nexts = strchr(s, '/'))
242 2277c5d7 2004-03-21 devnull *nexts++ = '\0';
244 2277c5d7 2004-03-21 devnull nexts = s+strlen(s);
245 729e53b9 2006-10-12 devnull f = walkfile1(f, s);
246 2277c5d7 2004-03-21 devnull if(f == nil)
249 2277c5d7 2004-03-21 devnull free(os);
250 2277c5d7 2004-03-21 devnull return f;
253 a0f1e21f 2004-04-20 devnull static Qid
254 a0f1e21f 2004-04-20 devnull mkqid(vlong path, long vers, int type)
258 a0f1e21f 2004-04-20 devnull q.path = path;
259 a0f1e21f 2004-04-20 devnull q.vers = vers;
260 a0f1e21f 2004-04-20 devnull q.type = type;
261 a0f1e21f 2004-04-20 devnull return q;
266 2277c5d7 2004-03-21 devnull alloctree(char *uid, char *gid, ulong mode, void (*destroy)(File*))
268 2277c5d7 2004-03-21 devnull char *muid;
269 2277c5d7 2004-03-21 devnull Tree *t;
270 2277c5d7 2004-03-21 devnull File *f;
272 2277c5d7 2004-03-21 devnull t = emalloc9p(sizeof *t);
273 2277c5d7 2004-03-21 devnull f = allocfile();
274 2277c5d7 2004-03-21 devnull f->dir.name = estrdup9p("/");
275 2277c5d7 2004-03-21 devnull if(uid == nil){
276 2277c5d7 2004-03-21 devnull if(uid = getuser())
277 2277c5d7 2004-03-21 devnull uid = estrdup9p(uid);
279 2277c5d7 2004-03-21 devnull if(uid == nil)
280 2277c5d7 2004-03-21 devnull uid = estrdup9p("none");
282 2277c5d7 2004-03-21 devnull uid = estrdup9p(uid);
284 2277c5d7 2004-03-21 devnull if(gid == nil)
285 2277c5d7 2004-03-21 devnull gid = estrdup9p(uid);
287 2277c5d7 2004-03-21 devnull gid = estrdup9p(gid);
289 2277c5d7 2004-03-21 devnull muid = estrdup9p(uid);
291 a0f1e21f 2004-04-20 devnull f->dir.qid = mkqid(0, 0, QTDIR);
292 2277c5d7 2004-03-21 devnull f->dir.length = 0;
293 2277c5d7 2004-03-21 devnull f->dir.atime = f->dir.mtime = time(0);
294 2277c5d7 2004-03-21 devnull f->dir.mode = DMDIR | mode;
295 2277c5d7 2004-03-21 devnull f->tree = t;
296 2277c5d7 2004-03-21 devnull f->parent = f;
297 2277c5d7 2004-03-21 devnull f->dir.uid = uid;
298 2277c5d7 2004-03-21 devnull f->dir.gid = gid;
299 2277c5d7 2004-03-21 devnull f->dir.muid = muid;
301 2277c5d7 2004-03-21 devnull incref(&f->ref);
302 2277c5d7 2004-03-21 devnull t->root = f;
303 2277c5d7 2004-03-21 devnull t->qidgen = 0;
304 2277c5d7 2004-03-21 devnull t->dirqidgen = 1;
305 2277c5d7 2004-03-21 devnull if(destroy == nil)
306 2277c5d7 2004-03-21 devnull destroy = nop;
307 2277c5d7 2004-03-21 devnull t->destroy = destroy;
309 2277c5d7 2004-03-21 devnull return t;
312 2277c5d7 2004-03-21 devnull static void
313 2277c5d7 2004-03-21 devnull _freefiles(File *f)
315 2277c5d7 2004-03-21 devnull Filelist *fl, *flnext;
317 2277c5d7 2004-03-21 devnull for(fl=f->filelist; fl; fl=flnext){
318 2277c5d7 2004-03-21 devnull flnext = fl->link;
319 2277c5d7 2004-03-21 devnull _freefiles(fl->f);
320 2277c5d7 2004-03-21 devnull free(fl);
323 2277c5d7 2004-03-21 devnull f->tree->destroy(f);
324 2277c5d7 2004-03-21 devnull freefile(f);
328 2277c5d7 2004-03-21 devnull freetree(Tree *t)
330 2277c5d7 2004-03-21 devnull _freefiles(t->root);
331 2277c5d7 2004-03-21 devnull free(t);
334 2277c5d7 2004-03-21 devnull struct Readdir {
335 2277c5d7 2004-03-21 devnull Filelist *fl;
338 2277c5d7 2004-03-21 devnull Readdir*
339 2277c5d7 2004-03-21 devnull opendirfile(File *dir)
341 2277c5d7 2004-03-21 devnull Readdir *r;
343 2277c5d7 2004-03-21 devnull rlock(&dir->rwlock);
344 2277c5d7 2004-03-21 devnull if((dir->dir.mode & DMDIR)==0){
345 2277c5d7 2004-03-21 devnull runlock(&dir->rwlock);
346 2277c5d7 2004-03-21 devnull return nil;
348 2277c5d7 2004-03-21 devnull r = emalloc9p(sizeof(*r));
351 2277c5d7 2004-03-21 devnull * This reference won't go away while we're using it
352 2277c5d7 2004-03-21 devnull * since we are dir->rdir.
354 2277c5d7 2004-03-21 devnull r->fl = dir->filelist;
355 2277c5d7 2004-03-21 devnull runlock(&dir->rwlock);
356 2277c5d7 2004-03-21 devnull return r;
360 2277c5d7 2004-03-21 devnull readdirfile(Readdir *r, uchar *buf, long n)
362 2277c5d7 2004-03-21 devnull long x, m;
363 2277c5d7 2004-03-21 devnull Filelist *fl;
365 2277c5d7 2004-03-21 devnull for(fl=r->fl, m=0; fl && m+2<=n; fl=fl->link, m+=x){
366 2277c5d7 2004-03-21 devnull if(fl->f == nil)
368 2277c5d7 2004-03-21 devnull else if((x=convD2M(&fl->f->dir, buf+m, n-m)) <= BIT16SZ)
371 2277c5d7 2004-03-21 devnull r->fl = fl;
372 2277c5d7 2004-03-21 devnull return m;
376 2277c5d7 2004-03-21 devnull closedirfile(Readdir *r)
378 2277c5d7 2004-03-21 devnull free(r);