]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/9660srv/xfile.c
make error handling in 9p service loops consistent
[plan9front.git] / sys / src / cmd / 9660srv / xfile.c
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include "dat.h"
6 #include "fns.h"
7
8 static Xfile*   clean(Xfile*);
9
10 #define FIDMOD  127     /* prime */
11
12 static Xdata*   xhead;
13 static Xfile*   xfiles[FIDMOD];
14 static Xfile*   freelist;
15
16 Xdata*
17 getxdata(char *name)
18 {
19         int fd;
20         Dir *dir;
21         Xdata *xf, *fxf;
22         int flag;
23
24         if(name[0] == 0)
25                 name = deffile;
26         if(name == 0)
27                 error(Enofile);
28         flag = (access(name, 6) == 0) ? ORDWR : OREAD;
29         fd = open(name, flag);
30         if(fd < 0)
31                 error(Enonexist);
32         dir = nil;
33         if(waserror()){
34                 close(fd);
35                 free(dir);
36                 nexterror();
37         }
38         if((dir = dirfstat(fd)) == nil)
39                 error("I/O error");
40         if((dir->qid.type & ~QTTMP) != QTFILE)
41                 error("attach name not a plain file");
42         for(fxf=0,xf=xhead; xf; xf=xf->next){
43                 if(xf->name == 0){
44                         if(fxf == 0)
45                                 fxf = xf;
46                         continue;
47                 }
48                 if(xf->qid.path != dir->qid.path || xf->qid.vers != dir->qid.vers)
49                         continue;
50                 if(xf->type != dir->type || xf->fdev != dir->dev)
51                         continue;
52                 xf->ref++;
53                 chat("incref=%d, \"%s\", dev=%d...", xf->ref, xf->name, xf->dev);
54                 close(fd);
55                 poperror();
56                 free(dir);
57                 return xf;
58         }
59         if(fxf==0){
60                 fxf = ealloc(sizeof(Xfs));
61                 fxf->next = xhead;
62                 xhead = fxf;
63         }
64         chat("alloc \"%s\", dev=%d...", name, fd);
65         fxf->ref = 1;
66         fxf->name = strcpy(ealloc(strlen(name)+1), name);
67         fxf->qid = dir->qid;
68         fxf->type = dir->type;
69         fxf->fdev = dir->dev;
70         fxf->dev = fd;
71         free(dir);
72         poperror();
73         return fxf;
74 }
75
76 static void
77 putxdata(Xdata *d)
78 {
79         if(d->ref <= 0)
80                 panic(0, "putxdata");
81         d->ref--;
82         chat("decref=%d, \"%s\", dev=%d...", d->ref, d->name, d->dev);
83         if(d->ref == 0){
84                 chat("purgebuf...");
85                 purgebuf(d);
86                 close(d->dev);
87                 free(d->name);
88                 d->name = 0;
89         }
90 }
91
92 void
93 refxfs(Xfs *xf, int delta)
94 {
95         xf->ref += delta;
96         if(xf->ref == 0){
97                 if(xf->d)
98                         putxdata(xf->d);
99                 if(xf->ptr)
100                         free(xf->ptr);
101                 free(xf);
102         }
103 }
104
105 Xfile*
106 xfile(int fid, int flag)
107 {
108         int k = fid%FIDMOD;
109         Xfile **hp=&xfiles[k], *f, *pf;
110
111         for(f=*hp,pf=0; f; pf=f,f=f->next)
112                 if(f->fid == fid)
113                         break;
114         if(f && pf){
115                 pf->next = f->next;
116                 f->next = *hp;
117                 *hp = f;
118         }
119         switch(flag){
120         default:
121                 panic(0, "xfile");
122         case Asis:
123                 if(f == 0)
124                         error("unassigned fid");
125                 return f;
126         case Clean:
127                 break;
128         case Clunk:
129                 if(f){
130                         *hp = f->next;
131                         clean(f);
132                         f->next = freelist;
133                         freelist = f;
134                 }
135                 return 0;
136         }
137         if(f)
138                 return clean(f);
139         if(f = freelist)        /* assign = */
140                 freelist = f->next;
141         else
142                 f = ealloc(sizeof(Xfile));
143         f->next = *hp;
144         *hp = f;
145         f->xf = 0;
146         f->fid = fid;
147         f->flags = 0;
148         f->qid = (Qid){0,0,0};
149         f->len = 0;
150         f->ptr = 0;
151         return f;
152 }
153
154 static Xfile *
155 clean(Xfile *f)
156 {
157         if(f->xf){
158                 refxfs(f->xf, -1);
159                 f->xf = 0;
160         }
161         if(f->len){
162                 free(f->ptr);
163                 f->len = 0;
164         }
165         f->ptr = 0;
166         f->flags = 0;
167         f->qid = (Qid){0,0,0};
168         return f;
169 }
170