long qidpathgen(Device *dev) { Iobuf *p; Superb *sb; long path; p = getbuf(*dev, superaddr((*dev)), Bread|Bmod); if(!p || checktag(p, Tsuper, QPSUPER)) panic("newqid: super block"); sb = (Superb*)p->iobuf; sb->qidgen++; path = sb->qidgen; putbuf(p); return path; }
/* zero bytes past new file length; return an error code */ int trunczero(Truncstate *ts) { int blkoff = ts->newsize % BUFSIZE; Iobuf *pd; pd = dnodebuf(ts->p, ts->d, ts->lastblk, Tfile, ts->uid); if (pd == nil || checktag(pd, Tfile, QPNONE)) { if (pd != nil) putbuf(pd); ts->err = Ephase; return Ephase; } memset(pd->iobuf+blkoff, 0, BUFSIZE - blkoff); putbuf(pd); return 0; }
Qid newqid(Device dev) { Iobuf *p; Superb *sb; Qid qid; p = getbuf(dev, superaddr(dev), Bread|Bmod); if(!p || checktag(p, Tsuper, QPSUPER)) panic("newqid: super block"); sb = (Superb*)p->iobuf; sb->qidgen++; qid.path = sb->qidgen; qid.vers = 0; qid.type = 0; putbuf(p); return qid; }
void bfree(Device dev, long addr, int d) { Iobuf *p; long a; int i; if(!addr) return; if(d > 0) { d--; p = getbuf(dev, addr, Bread); if(p) { for(i=INDPERBUF-1; i>=0; i--) { a = ((long*)p->iobuf)[i]; bfree(dev, a, d); } putbuf(p); } } /* * stop outstanding i/o */ p = getbuf(dev, addr, Bprobe); if(p) { p->flags &= ~(Bmod|Bimm); putbuf(p); } /* * dont put written worm * blocks into free list */ if(nofree(dev, addr)) return; p = getbuf(dev, superaddr(dev), Bread|Bmod); if(!p || checktag(p, Tsuper, QPSUPER)) panic("bfree: super block"); addfree(dev, addr, (Superb*)p->iobuf); putbuf(p); }
void f_stat(Chan *cp, Oldfcall *in, Oldfcall *ou) { Iobuf *p; Dentry *d; File *f; if(CHAT(cp)) { print("c_stat %d\n", cp->chan); print(" fid = %d\n", in->fid); } p = 0; memset(ou->stat, 0, sizeof(ou->stat)); f = filep(cp, in->fid, 0); if(!f) { ou->err = Efid; goto out; } p = getbuf(f->fs->dev, f->addr, Bread); d = getdir(p, f->slot); if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) { ou->err = Ealloc; goto out; } if(ou->err = mkqidcmp(&f->qid, d)) goto out; if(d->qid.path == QPROOT) /* stat of root gives time */ d->atime = time(0); if(convD2M9p1(d, ou->stat) != DIRREC) print("stat convD2M\n"); out: if(p) putbuf(p); if(f) qunlock(f); ou->fid = in->fid; }
void f_attach(Chan *cp, Oldfcall *in, Oldfcall *ou) { Iobuf *p; Dentry *d; File *f; int u; Filsys *fs; int32_t raddr; if(CHAT(cp)) { print("c_attach %d\n", cp->chan); print(" fid = %d\n", in->fid); print(" uid = %s\n", in->uname); print(" arg = %s\n", in->aname); } ou->qid = QID9P1(0,0); ou->fid = in->fid; if(!in->aname[0]) /* default */ strncpy(in->aname, filesys[0].name, sizeof(in->aname)); p = 0; f = filep(cp, in->fid, 1); if(!f) { ou->err = Efid; goto out; } u = -1; if(cp != cons.chan){ if(authorize(cp, in, ou) == 0 || strcmp(in->uname, "adm") == 0){ ou->err = Eauth; goto out; } u = strtouid(in->uname); if(u < 0){ ou->err = Ebadu; goto out; } } fs = fsstr(in->aname); if(fs == 0) { ou->err = Ebadspc; goto out; } raddr = getraddr(fs->dev); p = getbuf(fs->dev, raddr, Bread); d = getdir(p, 0); if(!d || checktag(p, Tdir, QPROOT) || !(d->mode & DALLOC)) { ou->err = Ealloc; goto out; } f->uid = u; if(iaccess(f, d, DREAD)) { ou->err = Eaccess; goto out; } accessdir(p, d, FREAD); mkqid(&f->qid, d, 1); f->fs = fs; f->addr = raddr; f->slot = 0; f->open = 0; freewp(f->wpath); f->wpath = 0; mkqid9p1(&ou->qid, &f->qid); out: if(p) putbuf(p); if(f) { qunlock(f); if(ou->err) freefp(f); } }
void sysinit(void) { int error; char *cp, *ep; Device *d; Filsys *fs; Fspar *fsp; Iobuf *p; cons.chan = fs_chaninit(Devcon, 1, 0); start: /* * part 1 -- read the config file */ devnone = iconfig("n"); cp = nvrgetconfig(); print("config %s\n", cp); confdev = d = iconfig(cp); devinit(d); if(f.newconf) { p = getbuf(d, 0, Bmod); memset(p->iobuf, 0, RBUFSIZE); settag(p, Tconfig, 0); } else p = getbuf(d, 0, Brd|Bmod); if(!p || checktag(p, Tconfig, 0)) panic("config io"); mergeconf(p); if (resetparams) { for (fsp = fspar; fsp->name != nil; fsp++) fsp->declared = 0; resetparams = 0; } for (fsp = fspar; fsp->name != nil; fsp++) { /* supply defaults from this cwfs instance */ if (fsp->declared == 0) { fsp->declared = fsp->actual; f.modconf = 1; } /* warn if declared value is not our compiled-in value */ if (fsp->declared != fsp->actual) print("warning: config %s %ld != compiled-in %ld\n", fsp->name, fsp->declared, fsp->actual); } if(f.modconf) { memset(p->iobuf, 0, BUFSIZE); p->flags |= Bmod|Bimm; cp = p->iobuf; ep = p->iobuf + RBUFSIZE - 1; if(service[0]) cp = seprint(cp, ep, "service %s\n", service); for(fs=filsys; fs->name; fs++) if(fs->conf && fs->conf[0] != '\0') cp = seprint(cp, ep, "filsys %s %s\n", fs->name, fs->conf); for (fsp = fspar; fsp->name != nil; fsp++) cp = seprint(cp, ep, "%s %ld\n", fsp->name, fsp->declared); putbuf(p); f.modconf = f.newconf = 0; print("config block written\n"); goto start; } putbuf(p); print("service %s\n", service); loop: /* * part 2 -- squeeze out the deleted filesystems */ for(fs=filsys; fs->name; fs++) if(fs->conf == nil || fs->conf[0] == '\0') { for(; fs->name; fs++) *fs = *(fs+1); goto loop; } if(filsys[0].name == nil) panic("no filsys"); /* * part 3 -- compile the device expression */ error = 0; for(fs=filsys; fs->name; fs++) { print("filsys %s %s\n", fs->name, fs->conf); fs->dev = iconfig(fs->conf); if(f.error) { error = 1; continue; } } if(error) panic("fs config"); /* * part 4 -- initialize the devices */ for(fs=filsys; fs->name; fs++) { delay(3000); print("sysinit: %s\n", fs->name); if(fs->flags & FREAM) devream(fs->dev, 1); if(fs->flags & FRECOVER) devrecover(fs->dev); devinit(fs->dev); } /* * part 5 -- optionally copy devices or worms */ if (copyworm) { dowormcopy(); /* can return if user quits early */ panic("copyworm bailed out!"); } if (copydev) if (dodevcopy() < 0) panic("copydev failed!"); else panic("copydev done."); }
static int ffi_anim_len(lua_State *L) { struct anim *anim = checktag(L, 1, TAG_ANIM); lua_pushnumber(L, anim->frames - 1); return 1; }
int parseConfig(int argc, char *argv[], int *port_divert, unsigned int *roEnable, struct sockaddr_in *bAddr, struct in_addr *coa, MNLLIST *mn_ip_list, LLIST *all_if_list, LLIST *inner_if_list) { FILE *fp; int confFile = 0; long fpos = 0; int tagmask = 0; char tag[30]; char token[30]; /* if((!strcmp(argv[1], "-f")) && (argc == 5)){ confFile = 1; }else if(!strcmp(argv[1], "-ha")){ *isha = 1; confFile = 0; }else if(!strcmp(argv[1], "-fa")){ *isfa = 1; confFile = 0; }else{ printCmdUsage(); exit(1); } */ if(argc == 2){ confFile = 1; }else{ printCmdUsage(); exit(1); } if(confFile){ if((fp = fopen(argv[1], "r")) == NULL){ fprintf(stderr, "[X] Open agent config file fail.\n"); exit(1); } tagmask = gentagmask(); /* enable RO or not coresponding to the cmdline parameter. */ /* if(!strcmp(argv[3], "RO")){ tagmask ^= T_RO; *roEnable = 1; }else if(!strcmp(argv[3], "NORO")){ tagmask ^= T_RO; *roEnable = 0; } */ /* set the port for divert socket. */ /* *port_divert = atoi(argv[4]); */ #ifdef DEBUG_PARSECONF printf("tagmask: %d\n", tagmask); #endif while(fscanf(fp, "%s", tag) != EOF){ #ifdef DEBUG_PARSECONF printf("tag: %s ", tag); #endif switch (checktag(tag, &tagmask)){ case T_RO: fpos = ftell(fp); while(fscanf(fp, "%s", token) != EOF){ #ifdef DEBUG_PARSECONF printf("token: %s, ", token); #endif if(isTag(token)){ fseek(fp, fpos, SEEK_SET); break; } fpos = ftell(fp); #ifdef DEBUG_PARSECONF printf("RO: %s.\n", token); #endif if(!strcmp(token, "DISABLE")){ *roEnable = 0; }else if(!strcmp(token, "ENABLE")){ *roEnable = 1; } } break; case T_ALLIP: fpos = ftell(fp); while(fscanf(fp, "%s", token) != EOF){ #ifdef DEBUG_PARSECONF printf("token: %s, ", token); #endif if(isTag(token)){ fseek(fp, fpos, SEEK_SET); break; } fpos = ftell(fp); #ifdef DEBUG_PARSECONF printf("add %s to all_if_list.\n", token); #endif addEntry(all_if_list, token); } break; case T_INNERIP: fpos = ftell(fp); while(fscanf(fp, "%s", token) != EOF){ if(isTag(token)){ fseek(fp, fpos, SEEK_SET); break; } fpos = ftell(fp); #ifdef DEBUG_PARSECONF printf("add %s to inner_if_list.\n", token); #endif addEntry(inner_if_list, token); } break; case T_DPORT: fpos = ftell(fp); while(fscanf(fp, "%s", token) != EOF){ if(isTag(token)){ fseek(fp, fpos, SEEK_SET); break; } fpos = ftell(fp); #ifdef DEBUG_PARSECONF printf("DIVERT_PORT: %s.\n", token); #endif *port_divert = atoi(token); } break; case T_COA: fpos = ftell(fp); while(fscanf(fp, "%s", token) != EOF){ if(isTag(token)){ fseek(fp, fpos, SEEK_SET); break; } fpos = ftell(fp); #ifdef DEBUG_PARSECONF printf("set %s to care of addr.\n", token); #endif coa->s_addr = inet_addr(token); } break; /* case T_BCAST: fpos = ftell(fp); while(fscanf(fp, "%s", token) != EOF){ if(isTag(token)){ fseek(fp, fpos, SEEK_SET); break; } fpos = ftell(fp); #ifdef DEBUG_PARSECONF printf("set %s to broadcast addr.\n", token); #endif bAddr->sin_addr.s_addr = inet_addr(token); } break; */ case T_MN: fpos = ftell(fp); while(fscanf(fp, "%s", token) != EOF){ if(isTag(token)){ fseek(fp, fpos, SEEK_SET); break; } fpos = ftell(fp); #ifdef DEBUG_PARSECONF printf("add %s to mn_ip_list.\n", token); #endif addMNEntry(mn_ip_list, token, "", NA); } break; case T_ERR: printf("T_ERR--"); printConfFileUsage(); exit(1); } } /* check whether all necessary field is equipped. */ if(tagmask != 0){ printf("tagmask = %d != 0\n", tagmask); printConfFileUsage(); exit(1); } if(fclose(fp) == EOF){ fprintf(stderr, "[X] Close agent config file fail.\n"); /* Though fail to close, but we continue to execute. */ } }else{ } return 0; }
Off bufalloc(Device *dev, int tag, int32_t qid, int uid) { Iobuf *bp, *p; Superb *sb; Off a, n; p = getbuf(dev, superaddr(dev), Brd|Bmod); if(!p || checktag(p, Tsuper, QPSUPER)) { print("bufalloc: super block\n"); if(p) putbuf(p); return 0; } sb = (Superb*)p->iobuf; loop: n = --sb->fbuf.nfree; sb->tfree--; if(n < 0 || n >= FEPERBUF) { print("bufalloc: %Z: bad freelist\n", dev); n = 0; sb->fbuf.free[0] = 0; } a = sb->fbuf.free[n]; if(n <= 0) { if(a == 0) { sb->tfree = 0; sb->fbuf.nfree = 1; if(dev->type == Devcw) { n = uid; if(n < 0 || n >= nelem(growacct)) n = 0; growacct[n]++; if(cwgrow(dev, sb, uid)) goto loop; } putbuf(p); print("fs %Z full uid=%d\n", dev, uid); return 0; } bp = getbuf(dev, a, Brd); if(!bp || checktag(bp, Tfree, QPNONE)) { if(bp) putbuf(bp); putbuf(p); return 0; } sb->fbuf = *(Fbuf*)bp->iobuf; putbuf(bp); } bp = getbuf(dev, a, Bmod); memset(bp->iobuf, 0, RBUFSIZE); settag(bp, tag, qid); if(tag == Tind1 || tag == Tind2 || #ifndef COMPAT32 tag == Tind3 || tag == Tind4 || /* add more Tind tags here ... */ #endif tag == Tdir) bp->flags |= Bimm; putbuf(bp); putbuf(p); return a; }
int doremove(File *f, int iscon) { Iobuf *p, *p1; Dentry *d, *d1; int32_t addr; int slot, err; p = 0; p1 = 0; if(isro(f->fs->dev) || (f->cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) { err = Eronly; goto out; } /* * check on parent directory of file to be deleted */ if(f->wpath == 0 || f->wpath->addr == f->addr) { err = Ephase; goto out; } p1 = getbuf(f->fs->dev, f->wpath->addr, Bread); d1 = getdir(p1, f->wpath->slot); if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) { err = Ephase; goto out; } if(!iscon && iaccess(f, d1, DWRITE)) { err = Eaccess; goto out; } accessdir(p1, d1, FWRITE); putbuf(p1); p1 = 0; /* * check on file to be deleted */ p = getbuf(f->fs->dev, f->addr, Bread); d = getdir(p, f->slot); if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) { err = Ealloc; goto out; } if(err = mkqidcmp(&f->qid, d)) goto out; /* * if deleting a directory, make sure it is empty */ if((d->mode & DDIR)) for(addr=0;; addr++) { p1 = dnodebuf(p, d, addr, 0); if(!p1) break; if(checktag(p1, Tdir, d->qid.path)) { err = Ephase; goto out; } for(slot=0; slot<DIRPERBUF; slot++) { d1 = getdir(p1, slot); if(!(d1->mode & DALLOC)) continue; err = Eempty; goto out; } putbuf(p1); } /* * do it */ dtrunc(p, d); memset(d, 0, sizeof(Dentry)); settag(p, Tdir, QPNONE); out: if(p1) putbuf(p1); if(p) putbuf(p); return err; }
void f_write(Chan *cp, Oldfcall *in, Oldfcall *ou) { Iobuf *p, *p1; Dentry *d; File *f; Tlock *t; int32_t offset, addr, tim; int count, nwrite, o, n; if(CHAT(cp)) { print("c_write %d\n", cp->chan); print(" fid = %d\n", in->fid); print(" offset = %ld\n", in->offset); print(" count = %ld\n", in->count); } offset = in->offset; count = in->count; nwrite = 0; p = 0; f = filep(cp, in->fid, 0); if(!f) { ou->err = Efid; goto out; } if(!(f->open & FWRITE)) { ou->err = Eopen; goto out; } if(isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) { ou->err = Eronly; goto out; } if(count < 0 || count > MAXDAT) { ou->err = Ecount; goto out; } if(offset < 0) { ou->err = Eoffset; goto out; } p = getbuf(f->fs->dev, f->addr, Bread|Bmod); d = getdir(p, f->slot); if(!d || !(d->mode & DALLOC)) { ou->err = Ealloc; goto out; } if(ou->err = mkqidcmp(&f->qid, d)) goto out; if(t = f->tlock) { tim = time(0); if(t->time < tim || t->file != f) { ou->err = Ebroken; goto out; } /* renew the lock */ t->time = tim + TLOCK; } accessdir(p, d, FWRITE); if(d->mode & DAPND) offset = d->size; if(offset+count > d->size) d->size = offset+count; while(count > 0) { addr = offset / BUFSIZE; o = offset % BUFSIZE; n = BUFSIZE - o; if(n > count) n = count; p1 = dnodebuf(p, d, addr, Tfile); if(p1 == 0) { ou->err = Efull; goto out; } if(checktag(p1, Tfile, d->qid.path)) { putbuf(p1); ou->err = Ephase; goto out; } memmove(p1->iobuf+o, in->data+nwrite, n); p1->flags |= Bmod; putbuf(p1); count -= n; nwrite += n; offset += n; } if(CHAT(cp)) print(" nwrite = %d\n", nwrite); out: if(p) putbuf(p); if(f) qunlock(f); ou->fid = in->fid; ou->count = nwrite; }
void f_read(Chan *cp, Oldfcall *in, Oldfcall *ou) { Iobuf *p, *p1; File *f; Dentry *d, *d1; Tlock *t; int32_t addr, offset, tim; int nread, count, n, o, slot; if(CHAT(cp)) { print("c_read %d\n", cp->chan); print(" fid = %d\n", in->fid); print(" offset = %ld\n", in->offset); print(" count = %ld\n", in->count); } p = 0; count = in->count; offset = in->offset; nread = 0; f = filep(cp, in->fid, 0); if(!f) { ou->err = Efid; goto out; } if(!(f->open & FREAD)) { ou->err = Eopen; goto out; } if(count < 0 || count > MAXDAT) { ou->err = Ecount; goto out; } if(offset < 0) { ou->err = Eoffset; goto out; } p = getbuf(f->fs->dev, f->addr, Bread); d = getdir(p, f->slot); if(!d || !(d->mode & DALLOC)) { ou->err = Ealloc; goto out; } if(ou->err = mkqidcmp(&f->qid, d)) goto out; if(t = f->tlock) { tim = time(0); if(t->time < tim || t->file != f) { ou->err = Ebroken; goto out; } /* renew the lock */ t->time = tim + TLOCK; } accessdir(p, d, FREAD); if(d->mode & DDIR) { addr = 0; goto dread; } if(offset+count > d->size) count = d->size - offset; while(count > 0) { addr = offset / BUFSIZE; if(addr == f->lastra+1) dbufread(p, d, addr+1); f->lastra = addr; o = offset % BUFSIZE; n = BUFSIZE - o; if(n > count) n = count; p1 = dnodebuf(p, d, addr, 0); if(p1) { if(checktag(p1, Tfile, QPNONE)) { ou->err = Ephase; putbuf(p1); goto out; } memmove(ou->data+nread, p1->iobuf+o, n); putbuf(p1); } else memset(ou->data+nread, 0, n); count -= n; nread += n; offset += n; } goto out; dread: p1 = dnodebuf(p, d, addr, 0); if(!p1) goto out; if(checktag(p1, Tdir, QPNONE)) { ou->err = Ephase; putbuf(p1); goto out; } n = DIRREC; for(slot=0; slot<DIRPERBUF; slot++) { d1 = getdir(p1, slot); if(!(d1->mode & DALLOC)) continue; if(offset >= n) { offset -= n; continue; } if(count < n) { putbuf(p1); goto out; } if(convD2M9p1(d1, ou->data+nread) != n) print("dirread convD2M\n"); nread += n; count -= n; } putbuf(p1); addr++; goto dread; out: count = in->count - nread; if(count > 0) memset(ou->data+nread, 0, count); if(p) putbuf(p); if(f) qunlock(f); ou->fid = in->fid; ou->count = nread; if(CHAT(cp)) print(" nread = %d\n", nread); }
void f_create(Chan *cp, Oldfcall *in, Oldfcall *ou) { Iobuf *p, *p1; Dentry *d, *d1; File *f; int slot, slot1, fmod; int32_t addr, addr1, path; Qid qid; Tlock *t; Wpath *w; if(CHAT(cp)) { print("c_create %d\n", cp->chan); print(" fid = %d\n", in->fid); print(" name = %s\n", in->name); print(" perm = %lx+%lo\n", (in->perm>>28)&0xf, in->perm&0777); print(" mode = %d\n", in->mode); } p = 0; f = filep(cp, in->fid, 0); if(!f) { ou->err = Efid; goto out; } if(isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) { ou->err = Eronly; goto out; } p = getbuf(f->fs->dev, f->addr, Bread); d = getdir(p, f->slot); if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) { ou->err = Ealloc; goto out; } if(ou->err = mkqidcmp(&f->qid, d)) goto out; if(!(d->mode & DDIR)) { ou->err = Edir2; goto out; } if(cp != cons.chan && iaccess(f, d, DWRITE) && !writeallow) { ou->err = Eaccess; goto out; } accessdir(p, d, FREAD); if(!strncmp(in->name, ".", sizeof(in->name)) || !strncmp(in->name, "..", sizeof(in->name))) { ou->err = Edot; goto out; } if(checkname(in->name)) { ou->err = Ename; goto out; } addr1 = 0; slot1 = 0; /* set */ for(addr=0;; addr++) { p1 = dnodebuf(p, d, addr, 0); if(!p1) { if(addr1) break; p1 = dnodebuf(p, d, addr, Tdir); } if(p1 == 0) { ou->err = Efull; goto out; } if(checktag(p1, Tdir, d->qid.path)) { putbuf(p1); goto phase; } for(slot=0; slot<DIRPERBUF; slot++) { d1 = getdir(p1, slot); if(!(d1->mode & DALLOC)) { if(!addr1) { addr1 = p1->addr; slot1 = slot + addr*DIRPERBUF; } continue; } if(!strncmp(in->name, d1->name, sizeof(in->name))) { putbuf(p1); ou->err = Eexist; goto out; } } putbuf(p1); } switch(in->mode & 7) { case MEXEC: case MREAD: /* seems only useful to make directories */ fmod = FREAD; break; case MWRITE: fmod = FWRITE; break; case MBOTH: fmod = FREAD+FWRITE; break; default: ou->err = Emode; goto out; } if(in->perm & PDIR) if((in->mode & MTRUNC) || (in->perm & PAPND) || (fmod & FWRITE)) goto badaccess; /* * do it */ path = qidpathgen(&f->fs->dev); p1 = getbuf(f->fs->dev, addr1, Bread|Bimm|Bmod); d1 = getdir(p1, slot1); if(!d1 || checktag(p1, Tdir, d->qid.path)) { if(p1) putbuf(p1); goto phase; } if(d1->mode & DALLOC) { putbuf(p1); goto phase; } strncpy(d1->name, in->name, sizeof(in->name)); /* * bogus argument passing -- see console.c */ if(cp == cons.chan) { d1->uid = cons.uid; d1->gid = cons.gid; } else { d1->uid = f->uid; d1->gid = d->gid; in->perm &= d->mode | ~0666; if(in->perm & PDIR) in->perm &= d->mode | ~0777; } d1->qid.path = path; d1->qid.version = 0; d1->mode = DALLOC | (in->perm & 0777); if(in->perm & PDIR) { d1->mode |= DDIR; d1->qid.path |= QPDIR; } if(in->perm & PAPND) d1->mode |= DAPND; t = 0; if(in->perm & PLOCK) { d1->mode |= DLOCK; t = tlocked(p1, d1); } accessdir(p1, d1, FWRITE); mkqid(&qid, d1, 0); putbuf(p1); accessdir(p, d, FWRITE); /* * do a walk to new directory entry */ w = newwp(); if(!w) { ou->err = Ewalk; goto out; } w->addr = f->addr; w->slot = f->slot; w->up = f->wpath; f->wpath = w; f->qid = qid; f->tlock = t; f->lastra = 0; if(in->mode & MRCLOSE) fmod |= FREMOV; f->open = fmod; f->addr = addr1; f->slot = slot1; if(t) t->file = f; mkqid9p1(&ou->qid, &qid); goto out; badaccess: ou->err = Eaccess; goto out; phase: ou->err = Ephase; out: if(p) putbuf(p); if(f) qunlock(f); ou->fid = in->fid; }
void f_open(Chan *cp, Oldfcall *in, Oldfcall *ou) { Iobuf *p; Dentry *d; File *f; Tlock *t; Qid qid; int ro, fmod; if(CHAT(cp)) { print("c_open %d\n", cp->chan); print(" fid = %d\n", in->fid); print(" mode = %o\n", in->mode); } p = 0; f = filep(cp, in->fid, 0); if(!f) { ou->err = Efid; goto out; } /* * if remove on close, check access here */ ro = isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup)); if(in->mode & MRCLOSE) { if(ro) { ou->err = Eronly; goto out; } /* * check on parent directory of file to be deleted */ if(f->wpath == 0 || f->wpath->addr == f->addr) { ou->err = Ephase; goto out; } p = getbuf(f->fs->dev, f->wpath->addr, Bread); d = getdir(p, f->wpath->slot); if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) { ou->err = Ephase; goto out; } if(iaccess(f, d, DWRITE)) { ou->err = Eaccess; goto out; } putbuf(p); } p = getbuf(f->fs->dev, f->addr, Bread); d = getdir(p, f->slot); if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) { ou->err = Ealloc; goto out; } if(ou->err = mkqidcmp(&f->qid, d)) goto out; mkqid(&qid, d, 1); switch(in->mode & 7) { case MREAD: if(iaccess(f, d, DREAD) && !writeallow) goto badaccess; fmod = FREAD; break; case MWRITE: if((d->mode & DDIR) || (iaccess(f, d, DWRITE) && !writeallow)) goto badaccess; if(ro) { ou->err = Eronly; goto out; } fmod = FWRITE; break; case MBOTH: if((d->mode & DDIR) || (iaccess(f, d, DREAD) && !writeallow) || (iaccess(f, d, DWRITE) && !writeallow)) goto badaccess; if(ro) { ou->err = Eronly; goto out; } fmod = FREAD+FWRITE; break; case MEXEC: if((d->mode & DDIR) || iaccess(f, d, DEXEC)) goto badaccess; fmod = FREAD; break; default: ou->err = Emode; goto out; } if(in->mode & MTRUNC) { if((d->mode & DDIR) || (iaccess(f, d, DWRITE) && !writeallow)) goto badaccess; if(ro) { ou->err = Eronly; goto out; } } t = 0; if(d->mode & DLOCK) { t = tlocked(p, d); if(t == 0) { ou->err = Elocked; goto out; } t->file = f; } if(in->mode & MRCLOSE) fmod |= FREMOV; f->open = fmod; if(in->mode & MTRUNC) if(!(d->mode & DAPND)) dtrunc(p, d); f->tlock = t; f->lastra = 0; mkqid9p1(&ou->qid, &qid); goto out; badaccess: ou->err = Eaccess; f->open = 0; out: if(p) putbuf(p); if(f) qunlock(f); ou->fid = in->fid; }
void f_walk(Chan *cp, Oldfcall *in, Oldfcall *ou) { Iobuf *p, *p1; Dentry *d, *d1; File *f; Wpath *w, *ow; int slot; int32_t addr; if(CHAT(cp)) { print("c_walk %d\n", cp->chan); print(" fid = %d\n", in->fid); print(" name = %s\n", in->name); } ou->fid = in->fid; ou->qid = QID9P1(0,0); p = 0; f = filep(cp, in->fid, 0); if(!f) { ou->err = Efid; goto out; } p = getbuf(f->fs->dev, f->addr, Bread); d = getdir(p, f->slot); if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) { ou->err = Ealloc; goto out; } if(!(d->mode & DDIR)) { ou->err = Edir1; goto out; } if(ou->err = mkqidcmp(&f->qid, d)) goto out; if(cp != cons.chan && iaccess(f, d, DEXEC)) { ou->err = Eaccess; goto out; } accessdir(p, d, FREAD); if(strcmp(in->name, ".") == 0) goto setdot; if(strcmp(in->name, "..") == 0) { if(f->wpath == 0) goto setdot; putbuf(p); p = 0; addr = f->wpath->addr; slot = f->wpath->slot; p1 = getbuf(f->fs->dev, addr, Bread); d1 = getdir(p1, slot); if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) { if(p1) putbuf(p1); ou->err = Ephase; goto out; } ow = f->wpath; f->wpath = ow->up; putwp(ow); goto found; } for(addr=0;; addr++) { p1 = dnodebuf(p, d, addr, 0); if(!p1 || checktag(p1, Tdir, d->qid.path) ) { if(p1) putbuf(p1); ou->err = Eentry; goto out; } for(slot=0; slot<DIRPERBUF; slot++) { d1 = getdir(p1, slot); if(!(d1->mode & DALLOC)) continue; if(strncmp(in->name, d1->name, sizeof(in->name))) continue; /* * update walk path */ w = newwp(); if(!w) { ou->err = Ewalk; putbuf(p1); goto out; } w->addr = f->addr; w->slot = f->slot; w->up = f->wpath; f->wpath = w; slot += DIRPERBUF*addr; goto found; } putbuf(p1); } found: f->addr = p1->addr; mkqid(&f->qid, d1, 1); putbuf(p1); f->slot = slot; setdot: mkqid9p1(&ou->qid, &f->qid); f->open = 0; out: if(p) putbuf(p); if(f) qunlock(f); }
void f_wstat(Chan *cp, Oldfcall *in, Oldfcall *ou) { Iobuf *p, *p1; Dentry *d, *d1, xd; File *f; int slot; int32_t addr; if(CHAT(cp)) { print("c_wstat %d\n", cp->chan); print(" fid = %d\n", in->fid); } p = 0; p1 = 0; d1 = 0; f = filep(cp, in->fid, 0); if(!f) { ou->err = Efid; goto out; } if(isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) { ou->err = Eronly; goto out; } /* * first get parent */ if(f->wpath) { p1 = getbuf(f->fs->dev, f->wpath->addr, Bread); d1 = getdir(p1, f->wpath->slot); if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) { ou->err = Ephase; goto out; } } p = getbuf(f->fs->dev, f->addr, Bread); d = getdir(p, f->slot); if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) { ou->err = Ealloc; goto out; } if(ou->err = mkqidcmp(&f->qid, d)) goto out; convM2D9p1(in->stat, &xd); if(CHAT(cp)) { print(" d.name = %s\n", xd.name); print(" d.uid = %d\n", xd.uid); print(" d.gid = %d\n", xd.gid); print(" d.mode = %.4x\n", xd.mode); } /* * if chown, * must be god */ while(xd.uid != d->uid) { if(wstatallow) /* set to allow chown during boot */ break; ou->err = Enotu; goto out; } /* * if chgroup, * must be either * a) owner and in new group * b) leader of both groups */ while(xd.gid != d->gid) { if(wstatallow || writeallow) /* set to allow chgrp during boot */ break; if(d->uid == f->uid && ingroup(f->uid, xd.gid)) break; if(leadgroup(f->uid, xd.gid)) if(leadgroup(f->uid, d->gid)) break; ou->err = Enotg; goto out; } /* * if rename, * must have write permission in parent */ if(xd.name[0] == 0) strncpy(xd.name, d->name, sizeof(xd.name)); while(strncmp(d->name, xd.name, sizeof(d->name)) != 0) { if(checkname(xd.name)) { ou->err = Ename; goto out; } if(strcmp(xd.name, ".") == 0 || strcmp(xd.name, "..") == 0) { ou->err = Ename; goto out; } /* * drop entry to prevent lock, then * check that destination name is unique, */ putbuf(p); for(addr=0;; addr++) { p = dnodebuf(p1, d1, addr, 0); if(!p) break; if(checktag(p, Tdir, d1->qid.path)) { putbuf(p); continue; } for(slot=0; slot<DIRPERBUF; slot++) { d = getdir(p, slot); if(!(d->mode & DALLOC)) continue; if(!strncmp(xd.name, d->name, sizeof(xd.name))) { ou->err = Eexist; goto out; } } putbuf(p); } /* * reacquire entry */ p = getbuf(f->fs->dev, f->addr, Bread); d = getdir(p, f->slot); if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) { ou->err = Ephase; goto out; } if(wstatallow || writeallow) /* set to allow rename during boot */ break; if(!d1 || iaccess(f, d1, DWRITE)) { ou->err = Eaccess; goto out; } break; } /* * if mode/time, either * a) owner * b) leader of either group */ while(d->mtime != xd.mtime || ((d->mode^xd.mode) & (DAPND|DLOCK|0777))) { if(wstatallow) /* set to allow chmod during boot */ break; if(d->uid == f->uid) break; if(leadgroup(f->uid, xd.gid)) break; if(leadgroup(f->uid, d->gid)) break; ou->err = Enotu; goto out; } d->mtime = xd.mtime; d->uid = xd.uid; d->gid = xd.gid; d->mode = (xd.mode & (DAPND|DLOCK|0777)) | (d->mode & (DALLOC|DDIR)); strncpy(d->name, xd.name, sizeof(d->name)); if(wstatallow) { p->flags |= Bmod; if(xd.atime) d->atime = xd.atime; if(xd.mtime) d->mtime = xd.mtime; } else accessdir(p, d, FWSTAT); out: if(p) putbuf(p); if(p1) putbuf(p1); if(f) qunlock(f); ou->fid = in->fid; }