17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier * archfs - mount mkfs style archives
37dd7cddfSDavid du Colombier */
47dd7cddfSDavid du Colombier
57dd7cddfSDavid du Colombier #include <u.h>
67dd7cddfSDavid du Colombier #include <libc.h>
77dd7cddfSDavid du Colombier #include <bio.h>
87dd7cddfSDavid du Colombier #include <auth.h>
97dd7cddfSDavid du Colombier #include <fcall.h>
107dd7cddfSDavid du Colombier #include <thread.h>
117dd7cddfSDavid du Colombier #include <9p.h>
127dd7cddfSDavid du Colombier
137dd7cddfSDavid du Colombier Tree *archtree;
147dd7cddfSDavid du Colombier Biobuf *b;
157dd7cddfSDavid du Colombier int verbose;
167dd7cddfSDavid du Colombier
177dd7cddfSDavid du Colombier typedef struct Ahdr Ahdr;
187dd7cddfSDavid du Colombier struct Ahdr {
197dd7cddfSDavid du Colombier char *name;
207dd7cddfSDavid du Colombier Dir;
217dd7cddfSDavid du Colombier };
227dd7cddfSDavid du Colombier
237dd7cddfSDavid du Colombier typedef struct Arch Arch;
247dd7cddfSDavid du Colombier struct Arch {
257dd7cddfSDavid du Colombier vlong off;
267dd7cddfSDavid du Colombier vlong length;
277dd7cddfSDavid du Colombier };
287dd7cddfSDavid du Colombier
2959cc4ca5SDavid du Colombier static void*
emalloc(long sz)3059cc4ca5SDavid du Colombier emalloc(long sz)
3159cc4ca5SDavid du Colombier {
3259cc4ca5SDavid du Colombier void *v;
3359cc4ca5SDavid du Colombier
3459cc4ca5SDavid du Colombier v = malloc(sz);
3559cc4ca5SDavid du Colombier if(v == nil)
36*14cc0f53SDavid du Colombier sysfatal("malloc %lud fails", sz);
3759cc4ca5SDavid du Colombier memset(v, 0, sz);
3859cc4ca5SDavid du Colombier return v;
3959cc4ca5SDavid du Colombier }
4059cc4ca5SDavid du Colombier
4159cc4ca5SDavid du Colombier static char*
estrdup(char * s)4259cc4ca5SDavid du Colombier estrdup(char *s)
4359cc4ca5SDavid du Colombier {
4459cc4ca5SDavid du Colombier s = strdup(s);
4559cc4ca5SDavid du Colombier if(s == nil)
46*14cc0f53SDavid du Colombier sysfatal("strdup (%.10s) fails", s);
4759cc4ca5SDavid du Colombier return s;
4859cc4ca5SDavid du Colombier }
4959cc4ca5SDavid du Colombier
507dd7cddfSDavid du Colombier static char*
Bgetline(Biobuf * b)517dd7cddfSDavid du Colombier Bgetline(Biobuf *b)
527dd7cddfSDavid du Colombier {
537dd7cddfSDavid du Colombier char *p;
547dd7cddfSDavid du Colombier
557dd7cddfSDavid du Colombier if(p = Brdline(b, '\n'))
567dd7cddfSDavid du Colombier p[Blinelen(b)-1] = '\0';
577dd7cddfSDavid du Colombier return p;
587dd7cddfSDavid du Colombier }
597dd7cddfSDavid du Colombier
607dd7cddfSDavid du Colombier Ahdr*
gethdr(Biobuf * b)617dd7cddfSDavid du Colombier gethdr(Biobuf *b)
627dd7cddfSDavid du Colombier {
637dd7cddfSDavid du Colombier Ahdr *a;
647dd7cddfSDavid du Colombier char *p, *f[10];
657dd7cddfSDavid du Colombier
667dd7cddfSDavid du Colombier if((p = Bgetline(b)) == nil)
677dd7cddfSDavid du Colombier return nil;
687dd7cddfSDavid du Colombier
697dd7cddfSDavid du Colombier if(strcmp(p, "end of archive") == 0) {
707dd7cddfSDavid du Colombier werrstr("");
717dd7cddfSDavid du Colombier return nil;
727dd7cddfSDavid du Colombier }
737dd7cddfSDavid du Colombier
747dd7cddfSDavid du Colombier if(tokenize(p, f, nelem(f)) != 6) {
757dd7cddfSDavid du Colombier werrstr("bad format");
767dd7cddfSDavid du Colombier return nil;
777dd7cddfSDavid du Colombier }
787dd7cddfSDavid du Colombier
797dd7cddfSDavid du Colombier a = emalloc(sizeof(*a));
807dd7cddfSDavid du Colombier a->name = estrdup(f[0]);
817dd7cddfSDavid du Colombier a->mode = strtoul(f[1], 0, 8);
829a747e4fSDavid du Colombier a->uid = estrdup(f[2]);
839a747e4fSDavid du Colombier a->gid = estrdup(f[3]);
847dd7cddfSDavid du Colombier a->mtime = strtoll(f[4], 0, 10);
857dd7cddfSDavid du Colombier a->length = strtoll(f[5], 0, 10);
867dd7cddfSDavid du Colombier return a;
877dd7cddfSDavid du Colombier }
887dd7cddfSDavid du Colombier
897dd7cddfSDavid du Colombier static Arch*
newarch(vlong off,vlong length)907dd7cddfSDavid du Colombier newarch(vlong off, vlong length)
917dd7cddfSDavid du Colombier {
927dd7cddfSDavid du Colombier static Arch *abuf;
937dd7cddfSDavid du Colombier static int nabuf;
947dd7cddfSDavid du Colombier
957dd7cddfSDavid du Colombier if(nabuf == 0) {
967dd7cddfSDavid du Colombier nabuf = 256;
977dd7cddfSDavid du Colombier abuf = emalloc(sizeof(Arch)*nabuf);
987dd7cddfSDavid du Colombier }
997dd7cddfSDavid du Colombier
1007dd7cddfSDavid du Colombier nabuf--;
1017dd7cddfSDavid du Colombier abuf->off = off;
1027dd7cddfSDavid du Colombier abuf->length = length;
1037dd7cddfSDavid du Colombier return abuf++;
1047dd7cddfSDavid du Colombier }
1057dd7cddfSDavid du Colombier
1067dd7cddfSDavid du Colombier static File*
createpath(File * f,char * name,char * u,ulong m)1079a747e4fSDavid du Colombier createpath(File *f, char *name, char *u, ulong m)
1087dd7cddfSDavid du Colombier {
1097dd7cddfSDavid du Colombier char *p;
1107dd7cddfSDavid du Colombier File *nf;
1117dd7cddfSDavid du Colombier
1127dd7cddfSDavid du Colombier if(verbose)
1139a747e4fSDavid du Colombier fprint(2, "createpath %s\n", name);
1149a747e4fSDavid du Colombier incref(f);
1157dd7cddfSDavid du Colombier while(f && (p = strchr(name, '/'))) {
1169a747e4fSDavid du Colombier *p = '\0';
1179a747e4fSDavid du Colombier if(strcmp(name, "") != 0 && strcmp(name, ".") != 0){
1187dd7cddfSDavid du Colombier /* this would be a race if we were multithreaded */
1199a747e4fSDavid du Colombier incref(f); /* so walk doesn't kill it immediately on failure */
1209a747e4fSDavid du Colombier if((nf = walkfile(f, name)) == nil)
1219a747e4fSDavid du Colombier nf = createfile(f, name, u, DMDIR|0777, nil);
1229a747e4fSDavid du Colombier decref(f);
12359cc4ca5SDavid du Colombier f = nf;
1247dd7cddfSDavid du Colombier }
1259a747e4fSDavid du Colombier *p = '/';
1269a747e4fSDavid du Colombier name = p+1;
1279a747e4fSDavid du Colombier }
1287dd7cddfSDavid du Colombier if(f == nil)
1297dd7cddfSDavid du Colombier return nil;
1307dd7cddfSDavid du Colombier
1319a747e4fSDavid du Colombier incref(f);
1329a747e4fSDavid du Colombier if((nf = walkfile(f, name)) == nil)
1339a747e4fSDavid du Colombier nf = createfile(f, name, u, m, nil);
1349a747e4fSDavid du Colombier decref(f);
1357dd7cddfSDavid du Colombier return nf;
1367dd7cddfSDavid du Colombier }
1377dd7cddfSDavid du Colombier
1387dd7cddfSDavid du Colombier static void
archcreatefile(char * name,Arch * arch,Dir * d)1399a747e4fSDavid du Colombier archcreatefile(char *name, Arch *arch, Dir *d)
1407dd7cddfSDavid du Colombier {
1417dd7cddfSDavid du Colombier File *f;
1429a747e4fSDavid du Colombier f = createpath(archtree->root, name, d->uid, d->mode);
1437dd7cddfSDavid du Colombier if(f == nil)
1447dd7cddfSDavid du Colombier sysfatal("creating %s: %r", name);
1459a747e4fSDavid du Colombier free(f->gid);
1469a747e4fSDavid du Colombier f->gid = estrdup9p(d->gid);
1477dd7cddfSDavid du Colombier f->aux = arch;
1487dd7cddfSDavid du Colombier f->mtime = d->mtime;
1497dd7cddfSDavid du Colombier f->length = d->length;
1509a747e4fSDavid du Colombier decref(f);
1517dd7cddfSDavid du Colombier }
1527dd7cddfSDavid du Colombier
1537dd7cddfSDavid du Colombier static void
fsread(Req * r)1549a747e4fSDavid du Colombier fsread(Req *r)
1557dd7cddfSDavid du Colombier {
1567dd7cddfSDavid du Colombier Arch *a;
1579a747e4fSDavid du Colombier char err[ERRMAX];
1589a747e4fSDavid du Colombier int n;
1597dd7cddfSDavid du Colombier
1609a747e4fSDavid du Colombier a = r->fid->file->aux;
1619a747e4fSDavid du Colombier if(a->length <= r->ifcall.offset)
1629a747e4fSDavid du Colombier r->ifcall.count = 0;
1639a747e4fSDavid du Colombier else if(a->length <= r->ifcall.offset+r->ifcall.count)
1649a747e4fSDavid du Colombier r->ifcall.count = a->length - r->ifcall.offset;
1657dd7cddfSDavid du Colombier
1669a747e4fSDavid du Colombier werrstr("unknown error");
1679a747e4fSDavid du Colombier if(Bseek(b, a->off+r->ifcall.offset, 0) < 0
1689a747e4fSDavid du Colombier || (n = Bread(b, r->ofcall.data, r->ifcall.count)) < 0) {
1697dd7cddfSDavid du Colombier err[0] = '\0';
1709a747e4fSDavid du Colombier errstr(err, sizeof err);
1717dd7cddfSDavid du Colombier respond(r, err);
1727dd7cddfSDavid du Colombier } else {
1739a747e4fSDavid du Colombier r->ofcall.count = n;
1747dd7cddfSDavid du Colombier respond(r, nil);
1757dd7cddfSDavid du Colombier }
1767dd7cddfSDavid du Colombier }
1777dd7cddfSDavid du Colombier
1789a747e4fSDavid du Colombier Srv fs = {
1799a747e4fSDavid du Colombier .read= fsread,
1807dd7cddfSDavid du Colombier };
1817dd7cddfSDavid du Colombier
1827dd7cddfSDavid du Colombier static void
usage(void)1837dd7cddfSDavid du Colombier usage(void)
1847dd7cddfSDavid du Colombier {
1857dd7cddfSDavid du Colombier fprint(2, "usage: archfs [-abcC] [-m mtpt] archfile\n");
1867dd7cddfSDavid du Colombier exits("usage");
1877dd7cddfSDavid du Colombier }
1887dd7cddfSDavid du Colombier
1897dd7cddfSDavid du Colombier void
main(int argc,char ** argv)1907dd7cddfSDavid du Colombier main(int argc, char **argv)
1917dd7cddfSDavid du Colombier {
1927dd7cddfSDavid du Colombier Ahdr *a;
1937dd7cddfSDavid du Colombier ulong flag;
1947dd7cddfSDavid du Colombier char *mtpt;
1959a747e4fSDavid du Colombier char err[ERRMAX];
1967dd7cddfSDavid du Colombier
1977dd7cddfSDavid du Colombier flag = 0;
1987dd7cddfSDavid du Colombier mtpt = "/mnt/arch";
1997dd7cddfSDavid du Colombier ARGBEGIN{
2009a747e4fSDavid du Colombier case 'D':
2019a747e4fSDavid du Colombier chatty9p++;
2029a747e4fSDavid du Colombier break;
2037dd7cddfSDavid du Colombier case 'a':
2047dd7cddfSDavid du Colombier flag |= MAFTER;
2057dd7cddfSDavid du Colombier break;
2067dd7cddfSDavid du Colombier case 'b':
2077dd7cddfSDavid du Colombier flag |= MBEFORE;
2087dd7cddfSDavid du Colombier break;
2097dd7cddfSDavid du Colombier case 'c':
2107dd7cddfSDavid du Colombier flag |= MCREATE;
2117dd7cddfSDavid du Colombier break;
2127dd7cddfSDavid du Colombier case 'C':
2137dd7cddfSDavid du Colombier flag |= MCACHE;
2147dd7cddfSDavid du Colombier break;
2157dd7cddfSDavid du Colombier case 'm':
216de8abbc9SDavid du Colombier mtpt = EARGF(usage());
2177dd7cddfSDavid du Colombier break;
2187dd7cddfSDavid du Colombier default:
2197dd7cddfSDavid du Colombier usage();
2207dd7cddfSDavid du Colombier break;
2217dd7cddfSDavid du Colombier }ARGEND;
2227dd7cddfSDavid du Colombier
2237dd7cddfSDavid du Colombier if(argc != 1)
2247dd7cddfSDavid du Colombier usage();
2257dd7cddfSDavid du Colombier
2267dd7cddfSDavid du Colombier if((b = Bopen(argv[0], OREAD)) == nil)
2277dd7cddfSDavid du Colombier sysfatal("open '%s': %r", argv[0]);
2287dd7cddfSDavid du Colombier
2299a747e4fSDavid du Colombier archtree = fs.tree = alloctree("sys", "sys", DMDIR|0775, nil);
2307dd7cddfSDavid du Colombier while(a = gethdr(b)) {
2319a747e4fSDavid du Colombier archcreatefile(a->name, newarch(Boffset(b), a->length), a);
2327dd7cddfSDavid du Colombier Bseek(b, a->length, 1);
2337dd7cddfSDavid du Colombier }
2347dd7cddfSDavid du Colombier
2357dd7cddfSDavid du Colombier err[0] = '\0';
2369a747e4fSDavid du Colombier errstr(err, sizeof err);
2377dd7cddfSDavid du Colombier if(err[0])
2387dd7cddfSDavid du Colombier sysfatal("reading archive: %s", err);
2397dd7cddfSDavid du Colombier
2409a747e4fSDavid du Colombier postmountsrv(&fs, nil, mtpt, flag);
2417dd7cddfSDavid du Colombier exits(0);
2427dd7cddfSDavid du Colombier }
243