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

📄 hget.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
			tm.year--;	}	strcpy(tm.zone, "GMT");	/* convert to epoch seconds */	u->mtime = tm2sec(&tm);}voidhhclen(char *p, URL*, Range *r){	r->end = atoi(p);}voidhhcrange(char *p, URL*, Range *r){	char *x;	vlong l;	l = 0;	x = strchr(p, '/');	if(x)		l = atoll(x+1);	if(l == 0) {		x = strchr(p, '-');		if(x)			l = atoll(x+1);	}	if(l)		r->end = l;}voidhhuri(char *p, URL *u, Range*){	if(*p != '<')		return;	u->redirect = strdup(p+1);	p = strchr(u->redirect, '>');	if(p != nil)		*p = 0;}voidhhlocation(char *p, URL *u, Range*){	u->redirect = strdup(p);}voidhhauth(char *p, URL *u, Range*){	char *f[4];	UserPasswd *up;	char *s, cred[64];	if (cistrncmp(p, "basic ", 6) != 0)		sysfatal("only Basic authentication supported");	if (gettokens(p, f, nelem(f), "\"") < 2)		sysfatal("garbled auth data");	if ((up = auth_getuserpasswd(auth_getkey, "proto=pass service=http server=%q realm=%q",	    	u->host, f[1])) == nil)			sysfatal("cannot authenticate");	s = smprint("%s:%s", up->user, up->passwd);	if(enc64(cred, sizeof(cred), (uchar *)s, strlen(s)) == -1)		sysfatal("enc64");  		free(s);	assert(u->cred = strdup(cred));}enum{	/* ftp return codes */	Extra=		1,	Success=	2,	Incomplete=	3,	TempFail=	4,	PermFail=	5,	Nnetdir=	64,	/* max length of network directory paths */	Ndialstr=	64,		/* max length of dial strings */};int ftpcmd(int, char*, ...);int ftprcode(int, char*, int);int hello(int);int logon(int);int xfertype(int, char*);int passive(int, URL*);int active(int, URL*);int ftpxfer(int, Out*, Range*);int terminateftp(int, int);int getaddrport(char*, uchar*, uchar*);int ftprestart(int, Out*, URL*, Range*, long);intdoftp(URL *u, URL *px, Range *r, Out *out, long mtime){	int pid, ctl, data, rv;	Waitmsg *w;	char msg[64];	char conndir[NETPATHLEN];	char *p;	/* untested, proxy doesn't work with ftp (I think) */	if(px->host == nil){		ctl = dial(netmkaddr(u->host, tcpdir, u->port), 0, conndir, 0);	} else {		ctl = dial(netmkaddr(px->host, tcpdir, px->port), 0, conndir, 0);	}	if(ctl < 0)		return Error;	if(net == nil){		p = strrchr(conndir, '/');		*p = 0;		snprint(tcpdir, sizeof(tcpdir), conndir);	}	initibuf();	rv = hello(ctl);	if(rv < 0)		return terminateftp(ctl, rv);	rv = logon(ctl);	if(rv < 0)		return terminateftp(ctl, rv);	rv = xfertype(ctl, "I");	if(rv < 0)		return terminateftp(ctl, rv);	/* if file is up to date and the right size, stop */	if(ftprestart(ctl, out, u, r, mtime) > 0){		close(ctl);		return Eof;	}			/* first try passive mode, then active */	data = passive(ctl, u);	if(data < 0){		data = active(ctl, u);		if(data < 0)			return Error;	}	/* fork */	switch(pid = rfork(RFPROC|RFFDG|RFMEM)){	case -1:		close(data);		return terminateftp(ctl, Error);	case 0:		ftpxfer(data, out, r);		close(data);		_exits(0);	default:		close(data);		break;	}	/* wait for reply message */	rv = ftprcode(ctl, msg, sizeof(msg));	close(ctl);	/* wait for process to terminate */	w = nil;	for(;;){		free(w);		w = wait();		if(w == nil)			return Error;		if(w->pid == pid){			if(w->msg[0] == 0){				free(w);				break;			}			werrstr("xfer: %s", w->msg);			free(w);			return Error;		}	}	switch(rv){	case Success:		return Eof;	case TempFail:		return Server;	default:		return Error;	}}intftpcmd(int ctl, char *fmt, ...){	va_list arg;	char buf[2*1024], *s;	va_start(arg, fmt);	s = vseprint(buf, buf + (sizeof(buf)-4) / sizeof(*buf), fmt, arg);	va_end(arg);	if(debug)		fprint(2, "%d -> %s\n", ctl, buf);	*s++ = '\r';	*s++ = '\n';	if(write(ctl, buf, s - buf) != s - buf)		return -1;	return 0;}intftprcode(int ctl, char *msg, int len){	int rv;	int i;	char *p;	len--;	/* room for terminating null */	for(;;){		*msg = 0;		i = readline(ctl, msg, len);		if(i < 0)			break;		if(debug)			fprint(2, "%d <- %s\n", ctl, msg);		/* stop if not a continuation */		rv = strtol(msg, &p, 10);		if(rv >= 100 && rv < 600 && p==msg+3 && *p == ' ')			return rv/100;	}	*msg = 0;	return -1;}inthello(int ctl){	char msg[1024];	/* wait for hello from other side */	if(ftprcode(ctl, msg, sizeof(msg)) != Success){		werrstr("HELLO: %s", msg);		return Server;	}	return 0;}intgetdec(char *p, int n){	int x = 0;	int i;	for(i = 0; i < n; i++)		x = x*10 + (*p++ - '0');	return x;}intftprestart(int ctl, Out *out, URL *u, Range *r, long mtime){	Tm tm;	char msg[1024];	long x, rmtime;	ftpcmd(ctl, "MDTM %s", u->page);	if(ftprcode(ctl, msg, sizeof(msg)) != Success){		r->start = 0;		return 0;		/* need to do something */	}	/* decode modification time */	if(strlen(msg) < 4 + 4 + 2 + 2 + 2 + 2 + 2){		r->start = 0;		return 0;		/* need to do something */	}	memset(&tm, 0, sizeof(tm));	tm.year = getdec(msg+4, 4) - 1900;	tm.mon = getdec(msg+4+4, 2) - 1;	tm.mday = getdec(msg+4+4+2, 2);	tm.hour = getdec(msg+4+4+2+2, 2);	tm.min = getdec(msg+4+4+2+2+2, 2);	tm.sec = getdec(msg+4+4+2+2+2+2, 2);	strcpy(tm.zone, "GMT");	rmtime = tm2sec(&tm);	if(rmtime > mtime)		r->start = 0;	/* get size */	ftpcmd(ctl, "SIZE %s", u->page);	if(ftprcode(ctl, msg, sizeof(msg)) == Success){		x = atol(msg+4);		if(r->start == x)			return 1;	/* we're up to date */		r->end = x;	}	/* seek to restart point */	if(r->start > 0){		ftpcmd(ctl, "REST %lud", r->start);		if(ftprcode(ctl, msg, sizeof(msg)) == Incomplete){			setoffset(out, r->start);		}else			r->start = 0;	}	return 0;	/* need to do something */}intlogon(int ctl){	char msg[1024];	/* login anonymous */	ftpcmd(ctl, "USER anonymous");	switch(ftprcode(ctl, msg, sizeof(msg))){	case Success:		return 0;	case Incomplete:		break;	/* need password */	default:		werrstr("USER: %s", msg);		return Server;	}	/* send user id as password */	sprint(msg, "%s@closedmind.org", getuser());	ftpcmd(ctl, "PASS %s", msg);	if(ftprcode(ctl, msg, sizeof(msg)) != Success){		werrstr("PASS: %s", msg);		return Server;	}	return 0;}intxfertype(int ctl, char *t){	char msg[1024];	ftpcmd(ctl, "TYPE %s", t);	if(ftprcode(ctl, msg, sizeof(msg)) != Success){		werrstr("TYPE %s: %s", t, msg);		return Server;	}	return 0;}intpassive(int ctl, URL *u){	char msg[1024];	char ipaddr[32];	char *f[6];	char *p;	int fd;	int port;	char aport[12];	ftpcmd(ctl, "PASV");	if(ftprcode(ctl, msg, sizeof(msg)) != Success)		return Error;	/* get address and port number from reply, this is AI */	p = strchr(msg, '(');	if(p == nil){		for(p = msg+3; *p; p++)			if(isdigit(*p))				break;	} else		p++;	if(getfields(p, f, 6, 0, ",)") < 6){		werrstr("ftp protocol botch");		return Server;	}	snprint(ipaddr, sizeof(ipaddr), "%s.%s.%s.%s",		f[0], f[1], f[2], f[3]);	port = ((atoi(f[4])&0xff)<<8) + (atoi(f[5])&0xff);	sprint(aport, "%d", port);	/* open data connection */	fd = dial(netmkaddr(ipaddr, tcpdir, aport), 0, 0, 0);	if(fd < 0){		werrstr("passive mode failed: %r");		return Error;	}	/* tell remote to send a file */	ftpcmd(ctl, "RETR %s", u->page);	if(ftprcode(ctl, msg, sizeof(msg)) != Extra){		werrstr("RETR %s: %s", u->page, msg);		return Error;	}	return fd;}intactive(int ctl, URL *u){	char msg[1024];	char dir[40], ldir[40];	uchar ipaddr[4];	uchar port[2];	int lcfd, dfd, afd;	/* announce a port for the call back */	snprint(msg, sizeof(msg), "%s!*!0", tcpdir);	afd = announce(msg, dir);	if(afd < 0)		return Error;	/* get a local address/port of the annoucement */	if(getaddrport(dir, ipaddr, port) < 0){		close(afd);		return Error;	}	/* tell remote side address and port*/	ftpcmd(ctl, "PORT %d,%d,%d,%d,%d,%d", ipaddr[0], ipaddr[1], ipaddr[2],		ipaddr[3], port[0], port[1]);	if(ftprcode(ctl, msg, sizeof(msg)) != Success){		close(afd);		werrstr("active: %s", msg);		return Error;	}	/* tell remote to send a file */	ftpcmd(ctl, "RETR %s", u->page);	if(ftprcode(ctl, msg, sizeof(msg)) != Extra){		close(afd);		werrstr("RETR: %s", msg);		return Server;	}	/* wait for a connection */	lcfd = listen(dir, ldir);	if(lcfd < 0){		close(afd);		return Error;	}	dfd = accept(lcfd, ldir);	if(dfd < 0){		close(afd);		close(lcfd);		return Error;	}	close(afd);	close(lcfd);		return dfd;}intftpxfer(int in, Out *out, Range *r){	char buf[1024];	long vtime;	int i, n;	vtime = 0;	for(n = 0;;n += i){		i = read(in, buf, sizeof(buf));		if(i == 0)			break;		if(i < 0)			return Error;		if(output(out, buf, i) != i)			return Error;		r->start += i;		if(verbose && (vtime != time(0) || r->start == r->end)) {			vtime = time(0);			fprint(2, "%ld %ld\n", r->start, r->end);		}	}	return n;}intterminateftp(int ctl, int rv){	close(ctl);	return rv;}/* * case insensitive strcmp (why aren't these in libc?) */intcistrncmp(char *a, char *b, int n){	while(n-- > 0){		if(tolower(*a++) != tolower(*b++))			return -1;	}	return 0;}intcistrcmp(char *a, char *b){	while(*a || *b)		if(tolower(*a++) != tolower(*b++))			return -1;	return 0;}/* *  buffered io */struct{	char *rp;	char *wp;	char buf[4*1024];} b;voidinitibuf(void){	b.rp = b.wp = b.buf;}/* *  read a possibly buffered line, strip off trailing while */intreadline(int fd, char *buf, int len){	int n;	char *p;	int eof = 0;	len--;	for(p = buf;;){		if(b.rp >= b.wp){			n = read(fd, b.wp, sizeof(b.buf)/2);			if(n < 0)				return -1;			if(n == 0){				eof = 1;				break;			}			b.wp += n;		}		n = *b.rp++;		if(len > 0){			*p++ = n;			len--;		}		if(n == '\n')			break;	}	/* drop trailing white */	for(;;){		if(p <= buf)			break;		n = *(p-1);		if(n != ' ' && n != '\t' && n != '\r' && n != '\n')			break;		p--;	}	*p = 0;	if(eof && p == buf)		return -1;	return p-buf;}voidunreadline(char *line){	int i, n;	i = strlen(line);	n = b.wp-b.rp;	memmove(&b.buf[i+1], b.rp, n);	memmove(b.buf, line, i);	b.buf[i] = '\n';	b.rp = b.buf;	b.wp = b.rp + i + 1 + n;}intreadibuf(int fd, char *buf, int len){	int n;	n = b.wp-b.rp;	if(n > 0){		if(n > len)			n = len;		memmove(buf, b.rp, n);		b.rp += n;		return n;	}	return read(fd, buf, len);}intdfprint(int fd, char *fmt, ...){	char buf[4*1024];	va_list arg;	va_start(arg, fmt);	vseprint(buf, buf+sizeof(buf), fmt, arg);	va_end(arg);	if(debug)		fprint(2, "%d -> %s", fd, buf);	return fprint(fd, "%s", buf);}intgetaddrport(char *dir, uchar *ipaddr, uchar *port){	char buf[256];	int fd, i;	char *p;	snprint(buf, sizeof(buf), "%s/local", dir);	fd = open(buf, OREAD);	if(fd < 0)		return -1;	i = read(fd, buf, sizeof(buf)-1);	close(fd);	if(i <= 0)		return -1;	buf[i] = 0;	p = strchr(buf, '!');	if(p != nil)		*p++ = 0;	v4parseip(ipaddr, buf);	i = atoi(p);	port[0] = i>>8;	port[1] = i;	return 0;}voidmd5free(DigestState *state){	uchar x[MD5dlen];	md5(nil, 0, x, state);}DigestState*md5dup(DigestState *state){	char *p;	p = md5pickle(state);	if(p == nil)		sysfatal("md5pickle: %r");	state = md5unpickle(p);	if(state == nil)		sysfatal("md5unpickle: %r");	free(p);	return state;}voidsetoffset(Out *out, int offset){	md5free(out->curr);	if(offset == 0)		out->curr = md5(nil, 0, nil, nil);	else		out->curr = nil;	out->offset = offset;	out->written = offset;	if(ofile != nil)		if(seek(out->fd, offset, 0) != offset)			sysfatal("seek: %r");}/* * write some output, discarding it (but keeping track) * if we've already written it. if we've gone backwards, * verify that everything previously written matches * that which would have been written from the current * output. */intoutput(Out *out, char *buf, int nb){	int n, d;	uchar m0[MD5dlen], m1[MD5dlen];	n = nb;	d = out->written - out->offset;	assert(d >= 0);	if(d > 0){		if(n < d){			if(out->curr != nil)				md5((uchar*)buf, n, nil, out->curr);			out->offset += n;			return n;		}		if(out->curr != nil){			md5((uchar*)buf, d, m0, out->curr);			out->curr = nil;			md5(nil, 0, m1, md5dup(out->hiwat));			if(memcmp(m0, m1, MD5dlen) != 0){				fprint(2, "integrity check failure at offset %d\n", out->written);				return -1;			}		}		buf += d;		n -= d;		out->offset += d;	}	if(n > 0){		out->hiwat = md5((uchar*)buf, n, nil, out->hiwat);		n = write(out->fd, buf, n);		if(n > 0){			out->offset += n;			out->written += n;		}	}	return n + d;}

⌨️ 快捷键说明

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