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; }
int fcallfmt9p1(Fmt *f1) { Fcall9p1 *f; int fid, type, tag, n; char buf[512]; Dir d; f = va_arg(f1->args, Fcall9p1*); type = f->type; fid = f->fid; tag = f->tag; switch(type){ case Tnop9p1: /* 50 */ sprint(buf, "old Tnop tag %ud", tag); break; case Rnop9p1: sprint(buf, "old Rnop tag %ud", tag); break; case Tsession9p1: /* 52 */ sprint(buf, "old Tsession tag %ud", tag); break; case Rsession9p1: sprint(buf, "old Rsession tag %ud", tag); break; case Rerror9p1: /* 55 */ sprint(buf, "old Rerror tag %ud error %.64s", tag, f->ename); break; case Tflush9p1: /* 56 */ sprint(buf, "old Tflush tag %ud oldtag %d", tag, f->oldtag); break; case Rflush9p1: sprint(buf, "old Rflush tag %ud", tag); break; case Tattach9p1: /* 58 */ sprint(buf, "old Tattach tag %ud fid %d uname %.28s aname %.28s auth %.28s", tag, f->fid, f->uname, f->aname, f->auth); break; case Rattach9p1: sprint(buf, "old Rattach tag %ud fid %d qid 0x%lux|0x%lux", tag, fid, f->qid.path, f->qid.version); break; case Tclone9p1: /* 60 */ sprint(buf, "old Tclone tag %ud fid %d newfid %d", tag, fid, f->newfid); break; case Rclone9p1: sprint(buf, "old Rclone tag %ud fid %d", tag, fid); break; case Twalk9p1: /* 62 */ sprint(buf, "old Twalk tag %ud fid %d name %.28s", tag, fid, f->name); break; case Rwalk9p1: sprint(buf, "old Rwalk tag %ud fid %d qid 0x%lux|0x%lux", tag, fid, f->qid.path, f->qid.version); break; case Topen9p1: /* 64 */ sprint(buf, "old Topen tag %ud fid %d mode %d", tag, fid, f->mode); break; case Ropen9p1: sprint(buf, "old Ropen tag %ud fid %d qid 0x%lux|0x%lux", tag, fid, f->qid.path, f->qid.version); break; case Tcreate9p1: /* 66 */ sprint(buf, "old Tcreate tag %ud fid %d name %.28s perm 0x%lux mode %d", tag, fid, f->name, f->perm, f->mode); break; case Rcreate9p1: sprint(buf, "old Rcreate tag %ud fid %d qid 0x%lux|0x%lux", tag, fid, f->qid.path, f->qid.version); break; case Tread9p1: /* 68 */ sprint(buf, "old Tread tag %ud fid %d offset %ld count %ld", tag, fid, f->offset, f->count); break; case Rread9p1: n = sprint(buf, "old Rread tag %ud fid %d count %ld ", tag, fid, f->count); dumpsome(buf+n, f->data, f->count); break; case Twrite9p1: /* 70 */ n = sprint(buf, "old Twrite tag %ud fid %d offset %ld count %ld ", tag, fid, f->offset, f->count); dumpsome(buf+n, f->data, f->count); break; case Rwrite9p1: sprint(buf, "old Rwrite tag %ud fid %d count %ld", tag, fid, f->count); break; case Tclunk9p1: /* 72 */ sprint(buf, "old Tclunk tag %ud fid %d", tag, fid); break; case Rclunk9p1: sprint(buf, "old Rclunk tag %ud fid %d", tag, fid); break; case Tremove9p1: /* 74 */ sprint(buf, "old Tremove tag %ud fid %d", tag, fid); break; case Rremove9p1: sprint(buf, "old Rremove tag %ud fid %d", tag, fid); break; case Tstat9p1: /* 76 */ sprint(buf, "old Tstat tag %ud fid %d", tag, fid); break; case Rstat9p1: convM2D9p1(f->stat, &d); sprint(buf, "old Rstat tag %ud fid %d stat %D", tag, fid, &d); break; case Twstat9p1: /* 78 */ convM2D9p1(f->stat, &d); sprint(buf, "old Twstat tag %ud fid %d stat %D", tag, fid, &d); break; case Rwstat9p1: sprint(buf, "old Rwstat tag %ud fid %d", tag, fid); break; case Tclwalk9p1: /* 81 */ sprint(buf, "old Tclwalk tag %ud fid %d newfid %d name %.28s", tag, fid, f->newfid, f->name); break; case Rclwalk9p1: sprint(buf, "old Rclwalk tag %ud fid %d qid 0x%lux|0x%lux", tag, fid, f->qid.path, f->qid.version); break; default: sprint(buf, "unknown type %d", type); } return fmtstrcpy(f1, buf); }
void cmd_rename(void) { uint32_t perm; Dentry d; char stat[DIRREC]; char oelem[NAMELEN], noelem[NAMELEN], nxelem[NAMELEN]; int err; if(con_clone(FID1, FID2)) return; if(skipbl(1)) return; oelem[0] = 0; while(nextelem()) { if(oelem[0]) if(con_walk(FID2, oelem)){ cprint("file does not exits"); return; } memmove(oelem, elem, NAMELEN); } if(skipbl(1)) return; if(cons.arg[0]=='/'){ if(con_clone(FID1, FID3)) return; noelem[0] = 0; while(nextelem()){ if(noelem[0]) if(con_walk(FID3, noelem)){ cprint("target path %s does not exist", noelem); return; } memmove(noelem, elem, NAMELEN); } if(!con_walk(FID3, elem)){ cprint("target %s already exists\n", elem); return; } if(con_walk(FID2, oelem)){ cprint("src %s does not exist\n", oelem); return; } /* * we know the target does not exist, * the source does exist. * to do the rename, create the target and then * copy the directory entry directly. then remove the source. */ if(err = con_stat(FID2, stat)){ cprint("can't stat file: %s\n", errstring[err]); return; } convM2D9p1(stat, &d); perm = (d.mode&0777)|((d.mode&0x7000)<<17); if(err = con_create(FID3, elem, d.uid, d.gid, perm, (d.mode&DDIR)?OREAD:ORDWR)){ cprint("can't create %s: %s\n", elem, errstring[err]); return; } if(err = con_swap(FID2, FID3)){ cprint("can't swap data: %s\n", errstring[err]); return; } if(err = con_remove(FID2)){ cprint("can't remove file: %s\n", errstring[err]); return; } }else{ cname(nxelem); if(strchr(nxelem, '/')){ cprint("bad rename target: not full path, but contains slashes\n"); return; } if(!con_walk(FID2, nxelem)) cprint("file %s already exists\n", nxelem); else if(con_walk(FID2, oelem)) cprint("file does not already exist\n"); else if(err = con_stat(FID2, stat)) cprint("can't stat file: %s\n", errstring[err]); else{ convM2D9p1(stat, &d); strncpy(d.name, nxelem, NAMELEN); convD2M9p1(&d, stat); if(err = con_wstat(FID2, stat)) cprint("can't move file: %s\n", errstring[err]); } } }