9 * Rather than reading /adm/users, which is a lot of work for
10 * a toy program, we assume all groups have the form
12 * meaning that each user is the leader of his own group.
17 OPERM = 0x3, /* mask of all permission types in open mode */
19 OffsetSize = 4, /* size in bytes of an offset */
23 typedef struct Fid Fid;
24 typedef struct Path Path;
25 typedef struct Sac Sac;
26 typedef struct Cache Cache;
75 char mdata[MAXMSG+MAXFDATA];
80 Cache cache[CacheSize];
84 void sacstat(SacDir*, char*);
87 void *erealloc(void*, ulong);
90 int perm(Fid*, Sac*, int);
94 Sac *saclookup(Sac *s, char *name);
95 int sacdirread(Sac *s, char *p, long off, long cnt);
96 void loadblock(void *buf, uchar *offset, int blocksize);
99 char *rflush(Fid*), *rnop(Fid*), *rsession(Fid*),
100 *rattach(Fid*), *rclone(Fid*), *rwalk(Fid*),
101 *rclwalk(Fid*), *ropen(Fid*), *rcreate(Fid*),
102 *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
103 *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
105 char *(*fcalls[])(Fid*) = {
123 char Eperm[] = "permission denied";
124 char Enotdir[] = "not a directory";
125 char Enoauth[] = "no authentication in ramfs";
126 char Enotexist[] = "file does not exist";
127 char Einuse[] = "file in use";
128 char Eexist[] = "file exists";
129 char Enotowner[] = "not owner";
130 char Eisopen[] = "file already open for I/O";
131 char Excl[] = "exclusive use file already open";
132 char Ename[] = "illegal name";
133 char Erdonly[] = "read only file system";
138 notifyf(void *a, char *s)
141 if(strncmp(s, "interrupt", 9) == 0)
147 main(int argc, char *argv[])
182 error("pipe failed");
187 fd = create("#s/sacfs", OWRITE, 0666);
189 error("create of /srv/sacfs failed");
190 sprint(buf, "%d", p[1]);
191 if(write(fd, buf, strlen(buf)) < 0)
192 error("writing /srv/sacfs");
197 fmtinstall('F', fcallconv);
198 switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
206 close(p[0]); /* don't deadlock if child fails */
207 if(defmnt && mount(p[1], defmnt, MREPL|MCREATE, "") < 0)
208 error("mount failed");
221 rsession(Fid *unused)
227 for(f = fids; f; f = f->next)
230 memset(thdr.authid, 0, sizeof(thdr.authid));
231 memset(thdr.authdom, 0, sizeof(thdr.authdom));
232 memset(thdr.chal, 0, sizeof(thdr.chal));
246 /* no authentication! */
248 f->qid = (Qid){getl(root.qid), 0};
249 f->sac = saccpy(&root);
252 f->user = strdup(rhdr.uname);
267 nf = newfid(rhdr.newfid);
271 nf->sac = saccpy(f->sac);
272 nf->user = strdup(f->user);
282 if((f->qid.path & CHDIR) == 0)
288 if(strcmp(name, ".") == 0){
292 if(!perm(f, sac, Pexec))
294 sac = saclookup(sac, name);
298 f->qid = (Qid){getl(sac->qid), 0};
309 nf = newfid(rhdr.newfid);
311 nf->sac = saccpy(f->sac);
312 nf->user = strdup(f->user);
328 if(f->qid.path & CHDIR){
336 trunc = mode & OTRUNC;
338 if(mode==OWRITE || mode==ORDWR || trunc)
341 if(!perm(f, f->sac, Pread))
344 if(!perm(f, f->sac, Pexec))
378 if(f->qid.path & CHDIR){
379 cnt = (rhdr.count/DIRLEN)*DIRLEN;
382 thdr.count = sacdirread(sac, buf, off, cnt);
385 length = getl(sac->length);
395 blocks = data + getl(sac->blocks);
396 buf2 = malloc(blocksize);
398 sysfatal("malloc failed");
402 if(n > length-i*blocksize)
403 n = length-i*blocksize;
404 loadblock(buf2, blocks+i*OffsetSize, n);
409 memmove(buf, buf2+j, n);
451 sacstat(f->sac, thdr.stat);
468 ss = emalloc(sizeof(Sac));
476 pathalloc(Path *p, long blocks, int entry, int nentry)
478 Path *pp = emalloc(sizeof(Path));
510 sacstat(SacDir *s, char *buf)
514 memmove(dir.name, s->name, NAMELEN);
515 dir.qid = (Qid){getl(s->qid), 0};
516 dir.mode = getl(s->mode);
517 dir.length = getl(s->length);
519 dir.length *= DIRLEN;
520 memmove(dir.uid, s->uid, NAMELEN);
521 memmove(dir.gid, s->gid, NAMELEN);
522 dir.atime = getl(s->atime);
523 dir.mtime = getl(s->mtime);
528 loadblock(void *buf, uchar *offset, int blocksize)
534 block = getl(offset);
540 for(i=0; i<CacheSize; i++)
545 for(i=0; i<CacheSize; i++) {
546 if(cache[i].age < age) {
550 if(cache[i].block != block)
552 memmove(buf, cache[i].data, blocksize);
553 cache[i].age = cacheage;
557 n = getl(offset+OffsetSize);
561 if(unsac(buf, data+block, blocksize, n)<0)
562 sysfatal("unsac failed!");
563 memmove(cache[j].data, buf, blocksize);
564 cache[j].age = cacheage;
565 cache[j].block = block;
567 memmove(buf, data+block, blocksize);
580 if(p == nil || p->up == nil) {
587 blocks = data + p->blocks;
588 per = blocksize/sizeof(SacDir);
591 if(n > p->nentry-i*per)
593 buf = emalloc(per*sizeof(SacDir));
594 loadblock(buf, blocks + i*OffsetSize, n*sizeof(SacDir));
595 s->SacDir = buf[p->entry-i*per];
604 sacdirread(Sac *s, char *p, long off, long cnt)
608 int iblock, per, i, j, ndir, n;
610 blocks = data + getl(s->blocks);
611 per = blocksize/sizeof(SacDir);
612 ndir = getl(s->length);
620 buf = emalloc(per*sizeof(SacDir));
621 for(i=off; i<off+cnt; i++) {
627 loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir));
630 sacstat(buf+i-j*per, p);
638 saclookup(Sac *s, char *name)
641 int top, bot, i, j, k, n, per;
647 if(strcmp(name, "..") == 0)
649 blocks = data + getl(s->blocks);
650 per = blocksize/sizeof(SacDir);
651 ndir = getl(s->length);
652 buf = malloc(per*sizeof(SacDir));
654 sysfatal("malloc failed");
659 for(i=0; i<ndir; i++) {
665 loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir));
669 k = strcmp(name, sd->name);
671 s->path = pathalloc(s->path, getl(s->blocks), i, ndir);
691 loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir));
696 k = strcmp(name, sd->name);
698 s->path = pathalloc(s->path, getl(s->blocks), i, ndir);
705 if(strcmp(name, sd->name) < 0)
714 if(strcmp(name, sd->name) > 0)
727 for(f = fids; f; f = f->next)
730 else if(!ff && !f->busy)
736 f = emalloc(sizeof *f);
737 memset(f, 0 , sizeof(Fid));
752 * reading from a pipe or a network device
753 * will give an error after a few eof reads
754 * however, we cannot tell the difference
755 * between a zero-length read and an interrupt
756 * on the processes writing to us,
757 * so we wait for the error
759 n = read(mfd[0], mdata, sizeof mdata);
764 if(convM2S(mdata, &rhdr, n) == 0)
768 fprint(2, "sacfs:<-%F\n", &rhdr);
770 thdr.data = mdata + MAXMSG;
771 if(!fcalls[rhdr.type])
772 err = "bad fcall type";
774 err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
777 strncpy(thdr.ename, err, ERRLEN);
779 thdr.type = rhdr.type + 1;
784 fprint(2, "ramfs:->%F\n", &thdr);/**/
785 n = convS2M(&thdr, mdata);
786 if(write(mfd[1], mdata, n) != n)
787 error("mount write");
792 perm(Fid *f, Sac *s, int p)
794 ulong perm = getl(s->mode);
795 if((p*Pother) & perm)
797 if(strcmp(f->user, s->gid)==0 && ((p*Pgroup) & perm))
799 if(strcmp(f->user, s->uid)==0 && ((p*Powner) & perm))
814 strcpy(user, getuser());
817 if(dirstat(file, &dir) < 0)
819 data = emalloc(dir.length);
820 fd = open(file, OREAD);
822 error("opening file");
823 if(read(fd, data, dir.length) < dir.length)
824 error("reading file");
825 hdr = (SacHeader*)data;
826 if(getl(hdr->magic) != Magic)
828 if(getl(hdr->length) != (ulong)(dir.length))
830 blocksize = getl(hdr->blocksize);
831 root.SacDir = *(SacDir*)(data + sizeof(SacHeader));
832 p = malloc(CacheSize*blocksize);
834 error("allocating cache");
835 for(i=0; i<CacheSize; i++) {
844 fprint(2, "%s: %s: %r\n", argv0, s);
855 error("out of memory");
860 erealloc(void *p, ulong n)
864 error("out of memory");
871 fprint(2, "usage: %s [-i infd outfd] [-s] [-m mountpoint] sacfsfile\n", argv0);
880 return (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3];