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

📄 nntpfs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
		lo = strtol(f[2], 0, 10);		if(g->hi != hi){			g->hi = hi;			if(g->lo==0)				g->lo = lo;			g->canpost = f[3][0] == 'y';			g->mtime = time(0);		}	}}voidnntprefresh(Netbuf *n, Group *g){	char cmd[1024];	char *f[5];	int lo, hi;	if(g->isgroup==0)		return;	if(time(0) - g->atime < 30)		return;	strcpy(cmd, "GROUP ");	printgroup(cmd, g);	if(nntpcmd(n, cmd, 21) < 0){		n->currentgroup = nil;		return;	}	n->currentgroup = g;	if(tokenize(n->response, f, nelem(f)) < 4){		fprint(2, "error reading GROUP response");		return;	}	/* backwards from LIST! */	hi = strtol(f[3], 0, 10)+1;	lo = strtol(f[2], 0, 10);	if(g->hi != hi){		g->mtime = time(0);		if(g->lo==0)			g->lo = lo;		g->hi = hi;	}	g->atime = time(0);}char*nntppost(Netbuf *n, char *msg){	char *p, *q;	if(nntpcmd(n, "POST", 34) < 0)		return n->response;	for(p=msg; *p; p=q){		if(q = strchr(p, '\n'))			*q++ = '\0';		else			q = p+strlen(p);		if(p[0]=='.')			Bputc(&n->bw, '.');		Bwrite(&n->bw, p, strlen(p));		Bputc(&n->bw, '\r');		Bputc(&n->bw, '\n');	}	Bprint(&n->bw, ".\r\n");	if(nntpresponse(n, 0, nil) < 0)		return n->response;	if(n->code/100 != 2)		return n->response;	return nil;}/* * Because an expanded QID space makes thngs much easier, * we sleazily use the version part of the QID as more path bits.  * Since we make sure not to mount ourselves cached, this * doesn't break anything (unless you want to bind on top of  * things in this file system).  In the next version of 9P, we'll * have more QID bits to play with. *  * The newsgroup is encoded in the top 15 bits * of the path.  The message number is the bottom 17 bits. * The file within the message directory is in the version [sic]. */enum {	/* file qids */	Qhead,	Qbody,	Qarticle,	Qxover,	Nfile,};char *filename[] = {	"header",	"body",	"article",	"xover",};char *nntpname[] = {	"HEAD",	"BODY",	"ARTICLE",	"XOVER",};#define GROUP(p)	(((p)>>17)&0x3FFF)#define MESSAGE(p)	((p)&0x1FFFF)#define FILE(v)		((v)&0x3)#define PATH(g,m)	((((g)&0x3FFF)<<17)|((m)&0x1FFFF))#define POST(g)	PATH(0,g,0)#define VERS(f)		((f)&0x3)typedef struct Aux Aux;struct Aux {	Group *g;	int n;	int ispost;	int file;	char *s;	int ns;	int offset;};static voidfsattach(Req *r){	Aux *a;	char *spec;	spec = r->ifcall.aname;	if(spec && spec[0]){		respond(r, "invalid attach specifier");		return;	}	a = emalloc(sizeof *a);	a->g = root;	a->n = -1;	r->fid->aux = a;		r->ofcall.qid = (Qid){0, 0, QTDIR};	r->fid->qid = r->ofcall.qid;	respond(r, nil);}static char*fsclone(Fid *ofid, Fid *fid){	Aux *a;	a = emalloc(sizeof(*a));	*a = *(Aux*)ofid->aux;	fid->aux = a;	return nil;}static char*fswalk1(Fid *fid, char *name, Qid *qid){	char *p;	int i, isdotdot, n;	Aux *a;	Group *ng;	isdotdot = strcmp(name, "..")==0;	a = fid->aux;	if(a->s)	/* file */		return "protocol botch";	if(a->n != -1){		if(isdotdot){			*qid = (Qid){PATH(a->g->num, 0), 0, QTDIR};			fid->qid = *qid;			a->n = -1;			return nil;		}		for(i=0; i<Nfile; i++){ 			if(strcmp(name, filename[i])==0){				if(a->s = nntpget(net, a->g, a->n, nntpname[i])){					*qid = (Qid){PATH(a->g->num, a->n), Qbody, 0};					fid->qid = *qid;					a->file = i;					return nil;				}else					return "file does not exist";			}		}		return "file does not exist";	}	if(isdotdot){		a->g = a->g->parent;		*qid = (Qid){PATH(a->g->num, 0), 0, QTDIR};		fid->qid = *qid;		return nil;	}	if(a->g->isgroup && !readonly && a->g->canpost	&& strcmp(name, "post")==0){		a->ispost = 1;		*qid = (Qid){PATH(a->g->num, 0), 0, 0};		fid->qid = *qid;		return nil;	}	if(ng = findgroup(a->g, name, 0)){		a->g = ng;		*qid = (Qid){PATH(a->g->num, 0), 0, QTDIR};		fid->qid = *qid;		return nil;	}	n = strtoul(name, &p, 0);	if('0'<=name[0] && name[0]<='9' && *p=='\0' && a->g->lo<=n && n<a->g->hi){		a->n = n;		*qid = (Qid){PATH(a->g->num, n+1-a->g->lo), 0, QTDIR};		fid->qid = *qid;		return nil;	}	return "file does not exist";}static voidfsopen(Req *r){	Aux *a;	a = r->fid->aux;	if((a->ispost && (r->ifcall.mode&~OTRUNC) != OWRITE)	|| (!a->ispost && r->ifcall.mode != OREAD))		respond(r, "permission denied");	else		respond(r, nil);}static voidfillstat(Dir *d, Aux *a){	char buf[32];	Group *g;	memset(d, 0, sizeof *d);	d->uid = estrdup("nntp");	d->gid = estrdup("nntp");	g = a->g;	d->atime = d->mtime = g->mtime;	if(a->ispost){		d->name = estrdup("post");		d->mode = 0222;		d->qid = (Qid){PATH(g->num, 0), 0, 0};		d->length = a->ns;		return;	}	if(a->s){	/* article file */		d->name = estrdup(filename[a->file]);		d->mode = 0444;		d->qid = (Qid){PATH(g->num, a->n+1-g->lo), a->file, 0};		return;	}	if(a->n != -1){	/* article directory */		sprint(buf, "%d", a->n);		d->name = estrdup(buf);		d->mode = DMDIR|0555;		d->qid = (Qid){PATH(g->num, a->n+1-g->lo), 0, QTDIR};		return;	}	/* group directory */	if(g->name[0])		d->name = estrdup(g->name);	else		d->name = estrdup("/");	d->mode = DMDIR|0555;	d->qid = (Qid){PATH(g->num, 0), g->hi-1, QTDIR};}static intdirfillstat(Dir *d, Aux *a, int i){	int ndir;	Group *g;	char buf[32];	memset(d, 0, sizeof *d);	d->uid = estrdup("nntp");	d->gid = estrdup("nntp");	g = a->g;	d->atime = d->mtime = g->mtime;	if(a->n != -1){	/* article directory */		if(i >= Nfile)			return -1;		d->name = estrdup(filename[i]);		d->mode = 0444;		d->qid = (Qid){PATH(g->num, a->n), i, 0};		return 0;	}	/* hierarchy directory: child groups */	if(i < g->nkid){		d->name = estrdup(g->kid[i]->name);		d->mode = DMDIR|0555;		d->qid = (Qid){PATH(g->kid[i]->num, 0), g->kid[i]->hi-1, QTDIR};		return 0;	}	i -= g->nkid;	/* group directory: post file */	if(g->isgroup && !readonly && g->canpost){		if(i < 1){			d->name = estrdup("post");			d->mode = 0222;			d->qid = (Qid){PATH(g->num, 0), 0, 0};			return 0;		}		i--;	}	/* group directory: child articles */	ndir = g->hi - g->lo;	if(i < ndir){		sprint(buf, "%d", g->lo+i);		d->name = estrdup(buf);		d->mode = DMDIR|0555;		d->qid = (Qid){PATH(g->num, i+1), 0, QTDIR};		return 0;	}	return -1;}static voidfsstat(Req *r){	Aux *a;	a = r->fid->aux;	if(r->fid->qid.path == 0 && (r->fid->qid.type & QTDIR))		nntprefreshall(net);	else if(a->g->isgroup)		nntprefresh(net, a->g);	fillstat(&r->d, a);	respond(r, nil);}static voidfsread(Req *r){	int offset, n;	Aux *a;	char *p, *ep;	Dir d;	a = r->fid->aux;	if(a->s){		readstr(r, a->s);		respond(r, nil);		return;	}	if(r->ifcall.offset == 0)		offset = 0;	else		offset = a->offset;	p = r->ofcall.data;	ep = r->ofcall.data+r->ifcall.count;	for(; p+2 < ep; p += n){		if(dirfillstat(&d, a, offset) < 0)			break;		n=convD2M(&d, (uchar*)p, ep-p);		free(d.name);		free(d.uid);		free(d.gid);		free(d.muid);		if(n <= BIT16SZ)			break;		offset++;	}	a->offset = offset;	r->ofcall.count = p - r->ofcall.data;	respond(r, nil);}static voidfswrite(Req *r){	Aux *a;	long count;	vlong offset;	a = r->fid->aux;	if(r->ifcall.count == 0){	/* commit */		respond(r, nntppost(net, a->s));		free(a->s);		a->ns = 0;		a->s = nil;		return;	}	count = r->ifcall.count;	offset = r->ifcall.offset;	if(a->ns < count+offset+1){		a->s = erealloc(a->s, count+offset+1);		a->ns = count+offset;		a->s[a->ns] = '\0';	}	memmove(a->s+offset, r->ifcall.data, count);	r->ofcall.count = count;	respond(r, nil);}static voidfsdestroyfid(Fid *fid){	Aux *a;	a = fid->aux;	if(a==nil)		return;	if(a->ispost && a->s)		nntppost(net, a->s);	free(a->s);	free(a);}Srv nntpsrv = {.destroyfid=	fsdestroyfid,.attach=	fsattach,.clone=	fsclone,.walk1=	fswalk1,.open=	fsopen,.read=	fsread,.write=	fswrite,.stat=	fsstat,};voidusage(void){	fprint(2, "usage: nntpsrv [-a] [-s service] [-m mtpt] [nntp.server]\n");	exits("usage");}voiddumpgroups(Group *g, int ind){	int i;	print("%*s%s\n", ind*4, "", g->name);	for(i=0; i<g->nkid; i++)		dumpgroups(g->kid[i], ind+1);}voidmain(int argc, char **argv){	int auth, x;	char *mtpt, *service, *where, *user;	Netbuf n;	UserPasswd *up;	mtpt = "/mnt/news";	service = nil;	memset(&n, 0, sizeof n);	user = nil;	auth = 0;	ARGBEGIN{	case 'D':		chatty9p++;		break;	case 'N':		netdebug = 1;		break;	case 'a':		auth = 1;		break;	case 'u':		user = EARGF(usage());		break;	case 's':		service = EARGF(usage());		break;	case 'm':		mtpt = EARGF(usage());		break;	default:		usage();	}ARGEND	if(argc > 1)		usage();	if(argc==0)		where = "$nntp";	else		where = argv[0]; 	now = time(0);	net = &n;	if(auth) {		n.auth = 1;		if(user)			up = auth_getuserpasswd(auth_getkey, "proto=pass service=nntp server=%q user=%q", where, user);		else			up = auth_getuserpasswd(auth_getkey, "proto=pass service=nntp server=%q", where);		if(up == nil)			sysfatal("no password: %r");		n.user = up->user;		n.pass = up->passwd;	}	n.addr = netmkaddr(where, "tcp", "nntp");	root = emalloc(sizeof *root);	root->name = estrdup("");	root->parent = root;	n.fd = -1;	if(nntpconnect(&n) < 0)		sysfatal("nntpconnect: %s", n.response);	x=netdebug;	netdebug=0;	nntprefreshall(&n);	netdebug=x;//	dumpgroups(root, 0);	postmountsrv(&nntpsrv, service, mtpt, MREPL);	exits(nil);}

⌨️ 快捷键说明

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