Charles.Forsyth20060303a828770d19 years agoHistory
3842 lines · 76.2 KB · Brainfuck
RawDownload
implement Kfs; ## Copyright © 1991-2003 Lucent Technologies Inc.# Limbo version Copyright © 2004 Vita Nuova Holdings Limited# ## TO DO:#	- sync proc; Bmod; process structure#	- swiz? include "sys.m";	sys: Sys;	Qid, Dir: import Sys;	DMEXCL, DMAPPEND, DMDIR: import Sys;	QTEXCL, QTAPPEND, QTDIR: import Sys; include "draw.m"; include "styx.m";	styx: Styx;	Tmsg, Rmsg: import styx;	NOFID, OEXEC, ORCLOSE, OREAD, OWRITE, ORDWR, OTRUNC: import Styx;	IOHDRSZ: import Styx; include "daytime.m";	daytime: Daytime;	now: import daytime; include "arg.m"; Kfs: module{	init:	fn(nil: ref Draw->Context, nil: list of string);}; MAXBUFSIZE:	con 16*1024; ##  fundamental constants#NAMELEN: con 28;	# size of names, including null byteNDBLOCK:	con 6;	# number of direct blocks in DentryMAXFILESIZE:	con big 16r7FFFFFFF;	# Plan 9's limit (kfs's size is signed) SUPERADDR: con 1;ROOTADDR: con 2; QPDIR:	con int (1<<31);QPNONE: con 0;QPROOT: con 1;QPSUPER: con 2; ## don't change, these are the mode bits on disc#DALLOC: con 16r8000;DDIR:	con 16r4000;DAPND:	con 16r2000;DLOCK:	con 16r1000;DREAD:	con 4;DWRITE:	con 2;DEXEC:	con 1; ## other constants# MINUTE:	con 60;TLOCK:	con 5*MINUTE;NTLOCK:	con 200;	# number of active file locks Buffering: con 1; FID1, FID2, FID3: con 1+iota; None: con 0;	# user ID for "none"Noworld: con 9999;	# conventional id for "noworld" group Lock: adt{	c: chan of int;	new:	fn(): ref Lock;	lock:	fn(c: self ref Lock);	canlock:	fn(c: self ref Lock): int;	unlock:	fn(c: self ref Lock);}; Dentry: adt{	name:	string;	uid:	int;	gid:	int;	muid:	int;	# not set by plan 9's kfs	mode:	int;	# mode bits on disc: DALLOC etc	qid:	Qid;	# 9p1 format on disc	size:	big;	# only 32-bits on disc, and Plan 9 limits it to signed	atime:	int;	mtime:	int; 	iob:	ref Iobuf;	# locked block containing directory entry, when in memory	buf:	array of byte;	# pointer into block to packed directory entry, when in memory	mod:	int;	# bits of buf that need updating 	unpack:	fn(a: array of byte): ref Dentry;	get:	fn(p: ref Iobuf, slot: int): ref Dentry;	geta:	fn(d: ref Device, addr: int, slot: int, qpath: int, mode: int): (ref Dentry, string);	getd:	fn(f: ref File, mode: int): (ref Dentry, string);	put:	fn(d: self ref Dentry);	access:	fn(d: self ref Dentry, f: int, uid: int);	change:	fn(d: self ref Dentry, f: int);	release:	fn(d: self ref Dentry);	getblk:	fn(d: self ref Dentry, a: int, tag: int): ref Iobuf;	getblk1:	fn(d: self ref Dentry, a: int, tag: int): ref Iobuf;	rel2abs:	fn(d: self ref Dentry, a: int, tag: int, putb: int): int;	trunc:	fn(d: self ref Dentry, uid: int);	update:	fn(d: self ref Dentry);	print:	fn(d: self ref Dentry);}; Uname, Uids, Umode, Uqid, Usize, Utime: con 1<<iota;	# Dentry.mod ## disc structure:#	Tag:	pad[2] tag[2] path[4]Tagsize: con 2+2+4; Tag: adt{	tag:	int;	path:	int; 	unpack:	fn(a: array of byte): Tag;	pack:	fn(t: self Tag, a: array of byte);}; Superb: adt{	iob:	ref Iobuf; 	fstart:	int;	fsize:	int;	tfree:	int;	qidgen:	int;		# generator for unique ids 	fsok:	int; 	fbuf:	array of byte;	# nfree[4] free[FEPERBLK*4]; aliased into containing block 	get:	fn(dev: ref Device, flags: int): ref Superb;	touched:	fn(s: self ref Superb);	put:	fn(s: self ref Superb);	print:	fn(s: self ref Superb); 	pack:	fn(s: self ref Superb, a: array of byte);	unpack:	fn(a: array of byte): ref Superb;}; Device: adt{	fd:	ref Sys->FD;	ronly:	int;	# could put locks here if necessary	# partitioning by ds(3)}; ## one for each locked qid#Tlock: adt{	dev:	ref Device;	time:	int;	qpath:	int;	file:	cyclic ref File;	# TO DO: probably not needed}; File: adt{	qlock:	chan of int;	qid:	Qid;	wpath:	ref Wpath;	tlock:	cyclic ref Tlock;		# if file is locked	fs:	ref Device;	addr:	int;	slot:	int;	lastra:	int;		# read ahead address	fid:	int;	uid:	int;	open:	int;	cons:	int;	# if opened by console	doffset: big;	# directory reading	dvers:	int;	dslot:	int; 	new:	fn(fid: int): ref File;	access:	fn(f: self ref File, d: ref Dentry, mode: int): int;	lock:	fn(f: self ref File);	unlock:	fn(f: self ref File);}; FREAD, FWRITE, FREMOV, FWSTAT: con 1<<iota;	# File.open Chan: adt{	fd:	ref Sys->FD;			# fd request came in on#	rlock, wlock: QLock;		# lock for reading/writing messages on cp	flags:	int;	flist:	list of ref File;			# active files	fqlock:	chan of int;#	reflock:	RWLock;		# lock for Tflush	msize:	int;			# version 	new:	fn(fd: ref Sys->FD): ref Chan;	getfid:	fn(c: self ref Chan, fid: int, flag: int): ref File;	putfid:	fn(c: self ref Chan, f: ref File);	flock: fn(nil: self ref Chan);	funlock:	fn(nil: self ref Chan);}; Hiob: adt{	link:	ref Iobuf;	# TO DO: eliminate circular list	lk:	ref Lock;	niob: int; 	newbuf:	fn(h: self ref Hiob): ref Iobuf;}; Iobuf: adt{	qlock:	chan of int;	dev:	ref Device;	fore:	cyclic ref Iobuf;		# lru hash chain	back:	cyclic ref Iobuf;		# for lru	iobuf:	array of byte;		# only active while locked	xiobuf:	array of byte;	# "real" buffer pointer	addr:	int;	flags:	int; 	get:	fn(dev: ref Device, addr: int, flags: int):ref Iobuf;	put:	fn(iob: self ref Iobuf);	lock:	fn(iob: self ref Iobuf);	canlock:	fn(iob: self ref Iobuf): int;	unlock:	fn(iob: self ref Iobuf); 	checktag:	fn(iob: self ref Iobuf, tag: int, qpath: int): int;	settag:	fn(iob: self ref Iobuf, tag: int, qpath: int);}; Wpath: adt{	up: cyclic ref Wpath;		# pointer upwards in path	addr: int;		# directory entry addr	slot: int;		# directory entry slot}; ##  error codes generated from the file server#Eaccess: con "access permission denied";Ealloc: con "phase error -- directory entry not allocated";Eauth: con "authentication failed";Eauthmsg: con "kfs: authentication not required";Ebadspc: con "attach -- bad specifier";Ebadu: con "attach -- privileged user";Ebroken: con "close/read/write -- lock is broken";Echar: con "bad character in directory name";Econvert: con "protocol botch";Ecount: con "read/write -- count too big";Edir1: con "walk -- in a non-directory";Edir2: con "create -- in a non-directory";Edot: con "create -- . and .. illegal names";Eempty: con "remove -- directory not empty";Eentry: con "directory entry not found";Eexist: con "create -- file exists";Efid: con "unknown fid";Efidinuse: con "fid already in use";Efull: con "file system full";Elocked: con "open/create -- file is locked";Emode: con "open/create -- unknown mode";Ename: con "create/wstat -- bad character in file name";Enotd: con "wstat -- attempt to change directory";Enotg: con "wstat -- not in group";Enotl: con "wstat -- attempt to change length";Enotm: con "wstat -- unknown type/mode";Enotu: con "wstat -- not owner";Eoffset: con "read/write -- offset negative";Eopen: con "read/write -- on non open fid";Ephase: con "phase error -- cannot happen";Eqid: con "phase error -- qid does not match";Eqidmode: con "wstat -- qid.qtype/dir.mode mismatch";Eronly: con "file system read only";Ersc: con "it's russ's fault.  bug him.";Esystem: con "kfs system error";Etoolong: con "name too long";Etoobig: con "write -- file size limit";Ewalk: con "walk -- too many (system wide)"; ##  tags on block#Tnone,Tsuper,			# the super blockTdir,			# directory contentsTind1,			# points to blocksTind2,			# points to Tind1Tfile,			# file contentsTfree,			# in free listTbuck,			# cache fs bucketTvirgo,			# fake worm virgin bitsTcache,			# cw cache thingsMAXTAG: con iota; ##  flags to Iobuf.get#	Bread,	# read the block if miss	Bprobe,	# return null if miss	Bmod,	# set modified bit in buffer	Bimm,	# set immediate bit in buffer	Bres:		# never renamed	con 1<<iota; ##  check flags#	Crdall,	# read all files	Ctag,	# rebuild tags	Cpfile,	# print files	Cpdir,	# print directories	Cfree,	# rebuild free list	Cream,	# clear all bad tags	Cbad,	# clear all bad blocks	Ctouch,	# touch old dir and indir	Cquiet:	# report just nasty things	con 1<<iota; ##  buffer size variables, determined by RBUFSIZE#RBUFSIZE: int;BUFSIZE: int;DIRPERBUF: int;INDPERBUF: int;INDPERBUF2: int;FEPERBUF: int; emptyblock: array of byte; wrenfd: ref Sys->FD;thedevice: ref Device;devnone: ref Device;wstatallow := 0;writeallow := 0;writegroup := 0; ream := 0;readonly := 0;noatime := 0;localfs: con 1;conschan: ref Chan;consuid := -1;consgid := -1;debug := 0;kfsname: string;consoleout: chan of string;mainlock: ref Lock;pids: list of int; noqid: Qid; init(nil: ref Draw->Context, args: list of string){	sys = load Sys Sys->PATH;	styx = load Styx Styx->PATH;	daytime = load Daytime Daytime->PATH; 	styx->init();  	arg := load Arg Arg->PATH;	if(arg == nil)		error(sys->sprint("can't load %s: %r", Arg->PATH));	arg->init(args);	arg->setusage("disk/kfs [-r [-b bufsize]] [-cADPRW] [-n name] kfsfile");	bufsize := 1024;	nocheck := 0;	while((o := arg->opt()) != 0)		case o {		'c' => nocheck = 1;		'r' =>	ream = 1;		'b' => bufsize = int arg->earg();		'D' => debug = !debug;		'P' => writeallow = 1;		'W' => wstatallow = 1;		'R' => readonly = 1;		'A' => noatime = 1;	# mainly useful for flash		'n' => kfsname = arg->earg();		* =>	arg->usage();		}	args = arg->argv();	if(args == nil)		arg->usage();	arg = nil; 	devnone = ref Device(nil, 1);	mainlock = Lock.new(); 	conschan = Chan.new(nil);	conschan.msize = Styx->MAXRPC; 	mode := Sys->ORDWR;	if(readonly)		mode = Sys->OREAD;	wrenfd = sys->open(hd args, mode);	if(wrenfd == nil)		error(sys->sprint("can't open %s: %r", hd args));	thedevice = ref Device(wrenfd, readonly);	if(ream){		if(bufsize <= 0 || bufsize % 512 || bufsize > MAXBUFSIZE)			error(sys->sprint("invalid block size %d", bufsize));		RBUFSIZE = bufsize;		wrenream(thedevice);	}else{		if(!wreninit(thedevice))			error("kfs magic in trouble");	}	BUFSIZE = RBUFSIZE - Tagsize;	DIRPERBUF = BUFSIZE / Dentrysize;	INDPERBUF = BUFSIZE / 4;	INDPERBUF2 = INDPERBUF * INDPERBUF;	FEPERBUF = (BUFSIZE - Super1size - 4) / 4;	emptyblock = array[RBUFSIZE] of {* => byte 0}; 	iobufinit(30); 	if(ream){		superream(thedevice, SUPERADDR);		rootream(thedevice, ROOTADDR);		wstatallow = writeallow = 1;	}	if(wrencheck(wrenfd))		error("kfs super/root in trouble"); 	if(!ream && !superok(0)){		sys->print("kfs needs check\n");		if(!nocheck)			check(thedevice, Cquiet|Cfree);	} 	(d, e) := Dentry.geta(thedevice, ROOTADDR, 0, QPROOT, Bread);	if(d != nil && !(d.mode & DDIR))		e = "not a directory";	if(e != nil)		error("bad root: "+e);	if(debug)		d.print();	d.put(); 	sys->pctl(Sys->FORKFD|Sys->NEWPGRP, nil); 	sys->pctl(Sys->NEWFD, wrenfd.fd :: 0 :: 1 :: 2 :: nil);	wrenfd = sys->fildes(wrenfd.fd);	thedevice.fd = wrenfd; 	c := chan of int; 	if(Buffering){		spawn syncproc(c);		pid := <-c;		if(pid)			pids = pid :: pids;	}	spawn consinit(c);	pid := <- c;	if(pid)		pids = pid :: pids; 	spawn kfs(sys->fildes(0));} error(s: string){	sys->fprint(sys->fildes(2), "kfs: %s\n", s);	for(; pids != nil; pids = tl pids)		kill(hd pids);	raise "fail:error";} panic(s: string){	sys->fprint(sys->fildes(2), "kfs: panic: %s\n", s);	for(; pids != nil; pids = tl pids)		kill(hd pids);	raise "panic";} syncproc(c: chan of int)

Lines 1–500 of 3842.