Charles.Forsyth20060303a828770d19 years agoHistory
1504 lines · 28.6 KB · Brainfuck
RawDownload
implement ISO9660; include "sys.m";	sys: Sys;	Dir, Qid, QTDIR, QTFILE, DMDIR: import sys; include "draw.m"; include "daytime.m";	daytime:	Daytime; include "string.m";	str: String; include "styx.m";	styx: Styx;	Rmsg, Tmsg: import styx; include "arg.m"; ISO9660: module{	init:	fn(nil: ref Draw->Context, nil: list of string);}; Sectorsize: con 2048;Maxname: con 256; Enonexist:	con "file does not exist";Eperm:	con "permission denied";Enofile:	con "no file system specified";Eauth:	con "authentication failed";Ebadfid:	con	"invalid fid";Efidinuse:	con	"fid already in use";Enotdir:	con	"not a directory";Esyntax:	con	"file name syntax"; devname: string; chatty := 0;showstyx := 0;progname := "9660srv";stderr: ref Sys->FD;noplan9 := 0;nojoliet := 0;norock := 0; usage(){	sys->fprint(sys->fildes(2), "usage: %s [-rabc] [-9JR] [-s] cd_device dir\n", progname);	raise "fail:usage";} init(nil: ref Draw->Context, args: list of string){	sys = load Sys Sys->PATH; 	sys->pctl(Sys->FORKFD|Sys->NEWPGRP, nil);	stderr = sys->fildes(2); 	if(args != nil)		progname = hd args;	styx = load Styx Styx->PATH;	if(styx == nil)		noload(Styx->PATH);	styx->init(); 	if(args != nil)		progname = hd args;	mountopt := Sys->MREPL;	copt := 0;	stdio := 0; 	arg := load Arg Arg->PATH;	if(arg == nil)		noload(Arg->PATH);	arg->init(args);	while((c := arg->opt()) != 0)		case c {		'v' or 'D' => chatty = 1; showstyx = 1;		'r' => mountopt = Sys->MREPL;		'a' => mountopt = Sys->MAFTER;		'b' => mountopt = Sys->MBEFORE;		'c' => copt = Sys->MCREATE;		's' => stdio = 1;		'9' => noplan9 = 1;		'J' => nojoliet = 1;		'R' => norock = 1;		* => usage();		}	args = arg->argv();	arg = nil; 	if(args == nil || tl args == nil)		usage();	what := hd args;	mountpt := hd tl args; 	daytime = load Daytime Daytime->PATH;	if(daytime == nil)		noload(Daytime->PATH); 	iobufinit(Sectorsize); 	pip := array[2] of ref Sys->FD;	if(stdio){		pip[0] = sys->fildes(0);		pip[1] = sys->fildes(1);	}else		if(sys->pipe(pip) < 0)			error(sys->sprint("can't create pipe: %r")); 	devname = what; 	sync := chan of int;	spawn fileserve(pip[1], sync);	<-sync; 	if(sys->mount(pip[0], nil, mountpt, mountopt|copt, nil) < 0) {		sys->fprint(sys->fildes(2), "%s: mount %s %s failed: %r\n", progname, what, mountpt);		exit;	}} noload(s: string){	sys->fprint(sys->fildes(2), "%s: can't load %s: %r\n", progname, s);	raise "fail:load";} error(p: string){	sys->fprint(sys->fildes(2), "9660srv: %s\n", p);	raise "fail:error";} fileserve(rfd: ref Sys->FD, sync: chan of int){	sys->pctl(Sys->NEWFD|Sys->FORKNS, list of {2, rfd.fd});	rfd = sys->fildes(rfd.fd);	stderr = sys->fildes(2);	sync <-= 1;	while((m := Tmsg.read(rfd, 0)) != nil){		if(showstyx)			chat(sys->sprint("%s...", m.text()));		r: ref Rmsg;		pick t := m {		Readerror =>			error(sys->sprint("mount read error: %s", t.error));		Version => 			r = rversion(t);		Auth =>			r = rauth(t);		Flush => 			r = rflush(t);		Attach => 			r = rattach(t);		Walk => 			r = rwalk(t);		Open => 			r = ropen(t);		Create => 			r = rcreate(t);		Read => 			r = rread(t);		Write => 			r = rwrite(t);		Clunk => 			r = rclunk(t);		Remove => 			r = rremove(t);		Stat => 			r = rstat(t);		Wstat => 			r = rwstat(t);		* =>			error(sys->sprint("invalid T-message tag: %d", tagof m));		}		pick e := r {		Error =>			r.tag = m.tag;		}		rbuf := r.pack();		if(rbuf == nil)			error("bad R-message conversion");		if(showstyx)			chat(r.text()+"\n");		if(styx->write(rfd, rbuf, len rbuf) != len rbuf)			error(sys->sprint("connection write error: %r"));	} 	if(chatty)		chat("server end of file\n");} E(s: string): ref Rmsg.Error{	return ref Rmsg.Error(0, s);} rversion(t: ref Tmsg.Version): ref Rmsg{	(msize, version) := styx->compatible(t, Styx->MAXRPC, Styx->VERSION);	return ref Rmsg.Version(t.tag, msize, version);} rauth(t: ref Tmsg.Auth): ref Rmsg{	return ref Rmsg.Error(t.tag, "authentication not required");} rflush(t: ref Tmsg.Flush): ref Rmsg{	return ref Rmsg.Flush(t.tag);} rattach(t: ref Tmsg.Attach): ref Rmsg{	dname := devname;	if(t.aname != "")		dname = t.aname;	(dev, err) := devattach(dname, Sys->OREAD, Sectorsize);	if(dev == nil)		return E(err); 	xf := Xfs.new(dev);	root := cleanfid(t.fid);	root.qid = Sys->Qid(big 0, 0, Sys->QTDIR);	root.xf = xf;	err = root.attach();	if(err != nil){		clunkfid(t.fid);		return E(err);	}	xf.rootqid = root.qid;	return ref Rmsg.Attach(t.tag, root.qid);} walk1(f: ref Xfile, name: string): string{	if(!(f.qid.qtype & Sys->QTDIR))		return Enotdir;	case name {	"." =>		return nil;	# nop, but shouldn't happen	".." =>		if(f.qid.path==f.xf.rootqid.path)			return nil;		return f.walkup();	* =>		return f.walk(name);	}} rwalk(t: ref Tmsg.Walk): ref Rmsg{	f:=findfid(t.fid);	if(f == nil)		return E(Ebadfid);	nf, sf: ref Xfile;	if(t.newfid != t.fid){		nf = cleanfid(t.newfid);		if(nf == nil)			return E(Efidinuse);		f.clone(nf);		f = nf;	}else		sf = f.save(); 	qids: array of Sys->Qid;	if(len t.names > 0){		qids = array[len t.names] of Sys->Qid;		for(i := 0; i < len t.names; i++){			e := walk1(f, t.names[i]);			if(e != nil){				if(nf != nil){					nf.clunk();					clunkfid(t.newfid);				}else					f.restore(sf);				if(i == 0)					return E(e);				return ref Rmsg.Walk(t.tag, qids[0:i]);			}			qids[i] = f.qid;		}	}	return ref Rmsg.Walk(t.tag, qids);} ropen(t: ref Tmsg.Open): ref Rmsg{	f := findfid(t.fid);	if(f == nil)		return E(Ebadfid);	if(f.flags&Omodes)		return E("open on open file");	e := f.open(t.mode);	if(e != nil)		return E(e);	f.flags = openflags(t.mode);	return ref Rmsg.Open(t.tag, f.qid, Styx->MAXFDATA);} rcreate(t: ref Tmsg.Create): ref Rmsg{	name := t.name;	if(name == "." || name == "..")		return E(Esyntax);	f := findfid(t.fid);	if(f == nil)		return E(Ebadfid);	if(f.flags&Omodes)		return E("create on open file");	if(!(f.qid.qtype&Sys->QTDIR))		return E("create in non-directory");	e := f.create(name, t.perm, t.mode);	if(e != nil)		return E(e);	f.flags = openflags(t.mode);	return ref Rmsg.Create(t.tag, f.qid, Styx->MAXFDATA);} rread(t: ref Tmsg.Read): ref Rmsg{	err: string; 	f := findfid(t.fid);	if(f == nil)		return E(Ebadfid);	if (!(f.flags&Oread))		return E("file not opened for reading");	if(t.count < 0 || t.offset < big 0)		return E("negative offset or count");	b := array[Styx->MAXFDATA] of byte;	count: int;	if(f.qid.qtype & Sys->QTDIR)		(count, err) = f.readdir(b, int t.offset, t.count);	else		(count, err) = f.read(b, int t.offset, t.count);	if(err != nil)		return E(err);	if(count != len b)		b = b[0:count];	return ref Rmsg.Read(t.tag, b);} rwrite(nil: ref Tmsg.Write): ref Rmsg{	return E(Eperm);} rclunk(t: ref Tmsg.Clunk): ref Rmsg{	f := findfid(t.fid);	if(f == nil)		return E(Ebadfid);	f.clunk();	clunkfid(t.fid);	return ref Rmsg.Clunk(t.tag);} rremove(t: ref Tmsg.Remove): ref Rmsg{	f := findfid(t.fid);	if(f == nil)		return E(Ebadfid);	f.clunk();	clunkfid(t.fid);	return E(Eperm);} rstat(t: ref Tmsg.Stat): ref Rmsg{	f := findfid(t.fid);	if(f == nil)		return E(Ebadfid);	(dir, nil) := f.stat();	return ref Rmsg.Stat(t.tag, *dir);} rwstat(nil: ref Tmsg.Wstat): ref Rmsg{	return E(Eperm);} openflags(mode: int): int{	flags := 0;	case mode & ~(Sys->OTRUNC|Sys->ORCLOSE) {	Sys->OREAD =>		flags = Oread;	Sys->OWRITE =>		flags = Owrite;	Sys->ORDWR =>		flags = Oread|Owrite;	}	if(mode & Sys->ORCLOSE)		flags |= Orclose;	return flags;} chat(s: string){	if(chatty)		sys->fprint(stderr, "%s", s);} Fid: adt {	fid:	int;	file:	ref Xfile;}; FIDMOD: con 127;	# primefids := array[FIDMOD] of list of ref Fid; hashfid(fid: int): (ref Fid, array of list of ref Fid){	nl: list of ref Fid; 	hp := fids[fid%FIDMOD:];	nl = nil;	for(l := hp[0]; l != nil; l = tl l){		f := hd l;		if(f.fid == fid){			l = tl l;	# excluding f			for(; nl != nil; nl = tl nl)				l = (hd nl) :: l;	# put examined ones back, in order			hp[0] = l;			return (f, hp);		} else			nl = f :: nl;	}	return (nil, hp);} findfid(fid: int): ref Xfile{	(f, hp) := hashfid(fid);	if(f == nil){		chat("unassigned fid");		return nil;	}	hp[0] = f :: hp[0];	return f.file;} cleanfid(fid: int): ref Xfile{	(f, hp) := hashfid(fid);	if(f != nil){		chat("fid in use");		return nil;	}	f = ref Fid;	f.fid = fid;	f.file = Xfile.new();	hp[0] = f :: hp[0];	return f.file.clean();} clunkfid(fid: int){	(f, nil) := hashfid(fid);	if(f != nil)		f.file.clean();} ### Xfs: adt {	d:	ref Device;	inuse:	int;	issusp:	int;	# system use sharing protocol in use?	suspoff:	int;	# LEN_SKP, if so	isplan9:	int;	# has Plan 9-specific directory info	isrock:	int;	# is rock ridge	rootqid:	Sys->Qid;	ptr:	int;	# tag for private data 	new:	fn(nil: ref Device): ref Xfs;	incref:	fn(nil: self ref Xfs);	decref:	fn(nil: self ref Xfs);}; Xfile:	adt {	xf:	ref Xfs;	flags:	int;	qid:	Sys->Qid;	ptr:	ref Isofile;	# tag for private data 	new:		fn(): ref Xfile;	clean:	fn(nil: self ref Xfile): ref Xfile; 	save:		fn(nil: self ref Xfile): ref Xfile;	restore:	fn(nil: self ref Xfile, s: ref Xfile); 	attach:	fn(nil: self ref Xfile): string;

Lines 1–500 of 1504.