📄 u9fs.c
字号:
/* already in plan9.h #include <sys/types.h> *//* for struct passwd, struct group, struct stat ... *//* plan9.h is first to get the large file support definitions as early as possible */#include <plan9.h>#include <sys/stat.h> /* for stat, umask */#include <stdlib.h> /* for malloc */#include <string.h> /* for strcpy, memmove */#include <pwd.h> /* for getpwnam, getpwuid */#include <grp.h> /* for getgrnam, getgrgid */#include <unistd.h> /* for gethostname, pread, pwrite, read, write */#include <utime.h> /* for utime */#include <dirent.h> /* for readdir */#include <errno.h> /* for errno */#include <stdio.h> /* for remove [sic] */#include <fcntl.h> /* for O_RDONLY, etc. */#include <sys/socket.h> /* various networking crud */#include <netinet/in.h>#include <netdb.h>#include <fcall.h>#include <oldfcall.h>#include <u9fs.h>/* #ifndef because can be given in makefile */#ifndef DEFAULTLOG#define DEFAULTLOG "/tmp/u9fs.log"#endifchar *logfile = DEFAULTLOG;#define S_ISSPECIAL(m) (S_ISCHR(m) || S_ISBLK(m) || S_ISFIFO(m))enum { Tdot = 1, Tdotdot};enum { P9P1, P9P2000};typedef struct User User;struct User { int id; gid_t defaultgid; char *name; char **mem; /* group members */ int nmem; User *next;};struct Fid { int fid; char *path; struct stat st; User *u; int omode; DIR *dir; int diroffset; int fd; struct dirent *dirent; Fid *next; Fid *prev; int auth; void *authmagic;};void* emalloc(size_t);void* erealloc(void*, size_t);char* estrdup(char*);char* estrpath(char*, char*);void sysfatal(char*, ...);int okuser(char*);void rversion(Fcall*, Fcall*);void rauth(Fcall*, Fcall*);void rattach(Fcall*, Fcall*);void rflush(Fcall*, Fcall*);void rclone(Fcall*, Fcall*);void rwalk(Fcall*, Fcall*);void ropen(Fcall*, Fcall*);void rcreate(Fcall*, Fcall*);void rread(Fcall*, Fcall*);void rwrite(Fcall*, Fcall*);void rclunk(Fcall*, Fcall*);void rstat(Fcall*, Fcall*);void rwstat(Fcall*, Fcall*);void rclwalk(Fcall*, Fcall*);void rremove(Fcall*, Fcall*);User* uname2user(char*);User* gname2user(char*);User* uid2user(int);User* gid2user(int);Fid* newfid(int, char**);Fid* oldfidex(int, int, char**);Fid* oldfid(int, char**);int fidstat(Fid*, char**);void freefid(Fid*);int userchange(User*, char**);int userwalk(User*, char**, char*, Qid*, char**);int useropen(Fid*, int, char**);int usercreate(Fid*, char*, int, long, char**);int userremove(Fid*, char**);int userperm(User*, char*, int, int);int useringroup(User*, User*);Qid stat2qid(struct stat*);void getfcallold(int, Fcall*, int);void putfcallold(int, Fcall*);char Eauth[] = "authentication failed";char Ebadfid[] = "fid unknown or out of range";char Ebadoffset[] = "bad offset in directory read";char Ebadusefid[] = "bad use of fid";char Edirchange[] = "wstat can't convert between files and directories";char Eexist[] = "file or directory already exists";char Efidactive[] = "fid already in use";char Enotdir[] = "not a directory";char Enotingroup[] = "not a member of proposed group";char Enotowner[] = "only owner can change group in wstat";char Eperm[] = "permission denied";char Especial0[] = "already attached without access to special files";char Especial1[] = "already attached with access to special files";char Especial[] = "no access to special file";char Etoolarge[] = "i/o count too large";char Eunknowngroup[] = "unknown group";char Eunknownuser[] = "unknown user";char Ewstatbuffer[] = "bogus wstat buffer";ulong msize = IOHDRSZ+8192;uchar* rxbuf;uchar* txbuf;void* databuf;int connected;int devallowed;char* autharg;char* defaultuser;char hostname[256];char remotehostname[256];int chatty9p = 0;int network = 1;int old9p = -1;int authed;User* none;Auth *authmethods[] = { /* first is default */ &authrhosts, &authp9any, &authnone,};Auth *auth;voidgetfcallnew(int fd, Fcall *fc, int have){ int len; if(have > BIT32SZ) sysfatal("cannot happen"); if(have < BIT32SZ && readn(fd, rxbuf+have, BIT32SZ-have) != BIT32SZ-have) sysfatal("couldn't read message"); len = GBIT32(rxbuf); if(len <= BIT32SZ) sysfatal("bogus message"); len -= BIT32SZ; if(readn(fd, rxbuf+BIT32SZ, len) != len) sysfatal("short message"); if(convM2S(rxbuf, len+BIT32SZ, fc) != len+BIT32SZ) sysfatal("badly sized message type %d", rxbuf[0]);}voidgetfcallold(int fd, Fcall *fc, int have){ int len, n; if(have > 3) sysfatal("cannot happen"); if(have < 3 && readn(fd, rxbuf, 3-have) != 3-have) sysfatal("couldn't read message"); len = oldhdrsize(rxbuf[0]); if(len < 3) sysfatal("bad message %d", rxbuf[0]); if(len > 3 && readn(fd, rxbuf+3, len-3) != len-3) sysfatal("couldn't read message"); n = iosize(rxbuf); if(readn(fd, rxbuf+len, n) != n) sysfatal("couldn't read message"); len += n; if(convM2Sold(rxbuf, len, fc) != len) sysfatal("badly sized message type %d", rxbuf[0]);}voidputfcallnew(int wfd, Fcall *tx){ uint n; if((n = convS2M(tx, txbuf, msize)) == 0) sysfatal("couldn't format message type %d", tx->type); if(write(wfd, txbuf, n) != n) sysfatal("couldn't send message");}voidputfcallold(int wfd, Fcall *tx){ uint n; if((n = convS2Mold(tx, txbuf, msize)) == 0) sysfatal("couldn't format message type %d", tx->type); if(write(wfd, txbuf, n) != n) sysfatal("couldn't send message");}voidgetfcall(int fd, Fcall *fc){ if(old9p == 1){ getfcallold(fd, fc, 0); return; } if(old9p == 0){ getfcallnew(fd, fc, 0); return; } /* auto-detect */ if(readn(fd, rxbuf, 3) != 3) sysfatal("couldn't read message"); /* is it an old (9P1) message? */ if(50 <= rxbuf[0] && rxbuf[0] <= 87 && (rxbuf[0]&1)==0 && GBIT16(rxbuf+1) == 0xFFFF){ old9p = 1; getfcallold(fd, fc, 3); return; } getfcallnew(fd, fc, 3); old9p = 0;}voidseterror(Fcall *f, char *error){ f->type = Rerror; f->ename = error ? error : "programmer error";}intisowner(User *u, Fid *f){ return u->id == f->st.st_uid;}voidserve(int rfd, int wfd){ Fcall rx, tx; for(;;){ getfcall(rfd, &rx); if(chatty9p) fprint(2, "<- %F\n", &rx); memset(&tx, 0, sizeof tx); tx.type = rx.type+1; tx.tag = rx.tag; switch(rx.type){ case Tflush: break; case Tversion: rversion(&rx, &tx); break; case Tauth: rauth(&rx, &tx); break; case Tattach: rattach(&rx, &tx); break; case Twalk: rwalk(&rx, &tx); break; case Tstat: tx.stat = databuf; rstat(&rx, &tx); break; case Twstat: rwstat(&rx, &tx); break; case Topen: ropen(&rx, &tx); break; case Tcreate: rcreate(&rx, &tx); break; case Tread: tx.data = databuf; rread(&rx, &tx); break; case Twrite: rwrite(&rx, &tx); break; case Tclunk: rclunk(&rx, &tx); break; case Tremove: rremove(&rx, &tx); break; default: fprint(2, "unknown message %F\n", &rx); seterror(&tx, "bad message"); break; } if(chatty9p) fprint(2, "-> %F\n", &tx); (old9p ? putfcallold : putfcallnew)(wfd, &tx); }}voidrversion(Fcall *rx, Fcall *tx){ if(msize > rx->msize) msize = rx->msize; tx->msize = msize; if(strncmp(rx->version, "9P", 2) != 0) tx->version = "unknown"; else tx->version = "9P2000";}voidrauth(Fcall *rx, Fcall *tx){ char *e; if((e = auth->auth(rx, tx)) != nil) seterror(tx, e);}voidrattach(Fcall *rx, Fcall *tx){ char *e; Fid *fid; User *u; if(rx->aname == nil) rx->aname = ""; if(strcmp(rx->aname, "device") == 0){ if(connected && !devallowed){ seterror(tx, Especial0); return; } devallowed = 1; }else{ if(connected && devallowed){ seterror(tx, Especial1); return; } } if(strcmp(rx->uname, "none") == 0){ if(authed == 0){ seterror(tx, Eauth); return; } } else { if((e = auth->attach(rx, tx)) != nil){ seterror(tx, e); return; } authed++; } if((fid = newfid(rx->fid, &e)) == nil){ seterror(tx, e); return; } fid->path = estrdup("/"); if(fidstat(fid, &e) < 0){ seterror(tx, e); freefid(fid); return; } if(defaultuser) rx->uname = defaultuser; if((u = uname2user(rx->uname)) == nil || (!defaultuser && u->id == 0)){ /* we don't know anyone named root... */ seterror(tx, Eunknownuser); freefid(fid); return; } fid->u = u; tx->qid = stat2qid(&fid->st); return;}voidrwalk(Fcall *rx, Fcall *tx){ int i; char *path, *e; Fid *fid, *nfid; e = nil; if((fid = oldfid(rx->fid, &e)) == nil){ seterror(tx, e); return; } if(fid->omode != -1){ seterror(tx, Ebadusefid); return; } if(fidstat(fid, &e) < 0){ seterror(tx, e); return; } if(!S_ISDIR(fid->st.st_mode) && rx->nwname){ seterror(tx, Enotdir); return; } nfid = nil; if(rx->newfid != rx->fid && (nfid = newfid(rx->newfid, &e)) == nil){ seterror(tx, e); return; } path = estrdup(fid->path); e = nil; for(i=0; i<rx->nwname; i++) if(userwalk(fid->u, &path, rx->wname[i], &tx->wqid[i], &e) < 0) break; if(i == rx->nwname){ /* successful clone or walk */ tx->nwqid = i; if(nfid){ nfid->path = path; nfid->u = fid->u; }else{ free(fid->path); fid->path = path; } }else{ if(i > 0) /* partial walk? */ tx->nwqid = i; else seterror(tx, e); if(nfid) /* clone implicit new fid */ freefid(nfid); free(path); } return;}voidropen(Fcall *rx, Fcall *tx){ char *e; Fid *fid; if((fid = oldfid(rx->fid, &e)) == nil){ seterror(tx, e); return; } if(fid->omode != -1){ seterror(tx, Ebadusefid); return; } if(fidstat(fid, &e) < 0){ seterror(tx, e); return; } if(!devallowed && S_ISSPECIAL(fid->st.st_mode)){ seterror(tx, Especial); return; } if(useropen(fid, rx->mode, &e) < 0){ seterror(tx, e); return; } tx->iounit = 0; tx->qid = stat2qid(&fid->st);}voidrcreate(Fcall *rx, Fcall *tx){ char *e; Fid *fid; if((fid = oldfid(rx->fid, &e)) == nil){ seterror(tx, e); return; } if(fid->omode != -1){ seterror(tx, Ebadusefid); return; } if(fidstat(fid, &e) < 0){ seterror(tx, e); return; } if(!S_ISDIR(fid->st.st_mode)){ seterror(tx, Enotdir); return; } if(usercreate(fid, rx->name, rx->mode, rx->perm, &e) < 0){ seterror(tx, e); return; } if(fidstat(fid, &e) < 0){ seterror(tx, e); return; } tx->iounit = 0; tx->qid = stat2qid(&fid->st);}ucharmodebyte(struct stat *st){ uchar b; b = 0; if(S_ISDIR(st->st_mode))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -