1 #include <u.h>
2 #include <libc.h>
3 #include "iotrack.h"
4 #include "dat.h"
5 #include "fns.h"
6
7 #define FIDMOD 127 /* prime */
8
9 static Xfs *xhead;
10 static Xfile *xfiles[FIDMOD], *freelist;
11 static MLock xlock, xlocks[FIDMOD], freelock;
12
13 static int
okmode(int omode,int fmode)14 okmode(int omode, int fmode)
15 {
16 if(omode == OREAD)
17 return fmode & 4;
18 /* else ORDWR */
19 return (fmode & 6) == 6;
20 }
21
22 Xfs *
getxfs(char * user,char * name)23 getxfs(char *user, char *name)
24 {
25 Xfs *xf, *fxf;
26 Dir *dir;
27 Qid dqid;
28 char *p, *q;
29 long offset;
30 int fd, omode;
31
32 USED(user);
33 if(name==nil || name[0]==0)
34 name = deffile;
35 if(name == nil){
36 errno = Enofilsys;
37 return 0;
38 }
39
40 /*
41 * If the name passed is of the form 'name:offset' then
42 * offset is used to prime xf->offset. This allows accessing
43 * a FAT-based filesystem anywhere within a partition.
44 * Typical use would be to mount a filesystem in the presence
45 * of a boot manager programme at the beginning of the disc.
46 */
47 offset = 0;
48 if(p = strrchr(name, ':')){
49 *p++ = 0;
50 offset = strtol(p, &q, 0);
51 chat("name %s, offset %ld\n", p, offset);
52 if(offset < 0 || p == q){
53 errno = Enofilsys;
54 return 0;
55 }
56 offset *= Sectorsize;
57 }
58
59 if(readonly)
60 omode = OREAD;
61 else
62 omode = ORDWR;
63 fd = open(name, omode);
64
65 if(fd < 0 && omode==ORDWR){
66 omode = OREAD;
67 fd = open(name, omode);
68 }
69
70 if(fd < 0){
71 chat("can't open %s: %r\n", name);
72 errno = Eerrstr;
73 return 0;
74 }
75 dir = dirfstat(fd);
76 if(dir == nil){
77 errno = Eio;
78 close(fd);
79 return 0;
80 }
81
82 dqid = dir->qid;
83 free(dir);
84 mlock(&xlock);
85 for(fxf=0,xf=xhead; xf; xf=xf->next){
86 if(xf->ref == 0){
87 if(fxf == 0)
88 fxf = xf;
89 continue;
90 }
91 if(!eqqid(xf->qid, dqid))
92 continue;
93 if(strcmp(xf->name, name) != 0 || xf->dev < 0)
94 continue;
95 if(devcheck(xf) < 0) /* look for media change */
96 continue;
97 if(offset && xf->offset != offset)
98 continue;
99 chat("incref \"%s\", dev=%d...", xf->name, xf->dev);
100 ++xf->ref;
101 unmlock(&xlock);
102 close(fd);
103 return xf;
104 }
105 if(fxf == nil){
106 fxf = malloc(sizeof(Xfs));
107 if(fxf == nil){
108 unmlock(&xlock);
109 close(fd);
110 errno = Enomem;
111 return nil;
112 }
113 fxf->next = xhead;
114 xhead = fxf;
115 }
116 chat("alloc \"%s\", dev=%d...", name, fd);
117 fxf->name = strdup(name);
118 fxf->ref = 1;
119 fxf->qid = dqid;
120 fxf->dev = fd;
121 fxf->fmt = 0;
122 fxf->offset = offset;
123 fxf->ptr = nil;
124 fxf->isfat32 = 0;
125 fxf->omode = omode;
126 unmlock(&xlock);
127 return fxf;
128 }
129
130 void
refxfs(Xfs * xf,int delta)131 refxfs(Xfs *xf, int delta)
132 {
133 mlock(&xlock);
134 xf->ref += delta;
135 if(xf->ref == 0){
136 chat("free \"%s\", dev=%d...", xf->name, xf->dev);
137 free(xf->name);
138 free(xf->ptr);
139 purgebuf(xf);
140 if(xf->dev >= 0){
141 close(xf->dev);
142 xf->dev = -1;
143 }
144 }
145 unmlock(&xlock);
146 }
147
148 Xfile *
xfile(int fid,int flag)149 xfile(int fid, int flag)
150 {
151 Xfile **hp, *f, *pf;
152 int k;
153
154 k = ((ulong)fid) % FIDMOD;
155 hp = &xfiles[k];
156 mlock(&xlocks[k]);
157 pf = nil;
158 for(f=*hp; f; f=f->next){
159 if(f->fid == fid)
160 break;
161 pf = f;
162 }
163 if(f && pf){
164 pf->next = f->next;
165 f->next = *hp;
166 *hp = f;
167 }
168 switch(flag){
169 default:
170 panic("xfile");
171 case Asis:
172 unmlock(&xlocks[k]);
173 return (f && f->xf && f->xf->dev < 0) ? nil : f;
174 case Clean:
175 break;
176 case Clunk:
177 if(f){
178 *hp = f->next;
179 unmlock(&xlocks[k]);
180 clean(f);
181 mlock(&freelock);
182 f->next = freelist;
183 freelist = f;
184 unmlock(&freelock);
185 } else
186 unmlock(&xlocks[k]);
187 return nil;
188 }
189 unmlock(&xlocks[k]);
190 if(f)
191 return clean(f);
192 mlock(&freelock);
193 if(f = freelist){ /* assign = */
194 freelist = f->next;
195 unmlock(&freelock);
196 } else {
197 unmlock(&freelock);
198 f = malloc(sizeof(Xfile));
199 if(f == nil){
200 errno = Enomem;
201 return nil;
202 }
203 }
204 mlock(&xlocks[k]);
205 f->next = *hp;
206 *hp = f;
207 unmlock(&xlocks[k]);
208 f->fid = fid;
209 f->flags = 0;
210 f->qid = (Qid){0,0,0};
211 f->xf = nil;
212 f->ptr = nil;
213 return f;
214 }
215
216 Xfile *
clean(Xfile * f)217 clean(Xfile *f)
218 {
219 if(f->ptr){
220 free(f->ptr);
221 f->ptr = nil;
222 }
223 if(f->xf){
224 refxfs(f->xf, -1);
225 f->xf = nil;
226 }
227 f->flags = 0;
228 f->qid = (Qid){0,0,0};
229 return f;
230 }
231
232 /*
233 * the file at <addr, offset> has moved
234 * relocate the dos entries of all fids in the same file
235 */
236 void
dosptrreloc(Xfile * f,Dosptr * dp,ulong addr,ulong offset)237 dosptrreloc(Xfile *f, Dosptr *dp, ulong addr, ulong offset)
238 {
239 int i;
240 Xfile *p;
241 Dosptr *xdp;
242
243 for(i=0; i < FIDMOD; i++){
244 for(p = xfiles[i]; p != nil; p = p->next){
245 xdp = p->ptr;
246 if(p != f && p->xf == f->xf
247 && xdp != nil && xdp->addr == addr && xdp->offset == offset){
248 memmove(xdp, dp, sizeof(Dosptr));
249 xdp->p = nil;
250 xdp->d = nil;
251 p->qid.path = QIDPATH(xdp);
252 }
253 }
254 }
255 }
256