123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512 |
- #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;
- void
- main(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);
- }
- void
- usage(void)
- {
- fprint(2, "usage: %s [-u] [-b blocksize] -o output [root]\n", argv0);
- exits("usage");
- }
- void
- paqfs(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;
- }
- void
- paqDirFree(PaqDir *pd)
- {
- if(pd == nil)
- return;
- free(pd->name);
- free(pd->uid);
- free(pd->gid);
- free(pd);
- }
- void
- writeHeader(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));
- }
- void
- writeTrailer(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));
- }
- ulong
- writeBlock(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;
- }
- void
- outWrite(void *buf, int n)
- {
- if(Bwrite(out, buf, n) < n)
- sysfatal("write failed: %r");
- outdg = sha1((uchar*)buf, n, nil, outdg);
- }
- int
- paqDirSize(PaqDir *d)
- {
- return MinDirSize + strlen(d->name) + strlen(d->uid) + strlen(d->gid);
- }
- void
- putHeader(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));
- }
- void
- putTrailer(uchar *p, PaqTrailer *h)
- {
- putl(p, h->magic);
- putl(p+4, h->root);
- outdg = sha1(p, 8, p+8, outdg);
- }
- void
- putBlock(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);
- }
- void
- putDir(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));
- }
- void
- putl(uchar *p, ulong v)
- {
- p[0] = v>>24;
- p[1] = v>>16;
- p[2] = v>>8;
- p[3] = v;
- }
- void
- puts(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;
- }
- void
- warn(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);
- }
|