xref: /plan9/sys/src/cmd/paqfs/paqfs.c (revision f1a26d48345bb11f3a3fddaf7f7d35e9d4d8a55b)
19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <auth.h>
49a747e4fSDavid du Colombier #include <fcall.h>
59a747e4fSDavid du Colombier #include <bio.h>
69a747e4fSDavid du Colombier #include <mp.h>
79a747e4fSDavid du Colombier #include <libsec.h>
89a747e4fSDavid du Colombier #include <flate.h>
99a747e4fSDavid du Colombier 
109a747e4fSDavid du Colombier #include "paqfs.h"
119a747e4fSDavid du Colombier 
129a747e4fSDavid du Colombier enum
139a747e4fSDavid du Colombier {
149a747e4fSDavid du Colombier 	OPERM	= 0x3,		/* mask of all permission types in open mode */
159a747e4fSDavid du Colombier 	OffsetSize = 4,		/* size in bytes of an offset */
169a747e4fSDavid du Colombier };
179a747e4fSDavid du Colombier 
189a747e4fSDavid du Colombier typedef struct Fid Fid;
199a747e4fSDavid du Colombier typedef struct Paq Paq;
209a747e4fSDavid du Colombier typedef struct Block Block;
219a747e4fSDavid du Colombier 
229a747e4fSDavid du Colombier struct Fid
239a747e4fSDavid du Colombier {
249a747e4fSDavid du Colombier 	short	busy;
259a747e4fSDavid du Colombier 	short	open;
269a747e4fSDavid du Colombier 	int	fid;
279a747e4fSDavid du Colombier 	char	*user;
289a747e4fSDavid du Colombier 	ulong	offset;		/* for directory reading */
299a747e4fSDavid du Colombier 
309a747e4fSDavid du Colombier 	Paq	*paq;
319a747e4fSDavid du Colombier 	Fid	*next;
329a747e4fSDavid du Colombier };
339a747e4fSDavid du Colombier 
349a747e4fSDavid du Colombier struct Paq
359a747e4fSDavid du Colombier {
369a747e4fSDavid du Colombier 	int ref;
379a747e4fSDavid du Colombier 	Paq *up;
389a747e4fSDavid du Colombier 	PaqDir *dir;
399a747e4fSDavid du Colombier 	Qid qid;
409a747e4fSDavid du Colombier };
419a747e4fSDavid du Colombier 
429a747e4fSDavid du Colombier struct Block
439a747e4fSDavid du Colombier {
449a747e4fSDavid du Colombier 	int ref;
459a747e4fSDavid du Colombier 	ulong addr;	/* block byte address */
469a747e4fSDavid du Colombier 	ulong age;
479a747e4fSDavid du Colombier 	uchar *data;
489a747e4fSDavid du Colombier };
499a747e4fSDavid du Colombier 
509a747e4fSDavid du Colombier enum
519a747e4fSDavid du Colombier {
529a747e4fSDavid du Colombier 	Pexec =		1,
539a747e4fSDavid du Colombier 	Pwrite = 	2,
549a747e4fSDavid du Colombier 	Pread = 	4,
559a747e4fSDavid du Colombier 	Pother = 	1,
569a747e4fSDavid du Colombier 	Pgroup = 	8,
579a747e4fSDavid du Colombier 	Powner =	64,
589a747e4fSDavid du Colombier };
599a747e4fSDavid du Colombier 
60fe853e23SDavid du Colombier int	noauth;
619a747e4fSDavid du Colombier Fid	*fids;
623ff48bf5SDavid du Colombier Fcall	rhdr, thdr;
639a747e4fSDavid du Colombier int 	blocksize;
649a747e4fSDavid du Colombier int 	cachesize = 20;
659a747e4fSDavid du Colombier int	mesgsize = 8*1024 + IOHDRSZ;
66fe853e23SDavid du Colombier Paq 	*root, *rootfile;
679a747e4fSDavid du Colombier Block 	*cache;
689a747e4fSDavid du Colombier ulong 	cacheage;
699a747e4fSDavid du Colombier Biobuf	*bin;
70238ca1feSDavid du Colombier int	qflag;
719a747e4fSDavid du Colombier 
729a747e4fSDavid du Colombier Fid *	newfid(int);
739a747e4fSDavid du Colombier void	paqstat(PaqDir*, char*);
749a747e4fSDavid du Colombier void	io(int fd);
759a747e4fSDavid du Colombier void	*erealloc(void*, ulong);
769a747e4fSDavid du Colombier void	*emalloc(ulong);
779a747e4fSDavid du Colombier void 	*emallocz(ulong n);
789a747e4fSDavid du Colombier char 	*estrdup(char*);
799a747e4fSDavid du Colombier void	usage(void);
809a747e4fSDavid du Colombier ulong	getl(uchar *p);
819a747e4fSDavid du Colombier int	gets(uchar *p);
829a747e4fSDavid du Colombier char 	*getstr(uchar *p);
839a747e4fSDavid du Colombier PaqDir	*getDir(uchar*);
849a747e4fSDavid du Colombier void	getHeader(uchar *p, PaqHeader *b);
859a747e4fSDavid du Colombier void	getBlock(uchar *p, PaqBlock *b);
869a747e4fSDavid du Colombier void	getTrailer(uchar *p, PaqTrailer *b);
879a747e4fSDavid du Colombier void	init(char*, int);
889a747e4fSDavid du Colombier void	paqDirFree(PaqDir*);
899a747e4fSDavid du Colombier Qid	paqDirQid(PaqDir *d);
909a747e4fSDavid du Colombier Paq	*paqCpy(Paq *s);
919a747e4fSDavid du Colombier Paq	*paqLookup(Paq *s, char *name);
929a747e4fSDavid du Colombier void	paqFree(Paq*);
939a747e4fSDavid du Colombier Paq	*paqWalk(Paq *s, char *name);
949a747e4fSDavid du Colombier int	perm(PaqDir *s, char *user, int p);
959a747e4fSDavid du Colombier int	dirRead(Fid*, uchar*, int);
969a747e4fSDavid du Colombier Block	*blockLoad(ulong addr, int type);
979a747e4fSDavid du Colombier void	blockFree(Block*);
989a747e4fSDavid du Colombier int	checkDirSize(uchar *p, uchar *ep);
999a747e4fSDavid du Colombier int	packDir(PaqDir*, uchar*, int);
1009a747e4fSDavid du Colombier int	blockRead(uchar *data, ulong addr, int type);
1019a747e4fSDavid du Colombier void	readHeader(PaqHeader *hdr, char *name, DigestState *ds);
1029a747e4fSDavid du Colombier void	readBlocks(char *name, DigestState *ds);
1039a747e4fSDavid du Colombier void	readTrailer(PaqTrailer *tlr, char *name, DigestState *ds);
1049a747e4fSDavid du Colombier 
1059a747e4fSDavid du Colombier char	*rflush(Fid*), *rversion(Fid*),
1069a747e4fSDavid du Colombier 	*rauth(Fid*), *rattach(Fid*), *rwalk(Fid*),
1079a747e4fSDavid du Colombier 	*ropen(Fid*), *rcreate(Fid*),
1089a747e4fSDavid du Colombier 	*rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
1099a747e4fSDavid du Colombier 	*rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
1109a747e4fSDavid du Colombier 
1119a747e4fSDavid du Colombier char 	*(*fcalls[])(Fid*) = {
1129a747e4fSDavid du Colombier 	[Tflush]	rflush,
1139a747e4fSDavid du Colombier 	[Tversion]	rversion,
1149a747e4fSDavid du Colombier 	[Tattach]	rattach,
1159a747e4fSDavid du Colombier 	[Tauth]		rauth,
1169a747e4fSDavid du Colombier 	[Twalk]		rwalk,
1179a747e4fSDavid du Colombier 	[Topen]		ropen,
1189a747e4fSDavid du Colombier 	[Tcreate]	rcreate,
1199a747e4fSDavid du Colombier 	[Tread]		rread,
1209a747e4fSDavid du Colombier 	[Twrite]	rwrite,
1219a747e4fSDavid du Colombier 	[Tclunk]	rclunk,
1229a747e4fSDavid du Colombier 	[Tremove]	rremove,
1239a747e4fSDavid du Colombier 	[Tstat]		rstat,
1249a747e4fSDavid du Colombier 	[Twstat]	rwstat,
1259a747e4fSDavid du Colombier };
1269a747e4fSDavid du Colombier 
1279a747e4fSDavid du Colombier char	Eperm[] =	"permission denied";
1289a747e4fSDavid du Colombier char	Enotdir[] =	"not a directory";
1293ff48bf5SDavid du Colombier char	Enoauth[] =	"authentication not required";
1309a747e4fSDavid du Colombier char	Enotexist[] =	"file does not exist";
1319a747e4fSDavid du Colombier char	Einuse[] =	"file in use";
1329a747e4fSDavid du Colombier char	Eexist[] =	"file exists";
1339a747e4fSDavid du Colombier char	Enotowner[] =	"not owner";
1349a747e4fSDavid du Colombier char	Eisopen[] = 	"file already open for I/O";
1359a747e4fSDavid du Colombier char	Excl[] = 	"exclusive use file already open";
1369a747e4fSDavid du Colombier char	Ename[] = 	"illegal name";
1379a747e4fSDavid du Colombier char	Erdonly[] = 	"read only file system";
1389a747e4fSDavid du Colombier char	Ebadblock[] = 	"bad block";
1399a747e4fSDavid du Colombier char	Eversion[] = 	"bad version of P9";
1409a747e4fSDavid du Colombier char	Edirtoobig[] = 	"directory entry too big";
1419a747e4fSDavid du Colombier 
1429a747e4fSDavid du Colombier int debug;
1439a747e4fSDavid du Colombier 
144238ca1feSDavid du Colombier #pragma varargck	type	"V"	uchar*
145238ca1feSDavid du Colombier 
146238ca1feSDavid du Colombier static int
sha1fmt(Fmt * f)147238ca1feSDavid du Colombier sha1fmt(Fmt *f)
148238ca1feSDavid du Colombier {
149238ca1feSDavid du Colombier 	int i;
150238ca1feSDavid du Colombier 	uchar *v;
151238ca1feSDavid du Colombier 
152238ca1feSDavid du Colombier 	v = va_arg(f->args, uchar*);
153238ca1feSDavid du Colombier 	if(v == nil){
154238ca1feSDavid du Colombier 		fmtprint(f, "*");
155238ca1feSDavid du Colombier 	}
156238ca1feSDavid du Colombier 	else{
157238ca1feSDavid du Colombier 		for(i = 0; i < SHA1dlen; i++)
158238ca1feSDavid du Colombier 			fmtprint(f, "%2.2ux", v[i]);
159238ca1feSDavid du Colombier 	}
160238ca1feSDavid du Colombier 
161238ca1feSDavid du Colombier 	return 0;
162238ca1feSDavid du Colombier }
163238ca1feSDavid du Colombier 
1649a747e4fSDavid du Colombier void
main(int argc,char * argv[])1659a747e4fSDavid du Colombier main(int argc, char *argv[])
1669a747e4fSDavid du Colombier {
1679a747e4fSDavid du Colombier 	int pfd[2];
168f27f737dSDavid du Colombier 	int fd, mnt, srv, stdio, verify;
169f27f737dSDavid du Colombier 	char buf[64], *mntpoint, *srvname, *p;
170238ca1feSDavid du Colombier 
171238ca1feSDavid du Colombier 	fmtinstall('V', sha1fmt);
1729a747e4fSDavid du Colombier 
173f27f737dSDavid du Colombier 	mntpoint = "/n/paq";
174f27f737dSDavid du Colombier 	srvname = "paqfs";
175f27f737dSDavid du Colombier 	mnt = 1;
176f27f737dSDavid du Colombier 	srv = stdio = verify = 0;
177f27f737dSDavid du Colombier 
1789a747e4fSDavid du Colombier 	ARGBEGIN{
179f27f737dSDavid du Colombier 	default:
180f27f737dSDavid du Colombier 		usage();
181fe853e23SDavid du Colombier 	case 'a':
182fe853e23SDavid du Colombier 		noauth = 1;
183fe853e23SDavid du Colombier 		break;
184f27f737dSDavid du Colombier 	case 'c':
185f27f737dSDavid du Colombier 		p = EARGF(usage());
186f27f737dSDavid du Colombier 		cachesize = atoi(p);
1879a747e4fSDavid du Colombier 		break;
1889a747e4fSDavid du Colombier 	case 'd':
1899a747e4fSDavid du Colombier 		debug = 1;
1909a747e4fSDavid du Colombier 		break;
1919a747e4fSDavid du Colombier 	case 'i':
192f27f737dSDavid du Colombier 		mnt = 0;
1939a747e4fSDavid du Colombier 		stdio = 1;
1949a747e4fSDavid du Colombier 		pfd[0] = 0;
1959a747e4fSDavid du Colombier 		pfd[1] = 1;
1969a747e4fSDavid du Colombier 		break;
1979a747e4fSDavid du Colombier 	case 'm':
198f27f737dSDavid du Colombier 		mntpoint = EARGF(usage());
1999a747e4fSDavid du Colombier 		break;
2009a747e4fSDavid du Colombier 	case 'M':
201238ca1feSDavid du Colombier 		p = EARGF(usage());
2029a747e4fSDavid du Colombier 		mesgsize = atoi(p);
2039a747e4fSDavid du Colombier 		if(mesgsize < 512)
2049a747e4fSDavid du Colombier 			mesgsize = 512;
2059a747e4fSDavid du Colombier 		if(mesgsize > 128*1024)
2069a747e4fSDavid du Colombier 			mesgsize = 128*1024;
2079a747e4fSDavid du Colombier 		break;
208f27f737dSDavid du Colombier 	case 'p':
209f27f737dSDavid du Colombier 		srv = 1;
210f27f737dSDavid du Colombier 		mnt = 1;
211238ca1feSDavid du Colombier 		break;
212238ca1feSDavid du Colombier 	case 'q':
213238ca1feSDavid du Colombier 		qflag = 1;
214238ca1feSDavid du Colombier 		break;
215f27f737dSDavid du Colombier 	case 's':
216f27f737dSDavid du Colombier 		srv = 1;
217f27f737dSDavid du Colombier 		mnt = 0;
218f27f737dSDavid du Colombier 		break;
219f27f737dSDavid du Colombier 	case 'S':
220f27f737dSDavid du Colombier 		srvname = EARGF(usage());
221f27f737dSDavid du Colombier 		break;
222f27f737dSDavid du Colombier 	case 'v':
223f27f737dSDavid du Colombier 		verify = 1;
224f27f737dSDavid du Colombier 		break;
2259a747e4fSDavid du Colombier 	}ARGEND
2269a747e4fSDavid du Colombier 
2279a747e4fSDavid du Colombier 	if(argc != 1)
2289a747e4fSDavid du Colombier 		usage();
2299a747e4fSDavid du Colombier 
2309a747e4fSDavid du Colombier 	init(argv[0], verify);
2319a747e4fSDavid du Colombier 
2329a747e4fSDavid du Colombier 	if(!stdio){
2339a747e4fSDavid du Colombier 		if(pipe(pfd) < 0)
234f27f737dSDavid du Colombier 			sysfatal("pipe: %r");
235f27f737dSDavid du Colombier 		if(srv){
236f27f737dSDavid du Colombier 			snprint(buf, sizeof buf, "#s/%s", srvname);
237238ca1feSDavid du Colombier 			fd = create(buf, OWRITE, 0666);
2389a747e4fSDavid du Colombier 			if(fd < 0)
239238ca1feSDavid du Colombier 				sysfatal("create %s: %r", buf);
2409a747e4fSDavid du Colombier 			if(fprint(fd, "%d", pfd[0]) < 0)
241f27f737dSDavid du Colombier 				sysfatal("write %s: %r", buf);
2429a747e4fSDavid du Colombier 		}
2439a747e4fSDavid du Colombier 	}
2449a747e4fSDavid du Colombier 
2459a747e4fSDavid du Colombier 	if(debug)
2469a747e4fSDavid du Colombier 		fmtinstall('F', fcallfmt);
2479a747e4fSDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
2489a747e4fSDavid du Colombier 	case -1:
2499a747e4fSDavid du Colombier 		sysfatal("fork");
2509a747e4fSDavid du Colombier 	case 0:
2519a747e4fSDavid du Colombier 		close(pfd[0]);
2529a747e4fSDavid du Colombier 		io(pfd[1]);
2539a747e4fSDavid du Colombier 		break;
2549a747e4fSDavid du Colombier 	default:
2559a747e4fSDavid du Colombier 		close(pfd[1]);	/* don't deadlock if child fails */
256f27f737dSDavid du Colombier 		if(mnt && mount(pfd[0], -1, mntpoint, MREPL|MCREATE, "") < 0)
257f27f737dSDavid du Colombier 			sysfatal("mount %s: %r", mntpoint);
2589a747e4fSDavid du Colombier 	}
2599a747e4fSDavid du Colombier 	exits(0);
2609a747e4fSDavid du Colombier }
2619a747e4fSDavid du Colombier 
2629a747e4fSDavid du Colombier char*
rversion(Fid *)2639a747e4fSDavid du Colombier rversion(Fid*)
2649a747e4fSDavid du Colombier {
2659a747e4fSDavid du Colombier 	Fid *f;
2669a747e4fSDavid du Colombier 
2679a747e4fSDavid du Colombier 	for(f = fids; f; f = f->next)
2689a747e4fSDavid du Colombier 		if(f->busy)
2699a747e4fSDavid du Colombier 			rclunk(f);
2703ff48bf5SDavid du Colombier 	if(rhdr.msize > mesgsize)
2713ff48bf5SDavid du Colombier 		thdr.msize = mesgsize;
2729a747e4fSDavid du Colombier 	else
2733ff48bf5SDavid du Colombier 		thdr.msize = rhdr.msize;
2743ff48bf5SDavid du Colombier 	if(strcmp(rhdr.version, "9P2000") != 0)
2759a747e4fSDavid du Colombier 		return Eversion;
2763ff48bf5SDavid du Colombier 	thdr.version = "9P2000";
2779a747e4fSDavid du Colombier 	return 0;
2789a747e4fSDavid du Colombier }
2799a747e4fSDavid du Colombier 
2809a747e4fSDavid du Colombier char*
rauth(Fid *)2819a747e4fSDavid du Colombier rauth(Fid*)
2829a747e4fSDavid du Colombier {
2839a747e4fSDavid du Colombier 	return Enoauth;
2849a747e4fSDavid du Colombier }
2859a747e4fSDavid du Colombier 
2869a747e4fSDavid du Colombier char*
rflush(Fid * f)2879a747e4fSDavid du Colombier rflush(Fid *f)
2889a747e4fSDavid du Colombier {
2899a747e4fSDavid du Colombier 	USED(f);
2909a747e4fSDavid du Colombier 	return 0;
2919a747e4fSDavid du Colombier }
2929a747e4fSDavid du Colombier 
2939a747e4fSDavid du Colombier char*
rattach(Fid * f)2949a747e4fSDavid du Colombier rattach(Fid *f)
2959a747e4fSDavid du Colombier {
2969a747e4fSDavid du Colombier 	/* no authentication! */
2979a747e4fSDavid du Colombier 	f->busy = 1;
2989a747e4fSDavid du Colombier 	f->paq = paqCpy(root);
2993ff48bf5SDavid du Colombier 	thdr.qid = f->paq->qid;
3003ff48bf5SDavid du Colombier 	if(rhdr.uname[0])
3013ff48bf5SDavid du Colombier 		f->user = estrdup(rhdr.uname);
3029a747e4fSDavid du Colombier 	else
3039a747e4fSDavid du Colombier 		f->user = "none";
3049a747e4fSDavid du Colombier 	return 0;
3059a747e4fSDavid du Colombier }
3069a747e4fSDavid du Colombier 
3079a747e4fSDavid du Colombier char*
clone(Fid * f,Fid ** res)3089a747e4fSDavid du Colombier clone(Fid *f, Fid **res)
3099a747e4fSDavid du Colombier {
3109a747e4fSDavid du Colombier 	Fid *nf;
3119a747e4fSDavid du Colombier 
3129a747e4fSDavid du Colombier 	if(f->open)
3139a747e4fSDavid du Colombier 		return Eisopen;
3149a747e4fSDavid du Colombier 	if(f->busy == 0)
3159a747e4fSDavid du Colombier 		return Enotexist;
3163ff48bf5SDavid du Colombier 	nf = newfid(rhdr.newfid);
3179a747e4fSDavid du Colombier 	nf->busy = 1;
3189a747e4fSDavid du Colombier 	nf->open = 0;
3199a747e4fSDavid du Colombier 	nf->paq = paqCpy(f->paq);
3209a747e4fSDavid du Colombier 	nf->user = strdup(f->user);
3219a747e4fSDavid du Colombier 	*res = nf;
3229a747e4fSDavid du Colombier 	return 0;
3239a747e4fSDavid du Colombier }
3249a747e4fSDavid du Colombier 
3259a747e4fSDavid du Colombier char*
rwalk(Fid * f)3269a747e4fSDavid du Colombier rwalk(Fid *f)
3279a747e4fSDavid du Colombier {
3289a747e4fSDavid du Colombier 	Paq *paq, *npaq;
3299a747e4fSDavid du Colombier 	Fid *nf;
3309a747e4fSDavid du Colombier 	int nqid, nwname;
3319a747e4fSDavid du Colombier 	Qid qid;
3329a747e4fSDavid du Colombier 	char *err;
3339a747e4fSDavid du Colombier 
3349a747e4fSDavid du Colombier 	if(f->busy == 0)
3359a747e4fSDavid du Colombier 		return Enotexist;
3369a747e4fSDavid du Colombier 	nf = nil;
3373ff48bf5SDavid du Colombier 	if(rhdr.fid != rhdr.newfid){
3389a747e4fSDavid du Colombier 		err = clone(f, &nf);
3399a747e4fSDavid du Colombier 		if(err)
3409a747e4fSDavid du Colombier 			return err;
3419a747e4fSDavid du Colombier 		f = nf;	/* walk the new fid */
3429a747e4fSDavid du Colombier 	}
3439a747e4fSDavid du Colombier 
3443ff48bf5SDavid du Colombier 	nwname = rhdr.nwname;
3459a747e4fSDavid du Colombier 
3469a747e4fSDavid du Colombier 	/* easy case */
3479a747e4fSDavid du Colombier 	if(nwname == 0) {
3483ff48bf5SDavid du Colombier 		thdr.nwqid = 0;
3499a747e4fSDavid du Colombier 		return 0;
3509a747e4fSDavid du Colombier 	}
3519a747e4fSDavid du Colombier 
3529a747e4fSDavid du Colombier 	paq = paqCpy(f->paq);
3539a747e4fSDavid du Colombier 	qid = paq->qid;
3549a747e4fSDavid du Colombier 	err = nil;
3559a747e4fSDavid du Colombier 
3569a747e4fSDavid du Colombier 	for(nqid = 0; nqid < nwname; nqid++){
3579a747e4fSDavid du Colombier 		if((qid.type & QTDIR) == 0){
3589a747e4fSDavid du Colombier 			err = Enotdir;
3599a747e4fSDavid du Colombier 			break;
3609a747e4fSDavid du Colombier 		}
3619a747e4fSDavid du Colombier 		if(!perm(paq->dir, f->user, Pexec)) {
3629a747e4fSDavid du Colombier 			err = Eperm;
3639a747e4fSDavid du Colombier 			break;
3649a747e4fSDavid du Colombier 		}
3653ff48bf5SDavid du Colombier 		npaq = paqWalk(paq, rhdr.wname[nqid]);
3669a747e4fSDavid du Colombier 		if(npaq == nil) {
3679a747e4fSDavid du Colombier 			err = Enotexist;
3689a747e4fSDavid du Colombier 			break;
3699a747e4fSDavid du Colombier 		}
3709a747e4fSDavid du Colombier 		paqFree(paq);
3719a747e4fSDavid du Colombier 		paq = npaq;
3729a747e4fSDavid du Colombier 		qid = paq->qid;
3733ff48bf5SDavid du Colombier 		thdr.wqid[nqid] = qid;
3749a747e4fSDavid du Colombier 	}
3759a747e4fSDavid du Colombier 
3763ff48bf5SDavid du Colombier 	thdr.nwqid = nqid;
3779a747e4fSDavid du Colombier 
3789a747e4fSDavid du Colombier 	if(nqid == nwname){
3799a747e4fSDavid du Colombier 		/* success */
3809a747e4fSDavid du Colombier 		paqFree(f->paq);
3819a747e4fSDavid du Colombier 		f->paq = paq;
3829a747e4fSDavid du Colombier 		return 0;
3839a747e4fSDavid du Colombier 	}
3849a747e4fSDavid du Colombier 
3859a747e4fSDavid du Colombier 	paqFree(paq);
3869a747e4fSDavid du Colombier 	if(nf != nil)
3879a747e4fSDavid du Colombier 		rclunk(nf);
3889a747e4fSDavid du Colombier 
3899a747e4fSDavid du Colombier 	/* only error on the first element */
3909a747e4fSDavid du Colombier 	if(nqid == 0)
3919a747e4fSDavid du Colombier 		return err;
3929a747e4fSDavid du Colombier 
3939a747e4fSDavid du Colombier 	return 0;
3949a747e4fSDavid du Colombier }
3959a747e4fSDavid du Colombier 
3969a747e4fSDavid du Colombier char *
ropen(Fid * f)3979a747e4fSDavid du Colombier ropen(Fid *f)
3989a747e4fSDavid du Colombier {
3999a747e4fSDavid du Colombier 	int mode, trunc;
4009a747e4fSDavid du Colombier 
4019a747e4fSDavid du Colombier 	if(f->open)
4029a747e4fSDavid du Colombier 		return Eisopen;
4039a747e4fSDavid du Colombier 	if(f->busy == 0)
4049a747e4fSDavid du Colombier 		return Enotexist;
4053ff48bf5SDavid du Colombier 	mode = rhdr.mode;
4069a747e4fSDavid du Colombier 	if(f->paq->qid.type & QTDIR){
4079a747e4fSDavid du Colombier 		if(mode != OREAD)
4089a747e4fSDavid du Colombier 			return Eperm;
4093ff48bf5SDavid du Colombier 		thdr.qid = f->paq->qid;
4109a747e4fSDavid du Colombier 		return 0;
4119a747e4fSDavid du Colombier 	}
4129a747e4fSDavid du Colombier 	if(mode & ORCLOSE)
4139a747e4fSDavid du Colombier 		return Erdonly;
4149a747e4fSDavid du Colombier 	trunc = mode & OTRUNC;
4159a747e4fSDavid du Colombier 	mode &= OPERM;
4169a747e4fSDavid du Colombier 	if(mode==OWRITE || mode==ORDWR || trunc)
4179a747e4fSDavid du Colombier 		return Erdonly;
4189a747e4fSDavid du Colombier 	if(mode==OREAD)
4199a747e4fSDavid du Colombier 		if(!perm(f->paq->dir, f->user, Pread))
4209a747e4fSDavid du Colombier 			return Eperm;
4219a747e4fSDavid du Colombier 	if(mode==OEXEC)
4229a747e4fSDavid du Colombier 		if(!perm(f->paq->dir, f->user, Pexec))
4239a747e4fSDavid du Colombier 			return Eperm;
4243ff48bf5SDavid du Colombier 	thdr.qid = f->paq->qid;
4259a747e4fSDavid du Colombier 	f->open = 1;
4269a747e4fSDavid du Colombier 	return 0;
4279a747e4fSDavid du Colombier }
4289a747e4fSDavid du Colombier 
4299a747e4fSDavid du Colombier char *
rcreate(Fid * f)4309a747e4fSDavid du Colombier rcreate(Fid *f)
4319a747e4fSDavid du Colombier {
4329a747e4fSDavid du Colombier 	if(f->open)
4339a747e4fSDavid du Colombier 		return Eisopen;
4349a747e4fSDavid du Colombier 	if(f->busy == 0)
4359a747e4fSDavid du Colombier 		return Enotexist;
4369a747e4fSDavid du Colombier 	return Erdonly;
4379a747e4fSDavid du Colombier }
4389a747e4fSDavid du Colombier 
4399a747e4fSDavid du Colombier char *
readdir(Fid * f)4409a747e4fSDavid du Colombier readdir(Fid *f)
4419a747e4fSDavid du Colombier {
4429a747e4fSDavid du Colombier 	PaqDir *pd;
4439a747e4fSDavid du Colombier 	uchar *p, *ep;
4449a747e4fSDavid du Colombier 	ulong off;
4459a747e4fSDavid du Colombier 	int n, cnt, i;
4469a747e4fSDavid du Colombier 	uchar *buf;
4479a747e4fSDavid du Colombier 	Block *ptr, *b;
4489a747e4fSDavid du Colombier 
4493ff48bf5SDavid du Colombier 	buf = (uchar*)thdr.data;
4503ff48bf5SDavid du Colombier 	cnt = rhdr.count;
4513ff48bf5SDavid du Colombier 	if(rhdr.offset == 0)
4529a747e4fSDavid du Colombier 		f->offset = 0;
4539a747e4fSDavid du Colombier 	off = f->offset;
4549a747e4fSDavid du Colombier 
455fe853e23SDavid du Colombier 	if(rootfile && f->paq == root){
456fe853e23SDavid du Colombier 		if(off != 0){
457fe853e23SDavid du Colombier 			rhdr.count = 0;
458fe853e23SDavid du Colombier 			return nil;
459fe853e23SDavid du Colombier 		}
460fe853e23SDavid du Colombier 		n = packDir(rootfile->dir, buf, cnt);
461fe853e23SDavid du Colombier 		rhdr.count = n;
462fe853e23SDavid du Colombier 		return nil;
463fe853e23SDavid du Colombier 	}
464fe853e23SDavid du Colombier 
4659a747e4fSDavid du Colombier 	ptr = blockLoad(f->paq->dir->offset, PointerBlock);
4669a747e4fSDavid du Colombier 	if(ptr == nil)
4679a747e4fSDavid du Colombier 		return Ebadblock;
4689a747e4fSDavid du Colombier 	i = off/blocksize;
4699a747e4fSDavid du Colombier 	off -= i*blocksize;
4709a747e4fSDavid du Colombier 
4713ff48bf5SDavid du Colombier 	thdr.count = 0;
4729a747e4fSDavid du Colombier 	b = blockLoad(getl(ptr->data + i*4), DirBlock);
4739a747e4fSDavid du Colombier 	while(b != nil) {
4749a747e4fSDavid du Colombier 		p = b->data + off;
4759a747e4fSDavid du Colombier 		ep = b->data + blocksize;
4769a747e4fSDavid du Colombier 		if(checkDirSize(p, ep)) {
4779a747e4fSDavid du Colombier 			pd = getDir(p);
4789a747e4fSDavid du Colombier 			n = packDir(pd, buf, cnt);
4799a747e4fSDavid du Colombier 			paqDirFree(pd);
4809a747e4fSDavid du Colombier 			if(n == 0) {
4819a747e4fSDavid du Colombier 				blockFree(b);
4823ff48bf5SDavid du Colombier 				if(thdr.count == 0) {
4839a747e4fSDavid du Colombier 					blockFree(ptr);
4849a747e4fSDavid du Colombier 					return Edirtoobig;
4859a747e4fSDavid du Colombier 				}
4869a747e4fSDavid du Colombier 				break;
4879a747e4fSDavid du Colombier 			}
4889a747e4fSDavid du Colombier 			off += gets(p);
4899a747e4fSDavid du Colombier 			cnt -= n;
4909a747e4fSDavid du Colombier 			buf += n;
4913ff48bf5SDavid du Colombier 			thdr.count += n;
4929a747e4fSDavid du Colombier 		} else {
4939a747e4fSDavid du Colombier 			off = 0;
4949a747e4fSDavid du Colombier 			i++;
4959a747e4fSDavid du Colombier 			blockFree(b);
496*f1a26d48SDavid du Colombier 			b = blockLoad(getl(ptr->data + i*4), DirBlock);
4979a747e4fSDavid du Colombier 		}
4989a747e4fSDavid du Colombier 	}
4999a747e4fSDavid du Colombier 	f->offset = i*blocksize + off;
5009a747e4fSDavid du Colombier 	blockFree(ptr);
5019a747e4fSDavid du Colombier 
5029a747e4fSDavid du Colombier 	return 0;
5039a747e4fSDavid du Colombier }
5049a747e4fSDavid du Colombier 
5059a747e4fSDavid du Colombier char*
rread(Fid * f)5069a747e4fSDavid du Colombier rread(Fid *f)
5079a747e4fSDavid du Colombier {
5089a747e4fSDavid du Colombier 	PaqDir *pd;
5099a747e4fSDavid du Colombier 	uchar *buf;
510fe853e23SDavid du Colombier 	vlong off;
511fe853e23SDavid du Colombier 	ulong uoff;
5129a747e4fSDavid du Colombier 	int n, cnt, i;
5139a747e4fSDavid du Colombier 	Block *ptr, *b;
5149a747e4fSDavid du Colombier 
5159a747e4fSDavid du Colombier 	if(f->busy == 0)
5169a747e4fSDavid du Colombier 		return Enotexist;
5179a747e4fSDavid du Colombier 	if(f->paq->qid.type & QTDIR)
5189a747e4fSDavid du Colombier 		return readdir(f);
5199a747e4fSDavid du Colombier 	pd = f->paq->dir;
5203ff48bf5SDavid du Colombier 	off = rhdr.offset;
5213ff48bf5SDavid du Colombier 	buf = (uchar*)thdr.data;
5223ff48bf5SDavid du Colombier 	cnt = rhdr.count;
5239a747e4fSDavid du Colombier 
5243ff48bf5SDavid du Colombier 	thdr.count = 0;
5253ff48bf5SDavid du Colombier 	if(off >= pd->length || cnt == 0)
5269a747e4fSDavid du Colombier 		return 0;
5279a747e4fSDavid du Colombier 
5283ff48bf5SDavid du Colombier 	if(cnt > pd->length - off)
5299a747e4fSDavid du Colombier 		cnt = pd->length - off;
5303ff48bf5SDavid du Colombier 
5319a747e4fSDavid du Colombier 	ptr = blockLoad(pd->offset, PointerBlock);
5329a747e4fSDavid du Colombier 	if(ptr == nil)
5339a747e4fSDavid du Colombier 		return Ebadblock;
5349a747e4fSDavid du Colombier 
5359a747e4fSDavid du Colombier 	i = off/blocksize;
536fe853e23SDavid du Colombier 	uoff = off-i*blocksize;
5379a747e4fSDavid du Colombier 
5389a747e4fSDavid du Colombier 	while(cnt > 0) {
5399a747e4fSDavid du Colombier 		b = blockLoad(getl(ptr->data + i*4), DataBlock);
5409a747e4fSDavid du Colombier 		if(b == nil) {
5419a747e4fSDavid du Colombier 			blockFree(ptr);
5429a747e4fSDavid du Colombier 			return Ebadblock;
5439a747e4fSDavid du Colombier 		}
544fe853e23SDavid du Colombier 		n = blocksize - uoff;
5459a747e4fSDavid du Colombier 		if(n > cnt)
5469a747e4fSDavid du Colombier 			n = cnt;
547fe853e23SDavid du Colombier 		memmove(buf, b->data + uoff, n);
5489a747e4fSDavid du Colombier 		cnt -= n;
5493ff48bf5SDavid du Colombier 		thdr.count += n;
5509a747e4fSDavid du Colombier 		buf += n;
551fe853e23SDavid du Colombier 		uoff = 0;
5529a747e4fSDavid du Colombier 		i++;
5539a747e4fSDavid du Colombier 		blockFree(b);
5549a747e4fSDavid du Colombier 	}
5559a747e4fSDavid du Colombier 	blockFree(ptr);
5569a747e4fSDavid du Colombier 	return 0;
5579a747e4fSDavid du Colombier }
5589a747e4fSDavid du Colombier 
5599a747e4fSDavid du Colombier char*
rwrite(Fid * f)5609a747e4fSDavid du Colombier rwrite(Fid *f)
5619a747e4fSDavid du Colombier {
5629a747e4fSDavid du Colombier 	if(f->busy == 0)
5639a747e4fSDavid du Colombier 		return Enotexist;
5649a747e4fSDavid du Colombier 	return Erdonly;
5659a747e4fSDavid du Colombier }
5669a747e4fSDavid du Colombier 
5679a747e4fSDavid du Colombier char *
rclunk(Fid * f)5689a747e4fSDavid du Colombier rclunk(Fid *f)
5699a747e4fSDavid du Colombier {
5709a747e4fSDavid du Colombier 	f->busy = 0;
5719a747e4fSDavid du Colombier 	f->open = 0;
5729a747e4fSDavid du Colombier 	free(f->user);
5739a747e4fSDavid du Colombier 	paqFree(f->paq);
5749a747e4fSDavid du Colombier 	return 0;
5759a747e4fSDavid du Colombier }
5769a747e4fSDavid du Colombier 
5779a747e4fSDavid du Colombier char *
rremove(Fid * f)5789a747e4fSDavid du Colombier rremove(Fid *f)
5799a747e4fSDavid du Colombier {
5809a747e4fSDavid du Colombier 	rclunk(f);
5819a747e4fSDavid du Colombier 	return Erdonly;
5829a747e4fSDavid du Colombier }
5839a747e4fSDavid du Colombier 
5849a747e4fSDavid du Colombier char *
rstat(Fid * f)5859a747e4fSDavid du Colombier rstat(Fid *f)
5869a747e4fSDavid du Colombier {
5879a747e4fSDavid du Colombier 	if(f->busy == 0)
5889a747e4fSDavid du Colombier 		return Enotexist;
5893ff48bf5SDavid du Colombier 	thdr.stat = (uchar*)thdr.data;
5903ff48bf5SDavid du Colombier 	thdr.nstat = packDir(f->paq->dir, thdr.stat, mesgsize);
5913ff48bf5SDavid du Colombier 	if(thdr.nstat == 0)
5929a747e4fSDavid du Colombier 		return Edirtoobig;
5939a747e4fSDavid du Colombier 	return 0;
5949a747e4fSDavid du Colombier }
5959a747e4fSDavid du Colombier 
5969a747e4fSDavid du Colombier char *
rwstat(Fid * f)5979a747e4fSDavid du Colombier rwstat(Fid *f)
5989a747e4fSDavid du Colombier {
5999a747e4fSDavid du Colombier 	if(f->busy == 0)
6009a747e4fSDavid du Colombier 		return Enotexist;
6019a747e4fSDavid du Colombier 	return Erdonly;
6029a747e4fSDavid du Colombier }
6039a747e4fSDavid du Colombier 
6049a747e4fSDavid du Colombier Paq*
paqCpy(Paq * s)6059a747e4fSDavid du Colombier paqCpy(Paq *s)
6069a747e4fSDavid du Colombier {
6079a747e4fSDavid du Colombier 	s->ref++;
6089a747e4fSDavid du Colombier 	return s;
6099a747e4fSDavid du Colombier }
6109a747e4fSDavid du Colombier 
6119a747e4fSDavid du Colombier void
paqFree(Paq * p)6129a747e4fSDavid du Colombier paqFree(Paq *p)
6139a747e4fSDavid du Colombier {
6149a747e4fSDavid du Colombier 	if(p == nil)
6159a747e4fSDavid du Colombier 		return;
6169a747e4fSDavid du Colombier 	p->ref--;
6179a747e4fSDavid du Colombier 	if(p->ref > 0)
6189a747e4fSDavid du Colombier 		return;
6199a747e4fSDavid du Colombier assert(p != root);
6209a747e4fSDavid du Colombier 	paqFree(p->up);
6219a747e4fSDavid du Colombier 	paqDirFree(p->dir);
6229a747e4fSDavid du Colombier 	free(p);
6239a747e4fSDavid du Colombier }
6249a747e4fSDavid du Colombier 
6259a747e4fSDavid du Colombier void
paqDirFree(PaqDir * pd)6269a747e4fSDavid du Colombier paqDirFree(PaqDir *pd)
6279a747e4fSDavid du Colombier {
6289a747e4fSDavid du Colombier 	if(pd == nil)
6299a747e4fSDavid du Colombier 		return;
6309a747e4fSDavid du Colombier 	free(pd->name);
6319a747e4fSDavid du Colombier 	free(pd->uid);
6329a747e4fSDavid du Colombier 	free(pd->gid);
6339a747e4fSDavid du Colombier 	free(pd);
6349a747e4fSDavid du Colombier }
6359a747e4fSDavid du Colombier 
6369a747e4fSDavid du Colombier Qid
paqDirQid(PaqDir * d)6379a747e4fSDavid du Colombier paqDirQid(PaqDir *d)
6389a747e4fSDavid du Colombier {
6399a747e4fSDavid du Colombier 	Qid q;
6409a747e4fSDavid du Colombier 
6419a747e4fSDavid du Colombier 	q.path = d->qid;
6429a747e4fSDavid du Colombier 	q.vers = 0;
6439a747e4fSDavid du Colombier 	q.type = d->mode >> 24;
6449a747e4fSDavid du Colombier 
6459a747e4fSDavid du Colombier 	return q;
6469a747e4fSDavid du Colombier }
6479a747e4fSDavid du Colombier 
6489a747e4fSDavid du Colombier int
packDir(PaqDir * s,uchar * buf,int n)6499a747e4fSDavid du Colombier packDir(PaqDir *s, uchar *buf, int n)
6509a747e4fSDavid du Colombier {
6519a747e4fSDavid du Colombier 	Dir dir;
6529a747e4fSDavid du Colombier 
6539a747e4fSDavid du Colombier 	memset(&dir, 0, sizeof(dir));
6549a747e4fSDavid du Colombier 	dir.qid = paqDirQid(s);
6559a747e4fSDavid du Colombier 	dir.mode = s->mode;
6569a747e4fSDavid du Colombier 	dir.atime = s->mtime;
6579a747e4fSDavid du Colombier 	dir.mtime = s->mtime;
6589a747e4fSDavid du Colombier 	dir.length = s->length;
6599a747e4fSDavid du Colombier 	dir.name = s->name;
6609a747e4fSDavid du Colombier 	dir.uid = s->uid;
6619a747e4fSDavid du Colombier 	dir.gid = s->gid;
6629a747e4fSDavid du Colombier 	dir.muid = s->uid;
6639a747e4fSDavid du Colombier 
6649a747e4fSDavid du Colombier 	n = convD2M(&dir, buf, n);
6659a747e4fSDavid du Colombier 	if(n < STATFIXLEN)
6669a747e4fSDavid du Colombier 		return 0;
6679a747e4fSDavid du Colombier 	return n;
6689a747e4fSDavid du Colombier }
6699a747e4fSDavid du Colombier 
6709a747e4fSDavid du Colombier Block *
blockLoad(ulong addr,int type)6719a747e4fSDavid du Colombier blockLoad(ulong addr, int type)
6729a747e4fSDavid du Colombier {
6739a747e4fSDavid du Colombier 	ulong age;
6749a747e4fSDavid du Colombier 	int i, j;
6759a747e4fSDavid du Colombier 	Block *b;
6769a747e4fSDavid du Colombier 
6775d459b5aSDavid du Colombier 	if(addr == 0)
6785d459b5aSDavid du Colombier 		return nil;
6795d459b5aSDavid du Colombier 
6809a747e4fSDavid du Colombier 	cacheage++;
6819a747e4fSDavid du Colombier 
6829a747e4fSDavid du Colombier 	/* age has wraped */
6839a747e4fSDavid du Colombier 	if(cacheage == 0) {
6849a747e4fSDavid du Colombier 		for(i=0; i<cachesize; i++)
6859a747e4fSDavid du Colombier 			cache[i].age = 0;
6869a747e4fSDavid du Colombier 	}
6879a747e4fSDavid du Colombier 
6889a747e4fSDavid du Colombier 	j = -1;
6899a747e4fSDavid du Colombier 	age = ~0;
6909a747e4fSDavid du Colombier 	for(i=0; i<cachesize; i++) {
6919a747e4fSDavid du Colombier 		b = &cache[i];
6929a747e4fSDavid du Colombier 		if(b->age < age && b->ref == 0) {
6939a747e4fSDavid du Colombier 			age = b->age;
6949a747e4fSDavid du Colombier 			j = i;
6959a747e4fSDavid du Colombier 		}
6969a747e4fSDavid du Colombier 		if(b->addr != addr)
6979a747e4fSDavid du Colombier 			continue;
6989a747e4fSDavid du Colombier 		b->age = cacheage;
6999a747e4fSDavid du Colombier 		b->ref++;
7009a747e4fSDavid du Colombier 		return b;
7019a747e4fSDavid du Colombier 	}
7029a747e4fSDavid du Colombier 	if(j < 0)
70314cc0f53SDavid du Colombier 		sysfatal("no empty spots in cache!");
7049a747e4fSDavid du Colombier 	b = &cache[j];
7059a747e4fSDavid du Colombier 	assert(b->ref == 0);
7069a747e4fSDavid du Colombier 
7079a747e4fSDavid du Colombier 	if(!blockRead(b->data, addr, type)) {
7089a747e4fSDavid du Colombier 		b->addr = 0;
7099a747e4fSDavid du Colombier 		b->age = 0;
7109a747e4fSDavid du Colombier 		return nil;
7119a747e4fSDavid du Colombier 	}
7129a747e4fSDavid du Colombier 
7139a747e4fSDavid du Colombier 	b->age = cacheage;
7149a747e4fSDavid du Colombier 	b->addr = addr;
7159a747e4fSDavid du Colombier 	b->ref = 1;
7169a747e4fSDavid du Colombier 
7179a747e4fSDavid du Colombier 	return b;
7189a747e4fSDavid du Colombier }
7199a747e4fSDavid du Colombier 
7209a747e4fSDavid du Colombier void
blockFree(Block * b)7219a747e4fSDavid du Colombier blockFree(Block *b)
7229a747e4fSDavid du Colombier {
7239a747e4fSDavid du Colombier 	if(b == nil)
7249a747e4fSDavid du Colombier 		return;
7259a747e4fSDavid du Colombier 	if(--b->ref > 0)
7269a747e4fSDavid du Colombier 		return;
7279a747e4fSDavid du Colombier 	assert(b->ref == 0);
7289a747e4fSDavid du Colombier }
7299a747e4fSDavid du Colombier 
7309a747e4fSDavid du Colombier Paq*
paqWalk(Paq * s,char * name)7319a747e4fSDavid du Colombier paqWalk(Paq *s, char *name)
7329a747e4fSDavid du Colombier {
7339a747e4fSDavid du Colombier 	Block *ptr, *b;
7349a747e4fSDavid du Colombier 	uchar *p, *ep;
7359a747e4fSDavid du Colombier 	PaqDir *pd;
7369a747e4fSDavid du Colombier 	int i, n;
7379a747e4fSDavid du Colombier 	Paq *ss;
7389a747e4fSDavid du Colombier 
7399a747e4fSDavid du Colombier 	if(strcmp(name, "..") == 0)
7409a747e4fSDavid du Colombier 		return paqCpy(s->up);
7419a747e4fSDavid du Colombier 
742fe853e23SDavid du Colombier 	if(rootfile && s == root){
743fe853e23SDavid du Colombier 		if(strcmp(name, rootfile->dir->name) == 0)
744fe853e23SDavid du Colombier 			return paqCpy(rootfile);
745fe853e23SDavid du Colombier 		return nil;
746fe853e23SDavid du Colombier 	}
747fe853e23SDavid du Colombier 
7489a747e4fSDavid du Colombier 	ptr = blockLoad(s->dir->offset, PointerBlock);
7499a747e4fSDavid du Colombier 	if(ptr == nil)
7509a747e4fSDavid du Colombier 		return nil;
7519a747e4fSDavid du Colombier 
7529a747e4fSDavid du Colombier 	for(i=0; i<blocksize/4; i++) {
7539a747e4fSDavid du Colombier 		b = blockLoad(getl(ptr->data+i*4), DirBlock);
7549a747e4fSDavid du Colombier 		if(b == nil)
7559a747e4fSDavid du Colombier 			break;
7569a747e4fSDavid du Colombier 		p = b->data;
7579a747e4fSDavid du Colombier 		ep = p + blocksize;
7589a747e4fSDavid du Colombier 		while(checkDirSize(p, ep)) {
7599a747e4fSDavid du Colombier 			n = gets(p);
7609a747e4fSDavid du Colombier 			pd = getDir(p);
7619a747e4fSDavid du Colombier 			if(strcmp(pd->name, name) == 0) {
7629a747e4fSDavid du Colombier 				ss = emallocz(sizeof(Paq));
7639a747e4fSDavid du Colombier 				ss->ref = 1;
7649a747e4fSDavid du Colombier 				ss->up = paqCpy(s);
7659a747e4fSDavid du Colombier 				ss->dir = pd;
7669a747e4fSDavid du Colombier 				ss->qid = paqDirQid(pd);
7679a747e4fSDavid du Colombier 				blockFree(b);
7689a747e4fSDavid du Colombier 				blockFree(ptr);
7699a747e4fSDavid du Colombier 				return ss;
7709a747e4fSDavid du Colombier 			}
7719a747e4fSDavid du Colombier 			paqDirFree(pd);
7729a747e4fSDavid du Colombier 			p += n;
7739a747e4fSDavid du Colombier 		}
7749a747e4fSDavid du Colombier 		blockFree(b);
7759a747e4fSDavid du Colombier 	}
7769a747e4fSDavid du Colombier 
7779a747e4fSDavid du Colombier 	blockFree(ptr);
7789a747e4fSDavid du Colombier 	return nil;
7799a747e4fSDavid du Colombier }
7809a747e4fSDavid du Colombier 
7819a747e4fSDavid du Colombier Fid *
newfid(int fid)7829a747e4fSDavid du Colombier newfid(int fid)
7839a747e4fSDavid du Colombier {
7849a747e4fSDavid du Colombier 	Fid *f, *ff;
7859a747e4fSDavid du Colombier 
7869a747e4fSDavid du Colombier 	ff = 0;
7879a747e4fSDavid du Colombier 	for(f = fids; f; f = f->next)
7889a747e4fSDavid du Colombier 		if(f->fid == fid)
7899a747e4fSDavid du Colombier 			return f;
7909a747e4fSDavid du Colombier 		else if(!ff && !f->busy)
7919a747e4fSDavid du Colombier 			ff = f;
7929a747e4fSDavid du Colombier 	if(ff){
7939a747e4fSDavid du Colombier 		ff->fid = fid;
7949a747e4fSDavid du Colombier 		return ff;
7959a747e4fSDavid du Colombier 	}
7969a747e4fSDavid du Colombier 	f = emallocz(sizeof *f);
7979a747e4fSDavid du Colombier 	f->fid = fid;
7989a747e4fSDavid du Colombier 	f->next = fids;
7999a747e4fSDavid du Colombier 	fids = f;
8009a747e4fSDavid du Colombier 	return f;
8019a747e4fSDavid du Colombier }
8029a747e4fSDavid du Colombier 
8039a747e4fSDavid du Colombier void
io(int fd)8049a747e4fSDavid du Colombier io(int fd)
8059a747e4fSDavid du Colombier {
8069a747e4fSDavid du Colombier 	char *err;
8079a747e4fSDavid du Colombier 	int n, pid;
8089a747e4fSDavid du Colombier 	uchar *mdata;
8099a747e4fSDavid du Colombier 
8109a747e4fSDavid du Colombier 	mdata = emalloc(mesgsize);
8119a747e4fSDavid du Colombier 
8129a747e4fSDavid du Colombier 	pid = getpid();
8139a747e4fSDavid du Colombier 
8149a747e4fSDavid du Colombier 	for(;;){
8159a747e4fSDavid du Colombier 		n = read9pmsg(fd, mdata, mesgsize);
8169a747e4fSDavid du Colombier 		if(n < 0)
8179a747e4fSDavid du Colombier 			sysfatal("mount read");
8189a747e4fSDavid du Colombier 		if(n == 0)
8199a747e4fSDavid du Colombier 			break;
8203ff48bf5SDavid du Colombier 		if(convM2S(mdata, n, &rhdr) == 0)
8219a747e4fSDavid du Colombier 			continue;
8229a747e4fSDavid du Colombier 
8239a747e4fSDavid du Colombier 		if(debug)
8243ff48bf5SDavid du Colombier 			fprint(2, "paqfs %d:<-%F\n", pid, &rhdr);
8259a747e4fSDavid du Colombier 
8263ff48bf5SDavid du Colombier 		thdr.data = (char*)mdata + IOHDRSZ;
8273ff48bf5SDavid du Colombier 		if(!fcalls[rhdr.type])
8289a747e4fSDavid du Colombier 			err = "bad fcall type";
8299a747e4fSDavid du Colombier 		else
8303ff48bf5SDavid du Colombier 			err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
8319a747e4fSDavid du Colombier 		if(err){
8323ff48bf5SDavid du Colombier 			thdr.type = Rerror;
8333ff48bf5SDavid du Colombier 			thdr.ename = err;
8349a747e4fSDavid du Colombier 		}else{
8353ff48bf5SDavid du Colombier 			thdr.type = rhdr.type + 1;
8363ff48bf5SDavid du Colombier 			thdr.fid = rhdr.fid;
8379a747e4fSDavid du Colombier 		}
8383ff48bf5SDavid du Colombier 		thdr.tag = rhdr.tag;
8399a747e4fSDavid du Colombier 		if(debug)
8403ff48bf5SDavid du Colombier 			fprint(2, "paqfs %d:->%F\n", pid, &thdr);/**/
8413ff48bf5SDavid du Colombier 		n = convS2M(&thdr, mdata, mesgsize);
8429a747e4fSDavid du Colombier 		if(n == 0)
8439a747e4fSDavid du Colombier 			sysfatal("convS2M sysfatal on write");
8449a747e4fSDavid du Colombier 		if(write(fd, mdata, n) != n)
8459a747e4fSDavid du Colombier 			sysfatal("mount write");
8469a747e4fSDavid du Colombier 	}
8479a747e4fSDavid du Colombier }
8489a747e4fSDavid du Colombier 
8499a747e4fSDavid du Colombier int
perm(PaqDir * s,char * user,int p)8509a747e4fSDavid du Colombier perm(PaqDir *s, char *user, int p)
8519a747e4fSDavid du Colombier {
8529a747e4fSDavid du Colombier 	ulong perm = s->mode;
8539a747e4fSDavid du Colombier 
8549a747e4fSDavid du Colombier 	if((p*Pother) & perm)
8559a747e4fSDavid du Colombier 		return 1;
856fe853e23SDavid du Colombier 	if((noauth || strcmp(user, s->gid)==0) && ((p*Pgroup) & perm))
8579a747e4fSDavid du Colombier 		return 1;
858fe853e23SDavid du Colombier 	if((noauth || strcmp(user, s->uid)==0) && ((p*Powner) & perm))
8599a747e4fSDavid du Colombier 		return 1;
8609a747e4fSDavid du Colombier 	return 0;
8619a747e4fSDavid du Colombier }
8629a747e4fSDavid du Colombier 
8639a747e4fSDavid du Colombier void
init(char * file,int verify)8649a747e4fSDavid du Colombier init(char *file, int verify)
8659a747e4fSDavid du Colombier {
8669a747e4fSDavid du Colombier 	PaqHeader hdr;
8679a747e4fSDavid du Colombier 	PaqTrailer tlr;
8689a747e4fSDavid du Colombier 	Dir *dir;
8699a747e4fSDavid du Colombier 	int i;
8709a747e4fSDavid du Colombier 	uchar *p;
8719a747e4fSDavid du Colombier 	DigestState *ds = nil;
8729a747e4fSDavid du Colombier 	PaqDir *r;
8739a747e4fSDavid du Colombier 	Block *b;
8749a747e4fSDavid du Colombier 	ulong offset;
8759a747e4fSDavid du Colombier 
8769a747e4fSDavid du Colombier 	inflateinit();
8779a747e4fSDavid du Colombier 
8789a747e4fSDavid du Colombier 	bin = Bopen(file, OREAD);
8799a747e4fSDavid du Colombier 	if(bin == nil)
8809a747e4fSDavid du Colombier 		sysfatal("could not open file: %s: %r", file);
8819a747e4fSDavid du Colombier 	if(verify)
8829a747e4fSDavid du Colombier 		ds = sha1(0, 0, 0, 0);
8839a747e4fSDavid du Colombier 
8849a747e4fSDavid du Colombier 	readHeader(&hdr, file, ds);
8859a747e4fSDavid du Colombier 	blocksize = hdr.blocksize;
8869a747e4fSDavid du Colombier 
8879a747e4fSDavid du Colombier 	if(verify) {
8889a747e4fSDavid du Colombier 		readBlocks(file, ds);
8899a747e4fSDavid du Colombier 	} else {
8909a747e4fSDavid du Colombier 		dir = dirstat(file);
8919a747e4fSDavid du Colombier 		if(dir == nil)
8929a747e4fSDavid du Colombier 			sysfatal("could not stat file: %s: %r", file);
8939a747e4fSDavid du Colombier 		offset = dir->length - TrailerSize;
8949a747e4fSDavid du Colombier 		free(dir);
8959a747e4fSDavid du Colombier 		if(Bseek(bin, offset, 0) != offset)
8969a747e4fSDavid du Colombier 			sysfatal("could not seek to trailer: %s", file);
8979a747e4fSDavid du Colombier 	}
8989a747e4fSDavid du Colombier 
8999a747e4fSDavid du Colombier 	readTrailer(&tlr, file, ds);
9009a747e4fSDavid du Colombier 
9019a747e4fSDavid du Colombier 	/* asctime includes a newline - yuk */
902238ca1feSDavid du Colombier 	if(!qflag){
9039a747e4fSDavid du Colombier 		fprint(2, "%s: %s", hdr.label, asctime(gmtime(hdr.time)));
904238ca1feSDavid du Colombier 		fprint(2, "fingerprint: %V\n", tlr.sha1);
905238ca1feSDavid du Colombier 	}
9069a747e4fSDavid du Colombier 
9079a747e4fSDavid du Colombier 	cache = emallocz(cachesize*sizeof(Block));
9089a747e4fSDavid du Colombier 	p = emalloc(cachesize*blocksize);
9099a747e4fSDavid du Colombier 	for(i=0; i<cachesize; i++) {
9109a747e4fSDavid du Colombier 		cache[i].data = p;
9119a747e4fSDavid du Colombier 		p += blocksize;
9129a747e4fSDavid du Colombier 	}
9139a747e4fSDavid du Colombier 
9149a747e4fSDavid du Colombier 	/* hand craft root */
9159a747e4fSDavid du Colombier 	b = blockLoad(tlr.root, DirBlock);
9169a747e4fSDavid du Colombier 	if(b == nil || !checkDirSize(b->data, b->data+blocksize))
9179a747e4fSDavid du Colombier 		sysfatal("could not read root block: %s", file);
9189a747e4fSDavid du Colombier 	r = getDir(b->data);
9199a747e4fSDavid du Colombier 	blockFree(b);
9209a747e4fSDavid du Colombier 	root = emallocz(sizeof(Paq));
9219a747e4fSDavid du Colombier 	root->qid = paqDirQid(r);
9229a747e4fSDavid du Colombier 	root->ref = 1;
9239a747e4fSDavid du Colombier 	root->dir = r;
9249a747e4fSDavid du Colombier 	root->up = root;	/* parent of root is root */
925fe853e23SDavid du Colombier 
926fe853e23SDavid du Colombier 	/* craft root directory if root is a normal file */
927fe853e23SDavid du Colombier 	if(!(root->qid.type&QTDIR)){
928fe853e23SDavid du Colombier 		rootfile = root;
929fe853e23SDavid du Colombier 		root = emallocz(sizeof(Paq));
930fe853e23SDavid du Colombier 		root->qid = rootfile->qid;
931fe853e23SDavid du Colombier 		root->qid.type |= QTDIR;
932fe853e23SDavid du Colombier 		root->qid.path++;
933fe853e23SDavid du Colombier 		root->ref = 1;
934fe853e23SDavid du Colombier 		root->dir = emallocz(sizeof(PaqDir));
935fe853e23SDavid du Colombier 		*root->dir = *r;
936fe853e23SDavid du Colombier 		root->dir->mode |= DMDIR|0111;
937fe853e23SDavid du Colombier 		root->up = root;
938fe853e23SDavid du Colombier 	}
9399a747e4fSDavid du Colombier }
9409a747e4fSDavid du Colombier 
9419a747e4fSDavid du Colombier int
blockRead(uchar * data,ulong addr,int type)9429a747e4fSDavid du Colombier blockRead(uchar *data, ulong addr, int type)
9439a747e4fSDavid du Colombier {
9449a747e4fSDavid du Colombier 	uchar buf[BlockSize];
9459a747e4fSDavid du Colombier 	PaqBlock b;
9469a747e4fSDavid du Colombier 	uchar *cdat;
9479a747e4fSDavid du Colombier 
948fe853e23SDavid du Colombier 	if(Bseek(bin, addr, 0) != addr){
949fe853e23SDavid du Colombier 		fprint(2, "paqfs: seek %lud: %r\n", addr);
9509a747e4fSDavid du Colombier 		return 0;
951fe853e23SDavid du Colombier 	}
952fe853e23SDavid du Colombier 	if(Bread(bin, buf, BlockSize) != BlockSize){
953fe853e23SDavid du Colombier 		fprint(2, "paqfs: read %d at %lud: %r\n", BlockSize, addr);
9549a747e4fSDavid du Colombier 		return 0;
955fe853e23SDavid du Colombier 	}
9569a747e4fSDavid du Colombier 	getBlock(buf, &b);
957fe853e23SDavid du Colombier 	if(b.magic != BlockMagic || b.size > blocksize || b.type != type){
958da51d93aSDavid du Colombier 		fprint(2, "paqfs: bad block: magic %.8lux (want %.8ux) size %lud (max %d) type %ud (want %ud)\n",
959fe853e23SDavid du Colombier 			b.magic, BlockMagic, b.size, blocksize, b.type, type);
9609a747e4fSDavid du Colombier 		return 0;
961fe853e23SDavid du Colombier 	}
9629a747e4fSDavid du Colombier 
9639a747e4fSDavid du Colombier 	switch(b.encoding) {
9649a747e4fSDavid du Colombier 	default:
9659a747e4fSDavid du Colombier 		return 0;
9669a747e4fSDavid du Colombier 	case NoEnc:
9679a747e4fSDavid du Colombier 		if(Bread(bin, data, blocksize) < blocksize)
9689a747e4fSDavid du Colombier 			return 0;
9699a747e4fSDavid du Colombier 		break;
9709a747e4fSDavid du Colombier 	case DeflateEnc:
9719a747e4fSDavid du Colombier 		cdat = emalloc(b.size);
9729a747e4fSDavid du Colombier 		if(Bread(bin, cdat, b.size) < b.size) {
9739a747e4fSDavid du Colombier 			free(cdat);
9749a747e4fSDavid du Colombier 			return 0;
9759a747e4fSDavid du Colombier 		}
9769a747e4fSDavid du Colombier 		if(inflateblock(data, blocksize, cdat, b.size) < 0) {
977fe853e23SDavid du Colombier 			fprint(2, "inflate error: %r\n");
9789a747e4fSDavid du Colombier 			free(cdat);
9799a747e4fSDavid du Colombier 			return 0;
9809a747e4fSDavid du Colombier 		}
9819a747e4fSDavid du Colombier 		free(cdat);
9829a747e4fSDavid du Colombier 		break;
9839a747e4fSDavid du Colombier 	}
9849a747e4fSDavid du Colombier 	if(adler32(0, data, blocksize) != b.adler32)
9859a747e4fSDavid du Colombier 		return 0;
9869a747e4fSDavid du Colombier 	return 1;
9879a747e4fSDavid du Colombier }
9889a747e4fSDavid du Colombier 
9899a747e4fSDavid du Colombier void
readHeader(PaqHeader * hdr,char * name,DigestState * ds)9909a747e4fSDavid du Colombier readHeader(PaqHeader *hdr, char *name, DigestState *ds)
9919a747e4fSDavid du Colombier {
9929a747e4fSDavid du Colombier 	uchar buf[HeaderSize];
9939a747e4fSDavid du Colombier 
9949a747e4fSDavid du Colombier 	if(Bread(bin, buf, HeaderSize) < HeaderSize)
9959a747e4fSDavid du Colombier 		sysfatal("could not read header: %s: %r", name);
9969a747e4fSDavid du Colombier 	if(ds)
9979a747e4fSDavid du Colombier 		sha1(buf, HeaderSize, 0, ds);
9989a747e4fSDavid du Colombier 	getHeader(buf, hdr);
9999a747e4fSDavid du Colombier 	if(hdr->magic != HeaderMagic)
10009a747e4fSDavid du Colombier 		sysfatal("bad header magic 0x%lux: %s", hdr->magic, name);
10019a747e4fSDavid du Colombier 	if(hdr->version != Version)
10029a747e4fSDavid du Colombier 		sysfatal("unknown file version: %s", name);
10039a747e4fSDavid du Colombier }
10049a747e4fSDavid du Colombier 
10059a747e4fSDavid du Colombier void
readBlocks(char * name,DigestState * ds)10069a747e4fSDavid du Colombier readBlocks(char *name, DigestState *ds)
10079a747e4fSDavid du Colombier {
10089a747e4fSDavid du Colombier 	uchar *buf;
10099a747e4fSDavid du Colombier 	PaqBlock b;
10109a747e4fSDavid du Colombier 
10119a747e4fSDavid du Colombier 	buf = emalloc(BlockSize+blocksize);
10129a747e4fSDavid du Colombier 
10139a747e4fSDavid du Colombier 	for(;;) {
10149a747e4fSDavid du Colombier 		if(Bread(bin, buf, 4) < 4)
10159a747e4fSDavid du Colombier 			sysfatal("could not read block: %s: %r", name);
10169a747e4fSDavid du Colombier 		Bseek(bin, -4, 1);
10179a747e4fSDavid du Colombier 		/* check if it is a data block */
10189a747e4fSDavid du Colombier 
10199a747e4fSDavid du Colombier 		if(getl(buf) != BlockMagic)
10209a747e4fSDavid du Colombier 			break;
10219a747e4fSDavid du Colombier 
10229a747e4fSDavid du Colombier 		if(Bread(bin, buf, BlockSize) < BlockSize)
10239a747e4fSDavid du Colombier 			sysfatal("could not read block: %s: %r", name);
10249a747e4fSDavid du Colombier 		if(ds)
10259a747e4fSDavid du Colombier 			sha1(buf, BlockSize, 0, ds);
10269a747e4fSDavid du Colombier 		getBlock(buf, &b);
10279a747e4fSDavid du Colombier 
10289a747e4fSDavid du Colombier 		if(b.size > blocksize)
1029da51d93aSDavid du Colombier 			sysfatal("bad block size: %lud: %s", b.size, name);
10309a747e4fSDavid du Colombier 		if(ds) {
10319a747e4fSDavid du Colombier 			if(Bread(bin, buf, b.size) < b.size)
10329a747e4fSDavid du Colombier 				sysfatal("sysfatal reading block: %s: %r", name);
10339a747e4fSDavid du Colombier 			sha1(buf, b.size, 0, ds);
10349a747e4fSDavid du Colombier 		} else
10359a747e4fSDavid du Colombier 			Bseek(bin, b.size, 1);
10369a747e4fSDavid du Colombier 	}
10379a747e4fSDavid du Colombier 
10389a747e4fSDavid du Colombier 	free(buf);
10399a747e4fSDavid du Colombier }
10409a747e4fSDavid du Colombier 
10419a747e4fSDavid du Colombier void
readTrailer(PaqTrailer * tlr,char * name,DigestState * ds)10429a747e4fSDavid du Colombier readTrailer(PaqTrailer *tlr, char *name, DigestState *ds)
10439a747e4fSDavid du Colombier {
10449a747e4fSDavid du Colombier 	uchar buf[TrailerSize];
1045238ca1feSDavid du Colombier 	uchar digest[SHA1dlen];
10469a747e4fSDavid du Colombier 
10479a747e4fSDavid du Colombier 	if(Bread(bin, buf, TrailerSize) < TrailerSize)
10489a747e4fSDavid du Colombier 		sysfatal("could not read trailer: %s: %r", name);
10499a747e4fSDavid du Colombier 	getTrailer(buf, tlr);
10509a747e4fSDavid du Colombier 	if(tlr->magic != TrailerMagic)
10519a747e4fSDavid du Colombier 		sysfatal("bad trailer magic: %s", name);
10529a747e4fSDavid du Colombier 	if(ds) {
1053238ca1feSDavid du Colombier 		sha1(buf, TrailerSize-SHA1dlen, digest, ds);
1054238ca1feSDavid du Colombier 		if(memcmp(digest, tlr->sha1, SHA1dlen) != 0)
10559a747e4fSDavid du Colombier 			sysfatal("bad sha1 digest: %s", name);
10569a747e4fSDavid du Colombier 	}
10579a747e4fSDavid du Colombier }
10589a747e4fSDavid du Colombier 
10599a747e4fSDavid du Colombier void *
emalloc(ulong n)10609a747e4fSDavid du Colombier emalloc(ulong n)
10619a747e4fSDavid du Colombier {
10629a747e4fSDavid du Colombier 	void *p;
10639a747e4fSDavid du Colombier 
10649a747e4fSDavid du Colombier 	p = malloc(n);
10659a747e4fSDavid du Colombier 	if(!p)
10669a747e4fSDavid du Colombier 		sysfatal("out of memory");
10679a747e4fSDavid du Colombier 	return p;
10689a747e4fSDavid du Colombier }
10699a747e4fSDavid du Colombier 
10709a747e4fSDavid du Colombier void *
emallocz(ulong n)10719a747e4fSDavid du Colombier emallocz(ulong n)
10729a747e4fSDavid du Colombier {
10739a747e4fSDavid du Colombier 	void *p;
10749a747e4fSDavid du Colombier 
10759a747e4fSDavid du Colombier 	p = emalloc(n);
10769a747e4fSDavid du Colombier 	memset(p, 0, n);
10779a747e4fSDavid du Colombier 
10789a747e4fSDavid du Colombier 	return p;
10799a747e4fSDavid du Colombier }
10809a747e4fSDavid du Colombier 
10819a747e4fSDavid du Colombier void *
erealloc(void * p,ulong n)10829a747e4fSDavid du Colombier erealloc(void *p, ulong n)
10839a747e4fSDavid du Colombier {
10849a747e4fSDavid du Colombier 	p = realloc(p, n);
10859a747e4fSDavid du Colombier 	if(!p)
10869a747e4fSDavid du Colombier 		sysfatal("out of memory");
10879a747e4fSDavid du Colombier 	return p;
10889a747e4fSDavid du Colombier }
10899a747e4fSDavid du Colombier 
10909a747e4fSDavid du Colombier char *
estrdup(char * s)10919a747e4fSDavid du Colombier estrdup(char *s)
10929a747e4fSDavid du Colombier {
10939a747e4fSDavid du Colombier 	s = strdup(s);
10949a747e4fSDavid du Colombier 	if(s == nil)
10959a747e4fSDavid du Colombier 		sysfatal("out of memory");
10969a747e4fSDavid du Colombier 	return s;
10979a747e4fSDavid du Colombier }
10989a747e4fSDavid du Colombier 
10999a747e4fSDavid du Colombier 
11009a747e4fSDavid du Colombier ulong
getl(uchar * p)11019a747e4fSDavid du Colombier getl(uchar *p)
11029a747e4fSDavid du Colombier {
11039a747e4fSDavid du Colombier 	return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
11049a747e4fSDavid du Colombier }
11059a747e4fSDavid du Colombier 
11069a747e4fSDavid du Colombier 
11079a747e4fSDavid du Colombier int
gets(uchar * p)11089a747e4fSDavid du Colombier gets(uchar *p)
11099a747e4fSDavid du Colombier {
11109a747e4fSDavid du Colombier 	return (p[0]<<8) | p[1];
11119a747e4fSDavid du Colombier }
11129a747e4fSDavid du Colombier 
11139a747e4fSDavid du Colombier int
checkDirSize(uchar * p,uchar * ep)11149a747e4fSDavid du Colombier checkDirSize(uchar *p, uchar *ep)
11159a747e4fSDavid du Colombier {
11169a747e4fSDavid du Colombier 	int n;
11179a747e4fSDavid du Colombier 	int i;
11189a747e4fSDavid du Colombier 
11199a747e4fSDavid du Colombier 	if(ep-p < 2)
11209a747e4fSDavid du Colombier 		return 0;
11219a747e4fSDavid du Colombier 	n = gets(p);
11229a747e4fSDavid du Colombier 	if(p+n > ep)
11239a747e4fSDavid du Colombier 		return 0;
11249a747e4fSDavid du Colombier 	ep = p+n;
11259a747e4fSDavid du Colombier 	p += 22;
11269a747e4fSDavid du Colombier 	for(i=0; i<3; i++) {
11279a747e4fSDavid du Colombier 		if(p+2 > ep)
11289a747e4fSDavid du Colombier 			return 0;
11299a747e4fSDavid du Colombier 		n = gets(p);
11309a747e4fSDavid du Colombier 		if(p+n > ep)
11319a747e4fSDavid du Colombier 			return 0;
11329a747e4fSDavid du Colombier 		p += n;
11339a747e4fSDavid du Colombier 	}
11349a747e4fSDavid du Colombier 	return 1;
11359a747e4fSDavid du Colombier }
11369a747e4fSDavid du Colombier 
11379a747e4fSDavid du Colombier void
getHeader(uchar * p,PaqHeader * h)11389a747e4fSDavid du Colombier getHeader(uchar *p, PaqHeader *h)
11399a747e4fSDavid du Colombier {
11409a747e4fSDavid du Colombier 	h->magic = getl(p);
11419a747e4fSDavid du Colombier 	h->version = gets(p+4);
11429a747e4fSDavid du Colombier 	h->blocksize = gets(p+6);
1143fe853e23SDavid du Colombier 	if((h->magic>>16) == BigHeaderMagic){
1144fe853e23SDavid du Colombier 		h->magic = HeaderMagic;
1145fe853e23SDavid du Colombier 		h->version = gets(p+2);
1146fe853e23SDavid du Colombier 		h->blocksize = getl(p+4);
1147fe853e23SDavid du Colombier 	}
11489a747e4fSDavid du Colombier 	h->time = getl(p+8);
11499a747e4fSDavid du Colombier 	memmove(h->label, p+12, sizeof(h->label));
11509a747e4fSDavid du Colombier 	h->label[sizeof(h->label)-1] = 0;
11519a747e4fSDavid du Colombier }
11529a747e4fSDavid du Colombier 
11539a747e4fSDavid du Colombier void
getTrailer(uchar * p,PaqTrailer * t)11549a747e4fSDavid du Colombier getTrailer(uchar *p, PaqTrailer *t)
11559a747e4fSDavid du Colombier {
11569a747e4fSDavid du Colombier 	t->magic = getl(p);
11579a747e4fSDavid du Colombier 	t->root = getl(p+4);
1158238ca1feSDavid du Colombier 	memmove(t->sha1, p+8, SHA1dlen);
11599a747e4fSDavid du Colombier }
11609a747e4fSDavid du Colombier 
11619a747e4fSDavid du Colombier void
getBlock(uchar * p,PaqBlock * b)11629a747e4fSDavid du Colombier getBlock(uchar *p, PaqBlock *b)
11639a747e4fSDavid du Colombier {
11649a747e4fSDavid du Colombier 	b->magic = getl(p);
11659a747e4fSDavid du Colombier 	b->size = gets(p+4);
1166fe853e23SDavid du Colombier 	if((b->magic>>16) == BigBlockMagic){
1167fe853e23SDavid du Colombier 		b->magic = BlockMagic;
1168fe853e23SDavid du Colombier 		b->size = getl(p+2);
1169fe853e23SDavid du Colombier 	}
11709a747e4fSDavid du Colombier 	b->type = p[6];
11719a747e4fSDavid du Colombier 	b->encoding = p[7];
11729a747e4fSDavid du Colombier 	b->adler32 = getl(p+8);
11739a747e4fSDavid du Colombier }
11749a747e4fSDavid du Colombier 
11759a747e4fSDavid du Colombier PaqDir *
getDir(uchar * p)11769a747e4fSDavid du Colombier getDir(uchar *p)
11779a747e4fSDavid du Colombier {
11789a747e4fSDavid du Colombier 	PaqDir *pd;
11799a747e4fSDavid du Colombier 
11809a747e4fSDavid du Colombier 	pd = emallocz(sizeof(PaqDir));
11819a747e4fSDavid du Colombier 	pd->qid = getl(p+2);
11829a747e4fSDavid du Colombier 	pd->mode = getl(p+6);
11839a747e4fSDavid du Colombier 	pd->mtime = getl(p+10);
11849a747e4fSDavid du Colombier 	pd->length = getl(p+14);
11859a747e4fSDavid du Colombier 	pd->offset = getl(p+18);
11869a747e4fSDavid du Colombier 	p += 22;
11879a747e4fSDavid du Colombier 	pd->name = getstr(p);
11889a747e4fSDavid du Colombier 	p += gets(p);
11899a747e4fSDavid du Colombier 	pd->uid = getstr(p);
11909a747e4fSDavid du Colombier 	p += gets(p);
11919a747e4fSDavid du Colombier 	pd->gid = getstr(p);
11929a747e4fSDavid du Colombier 
11939a747e4fSDavid du Colombier 	return pd;
11949a747e4fSDavid du Colombier }
11959a747e4fSDavid du Colombier 
11969a747e4fSDavid du Colombier 
11979a747e4fSDavid du Colombier char *
getstr(uchar * p)11989a747e4fSDavid du Colombier getstr(uchar *p)
11999a747e4fSDavid du Colombier {
12009a747e4fSDavid du Colombier 	char *s;
12019a747e4fSDavid du Colombier 	int n;
12029a747e4fSDavid du Colombier 
12039a747e4fSDavid du Colombier 	n = gets(p);
12049a747e4fSDavid du Colombier 	s = emalloc(n+1);
12059a747e4fSDavid du Colombier 	memmove(s, p+2, n);
12069a747e4fSDavid du Colombier 	s[n] = 0;
12079a747e4fSDavid du Colombier 	return s;
12089a747e4fSDavid du Colombier }
12099a747e4fSDavid du Colombier 
12109a747e4fSDavid du Colombier void
usage(void)12119a747e4fSDavid du Colombier usage(void)
12129a747e4fSDavid du Colombier {
12139a747e4fSDavid du Colombier 	fprint(2, "usage: %s [-disv] [-c cachesize] [-m mountpoint] [-M mesgsize] paqfile\n", argv0);
12149a747e4fSDavid du Colombier 	exits("usage");
12159a747e4fSDavid du Colombier }
12169a747e4fSDavid du Colombier 
1217