📄 paqfs.c
字号:
paqDirFree(PaqDir *pd){ if(pd == nil) return; free(pd->name); free(pd->uid); free(pd->gid); free(pd);}QidpaqDirQid(PaqDir *d){ Qid q; q.path = d->qid; q.vers = 0; q.type = d->mode >> 24; return q;}intpackDir(PaqDir *s, uchar *buf, int n){ Dir dir; memset(&dir, 0, sizeof(dir)); dir.qid = paqDirQid(s); dir.mode = s->mode; dir.atime = s->mtime; dir.mtime = s->mtime; dir.length = s->length; dir.name = s->name; dir.uid = s->uid; dir.gid = s->gid; dir.muid = s->uid; n = convD2M(&dir, buf, n); if(n < STATFIXLEN) return 0; return n;}Block *blockLoad(ulong addr, int type){ ulong age; int i, j; Block *b; if(addr == 0) return nil; cacheage++; /* age has wraped */ if(cacheage == 0) { for(i=0; i<cachesize; i++) cache[i].age = 0; } j = -1; age = ~0; for(i=0; i<cachesize; i++) { b = &cache[i]; if(b->age < age && b->ref == 0) { age = b->age; j = i; } if(b->addr != addr) continue; b->age = cacheage; b->ref++; return b; } if(j < 0) sysfatal("no empty spots in cache!\n"); b = &cache[j]; assert(b->ref == 0); if(!blockRead(b->data, addr, type)) { b->addr = 0; b->age = 0; return nil; } b->age = cacheage; b->addr = addr; b->ref = 1; return b;}voidblockFree(Block *b){ if(b == nil) return; if(--b->ref > 0) return; assert(b->ref == 0);}Paq*paqWalk(Paq *s, char *name){ Block *ptr, *b; uchar *p, *ep; PaqDir *pd; int i, n; Paq *ss; if(strcmp(name, "..") == 0) return paqCpy(s->up); if(rootfile && s == root){ if(strcmp(name, rootfile->dir->name) == 0) return paqCpy(rootfile); return nil; } ptr = blockLoad(s->dir->offset, PointerBlock); if(ptr == nil) return nil; for(i=0; i<blocksize/4; i++) { b = blockLoad(getl(ptr->data+i*4), DirBlock); if(b == nil) break; p = b->data; ep = p + blocksize; while(checkDirSize(p, ep)) { n = gets(p); pd = getDir(p); if(strcmp(pd->name, name) == 0) { ss = emallocz(sizeof(Paq)); ss->ref = 1; ss->up = paqCpy(s); ss->dir = pd; ss->qid = paqDirQid(pd); blockFree(b); blockFree(ptr); return ss; } paqDirFree(pd); p += n; } blockFree(b); } blockFree(ptr); return nil;}Fid *newfid(int fid){ Fid *f, *ff; ff = 0; for(f = fids; f; f = f->next) if(f->fid == fid) return f; else if(!ff && !f->busy) ff = f; if(ff){ ff->fid = fid; return ff; } f = emallocz(sizeof *f); f->fid = fid; f->next = fids; fids = f; return f;}voidio(int fd){ char *err; int n, pid; uchar *mdata; mdata = emalloc(mesgsize); pid = getpid(); for(;;){ n = read9pmsg(fd, mdata, mesgsize); if(n < 0) sysfatal("mount read"); if(n == 0) break; if(convM2S(mdata, n, &rhdr) == 0) continue; if(debug) fprint(2, "paqfs %d:<-%F\n", pid, &rhdr); thdr.data = (char*)mdata + IOHDRSZ; if(!fcalls[rhdr.type]) err = "bad fcall type"; else err = (*fcalls[rhdr.type])(newfid(rhdr.fid)); if(err){ thdr.type = Rerror; thdr.ename = err; }else{ thdr.type = rhdr.type + 1; thdr.fid = rhdr.fid; } thdr.tag = rhdr.tag; if(debug) fprint(2, "paqfs %d:->%F\n", pid, &thdr);/**/ n = convS2M(&thdr, mdata, mesgsize); if(n == 0) sysfatal("convS2M sysfatal on write"); if(write(fd, mdata, n) != n) sysfatal("mount write"); }}intperm(PaqDir *s, char *user, int p){ ulong perm = s->mode; if((p*Pother) & perm) return 1; if((noauth || strcmp(user, s->gid)==0) && ((p*Pgroup) & perm)) return 1; if((noauth || strcmp(user, s->uid)==0) && ((p*Powner) & perm)) return 1; return 0;}voidinit(char *file, int verify){ PaqHeader hdr; PaqTrailer tlr; Dir *dir; int i; uchar *p; DigestState *ds = nil; PaqDir *r; Block *b; ulong offset; inflateinit(); bin = Bopen(file, OREAD); if(bin == nil) sysfatal("could not open file: %s: %r", file); if(verify) ds = sha1(0, 0, 0, 0); readHeader(&hdr, file, ds); blocksize = hdr.blocksize; if(verify) { readBlocks(file, ds); } else { dir = dirstat(file); if(dir == nil) sysfatal("could not stat file: %s: %r", file); offset = dir->length - TrailerSize; free(dir); if(Bseek(bin, offset, 0) != offset) sysfatal("could not seek to trailer: %s", file); } readTrailer(&tlr, file, ds); /* asctime includes a newline - yuk */ fprint(2, "%s: %s", hdr.label, asctime(gmtime(hdr.time))); fprint(2, "fingerprint: "); for(i=0; i<20; i++) fprint(2, "%.2x", tlr.sha1[i]); fprint(2, "\n"); cache = emallocz(cachesize*sizeof(Block)); p = emalloc(cachesize*blocksize); for(i=0; i<cachesize; i++) { cache[i].data = p; p += blocksize; } /* hand craft root */ b = blockLoad(tlr.root, DirBlock); if(b == nil || !checkDirSize(b->data, b->data+blocksize)) sysfatal("could not read root block: %s", file); r = getDir(b->data); blockFree(b); root = emallocz(sizeof(Paq)); root->qid = paqDirQid(r); root->ref = 1; root->dir = r; root->up = root; /* parent of root is root */ /* craft root directory if root is a normal file */ if(!(root->qid.type&QTDIR)){ rootfile = root; root = emallocz(sizeof(Paq)); root->qid = rootfile->qid; root->qid.type |= QTDIR; root->qid.path++; root->ref = 1; root->dir = emallocz(sizeof(PaqDir)); *root->dir = *r; root->dir->mode |= DMDIR|0111; root->up = root; }}intblockRead(uchar *data, ulong addr, int type){ uchar buf[BlockSize]; PaqBlock b; uchar *cdat; if(Bseek(bin, addr, 0) != addr){ fprint(2, "paqfs: seek %lud: %r\n", addr); return 0; } if(Bread(bin, buf, BlockSize) != BlockSize){ fprint(2, "paqfs: read %d at %lud: %r\n", BlockSize, addr); return 0; } getBlock(buf, &b); if(b.magic != BlockMagic || b.size > blocksize || b.type != type){ fprint(2, "paqfs: bad block: magic %.8lux (want %.8ux) size %lud (max %d) type %ud (want %ud)\n", b.magic, BlockMagic, b.size, blocksize, b.type, type); return 0; } switch(b.encoding) { default: return 0; case NoEnc: if(Bread(bin, data, blocksize) < blocksize) return 0; break; case DeflateEnc: cdat = emalloc(b.size); if(Bread(bin, cdat, b.size) < b.size) { free(cdat); return 0; } if(inflateblock(data, blocksize, cdat, b.size) < 0) { fprint(2, "inflate error: %r\n"); free(cdat); return 0; } free(cdat); break; } if(adler32(0, data, blocksize) != b.adler32) return 0; return 1;}voidreadHeader(PaqHeader *hdr, char *name, DigestState *ds){ uchar buf[HeaderSize]; if(Bread(bin, buf, HeaderSize) < HeaderSize) sysfatal("could not read header: %s: %r", name); if(ds) sha1(buf, HeaderSize, 0, ds); getHeader(buf, hdr); if(hdr->magic != HeaderMagic) sysfatal("bad header magic 0x%lux: %s", hdr->magic, name); if(hdr->version != Version) sysfatal("unknown file version: %s", name);}voidreadBlocks(char *name, DigestState *ds){ uchar *buf; PaqBlock b; buf = emalloc(BlockSize+blocksize); for(;;) { if(Bread(bin, buf, 4) < 4) sysfatal("could not read block: %s: %r", name); Bseek(bin, -4, 1); /* check if it is a data block */ if(getl(buf) != BlockMagic) break; if(Bread(bin, buf, BlockSize) < BlockSize) sysfatal("could not read block: %s: %r", name); if(ds) sha1(buf, BlockSize, 0, ds); getBlock(buf, &b); if(b.size > blocksize) sysfatal("bad block size: %lud: %s", b.size, name); if(ds) { if(Bread(bin, buf, b.size) < b.size) sysfatal("sysfatal reading block: %s: %r", name); sha1(buf, b.size, 0, ds); } else Bseek(bin, b.size, 1); } free(buf);}voidreadTrailer(PaqTrailer *tlr, char *name, DigestState *ds){ uchar buf[TrailerSize]; uchar digest[20]; if(Bread(bin, buf, TrailerSize) < TrailerSize) sysfatal("could not read trailer: %s: %r", name); getTrailer(buf, tlr); if(tlr->magic != TrailerMagic) sysfatal("bad trailer magic: %s", name); if(ds) { sha1(buf, TrailerSize-20, digest, ds); if(memcmp(digest, tlr->sha1, 20) != 0) sysfatal("bad sha1 digest: %s", name); }}void *emalloc(ulong n){ void *p; p = malloc(n); if(!p) sysfatal("out of memory"); return p;}void *emallocz(ulong n){ void *p; p = emalloc(n); memset(p, 0, n); return p;}void *erealloc(void *p, ulong n){ p = realloc(p, n); if(!p) sysfatal("out of memory"); return p;}char *estrdup(char *s){ s = strdup(s); if(s == nil) sysfatal("out of memory"); return s;}ulonggetl(uchar *p){ return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];}intgets(uchar *p){ return (p[0]<<8) | p[1];}intcheckDirSize(uchar *p, uchar *ep){ int n; int i; if(ep-p < 2) return 0; n = gets(p); if(p+n > ep) return 0; ep = p+n; p += 22; for(i=0; i<3; i++) { if(p+2 > ep) return 0; n = gets(p); if(p+n > ep) return 0; p += n; } return 1;}voidgetHeader(uchar *p, PaqHeader *h){ h->magic = getl(p); h->version = gets(p+4); h->blocksize = gets(p+6); if((h->magic>>16) == BigHeaderMagic){ h->magic = HeaderMagic; h->version = gets(p+2); h->blocksize = getl(p+4); } h->time = getl(p+8); memmove(h->label, p+12, sizeof(h->label)); h->label[sizeof(h->label)-1] = 0;}voidgetTrailer(uchar *p, PaqTrailer *t){ t->magic = getl(p); t->root = getl(p+4); memmove(t->sha1, p+8, 20);}voidgetBlock(uchar *p, PaqBlock *b){ b->magic = getl(p); b->size = gets(p+4); if((b->magic>>16) == BigBlockMagic){ b->magic = BlockMagic; b->size = getl(p+2); } b->type = p[6]; b->encoding = p[7]; b->adler32 = getl(p+8);}PaqDir *getDir(uchar *p){ PaqDir *pd; pd = emallocz(sizeof(PaqDir)); pd->qid = getl(p+2); pd->mode = getl(p+6); pd->mtime = getl(p+10); pd->length = getl(p+14); pd->offset = getl(p+18); p += 22; pd->name = getstr(p); p += gets(p); pd->uid = getstr(p); p += gets(p); pd->gid = getstr(p); return pd;}char *getstr(uchar *p){ char *s; int n; n = gets(p); s = emalloc(n+1); memmove(s, p+2, n); s[n] = 0; return s;}voidusage(void){ fprint(2, "usage: %s [-disv] [-c cachesize] [-m mountpoint] [-M mesgsize] paqfile\n", argv0); exits("usage");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -