830 lines · 14.0 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h>#include <String.h>#include "ftpfs.h" /* an active fid */typedef struct Fid	Fid;struct Fid{	int	fid;	Node	*node;		/* path to remote file */	int	busy;	Fid	*next;	int	open;}; Fid	*fids;			/* linked list of fids */char	errstring[128];		/* error to return */int	mfd;			/* fd for 9fs */int	messagesize = 4*1024*IOHDRSZ;uchar	mdata[8*1024*IOHDRSZ];uchar	mbuf[8*1024*IOHDRSZ];Fcall	rhdr;Fcall	thdr;int	debug;int	usenlst;int	usetls;char	*ext;int	quiet;int	kapid = -1;int	dying;		/* set when any process decides to die */int	dokeepalive; char	*rflush(Fid*), *rnop(Fid*), *rversion(Fid*),	*rattach(Fid*), *rclone(Fid*), *rwalk(Fid*),	*rclwalk(Fid*), *ropen(Fid*), *rcreate(Fid*),	*rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),	*rremove(Fid*), *rstat(Fid*), *rwstat(Fid*),	*rauth(Fid*);;void	mountinit(char*);void	io(void);int	readpdir(Node*); char 	*(*fcalls[])(Fid*) = {	[Tflush]	rflush,	[Tversion]	rversion,	[Tattach]	rattach,	[Tauth]		rauth,	[Twalk]		rwalk,	[Topen]		ropen,	[Tcreate]	rcreate,	[Tread]		rread,	[Twrite]	rwrite,	[Tclunk]	rclunk,	[Tremove]	rremove,	[Tstat]		rstat,	[Twstat]	rwstat,}; /* these names are matched as prefixes, so VMS must precede VM */OS oslist[] = {	{ Plan9,	"Plan 9", },	{ Plan9,	"Plan9", },	{ Plan9,	"UNIX Type: L8 Version: Plan 9", },	{ Unix,		"SUN", },	{ Unix,		"UNIX", },	{ VMS,		"VMS", },	{ VM,		"VM", },	{ Tops,		"TOPS", },	{ MVS,		"MVS", },	{ NetWare,	"NetWare", },	{ NetWare,	"NETWARE", },	{ OS½,		"OS/2", },	{ TSO,		"TSO", },	{ NT,		"Windows_NT", },	/* DOS like interface */	{ NT,		"WINDOWS_NT", },	/* Unix like interface */	{ Unknown,	0 },}; char *nouid = "?uid?"; #define S2P(x) (((ulong)(x)) & 0xffffff) char *nosuchfile = "file does not exist";char *keyspec = ""; voidusage(void){	fprint(2, "ftpfs [-/dqnt] [-a passwd] [-m mountpoint] [-e ext] [-k keyspec] [-o os] [-r root] [net!]address\n");	exits("usage");} voidmain(int argc, char *argv[]){	char *mountroot = 0;	char *mountpoint = "/n/ftp";	char *cpassword = 0;	char *cp;	int p[2];	OS *o; 	defos = Unix;	user = strdup(getuser());	usetls = 0; 	ARGBEGIN {	case '/':		mountroot = "/";		break;	case 'a':		cpassword = ARGF();		break;	case 'd':		debug = 1;		break;	case 'k':		keyspec = EARGF(usage());		break;	case 'K':		dokeepalive = 1;		break;	case 'm':		mountpoint = ARGF();		break;	case 'n':		usenlst = 1;		break;	case 'e':		ext = ARGF();		break;	case 't':		usetls = 1;		break;	case 'o':		cp = ARGF();		for(o = oslist; o->os != Unknown; o++)			if(strncmp(cp, o->name, strlen(o->name)) == 0){				defos = o->os;				break;			}		break;	case 'r':		mountroot = ARGF();		break;	case 'q':		quiet = 1;		break;	} ARGEND	if(argc != 1)		usage(); 	/* get a pipe to mount and run 9fs on */	if(pipe(p) < 0)		fatal("pipe failed: %r");	mfd = p[0]; 	/* initial handshakes with remote side */	hello(*argv);	if(cpassword == 0)		rlogin(*argv, keyspec);	else		clogin("anonymous", cpassword);	preamble(mountroot); 	/* start the 9fs protocol */	switch(rfork(RFPROC|RFNAMEG|RFENVG|RFFDG|RFNOTEG|RFREND)){	case -1:		fatal("fork: %r");	case 0:		/* seal off standard input/output */		close(0);		open("/dev/null", OREAD);		close(1);		open("/dev/null", OWRITE); 		close(p[1]);		fmtinstall('F', fcallfmt); /* debugging */		fmtinstall('D', dirfmt); /* expected by %F */		fmtinstall('M', dirmodefmt); /* expected by %F */		io();		quit();		break;	default:		close(p[0]);		if(mount(p[1], -1, mountpoint, MREPL|MCREATE, "") < 0)			fatal("mount failed: %r");	}	exits(0);} /* *  lookup an fid. if not found, create a new one. */Fid *newfid(int fid){	Fid *f, *ff; 	ff = 0;	for(f = fids; f; f = f->next){		if(f->fid == fid){			if(f->busy)				return f;			else{				ff = f;				break;			}		} else if(!ff && !f->busy)			ff = f;	}	if(ff == 0){		ff = mallocz(sizeof(*f), 1);		ff->next = fids;		fids = ff;	}	ff->node = nil;	ff->fid = fid;	return ff;} /* *  a process that sends keep alive messages to *  keep the server from shutting down the connection */intkaproc(void){	int pid; 	if(!dokeepalive)		return -1; 	switch(pid = rfork(RFPROC|RFMEM)){	case -1:		return -1;	case 0:		break;	default:		return pid;	} 	while(!dying){		sleep(5000);		nop();	} 	_exits(0);	return -1;} voidio(void){	char *err, buf[ERRMAX];	int n; 	kapid = kaproc(); 	while(!dying){		n = read9pmsg(mfd, mdata, messagesize);		if(n <= 0){			errstr(buf, sizeof buf);			if(buf[0]=='\0' || strstr(buf, "hungup"))				exits("");			fatal("mount read: %s\n", buf);		}		if(convM2S(mdata, n, &thdr) == 0)			continue; 		if(debug)			fprint(2, "<-%F\n", &thdr);/**/ 		if(!fcalls[thdr.type])			err = "bad fcall type";		else			err = (*fcalls[thdr.type])(newfid(thdr.fid));		if(err){			rhdr.type = Rerror;			rhdr.ename = err;		}else{			rhdr.type = thdr.type + 1;			rhdr.fid = thdr.fid;		}		rhdr.tag = thdr.tag;		if(debug)			fprint(2, "->%F\n", &rhdr);/**/		n = convS2M(&rhdr, mdata, messagesize);		if(write(mfd, mdata, n) != n)			fatal("mount write");	}} char*rnop(Fid *f){	USED(f);	return 0;} char*rversion(Fid*){	if(thdr.msize > sizeof(mdata))		rhdr.msize = messagesize;	else		rhdr.msize = thdr.msize;	messagesize = thdr.msize; 	if(strncmp(thdr.version, "9P2000", 6) != 0)		return "unknown 9P version";	rhdr.version = "9P2000";	return nil;} char*rflush(Fid*){	return 0;} char*rauth(Fid*){	return "auth unimplemented";} char*rattach(Fid *f){	f->busy = 1;	f->node = remroot;	rhdr.qid = f->node->d->qid;	return 0;} char*rwalk(Fid *f){	Node *np;	Fid *nf;	char **elems;	int i, nelems;	char *err;	Node *node; 	/* clone fid */	nf = nil;	if(thdr.newfid != thdr.fid){		nf = newfid(thdr.newfid);		if(nf->busy)			return "newfid in use";		nf->busy = 1;		nf->node = f->node;		f = nf;	} 	err = nil;	elems = thdr.wname;	nelems = thdr.nwname;	node = f->node;	rhdr.nwqid = 0;	if(nelems > 0){		/* walk fid */		for(i=0; i<nelems && i<MAXWELEM; i++){			if((node->d->qid.type & QTDIR) == 0){				err = "not a directory";				break;			}			if(strcmp(elems[i], ".") == 0){   Found:				rhdr.wqid[i] = node->d->qid;				rhdr.nwqid++;				continue;			}			if(strcmp(elems[i], "..") == 0){				node = node->parent;				goto Found;			}			if(strcmp(elems[i], ".flush.ftpfs") == 0){				/* hack to flush the cache */				invalidate(node);				readdir(node);				goto Found;			} 			/* some top level names are special */			if((os == Tops || os == VM || os == VMS) && node == remroot){				np = newtopsdir(elems[i]);				if(np){					node = np;					goto Found;				} else {					err = nosuchfile;					break;				}			} 			/* everything else */			node = extendpath(node, s_copy(elems[i]));			if(ISCACHED(node->parent)){				/* the cache of the parent is good, believe it */				if(!ISVALID(node)){					err = nosuchfile;					break;				}				if(node->parent->chdirunknown || (node->d->mode & DMSYML))					fixsymbolic(node);			} else if(!ISVALID(node)){				/* this isn't a valid node, try cd'ing */				if(changedir(node) == 0){					node->d->qid.type = QTDIR;					node->d->mode |= DMDIR;				}else{					node->d->qid.type = QTFILE;					node->d->mode &= ~DMDIR;				}			}			goto Found;		}		if(i == 0 && err == 0)			err = "file does not exist";	} 	/* clunk a newly cloned fid if the walk didn't succeed */	if(nf != nil && (err != nil || rhdr.nwqid<nelems)){		nf->busy = 0;		nf->fid = 0;	} 	/* if it all worked, point the fid to the enw node */	if(err == nil)		f->node = node; 	return err;} char *ropen(Fid *f){	int mode; 	mode = thdr.mode;	if(f->node->d->qid.type & QTDIR)		if(mode != OREAD)			return "permission denied"; 	if(mode & OTRUNC){		uncache(f->node);		uncache(f->node->parent);		filedirty(f->node);	} else {		/* read the remote file or directory */		if(!ISCACHED(f->node)){			filefree(f->node);			if(f->node->d->qid.type & QTDIR){				invalidate(f->node);				if(readdir(f->node) < 0)					return nosuchfile;			} else {				if(readfile(f->node) < 0)					return errstring;			}			CACHED(f->node);		}	} 	rhdr.qid = f->node->d->qid;	f->open = 1;	f->node->opens++;	return 0;} char*rcreate(Fid *f){	char *name; 	if((f->node->d->qid.type&QTDIR) == 0)		return "not a directory"; 	name = thdr.name;	f->node = extendpath(f->node, s_copy(name));	uncache(f->node);	if(thdr.perm & DMDIR){		if(createdir(f->node) < 0)			return "permission denied";	} else

Lines 1–500 of 830.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t