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