📄 u9fs.c
字号:
b |= QTDIR; /* no way to test append-only */ /* no real way to test exclusive use, but mark devices as such */ if(S_ISSPECIAL(st->st_mode)) b |= QTEXCL; return b;}ulongplan9mode(struct stat *st){ return ((ulong)modebyte(st)<<24) | (st->st_mode & 0777);}/* * this is for chmod, so don't worry about S_IFDIR */mode_tunixmode(Dir *d){ return (mode_t)(d->mode&0777);}Qidstat2qid(struct stat *st){ uchar *p, *ep, *q; Qid qid; /* * For now, ignore the device number. */ qid.path = 0; p = (uchar*)&qid.path; ep = p+sizeof(qid.path); q = p+sizeof(ino_t); if(q > ep){ fprint(2, "warning: inode number too big\n"); q = ep; } memmove(p, &st->st_ino, q-p); q = q+sizeof(dev_t); if(q > ep){/* fprint(2, "warning: inode number + device number too big %d+%d\n", sizeof(ino_t), sizeof(dev_t)); */ q = ep - sizeof(dev_t); if(q < p) fprint(2, "warning: device number too big by itself\n"); else *(dev_t*)q ^= st->st_dev; } qid.vers = st->st_mtime ^ (st->st_size << 8); qid.type = modebyte(st); return qid;}voidstat2dir(char *path, struct stat *st, Dir *d){ User *u; char *q; memset(d, 0, sizeof(*d)); d->qid = stat2qid(st); d->mode = plan9mode(st); d->atime = st->st_atime; d->mtime = st->st_mtime; d->length = st->st_size; d->uid = (u = uid2user(st->st_uid)) ? u->name : "???"; d->gid = (u = gid2user(st->st_gid)) ? u->name : "???"; d->muid = ""; if((q = strrchr(path, '/')) != nil) d->name = q+1; else d->name = path;}voidrread(Fcall *rx, Fcall *tx){ char *e, *path; uchar *p, *ep; int n; Fid *fid; Dir d; struct stat st; if(rx->count > msize-IOHDRSZ){ seterror(tx, Etoolarge); return; } if((fid = oldfidex(rx->fid, -1, &e)) == nil){ seterror(tx, e); return; } if (fid->auth) { char *e; e = auth->read(rx, tx); if (e) seterror(tx, e); return; } if(fid->omode == -1 || (fid->omode&3) == OWRITE){ seterror(tx, Ebadusefid); return; } if(fid->dir){ if(rx->offset != fid->diroffset){ if(rx->offset != 0){ seterror(tx, Ebadoffset); return; } rewinddir(fid->dir); fid->diroffset = 0; } p = (uchar*)tx->data; ep = (uchar*)tx->data+rx->count; for(;;){ if(p+BIT16SZ >= ep) break; if(fid->dirent == nil) /* one entry cache for when convD2M fails */ if((fid->dirent = readdir(fid->dir)) == nil) break; if(strcmp(fid->dirent->d_name, ".") == 0 || strcmp(fid->dirent->d_name, "..") == 0){ fid->dirent = nil; continue; } path = estrpath(fid->path, fid->dirent->d_name); memset(&st, 0, sizeof st); if(stat(path, &st) < 0){ fprint(2, "dirread: stat(%s) failed: %s\n", path, strerror(errno)); fid->dirent = nil; free(path); continue; } free(path); stat2dir(fid->dirent->d_name, &st, &d); if((n=(old9p ? convD2Mold : convD2M)(&d, p, ep-p)) <= BIT16SZ) break; p += n; fid->dirent = nil; } tx->count = p - (uchar*)tx->data; fid->diroffset += tx->count; }else{ if((n = pread(fid->fd, tx->data, rx->count, rx->offset)) < 0){ seterror(tx, strerror(errno)); return; } tx->count = n; }}voidrwrite(Fcall *rx, Fcall *tx){ char *e; Fid *fid; int n; if(rx->count > msize-IOHDRSZ){ seterror(tx, Etoolarge); return; } if((fid = oldfidex(rx->fid, -1, &e)) == nil){ seterror(tx, e); return; } if (fid->auth) { char *e; e = auth->write(rx, tx); if (e) seterror(tx, e); return; } if(fid->omode == -1 || (fid->omode&3) == OREAD || (fid->omode&3) == OEXEC){ seterror(tx, Ebadusefid); return; } if((n = pwrite(fid->fd, rx->data, rx->count, rx->offset)) < 0){ seterror(tx, strerror(errno)); return; } tx->count = n;}voidrclunk(Fcall *rx, Fcall *tx){ char *e; Fid *fid; if((fid = oldfidex(rx->fid, -1, &e)) == nil){ seterror(tx, e); return; } if (fid->auth) { if (auth->clunk) { e = (*auth->clunk)(rx, tx); if (e) { seterror(tx, e); return; } } } else if(fid->omode != -1 && fid->omode&ORCLOSE) remove(fid->path); freefid(fid);}voidrremove(Fcall *rx, Fcall *tx){ char *e; Fid *fid; if((fid = oldfid(rx->fid, &e)) == nil){ seterror(tx, e); return; } if(userremove(fid, &e) < 0) seterror(tx, e); freefid(fid);}voidrstat(Fcall *rx, Fcall *tx){ char *e; Fid *fid; Dir d; if((fid = oldfid(rx->fid, &e)) == nil){ seterror(tx, e); return; } if(fidstat(fid, &e) < 0){ seterror(tx, e); return; } stat2dir(fid->path, &fid->st, &d); if((tx->nstat=(old9p ? convD2Mold : convD2M)(&d, tx->stat, msize)) <= BIT16SZ) seterror(tx, "convD2M fails");}voidrwstat(Fcall *rx, Fcall *tx){ char *e; char *p, *old, *new, *dir; gid_t gid; Dir d; Fid *fid; if((fid = oldfid(rx->fid, &e)) == nil){ seterror(tx, e); return; } /* * wstat is supposed to be atomic. * we check all the things we can before trying anything. * still, if we are told to truncate a file and rename it and only * one works, we're screwed. in such cases we leave things * half broken and return an error. it's hardly perfect. */ if((old9p ? convM2Dold : convM2D)(rx->stat, rx->nstat, &d, (char*)rx->stat) <= BIT16SZ){ seterror(tx, Ewstatbuffer); return; } if(fidstat(fid, &e) < 0){ seterror(tx, e); return; } /* * The casting is necessary because d.mode is ulong and might, * on some systems, be 64 bits. We only want to compare the * bottom 32 bits, since that's all that gets sent in the protocol. * * Same situation for d.mtime and d.length (although that last check * is admittedly superfluous, given the current lack of 128-bit machines). */ gid = (gid_t)-1; if(d.gid[0] != '\0'){ User *g; g = gname2user(d.gid); if(g == nil){ seterror(tx, Eunknowngroup); return; } gid = (gid_t)g->id; if(groupchange(fid->u, gid2user(gid), &e) < 0){ seterror(tx, e); return; } } if((u32int)d.mode != (u32int)~0 && (((d.mode&DMDIR)!=0) ^ (S_ISDIR(fid->st.st_mode)!=0))){ seterror(tx, Edirchange); return; } if(strcmp(fid->path, "/") == 0){ seterror(tx, "no wstat of root"); return; } /* * try things in increasing order of harm to the file. * mtime should come after truncate so that if you * do both the mtime actually takes effect, but i'd rather * leave truncate until last. * (see above comment about atomicity). */ if((u32int)d.mode != (u32int)~0 && chmod(fid->path, unixmode(&d)) < 0){ if(chatty9p) fprint(2, "chmod(%s, 0%luo) failed\n", fid->path, unixmode(&d)); seterror(tx, strerror(errno)); return; } if((u32int)d.mtime != (u32int)~0){ struct utimbuf t; t.actime = 0; t.modtime = d.mtime; if(utime(fid->path, &t) < 0){ if(chatty9p) fprint(2, "utime(%s) failed\n", fid->path); seterror(tx, strerror(errno)); return; } } if(gid != (gid_t)-1 && gid != fid->st.st_gid){ if(chown(fid->path, (uid_t)-1, gid) < 0){ if(chatty9p) fprint(2, "chgrp(%s, %d) failed\n", fid->path, gid); seterror(tx, strerror(errno)); return; } } if(d.name[0]){ old = fid->path; dir = estrdup(fid->path); if((p = strrchr(dir, '/')) > dir) *p = '\0'; else{ seterror(tx, "whoops: can't happen in u9fs"); return; } new = estrpath(dir, d.name); if(strcmp(old, new) != 0 && rename(old, new) < 0){ if(chatty9p) fprint(2, "rename(%s, %s) failed\n", old, new); seterror(tx, strerror(errno)); free(new); free(dir); return; } fid->path = new; free(old); free(dir); } if((u64int)d.length != (u64int)~0 && truncate(fid->path, d.length) < 0){ fprint(2, "truncate(%s, %lld) failed\n", fid->path, d.length); seterror(tx, strerror(errno)); return; }}/* * we keep a table by numeric id. by name lookups happen infrequently * while by-number lookups happen once for every directory entry read * and every stat request. */User *utab[64];User *gtab[64];User*adduser(struct passwd *p){ User *u; u = emalloc(sizeof(*u)); u->id = p->pw_uid; u->name = estrdup(p->pw_name); u->next = utab[p->pw_uid%nelem(utab)]; u->defaultgid = p->pw_gid; utab[p->pw_uid%nelem(utab)] = u; return u;}intuseringroup(User *u, User *g){ int i; for(i=0; i<g->nmem; i++) if(strcmp(g->mem[i], u->name) == 0) return 1; /* * Hack around common Unix problem that everyone has * default group "user" but /etc/group lists no members. */ if(u->defaultgid == g->id) return 1; return 0;}User*addgroup(struct group *g){ User *u; char **p; int n; u = emalloc(sizeof(*u)); n = 0; for(p=g->gr_mem; *p; p++) n++; u->mem = emalloc(sizeof(u->mem[0])*n); n = 0; for(p=g->gr_mem; *p; p++) u->mem[n++] = estrdup(*p); u->nmem = n; u->id = g->gr_gid; u->name = estrdup(g->gr_name); u->next = gtab[g->gr_gid%nelem(gtab)]; gtab[g->gr_gid%nelem(gtab)] = u; return u;}User*uname2user(char *name){ int i; User *u; struct passwd *p; for(i=0; i<nelem(utab); i++) for(u=utab[i]; u; u=u->next) if(strcmp(u->name, name) == 0) return u; if((p = getpwnam(name)) == nil) return nil; return adduser(p);}User*uid2user(int id){ User *u; struct passwd *p; for(u=utab[id%nelem(utab)]; u; u=u->next) if(u->id == id) return u; if((p = getpwuid(id)) == nil) return nil; return adduser(p);}User*gname2user(char *name){ int i; User *u; struct group *g; for(i=0; i<nelem(gtab); i++) for(u=gtab[i]; u; u=u->next) if(strcmp(u->name, name) == 0) return u; if((g = getgrnam(name)) == nil) return nil; return addgroup(g);}User*gid2user(int id){ User *u; struct group *g; for(u=gtab[id%nelem(gtab)]; u; u=u->next) if(u->id == id) return u; if((g = getgrgid(id)) == nil) return nil; return addgroup(g);}voidsysfatal(char *fmt, ...){ char buf[1024]; va_list va, temp; va_start(va, fmt); va_copy(temp, va); doprint(buf, buf+sizeof buf, fmt, &temp); va_end(temp); va_end(va); fprint(2, "u9fs: %s\n", buf); fprint(2, "last unix error: %s\n", strerror(errno)); exit(1);}void*emalloc(size_t n){ void *p; if(n == 0) n = 1; p = malloc(n); if(p == 0) sysfatal("malloc(%ld) fails", (long)n); memset(p, 0, n); return p;}void*erealloc(void *p, size_t n){ if(p == 0) p = malloc(n); else p = realloc(p, n); if(p == 0) sysfatal("realloc(..., %ld) fails", (long)n); return p;}char*estrdup(char *p){ p = strdup(p); if(p == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -