]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ramfs.c
audiohda: fix syntax error
[plan9front.git] / sys / src / cmd / ramfs.c
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include <thread.h>
6 #include <9p.h>
7 #include <pool.h>
8
9 char Ebadoff[] = "bad file offset or count";
10 char Eexist[] = "file already exists";
11 char Enomem[] = "no memory";
12 char Eperm[] = "permission denied";
13 char Enotowner[] = "not owner";
14 char Elocked[] = "file is locked";
15
16 enum {
17         Tdat    = 0xbabababa,   
18         Tind    = 0xdadadada,
19
20         ESIZE   = 64*1024,
21 };
22
23 #define MAXFSIZE ((0x7fffffffll/sizeof(Ram*))*ESIZE)
24
25 typedef struct Ram Ram;
26 struct Ram
27 {
28         int     type;
29         int     size;
30         Ram     **link;
31         Ram     *ent[];
32 };
33
34 int private;
35
36 void*
37 ramalloc(ulong size)
38 {
39         void *v;
40
41         v = sbrk(size);
42         if(v == (void*)-1)
43                 return nil;
44         return v;
45 }
46
47 void
48 rammoved(void*, void *to)
49 {
50         Ram **link, **elink, *x = to;
51
52         *x->link = x;
53         if(x->type != Tind)
54                 return;
55
56         link = x->ent;
57         for(elink = link + (x->size / sizeof(Ram*)); link < elink; link++)
58                 if((x = *link) != nil)
59                         x->link = link;
60 }
61
62 void
63 ramnolock(Pool*)
64 {
65 }
66
67 Pool rampool = {
68         .name=          "ram",
69         .maxsize=       800*1024*1024,
70         .minarena=      4*1024,
71         .quantum=       32,
72         .alloc=         ramalloc,
73         .move=          rammoved,
74         .lock=          ramnolock,
75         .unlock=        ramnolock,
76         .flags=         0,
77 };
78
79 void
80 accessfile(File *f, int a)
81 {
82         f->atime = time(0);
83         if(a & AWRITE){
84                 f->mtime = f->atime;
85                 f->qid.vers++;
86         }
87 }
88
89 void
90 fsread(Req *r)
91 {
92         int o, n, i, count;
93         vlong top, off;
94         File *f;
95         Ram *x;
96         char *p;
97
98         f = r->fid->file;
99         off = r->ifcall.offset;
100         count = r->ifcall.count;
101
102         if(count == 0 || off >= f->length || f->aux == nil){
103                 r->ofcall.count = 0;
104                 respond(r, nil);
105                 return;
106         }
107
108         top = off + count;
109         if(top > MAXFSIZE){
110                 respond(r, Ebadoff);
111                 return;
112         }
113                 
114         if(top > f->length){
115                 top = f->length;
116                 count = top - off;
117         }
118         p = (char*)r->ofcall.data;
119         while(count > 0){
120                 i = off / ESIZE;
121                 o = off % ESIZE;
122
123                 x = (Ram*)f->aux;
124                 if(i < (x->size / sizeof(Ram*)))
125                         x = x->ent[i];
126                 else
127                         x = nil;
128                 if(x != nil && o < x->size){
129                         n = x->size - o;
130                         if(n > count)
131                                 n = count;
132                         memmove(p, (char*)&x[1] + o, n);
133                 } else {
134                         n = ESIZE - o;
135                         if(n > count)
136                                 n = count;
137                         memset(p, 0, n);
138                 }
139                 p += n;
140                 off += n;
141                 count -= n;
142         }
143         accessfile(f, AREAD);
144
145         r->ofcall.count = p - (char*)r->ofcall.data;
146         respond(r, nil);
147 }
148
149 void
150 fswrite(Req *r)
151 {
152         int o, n, i, count;
153         Ram *x, **link;
154         vlong top, off;
155         File *f;
156         char *p;
157
158         f = r->fid->file;
159         off = r->ifcall.offset;
160         count = r->ifcall.count;
161
162         if(f->mode & DMAPPEND)
163                 off = f->length;
164
165         if(count == 0){
166                 r->ofcall.count = 0;
167                 respond(r, nil);
168                 return;
169         }
170
171         top = off + count;
172         if(top > MAXFSIZE){
173                 respond(r, Ebadoff);
174                 return;
175         }
176
177         n = ((top + ESIZE-1)/ESIZE) * sizeof(Ram*);
178         x = (Ram*)f->aux;
179         if(x == nil || x->size < n){
180                 x = poolrealloc(&rampool, x, sizeof(Ram) + n);          
181                 if(x == nil){
182                         respond(r, Enomem);
183                         return;
184                 }
185                 link = (Ram**)&f->aux;
186                 if(*link == nil){
187                         memset(x, 0, sizeof(Ram));
188                         x->type = Tind;
189                         x->link = link;
190                         *link = x;
191                 } else if(x != *link)
192                         rammoved(*link, x);
193                 memset((char*)&x[1] + x->size, 0, n - x->size);
194                 x->size = n;
195         }
196
197         p = (char*)r->ifcall.data;
198         while(count > 0){
199                 i = off / ESIZE;
200                 o = off % ESIZE;
201
202                 n = ESIZE - o;
203                 if(n > count)
204                         n = count;
205
206                 x = ((Ram*)f->aux)->ent[i];
207                 if(x == nil || x->size < o+n){
208                         x = poolrealloc(&rampool, x, sizeof(Ram) + o+n);
209                         if(x == nil){
210                                 respond(r, Enomem);
211                                 return;
212                         }
213                         link = &((Ram*)f->aux)->ent[i];
214                         if(*link == nil){
215                                 memset(x, 0, sizeof(Ram));
216                                 x->type = Tdat;
217                         }
218                         if(o > x->size)
219                                 memset((char*)&x[1] + x->size, 0, o - x->size);
220                         x->size = o + n;
221                         x->link = link;
222                         *link = x;
223                 }
224
225                 memmove((char*)&x[1] + o, p, n);
226                 p += n;
227                 off += n;
228                 count -= n;
229         }
230
231         if(top > f->length)
232                 f->length = top;
233         accessfile(f, AWRITE);
234
235         r->ofcall.count = p - (char*)r->ifcall.data;
236         respond(r, nil);
237 }
238
239 void
240 truncfile(File *f, vlong l)
241 {
242         int i, o, n;
243         Ram *x;
244
245         x = (Ram*)f->aux;
246         if(x != nil){
247                 n = x->size / sizeof(Ram*);
248                 i = l / ESIZE;
249                 if(i < n){
250                         o = l % ESIZE;
251                         if(o != 0 && x->ent[i] != nil){
252                                 if(o < x->ent[i]->size)
253                                         x->ent[i]->size = o;
254                                 i++;
255                         }
256                         while(i < n){
257                                 if(x->ent[i] != nil){
258                                         poolfree(&rampool, x->ent[i]);
259                                         x->ent[i] = nil;
260                                 }
261                                 i++;
262                         }
263                 }
264                 if(l == 0){
265                         poolfree(&rampool, (Ram*)f->aux);
266                         f->aux = nil;
267                 }
268         }
269         f->length = l;
270 }
271
272 void
273 fswstat(Req *r)
274 {
275         File *f, *w;
276         char *u;
277
278         f = r->fid->file;
279         u = r->fid->uid;
280
281         /*
282          * To change length, must have write permission on file.
283          */
284         if(r->d.length != ~0 && r->d.length != f->length){
285                 if(r->d.length > MAXFSIZE){
286                         respond(r, Ebadoff);
287                         return;
288                 }
289                 if(!hasperm(f, u, AWRITE) || (f->mode & DMDIR) != 0)
290                         goto Perm;
291         }
292
293         /*
294          * To change name, must have write permission in parent.
295          */
296         if(r->d.name[0] != '\0' && strcmp(r->d.name, f->name) != 0){
297                 if((w = f->parent) == nil)
298                         goto Perm;
299                 incref(w);
300                 if(!hasperm(w, u, AWRITE)){
301                         closefile(w);
302                         goto Perm;
303                 }
304                 if((w = walkfile(w, r->d.name)) != nil){
305                         closefile(w);
306                         respond(r, Eexist);
307                         return;
308                 }
309         }
310
311         /*
312          * To change mode, must be owner or group leader.
313          * Because of lack of users file, leader=>group itself.
314          */
315         if(r->d.mode != ~0 && f->mode != r->d.mode){
316                 if(strcmp(u, f->uid) != 0)
317                 if(strcmp(u, f->gid) != 0){
318                         respond(r, Enotowner);
319                         return;
320                 }
321         }
322
323         /*
324          * To change group, must be owner and member of new group,
325          * or leader of current group and leader of new group.
326          * Second case cannot happen, but we check anyway.
327          */
328         while(r->d.gid[0] != '\0' && strcmp(f->gid, r->d.gid) != 0){
329                 if(strcmp(u, f->uid) == 0)
330                         break;
331                 if(strcmp(u, f->gid) == 0)
332                 if(strcmp(u, r->d.gid) == 0)
333                         break;
334                 respond(r, Enotowner);
335                 return;
336         }
337
338         if(r->d.mode != ~0){
339                 f->mode = r->d.mode;
340                 f->qid.type = f->mode >> 24;
341         }
342         if(r->d.name[0] != '\0'){
343                 free(f->name);
344                 f->name = estrdup9p(r->d.name);
345         }
346         if(r->d.length != ~0 && r->d.length != f->length)
347                 truncfile(f, r->d.length);
348
349         accessfile(f, AWRITE);
350         if(r->d.mtime != ~0){
351                 f->mtime = r->d.mtime;
352         }
353
354         respond(r, nil);
355         return;
356
357 Perm:
358         respond(r, Eperm);
359 }
360
361 void
362 fscreate(Req *r)
363 {
364         File *f;
365         int p;
366
367         f = r->fid->file;
368         p = r->ifcall.perm;
369         if((p & DMDIR) != 0)
370                 p = (p & ~0777) | ((p & f->mode) & 0777);
371         else
372                 p = (p & ~0666) | ((p & f->mode) & 0666);
373         if((f = createfile(f, r->ifcall.name, r->fid->uid, p, nil)) == nil){
374                 responderror(r);
375                 return;
376         }
377         f->atime = f->mtime = time(0);
378         f->aux = nil;
379         r->fid->file = f;
380         r->ofcall.qid = f->qid;
381         respond(r, nil);
382 }
383
384 void
385 fsopen(Req *r)
386 {
387         File *f;
388
389         f = r->fid->file;
390         if((f->mode & DMEXCL) != 0){
391                 if(f->ref > 2 && (long)((ulong)time(0)-(ulong)f->atime) < 300){
392                         respond(r, Elocked);
393                         return;
394                 }
395         }
396         if((f->mode & DMAPPEND) == 0 && (r->ifcall.mode & OTRUNC) != 0){
397                 truncfile(f, 0);
398                 accessfile(f, AWRITE);
399         }
400         respond(r, nil);
401 }
402
403 void
404 fsdestroyfid(Fid *fid)
405 {
406         File *f;
407
408         f = fid->file;
409         if(fid->omode != -1 && (fid->omode & ORCLOSE) != 0 && f != nil && f->parent != nil)
410                 removefile(f);
411 }
412
413 void
414 fsdestroyfile(File *f)
415 {
416         truncfile(f, 0);
417 }
418
419 void
420 fsstart(Srv *)
421 {
422         char buf[40];
423         int ctl;
424
425         if(private){
426                 snprint(buf, sizeof buf, "/proc/%d/ctl", getpid());
427                 if((ctl = open(buf, OWRITE)) < 0)
428                         sysfatal("can't protect memory: %r");
429                 fprint(ctl, "noswap\n");
430                 fprint(ctl, "private\n");
431                 close(ctl);
432         }
433 }
434
435 Srv fs = {
436         .open=          fsopen,
437         .read=          fsread,
438         .write=         fswrite,
439         .wstat=         fswstat,
440         .create=        fscreate,
441         .destroyfid=    fsdestroyfid,
442
443         .start=         fsstart,
444 };
445
446 void
447 usage(void)
448 {
449         fprint(2, "usage: %s [-Dipsubac] [-m mountpoint] [-S srvname]\n", argv0);
450         exits("usage");
451 }
452
453 void
454 main(int argc, char **argv)
455 {
456         char *srvname = nil;
457         char *mtpt = "/tmp";
458         int mountflags, stdio;
459
460         fs.tree = alloctree(nil, nil, DMDIR|0777, fsdestroyfile);
461
462         mountflags = stdio = 0;
463         ARGBEGIN{
464         case 'D':
465                 chatty9p++;
466                 break;
467         case 's':
468                 srvname = "ramfs";
469                 mtpt = nil;
470                 break;
471         case 'S':
472                 srvname = EARGF(usage());
473                 mtpt = nil;
474                 break;
475         case 'm':
476                 mtpt = EARGF(usage());
477                 break;
478         case 'i':
479                 stdio = 1;
480                 break;
481         case 'p':
482                 private = 1;
483                 break;
484         case 'u':
485                 rampool.maxsize = (uintptr)~0;
486                 break;
487         case 'b':
488                 mountflags |= MBEFORE;
489                 break;
490         case 'c':
491                 mountflags |= MCREATE;
492                 break;
493         case 'a':
494                 mountflags |= MAFTER;
495                 break;
496         default:
497                 usage();
498         }ARGEND;
499         if(argc > 0)
500                 usage();
501
502         if(stdio){
503                 fs.infd = 0;
504                 fs.outfd = 1;
505                 srv(&fs);
506                 exits(0);
507         }
508
509         if(srvname == nil && mtpt == nil)
510                 sysfatal("must specify -S, or -m option");
511
512         if(mountflags == 0)
513                 mountflags = MREPL | MCREATE;
514         postmountsrv(&fs, srvname, mtpt, mountflags);
515         exits(0);
516 }