10 OffsetSize = 4, /* size of block offset */
13 void paqfs(char *root, char *label);
14 PaqDir *paqFile(char *name, Dir *dir);
15 PaqDir *paqDir(char *name, Dir *dir);
16 PaqDir *paqDirAlloc(Dir *d, ulong offset);
17 void paqDirFree(PaqDir *pd);
18 void writeHeader(char *label);
19 void writeTrailer(ulong root);
20 ulong writeBlock(uchar *buf, int type);
22 void outWrite(void *buf, int n);
23 int paqDirSize(PaqDir *dir);
24 void putDir(uchar *p, PaqDir *dir);
25 void putHeader(uchar *p, PaqHeader *h);
26 void putBlock(uchar *p, PaqBlock *h);
27 void putTrailer(uchar *p, PaqTrailer *t);
28 void putl(uchar *p, ulong v);
29 void puts(uchar *p, int x);
30 uchar *putstr(uchar *p, char *s);
31 void *emallocz(int size);
32 void warn(char *fmt, ...);
34 int uflag=0; /* uncompressed */
35 long blocksize = 4*1024;
41 main(int argc, char *argv[])
63 blocksize = strtoul(s, &ss, 0);
69 if(blocksize < MinBlockSize)
70 sysfatal("blocksize too small: must be at least %d", MinBlockSize);
71 if(blocksize > MaxBlockSize)
72 sysfatal("blocksize too large: must be no greater than %d", MaxBlockSize);
77 out = emallocz(sizeof(Biobuf));
78 Binit(out, 1, OWRITE);
80 out = Bopen(outfile, OWRITE|OTRUNC);
82 sysfatal("could not create file: %s: %r", outfile);
92 if(strrchr(file, '/'))
93 label = strrchr(file, '/') + 1;
108 fprint(2, "usage: %s [-u] [-b blocksize] -o output [root]\n", argv0);
113 paqfs(char *root, char *label)
122 sysfatal("could not stat root: %s: %r", root);
124 if(dir->mode & DMDIR)
125 pd = paqDir(root, dir);
127 pd = paqFile(root, dir);
128 buf = emallocz(blocksize);
130 offset = writeBlock(buf, DirBlock);
131 writeTrailer(offset);
138 paqFile(char *name, Dir *dir)
142 uchar *block, *pointer;
145 fd = open(name, OREAD);
147 warn("could not open file: %s: %r", name);
151 block = emallocz(blocksize);
152 pointer = emallocz(blocksize);
157 nn = read(fd, block+n, blocksize-n);
159 warn("read failed: %s: %r", name);
166 /* pad out last block */
167 memset(block+n, 0, blocksize-n);
173 if(nb >= blocksize/OffsetSize) {
174 warn("file too big for blocksize: %s", name);
177 offset = writeBlock(block, DataBlock);
178 putl(pointer+nb*OffsetSize, offset);
183 offset = writeBlock(pointer, PointerBlock);
189 return paqDirAlloc(dir, offset);
198 paqDir(char *name, Dir *dir)
202 int i, n, nb, fd, ndir;
203 uchar *block, *pointer;
207 fd = open(name, OREAD);
209 warn("could not open directory: %s: %r", name);
213 ndir = dirreadall(fd, &dirs);
217 warn("could not read directory: %s: %r", name);
221 block = emallocz(blocksize);
222 pointer = emallocz(blocksize);
228 for(i=0; i<ndir; i++) {
231 nname = emallocz(strlen(name) + strlen(p->name) + 2);
232 sprint(nname, "%s/%s", name, p->name);
234 pd = paqDir(nname, p);
236 pd = paqFile(nname, p);
240 if(n+paqDirSize(pd) >= blocksize) {
242 /* zero fill the block */
243 memset(block+n, 0, blocksize-n);
244 offset = writeBlock(block, DirBlock);
246 if(nb >= blocksize/OffsetSize) {
247 warn("directory too big for blocksize: %s", nname);
250 putl(pointer+nb*OffsetSize, offset);
253 if(n+paqDirSize(pd) >= blocksize) {
254 warn("directory entry does not fit in a block: %s", nname);
265 /* zero fill the block */
266 memset(block+n, 0, blocksize-n);
267 offset = writeBlock(block, DirBlock);
268 if(nb >= blocksize/OffsetSize) {
269 warn("directory too big for blocksize: %s", nname);
272 putl(pointer+nb*OffsetSize, offset);
274 offset = writeBlock(pointer, PointerBlock);
281 return paqDirAlloc(dir, offset);
292 paqDirAlloc(Dir *dir, ulong offset)
295 static ulong qid = 1;
297 pd = emallocz(sizeof(PaqDir));
299 pd->name = strdup(dir->name);
301 pd->mode = dir->mode & (DMDIR|DMAPPEND|0777);
302 pd->mtime = dir->mtime;
303 pd->length = dir->length;
304 pd->uid = strdup(dir->uid);
305 pd->gid = strdup(dir->gid);
312 paqDirFree(PaqDir *pd)
324 writeHeader(char *label)
327 uchar buf[HeaderSize];
329 memset(&hdr, 0, sizeof(hdr));
330 hdr.magic = HeaderMagic;
331 hdr.version = Version;
332 hdr.blocksize = blocksize;
333 hdr.time = time(nil);
334 strncpy(hdr.label, label, sizeof(hdr.label));
335 hdr.label[sizeof(hdr.label)-1] = 0;
336 putHeader(buf, &hdr);
337 outWrite(buf, sizeof(buf));
341 writeTrailer(ulong root)
344 uchar buf[TrailerSize];
346 memset(&tlr, 0, sizeof(tlr));
347 tlr.magic = TrailerMagic;
349 putTrailer(buf, &tlr);
350 outWrite(buf, sizeof(buf));
354 writeBlock(uchar *b, int type)
359 uchar buf[BlockSize];
362 offset = Boffset(out);
364 bh.magic = BlockMagic;
368 bh.adler32 = adler32(0, b, blocksize);
372 cb = emallocz(blocksize);
373 n = deflateblock(cb, blocksize, b, blocksize, 6, 0);
374 if(n > 0 && n < blocksize) {
375 bh.encoding = DeflateEnc;
382 outWrite(buf, sizeof(buf));
383 outWrite(ob, bh.size);
392 outWrite(void *buf, int n)
394 if(Bwrite(out, buf, n) < n)
395 sysfatal("write failed: %r");
396 outdg = sha1((uchar*)buf, n, nil, outdg);
400 paqDirSize(PaqDir *d)
402 return MinDirSize + strlen(d->name) + strlen(d->uid) + strlen(d->gid);
406 putHeader(uchar *p, PaqHeader *h)
408 if(h->blocksize < 65536){
410 puts(p+4, h->version);
411 puts(p+6, h->blocksize);
413 assert(h->magic == HeaderMagic);
414 puts(p, BigHeaderMagic);
415 puts(p+2, h->version);
416 putl(p+4, h->blocksize);
419 memmove(p+12, h->label, sizeof(h->label));
423 putTrailer(uchar *p, PaqTrailer *h)
427 outdg = sha1(p, 8, p+8, outdg);
431 putBlock(uchar *p, PaqBlock *b)
437 assert(b->magic == BlockMagic);
438 puts(p, BigBlockMagic);
443 putl(p+8, b->adler32);
447 putDir(uchar *p, PaqDir *d)
451 puts(p, paqDirSize(d));
454 putl(p+10, d->mtime);
455 putl(p+14, d->length);
456 putl(p+18, d->offset);
457 q = putstr(p+22, d->name);
458 q = putstr(q, d->uid);
459 q = putstr(q, d->gid);
460 assert(q-p == paqDirSize(d));
464 putl(uchar *p, ulong v)
473 puts(uchar *p, int v)
481 putstr(uchar *p, char *s)
497 sysfatal("malloc failed");
509 vseprint(buf, buf+sizeof(buf), fmt, arg);
511 fprint(2, "%s: %s\n", argv0, buf);