📄 mkpaqfs.c
字号:
#include <u.h>#include <libc.h>#include <bio.h>#include <flate.h>#include <mp.h>#include <libsec.h>#include "paqfs.h"enum { OffsetSize = 4, /* size of block offset */};void paqfs(char *root, char *label);PaqDir *paqFile(char *name, Dir *dir);PaqDir *paqDir(char *name, Dir *dir);PaqDir *paqDirAlloc(Dir *d, ulong offset);void paqDirFree(PaqDir *pd);void writeHeader(char *label);void writeTrailer(ulong root);ulong writeBlock(uchar *buf, int type);void usage(void);void outWrite(void *buf, int n);int paqDirSize(PaqDir *dir);void putDir(uchar *p, PaqDir *dir);void putHeader(uchar *p, PaqHeader *h);void putBlock(uchar *p, PaqBlock *h);void putTrailer(uchar *p, PaqTrailer *t);void putl(uchar *p, ulong v);void puts(uchar *p, int x);uchar *putstr(uchar *p, char *s);void *emallocz(int size);void warn(char *fmt, ...);int uflag=0; /* uncompressed */long blocksize = 4*1024;Biobuf *out;DigestState *outdg;voidmain(int argc, char *argv[]){ char *s, *ss; char *outfile = nil; char *label = nil; char *file; ARGBEGIN { case 'u': uflag=1; break; case 'o': outfile = ARGF(); break; case 'l': label = ARGF(); if(label == nil) usage(); break; case 'b': s = ARGF(); if(s) { blocksize = strtoul(s, &ss, 0); if(s == ss) usage(); if(*ss == 'k') blocksize *= 1024; } if(blocksize < MinBlockSize) sysfatal("blocksize too small: must be at lease %d", MinBlockSize); if(blocksize > MaxBlockSize) sysfatal("blocksize too large: must be no greater than %d", MaxBlockSize); break; } ARGEND if(outfile == nil) { out = emallocz(sizeof(Biobuf)); Binit(out, 1, OWRITE); } else { out = Bopen(outfile, OWRITE|OTRUNC); if(out == nil) sysfatal("could not create file: %s: %r", outfile); } deflateinit(); file = argv[0]; if(file == nil) file = "."; if(label == nil) { if(strrchr(file, '/')) label = strrchr(file, '/') + 1; else label = file; } paqfs(file, label); Bterm(out); exits(0);}voidusage(void){ fprint(2, "usage: %s [-u] [-b blocksize] -o output [root]\n", argv0); exits("usage");}voidpaqfs(char *root, char *label){ Dir *dir; PaqDir *pd; ulong offset; uchar *buf; dir = dirstat(root); if(dir == nil) sysfatal("could not stat root: %s: %r", root); writeHeader(label); if(dir->mode & DMDIR) pd = paqDir(root, dir); else pd = paqFile(root, dir); buf = emallocz(blocksize); putDir(buf, pd); offset = writeBlock(buf, DirBlock); writeTrailer(offset); paqDirFree(pd); free(dir);}PaqDir *paqFile(char *name, Dir *dir){ int fd, n, nn, nb; vlong tot; uchar *block, *pointer; ulong offset; fd = open(name, OREAD); if(fd < 0) { warn("could not open file: %s: %r", name); return nil; } block = emallocz(blocksize); pointer = emallocz(blocksize); nb = 0; n = 0; tot = 0; for(;;) { nn = read(fd, block+n, blocksize-n); if(nn < 0) { warn("read failed: %s: %r", name); goto Err; } tot += nn; if(nn == 0) { if(n == 0) break; /* pad out last block */ memset(block+n, 0, blocksize-n); nn = blocksize - n; } n += nn; if(n < blocksize) continue; if(nb >= blocksize/OffsetSize) { warn("file too big for blocksize: %s", name); goto Err; } offset = writeBlock(block, DataBlock); putl(pointer+nb*OffsetSize, offset); nb++; n = 0; } offset = writeBlock(pointer, PointerBlock); close(fd); free(pointer); free(block); dir->length = tot; return paqDirAlloc(dir, offset);Err: close(fd); free(pointer); free(block); return nil;}PaqDir *paqDir(char *name, Dir *dir){ Dir *dirs, *p; PaqDir *pd; int i, n, nb, fd, ndir; uchar *block, *pointer; char *nname; ulong offset; fd = open(name, OREAD); if(fd < 0) { warn("could not open directory: %s: %r", name); return nil; } ndir = dirreadall(fd, &dirs); close(fd); if(ndir < 0) { warn("could not read directory: %s: %r", name); return nil; } block = emallocz(blocksize); pointer = emallocz(blocksize); nb = 0; n = 0; nname = nil; pd = nil; for(i=0; i<ndir; i++) { p = dirs + i; free(nname); nname = emallocz(strlen(name) + strlen(p->name) + 2); sprint(nname, "%s/%s", name, p->name); if(p->mode & DMDIR) pd = paqDir(nname, p); else pd = paqFile(nname, p); if(pd == nil) continue; if(n+paqDirSize(pd) >= blocksize) { /* zero fill the block */ memset(block+n, 0, blocksize-n); offset = writeBlock(block, DirBlock); n = 0; if(nb >= blocksize/OffsetSize) { warn("directory too big for blocksize: %s", nname); goto Err; } putl(pointer+nb*OffsetSize, offset); nb++; } if(n+paqDirSize(pd) >= blocksize) { warn("directory entry does not fit in a block: %s", nname); paqDirFree(pd); continue; } putDir(block+n, pd); n += paqDirSize(pd); paqDirFree(pd); pd = nil; } if(n > 0) { /* zero fill the block */ memset(block+n, 0, blocksize-n); offset = writeBlock(block, DirBlock); if(nb >= blocksize/OffsetSize) { warn("directory too big for blocksize: %s", nname); goto Err; } putl(pointer+nb*OffsetSize, offset); } offset = writeBlock(pointer, PointerBlock); free(nname); free(dirs); paqDirFree(pd); free(block); free(pointer); return paqDirAlloc(dir, offset);Err: free(nname); free(dirs); paqDirFree(pd); free(block); free(pointer); return nil;}PaqDir *paqDirAlloc(Dir *dir, ulong offset){ PaqDir *pd; static ulong qid = 1; pd = emallocz(sizeof(PaqDir)); pd->name = strdup(dir->name); pd->qid = qid++; pd->mode = dir->mode & (DMDIR|DMAPPEND|0777); pd->mtime = dir->mtime; pd->length = dir->length; pd->uid = strdup(dir->uid); pd->gid = strdup(dir->gid); pd->offset = offset; return pd;}voidpaqDirFree(PaqDir *pd){ if(pd == nil) return; free(pd->name); free(pd->uid); free(pd->gid); free(pd);}voidwriteHeader(char *label){ PaqHeader hdr; uchar buf[HeaderSize]; memset(&hdr, 0, sizeof(hdr)); hdr.magic = HeaderMagic; hdr.version = Version; hdr.blocksize = blocksize; hdr.time = time(nil); strncpy(hdr.label, label, sizeof(hdr.label)); hdr.label[sizeof(hdr.label)-1] = 0; putHeader(buf, &hdr); outWrite(buf, sizeof(buf));}voidwriteTrailer(ulong root){ PaqTrailer tlr; uchar buf[TrailerSize]; memset(&tlr, 0, sizeof(tlr)); tlr.magic = TrailerMagic; tlr.root = root; putTrailer(buf, &tlr); outWrite(buf, sizeof(buf));}ulongwriteBlock(uchar *b, int type){ uchar *cb, *ob; int n; PaqBlock bh; uchar buf[BlockSize]; ulong offset; offset = Boffset(out); bh.magic = BlockMagic; bh.size = blocksize; bh.type = type; bh.encoding = NoEnc; bh.adler32 = adler32(0, b, blocksize); ob = b; if(!uflag) { cb = emallocz(blocksize); n = deflateblock(cb, blocksize, b, blocksize, 6, 0); if(n > 0 && n < blocksize) { bh.encoding = DeflateEnc; bh.size = n; ob = cb; } } putBlock(buf, &bh); outWrite(buf, sizeof(buf)); outWrite(ob, bh.size); if(ob != b) free(ob); return offset;}voidoutWrite(void *buf, int n){ if(Bwrite(out, buf, n) < n) sysfatal("write failed: %r"); outdg = sha1((uchar*)buf, n, nil, outdg);}intpaqDirSize(PaqDir *d){ return MinDirSize + strlen(d->name) + strlen(d->uid) + strlen(d->gid);}voidputHeader(uchar *p, PaqHeader *h){ if(h->blocksize < 65536){ putl(p, h->magic); puts(p+4, h->version); puts(p+6, h->blocksize); }else{ assert(h->magic == HeaderMagic); puts(p, BigHeaderMagic); puts(p+2, h->version); putl(p+4, h->blocksize); } putl(p+8, h->time); memmove(p+12, h->label, sizeof(h->label));}voidputTrailer(uchar *p, PaqTrailer *h){ putl(p, h->magic); putl(p+4, h->root); outdg = sha1(p, 8, p+8, outdg);}voidputBlock(uchar *p, PaqBlock *b){ if(b->size < 65536){ putl(p, b->magic); puts(p+4, b->size); }else{ assert(b->magic == BlockMagic); puts(p, BigBlockMagic); putl(p+2, b->size); } p[6] = b->type; p[7] = b->encoding; putl(p+8, b->adler32);}voidputDir(uchar *p, PaqDir *d){ uchar *q; puts(p, paqDirSize(d)); putl(p+2, d->qid); putl(p+6, d->mode); putl(p+10, d->mtime); putl(p+14, d->length); putl(p+18, d->offset); q = putstr(p+22, d->name); q = putstr(q, d->uid); q = putstr(q, d->gid); assert(q-p == paqDirSize(d));}voidputl(uchar *p, ulong v){ p[0] = v>>24; p[1] = v>>16; p[2] = v>>8; p[3] = v;}voidputs(uchar *p, int v){ assert(v < (1<<16)); p[0] = v>>8; p[1] = v;}uchar *putstr(uchar *p, char *s){ int n = strlen(s); puts(p, n+2); memmove(p+2, s, n); return p+2+n;}void *emallocz(int size){ void *p; p = malloc(size); if(p == nil) sysfatal("malloc failed"); memset(p, 0, size); return p;}voidwarn(char *fmt, ...){ char buf[1024]; va_list arg; va_start(arg, fmt); vseprint(buf, buf+sizeof(buf), fmt, arg); va_end(arg); fprint(2, "%s: %s\n", argv0, buf);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -