forsyth20121205-174063a80cc13 years agoHistory
288 lines · 5.6 KB · Brainfuck
RawDownload
implement Arch; include "sys.m";	sys: Sys;include "draw.m";include "daytime.m";	daytime : Daytime;include "string.m";	str : String;include "bufio.m";	bufio : Bufio;	Iobuf : import bufio;include "sh.m";include "arch.m"; addp := 1; buf := array[Sys->ATOMICIO] of byte; init(bio: Bufio){	sys = load Sys Sys->PATH;	if(bio == nil)		bufio = load Bufio Bufio->PATH;	else		bufio = bio;	daytime = load Daytime Daytime->PATH;	str = load String String->PATH;} addperms(p: int){	addp = p;} openarch(file : string) : ref Archive{	return openarch0(file, 1);} openarchfs(file : string) : ref Archive{	return openarch0(file, 0);} openarch0(file : string, newpgrp : int) : ref Archive{	pid := 0;	canseek := 1;	b := bufio->open(file, Bufio->OREAD);	if (b == nil)		return nil;	if (b.getb() == 16r1f && ((c := b.getb()) == 16r8b || c == 16r9d)) {		# spawn gunzip		canseek = 0;		(b, pid) = gunzipstream(file, newpgrp);		if (b == nil)			return nil;	}	else		b.seek(big 0, Bufio->SEEKSTART);	ar := ref Archive;	ar.b = b;	ar.nexthdr = 0;	ar.canseek = canseek;	ar.pid = pid;	ar.hdr = ref Ahdr;	ar.hdr.d = ref Sys->Dir;	return ar;} EOARCH : con "end of archive\n";PREMEOARCH : con "premature end of archive";NFLDS : con 6; openarchgz(file : string) : (string, ref Sys->FD){	ar := openarch(file);	if (ar == nil || ar.canseek)		return (nil, nil);	(newfile, fd) := opentemp("wrap.gz");	if (fd == nil)		return (nil, nil);	bout := bufio->fopen(fd, Bufio->OWRITE);	if (bout == nil)		return (nil, nil);	while ((a := gethdr(ar)) != nil) {		if (len a.name >= 5 && a.name[0:5] == "/wrap") {			puthdr(bout, a.name, a.d);			getfile(ar, bout, int a.d.length);		}		else			break;	}	closearch(ar);	bout.puts(EOARCH);	bout.flush();	sys->seek(fd, big 0, Sys->SEEKSTART);	return (newfile, fd);} gunzipstream(file : string, newpgrp : int) : (ref Iobuf, int){	p := array[2] of ref Sys->FD;	if (sys->pipe(p) < 0)		return (nil, 0);	fd := sys->open(file, Sys->OREAD);	if (fd == nil)		return (nil, 0);	b := bufio->fopen(p[0], Bufio->OREAD);	if (b == nil)		return (nil, 0);	c := chan of int;	spawn gunzip(fd, p[1], c, newpgrp);	pid := <- c;	p[0] = p[1] = nil;	if (pid < 0)		return (nil, 0);	return (b, pid);} GUNZIP : con "/dis/gunzip.dis"; gunzip(stdin : ref Sys->FD, stdout : ref Sys->FD, c : chan of int, newpgrp : int){	if (newpgrp)		pid := sys->pctl(Sys->FORKFD|Sys->NEWPGRP, nil);	else		pid = sys->pctl(Sys->FORKFD, nil);	sys->dup(stdin.fd, 0);	sys->dup(stdout.fd, 1);	sys->dup(1, 2);	stdin = stdout = nil;	cmd := load Command GUNZIP;	if (cmd == nil) {		c <-= -1;		return;	}	c <-= pid;	cmd->init(nil, GUNZIP :: nil);} closearch(ar : ref Archive){	if (ar.pid != 0) {		fd := sys->open("#p/" + string ar.pid + "/ctl", sys->OWRITE);		if (fd != nil)			sys->fprint(fd, "killgrp");	}	ar.b.close();	ar.b = nil;} gethdr(ar : ref Archive) : ref Ahdr{	a := ar.hdr;	b := ar.b;	m := int b.offset();	n := ar.nexthdr;	if (m != n) {		if (ar.canseek)			b.seek(big n, Bufio->SEEKSTART);		else {			if (m > n)				fatal(sys->sprint("bad offset in gethdr: m=%d n=%d", m, n));			if(drain(ar, n-m) < 0)				return nil;		}	}	if ((s := b.gets('\n')) == nil) {		ar.err = PREMEOARCH;		return nil;	}# fd := sys->open("./debug", Sys->OWRITE);# sys->seek(fd, 0, Sys->SEEKEND);# sys->fprint(fd, "gethdr: %d %d %d %d %s\n", ar.canseek, m, n, b.offset(), s);# fd = nil;	if (s == EOARCH)		return nil;	(nf, fs) := sys->tokenize(s, " \t\n");	if(nf != NFLDS) {		ar.err = "too few fields in file header";		return nil;	}	a.name = hd fs;						fs = tl fs;	(a.d.mode, nil) = str->toint(hd fs, 8);		fs = tl fs;	a.d.uid = hd fs;						fs = tl fs;	a.d.gid = hd fs;						fs = tl fs;	(a.d.mtime, nil) = str->toint(hd fs, 10);	fs = tl fs;	(tmp, nil) := str->toint(hd fs, 10);		fs = tl fs;	a.d.length = big tmp;	ar.nexthdr = int (b.offset()+a.d.length);	return a;} getfile(ar : ref Archive, bout : ref Bufio->Iobuf, n : int) : string{	err: string;	bin := ar.b;	while (n > 0) {		m := len buf;		if (n < m)			m = n;		p := bin.read(buf, m);		if (p != m)			return PREMEOARCH;		p = bout.write(buf, m);		if (p != m)			err = sys->sprint("cannot write: %r");		n -= m;	}	return err;	} puthdr(b : ref Iobuf, name : string, d : ref Sys->Dir){	mode := d.mode;	if(addp){		mode |= 8r664;		if(mode & Sys->DMDIR || mode & 8r111)			mode |= 8r111;	}	b.puts(sys->sprint("%s %uo %s %s %ud %d\n", name, mode, d.uid, d.gid, d.mtime, int d.length));} putstring(b : ref Iobuf, s : string){	b.puts(s);} putfile(b : ref Iobuf, f : string, n : int) : string{	fd := sys->open(f, Sys->OREAD);	if (fd == nil)		return sys->sprint("cannot open %s: %r", f);	i := 0;	for (;;) {		m := sys->read(fd, buf, len buf);		if (m < 0)			return sys->sprint("cannot read %s: %r", f);		if (m == 0)			break;		if (b.write(buf, m) != m)			return sys->sprint("%s: cannot write: %r", f);		i += m;	}	if (i != n) {		b.seek(big (n-i), Sys->SEEKRELA);		return sys->sprint("%s: %d bytes written: should be %d", f, i, n);	}	return nil;} putend(b : ref Iobuf){	b.puts(EOARCH);	b.flush();} drain(ar : ref Archive, n : int) : int{	while (n > 0) {		m := n;		if (m > len buf)			m = len buf;		p := ar.b.read(buf, m);		if (p != m){			ar.err = "unexpectedly short read";			return -1;		}		n -= m;	}	return 0;	} opentemp(prefix: string): (string, ref Sys->FD){	name := sys->sprint("/tmp/%s.%ud.%d", prefix, daytime->now(), sys->pctl(0, nil));	# would use ORCLOSE here but it messes up under Nt	fd := sys->create(name, Sys->ORDWR, 8r600);	return (name, fd);} fatal(s : string){	sys->fprint(sys->fildes(2), "%s\n", s);	raise "fail:error";}