Charles.Forsyth20060303a828770d19 years agoHistory
195 lines · 4.0 KB · Brainfuck
RawDownload
implement Bundle;include "sys.m";	sys: Sys;include "bufio.m";	bufio: Bufio;	Iobuf: import bufio;include "readdir.m";	readdir: Readdir;include "draw.m";include "sh.m";include "fslib.m";	fslib: Fslib;	Report, Value, type2s, report, quit: import fslib;	Fschan, Fsdata, Entrychan, Entry,	Gatechan, Gatequery, Nilentry, Option,	Next, Down, Skip, Quit: import Fslib;include "bundle.m"; # XXX if we can't open a directory, is it ever worth passing its metadata# through anyway? EOF: con "end of archive\n"; types(): string{	return "vx";}badmod(p: string){	sys->fprint(sys->fildes(2), "fs: bundle: cannot load %s: %r\n", p);	raise "fail:bad module";} init(){	sys = load Sys Sys->PATH;	readdir = load Readdir Readdir->PATH;	if(readdir == nil)		badmod(Readdir->PATH);	bufio = load Bufio Bufio->PATH;	if(bufio == nil)		badmod(Readdir->PATH);	bufio->fopen(nil, Sys->OREAD);		# XXX no bufio->init!	fslib = load Fslib Fslib->PATH;	if(fslib == nil)		badmod(Readdir->PATH);} run(nil: ref Draw->Context, report: ref Report,			nil: list of Option, args: list of ref Value): ref Value{	return ref Value.V(		bundle(			report,			bufio->fopen(sys->fildes(1), Sys->OWRITE),			(hd args).x().i		)	);} bundle(r: ref Report, iob: ref Iobuf, c: Fschan): chan of int{	sync := chan of int;	spawn bundleproc(c, sync, iob, r.start("bundle"));	return sync;} bundleproc(c: Fschan, sync: chan of int, iob: ref Iobuf, errorc: chan of string){	if(sync != nil && <-sync == 0){		(<-c).t1 <-= Quit;		quit(errorc);	}	(d, reply) := <-c;	if(d.dir == nil){		report(errorc, "no root directory");		endarchive(iob, errorc);	}	if(puts(iob, dir2header(d.dir), errorc) == -1){		reply <-= Quit;		quit(errorc);	}	reply <-= Down;	bundledir(d.dir.name, d, c, iob, errorc);	endarchive(iob, errorc);} endarchive(iob: ref Iobuf, errorc: chan of string){	if(puts(iob, EOF, errorc) != -1)		iob.flush();	quit(errorc);	exit;} bundledir(path: string, d: Fsdata,		c: Fschan,		iob: ref Iobuf, errorc: chan of string){	if(d.dir.mode & Sys->DMDIR){		path[len path] = '/';		for(;;){			(ent, reply) := <-c;			if(ent.dir == nil){				reply <-= Skip;				break;			}			if(puts(iob, dir2header(ent.dir), errorc) == -1){				reply <-= Quit;				quit(errorc);			}			reply <-= Down;			bundledir(path + ent.dir.name, ent, c, iob, errorc);		}		iob.putc('\n');	}else{		buf: array of byte;		reply: chan of int;		length := big d.dir.length;		n := big 0;		for(;;){			((nil, buf), reply) = <-c;			if(buf == nil){				reply <-= Skip;				break;			}			if(write(iob, buf, len buf, errorc) != len buf){				reply <-= Quit;				quit(errorc);			}			n += big len buf;			if(n > length){		# should never happen				report(errorc, sys->sprint("%q is longer than expected (fatal)", path));				reply <-= Quit;				quit(errorc);			}			if(n == length){				reply <-= Skip;				break;			}			reply <-= Next;		}		if(n < length){			report(errorc, sys->sprint("%q is shorter than expected (%bd/%bd); adding null bytes", path, n, length));			buf = array[Sys->ATOMICIO] of {* => byte 0};			while(n < length){				nb := len buf;				if(length - n < big len buf)					nb = int (length - n);				if(write(iob, buf, nb, errorc) != nb){					(<-c).t1 <-= Quit;					quit(errorc);				}				report(errorc, sys->sprint("added %d null bytes", nb));				n += big nb;			}		}	}} dir2header(d: ref Sys->Dir): string{	return sys->sprint("%q %uo %q %q %ud %bd\n", d.name, d.mode, d.uid, d.gid, d.mtime, d.length);} puts(iob: ref Iobuf, s: string, errorc: chan of string): int{	{		if(iob.puts(s) == -1)			report(errorc, sys->sprint("write error: %r"));		return 0;	} exception {	"write on closed pipe" =>		return -1;	}} write(iob: ref Iobuf, buf: array of byte, n: int, errorc: chan of string): int{	{		nw := iob.write(buf, n);		if(nw < n){			if(nw >= 0)				report(errorc, "short write");			else{				report(errorc, sys->sprint("write error: %r"));			}		}		return nw;	} exception {	"write on closed pipe" =>		report(errorc, "write on closed pipe");		return -1;	}}