251 lines · 4.2 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * archfs - mount mkfs style archives */ #include <u.h>#include <libc.h>#include <bio.h>#include <auth.h>#include <fcall.h>#include <thread.h>#include <9p.h> Tree *archtree;Biobuf *b;int verbose; typedef struct Ahdr Ahdr;struct Ahdr {	char *name;	Dir;}; typedef struct Arch Arch;struct Arch {	vlong off;	vlong length;}; static void*emalloc(long sz){	void *v; 	v = malloc(sz);	if(v == nil)		sysfatal("malloc %lud fails", sz);	memset(v, 0, sz);	return v;} static char*estrdup(char *s){	s = strdup(s);	if(s == nil)		sysfatal("strdup (%.10s) fails", s);	return s;} static char*Bgetline(Biobuf *b){	char *p; 	if(p = Brdline(b, '\n'))		p[Blinelen(b)-1] = '\0';	return p;} Ahdr*gethdr(Biobuf *b){	Ahdr *a;	char *p, *f[10]; 	if((p = Bgetline(b)) == nil)		return nil; 	if(strcmp(p, "end of archive") == 0) {		werrstr("");		return nil;	} 	if(tokenize(p, f, nelem(f)) != 6) {		werrstr("bad format");		return nil;	} 	a = emalloc(sizeof(*a));	a->name = estrdup(f[0]);	a->mode = strtoul(f[1], 0, 8);	a->uid = estrdup(f[2]);	a->gid = estrdup(f[3]);	a->mtime = strtoll(f[4], 0, 10);	a->length = strtoll(f[5], 0, 10);	return a;} static Arch*newarch(vlong off, vlong length){	static Arch *abuf;	static int nabuf; 	if(nabuf == 0) {		nabuf = 256;		abuf = emalloc(sizeof(Arch)*nabuf);	} 	nabuf--;	abuf->off = off;	abuf->length = length;	return abuf++;} static File*createpath(File *f, char *name, char *u, ulong m){	char *p;	File *nf; 	if(verbose)		fprint(2, "createpath %s\n", name);	incref(f);	while(f && (p = strchr(name, '/'))) {		*p = '\0';		if(strcmp(name, "") != 0 && strcmp(name, ".") != 0){			/* this would be a race if we were multithreaded */			incref(f);	/* so walk doesn't kill it immediately on failure */			if((nf = walkfile(f, name)) == nil)				nf = createfile(f, name, u, DMDIR|0777, nil);			decref(f);			f = nf;		}		*p = '/';		name = p+1;	}	if(f == nil)		return nil; 	incref(f);	if((nf = walkfile(f, name)) == nil)		nf = createfile(f, name, u, m, nil);	decref(f);	return nf;} static voidarchcreatefile(char *name, Arch *arch, Dir *d){	File *f;	f = createpath(archtree->root, name, d->uid, d->mode);	if(f == nil)		sysfatal("creating %s: %r", name);	free(f->gid);	f->gid = estrdup9p(d->gid);	f->aux = arch;	f->mtime = d->mtime;	f->length = d->length;	decref(f);} static voidfsread(Req *r){	Arch *a;	char err[ERRMAX];	int n; 	a = r->fid->file->aux;	if(a->length <= r->ifcall.offset) 		r->ifcall.count = 0;	else if(a->length <= r->ifcall.offset+r->ifcall.count)		r->ifcall.count = a->length - r->ifcall.offset; 	werrstr("unknown error");	if(Bseek(b, a->off+r->ifcall.offset, 0) < 0 	|| (n = Bread(b, r->ofcall.data, r->ifcall.count)) < 0) {		err[0] = '\0';		errstr(err, sizeof err);		respond(r, err);	} else {		r->ofcall.count = n;		respond(r, nil);		}} Srv fs = {	.read=	fsread,}; static voidusage(void){	fprint(2, "usage: archfs [-abcC] [-m mtpt] archfile\n");	exits("usage");} voidmain(int argc, char **argv){	Ahdr *a;	ulong flag;	char *mtpt;	char err[ERRMAX]; 	flag = 0;	mtpt = "/mnt/arch";	ARGBEGIN{	case 'D':		chatty9p++;		break;	case 'a':		flag |= MAFTER;		break;	case 'b':		flag |= MBEFORE;		break;	case 'c':		flag |= MCREATE;		break;	case 'C':		flag |= MCACHE;		break;	case 'm':		mtpt = EARGF(usage());		break;	default:		usage();		break;	}ARGEND; 	if(argc != 1)		usage(); 	if((b = Bopen(argv[0], OREAD)) == nil)		sysfatal("open '%s': %r", argv[0]); 	archtree = fs.tree = alloctree("sys", "sys", DMDIR|0775, nil);	while(a = gethdr(b)) {		archcreatefile(a->name, newarch(Boffset(b), a->length), a);		Bseek(b, a->length, 1);	} 	err[0] = '\0';	errstr(err, sizeof err);	if(err[0])		sysfatal("reading archive: %s", err); 	postmountsrv(&fs, nil, mtpt, flag);	exits(0);}