Charles.Forsyth20080116-1354ff72aa718 years agoHistory
1963 lines · 35.3 KB · Brainfuck
RawDownload
implement Ftpfs; include "sys.m";	sys: Sys;	FD, Dir: import Sys; include "draw.m"; include "arg.m"; include "bufio.m";	bufio: Bufio;	Iobuf: import bufio; include "daytime.m";	time: Daytime;	Tm: import time; include "string.m";	str: String; include "styx.m";	styx: Styx;	Tmsg, Rmsg: import styx; include "dial.m";	dial: Dial;	Connection: import dial; include "factotum.m"; Ftpfs: module{	init: fn(nil: ref Draw->Context, argv: list of string);}; ##	File system node.  Refers to parent and file structure.#	Siblings are linked.  The head is parent.children.# Node: adt{	dir:		Dir;	uniq:		int;	parent:		cyclic ref Node;	sibs:		cyclic ref Node;	children:	cyclic ref Node;	file:		cyclic ref File;	depth:		int;	remname:	string;	cached:		int;	valid:		int; 	extendpath:	fn(parent: self ref Node, elem: string): ref Node;	fixsymbolic:	fn(n: self ref Node);	invalidate:	fn(n: self ref Node);	markcached:	fn(n: self ref Node);	uncache:	fn(n: self ref Node);	uncachedir:	fn(parent: self ref Node, child: ref Node); 	stat:		fn(n: self ref Node): array of byte;	qid:		fn(n: self ref Node): Sys->Qid; 	fileget:	fn(n: self ref Node): ref File;	filefree:	fn(n: self ref Node);	fileclean:	fn(n: self ref Node);	fileisdirty:	fn(n: self ref Node): int;	filedirty:	fn(n: self ref Node);	fileread:	fn(n: self ref Node, b: array of byte, off, c: int): int;	filewrite:	fn(n: self ref Node, b: array of byte, off, c: int): int; 	action:		fn(n: self ref Node, cmd: string): int;	createdir:	fn(n: self ref Node): int;	createfile:	fn(n: self ref Node): int;	changedir:	fn(n: self ref Node): int;	docreate:	fn(n: self ref Node): int;	pathname:	fn(n: self ref Node): string;	readdir:	fn(n: self ref Node): int;	readfile:	fn(n: self ref Node): int;	removedir:	fn(n: self ref Node): int;	removefile:	fn(n: self ref Node): int;}; ##	Styx protocol file identifier.# Fid: adt{	fid:	int;	node:	ref Node;	busy:	int;}; ##	Foreign file with cache.# File: adt{	cache:		array of byte;	length:		int;	offset:		int;	fd:		ref FD;	inuse, dirty:	int;	atime:		int;	node:		cyclic ref Node;	tempname:	string; 	createtmp:	fn(f: self ref File): ref FD;}; ftp:		ref Connection;dfid:			ref FD;dfidiob:		ref Iobuf;buffresidue:	int = 0;tbuff:		array of byte;rbuff:		array of byte;ccfd:			ref FD;stdin, stderr:	ref FD; fids:		list of ref Fid; BSZ:		con 8192;Chunk:		con 1024;Nfiles:		con 128; CHSYML:		con 16r40000000; mountpoint:	string = "/n/ftp";user:			string = nil;password:		string;hostname:	string = "kremvax";anon:		string = "anon"; firewall:		string = "tcp!$proxy!402";myname:		string = "anon";myhost:		string = "lucent.com";proxyid:		string;proxyhost:	string; errstr:		string;net:			string;port:			int; Enosuchfile:	con "file does not exist";Eftpproto:	con "ftp protocol error";Eshutdown:	con "remote shutdown";Eioerror:	con "io error";Enotadirectory:	con "not a directory";Eisadirectory:	con "is a directory";Epermission:	con "permission denied";Ebadoffset:	con "bad offset";Ebadlength:	con "bad length";Enowstat:	con "wstat not implemented";Emesgmismatch:	con "message size mismatch"; remdir:		ref Node;remroot:	ref Node;remrootpath:	string; heartbeatpid: int; ##	FTP protocol codes are 3 digits >= 100.#	The code type is obtained by dividing by 100.# Syserr:		con -2;Syntax:		con -1;Shutdown:	con 0;Extra:		con 1;Success:	con 2;Incomplete:	con 3;TempFail:	con 4;PermFail:	con 5;Impossible:	con 6;Err:		con 7; debug:		int = 0;quiet:		int = 0;active:		int = 0;cdtoroot:		int = 0; proxy:		int = 0; mountfd:	ref FD;styxfd: ref FD; ##	Set up FDs for service.# connect(): string{	pip := array[2] of ref Sys->FD;	if(sys->pipe(pip) < 0)		return sys->sprint("can't create pipe: %r");	mountfd = pip[0];	styxfd = pip[1];	return nil;} #shut(s: string)#{#	sys->print("ftpfs: %s shutdown\n", s);#} ##	Mount server.  Must be spawned because it does#	an attach transaction.# mount(mountpoint: string){	if (sys->mount(mountfd, nil, mountpoint, sys->MREPL | sys->MCREATE, nil) < 0) {		sys->print("mount %s failed: %r\n", mountpoint);		shutdown();	}	mountfd = nil;} ##	Keep the link alive.# beatquanta:	con 10;beatlimit:	con 10;beatcount:	int;activity:	int;transfer:	int; heartbeat(pidc: chan of int){	pid := sys->pctl(0, nil);	pidc <-= pid;	for (;;) {		sys->sleep(beatquanta * 1000);		if (activity || transfer) {			beatcount = 0;			activity = 0;			continue;		}		beatcount++;		if (beatcount == beatlimit) {			acquire();			if (sendrequest("NOOP", 0) == Success)				getreply(0);			release();			beatcount = 0;			activity = 0;		}	}} ##	Control lock.# ctllock: chan of int; acquire(){	ctllock <-= 1;} release(){	<-ctllock;} ##	Data formatting routines.# sendreply(r: ref Rmsg){	if (debug)		sys->print("> %s\n", r.text());	a := r.pack();	if(styx->write(styxfd, a, len a) != len a)		sys->print("ftpfs: error replying: %r\n");} rerror(tag: int, s: string){	if (debug)		sys->print("error: %s\n", s);	sendreply(ref Rmsg.Error(tag, s));} seterr(e: int, s: string): int{	case e {	Syserr =>		errstr = Eioerror;	Syntax =>		errstr = Eftpproto;	Shutdown =>		errstr = Eshutdown;	* =>		errstr = s;	}	return -1;} ##	Node routines.# anode:	Node;npath:	int	= 1; newnode(parent: ref Node, name: string): ref Node{	n := ref anode;	n.dir.name = name;	n.dir.atime = time->now();	n.children = nil;	n.remname = name;	if (parent != nil) {		n.parent = parent;		n.sibs = parent.children;		parent.children = n;		n.depth = parent.depth + 1;		n.valid = 0;	} else {		n.parent = n;		n.sibs = nil;		n.depth = 0;		n.valid = 1;		n.dir.uid = anon;		n.dir.gid = anon;		n.dir.mtime = n.dir.atime;	}	n.file = nil;	n.uniq = npath++;	n.cached = 0;	return n;} Node.extendpath(parent: self ref Node, elem: string): ref Node{	n: ref Node; 	for (n = parent.children; n != nil; n = n.sibs)		if (n.dir.name == elem)			return n;	return newnode(parent, elem);} Node.markcached(n: self ref Node){	n.cached = 1;	n.dir.atime = time->now();} Node.uncache(n: self ref Node){	if (n.fileisdirty())		n.createfile();	n.filefree();	n.cached = 0;} Node.uncachedir(parent: self ref Node, child: ref Node){	sp: ref Node; 	if (parent == nil || parent == child)		return;	for (sp = parent.children; sp != nil; sp = sp.sibs)		if (sp != child && sp.file != nil && !sp.file.dirty && sp.file.fd != nil) {			sp.filefree();			sp.cached = 0;		}} Node.invalidate(node: self ref Node){	n: ref Node; 	node.uncachedir(nil);	for (n = node.children; n != nil; n = n.sibs) {		n.cached = 0;		n.invalidate();		n.valid = 0;	}} Node.fixsymbolic(n: self ref Node){	if (n.changedir() == 0) {		n.dir.mode |= Sys->DMDIR; 		n.dir.qid.qtype = Sys->QTDIR;	} else		n.dir.qid.qtype = Sys->QTFILE;	n.dir.mode &= ~CHSYML; } Node.stat(n: self ref Node): array of byte{	return styx->packdir(n.dir);} Node.qid(n: self ref Node): Sys->Qid{	if(n.dir.mode & Sys->DMDIR)		return Sys->Qid(big n.uniq, 0, Sys->QTDIR);	return Sys->Qid(big n.uniq, 0, Sys->QTFILE);} ##	File routines.# ntmp:	int;files:	list of ref File;nfiles:	int;afile:	File;atime:	int; ##	Allocate a file structure for a node.  If too many#	are already allocated discard the oldest.# Node.fileget(n: self ref Node): ref File{	f, o: ref File;	l: list of ref File; 	if (n.file != nil)		return n.file;	o = nil;	for (l = files; l != nil; l = tl l) {		f = hd l;		if (f.inuse == 0)			break;		if (!f.dirty && (o == nil || o.atime > f.atime))			o = f;	}	if (l == nil) {		if (nfiles == Nfiles && o != nil) {			o.node.uncache();			f = o;		}		else {			f = ref afile;			files = f :: files;			nfiles++;		}	}	n.file = f;	f.node = n;	f.atime = atime++;	f.inuse = 1;	f.dirty = 0;	f.length = 0;	f.fd = nil;	return f;} ##	Create a temporary file for a local copy of a file.#	If too many are open uncache parent.# File.createtmp(f: self ref File): ref FD{	t := "/tmp/ftp." + string time->now() + "." + string ntmp;	if (ntmp >= 16)		f.node.parent.uncachedir(f.node);	f.fd = sys->create(t, Sys->ORDWR | Sys->ORCLOSE, 8r600);	f.tempname = t;	f.offset = 0;	ntmp++;	return f.fd;} ##	Read 'c' bytes at offset 'off' from a file into buffer 'b'.# Node.fileread(n: self ref Node, b: array of byte, off, c: int): int{	f: ref File;	t, i: int; 	f = n.file;	if (off + c > f.length)		c = f.length - off;	for (t = 0; t < c; t += i) {		if (off >= f.length)			return t;		if (off < Chunk) {			i = c;			if (off + i > Chunk)				i = Chunk - off;

Lines 1–500 of 1963.