📄 nntpfs.c
字号:
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 + -