⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftpd.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
			*(arg+n-4) = 0;			d = dirstat(arg);			if(d != nil){				if(d->qid.type & QTDIR){					retrievedir(arg);					free(d);					return;				}				free(d);			}		}		logit("get %s failed", arg);		reply("550 Error opening %s: %r", arg);		return;	}	if(offset != 0)		if(seek(fd, offset, 0) < 0){			reply("550 %s: seek to %lld failed", arg, offset);			close(fd);			return;		}	d = dirfstat(fd);	if(d != nil){		if(d->qid.type & QTDIR){			reply("550 %s: not a plain file.", arg);			close(fd);			free(d);			return;		}		free(d);	}	n = read(fd, buf, sizeof(buf));	if(n < 0){		logit("get %s failed", arg, mailaddr, nci->rsys);		reply("550 Error reading %s: %r", arg);		close(fd);		return;	}	if(type != Timage)		for(p = buf, ep = &buf[n]; p < ep; p++)			if(*p & 0x80){				close(fd);				reply("550 This file requires type binary/image");				return;			}	reply("150 Opening data connection for %s (%s)", arg, data);	dfd = dialdata();	if(dfd < 0){		reply("425 Error opening data connection:%r");		close(fd);		return;	}	bytes = 0;	do {		switch(type){		case Timage:			i = write(dfd, buf, n);			break;		default:			i = crlfwrite(dfd, buf, n);			break;		}		if(i != n){			close(fd);			close(dfd);			logit("get %s %r to data connection after %d", arg, bytes);			reply("550 Error writing to data connection: %r");			return;		}		bytes += n;	} while((n = read(fd, buf, sizeof(buf))) > 0);	if(n < 0)		logit("get %s %r after %d", arg, bytes);	close(fd);	close(dfd);	reply("226 Transfer complete");	logit("get %s OK %d", arg, bytes);}intretrievecmd(char *arg){	if(arg == 0)		return reply("501 Retrieve command requires an argument");	arg = abspath(arg);	if(arg == 0)		return reply("550 Permission denied");	return asproc(retrieve, arg, 0);}/* *  get a file from the user */intlfwrite(int fd, char *p, int n){	char *ep, *np;	char buf[Nbuf];	for(np = buf, ep = p + n; p < ep; p++){		if(*p != '\r')			*np++ = *p;	}	if(write(fd, buf, np - buf) == np - buf)		return n;	else		return -1;}voidstore(char *arg, int fd){	int dfd, n, i;	char buf[Nbuf];	reply("150 Opening data connection for %s (%s)", arg, data);	dfd = dialdata();	if(dfd < 0){		reply("425 Error opening data connection:%r");		close(fd);		return;	}	while((n = read(dfd, buf, sizeof(buf))) > 0){		switch(type){		case Timage:			i = write(fd, buf, n);			break;		default:			i = lfwrite(fd, buf, n);			break;		}		if(i != n){			close(fd);			close(dfd);			reply("550 Error writing file");			return;		}	}	close(fd);	close(dfd);	logit("put %s OK", arg);	reply("226 Transfer complete");}intstorecmd(char *arg){	int fd, rv;	if(arg == 0)		return reply("501 Store command requires an argument");	arg = abspath(arg);	if(arg == 0)		return reply("550 Permission denied");	if(isnone && strncmp(arg, "/incoming/", sizeof("/incoming/")-1))		return reply("550 Permission denied");	if(offset){		fd = open(arg, OWRITE);		if(fd == -1)			return reply("550 Error opening %s: %r", arg);		if(seek(fd, offset, 0) == -1)			return reply("550 Error seeking %s to %d: %r",				arg, offset);	} else {		fd = create(arg, OWRITE, createperm);		if(fd == -1)			return reply("550 Error creating %s: %r", arg);	}	rv = asproc(store, arg, fd);	close(fd);	return rv;}intappendcmd(char *arg){	int fd, rv;	if(arg == 0)		return reply("501 Append command requires an argument");	if(isnone)		return reply("550 Permission denied");	arg = abspath(arg);	if(arg == 0)		return reply("550 Error creating %s: Permission denied", arg);	fd = open(arg, OWRITE);	if(fd == -1){		fd = create(arg, OWRITE, createperm);		if(fd == -1)			return reply("550 Error creating %s: %r", arg);	}	seek(fd, 0, 2);	rv = asproc(store, arg, fd);	close(fd);	return rv;}intstoreucmd(char *arg){	int fd, rv;	char name[Maxpath];	USED(arg);	if(isnone)		return reply("550 Permission denied");	strncpy(name, "ftpXXXXXXXXXXX", sizeof name);	mktemp(name);	fd = create(name, OWRITE, createperm);	if(fd == -1)		return reply("550 Error creating %s: %r", name);	rv = asproc(store, name, fd);	close(fd);	return rv;}intmkdircmd(char *name){	int fd;	if(name == 0)		return reply("501 Mkdir command requires an argument");	if(isnone)		return reply("550 Permission denied");	name = abspath(name);	if(name == 0)		return reply("550 Permission denied");	fd = create(name, OREAD, DMDIR|0775);	if(fd < 0)		return reply("550 Can't create %s: %r", name);	close(fd);	return reply("226 %s created", name);}intdelcmd(char *name){	if(name == 0)		return reply("501 Rmdir/delete command requires an argument");	if(isnone)		return reply("550 Permission denied");	name = abspath(name);	if(name == 0)		return reply("550 Permission denied");	if(remove(name) < 0)		return reply("550 Can't remove %s: %r", name);	else		return reply("226 %s removed", name);}/* *  kill off the last transfer (if the process still exists) */intabortcmd(char *arg){	USED(arg);	logit("abort pid %d", pid);	if(pid){		if(postnote(PNPROC, pid, "kill") == 0)			reply("426 Command aborted");		else			logit("postnote pid %d %r", pid);	}	return reply("226 Abort processed");}intsystemcmd(char *arg){	USED(arg);	return reply("215 UNIX Type: L8 Version: Plan 9");}inthelpcmd(char *arg){	int i;	char buf[80];	char *p, *e;	USED(arg);	reply("214- the following commands are implemented:");	p = buf;	e = buf+sizeof buf;	for(i = 0; cmdtab[i].name; i++){		if((i%8) == 0){			reply("214-%s", buf);			p = buf;		}		p = seprint(p, e, " %-5.5s", cmdtab[i].name);	}	if(p != buf)		reply("214-%s", buf);	reply("214 ");	return 0;}/* *  renaming a file takes two commands */static String *filepath;intrnfrcmd(char *from){	if(isnone)		return reply("550 Permission denied");	if(from == 0)		return reply("501 Rename command requires an argument");	from = abspath(from);	if(from == 0)		return reply("550 Permission denied");	if(filepath == nil)		filepath = s_copy(from);	else{		s_reset(filepath);		s_append(filepath, from);	}	return reply("350 Rename %s to ...", s_to_c(filepath));}intrntocmd(char *to){	int r;	Dir nd;	char *fp, *tp;	if(isnone)		return reply("550 Permission denied");	if(to == 0)		return reply("501 Rename command requires an argument");	to = abspath(to);	if(to == 0)		return reply("550 Permission denied");	if(filepath == nil || *(s_to_c(filepath)) == 0)		return reply("503 Rnto must be preceeded by an rnfr");	tp = strrchr(to, '/');	fp = strrchr(s_to_c(filepath), '/');	if((tp && fp == 0) || (fp && tp == 0)	|| (fp && tp && (fp-s_to_c(filepath) != tp-to || memcmp(s_to_c(filepath), to, tp-to))))		return reply("550 Rename can't change directory");	if(tp)		to = tp+1;	nulldir(&nd);	nd.name = to;	if(dirwstat(s_to_c(filepath), &nd) < 0)		r = reply("550 Can't rename %s to %s: %r\n", s_to_c(filepath), to);	else		r = reply("250 %s now %s", s_to_c(filepath), to);	s_reset(filepath);	return r;}/* *  to dial out we need the network file system in our *  name space. */intdialdata(void){	int fd, cfd;	char ldir[40];	char err[Maxerr];	if(mountnet() < 0)		return -1;	if(!passive.inuse){		fd = dial(data, "20", 0, 0);		errstr(err, sizeof err);	} else {		alarm(5*60*1000);		cfd = listen(passive.adir, ldir);		alarm(0);		errstr(err, sizeof err);		if(cfd < 0)			return -1;		fd = accept(cfd, ldir);		errstr(err, sizeof err);		close(cfd);	}	if(fd < 0)		logit("can't dial %s: %s", data, err);	unmountnet();	werrstr(err, sizeof err);	return fd;}intpostnote(int group, int pid, char *note){	char file[128];	int f, r;	/*	 * Use #p because /proc may not be in the namespace.	 */	switch(group) {	case PNPROC:		sprint(file, "#p/%d/note", pid);		break;	case PNGROUP:		sprint(file, "#p/%d/notepg", pid);		break;	default:		return -1;	}	f = open(file, OWRITE);	if(f < 0)		return -1;	r = strlen(note);	if(write(f, note, r) != r) {		close(f);		return -1;	}	close(f);	return 0;}/* *  to circumscribe the accessible files we have to eliminate ..'s *  and resolve all names from the root.  We also remove any /bin/rc *  special characters to avoid later problems with executed commands. */char *special = "`;| ";char*abspath(char *origpath){	char *p, *sp, *path;	static String *rpath;	if(rpath == nil)		rpath = s_new();	else		s_reset(rpath);	if(origpath == nil)		s_append(rpath, curdir);	else{		if(*origpath != '/'){			s_append(rpath, curdir);			s_append(rpath, "/");		}		s_append(rpath, origpath);	}	path = s_to_c(rpath);	for(sp = special; *sp; sp++){		p = strchr(path, *sp);		if(p)			*p = 0;	}	cleanname(s_to_c(rpath));	rpath->ptr = rpath->base+strlen(rpath->base);	if(!accessok(s_to_c(rpath)))		return nil;	return s_to_c(rpath);}typedef struct Path Path;struct Path {	Path	*next;	String	*path;	int	inuse;	int	ok;};enum{	Maxlevel = 16,	Maxperlevel= 8,};Path *pathlevel[Maxlevel];Path*unlinkpath(char *path, int level){	String *s;	Path **l, *p;	int n;	n = 0;	for(l = &pathlevel[level]; *l; l = &(*l)->next){		p = *l;		/* hit */		if(strcmp(s_to_c(p->path), path) == 0){			*l = p->next;			p->next = nil;			return p;		}		/* reuse */		if(++n >= Maxperlevel){			*l = p->next;			s = p->path;			s_reset(p->path);			memset(p, 0, sizeof *p);			p->path = s_append(s, path);			return p;		}	}	/* allocate */	p = mallocz(sizeof *p, 1);	p->path = s_copy(path);	return p;}voidlinkpath(Path *p, int level){	p->next = pathlevel[level];	pathlevel[level] = p;	p->inuse = 1;}voidaddpath(Path *p, int level, int ok){	p->ok = ok;	p->next = pathlevel[level];	pathlevel[level] = p;}int_accessok(String *s, int level){	Path *p;	char *cp;	int lvl, offset;	static char httplogin[] = "/.httplogin";	if(level < 0)		return 1;	lvl = level;	if(lvl >= Maxlevel)		lvl = Maxlevel - 1;	p = unlinkpath(s_to_c(s), lvl);	if(p->inuse){		/* move to front */		linkpath(p, lvl);		return p->ok;	}	cp = strrchr(s_to_c(s), '/');	if(cp == nil)		offset = 0;	else		offset = cp - s_to_c(s);	s_append(s, httplogin);	if(access(s_to_c(s), AEXIST) == 0){		addpath(p, lvl, 0);		return 0;	}	/*	 * There's no way to shorten a String without	 * knowing the implementation.	 */	s->ptr = s->base+offset;	s_terminate(s);	addpath(p, lvl, _accessok(s, level-1));	return p->ok;}/* * check for a subdirectory containing .httplogin * at each level of the path. */intaccessok(char *path){	int level, r;	char *p;	String *npath;	npath = s_copy(path);	p = s_to_c(npath)+1;	for(level = 1; level < Maxlevel; level++){		p = strchr(p, '/');		if(p == nil)			break;		p++;	}	r = _accessok(npath, level-1);	s_free(npath);	return r;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -