14 OPERM = 0x3, /* mask of all permission types in open mode */
15 OffsetSize = 4, /* size in bytes of an offset */
18 typedef struct Fid Fid;
19 typedef struct Paq Paq;
20 typedef struct Block Block;
28 ulong offset; /* for directory reading */
45 ulong addr; /* block byte address */
65 int mesgsize = 8*1024 + IOHDRSZ;
73 void paqstat(PaqDir*, char*);
76 void *emallocz(ulong n);
81 char *getstr(uchar *p);
82 PaqDir *getDir(uchar*);
83 void getHeader(uchar *p, PaqHeader *b);
84 void getBlock(uchar *p, PaqBlock *b);
85 void getTrailer(uchar *p, PaqTrailer *b);
86 void init(char*, int);
87 void paqDirFree(PaqDir*);
88 Qid paqDirQid(PaqDir *d);
90 Paq *paqLookup(Paq *s, char *name);
92 Paq *paqWalk(Paq *s, char *name);
93 int perm(PaqDir *s, char *user, int p);
94 int dirRead(Fid*, uchar*, int);
95 Block *blockLoad(ulong addr, int type);
96 void blockFree(Block*);
97 int checkDirSize(uchar *p, uchar *ep);
98 int packDir(PaqDir*, uchar*, int);
99 int blockRead(uchar *data, ulong addr, int type);
100 void readHeader(PaqHeader *hdr, char *name, DigestState *ds);
101 void readBlocks(char *name, DigestState *ds);
102 void readTrailer(PaqTrailer *tlr, char *name, DigestState *ds);
104 char *rflush(Fid*), *rversion(Fid*),
105 *rauth(Fid*), *rattach(Fid*), *rwalk(Fid*),
106 *ropen(Fid*), *rcreate(Fid*),
107 *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
108 *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
110 char *(*fcalls[])(Fid*) = {
126 char Eperm[] = "permission denied";
127 char Enotdir[] = "not a directory";
128 char Enoauth[] = "authentication not required";
129 char Enotexist[] = "file does not exist";
130 char Einuse[] = "file in use";
131 char Eexist[] = "file exists";
132 char Enotowner[] = "not owner";
133 char Eisopen[] = "file already open for I/O";
134 char Excl[] = "exclusive use file already open";
135 char Ename[] = "illegal name";
136 char Erdonly[] = "read only file system";
137 char Ebadblock[] = "bad block";
138 char Eversion[] = "bad version of P9";
139 char Edirtoobig[] = "directory entry too big";
143 #pragma varargck type "V" uchar*
151 v = va_arg(f->args, uchar*);
156 for(i = 0; i < SHA1dlen; i++)
157 fmtprint(f, "%2.2ux", v[i]);
164 main(int argc, char *argv[])
167 int fd, mnt, srv, stdio, verify;
168 char buf[64], *mntpoint, *srvname, *p;
170 fmtinstall('V', sha1fmt);
175 srv = stdio = verify = 0;
197 mntpoint = EARGF(usage());
204 if(mesgsize > 128*1024)
219 srvname = EARGF(usage());
229 init(argv[0], verify);
233 sysfatal("pipe: %r");
235 snprint(buf, sizeof buf, "#s/%s", srvname);
236 fd = create(buf, OWRITE, 0666);
238 sysfatal("create %s: %r", buf);
239 if(fprint(fd, "%d", pfd[0]) < 0)
240 sysfatal("write %s: %r", buf);
245 fmtinstall('F', fcallfmt);
246 switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
254 close(pfd[1]); /* don't deadlock if child fails */
255 if(mnt && mount(pfd[0], -1, mntpoint, MREPL|MCREATE, "") < 0)
256 sysfatal("mount %s: %r", mntpoint);
266 for(f = fids; f; f = f->next)
269 if(rhdr.msize > mesgsize)
270 thdr.msize = mesgsize;
272 thdr.msize = rhdr.msize;
273 if(strcmp(rhdr.version, "9P2000") != 0)
275 thdr.version = "9P2000";
295 /* no authentication! */
297 f->paq = paqCpy(root);
298 thdr.qid = f->paq->qid;
300 f->user = estrdup(rhdr.uname);
302 f->user = estrdup("none");
307 clone(Fid *f, Fid **res)
315 nf = newfid(rhdr.newfid);
318 nf->paq = paqCpy(f->paq);
319 nf->user = estrdup(f->user);
336 if(rhdr.fid != rhdr.newfid){
340 f = nf; /* walk the new fid */
343 nwname = rhdr.nwname;
351 paq = paqCpy(f->paq);
355 for(nqid = 0; nqid < nwname; nqid++){
356 if((qid.type & QTDIR) == 0){
360 if(!perm(paq->dir, f->user, Pexec)) {
364 npaq = paqWalk(paq, rhdr.wname[nqid]);
372 thdr.wqid[nqid] = qid;
388 /* only error on the first element */
405 if(f->paq->qid.type & QTDIR){
408 thdr.qid = f->paq->qid;
413 trunc = mode & OTRUNC;
415 if(mode==OWRITE || mode==ORDWR || trunc)
418 if(!perm(f->paq->dir, f->user, Pread))
421 if(!perm(f->paq->dir, f->user, Pexec))
423 thdr.qid = f->paq->qid;
448 buf = (uchar*)thdr.data;
454 if(rootfile && f->paq == root){
459 n = packDir(rootfile->dir, buf, cnt);
464 ptr = blockLoad(f->paq->dir->offset, PointerBlock);
471 b = blockLoad(getl(ptr->data + i*4), DirBlock);
474 ep = b->data + blocksize;
475 if(checkDirSize(p, ep)) {
477 n = packDir(pd, buf, cnt);
481 if(thdr.count == 0) {
495 b = blockLoad(getl(ptr->data + i*4), DirBlock);
498 f->offset = i*blocksize + off;
516 if(f->paq->qid.type & QTDIR)
520 buf = (uchar*)thdr.data;
524 if(off >= pd->length || cnt == 0)
527 if(cnt > pd->length - off)
528 cnt = pd->length - off;
530 ptr = blockLoad(pd->offset, PointerBlock);
535 uoff = off-i*blocksize;
538 b = blockLoad(getl(ptr->data + i*4), DataBlock);
543 n = blocksize - uoff;
546 memmove(buf, b->data + uoff, n);
590 thdr.stat = (uchar*)thdr.data;
591 thdr.nstat = packDir(f->paq->dir, thdr.stat, mesgsize);
627 paqDirFree(PaqDir *pd)
644 q.type = d->mode >> 24;
650 packDir(PaqDir *s, uchar *buf, int n)
654 memset(&dir, 0, sizeof(dir));
655 dir.qid = paqDirQid(s);
657 dir.atime = s->mtime;
658 dir.mtime = s->mtime;
659 dir.length = s->length;
665 n = convD2M(&dir, buf, n);
672 blockLoad(ulong addr, int type)
685 for(i=0; i<cachesize; i++)
691 for(i=0; i<cachesize; i++) {
693 if(b->age < age && b->ref == 0) {
704 sysfatal("no empty spots in cache!");
708 if(!blockRead(b->data, addr, type)) {
732 paqWalk(Paq *s, char *name)
740 if(strcmp(name, "..") == 0)
741 return paqCpy(s->up);
743 if(rootfile && s == root){
744 if(strcmp(name, rootfile->dir->name) == 0)
745 return paqCpy(rootfile);
749 ptr = blockLoad(s->dir->offset, PointerBlock);
753 for(i=0; i<blocksize/4; i++) {
754 b = blockLoad(getl(ptr->data+i*4), DirBlock);
759 while(checkDirSize(p, ep)) {
762 if(strcmp(pd->name, name) == 0) {
763 ss = emallocz(sizeof(Paq));
767 ss->qid = paqDirQid(pd);
788 for(f = fids; f; f = f->next)
791 else if(!ff && !f->busy)
797 f = emallocz(sizeof *f);
811 mdata = emalloc(mesgsize);
815 while((n = read9pmsg(fd, mdata, mesgsize)) != 0){
817 sysfatal("mount read: %r");
818 if(convM2S(mdata, n, &rhdr) != n)
819 sysfatal("convM2S format error: %r");
822 fprint(2, "paqfs %d:<-%F\n", pid, &rhdr);
824 thdr.data = (char*)mdata + IOHDRSZ;
825 if(!fcalls[rhdr.type])
826 err = "bad fcall type";
828 err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
833 thdr.type = rhdr.type + 1;
838 fprint(2, "paqfs %d:->%F\n", pid, &thdr);/**/
839 n = convS2M(&thdr, mdata, mesgsize);
841 sysfatal("convS2M sysfatal on write");
842 if(write(fd, mdata, n) != n)
843 sysfatal("mount write");
848 perm(PaqDir *s, char *user, int p)
850 ulong perm = s->mode;
852 if((p*Pother) & perm)
854 if((noauth || strcmp(user, s->gid)==0) && ((p*Pgroup) & perm))
856 if((noauth || strcmp(user, s->uid)==0) && ((p*Powner) & perm))
862 init(char *file, int verify)
869 DigestState *ds = nil;
876 bin = Bopen(file, OREAD);
878 sysfatal("could not open file: %s: %r", file);
880 ds = sha1(0, 0, 0, 0);
882 readHeader(&hdr, file, ds);
883 blocksize = hdr.blocksize;
886 readBlocks(file, ds);
890 sysfatal("could not stat file: %s: %r", file);
891 offset = dir->length - TrailerSize;
893 if(Bseek(bin, offset, 0) != offset)
894 sysfatal("could not seek to trailer: %s", file);
897 readTrailer(&tlr, file, ds);
899 /* asctime includes a newline - yuk */
901 fprint(2, "%s: %s", hdr.label, asctime(gmtime(hdr.time)));
902 fprint(2, "fingerprint: %V\n", tlr.sha1);
905 cache = emallocz(cachesize*sizeof(Block));
906 p = emalloc(cachesize*blocksize);
907 for(i=0; i<cachesize; i++) {
912 /* hand craft root */
913 b = blockLoad(tlr.root, DirBlock);
914 if(b == nil || !checkDirSize(b->data, b->data+blocksize))
915 sysfatal("could not read root block: %s", file);
918 root = emallocz(sizeof(Paq));
919 root->qid = paqDirQid(r);
922 root->up = root; /* parent of root is root */
924 /* craft root directory if root is a normal file */
925 if(!(root->qid.type&QTDIR)){
927 root = emallocz(sizeof(Paq));
928 root->qid = rootfile->qid;
929 root->qid.type |= QTDIR;
932 root->dir = emallocz(sizeof(PaqDir));
934 root->dir->mode |= DMDIR|0111;
940 blockRead(uchar *data, ulong addr, int type)
942 uchar buf[BlockSize];
946 if(Bseek(bin, addr, 0) != addr){
947 fprint(2, "paqfs: seek %lud: %r\n", addr);
950 if(Bread(bin, buf, BlockSize) != BlockSize){
951 fprint(2, "paqfs: read %d at %lud: %r\n", BlockSize, addr);
955 if(b.magic != BlockMagic || b.size > blocksize || b.type != type){
956 fprint(2, "paqfs: bad block: magic %.8lux (want %.8ux) size %lud (max %d) type %ud (want %ud)\n",
957 b.magic, BlockMagic, b.size, blocksize, b.type, type);
965 if(Bread(bin, data, blocksize) < blocksize)
969 cdat = emalloc(b.size);
970 if(Bread(bin, cdat, b.size) < b.size) {
974 if(inflateblock(data, blocksize, cdat, b.size) < 0) {
975 fprint(2, "inflate error: %r\n");
982 if(adler32(0, data, blocksize) != b.adler32)
988 readHeader(PaqHeader *hdr, char *name, DigestState *ds)
990 uchar buf[HeaderSize];
992 if(Bread(bin, buf, HeaderSize) < HeaderSize)
993 sysfatal("could not read header: %s: %r", name);
995 sha1(buf, HeaderSize, 0, ds);
997 if(hdr->magic != HeaderMagic)
998 sysfatal("bad header magic 0x%lux: %s", hdr->magic, name);
999 if(hdr->version != Version)
1000 sysfatal("unknown file version: %s", name);
1004 readBlocks(char *name, DigestState *ds)
1009 buf = emalloc(BlockSize+blocksize);
1012 if(Bread(bin, buf, 4) < 4)
1013 sysfatal("could not read block: %s: %r", name);
1015 /* check if it is a data block */
1017 if(getl(buf) != BlockMagic)
1020 if(Bread(bin, buf, BlockSize) < BlockSize)
1021 sysfatal("could not read block: %s: %r", name);
1023 sha1(buf, BlockSize, 0, ds);
1026 if(b.size > blocksize)
1027 sysfatal("bad block size: %lud: %s", b.size, name);
1029 if(Bread(bin, buf, b.size) < b.size)
1030 sysfatal("sysfatal reading block: %s: %r", name);
1031 sha1(buf, b.size, 0, ds);
1033 Bseek(bin, b.size, 1);
1040 readTrailer(PaqTrailer *tlr, char *name, DigestState *ds)
1042 uchar buf[TrailerSize];
1043 uchar digest[SHA1dlen];
1045 if(Bread(bin, buf, TrailerSize) < TrailerSize)
1046 sysfatal("could not read trailer: %s: %r", name);
1047 getTrailer(buf, tlr);
1048 if(tlr->magic != TrailerMagic)
1049 sysfatal("bad trailer magic: %s", name);
1051 sha1(buf, TrailerSize-SHA1dlen, digest, ds);
1052 if(memcmp(digest, tlr->sha1, SHA1dlen) != 0)
1053 sysfatal("bad sha1 digest: %s", name);
1064 sysfatal("out of memory");
1084 sysfatal("out of memory");
1092 return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
1099 return (p[0]<<8) | p[1];
1103 checkDirSize(uchar *p, uchar *ep)
1115 for(i=0; i<3; i++) {
1127 getHeader(uchar *p, PaqHeader *h)
1130 h->version = gets(p+4);
1131 h->blocksize = gets(p+6);
1132 if((h->magic>>16) == BigHeaderMagic){
1133 h->magic = HeaderMagic;
1134 h->version = gets(p+2);
1135 h->blocksize = getl(p+4);
1137 h->time = getl(p+8);
1138 memmove(h->label, p+12, sizeof(h->label));
1139 h->label[sizeof(h->label)-1] = 0;
1143 getTrailer(uchar *p, PaqTrailer *t)
1146 t->root = getl(p+4);
1147 memmove(t->sha1, p+8, SHA1dlen);
1151 getBlock(uchar *p, PaqBlock *b)
1154 b->size = gets(p+4);
1155 if((b->magic>>16) == BigBlockMagic){
1156 b->magic = BlockMagic;
1157 b->size = getl(p+2);
1161 b->adler32 = getl(p+8);
1169 pd = emallocz(sizeof(PaqDir));
1170 pd->qid = getl(p+2);
1171 pd->mode = getl(p+6);
1172 pd->mtime = getl(p+10);
1173 pd->length = getl(p+14);
1174 pd->offset = getl(p+18);
1176 pd->name = getstr(p);
1178 pd->uid = getstr(p);
1180 pd->gid = getstr(p);
1202 fprint(2, "usage: %s [-disv] [-c cachesize] [-m mountpoint] [-M mesgsize] paqfile\n", argv0);