xref: /plan9/sys/src/cmd/paqfs/mkpaqfs.c (revision fe853e2326f51910bb38886e9bfc22ecdef993d7)
19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <bio.h>
49a747e4fSDavid du Colombier #include <flate.h>
59a747e4fSDavid du Colombier #include <mp.h>
69a747e4fSDavid du Colombier #include <libsec.h>
79a747e4fSDavid du Colombier #include "paqfs.h"
89a747e4fSDavid du Colombier 
99a747e4fSDavid du Colombier enum {
109a747e4fSDavid du Colombier 	OffsetSize = 4,	/* size of block offset */
119a747e4fSDavid du Colombier };
129a747e4fSDavid du Colombier 
139a747e4fSDavid du Colombier void paqfs(char *root, char *label);
149a747e4fSDavid du Colombier PaqDir *paqFile(char *name, Dir *dir);
159a747e4fSDavid du Colombier PaqDir *paqDir(char *name, Dir *dir);
169a747e4fSDavid du Colombier PaqDir *paqDirAlloc(Dir *d, ulong offset);
179a747e4fSDavid du Colombier void paqDirFree(PaqDir *pd);
189a747e4fSDavid du Colombier void writeHeader(char *label);
199a747e4fSDavid du Colombier void writeTrailer(ulong root);
209a747e4fSDavid du Colombier ulong writeBlock(uchar *buf, int type);
219a747e4fSDavid du Colombier void usage(void);
229a747e4fSDavid du Colombier void outWrite(void *buf, int n);
239a747e4fSDavid du Colombier int paqDirSize(PaqDir *dir);
249a747e4fSDavid du Colombier void putDir(uchar *p, PaqDir *dir);
259a747e4fSDavid du Colombier void putHeader(uchar *p, PaqHeader *h);
269a747e4fSDavid du Colombier void putBlock(uchar *p, PaqBlock *h);
279a747e4fSDavid du Colombier void putTrailer(uchar *p, PaqTrailer *t);
289a747e4fSDavid du Colombier void putl(uchar *p, ulong v);
299a747e4fSDavid du Colombier void puts(uchar *p, int x);
309a747e4fSDavid du Colombier uchar *putstr(uchar *p, char *s);
319a747e4fSDavid du Colombier void *emallocz(int size);
329a747e4fSDavid du Colombier void warn(char *fmt, ...);
339a747e4fSDavid du Colombier 
349a747e4fSDavid du Colombier int uflag=0;			/* uncompressed */
359a747e4fSDavid du Colombier long blocksize = 4*1024;
369a747e4fSDavid du Colombier 
379a747e4fSDavid du Colombier Biobuf *out;
389a747e4fSDavid du Colombier DigestState *outdg;
399a747e4fSDavid du Colombier 
409a747e4fSDavid du Colombier void
main(int argc,char * argv[])419a747e4fSDavid du Colombier main(int argc, char *argv[])
429a747e4fSDavid du Colombier {
439a747e4fSDavid du Colombier 	char *s, *ss;
449a747e4fSDavid du Colombier 	char *outfile = nil;
459a747e4fSDavid du Colombier 	char *label = nil;
469a747e4fSDavid du Colombier 	char *file;
479a747e4fSDavid du Colombier 
489a747e4fSDavid du Colombier 	ARGBEGIN {
499a747e4fSDavid du Colombier 	case 'u':
509a747e4fSDavid du Colombier 		uflag=1;
519a747e4fSDavid du Colombier 		break;
529a747e4fSDavid du Colombier 	case 'o':
539a747e4fSDavid du Colombier 		outfile = ARGF();
549a747e4fSDavid du Colombier 		break;
559a747e4fSDavid du Colombier 	case 'l':
569a747e4fSDavid du Colombier 		label = ARGF();
579a747e4fSDavid du Colombier 		if(label == nil)
589a747e4fSDavid du Colombier 			usage();
599a747e4fSDavid du Colombier 		break;
609a747e4fSDavid du Colombier 	case 'b':
619a747e4fSDavid du Colombier 		s = ARGF();
629a747e4fSDavid du Colombier 		if(s) {
639a747e4fSDavid du Colombier 			blocksize = strtoul(s, &ss, 0);
649a747e4fSDavid du Colombier 			if(s == ss)
659a747e4fSDavid du Colombier 				usage();
669a747e4fSDavid du Colombier 			if(*ss == 'k')
679a747e4fSDavid du Colombier 				blocksize *= 1024;
689a747e4fSDavid du Colombier 		}
699a747e4fSDavid du Colombier 		if(blocksize < MinBlockSize)
709a747e4fSDavid du Colombier 			sysfatal("blocksize too small: must be at lease %d", MinBlockSize);
719a747e4fSDavid du Colombier 		if(blocksize > MaxBlockSize)
729a747e4fSDavid du Colombier 			sysfatal("blocksize too large: must be no greater than %d", MaxBlockSize);
739a747e4fSDavid du Colombier 		break;
749a747e4fSDavid du Colombier 	} ARGEND
759a747e4fSDavid du Colombier 
769a747e4fSDavid du Colombier 	if(outfile == nil) {
779a747e4fSDavid du Colombier 		out = emallocz(sizeof(Biobuf));
789a747e4fSDavid du Colombier 		Binit(out, 1, OWRITE);
799a747e4fSDavid du Colombier 	} else {
809a747e4fSDavid du Colombier 		out = Bopen(outfile, OWRITE|OTRUNC);
819a747e4fSDavid du Colombier 		if(out == nil)
829a747e4fSDavid du Colombier 			sysfatal("could not create file: %s: %r", outfile);
839a747e4fSDavid du Colombier 	}
849a747e4fSDavid du Colombier 
859a747e4fSDavid du Colombier 	deflateinit();
869a747e4fSDavid du Colombier 
879a747e4fSDavid du Colombier 	file = argv[0];
889a747e4fSDavid du Colombier 	if(file == nil)
899a747e4fSDavid du Colombier 		file = ".";
909a747e4fSDavid du Colombier 
919a747e4fSDavid du Colombier 	if(label == nil) {
929a747e4fSDavid du Colombier 		if(strrchr(file, '/'))
939a747e4fSDavid du Colombier 			label = strrchr(file, '/') + 1;
949a747e4fSDavid du Colombier 		else
959a747e4fSDavid du Colombier 			label = file;
969a747e4fSDavid du Colombier 	}
979a747e4fSDavid du Colombier 
989a747e4fSDavid du Colombier 	paqfs(file, label);
999a747e4fSDavid du Colombier 
1009a747e4fSDavid du Colombier 	Bterm(out);
1019a747e4fSDavid du Colombier 
1029a747e4fSDavid du Colombier 	exits(0);
1039a747e4fSDavid du Colombier }
1049a747e4fSDavid du Colombier 
1059a747e4fSDavid du Colombier void
usage(void)1069a747e4fSDavid du Colombier usage(void)
1079a747e4fSDavid du Colombier {
1089a747e4fSDavid du Colombier 	fprint(2, "usage: %s [-u] [-b blocksize] -o output [root]\n", argv0);
1099a747e4fSDavid du Colombier 	exits("usage");
1109a747e4fSDavid du Colombier }
1119a747e4fSDavid du Colombier 
1129a747e4fSDavid du Colombier void
paqfs(char * root,char * label)1139a747e4fSDavid du Colombier paqfs(char *root, char *label)
1149a747e4fSDavid du Colombier {
1159a747e4fSDavid du Colombier 	Dir *dir;
1169a747e4fSDavid du Colombier 	PaqDir *pd;
1179a747e4fSDavid du Colombier 	ulong offset;
1189a747e4fSDavid du Colombier 	uchar *buf;
1199a747e4fSDavid du Colombier 
1209a747e4fSDavid du Colombier 	dir = dirstat(root);
1219a747e4fSDavid du Colombier 	if(dir == nil)
1229a747e4fSDavid du Colombier 		sysfatal("could not stat root: %s: %r", root);
1239a747e4fSDavid du Colombier 	writeHeader(label);
1249a747e4fSDavid du Colombier 	if(dir->mode & DMDIR)
1259a747e4fSDavid du Colombier 		pd = paqDir(root, dir);
1269a747e4fSDavid du Colombier 	else
1279a747e4fSDavid du Colombier 		pd = paqFile(root, dir);
1289a747e4fSDavid du Colombier 	buf = emallocz(blocksize);
1299a747e4fSDavid du Colombier 	putDir(buf, pd);
1309a747e4fSDavid du Colombier 	offset = writeBlock(buf, DirBlock);
1319a747e4fSDavid du Colombier 	writeTrailer(offset);
1329a747e4fSDavid du Colombier 	paqDirFree(pd);
1339a747e4fSDavid du Colombier 	free(dir);
1349a747e4fSDavid du Colombier }
1359a747e4fSDavid du Colombier 
1369a747e4fSDavid du Colombier 
1379a747e4fSDavid du Colombier PaqDir *
paqFile(char * name,Dir * dir)1389a747e4fSDavid du Colombier paqFile(char *name, Dir *dir)
1399a747e4fSDavid du Colombier {
1409a747e4fSDavid du Colombier 	int fd, n, nn, nb;
141*fe853e23SDavid du Colombier 	vlong tot;
1429a747e4fSDavid du Colombier 	uchar *block, *pointer;
1439a747e4fSDavid du Colombier 	ulong offset;
1449a747e4fSDavid du Colombier 
1459a747e4fSDavid du Colombier 	fd = open(name, OREAD);
1469a747e4fSDavid du Colombier 	if(fd < 0) {
1479a747e4fSDavid du Colombier 		warn("could not open file: %s: %r", name);
1489a747e4fSDavid du Colombier 		return nil;
1499a747e4fSDavid du Colombier 	}
1509a747e4fSDavid du Colombier 
1519a747e4fSDavid du Colombier 	block = emallocz(blocksize);
1529a747e4fSDavid du Colombier 	pointer = emallocz(blocksize);
1539a747e4fSDavid du Colombier 	nb = 0;
1549a747e4fSDavid du Colombier 	n = 0;
155*fe853e23SDavid du Colombier 	tot = 0;
1569a747e4fSDavid du Colombier 	for(;;) {
1579a747e4fSDavid du Colombier 		nn = read(fd, block+n, blocksize-n);
1589a747e4fSDavid du Colombier 		if(nn < 0) {
1599a747e4fSDavid du Colombier 			warn("read failed: %s: %r", name);
1609a747e4fSDavid du Colombier 			goto Err;
1619a747e4fSDavid du Colombier 		}
162*fe853e23SDavid du Colombier 		tot += nn;
1639a747e4fSDavid du Colombier 		if(nn == 0) {
1649a747e4fSDavid du Colombier 			if(n == 0)
1659a747e4fSDavid du Colombier 				break;
1669a747e4fSDavid du Colombier 			/* pad out last block */
1679a747e4fSDavid du Colombier 			memset(block+n, 0, blocksize-n);
1689a747e4fSDavid du Colombier 			nn = blocksize - n;
1699a747e4fSDavid du Colombier 		}
1709a747e4fSDavid du Colombier 		n += nn;
1719a747e4fSDavid du Colombier 		if(n < blocksize)
1729a747e4fSDavid du Colombier 			continue;
1739a747e4fSDavid du Colombier 		if(nb >= blocksize/OffsetSize) {
1743ff48bf5SDavid du Colombier 			warn("file too big for blocksize: %s", name);
1759a747e4fSDavid du Colombier 			goto Err;
1769a747e4fSDavid du Colombier 		}
1779a747e4fSDavid du Colombier 		offset = writeBlock(block, DataBlock);
1789a747e4fSDavid du Colombier 		putl(pointer+nb*OffsetSize, offset);
1799a747e4fSDavid du Colombier 		nb++;
1809a747e4fSDavid du Colombier 		n = 0;
1819a747e4fSDavid du Colombier 	}
1829a747e4fSDavid du Colombier 
1839a747e4fSDavid du Colombier 	offset = writeBlock(pointer, PointerBlock);
1849a747e4fSDavid du Colombier 
1859a747e4fSDavid du Colombier 	close(fd);
1869a747e4fSDavid du Colombier 	free(pointer);
1879a747e4fSDavid du Colombier 	free(block);
188*fe853e23SDavid du Colombier 	dir->length = tot;
1899a747e4fSDavid du Colombier 	return paqDirAlloc(dir, offset);
1909a747e4fSDavid du Colombier Err:
1919a747e4fSDavid du Colombier 	close(fd);
1929a747e4fSDavid du Colombier 	free(pointer);
1939a747e4fSDavid du Colombier 	free(block);
1949a747e4fSDavid du Colombier 	return nil;
1959a747e4fSDavid du Colombier }
1969a747e4fSDavid du Colombier 
1979a747e4fSDavid du Colombier PaqDir *
paqDir(char * name,Dir * dir)1989a747e4fSDavid du Colombier paqDir(char *name, Dir *dir)
1999a747e4fSDavid du Colombier {
2009a747e4fSDavid du Colombier 	Dir *dirs, *p;
2019a747e4fSDavid du Colombier 	PaqDir *pd;
2029a747e4fSDavid du Colombier 	int i, n, nb, fd, ndir;
2039a747e4fSDavid du Colombier 	uchar *block, *pointer;
2049a747e4fSDavid du Colombier 	char *nname;
2059a747e4fSDavid du Colombier 	ulong offset;
2069a747e4fSDavid du Colombier 
2079a747e4fSDavid du Colombier 	fd = open(name, OREAD);
2089a747e4fSDavid du Colombier 	if(fd < 0) {
2099a747e4fSDavid du Colombier 		warn("could not open directory: %s: %r", name);
2109a747e4fSDavid du Colombier 		return nil;
2119a747e4fSDavid du Colombier 	}
2129a747e4fSDavid du Colombier 
2139a747e4fSDavid du Colombier 	ndir = dirreadall(fd, &dirs);
2149a747e4fSDavid du Colombier 	close(fd);
2159a747e4fSDavid du Colombier 
2169a747e4fSDavid du Colombier 	if(ndir < 0) {
2179a747e4fSDavid du Colombier 		warn("could not read directory: %s: %r", name);
2189a747e4fSDavid du Colombier 		return nil;
2199a747e4fSDavid du Colombier 	}
2209a747e4fSDavid du Colombier 
2219a747e4fSDavid du Colombier 	block = emallocz(blocksize);
2229a747e4fSDavid du Colombier 	pointer = emallocz(blocksize);
2239a747e4fSDavid du Colombier 	nb = 0;
2249a747e4fSDavid du Colombier 	n = 0;
2259a747e4fSDavid du Colombier 	nname = nil;
2269a747e4fSDavid du Colombier 	pd = nil;
2279a747e4fSDavid du Colombier 
2289a747e4fSDavid du Colombier 	for(i=0; i<ndir; i++) {
2299a747e4fSDavid du Colombier 		p = dirs + i;
2309a747e4fSDavid du Colombier 		free(nname);
2319a747e4fSDavid du Colombier 		nname = emallocz(strlen(name) + strlen(p->name) + 2);
2329a747e4fSDavid du Colombier 		sprint(nname, "%s/%s", name, p->name);
2339a747e4fSDavid du Colombier 		if(p->mode & DMDIR)
2349a747e4fSDavid du Colombier 			pd = paqDir(nname, p);
2359a747e4fSDavid du Colombier 		else
2369a747e4fSDavid du Colombier 			pd = paqFile(nname, p);
2379a747e4fSDavid du Colombier 		if(pd == nil)
2389a747e4fSDavid du Colombier 			continue;
2399a747e4fSDavid du Colombier 
2409a747e4fSDavid du Colombier 		if(n+paqDirSize(pd) >= blocksize) {
2419a747e4fSDavid du Colombier 
2429a747e4fSDavid du Colombier 			/* zero fill the block */
2439a747e4fSDavid du Colombier 			memset(block+n, 0, blocksize-n);
2449a747e4fSDavid du Colombier 			offset = writeBlock(block, DirBlock);
2459a747e4fSDavid du Colombier 			n = 0;
2469a747e4fSDavid du Colombier 			if(nb >= blocksize/OffsetSize) {
2479a747e4fSDavid du Colombier 				warn("directory too big for blocksize: %s", nname);
2489a747e4fSDavid du Colombier 				goto Err;
2499a747e4fSDavid du Colombier 			}
2509a747e4fSDavid du Colombier 			putl(pointer+nb*OffsetSize, offset);
2519a747e4fSDavid du Colombier 			nb++;
2529a747e4fSDavid du Colombier 		}
2539a747e4fSDavid du Colombier 		if(n+paqDirSize(pd) >= blocksize) {
2549a747e4fSDavid du Colombier 			warn("directory entry does not fit in a block: %s", nname);
2559a747e4fSDavid du Colombier 			paqDirFree(pd);
2569a747e4fSDavid du Colombier 			continue;
2579a747e4fSDavid du Colombier 		}
2589a747e4fSDavid du Colombier 		putDir(block+n, pd);
2599a747e4fSDavid du Colombier 		n += paqDirSize(pd);
2609a747e4fSDavid du Colombier 		paqDirFree(pd);
2619a747e4fSDavid du Colombier 		pd = nil;
2629a747e4fSDavid du Colombier 	}
2639a747e4fSDavid du Colombier 
2649a747e4fSDavid du Colombier 	if(n > 0) {
2659a747e4fSDavid du Colombier 		/* zero fill the block */
2669a747e4fSDavid du Colombier 		memset(block+n, 0, blocksize-n);
2679a747e4fSDavid du Colombier 		offset = writeBlock(block, DirBlock);
2689a747e4fSDavid du Colombier 		if(nb >= blocksize/OffsetSize) {
2699a747e4fSDavid du Colombier 			warn("directory too big for blocksize: %s", nname);
2709a747e4fSDavid du Colombier 			goto Err;
2719a747e4fSDavid du Colombier 		}
2729a747e4fSDavid du Colombier 		putl(pointer+nb*OffsetSize, offset);
2739a747e4fSDavid du Colombier 	}
2749a747e4fSDavid du Colombier 	offset = writeBlock(pointer, PointerBlock);
2759a747e4fSDavid du Colombier 
2769a747e4fSDavid du Colombier 	free(nname);
2779a747e4fSDavid du Colombier 	free(dirs);
2789a747e4fSDavid du Colombier 	paqDirFree(pd);
2799a747e4fSDavid du Colombier 	free(block);
2809a747e4fSDavid du Colombier 	free(pointer);
2819a747e4fSDavid du Colombier 	return paqDirAlloc(dir, offset);
2829a747e4fSDavid du Colombier Err:
2839a747e4fSDavid du Colombier 	free(nname);
2849a747e4fSDavid du Colombier 	free(dirs);
2859a747e4fSDavid du Colombier 	paqDirFree(pd);
2869a747e4fSDavid du Colombier 	free(block);
2879a747e4fSDavid du Colombier 	free(pointer);
2889a747e4fSDavid du Colombier 	return nil;
2899a747e4fSDavid du Colombier }
2909a747e4fSDavid du Colombier 
2919a747e4fSDavid du Colombier PaqDir *
paqDirAlloc(Dir * dir,ulong offset)2929a747e4fSDavid du Colombier paqDirAlloc(Dir *dir, ulong offset)
2939a747e4fSDavid du Colombier {
2949a747e4fSDavid du Colombier 	PaqDir *pd;
2959a747e4fSDavid du Colombier 	static ulong qid = 1;
2969a747e4fSDavid du Colombier 
2979a747e4fSDavid du Colombier 	pd = emallocz(sizeof(PaqDir));
2989a747e4fSDavid du Colombier 
2999a747e4fSDavid du Colombier 	pd->name = strdup(dir->name);
3009a747e4fSDavid du Colombier 	pd->qid = qid++;
3019a747e4fSDavid du Colombier 	pd->mode = dir->mode & (DMDIR|DMAPPEND|0777);
3029a747e4fSDavid du Colombier 	pd->mtime = dir->mtime;
3039a747e4fSDavid du Colombier 	pd->length = dir->length;
3049a747e4fSDavid du Colombier 	pd->uid = strdup(dir->uid);
3059a747e4fSDavid du Colombier 	pd->gid = strdup(dir->gid);
3069a747e4fSDavid du Colombier 	pd->offset = offset;
3079a747e4fSDavid du Colombier 
3089a747e4fSDavid du Colombier 	return pd;
3099a747e4fSDavid du Colombier }
3109a747e4fSDavid du Colombier 
3119a747e4fSDavid du Colombier void
paqDirFree(PaqDir * pd)3129a747e4fSDavid du Colombier paqDirFree(PaqDir *pd)
3139a747e4fSDavid du Colombier {
3149a747e4fSDavid du Colombier 	if(pd == nil)
3159a747e4fSDavid du Colombier 		return;
3169a747e4fSDavid du Colombier 	free(pd->name);
3179a747e4fSDavid du Colombier 	free(pd->uid);
3189a747e4fSDavid du Colombier 	free(pd->gid);
3199a747e4fSDavid du Colombier 	free(pd);
3209a747e4fSDavid du Colombier }
3219a747e4fSDavid du Colombier 
3229a747e4fSDavid du Colombier 
3239a747e4fSDavid du Colombier void
writeHeader(char * label)3249a747e4fSDavid du Colombier writeHeader(char *label)
3259a747e4fSDavid du Colombier {
3269a747e4fSDavid du Colombier 	PaqHeader hdr;
3279a747e4fSDavid du Colombier 	uchar buf[HeaderSize];
3289a747e4fSDavid du Colombier 
3299a747e4fSDavid du Colombier 	memset(&hdr, 0, sizeof(hdr));
3309a747e4fSDavid du Colombier 	hdr.magic = HeaderMagic;
3319a747e4fSDavid du Colombier 	hdr.version = Version;
3329a747e4fSDavid du Colombier 	hdr.blocksize = blocksize;
3339a747e4fSDavid du Colombier 	hdr.time = time(nil);
3349a747e4fSDavid du Colombier 	strncpy(hdr.label, label, sizeof(hdr.label));
3359a747e4fSDavid du Colombier 	hdr.label[sizeof(hdr.label)-1] = 0;
3369a747e4fSDavid du Colombier 	putHeader(buf, &hdr);
3379a747e4fSDavid du Colombier 	outWrite(buf, sizeof(buf));
3389a747e4fSDavid du Colombier }
3399a747e4fSDavid du Colombier 
3409a747e4fSDavid du Colombier void
writeTrailer(ulong root)3419a747e4fSDavid du Colombier writeTrailer(ulong root)
3429a747e4fSDavid du Colombier {
3439a747e4fSDavid du Colombier 	PaqTrailer tlr;
3449a747e4fSDavid du Colombier 	uchar buf[TrailerSize];
3459a747e4fSDavid du Colombier 
3469a747e4fSDavid du Colombier 	memset(&tlr, 0, sizeof(tlr));
3479a747e4fSDavid du Colombier 	tlr.magic = TrailerMagic;
3489a747e4fSDavid du Colombier 	tlr.root = root;
3499a747e4fSDavid du Colombier 	putTrailer(buf, &tlr);
3509a747e4fSDavid du Colombier 	outWrite(buf, sizeof(buf));
3519a747e4fSDavid du Colombier }
3529a747e4fSDavid du Colombier 
3539a747e4fSDavid du Colombier ulong
writeBlock(uchar * b,int type)3549a747e4fSDavid du Colombier writeBlock(uchar *b, int type)
3559a747e4fSDavid du Colombier {
3569a747e4fSDavid du Colombier 	uchar *cb, *ob;
3579a747e4fSDavid du Colombier 	int n;
3589a747e4fSDavid du Colombier 	PaqBlock bh;
3599a747e4fSDavid du Colombier 	uchar buf[BlockSize];
3609a747e4fSDavid du Colombier 	ulong offset;
3619a747e4fSDavid du Colombier 
3629a747e4fSDavid du Colombier 	offset = Boffset(out);
3639a747e4fSDavid du Colombier 
3649a747e4fSDavid du Colombier 	bh.magic = BlockMagic;
3659a747e4fSDavid du Colombier 	bh.size = blocksize;
3669a747e4fSDavid du Colombier 	bh.type = type;
3679a747e4fSDavid du Colombier 	bh.encoding = NoEnc;
3689a747e4fSDavid du Colombier 	bh.adler32 = adler32(0, b, blocksize);
3699a747e4fSDavid du Colombier 	ob = b;
3709a747e4fSDavid du Colombier 
3719a747e4fSDavid du Colombier 	if(!uflag) {
3729a747e4fSDavid du Colombier 		cb = emallocz(blocksize);
3739a747e4fSDavid du Colombier 		n = deflateblock(cb, blocksize, b, blocksize, 6, 0);
3749a747e4fSDavid du Colombier 		if(n > 0 && n < blocksize) {
3759a747e4fSDavid du Colombier 			bh.encoding = DeflateEnc;
3769a747e4fSDavid du Colombier 			bh.size = n;
3779a747e4fSDavid du Colombier 			ob = cb;
3789a747e4fSDavid du Colombier 		}
3799a747e4fSDavid du Colombier 	}
3809a747e4fSDavid du Colombier 
3819a747e4fSDavid du Colombier 	putBlock(buf, &bh);
3829a747e4fSDavid du Colombier 	outWrite(buf, sizeof(buf));
3839a747e4fSDavid du Colombier 	outWrite(ob, bh.size);
3849a747e4fSDavid du Colombier 
3859a747e4fSDavid du Colombier 	if(ob != b)
3869a747e4fSDavid du Colombier 		free(ob);
3879a747e4fSDavid du Colombier 	return offset;
3889a747e4fSDavid du Colombier }
3899a747e4fSDavid du Colombier 
3909a747e4fSDavid du Colombier 
3919a747e4fSDavid du Colombier void
outWrite(void * buf,int n)3929a747e4fSDavid du Colombier outWrite(void *buf, int n)
3939a747e4fSDavid du Colombier {
3949a747e4fSDavid du Colombier 	if(Bwrite(out, buf, n) < n)
3959a747e4fSDavid du Colombier 		sysfatal("write failed: %r");
3969a747e4fSDavid du Colombier 	outdg = sha1((uchar*)buf, n, nil, outdg);
3979a747e4fSDavid du Colombier }
3989a747e4fSDavid du Colombier 
3999a747e4fSDavid du Colombier int
paqDirSize(PaqDir * d)4009a747e4fSDavid du Colombier paqDirSize(PaqDir *d)
4019a747e4fSDavid du Colombier {
4029a747e4fSDavid du Colombier 	return MinDirSize + strlen(d->name) + strlen(d->uid) + strlen(d->gid);
4039a747e4fSDavid du Colombier }
4049a747e4fSDavid du Colombier 
4059a747e4fSDavid du Colombier void
putHeader(uchar * p,PaqHeader * h)4069a747e4fSDavid du Colombier putHeader(uchar *p, PaqHeader *h)
4079a747e4fSDavid du Colombier {
408*fe853e23SDavid du Colombier 	if(h->blocksize < 65536){
4099a747e4fSDavid du Colombier 		putl(p, h->magic);
4109a747e4fSDavid du Colombier 		puts(p+4, h->version);
4119a747e4fSDavid du Colombier 		puts(p+6, h->blocksize);
412*fe853e23SDavid du Colombier 	}else{
413*fe853e23SDavid du Colombier 		assert(h->magic == HeaderMagic);
414*fe853e23SDavid du Colombier 		puts(p, BigHeaderMagic);
415*fe853e23SDavid du Colombier 		puts(p+2, h->version);
416*fe853e23SDavid du Colombier 		putl(p+4, h->blocksize);
417*fe853e23SDavid du Colombier 	}
4189a747e4fSDavid du Colombier 	putl(p+8, h->time);
4199a747e4fSDavid du Colombier 	memmove(p+12, h->label, sizeof(h->label));
4209a747e4fSDavid du Colombier }
4219a747e4fSDavid du Colombier 
4229a747e4fSDavid du Colombier void
putTrailer(uchar * p,PaqTrailer * h)4239a747e4fSDavid du Colombier putTrailer(uchar *p, PaqTrailer *h)
4249a747e4fSDavid du Colombier {
4259a747e4fSDavid du Colombier 	putl(p, h->magic);
4269a747e4fSDavid du Colombier 	putl(p+4, h->root);
4279a747e4fSDavid du Colombier 	outdg = sha1(p, 8, p+8, outdg);
4289a747e4fSDavid du Colombier }
4299a747e4fSDavid du Colombier 
4309a747e4fSDavid du Colombier void
putBlock(uchar * p,PaqBlock * b)4319a747e4fSDavid du Colombier putBlock(uchar *p, PaqBlock *b)
4329a747e4fSDavid du Colombier {
433*fe853e23SDavid du Colombier 	if(b->size < 65536){
4349a747e4fSDavid du Colombier 		putl(p, b->magic);
4359a747e4fSDavid du Colombier 		puts(p+4, b->size);
436*fe853e23SDavid du Colombier 	}else{
437*fe853e23SDavid du Colombier 		assert(b->magic == BlockMagic);
438*fe853e23SDavid du Colombier 		puts(p, BigBlockMagic);
439*fe853e23SDavid du Colombier 		putl(p+2, b->size);
440*fe853e23SDavid du Colombier 	}
4419a747e4fSDavid du Colombier 	p[6] = b->type;
4429a747e4fSDavid du Colombier 	p[7] = b->encoding;
4439a747e4fSDavid du Colombier 	putl(p+8, b->adler32);
4449a747e4fSDavid du Colombier }
4459a747e4fSDavid du Colombier 
4469a747e4fSDavid du Colombier void
putDir(uchar * p,PaqDir * d)4479a747e4fSDavid du Colombier putDir(uchar *p, PaqDir *d)
4489a747e4fSDavid du Colombier {
4499a747e4fSDavid du Colombier 	uchar *q;
4509a747e4fSDavid du Colombier 
4519a747e4fSDavid du Colombier 	puts(p, paqDirSize(d));
4529a747e4fSDavid du Colombier 	putl(p+2, d->qid);
4539a747e4fSDavid du Colombier 	putl(p+6, d->mode);
4549a747e4fSDavid du Colombier 	putl(p+10, d->mtime);
4559a747e4fSDavid du Colombier 	putl(p+14, d->length);
4569a747e4fSDavid du Colombier 	putl(p+18, d->offset);
4579a747e4fSDavid du Colombier 	q = putstr(p+22, d->name);
4589a747e4fSDavid du Colombier 	q = putstr(q, d->uid);
4599a747e4fSDavid du Colombier 	q = putstr(q, d->gid);
4609a747e4fSDavid du Colombier 	assert(q-p == paqDirSize(d));
4619a747e4fSDavid du Colombier }
4629a747e4fSDavid du Colombier 
4639a747e4fSDavid du Colombier void
putl(uchar * p,ulong v)4649a747e4fSDavid du Colombier putl(uchar *p, ulong v)
4659a747e4fSDavid du Colombier {
4669a747e4fSDavid du Colombier 	p[0] = v>>24;
4679a747e4fSDavid du Colombier 	p[1] = v>>16;
4689a747e4fSDavid du Colombier 	p[2] = v>>8;
4699a747e4fSDavid du Colombier 	p[3] = v;
4709a747e4fSDavid du Colombier }
4719a747e4fSDavid du Colombier 
4729a747e4fSDavid du Colombier void
puts(uchar * p,int v)4739a747e4fSDavid du Colombier puts(uchar *p, int v)
4749a747e4fSDavid du Colombier {
4759a747e4fSDavid du Colombier 	assert(v < (1<<16));
4769a747e4fSDavid du Colombier 	p[0] = v>>8;
4779a747e4fSDavid du Colombier 	p[1] = v;
4789a747e4fSDavid du Colombier }
4799a747e4fSDavid du Colombier 
4809a747e4fSDavid du Colombier uchar *
putstr(uchar * p,char * s)4819a747e4fSDavid du Colombier putstr(uchar *p, char *s)
4829a747e4fSDavid du Colombier {
4839a747e4fSDavid du Colombier 	int n = strlen(s);
4849a747e4fSDavid du Colombier 	puts(p, n+2);
4859a747e4fSDavid du Colombier 	memmove(p+2, s, n);
4869a747e4fSDavid du Colombier 	return p+2+n;
4879a747e4fSDavid du Colombier }
4889a747e4fSDavid du Colombier 
4899a747e4fSDavid du Colombier 
4909a747e4fSDavid du Colombier void *
emallocz(int size)4919a747e4fSDavid du Colombier emallocz(int size)
4929a747e4fSDavid du Colombier {
4939a747e4fSDavid du Colombier 	void *p;
4949a747e4fSDavid du Colombier 
4959a747e4fSDavid du Colombier 	p = malloc(size);
4969a747e4fSDavid du Colombier 	if(p == nil)
4979a747e4fSDavid du Colombier 		sysfatal("malloc failed");
4989a747e4fSDavid du Colombier 	memset(p, 0, size);
4999a747e4fSDavid du Colombier 	return p;
5009a747e4fSDavid du Colombier }
5019a747e4fSDavid du Colombier 
5029a747e4fSDavid du Colombier void
warn(char * fmt,...)5039a747e4fSDavid du Colombier warn(char *fmt, ...)
5049a747e4fSDavid du Colombier {
5059a747e4fSDavid du Colombier 	char buf[1024];
5069a747e4fSDavid du Colombier 	va_list arg;
5079a747e4fSDavid du Colombier 
5089a747e4fSDavid du Colombier 	va_start(arg, fmt);
5099a747e4fSDavid du Colombier 	vseprint(buf, buf+sizeof(buf), fmt, arg);
5109a747e4fSDavid du Colombier 	va_end(arg);
5119a747e4fSDavid du Colombier 	fprint(2, "%s: %s\n", argv0, buf);
5129a747e4fSDavid du Colombier }
513