Charles.Forsyth20060303a828770d19 years agoHistory
579 lines · 11.3 KB · Brainfuck
RawDownload
implement Archfs; include "sys.m";	sys : Sys;include "draw.m";include "bufio.m";	bufio : Bufio;include "arg.m";	arg : Arg;include "string.m";	str : String;include "daytime.m";	daytime : Daytime;include "styx.m";	styx: Styx;include "archfs.m";include "arch.m";	arch : Arch; # add write some day Iobuf : import bufio;Tmsg, Rmsg: import styx; Einuse		: con "fid already in use";Ebadfid		: con "bad fid";Eopen		: con "fid already opened";Enotfound	: con "file does not exist";Enotdir		: con "not a directory";Eperm		: con "permission denied";Ebadarg		: con "bad argument";Eexists		: con "file already exists"; UID : con "inferno";GID : con "inferno"; DEBUG: con 0; Dir : adt {	dir : Sys->Dir;	offset : int;	parent : cyclic ref Dir;	child : cyclic ref Dir;	sibling : cyclic ref Dir;}; Fid : adt {	fid : int;	open: int;	dir : ref Dir;	next : cyclic ref Fid;}; HTSZ : con 32;fidtab := array[HTSZ] of ref Fid; root : ref Dir;qid : int;mtpt := "/mnt";bio : ref Iobuf;buf : array of byte;skip := 0; # Archfs : module# {# 	init : fn(ctxt : ref Draw->Context, args : list of string);# }; init(nil : ref Draw->Context, args : list of string){	init0(nil, args, nil);} initc(args : list of string, c : chan of int){	init0(nil, args, c);} chanint : chan of int; init0(nil : ref Draw->Context, args : list of string, chi : chan of int){	chanint = chi;	sys = load Sys Sys->PATH;	bufio = load Bufio Bufio->PATH;	arg = load Arg Arg->PATH;	str = load String String->PATH;	daytime = load Daytime Daytime->PATH;	styx = load Styx Styx->PATH;	arch = load Arch Arch->PATH;	if (bufio == nil || arg == nil || styx == nil || arch == nil)		fatal("failed to load modules", 1);	styx->init();	arch->init(bufio);	arg->init(args);	while ((c := arg->opt()) != 0) {		case c {			'm' =>				mtpt = arg->arg();				if (mtpt == nil)					fatal("mount point missing", 1);			's' =>				skip = 1;		}	}	args = arg->argv();	if (args == nil)		fatal("missing archive file", 1);	buf = array[Sys->ATOMICIO] of byte;	# root = newdir("/", UID, GID, 8r755|Sys->DMDIR, daytime->now());	root = newdir(basename(mtpt), UID, GID, 8r755|Sys->DMDIR, daytime->now());	root.parent = root;	readarch(hd args, tl args);	p := array[2] of ref Sys->FD;	if(sys->pipe(p) < 0)		fatal("can't create pipe", 1);	ch := chan of ref Tmsg;	sync := chan of int;	spawn reader(p[1], ch, sync);	<- sync;	pidch := chan of int;	spawn serve(p[1], ch, pidch);	pid := <- pidch;	if(sys->mount(p[0], nil, mtpt, Sys->MREPL, nil) < 0)		fatal(sys->sprint("cannot mount archive on %s: %r", mtpt), 1);	p[0] = p[1] = nil;	if (chi != nil) {		chi <-= pid;		chanint = nil;	}} reply(fd: ref Sys->FD, m: ref Rmsg): int{	if(DEBUG)		sys->fprint(sys->fildes(2), "R: %s\n", m.text());	s := m.pack();	if(s == nil)		return -1;	return sys->write(fd, s, len s);} error(fd: ref Sys->FD, m: ref Tmsg, e : string){	reply(fd, ref Rmsg.Error(m.tag, e));} reader(fd: ref Sys->FD, ch: chan of ref Tmsg, sync: chan of int){	sys->pctl(Sys->NEWFD|Sys->NEWNS, fd.fd :: nil);	sync <-= 1;	while((m := Tmsg.read(fd, Styx->MAXRPC)) != nil && tagof m != tagof Tmsg.Readerror)		ch <-= m;	ch <-= m;} serve(fd: ref Sys->FD, ch : chan of ref Tmsg, pidch : chan of int){	e : string;	f : ref Fid; 	pidch <-= sys->pctl(0, nil);	for (;;) {		m0 := <- ch;		if (m0 == nil)			return;		if(DEBUG)			sys->fprint(sys->fildes(2), "T: %s\n", m0.text());		pick m := m0 {			Readerror =>				fatal("read error on styx server", 1);			Version =>				(s, v) := styx->compatible(m, Styx->MAXRPC, Styx->VERSION);				reply(fd, ref Rmsg.Version(m.tag, s, v));			Auth =>				error(fd, m, "no authentication required");			Flush =>				reply(fd, ref Rmsg.Flush(m.tag));			Walk =>				(f, e) = mapfid(m.fid);				if (e != nil) {					error(fd, m, e);					continue;				}				if (f.open) {					error(fd, m, Eopen);					continue;				}				err := 0;				dir := f.dir;				nq := 0;				nn := len m.names;				qids := array[nn] of Sys->Qid;				if(nn > 0){					for(k := 0; k < nn; k++){						if ((dir.dir.mode & Sys->DMDIR) == 0) {							if(k == 0){								error(fd, m, Enotdir);								err = 1;							}							break;						}						dir  = lookup(dir, m.names[k]);						if (dir == nil) {							if(k == 0){								error(fd, m, Enotfound);								err = 1;							}							break;						}						qids[nq++] = dir.dir.qid;					}				}				if(err)					continue;				if(nq < nn)					qids = qids[0: nq];				if(nq == nn){					if(m.newfid != m.fid){						f = newfid(m.newfid);						if (f == nil) {							error(fd, m, Einuse);							continue;						}					}					f.dir = dir;				}				reply(fd, ref Rmsg.Walk(m.tag, qids));			Open =>				(f, e) = mapfid(m.fid);				if (e != nil) {					error(fd, m, e);					continue;				}				if (m.mode & (Sys->OWRITE|Sys->ORDWR|Sys->OTRUNC|Sys->ORCLOSE)) {					error(fd, m, Eperm);					continue;				}				f.open = 1;				reply(fd, ref Rmsg.Open(m.tag, f.dir.dir.qid, Styx->MAXFDATA));			Create =>				error(fd, m, Eperm);			Read =>				(f, e) = mapfid(m.fid);				if (e != nil) {					error(fd, m, e);					continue;				}				data := readdir(f.dir, int m.offset, m.count);				reply(fd, ref Rmsg.Read(m.tag, data));			Write =>				error(fd, m, Eperm);							Clunk =>				(f, e) = mapfid(m.fid);				if (e != nil) {					error(fd, m, e);					continue;				}				freefid(f);				reply(fd, ref Rmsg.Clunk(m.tag));			Stat =>				(f, e) = mapfid(m.fid);				if (e != nil) {					error(fd, m, e);					continue;				}				reply(fd, ref Rmsg.Stat(m.tag, f.dir.dir));			Remove =>				error(fd, m, Eperm);			Wstat =>				error(fd, m, Eperm);			Attach =>				f = newfid(m.fid);				if (f == nil) {					error(fd, m, Einuse);					continue;				}				f.dir = root;				reply(fd, ref Rmsg.Attach(m.tag, f.dir.dir.qid));			* =>				fatal("unknown styx message", 1);		}	}} newfid(fid : int) : ref Fid{	(f, nil) := mapfid(fid);	if(f != nil)		return nil;	f = ref Fid;	f.fid = fid;	f.open = 0;	hv := hashval(fid);	f.next = fidtab[hv];	fidtab[hv] = f;	return f;} freefid(f: ref Fid){	hv := hashval(f.fid);	lf : ref Fid;	for(ff := fidtab[hv]; ff != nil; ff = ff.next){		if(f == ff){			if(lf == nil)				fidtab[hv] = ff.next;			else				lf.next = ff.next;			return;		}		lf = ff;	}	fatal("cannot find fid", 1);}	mapfid(fid : int) : (ref Fid, string){	hv := hashval(fid);	for (f := fidtab[hv]; f != nil; f = f.next)		if (int f.fid == fid)			break;	if (f == nil)		return (nil, Ebadfid);	if (f.dir == nil)		return (nil, Enotfound);	return (f, nil);} hashval(n : int) : int{	return (n & ~Sys->DMDIR)%HTSZ;} readarch(f : string, args : list of string){	ar := arch->openarchfs(f);	if(ar == nil || ar.b == nil)		fatal(sys->sprint("cannot open %s(%r)\n", f), 1);	bio = ar.b;	while ((a := arch->gethdr(ar)) != nil) {		if (args != nil) {			if (!selected(a.name, args)) {				if (skip)					return;				arch->drain(ar, int a.d.length);				continue;			}			mkdirs("/", a.name);		}		d := mkdir(a.name, a.d.mode, a.d.mtime, a.d.uid, a.d.gid, 0);		if((a.d.mode & Sys->DMDIR) == 0) {			d.dir.length = a.d.length;			d.offset = int bio.offset();		}		arch->drain(ar, int a.d.length);	}	if (ar.err != nil)		fatal(ar.err, 0);} selected(s: string, args: list of string): int{	for(; args != nil; args = tl args)		if(fileprefix(hd args, s))			return 1;	return 0;} fileprefix(prefix, s: string): int{	n := len prefix;	m := len s;	if(n > m || !str->prefix(prefix, s))		return 0;	if(m > n && s[n] != '/')		return 0;	return 1;} basename(f : string) : string{	for (i := len f; i > 0; ) 		if (f[--i] == '/')			return f[i+1:];	return f;} split(p : string) : (string, string){	if (p == nil)		fatal("nil string in split", 1);	if (p[0] != '/')		fatal("p0 not / in split", 1);	while (p[0] == '/')		p = p[1:];	i := 0;	while (i < len p && p[i] != '/')		i++;	if (i == len p)		return (p, nil);	else		return (p[0:i], p[i:]);} mkdirs(basedir, name: string){	(nil, names) := sys->tokenize(name, "/");	while(names != nil) {		# sys->print("mkdir %s\n", basedir);		mkdir(basedir, 8r775|Sys->DMDIR, daytime->now(), UID, GID, 1);		if(tl names == nil)			break;		basedir = basedir + "/" + hd names;		names = tl names;	}} readdir(d : ref Dir, offset : int, n : int) : array of byte{	if (d.dir.mode & Sys->DMDIR)		return readd(d, offset, n);	else		return readf(d, offset, n);}	readd(d : ref Dir, o : int, n : int) : array of byte{	k := 0;	m := 0;	b := array[n] of byte;	for (s := d.child; s != nil; s = s.sibling) {		l := styx->packdirsize(s.dir);		if(k < o){			k += l;			continue;		}		if(m+l > n)			break;		b[m: ] = styx->packdir(s.dir);		m += l;	}	return b[0: m];} readf(d : ref Dir, offset : int, n : int) : array of byte{	leng := int d.dir.length;	if (offset+n > leng)		n = leng-offset;	if (n <= 0 || offset < 0)		return nil;	bio.seek(big (d.offset+offset), Bufio->SEEKSTART);	a := array[n] of byte;	p := 0;	m := 0;	for ( ; n != 0; n -= m) {		l := len buf;		if (n < l)			l = n;		m = bio.read(buf, l);		if (m <= 0 || m != l)			fatal("premature eof", 1);		a[p:] = buf[0:m];		p += m;	}	return a;} mkdir(f : string, mode : int, mtime : int, uid : string, gid : string, existsok : int) : ref Dir{	if (f == "/")		return nil;	d := newdir(basename(f), uid, gid, mode, mtime);	addfile(d, f, existsok);	return d;} addfile(d : ref Dir, path : string, existsok : int){	elem : string; 	opath := path;	p := prev := root;	basedir := "";# sys->print("addfile %s : %s\n", d.dir.name, path);	while (path != nil) {		(elem, path) = split(path);		basedir += "/" + elem;		op := p;		p = lookup(p, elem);		if (path == nil) {			if (p != nil) {				if (!existsok && (p.dir.mode&Sys->DMDIR) == 0)					sys->fprint(sys->fildes(2), "addfile: %s already there", opath);					# fatal(sys->sprint("addfile: %s already there", opath), 1);				return;			}			if (prev.child == nil)				prev.child = d;

Lines 1–500 of 579.