📄 vac.c
字号:
ln = smprint("%s/%s", lname, name); sn = smprint("%s/%s", sname, name); if (ln == nil || sn == nil) sysfatal("out of memory"); if(vf != nil) vvf = vfWalk(vf, name); else vvf = nil; vacFile(ds, ln, sn, vvf); if(vvf != nil) vfDecRef(vvf); free(ln); free(sn); } free(dirs); } dirSinkClose(ds); dirSinkWriteSink(dsink, ds->sink); dirSinkWriteSink(dsink, ds->msink->sink); dirSinkFree(ds);}static intvacMergeFile(DirSink *dsink, VacFile *vf, VacDir *dir, uvlong offset, uvlong *max){ uchar buf[VtEntrySize]; VtEntry dd, md; int e; if(vfRead(vf, buf, VtEntrySize, (uvlong)dir->entry*VtEntrySize) != VtEntrySize) { warn("could not read venti dir entry: %s\n", dir->elem); return 0; } vtEntryUnpack(&dd, buf, 0); if(dir->mode & ModeDir) { e = dir->mentry; if(e == 0) e = dir->entry + 1; if(vfRead(vf, buf, VtEntrySize, e*VtEntrySize) != VtEntrySize) { warn("could not read venti dir entry: %s\n", dir->elem); return 0; } vtEntryUnpack(&md, buf, 0); } /* max might be incorrect in some old dumps */ if(dir->qid >= *max) { warn("qid out of range: %s", dir->elem); *max = dir->qid; } dir->qid += offset; dir->entry = dsink->nentry; if(dir->qidSpace) { dir->qidOffset += offset; } else { dir->qidSpace = 1; dir->qidOffset = offset; dir->qidMax = *max; } dirSinkWrite(dsink, &dd); if(dir->mode & ModeDir) dirSinkWrite(dsink, &md); metaSinkWriteDir(dsink->msink, dir); return 1;}static intvacMerge(DirSink *dsink, char *lname, char *sname){ char *p; VacFS *fs; VacFile *vf; VacDirEnum *d; VacDir dir; uvlong max; p = strrchr(sname, '.'); if(p == 0 || strcmp(p, ".vac")) return 0; d = nil; fs = vfsOpen(dsink->sink->z, sname, 1, 100); if(fs == nil) return 0; vf = vfOpen(fs, "/"); if(vf == nil) goto Done; max = vfGetId(vf); d = vdeOpen(fs, "/"); if(d == nil) goto Done; if(verbose) fprint(2, "%s: merging: %s\n", argv0, lname); if(maxbsize < vfsGetBlockSize(fs)) maxbsize = vfsGetBlockSize(fs); for(;;) { if(vdeRead(d, &dir, 1) < 1) break; vacMergeFile(dsink, vf, &dir, fileid, &max); vdCleanup(&dir); } fileid += max;Done: if(d != nil) vdeFree(d); if(vf != nil) vfDecRef(vf); vfsClose(fs); return 1;}Sink *sinkAlloc(VtSession *z, int psize, int dsize){ Sink *k; int i; if(psize < 512 || psize > VtMaxLumpSize) vtFatal("sinkAlloc: bad psize"); if(dsize < 512 || dsize > VtMaxLumpSize) vtFatal("sinkAlloc: bad psize"); psize = VtScoreSize*(psize/VtScoreSize); k = vtMemAllocZ(sizeof(Sink)); k->z = z; k->dir.flags = VtEntryActive; k->dir.psize = psize; k->dir.dsize = dsize; k->buf = vtMemAllocZ(VtPointerDepth*k->dir.psize + VtScoreSize); for(i=0; i<=VtPointerDepth; i++) k->pbuf[i] = k->buf + i*k->dir.psize; return k;}voidsinkWriteScore(Sink *k, uchar score[VtScoreSize], int n){ int i; uchar *p; VtEntry *d; memmove(k->pbuf[0], score, VtScoreSize); d = &k->dir; for(i=0; i<VtPointerDepth; i++) { k->pbuf[i] += VtScoreSize; if(k->pbuf[i] < k->buf + d->psize*(i+1)) break; if(i == VtPointerDepth-1) vtFatal("file too big"); p = k->buf+i*d->psize; stats.meta++; if(!vacWrite(k->z, k->pbuf[i+1], VtPointerType0+i, p, d->psize)) vtFatal("vacWrite failed: %s", vtGetError()); k->pbuf[i] = p; } /* round size up to multiple of dsize */ d->size = d->dsize * ((d->size + d->dsize-1)/d->dsize); d->size += n;}voidsinkWrite(Sink *k, uchar *p, int n){ int type; uchar score[VtScoreSize]; if(n > k->dir.dsize) vtFatal("sinkWrite: size too big"); if(k->dir.flags & VtEntryDir) { type = VtDirType; stats.meta++; } else { type = VtDataType; stats.data++; } if(!vacWrite(k->z, score, type, p, n)) vtFatal("vacWrite failed: %s", vtGetError()); sinkWriteScore(k, score, n);}static intsizeToDepth(uvlong s, int psize, int dsize){ int np; int d; /* determine pointer depth */ np = psize/VtScoreSize; s = (s + dsize - 1)/dsize; for(d = 0; s > 1; d++) s = (s + np - 1)/np; return d;}voidsinkClose(Sink *k){ int i, n; uchar *p; VtEntry *kd; kd = &k->dir; /* empty */ if(kd->size == 0) { memmove(kd->score, vtZeroScore, VtScoreSize); return; } for(n=VtPointerDepth-1; n>0; n--) if(k->pbuf[n] > k->buf + kd->psize*n) break; kd->depth = sizeToDepth(kd->size, kd->psize, kd->dsize); /* skip full part of tree */ for(i=0; i<n && k->pbuf[i] == k->buf + kd->psize*i; i++) ; /* is the tree completely full */ if(i == n && k->pbuf[n] == k->buf + kd->psize*n + VtScoreSize) { memmove(kd->score, k->pbuf[n] - VtScoreSize, VtScoreSize); return; } n++; /* clean up the edge */ for(; i<n; i++) { p = k->buf+i*kd->psize; stats.meta++; if(!vacWrite(k->z, k->pbuf[i+1], VtPointerType0+i, p, k->pbuf[i]-p)) vtFatal("vacWrite failed: %s", vtGetError()); k->pbuf[i+1] += VtScoreSize; } memmove(kd->score, k->pbuf[i] - VtScoreSize, VtScoreSize);}voidsinkFree(Sink *k){ vtMemFree(k->buf); vtMemFree(k);}DirSink *dirSinkAlloc(VtSession *z, int psize, int dsize){ DirSink *k; int ds; ds = VtEntrySize*(dsize/VtEntrySize); k = vtMemAllocZ(sizeof(DirSink)); k->sink = sinkAlloc(z, psize, ds); k->sink->dir.flags |= VtEntryDir; k->msink = metaSinkAlloc(z, psize, dsize); k->buf = vtMemAlloc(ds); k->p = k->buf; k->ep = k->buf + ds; return k;}voiddirSinkWrite(DirSink *k, VtEntry *dir){ if(k->p + VtEntrySize > k->ep) { sinkWrite(k->sink, k->buf, k->p - k->buf); k->p = k->buf; } vtEntryPack(dir, k->p, 0); k->nentry++; k->p += VtEntrySize;}voiddirSinkWriteSink(DirSink *k, Sink *sink){ dirSinkWrite(k, &sink->dir);}intdirSinkWriteFile(DirSink *k, VacFile *vf){ VtEntry dir; if(!vfGetVtEntry(vf, &dir)) return 0; dirSinkWrite(k, &dir); return 1;}voiddirSinkClose(DirSink *k){ metaSinkClose(k->msink); if(k->p != k->buf) sinkWrite(k->sink, k->buf, k->p - k->buf); sinkClose(k->sink);}voiddirSinkFree(DirSink *k){ sinkFree(k->sink); metaSinkFree(k->msink); vtMemFree(k->buf); vtMemFree(k);}MetaSink *metaSinkAlloc(VtSession *z, int psize, int dsize){ MetaSink *k; k = vtMemAllocZ(sizeof(MetaSink)); k->sink = sinkAlloc(z, psize, dsize); k->buf = vtMemAlloc(dsize); k->maxindex = dsize/100; /* 100 byte entries seems reasonable */ if(k->maxindex < 1) k->maxindex = 1; k->rp = k->p = k->buf + MetaHeaderSize + k->maxindex*MetaIndexSize; k->ep = k->buf + dsize; return k;}/* hack to get base to compare routine - not reentrant */uchar *blockBase;intdirCmp(void *p0, void *p1){ uchar *q0, *q1; int n0, n1, r; /* name is first element of entry */ q0 = p0; q0 = blockBase + (q0[0]<<8) + q0[1]; n0 = (q0[6]<<8) + q0[7]; q0 += 8; q1 = p1; q1 = blockBase + (q1[0]<<8) + q1[1]; n1 = (q1[6]<<8) + q1[7]; q1 += 8; if(n0 == n1) return memcmp(q0, q1, n0); else if (n0 < n1) { r = memcmp(q0, q1, n0); return (r==0)?1:r; } else { r = memcmp(q0, q1, n1); return (r==0)?-1:r; }}voidmetaSinkFlush(MetaSink *k){ uchar *p; int n; MetaBlock mb; if(k->nindex == 0) return; assert(k->nindex <= k->maxindex); p = k->buf; n = k->rp - p; mb.size = n; mb.free = 0; mb.nindex = k->nindex; mb.maxindex = k->maxindex; mb.buf = p; mbPack(&mb); p += MetaHeaderSize; /* XXX this is not reentrant! */ blockBase = k->buf; qsort(p, k->nindex, MetaIndexSize, dirCmp); p += k->nindex*MetaIndexSize; memset(p, 0, (k->maxindex-k->nindex)*MetaIndexSize); p += (k->maxindex-k->nindex)*MetaIndexSize; sinkWrite(k->sink, k->buf, n); /* move down partial entry */ n = k->p - k->rp; memmove(p, k->rp, n); k->rp = p; k->p = p + n; k->nindex = 0;}voidmetaSinkPutc(MetaSink *k, int c){ if(k->p+1 > k->ep) metaSinkFlush(k); if(k->p+1 > k->ep) vtFatal("directory entry too large"); k->p[0] = c; k->p++;}voidmetaSinkPutString(MetaSink *k, char *s){ int n = strlen(s); metaSinkPutc(k, n>>8); metaSinkPutc(k, n); metaSinkWrite(k, (uchar*)s, n);}voidmetaSinkPutUint32(MetaSink *k, ulong x){ metaSinkPutc(k, x>>24); metaSinkPutc(k, x>>16); metaSinkPutc(k, x>>8); metaSinkPutc(k, x);}voidmetaSinkPutUint64(MetaSink *k, uvlong x){ metaSinkPutUint32(k, x>>32); metaSinkPutUint32(k, x);}voidmetaSinkWrite(MetaSink *k, uchar *data, int n){ if(k->p + n > k->ep) metaSinkFlush(k); if(k->p + n > k->ep) vtFatal("directory entry too large"); memmove(k->p, data, n); k->p += n;}voidmetaSinkWriteDir(MetaSink *ms, VacDir *dir){ metaSinkPutUint32(ms, DirMagic); metaSinkPutc(ms, Version>>8); metaSinkPutc(ms, Version); metaSinkPutString(ms, dir->elem); metaSinkPutUint32(ms, dir->entry); metaSinkPutUint64(ms, dir->qid); metaSinkPutString(ms, dir->uid); metaSinkPutString(ms, dir->gid); metaSinkPutString(ms, dir->mid); metaSinkPutUint32(ms, dir->mtime); metaSinkPutUint32(ms, dir->mcount); metaSinkPutUint32(ms, dir->ctime); metaSinkPutUint32(ms, dir->atime); metaSinkPutUint32(ms, dir->mode); if(dir->plan9) { metaSinkPutc(ms, DirPlan9Entry); /* plan9 extra info */ metaSinkPutc(ms, 0); /* plan9 extra size */ metaSinkPutc(ms, 12); /* plan9 extra size */ metaSinkPutUint64(ms, dir->p9path); metaSinkPutUint32(ms, dir->p9version); } if(dir->qidSpace != 0) { metaSinkPutc(ms, DirQidSpaceEntry); metaSinkPutc(ms, 0); metaSinkPutc(ms, 16); metaSinkPutUint64(ms, dir->qidOffset); metaSinkPutUint64(ms, dir->qidMax); } if(dir->gen != 0) { metaSinkPutc(ms, DirGenEntry); metaSinkPutc(ms, 0); metaSinkPutc(ms, 4); metaSinkPutUint32(ms, dir->gen); } metaSinkEOR(ms);}voidplan9ToVacDir(VacDir *vd, Dir *dir, ulong entry, uvlong qid){ memset(vd, 0, sizeof(VacDir)); vd->elem = vtStrDup(dir->name); vd->entry = entry; vd->qid = qid; vd->uid = vtStrDup(dir->uid); vd->gid = vtStrDup(dir->gid); vd->mid = vtStrDup(dir->muid); vd->mtime = dir->mtime; vd->mcount = 0; vd->ctime = dir->mtime; /* ctime: not available on plan 9 */ vd->atime = dir->atime; vd->mode = dir->mode & 0777; if(dir->mode & DMDIR) vd->mode |= ModeDir; if(dir->mode & DMAPPEND) vd->mode |= ModeAppend; if(dir->mode & DMEXCL) vd->mode |= ModeExclusive; vd->plan9 = 1; vd->p9path = dir->qid.path; vd->p9version = dir->qid.vers;}voidmetaSinkEOR(MetaSink *k){ uchar *p; int o, n; p = k->buf + MetaHeaderSize; p += k->nindex * MetaIndexSize; o = k->rp-k->buf; /* offset from start of block */ n = k->p-k->rp; /* size of entry */ p[0] = o >> 8; p[1] = o; p[2] = n >> 8; p[3] = n; k->rp = k->p; k->nindex++; if(k->nindex == k->maxindex) metaSinkFlush(k);}voidmetaSinkClose(MetaSink *k){ metaSinkFlush(k); sinkClose(k->sink);}voidmetaSinkFree(MetaSink *k){ sinkFree(k->sink); vtMemFree(k->buf); vtMemFree(k);}static voidwarn(char *fmt, ...){ va_list arg; va_start(arg, fmt); fprint(2, "%s: ", argv0); vfprint(2, fmt, arg); fprint(2, "\n"); va_end(arg);}static voidcleanup(void){ if(oname != nil) remove(oname);}#define TWID64 ((u64int)~(u64int)0)static u64intunittoull(char *s){ char *es; u64int n; if(s == nil) return TWID64; n = strtoul(s, &es, 0); if(*es == 'k' || *es == 'K'){ n *= 1024; es++; }else if(*es == 'm' || *es == 'M'){ n *= 1024*1024; es++; }else if(*es == 'g' || *es == 'G'){ n *= 1024*1024*1024; es++; } if(*es != '\0') return TWID64; return n;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -