proto.c

来自「这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易」· C语言 代码 · 共 1,658 行 · 第 1/2 页

C
1,658
字号
intcreatedir(Node *node){	if(changedir(node->parent) < 0)		return -1;		sendrequest("MKD", node->d->name);	if(getreply(&ctlin, msg, sizeof(msg), 0) != Success)		return -1;	return 0;}/* *  change to a remote directory. */intchangedir(Node *node){	Node *to;	String *cdpath;	to = node;	if(to == remdir)		return 0;	/* build an absolute path */	switch(os){	case Tops:	case VM:		switch(node->depth){		case 0:			remdir = node;			return 0;		case 1:			cdpath = s_clone(node->remname);			break;		default:			return seterr(nosuchfile);		}		break;	case VMS:		switch(node->depth){		case 0:			remdir = node;			return 0;		default:			cdpath = s_new();			vmspath(node, cdpath);		}		break;	case MVS:		if(node->depth == 0)			cdpath = s_clone(remrootpath);		else{			cdpath = s_new();			mvspath(node, cdpath);		}		break;	default:		if(node->depth == 0)			cdpath = s_clone(remrootpath);		else{			cdpath = s_new();			unixpath(node, cdpath);		}		break;	}	uncachedir(remdir, 0);	/*	 *  connect, if we need a password (Incomplete)	 *  act like it worked (best we can do).	 */	sendrequest("CWD", s_to_c(cdpath));	s_free(cdpath);	switch(getreply(&ctlin, msg, sizeof(msg), 0)){	case Success:	case Incomplete:		remdir = node;		return 0;	default:		return seterr(nosuchfile);	}}/* *  read a remote file */intreadfile1(Node *node){	Biobuf *bp;	char buf[4*1024];	long off;	int n;	int tries;	if(changedir(node->parent) < 0)		return -1;	for(tries = 0; tries < 4; tries++){		switch(data(OREAD, &bp, "RETR", s_to_c(node->remname))){		case Extra:			break;		case TempFail:			continue;		default:			return seterr(nosuchfile);		}		off = 0;		while((n = read(Bfildes(bp), buf, sizeof buf)) > 0){			if(filewrite(node, buf, off, n) != n){				off = -1;				break;			}			off += n;		}		if(off < 0)			return -1;		/* make sure a file gets created even for a zero length file */		if(off == 0)			filewrite(node, buf, 0, 0);		close(Bfildes(bp));		switch(getreply(&ctlin, msg, sizeof(msg), 0)){		case Success:			return off;		case TempFail:			continue;		default:			return seterr(nosuchfile);		}	}	return seterr(nosuchfile);}intreadfile(Node *node){	int rv, inimage;	switch(os){	case MVS:	case Plan9:	case Tops:	case TSO:		inimage = 0;		break;	default:		inimage = 1;		image();		break;	}	rv = readfile1(node);	if(inimage)		ascii();	return rv;}/* *  write back a file */intcreatefile1(Node *node){	Biobuf *bp;	char buf[4*1024];	long off;	int n;	if(changedir(node->parent) < 0)		return -1;	if(data(OWRITE, &bp, "STOR", s_to_c(node->remname)) != Extra)		return -1;	for(off = 0; ; off += n){		n = fileread(node, buf, off, sizeof(buf));		if(n <= 0)			break;		write(Bfildes(bp), buf, n);	}	close(Bfildes(bp));	if(getreply(&ctlin, msg, sizeof(msg), 0) != Success)		return -1;	return off;}intcreatefile(Node *node){	int rv;	switch(os){	case Plan9:	case Tops:		break;	default:		image();		break;	}	rv = createfile1(node);	switch(os){	case Plan9:	case Tops:		break;	default:		ascii();		break;	}	return rv;}/* *  remove a remote file */intremovefile(Node *node){	if(changedir(node->parent) < 0)		return -1;		sendrequest("DELE", s_to_c(node->remname));	if(getreply(&ctlin, msg, sizeof(msg), 0) != Success)		return -1;	return 0;}/* *  remove a remote directory */intremovedir(Node *node){	if(changedir(node->parent) < 0)		return -1;		sendrequest("RMD", s_to_c(node->remname));	if(getreply(&ctlin, msg, sizeof(msg), 0) != Success)		return -1;	return 0;}/* *  tell remote that we're exiting and then do it */voidquit(void){	sendrequest("QUIT", nil);	getreply(&ctlin, msg, sizeof(msg), 0);	exits(0);}/* *  send a request */static voidsendrequest(char *a, char *b){	char buf[2*1024];	int n;	n = strlen(a)+2+1;	if(b != nil)		n += strlen(b)+1;	if(n >= sizeof(buf))		fatal("proto request too long");	strcpy(buf, a);	if(b != nil){		strcat(buf, " ");		strcat(buf, b);	}	strcat(buf, "\r\n");	n = strlen(buf);	if(write(ctlfd, buf, n) != n)		fatal("remote side hung up");	if(debug)		write(2, buf, n);	lastsend = time(0);}/* *  replies codes are in the range [100, 999] and may contain multiple lines of *  continuation. */static intgetreply(Biobuf *bp, char *msg, int len, int printreply){	char *line;	char *p;	int rv;	int i, n;	while(line = Brdline(bp, '\n')){		/* add line to message buffer, strip off \r */		n = Blinelen(bp);		if(n > 1 && line[n-2] == '\r'){			n--;			line[n-1] = '\n';		}		if(printreply && !quiet)			write(1, line, n);		else if(debug)			write(2, line, n);		if(n > len - 1)			i = len - 1;		else			i = n;		if(i > 0){			memmove(msg, line, i);			msg += i;			len -= i;			*msg = 0;		}		/* stop if not a continuation */		rv = strtol(line, &p, 10);		if(rv >= 100 && rv < 600 && p==line+3 && *p != '-')			return rv/100;		/* tell user about continuations */		if(!debug && !quiet && !printreply)			write(2, line, n);	}	fatal("remote side closed connection");	return 0;}/* *  Announce on a local port and tell its address to the the remote side */static intport(void){	char buf[256];	int n, fd;	char *ptr;	uchar ipaddr[IPaddrlen];	int port;	/* get a channel to listen on, let kernel pick the port number */	sprint(buf, "%s!*!0", net);	listenfd = announce(buf, netdir);	if(listenfd < 0)		return seterr("can't announce");	/* get the local address and port number */	sprint(buf, "%s/local", netdir);	fd = open(buf, OREAD);	if(fd < 0)		return seterr("opening %s: %r", buf);	n = read(fd, buf, sizeof(buf)-1);	close(fd);	if(n <= 0)		return seterr("opening %s/local: %r", netdir);	buf[n] = 0;	ptr = strchr(buf, ' ');	if(ptr)		*ptr = 0;	ptr = strchr(buf, '!')+1;	port = atoi(ptr);	memset(ipaddr, 0, IPaddrlen);	if (*net){		strcpy(buf, net);		ptr = strchr(buf +1, '/');		if (ptr)			*ptr = 0;		myipaddr(ipaddr, buf);	}	/* tell remote side */	sprint(buf, "PORT %d,%d,%d,%d,%d,%d", ipaddr[IPv4off+0], ipaddr[IPv4off+1],		ipaddr[IPv4off+2], ipaddr[IPv4off+3], port>>8, port&0xff);	sendrequest(buf, nil);	if(getreply(&ctlin, msg, sizeof(msg), 0) != Success)		return seterr(msg);	return 0;}/* *  have server call back for a data connection */static intactive(int mode, Biobuf **bpp, char *cmda, char *cmdb){	int cfd, dfd, rv;	char newdir[Maxpath];	char datafile[Maxpath + 6];	TLSconn conn;	if(port() < 0)		return TempFail;	sendrequest(cmda, cmdb);	rv = getreply(&ctlin, msg, sizeof(msg), 0);	if(rv != Extra){		close(listenfd);		return rv;	}	/* wait for a new call */	cfd = listen(netdir, newdir);	if(cfd < 0)		fatal("waiting for data connection");	close(listenfd);	/* open it's data connection and close the control connection */	sprint(datafile, "%s/data", newdir);	dfd = open(datafile, ORDWR);	close(cfd);	if(dfd < 0)		fatal("opening data connection");	if(usetls){		memset(&conn, 0, sizeof(conn));		dfd = tlsClient(dfd, &conn);		if(dfd < 0)			fatal("starting tls: %r");		free(conn.cert);	}	Binit(&dbuf, dfd, mode);	*bpp = &dbuf;	return Extra;}/* *  call out for a data connection */static intpassive(int mode, Biobuf **bpp, char *cmda, char *cmdb){	char msg[1024];	char ds[1024];	char *f[6];	char *p;	int x, fd;	TLSconn conn;	if(nopassive)		return Impossible;	sendrequest("PASV", nil);	if(getreply(&ctlin, msg, sizeof(msg), 0) != Success){		nopassive = 1;		return Impossible;	}	/* get address and port number from reply, this is AI */	p = strchr(msg, '(');	if(p == 0){		for(p = msg+3; *p; p++)			if(isdigit(*p))				break;	} else		p++;	if(getfields(p, f, 6, 0, ",") < 6){		if(debug)			fprint(2, "passive mode protocol botch: %s\n", msg);		werrstr("ftp protocol botch");		nopassive = 1;		return Impossible;	}	snprint(ds, sizeof(ds), "%s!%s.%s.%s.%s!%d", net,		f[0], f[1], f[2], f[3],		((atoi(f[4])&0xff)<<8) + (atoi(f[5])&0xff));	/* open data connection */	fd = dial(ds, 0, 0, 0);	if(fd < 0){		if(debug)			fprint(2, "passive mode connect to %s failed: %r\n", ds);		nopassive = 1;		return TempFail;	}	/* tell remote to send a file */	sendrequest(cmda, cmdb);	x = getreply(&ctlin, msg, sizeof(msg), 0);	if(x != Extra){		close(fd);		if(debug)			fprint(2, "passive mode retrieve failed: %s\n", msg);		werrstr(msg);		return x;	}	if(usetls){		memset(&conn, 0, sizeof(conn));		fd = tlsClient(fd, &conn);		if(fd < 0)			fatal("starting tls: %r");		free(conn.cert);	}	Binit(&dbuf, fd, mode);	*bpp = &dbuf;	return Extra;}static intdata(int mode, Biobuf **bpp, char* cmda, char *cmdb){	int x;	x = passive(mode, bpp, cmda, cmdb);	if(x != Impossible)		return x;	return active(mode, bpp, cmda, cmdb);}/* *  used for keep alives */voidnop(void){	if(lastsend - time(0) < 15)		return;	sendrequest("PWD", nil);	getreply(&ctlin, msg, sizeof(msg), 0);}/* *  turn a vms spec into a path */static Node*vmsextendpath(Node *np, char *name){	np = extendpath(np, s_copy(name));	if(!ISVALID(np)){		np->d->qid.type = QTDIR;		np->d->atime = time(0);		np->d->mtime = np->d->atime;		strcpy(np->d->uid, "who");		strcpy(np->d->gid, "cares");		np->d->mode = DMDIR|0777;		np->d->length = 0;		if(changedir(np) >= 0)			VALID(np);	}	return np;}static Node*vmsdir(char *name){	char *cp;	Node *np;	char *oname;	np = remroot;	cp = strchr(name, '[');	if(cp)		strcpy(cp, cp+1);	cp = strchr(name, ']');	if(cp)		*cp = 0;	oname = name = strdup(name);	if(name == 0)		return 0;	while(cp = strchr(name, '.')){		*cp = 0;		np = vmsextendpath(np, name);		name = cp+1;	}	np = vmsextendpath(np, name);	/*	 *  walk back to first accessible directory	 */	for(; np->parent != np; np = np->parent)		if(ISVALID(np)){			CACHED(np->parent);			break;		}	free(oname);	return np;}/* *  walk up the tree building a VMS style path */static voidvmspath(Node *node, String *path){	char *p;	int n;	if(node->depth == 1){		p = strchr(s_to_c(node->remname), ':');		if(p){			n = p - s_to_c(node->remname) + 1;			s_nappend(path, s_to_c(node->remname), n);			s_append(path, "[");			s_append(path, p+1);		} else {			s_append(path, "[");			s_append(path, s_to_c(node->remname));		}		s_append(path, "]");		return;	}	vmspath(node->parent, path);	s_append(path, ".");	s_append(path, s_to_c(node->remname));}/* *  walk up the tree building a Unix style path */static voidunixpath(Node *node, String *path){	if(node == node->parent){		s_append(path, s_to_c(remrootpath));		return;	}	unixpath(node->parent, path);	if(s_len(path) > 0 && strcmp(s_to_c(path), "/") != 0)		s_append(path, "/");	s_append(path, s_to_c(node->remname));}/* *  walk up the tree building a MVS style path */static voidmvspath(Node *node, String *path){	if(node == node->parent){		s_append(path, s_to_c(remrootpath));		return;	}	mvspath(node->parent, path);	if(s_len(path) > 0)		s_append(path, ".");	s_append(path, s_to_c(node->remname));}static intgetpassword(char *buf, char *e){	char *p;	int c;	int consctl, rv = 0;	consctl = open("/dev/consctl", OWRITE);	if(consctl >= 0)		write(consctl, "rawon", 5);	print("Password: ");	e--;	for(p = buf; p <= e; p++){		c = Bgetc(&stdin);		if(c < 0){			rv = -1;			goto out;		}		if(c == '\n' || c == '\r')			break;		*p = c;	}	*p = 0;	print("\n");out:	if(consctl >= 0)		close(consctl);	return rv;}/* *  convert from latin1 to utf */static char*fromlatin1(char *from){	char *p, *to;	Rune r;	if(os == Plan9)		return nil;	/* don't convert if we don't have to */	for(p = from; *p; p++)		if(*p & 0x80)			break;	if(*p == 0)		return nil;	to = malloc(3*strlen(from)+2);	if(to == nil)		return nil;	for(p = to; *from; from++){		r = (*from) & 0xff;		p += runetochar(p, &r);	}	*p = 0;	return to;}Dir*reallocdir(Dir *d, int dofree){	Dir *dp;	char *p;	int nn, ng, nu, nm;	char *utf;	if(d->name == nil)		d->name = "?name?";	if(d->uid == nil)		d->uid = "?uid?";	if(d->gid == nil)		d->gid = d->uid;	if(d->muid == nil)		d->muid = d->uid;		utf = fromlatin1(d->name);	if(utf != nil)		d->name = utf;	nn = strlen(d->name)+1;	nu = strlen(d->uid)+1;	ng = strlen(d->gid)+1;	nm = strlen(d->muid)+1;	dp = malloc(sizeof(Dir)+nn+nu+ng+nm);	if(dp == nil){		if(dofree)			free(d);		if(utf != nil)			free(utf);		return nil;	}	*dp = *d;	p = (char*)&dp[1];	strcpy(p, d->name);	dp->name = p;	p += nn;	strcpy(p, d->uid);	dp->uid = p;	p += nu;	strcpy(p, d->gid);	dp->gid = p;	p += ng;	strcpy(p, d->muid);	dp->muid = p;	if(dofree)		free(d);	if(utf != nil)		free(utf);	return dp;}Dir*dir_change_name(Dir *d, char *name){	if(d->name && strlen(d->name) >= strlen(name)){		strcpy(d->name, name);		return d;	}	d->name = name;	return reallocdir(d, 1);}Dir*dir_change_uid(Dir *d, char *name){	if(d->uid && strlen(d->uid) >= strlen(name)){		strcpy(d->name, name);		return d;	}	d->uid = name;	return reallocdir(d, 1);}Dir*dir_change_gid(Dir *d, char *name){	if(d->gid && strlen(d->gid) >= strlen(name)){		strcpy(d->name, name);		return d;	}	d->gid = name;	return reallocdir(d, 1);}Dir*dir_change_muid(Dir *d, char *name){	if(d->muid && strlen(d->muid) >= strlen(name)){		strcpy(d->name, name);		return d;	}	d->muid = name;	return reallocdir(d, 1);}static intnw_mode(char dirlet, char *s)		/* NetWare file mode mapping */{	int mode = 0777;	if(dirlet == 'd')		mode |= DMDIR;	if (strlen(s) >= 10 && s[0] != '[' || s[9] != ']')		return(mode);	if (s[1] == '-')					/* can't read file */		mode &= ~0444;	if (dirlet == 'd' && s[6] == '-')			/* cannot scan dir */		mode &= ~0444;	if (s[2] == '-')					/* can't write file */		mode &= ~0222;	if (dirlet == 'd' && s[7] == '-' && s[3] == '-')	/* cannot create in, or modify dir */		mode &= ~0222;	return(mode);}

⌨️ 快捷键说明

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