Charles.Forsyth20060303a828770d19 years agoHistory
778 lines · 14.7 KB · Brainfuck
RawDownload
implement Mkfs; include "sys.m";	sys: Sys;	Dir, sprint, fprint: import sys; include "draw.m"; include "bufio.m";	bufio: Bufio;	Iobuf: import bufio; include "string.m";	str: String; include "arg.m";	arg: Arg; Mkfs: module{	init:	fn(nil: ref Draw->Context, nil: list of string);}; LEN: con Sys->ATOMICIO;HUNKS: con 128; Kfs, Fs, Archive: con iota;	# types of destination file sytems File: adt {	new:	string;	elem:	string;	old:	string;	uid:	string;	gid:	string;	mode:	int;}; b: ref Iobuf;bout: ref Iobuf;			# stdout when writing archivenewfile: string;oldfile: string;proto: string;cputype: string;users: string;oldroot: string;newroot: string;prog := "mkfs";lineno := 0;buf: array of byte;zbuf: array of byte;buflen := 1024-8;indent: int;verb: int;modes: int;ream: int;debug: int;xflag: int;qflag := 1;sfd: ref Sys->FD;fskind: int;	# Kfs, Fs, Archiveuser: string;stderr: ref Sys->FD;usrid, grpid : string;setuid: int;	usage(){	fprint(stderr, "usage: %s [-apqrvx] [-d root] [-n kfsname] [-s src-fs] [-u userfile] [-z n] proto ...\n", prog);	quit("usage");} init(nil: ref Draw->Context, args: list of string){	sys = load Sys Sys->PATH;	bufio = load Bufio Bufio->PATH;	str = load String String->PATH;	arg = load Arg Arg->PATH; 	sys->pctl(Sys->NEWPGRP|Sys->FORKNS|Sys->FORKFD, nil); 	stderr = sys->fildes(2);	if(arg == nil)		error(sys->sprint("can't load %s: %r", Arg->PATH)); 	user = getuser();	if(user == nil)		user = "none";	name := "";	file := ref File;	file.new = "";	file.old = nil;	file.mode = 0;	oldroot = "";	newroot = "/n/kfs";	users = nil;	fskind = Kfs;	# i suspect Inferno default should be different	arg->init(args);	while((c := arg->opt()) != 0)		case c {		'a' =>			fskind = Archive;			newroot = "";			bout = bufio->fopen(sys->fildes(1), Sys->OWRITE);			if(bout == nil)				error(sys->sprint("can't open standard output for archive: %r"));		'd' =>			fskind = Fs;			newroot = reqarg("destination directory (-d)");		'D' =>			debug = 1;		'n' =>			name = reqarg("kfs instance name (-n)");		'p' =>			modes = 1;		'q' =>			qflag = 0;		'r' =>			ream = 1;		's' =>			oldroot = reqarg("source directory (-d)");		'u' =>			users = reqarg("/adm/users file (-u)");		'v' =>			verb = 1;		'x' =>			xflag = 1;		'z' =>			(buflen, nil) = str->toint(reqarg("buffer length (-z)"), 10);			buflen -= 8;	# qid.path and tag at end of each kfs block		'U' => 			usrid = reqarg("user name (-U)");		'G' =>			grpid = reqarg("group name (-G)");		'S' =>			setuid = 1;		* =>			usage();		} 	args = arg->argv();	if(args == nil)		usage(); 	buf = array [buflen] of byte;	zbuf = array [buflen] of { * => byte 0 }; 	mountkfs(name);	kfscmd("allow");	proto = "users";	setusers();	cputype = getenv("cputype");	if(cputype == nil)		cputype = "dis"; 	errs := 0;	for(; args != nil; args = tl args){		proto = hd args;		fprint(stderr, "processing %s\n", proto); 		b = bufio->open(proto, Sys->OREAD);		if(b == nil){			fprint(stderr, "%s: can't open %s: %r: skipping\n", prog, proto);			errs++;			continue;		} 		lineno = 0;		indent = 0;		mkfs(file, -1);		b.close();	}	fprint(stderr, "file system made\n");	kfscmd("disallow");	kfscmd("sync");	if(errs)		quit("skipped protos");	if(fskind == Archive){		bout.puts("end of archive\n");		if(bout.flush() == Bufio->ERROR)			error(sys->sprint("write error: %r"));	}} quit(why: string){	if(bout != nil)		bout.flush();	if(why != nil)		raise "fail:"+why;	exit;} reqarg(what: string): string{	if((o := arg->arg()) == nil){		sys->fprint(stderr, "%s: missing %s\n", prog, what);		quit("usage");	}	return o;} mkfs(me: ref File, level: int){	(child, fp) := getfile(me);	if(child == nil)		return;	if(child.elem == "+" || child.elem == "*" || child.elem == "%"){		rec := child.elem[0] == '+';		filesonly := child.elem[0] == '%';		child.new = me.new;		setnames(child);		mktree(child, rec, filesonly);		(child, fp) = getfile(me);	}	while(child != nil && indent > level){		if(mkfile(child))			mkfs(child, indent);		(child, fp) = getfile(me);	}	if(child != nil){		b.seek(fp, 0);		lineno--;	}} mktree(me: ref File, rec: int, filesonly: int){	fd := sys->open(oldfile, Sys->OREAD);	if(fd == nil){		warn(sys->sprint("can't open %s: %r", oldfile));		return;	} 	child := ref *me;	r := ref Rec(nil, 0);	for(;;){		(n, d) := sys->dirread(fd);		if(n <= 0)			break;		for(i := 0; i < n; i++)		  	if (!recall(d[i].name, r)) {				if(filesonly && d[i].mode & Sys->DMDIR)					continue;				child.new = mkpath(me.new, d[i].name);				if(me.old != nil)					child.old = mkpath(me.old, d[i].name);				child.elem = d[i].name;				setnames(child);				if(copyfile(child, ref d[i], 1) && rec)					mktree(child, rec, filesonly);		  	}	}} # Recall namespace fix# -- remove duplicates (could use Readdir->init(,Readdir->COMPACT))# obc Rec: adt{	ad: array of string;	l: int;}; AL : con HUNKS;recall(e : string, r : ref Rec) : int{	if (r.ad == nil) r.ad = array[AL] of string;	# double array	if (r.l >= len r.ad) {		nar := array[2*(len r.ad)] of string;		nar[0:] = r.ad;		r.ad = nar;	}	for(i := 0; i < r.l; i++)		if (r.ad[i] == e) return 1;	r.ad[r.l++] = e;	return 0;} mkfile(f: ref File): int{	(i, dir) := sys->stat(oldfile);	if(i < 0){		warn(sys->sprint("can't stat file %s: %r", oldfile));		skipdir();		return 0;	}	return copyfile(f, ref dir, 0);} copyfile(f: ref File, d: ref Dir, permonly: int): int{	mode: int; 	if(xflag && bout != nil){		bout.puts(sys->sprint("%s\t%d\t%bd\n", quoted(f.new), d.mtime, d.length));		return (d.mode & Sys->DMDIR) != 0;	}	d.name = f.elem;	if(d.dtype != 'M' && d.dtype != 'U'){		# hmm... Indeed!		d.uid = "inferno";		d.gid = "inferno";		mode = (d.mode >> 6) & 7;		d.mode |= mode | (mode << 3);	}	if(f.uid != "-")		d.uid = f.uid;	if(f.gid != "-")		d.gid = f.gid;	if(fskind == Fs && !setuid){	# new system: set to nil		d.uid = user;		d.gid = user;	}	if (usrid != nil)		d.uid = usrid;	if (grpid != nil)		d.gid = grpid;	if(f.mode != ~0){		if(permonly)			d.mode = (d.mode & ~8r666) | (f.mode & 8r666);		else if((d.mode&Sys->DMDIR) != (f.mode&Sys->DMDIR))			warn(sys->sprint("inconsistent mode for %s", f.new));		else			d.mode = f.mode;	}	if(!uptodate(d, newfile)){		if(d.mode & Sys->DMDIR)			mkdir(d);		else {			if(verb)				fprint(stderr, "%s\n", f.new);			copy(d);		}	}else if(modes){		nd := sys->nulldir;		nd.mode = d.mode;		nd.mtime = d.mtime;		nd.gid = d.gid;		if(sys->wstat(newfile, nd) < 0)			warn(sys->sprint("can't set modes for %s: %r", f.new));		# do the uid separately since different file systems object		nd = sys->nulldir;		nd.uid = d.uid;		sys->wstat(newfile, nd);	}	return (d.mode & Sys->DMDIR) != 0;}  # check if file to is up to date with# respect to the file represented by df uptodate(df: ref Dir, newf: string): int{	if(fskind == Archive || ream)		return 0;	(i, dt) := sys->stat(newf);	if(i < 0)		return 0;	return dt.mtime >= df.mtime;} copy(d: ref Dir){	t: ref Sys->FD;	n: int; 	f := sys->open(oldfile, Sys->OREAD);	if(f == nil){		warn(sys->sprint("can't open %s: %r", oldfile));		return;	}	t = nil;	if(fskind == Archive)		arch(d);	else{		(dname, fname) := str->splitr(newfile, "/");		if(fname == nil)			error(sys->sprint("internal temporary file error (%s)", dname));		cptmp := dname+"__mkfstmp";		t = sys->create(cptmp, Sys->OWRITE, 8r666);		if(t == nil){			warn(sys->sprint("can't create %s: %r", newfile));			return;		}	} 	for(tot := big 0;; tot += big n){		n = sys->read(f, buf, buflen);		if(n < 0){			warn(sys->sprint("can't read %s: %r", oldfile));			break;		}		if(n == 0)			break;		if(fskind == Archive){			if(bout.write(buf, n) != n)				error(sys->sprint("write error: %r"));		}else if(buf[0:buflen] == zbuf[0:buflen]){			if(sys->seek(t, big buflen, 1) < big 0)				error(sys->sprint("can't write zeros to %s: %r", newfile));		}else if(sys->write(t, buf, n) < n)			error(sys->sprint("can't write %s: %r", newfile));	}	f = nil;	if(tot != d.length){		warn(sys->sprint("wrong number bytes written to %s (was %bd should be %bd)",			newfile, tot, d.length));		if(fskind == Archive){			warn("seeking to proper position");			bout.seek(d.length - tot, 1);		}	}	if(fskind == Archive)		return;	sys->remove(newfile);	nd := sys->nulldir;	nd.name = d.name;	nd.mode = d.mode;	nd.mtime = d.mtime;	if(sys->fwstat(t, nd) < 0)		error(sys->sprint("can't move tmp file to %s: %r", newfile));	nd = sys->nulldir;	nd.gid = d.gid;	if(sys->fwstat(t, nd) < 0)		warn(sys->sprint("can't set group id of %s to %s: %r", newfile, d.gid));	nd.gid = nil;	nd.uid = d.uid;	sys->fwstat(t, nd);} mkdir(d: ref Dir){	if(fskind == Archive){		arch(d);		return;	}	fd := sys->create(newfile, Sys->OREAD, d.mode);	nd := sys->nulldir;	nd.mode = d.mode;	nd.gid = d.gid;	nd.mtime = d.mtime;	if(fd == nil){		(i, d1) := sys->stat(newfile);		if(i < 0 || !(d1.mode & Sys->DMDIR))			error(sys->sprint("can't create %s", newfile));		if(sys->wstat(newfile, nd) < 0)			warn(sys->sprint("can't set modes for %s: %r", newfile));		nd = sys->nulldir;		nd.uid = d.uid;		sys->wstat(newfile, nd);		return;	}	if(sys->fwstat(fd, nd) < 0)		warn(sys->sprint("can't set modes for %s: %r", newfile));	nd = sys->nulldir;	nd.uid = d.uid;	sys->fwstat(fd, nd);} arch(d: ref Dir){	bout.puts(sys->sprint("%s %s %s %s %ud %bd\n",		quoted(newfile), octal(d.mode), d.uid, d.gid, d.mtime, d.length));} mkpath(prefix, elem: string): string{	return sys->sprint("%s/%s", prefix, elem);} setnames(f: ref File){	newfile = newroot+f.new;	if(f.old != nil){		if(f.old[0] == '/')			oldfile = oldroot+f.old;		else			oldfile = f.old;	}else		oldfile = oldroot+f.new;} ## skip all files in the proto that# could be in the current dir#skipdir(){	if(indent < 0)		return;	level := indent;	for(;;){		indent = 0;		fp := b.offset();		p := b.gets('\n');		lineno++;		if(p == nil){			indent = -1;

Lines 1–500 of 778.