1*01a344a2SDavid du Colombier #include "all.h" 2*01a344a2SDavid du Colombier #include <fcall.h> 3*01a344a2SDavid du Colombier 4*01a344a2SDavid du Colombier enum { MSIZE = MAXDAT+MAXMSG }; 5*01a344a2SDavid du Colombier 6*01a344a2SDavid du Colombier static int 7*01a344a2SDavid du Colombier mkmode9p1(ulong mode9p2) 8*01a344a2SDavid du Colombier { 9*01a344a2SDavid du Colombier int mode; 10*01a344a2SDavid du Colombier 11*01a344a2SDavid du Colombier /* 12*01a344a2SDavid du Colombier * Assume this is for an allocated entry. 13*01a344a2SDavid du Colombier */ 14*01a344a2SDavid du Colombier mode = DALLOC|(mode9p2 & 0777); 15*01a344a2SDavid du Colombier if(mode9p2 & DMEXCL) 16*01a344a2SDavid du Colombier mode |= DLOCK; 17*01a344a2SDavid du Colombier if(mode9p2 & DMAPPEND) 18*01a344a2SDavid du Colombier mode |= DAPND; 19*01a344a2SDavid du Colombier if(mode9p2 & DMDIR) 20*01a344a2SDavid du Colombier mode |= DDIR; 21*01a344a2SDavid du Colombier 22*01a344a2SDavid du Colombier return mode; 23*01a344a2SDavid du Colombier } 24*01a344a2SDavid du Colombier 25*01a344a2SDavid du Colombier void 26*01a344a2SDavid du Colombier mkqid9p1(Qid9p1* qid9p1, Qid* qid) 27*01a344a2SDavid du Colombier { 28*01a344a2SDavid du Colombier if(qid->path & 0xFFFFFFFF00000000LL) 29*01a344a2SDavid du Colombier panic("mkqid9p1: path %lluX", (Wideoff)qid->path); 30*01a344a2SDavid du Colombier qid9p1->path = qid->path & 0xFFFFFFFF; 31*01a344a2SDavid du Colombier if(qid->type & QTDIR) 32*01a344a2SDavid du Colombier qid9p1->path |= QPDIR; 33*01a344a2SDavid du Colombier qid9p1->version = qid->vers; 34*01a344a2SDavid du Colombier } 35*01a344a2SDavid du Colombier 36*01a344a2SDavid du Colombier static int 37*01a344a2SDavid du Colombier mktype9p2(int mode9p1) 38*01a344a2SDavid du Colombier { 39*01a344a2SDavid du Colombier int type; 40*01a344a2SDavid du Colombier 41*01a344a2SDavid du Colombier type = 0; 42*01a344a2SDavid du Colombier if(mode9p1 & DLOCK) 43*01a344a2SDavid du Colombier type |= QTEXCL; 44*01a344a2SDavid du Colombier if(mode9p1 & DAPND) 45*01a344a2SDavid du Colombier type |= QTAPPEND; 46*01a344a2SDavid du Colombier if(mode9p1 & DDIR) 47*01a344a2SDavid du Colombier type |= QTDIR; 48*01a344a2SDavid du Colombier 49*01a344a2SDavid du Colombier return type; 50*01a344a2SDavid du Colombier } 51*01a344a2SDavid du Colombier 52*01a344a2SDavid du Colombier static ulong 53*01a344a2SDavid du Colombier mkmode9p2(int mode9p1) 54*01a344a2SDavid du Colombier { 55*01a344a2SDavid du Colombier ulong mode; 56*01a344a2SDavid du Colombier 57*01a344a2SDavid du Colombier mode = mode9p1 & 0777; 58*01a344a2SDavid du Colombier if(mode9p1 & DLOCK) 59*01a344a2SDavid du Colombier mode |= DMEXCL; 60*01a344a2SDavid du Colombier if(mode9p1 & DAPND) 61*01a344a2SDavid du Colombier mode |= DMAPPEND; 62*01a344a2SDavid du Colombier if(mode9p1 & DDIR) 63*01a344a2SDavid du Colombier mode |= DMDIR; 64*01a344a2SDavid du Colombier 65*01a344a2SDavid du Colombier return mode; 66*01a344a2SDavid du Colombier } 67*01a344a2SDavid du Colombier 68*01a344a2SDavid du Colombier void 69*01a344a2SDavid du Colombier mkqid9p2(Qid* qid, Qid9p1* qid9p1, int mode9p1) 70*01a344a2SDavid du Colombier { 71*01a344a2SDavid du Colombier qid->path = (ulong)(qid9p1->path & ~QPDIR); 72*01a344a2SDavid du Colombier qid->vers = qid9p1->version; 73*01a344a2SDavid du Colombier qid->type = mktype9p2(mode9p1); 74*01a344a2SDavid du Colombier } 75*01a344a2SDavid du Colombier 76*01a344a2SDavid du Colombier static int 77*01a344a2SDavid du Colombier mkdir9p2(Dir* dir, Dentry* dentry, void* strs) 78*01a344a2SDavid du Colombier { 79*01a344a2SDavid du Colombier char *op, *p; 80*01a344a2SDavid du Colombier 81*01a344a2SDavid du Colombier memset(dir, 0, sizeof(Dir)); 82*01a344a2SDavid du Colombier mkqid(&dir->qid, dentry, 1); 83*01a344a2SDavid du Colombier dir->mode = mkmode9p2(dentry->mode); 84*01a344a2SDavid du Colombier dir->atime = dentry->atime; 85*01a344a2SDavid du Colombier dir->mtime = dentry->mtime; 86*01a344a2SDavid du Colombier dir->length = dentry->size; 87*01a344a2SDavid du Colombier 88*01a344a2SDavid du Colombier op = p = strs; 89*01a344a2SDavid du Colombier dir->name = p; 90*01a344a2SDavid du Colombier p += sprint(p, "%s", dentry->name)+1; 91*01a344a2SDavid du Colombier 92*01a344a2SDavid du Colombier dir->uid = p; 93*01a344a2SDavid du Colombier uidtostr(p, dentry->uid, 1); 94*01a344a2SDavid du Colombier p += strlen(p)+1; 95*01a344a2SDavid du Colombier 96*01a344a2SDavid du Colombier dir->gid = p; 97*01a344a2SDavid du Colombier uidtostr(p, dentry->gid, 1); 98*01a344a2SDavid du Colombier p += strlen(p)+1; 99*01a344a2SDavid du Colombier 100*01a344a2SDavid du Colombier dir->muid = p; 101*01a344a2SDavid du Colombier uidtostr(p, dentry->muid, 1); 102*01a344a2SDavid du Colombier p += strlen(p)+1; 103*01a344a2SDavid du Colombier 104*01a344a2SDavid du Colombier return p-op; 105*01a344a2SDavid du Colombier } 106*01a344a2SDavid du Colombier 107*01a344a2SDavid du Colombier static int 108*01a344a2SDavid du Colombier checkname9p2(char* name) 109*01a344a2SDavid du Colombier { 110*01a344a2SDavid du Colombier char *p; 111*01a344a2SDavid du Colombier 112*01a344a2SDavid du Colombier /* 113*01a344a2SDavid du Colombier * Return error or 0 if OK. 114*01a344a2SDavid du Colombier */ 115*01a344a2SDavid du Colombier if(name == nil || *name == 0) 116*01a344a2SDavid du Colombier return Ename; 117*01a344a2SDavid du Colombier 118*01a344a2SDavid du Colombier for(p = name; *p != 0; p++){ 119*01a344a2SDavid du Colombier if(p-name >= NAMELEN-1) 120*01a344a2SDavid du Colombier return Etoolong; 121*01a344a2SDavid du Colombier if((*p & 0xFF) <= 040) 122*01a344a2SDavid du Colombier return Ename; 123*01a344a2SDavid du Colombier } 124*01a344a2SDavid du Colombier if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) 125*01a344a2SDavid du Colombier return Edot; 126*01a344a2SDavid du Colombier 127*01a344a2SDavid du Colombier return 0; 128*01a344a2SDavid du Colombier } 129*01a344a2SDavid du Colombier 130*01a344a2SDavid du Colombier static int 131*01a344a2SDavid du Colombier version(Chan* chan, Fcall* f, Fcall* r) 132*01a344a2SDavid du Colombier { 133*01a344a2SDavid du Colombier if(chan->protocol != nil) 134*01a344a2SDavid du Colombier return Eversion; 135*01a344a2SDavid du Colombier 136*01a344a2SDavid du Colombier if(f->msize < MSIZE) 137*01a344a2SDavid du Colombier r->msize = f->msize; 138*01a344a2SDavid du Colombier else 139*01a344a2SDavid du Colombier r->msize = MSIZE; 140*01a344a2SDavid du Colombier 141*01a344a2SDavid du Colombier /* 142*01a344a2SDavid du Colombier * Should check the '.' stuff here. 143*01a344a2SDavid du Colombier */ 144*01a344a2SDavid du Colombier if(strcmp(f->version, VERSION9P) == 0){ 145*01a344a2SDavid du Colombier r->version = VERSION9P; 146*01a344a2SDavid du Colombier chan->protocol = serve9p2; 147*01a344a2SDavid du Colombier chan->msize = r->msize; 148*01a344a2SDavid du Colombier } else 149*01a344a2SDavid du Colombier r->version = "unknown"; 150*01a344a2SDavid du Colombier 151*01a344a2SDavid du Colombier fileinit(chan); 152*01a344a2SDavid du Colombier return 0; 153*01a344a2SDavid du Colombier } 154*01a344a2SDavid du Colombier 155*01a344a2SDavid du Colombier struct { 156*01a344a2SDavid du Colombier Lock; 157*01a344a2SDavid du Colombier ulong hi; 158*01a344a2SDavid du Colombier } authpath; 159*01a344a2SDavid du Colombier 160*01a344a2SDavid du Colombier static int 161*01a344a2SDavid du Colombier auth(Chan* chan, Fcall* f, Fcall* r) 162*01a344a2SDavid du Colombier { 163*01a344a2SDavid du Colombier char *aname; 164*01a344a2SDavid du Colombier File *file; 165*01a344a2SDavid du Colombier Filsys *fs; 166*01a344a2SDavid du Colombier int error; 167*01a344a2SDavid du Colombier 168*01a344a2SDavid du Colombier if(cons.flags & authdisableflag) 169*01a344a2SDavid du Colombier return Eauthdisabled; 170*01a344a2SDavid du Colombier 171*01a344a2SDavid du Colombier error = 0; 172*01a344a2SDavid du Colombier aname = f->aname; 173*01a344a2SDavid du Colombier 174*01a344a2SDavid du Colombier if(strcmp(f->uname, "none") == 0) 175*01a344a2SDavid du Colombier return Eauthnone; 176*01a344a2SDavid du Colombier 177*01a344a2SDavid du Colombier if(!aname[0]) /* default */ 178*01a344a2SDavid du Colombier aname = "main"; 179*01a344a2SDavid du Colombier file = filep(chan, f->afid, 1); 180*01a344a2SDavid du Colombier if(file == nil){ 181*01a344a2SDavid du Colombier error = Efidinuse; 182*01a344a2SDavid du Colombier goto out; 183*01a344a2SDavid du Colombier } 184*01a344a2SDavid du Colombier fs = fsstr(aname); 185*01a344a2SDavid du Colombier if(fs == nil){ 186*01a344a2SDavid du Colombier error = Ebadspc; 187*01a344a2SDavid du Colombier goto out; 188*01a344a2SDavid du Colombier } 189*01a344a2SDavid du Colombier lock(&authpath); 190*01a344a2SDavid du Colombier file->qid.path = authpath.hi++; 191*01a344a2SDavid du Colombier unlock(&authpath); 192*01a344a2SDavid du Colombier file->qid.type = QTAUTH; 193*01a344a2SDavid du Colombier file->qid.vers = 0; 194*01a344a2SDavid du Colombier file->fs = fs; 195*01a344a2SDavid du Colombier file->open = FREAD+FWRITE; 196*01a344a2SDavid du Colombier freewp(file->wpath); 197*01a344a2SDavid du Colombier file->wpath = 0; 198*01a344a2SDavid du Colombier file->auth = authnew(f->uname, f->aname); 199*01a344a2SDavid du Colombier if(file->auth == nil){ 200*01a344a2SDavid du Colombier error = Eauthfile; 201*01a344a2SDavid du Colombier goto out; 202*01a344a2SDavid du Colombier } 203*01a344a2SDavid du Colombier r->aqid = file->qid; 204*01a344a2SDavid du Colombier 205*01a344a2SDavid du Colombier out: 206*01a344a2SDavid du Colombier if((cons.flags & attachflag) && error) 207*01a344a2SDavid du Colombier print("9p2: auth %s %T SUCK EGGS --- %s\n", 208*01a344a2SDavid du Colombier f->uname, time(nil), errstr9p[error]); 209*01a344a2SDavid du Colombier if(file != nil){ 210*01a344a2SDavid du Colombier qunlock(file); 211*01a344a2SDavid du Colombier if(error) 212*01a344a2SDavid du Colombier freefp(file); 213*01a344a2SDavid du Colombier } 214*01a344a2SDavid du Colombier return error; 215*01a344a2SDavid du Colombier } 216*01a344a2SDavid du Colombier 217*01a344a2SDavid du Colombier int 218*01a344a2SDavid du Colombier authorize(Chan* chan, Fcall* f) 219*01a344a2SDavid du Colombier { 220*01a344a2SDavid du Colombier File* af; 221*01a344a2SDavid du Colombier int db, uid = -1; 222*01a344a2SDavid du Colombier 223*01a344a2SDavid du Colombier db = cons.flags & authdebugflag; 224*01a344a2SDavid du Colombier 225*01a344a2SDavid du Colombier if(strcmp(f->uname, "none") == 0){ 226*01a344a2SDavid du Colombier uid = strtouid(f->uname); 227*01a344a2SDavid du Colombier if(db) 228*01a344a2SDavid du Colombier print("permission granted to none: uid %s = %d\n", 229*01a344a2SDavid du Colombier f->uname, uid); 230*01a344a2SDavid du Colombier return uid; 231*01a344a2SDavid du Colombier } 232*01a344a2SDavid du Colombier 233*01a344a2SDavid du Colombier if(cons.flags & authdisableflag){ 234*01a344a2SDavid du Colombier uid = strtouid(f->uname); 235*01a344a2SDavid du Colombier if(db) 236*01a344a2SDavid du Colombier print("permission granted by authdisable uid %s = %d\n", 237*01a344a2SDavid du Colombier f->uname, uid); 238*01a344a2SDavid du Colombier return uid; 239*01a344a2SDavid du Colombier } 240*01a344a2SDavid du Colombier 241*01a344a2SDavid du Colombier af = filep(chan, f->afid, 0); 242*01a344a2SDavid du Colombier if(af == nil){ 243*01a344a2SDavid du Colombier if(db) 244*01a344a2SDavid du Colombier print("authorize: af == nil\n"); 245*01a344a2SDavid du Colombier return -1; 246*01a344a2SDavid du Colombier } 247*01a344a2SDavid du Colombier if(af->auth == nil){ 248*01a344a2SDavid du Colombier if(db) 249*01a344a2SDavid du Colombier print("authorize: af->auth == nil\n"); 250*01a344a2SDavid du Colombier goto out; 251*01a344a2SDavid du Colombier } 252*01a344a2SDavid du Colombier if(strcmp(f->uname, authuname(af->auth)) != 0){ 253*01a344a2SDavid du Colombier if(db) 254*01a344a2SDavid du Colombier print("authorize: strcmp(f->uname, authuname(af->auth)) != 0\n"); 255*01a344a2SDavid du Colombier goto out; 256*01a344a2SDavid du Colombier } 257*01a344a2SDavid du Colombier if(strcmp(f->aname, authaname(af->auth)) != 0){ 258*01a344a2SDavid du Colombier if(db) 259*01a344a2SDavid du Colombier print("authorize: strcmp(f->aname, authaname(af->auth)) != 0\n"); 260*01a344a2SDavid du Colombier goto out; 261*01a344a2SDavid du Colombier } 262*01a344a2SDavid du Colombier uid = authuid(af->auth); 263*01a344a2SDavid du Colombier if(db) 264*01a344a2SDavid du Colombier print("authorize: uid is %d\n", uid); 265*01a344a2SDavid du Colombier out: 266*01a344a2SDavid du Colombier qunlock(af); 267*01a344a2SDavid du Colombier return uid; 268*01a344a2SDavid du Colombier } 269*01a344a2SDavid du Colombier 270*01a344a2SDavid du Colombier static int 271*01a344a2SDavid du Colombier attach(Chan* chan, Fcall* f, Fcall* r) 272*01a344a2SDavid du Colombier { 273*01a344a2SDavid du Colombier char *aname; 274*01a344a2SDavid du Colombier Iobuf *p; 275*01a344a2SDavid du Colombier Dentry *d; 276*01a344a2SDavid du Colombier File *file; 277*01a344a2SDavid du Colombier Filsys *fs; 278*01a344a2SDavid du Colombier Off raddr; 279*01a344a2SDavid du Colombier int error, u; 280*01a344a2SDavid du Colombier 281*01a344a2SDavid du Colombier aname = f->aname; 282*01a344a2SDavid du Colombier if(!aname[0]) /* default */ 283*01a344a2SDavid du Colombier aname = "main"; 284*01a344a2SDavid du Colombier p = nil; 285*01a344a2SDavid du Colombier error = 0; 286*01a344a2SDavid du Colombier file = filep(chan, f->fid, 1); 287*01a344a2SDavid du Colombier if(file == nil){ 288*01a344a2SDavid du Colombier error = Efidinuse; 289*01a344a2SDavid du Colombier goto out; 290*01a344a2SDavid du Colombier } 291*01a344a2SDavid du Colombier 292*01a344a2SDavid du Colombier u = -1; 293*01a344a2SDavid du Colombier if(chan != cons.chan){ 294*01a344a2SDavid du Colombier if(noattach && strcmp(f->uname, "none")) { 295*01a344a2SDavid du Colombier error = Enoattach; 296*01a344a2SDavid du Colombier goto out; 297*01a344a2SDavid du Colombier } 298*01a344a2SDavid du Colombier u = authorize(chan, f); 299*01a344a2SDavid du Colombier if(u < 0){ 300*01a344a2SDavid du Colombier error = Ebadu; 301*01a344a2SDavid du Colombier goto out; 302*01a344a2SDavid du Colombier } 303*01a344a2SDavid du Colombier } 304*01a344a2SDavid du Colombier file->uid = u; 305*01a344a2SDavid du Colombier 306*01a344a2SDavid du Colombier fs = fsstr(aname); 307*01a344a2SDavid du Colombier if(fs == nil){ 308*01a344a2SDavid du Colombier error = Ebadspc; 309*01a344a2SDavid du Colombier goto out; 310*01a344a2SDavid du Colombier } 311*01a344a2SDavid du Colombier raddr = getraddr(fs->dev); 312*01a344a2SDavid du Colombier p = getbuf(fs->dev, raddr, Brd); 313*01a344a2SDavid du Colombier if(p == nil || checktag(p, Tdir, QPROOT)){ 314*01a344a2SDavid du Colombier error = Ealloc; 315*01a344a2SDavid du Colombier goto out; 316*01a344a2SDavid du Colombier } 317*01a344a2SDavid du Colombier d = getdir(p, 0); 318*01a344a2SDavid du Colombier if(d == nil || !(d->mode & DALLOC)){ 319*01a344a2SDavid du Colombier error = Ealloc; 320*01a344a2SDavid du Colombier goto out; 321*01a344a2SDavid du Colombier } 322*01a344a2SDavid du Colombier if (iaccess(file, d, DEXEC) || 323*01a344a2SDavid du Colombier file->uid == 0 && fs->dev->type == Devro) { 324*01a344a2SDavid du Colombier /* 325*01a344a2SDavid du Colombier * 'none' not allowed on dump 326*01a344a2SDavid du Colombier */ 327*01a344a2SDavid du Colombier error = Eaccess; 328*01a344a2SDavid du Colombier goto out; 329*01a344a2SDavid du Colombier } 330*01a344a2SDavid du Colombier accessdir(p, d, FREAD, file->uid); 331*01a344a2SDavid du Colombier mkqid(&file->qid, d, 1); 332*01a344a2SDavid du Colombier file->fs = fs; 333*01a344a2SDavid du Colombier file->addr = raddr; 334*01a344a2SDavid du Colombier file->slot = 0; 335*01a344a2SDavid du Colombier file->open = 0; 336*01a344a2SDavid du Colombier freewp(file->wpath); 337*01a344a2SDavid du Colombier file->wpath = 0; 338*01a344a2SDavid du Colombier 339*01a344a2SDavid du Colombier r->qid = file->qid; 340*01a344a2SDavid du Colombier 341*01a344a2SDavid du Colombier strncpy(chan->whoname, f->uname, sizeof(chan->whoname)); 342*01a344a2SDavid du Colombier chan->whotime = time(nil); 343*01a344a2SDavid du Colombier if(cons.flags & attachflag) 344*01a344a2SDavid du Colombier print("9p2: attach %s %T to \"%s\" C%d\n", 345*01a344a2SDavid du Colombier chan->whoname, chan->whotime, fs->name, chan->chan); 346*01a344a2SDavid du Colombier 347*01a344a2SDavid du Colombier out: 348*01a344a2SDavid du Colombier if((cons.flags & attachflag) && error) 349*01a344a2SDavid du Colombier print("9p2: attach %s %T SUCK EGGS --- %s\n", 350*01a344a2SDavid du Colombier f->uname, time(nil), errstr9p[error]); 351*01a344a2SDavid du Colombier if(p != nil) 352*01a344a2SDavid du Colombier putbuf(p); 353*01a344a2SDavid du Colombier if(file != nil){ 354*01a344a2SDavid du Colombier qunlock(file); 355*01a344a2SDavid du Colombier if(error) 356*01a344a2SDavid du Colombier freefp(file); 357*01a344a2SDavid du Colombier } 358*01a344a2SDavid du Colombier return error; 359*01a344a2SDavid du Colombier } 360*01a344a2SDavid du Colombier 361*01a344a2SDavid du Colombier static int 362*01a344a2SDavid du Colombier flush(Chan* chan, Fcall*, Fcall*) 363*01a344a2SDavid du Colombier { 364*01a344a2SDavid du Colombier runlock(&chan->reflock); 365*01a344a2SDavid du Colombier wlock(&chan->reflock); 366*01a344a2SDavid du Colombier wunlock(&chan->reflock); 367*01a344a2SDavid du Colombier rlock(&chan->reflock); 368*01a344a2SDavid du Colombier 369*01a344a2SDavid du Colombier return 0; 370*01a344a2SDavid du Colombier } 371*01a344a2SDavid du Colombier 372*01a344a2SDavid du Colombier static void 373*01a344a2SDavid du Colombier clone(File* nfile, File* file) 374*01a344a2SDavid du Colombier { 375*01a344a2SDavid du Colombier Wpath *wpath; 376*01a344a2SDavid du Colombier 377*01a344a2SDavid du Colombier nfile->qid = file->qid; 378*01a344a2SDavid du Colombier 379*01a344a2SDavid du Colombier lock(&wpathlock); 380*01a344a2SDavid du Colombier nfile->wpath = file->wpath; 381*01a344a2SDavid du Colombier for(wpath = nfile->wpath; wpath != nil; wpath = wpath->up) 382*01a344a2SDavid du Colombier wpath->refs++; 383*01a344a2SDavid du Colombier unlock(&wpathlock); 384*01a344a2SDavid du Colombier 385*01a344a2SDavid du Colombier nfile->fs = file->fs; 386*01a344a2SDavid du Colombier nfile->addr = file->addr; 387*01a344a2SDavid du Colombier nfile->slot = file->slot; 388*01a344a2SDavid du Colombier nfile->uid = file->uid; 389*01a344a2SDavid du Colombier nfile->open = file->open & ~FREMOV; 390*01a344a2SDavid du Colombier } 391*01a344a2SDavid du Colombier 392*01a344a2SDavid du Colombier static int 393*01a344a2SDavid du Colombier walkname(File* file, char* wname, Qid* wqid) 394*01a344a2SDavid du Colombier { 395*01a344a2SDavid du Colombier Wpath *w; 396*01a344a2SDavid du Colombier Iobuf *p, *p1; 397*01a344a2SDavid du Colombier Dentry *d, *d1; 398*01a344a2SDavid du Colombier int error, slot; 399*01a344a2SDavid du Colombier Off addr, qpath; 400*01a344a2SDavid du Colombier 401*01a344a2SDavid du Colombier p = p1 = nil; 402*01a344a2SDavid du Colombier 403*01a344a2SDavid du Colombier /* 404*01a344a2SDavid du Colombier * File must not have been opened for I/O by an open 405*01a344a2SDavid du Colombier * or create message and must represent a directory. 406*01a344a2SDavid du Colombier */ 407*01a344a2SDavid du Colombier if(file->open != 0){ 408*01a344a2SDavid du Colombier error = Emode; 409*01a344a2SDavid du Colombier goto out; 410*01a344a2SDavid du Colombier } 411*01a344a2SDavid du Colombier 412*01a344a2SDavid du Colombier p = getbuf(file->fs->dev, file->addr, Brd); 413*01a344a2SDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){ 414*01a344a2SDavid du Colombier error = Edir1; 415*01a344a2SDavid du Colombier goto out; 416*01a344a2SDavid du Colombier } 417*01a344a2SDavid du Colombier d = getdir(p, file->slot); 418*01a344a2SDavid du Colombier if(d == nil || !(d->mode & DALLOC)){ 419*01a344a2SDavid du Colombier error = Ealloc; 420*01a344a2SDavid du Colombier goto out; 421*01a344a2SDavid du Colombier } 422*01a344a2SDavid du Colombier if(!(d->mode & DDIR)){ 423*01a344a2SDavid du Colombier error = Edir1; 424*01a344a2SDavid du Colombier goto out; 425*01a344a2SDavid du Colombier } 426*01a344a2SDavid du Colombier if(error = mkqidcmp(&file->qid, d)) 427*01a344a2SDavid du Colombier goto out; 428*01a344a2SDavid du Colombier 429*01a344a2SDavid du Colombier /* 430*01a344a2SDavid du Colombier * For walked elements the implied user must 431*01a344a2SDavid du Colombier * have permission to search the directory. 432*01a344a2SDavid du Colombier */ 433*01a344a2SDavid du Colombier if(file->cp != cons.chan && iaccess(file, d, DEXEC)){ 434*01a344a2SDavid du Colombier error = Eaccess; 435*01a344a2SDavid du Colombier goto out; 436*01a344a2SDavid du Colombier } 437*01a344a2SDavid du Colombier accessdir(p, d, FREAD, file->uid); 438*01a344a2SDavid du Colombier 439*01a344a2SDavid du Colombier if(strcmp(wname, ".") == 0){ 440*01a344a2SDavid du Colombier setdot: 441*01a344a2SDavid du Colombier if(wqid != nil) 442*01a344a2SDavid du Colombier *wqid = file->qid; 443*01a344a2SDavid du Colombier goto out; 444*01a344a2SDavid du Colombier } 445*01a344a2SDavid du Colombier if(strcmp(wname, "..") == 0){ 446*01a344a2SDavid du Colombier if(file->wpath == 0) 447*01a344a2SDavid du Colombier goto setdot; 448*01a344a2SDavid du Colombier putbuf(p); 449*01a344a2SDavid du Colombier p = nil; 450*01a344a2SDavid du Colombier addr = file->wpath->addr; 451*01a344a2SDavid du Colombier slot = file->wpath->slot; 452*01a344a2SDavid du Colombier p1 = getbuf(file->fs->dev, addr, Brd); 453*01a344a2SDavid du Colombier if(p1 == nil || checktag(p1, Tdir, QPNONE)){ 454*01a344a2SDavid du Colombier error = Edir1; 455*01a344a2SDavid du Colombier goto out; 456*01a344a2SDavid du Colombier } 457*01a344a2SDavid du Colombier d1 = getdir(p1, slot); 458*01a344a2SDavid du Colombier if(d == nil || !(d1->mode & DALLOC)){ 459*01a344a2SDavid du Colombier error = Ephase; 460*01a344a2SDavid du Colombier goto out; 461*01a344a2SDavid du Colombier } 462*01a344a2SDavid du Colombier lock(&wpathlock); 463*01a344a2SDavid du Colombier file->wpath->refs--; 464*01a344a2SDavid du Colombier file->wpath = file->wpath->up; 465*01a344a2SDavid du Colombier unlock(&wpathlock); 466*01a344a2SDavid du Colombier goto found; 467*01a344a2SDavid du Colombier } 468*01a344a2SDavid du Colombier 469*01a344a2SDavid du Colombier for(addr = 0; ; addr++){ 470*01a344a2SDavid du Colombier if(p == nil){ 471*01a344a2SDavid du Colombier p = getbuf(file->fs->dev, file->addr, Brd); 472*01a344a2SDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){ 473*01a344a2SDavid du Colombier error = Ealloc; 474*01a344a2SDavid du Colombier goto out; 475*01a344a2SDavid du Colombier } 476*01a344a2SDavid du Colombier d = getdir(p, file->slot); 477*01a344a2SDavid du Colombier if(d == nil || !(d->mode & DALLOC)){ 478*01a344a2SDavid du Colombier error = Ealloc; 479*01a344a2SDavid du Colombier goto out; 480*01a344a2SDavid du Colombier } 481*01a344a2SDavid du Colombier } 482*01a344a2SDavid du Colombier qpath = d->qid.path; 483*01a344a2SDavid du Colombier p1 = dnodebuf1(p, d, addr, 0, file->uid); 484*01a344a2SDavid du Colombier p = nil; 485*01a344a2SDavid du Colombier if(p1 == nil || checktag(p1, Tdir, qpath)){ 486*01a344a2SDavid du Colombier error = Eentry; 487*01a344a2SDavid du Colombier goto out; 488*01a344a2SDavid du Colombier } 489*01a344a2SDavid du Colombier for(slot = 0; slot < DIRPERBUF; slot++){ 490*01a344a2SDavid du Colombier d1 = getdir(p1, slot); 491*01a344a2SDavid du Colombier if (!(d1->mode & DALLOC) || 492*01a344a2SDavid du Colombier strncmp(wname, d1->name, NAMELEN) != 0) 493*01a344a2SDavid du Colombier continue; 494*01a344a2SDavid du Colombier /* 495*01a344a2SDavid du Colombier * update walk path 496*01a344a2SDavid du Colombier */ 497*01a344a2SDavid du Colombier if((w = newwp()) == nil){ 498*01a344a2SDavid du Colombier error = Ewalk; 499*01a344a2SDavid du Colombier goto out; 500*01a344a2SDavid du Colombier } 501*01a344a2SDavid du Colombier w->addr = file->addr; 502*01a344a2SDavid du Colombier w->slot = file->slot; 503*01a344a2SDavid du Colombier w->up = file->wpath; 504*01a344a2SDavid du Colombier file->wpath = w; 505*01a344a2SDavid du Colombier slot += DIRPERBUF*addr; 506*01a344a2SDavid du Colombier goto found; 507*01a344a2SDavid du Colombier } 508*01a344a2SDavid du Colombier putbuf(p1); 509*01a344a2SDavid du Colombier p1 = nil; 510*01a344a2SDavid du Colombier } 511*01a344a2SDavid du Colombier 512*01a344a2SDavid du Colombier found: 513*01a344a2SDavid du Colombier file->addr = p1->addr; 514*01a344a2SDavid du Colombier mkqid(&file->qid, d1, 1); 515*01a344a2SDavid du Colombier putbuf(p1); 516*01a344a2SDavid du Colombier p1 = nil; 517*01a344a2SDavid du Colombier file->slot = slot; 518*01a344a2SDavid du Colombier if(wqid != nil) 519*01a344a2SDavid du Colombier *wqid = file->qid; 520*01a344a2SDavid du Colombier 521*01a344a2SDavid du Colombier out: 522*01a344a2SDavid du Colombier if(p1 != nil) 523*01a344a2SDavid du Colombier putbuf(p1); 524*01a344a2SDavid du Colombier if(p != nil) 525*01a344a2SDavid du Colombier putbuf(p); 526*01a344a2SDavid du Colombier 527*01a344a2SDavid du Colombier return error; 528*01a344a2SDavid du Colombier } 529*01a344a2SDavid du Colombier 530*01a344a2SDavid du Colombier static int 531*01a344a2SDavid du Colombier walk(Chan* chan, Fcall* f, Fcall* r) 532*01a344a2SDavid du Colombier { 533*01a344a2SDavid du Colombier int error, nwname; 534*01a344a2SDavid du Colombier File *file, *nfile, tfile; 535*01a344a2SDavid du Colombier 536*01a344a2SDavid du Colombier /* 537*01a344a2SDavid du Colombier * The file identified by f->fid must be valid in the 538*01a344a2SDavid du Colombier * current session and must not have been opened for I/O 539*01a344a2SDavid du Colombier * by an open or create message. 540*01a344a2SDavid du Colombier */ 541*01a344a2SDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil) 542*01a344a2SDavid du Colombier return Efid; 543*01a344a2SDavid du Colombier if(file->open != 0){ 544*01a344a2SDavid du Colombier qunlock(file); 545*01a344a2SDavid du Colombier return Emode; 546*01a344a2SDavid du Colombier } 547*01a344a2SDavid du Colombier 548*01a344a2SDavid du Colombier /* 549*01a344a2SDavid du Colombier * If newfid is not the same as fid, allocate a new file; 550*01a344a2SDavid du Colombier * a side effect is checking newfid is not already in use (error); 551*01a344a2SDavid du Colombier * if there are no names to walk this will be equivalent to a 552*01a344a2SDavid du Colombier * simple 'clone' operation. 553*01a344a2SDavid du Colombier * Otherwise, fid and newfid are the same and if there are names 554*01a344a2SDavid du Colombier * to walk make a copy of 'file' to be used during the walk as 555*01a344a2SDavid du Colombier * 'file' must only be updated on success. 556*01a344a2SDavid du Colombier * Finally, it's a no-op if newfid is the same as fid and f->nwname 557*01a344a2SDavid du Colombier * is 0. 558*01a344a2SDavid du Colombier */ 559*01a344a2SDavid du Colombier r->nwqid = 0; 560*01a344a2SDavid du Colombier if(f->newfid != f->fid){ 561*01a344a2SDavid du Colombier if((nfile = filep(chan, f->newfid, 1)) == nil){ 562*01a344a2SDavid du Colombier qunlock(file); 563*01a344a2SDavid du Colombier return Efidinuse; 564*01a344a2SDavid du Colombier } 565*01a344a2SDavid du Colombier } else if(f->nwname != 0){ 566*01a344a2SDavid du Colombier nfile = &tfile; 567*01a344a2SDavid du Colombier memset(nfile, 0, sizeof(File)); 568*01a344a2SDavid du Colombier nfile->cp = chan; 569*01a344a2SDavid du Colombier nfile->fid = ~0; 570*01a344a2SDavid du Colombier } else { 571*01a344a2SDavid du Colombier qunlock(file); 572*01a344a2SDavid du Colombier return 0; 573*01a344a2SDavid du Colombier } 574*01a344a2SDavid du Colombier clone(nfile, file); 575*01a344a2SDavid du Colombier 576*01a344a2SDavid du Colombier /* 577*01a344a2SDavid du Colombier * Should check name is not too long. 578*01a344a2SDavid du Colombier */ 579*01a344a2SDavid du Colombier error = 0; 580*01a344a2SDavid du Colombier for(nwname = 0; nwname < f->nwname; nwname++){ 581*01a344a2SDavid du Colombier error = walkname(nfile, f->wname[nwname], &r->wqid[r->nwqid]); 582*01a344a2SDavid du Colombier if(error != 0 || ++r->nwqid >= MAXDAT/sizeof(Qid)) 583*01a344a2SDavid du Colombier break; 584*01a344a2SDavid du Colombier } 585*01a344a2SDavid du Colombier 586*01a344a2SDavid du Colombier if(f->nwname == 0){ 587*01a344a2SDavid du Colombier /* 588*01a344a2SDavid du Colombier * Newfid must be different to fid (see above) 589*01a344a2SDavid du Colombier * so this is a simple 'clone' operation - there's 590*01a344a2SDavid du Colombier * nothing to do except unlock unless there's 591*01a344a2SDavid du Colombier * an error. 592*01a344a2SDavid du Colombier */ 593*01a344a2SDavid du Colombier if(error){ 594*01a344a2SDavid du Colombier freewp(nfile->wpath); 595*01a344a2SDavid du Colombier qunlock(nfile); 596*01a344a2SDavid du Colombier freefp(nfile); 597*01a344a2SDavid du Colombier } else 598*01a344a2SDavid du Colombier qunlock(nfile); 599*01a344a2SDavid du Colombier } else if(r->nwqid < f->nwname){ 600*01a344a2SDavid du Colombier /* 601*01a344a2SDavid du Colombier * Didn't walk all elements, 'clunk' nfile 602*01a344a2SDavid du Colombier * and leave 'file' alone. 603*01a344a2SDavid du Colombier * Clear error if some of the elements were 604*01a344a2SDavid du Colombier * walked OK. 605*01a344a2SDavid du Colombier */ 606*01a344a2SDavid du Colombier freewp(nfile->wpath); 607*01a344a2SDavid du Colombier if(nfile != &tfile){ 608*01a344a2SDavid du Colombier qunlock(nfile); 609*01a344a2SDavid du Colombier freefp(nfile); 610*01a344a2SDavid du Colombier } 611*01a344a2SDavid du Colombier if(r->nwqid != 0) 612*01a344a2SDavid du Colombier error = 0; 613*01a344a2SDavid du Colombier } else { 614*01a344a2SDavid du Colombier /* 615*01a344a2SDavid du Colombier * Walked all elements. If newfid is the same 616*01a344a2SDavid du Colombier * as fid must update 'file' from the temporary 617*01a344a2SDavid du Colombier * copy used during the walk. 618*01a344a2SDavid du Colombier * Otherwise just unlock (when using tfile there's 619*01a344a2SDavid du Colombier * no need to unlock as it's a local). 620*01a344a2SDavid du Colombier */ 621*01a344a2SDavid du Colombier if(nfile == &tfile){ 622*01a344a2SDavid du Colombier file->qid = nfile->qid; 623*01a344a2SDavid du Colombier freewp(file->wpath); 624*01a344a2SDavid du Colombier file->wpath = nfile->wpath; 625*01a344a2SDavid du Colombier file->addr = nfile->addr; 626*01a344a2SDavid du Colombier file->slot = nfile->slot; 627*01a344a2SDavid du Colombier } else 628*01a344a2SDavid du Colombier qunlock(nfile); 629*01a344a2SDavid du Colombier } 630*01a344a2SDavid du Colombier qunlock(file); 631*01a344a2SDavid du Colombier 632*01a344a2SDavid du Colombier return error; 633*01a344a2SDavid du Colombier } 634*01a344a2SDavid du Colombier 635*01a344a2SDavid du Colombier static int 636*01a344a2SDavid du Colombier fs_open(Chan* chan, Fcall* f, Fcall* r) 637*01a344a2SDavid du Colombier { 638*01a344a2SDavid du Colombier Iobuf *p; 639*01a344a2SDavid du Colombier Dentry *d; 640*01a344a2SDavid du Colombier File *file; 641*01a344a2SDavid du Colombier Tlock *t; 642*01a344a2SDavid du Colombier Qid qid; 643*01a344a2SDavid du Colombier int error, ro, fmod, wok; 644*01a344a2SDavid du Colombier 645*01a344a2SDavid du Colombier wok = 0; 646*01a344a2SDavid du Colombier p = nil; 647*01a344a2SDavid du Colombier 648*01a344a2SDavid du Colombier if(chan == cons.chan || writeallow) 649*01a344a2SDavid du Colombier wok = 1; 650*01a344a2SDavid du Colombier 651*01a344a2SDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil){ 652*01a344a2SDavid du Colombier error = Efid; 653*01a344a2SDavid du Colombier goto out; 654*01a344a2SDavid du Colombier } 655*01a344a2SDavid du Colombier if(file->open != 0){ 656*01a344a2SDavid du Colombier error = Emode; 657*01a344a2SDavid du Colombier goto out; 658*01a344a2SDavid du Colombier } 659*01a344a2SDavid du Colombier 660*01a344a2SDavid du Colombier /* 661*01a344a2SDavid du Colombier * if remove on close, check access here 662*01a344a2SDavid du Colombier */ 663*01a344a2SDavid du Colombier ro = file->fs->dev->type == Devro; 664*01a344a2SDavid du Colombier if(f->mode & ORCLOSE){ 665*01a344a2SDavid du Colombier if(ro){ 666*01a344a2SDavid du Colombier error = Eronly; 667*01a344a2SDavid du Colombier goto out; 668*01a344a2SDavid du Colombier } 669*01a344a2SDavid du Colombier /* 670*01a344a2SDavid du Colombier * check on parent directory of file to be deleted 671*01a344a2SDavid du Colombier */ 672*01a344a2SDavid du Colombier if(file->wpath == 0 || file->wpath->addr == file->addr){ 673*01a344a2SDavid du Colombier error = Ephase; 674*01a344a2SDavid du Colombier goto out; 675*01a344a2SDavid du Colombier } 676*01a344a2SDavid du Colombier p = getbuf(file->fs->dev, file->wpath->addr, Brd); 677*01a344a2SDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){ 678*01a344a2SDavid du Colombier error = Ephase; 679*01a344a2SDavid du Colombier goto out; 680*01a344a2SDavid du Colombier } 681*01a344a2SDavid du Colombier d = getdir(p, file->wpath->slot); 682*01a344a2SDavid du Colombier if(d == nil || !(d->mode & DALLOC)){ 683*01a344a2SDavid du Colombier error = Ephase; 684*01a344a2SDavid du Colombier goto out; 685*01a344a2SDavid du Colombier } 686*01a344a2SDavid du Colombier if(iaccess(file, d, DWRITE)){ 687*01a344a2SDavid du Colombier error = Eaccess; 688*01a344a2SDavid du Colombier goto out; 689*01a344a2SDavid du Colombier } 690*01a344a2SDavid du Colombier putbuf(p); 691*01a344a2SDavid du Colombier } 692*01a344a2SDavid du Colombier p = getbuf(file->fs->dev, file->addr, Brd); 693*01a344a2SDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){ 694*01a344a2SDavid du Colombier error = Ealloc; 695*01a344a2SDavid du Colombier goto out; 696*01a344a2SDavid du Colombier } 697*01a344a2SDavid du Colombier d = getdir(p, file->slot); 698*01a344a2SDavid du Colombier if(d == nil || !(d->mode & DALLOC)){ 699*01a344a2SDavid du Colombier error = Ealloc; 700*01a344a2SDavid du Colombier goto out; 701*01a344a2SDavid du Colombier } 702*01a344a2SDavid du Colombier if(error = mkqidcmp(&file->qid, d)) 703*01a344a2SDavid du Colombier goto out; 704*01a344a2SDavid du Colombier mkqid(&qid, d, 1); 705*01a344a2SDavid du Colombier switch(f->mode & 7){ 706*01a344a2SDavid du Colombier 707*01a344a2SDavid du Colombier case OREAD: 708*01a344a2SDavid du Colombier if(iaccess(file, d, DREAD) && !wok) 709*01a344a2SDavid du Colombier goto badaccess; 710*01a344a2SDavid du Colombier fmod = FREAD; 711*01a344a2SDavid du Colombier break; 712*01a344a2SDavid du Colombier 713*01a344a2SDavid du Colombier case OWRITE: 714*01a344a2SDavid du Colombier if((d->mode & DDIR) || (iaccess(file, d, DWRITE) && !wok)) 715*01a344a2SDavid du Colombier goto badaccess; 716*01a344a2SDavid du Colombier if(ro){ 717*01a344a2SDavid du Colombier error = Eronly; 718*01a344a2SDavid du Colombier goto out; 719*01a344a2SDavid du Colombier } 720*01a344a2SDavid du Colombier fmod = FWRITE; 721*01a344a2SDavid du Colombier break; 722*01a344a2SDavid du Colombier 723*01a344a2SDavid du Colombier case ORDWR: 724*01a344a2SDavid du Colombier if((d->mode & DDIR) 725*01a344a2SDavid du Colombier || (iaccess(file, d, DREAD) && !wok) 726*01a344a2SDavid du Colombier || (iaccess(file, d, DWRITE) && !wok)) 727*01a344a2SDavid du Colombier goto badaccess; 728*01a344a2SDavid du Colombier if(ro){ 729*01a344a2SDavid du Colombier error = Eronly; 730*01a344a2SDavid du Colombier goto out; 731*01a344a2SDavid du Colombier } 732*01a344a2SDavid du Colombier fmod = FREAD+FWRITE; 733*01a344a2SDavid du Colombier break; 734*01a344a2SDavid du Colombier 735*01a344a2SDavid du Colombier case OEXEC: 736*01a344a2SDavid du Colombier if((d->mode & DDIR) || (iaccess(file, d, DEXEC) && !wok)) 737*01a344a2SDavid du Colombier goto badaccess; 738*01a344a2SDavid du Colombier fmod = FREAD; 739*01a344a2SDavid du Colombier break; 740*01a344a2SDavid du Colombier 741*01a344a2SDavid du Colombier default: 742*01a344a2SDavid du Colombier error = Emode; 743*01a344a2SDavid du Colombier goto out; 744*01a344a2SDavid du Colombier } 745*01a344a2SDavid du Colombier if(f->mode & OTRUNC){ 746*01a344a2SDavid du Colombier if((d->mode & DDIR) || (iaccess(file, d, DWRITE) && !wok)) 747*01a344a2SDavid du Colombier goto badaccess; 748*01a344a2SDavid du Colombier if(ro){ 749*01a344a2SDavid du Colombier error = Eronly; 750*01a344a2SDavid du Colombier goto out; 751*01a344a2SDavid du Colombier } 752*01a344a2SDavid du Colombier } 753*01a344a2SDavid du Colombier t = 0; 754*01a344a2SDavid du Colombier if(d->mode & DLOCK){ 755*01a344a2SDavid du Colombier if((t = tlocked(p, d)) == nil){ 756*01a344a2SDavid du Colombier error = Elocked; 757*01a344a2SDavid du Colombier goto out; 758*01a344a2SDavid du Colombier } 759*01a344a2SDavid du Colombier } 760*01a344a2SDavid du Colombier if(f->mode & ORCLOSE) 761*01a344a2SDavid du Colombier fmod |= FREMOV; 762*01a344a2SDavid du Colombier file->open = fmod; 763*01a344a2SDavid du Colombier if((f->mode & OTRUNC) && !(d->mode & DAPND)){ 764*01a344a2SDavid du Colombier dtrunc(p, d, file->uid); 765*01a344a2SDavid du Colombier qid.vers = d->qid.version; 766*01a344a2SDavid du Colombier } 767*01a344a2SDavid du Colombier r->qid = qid; 768*01a344a2SDavid du Colombier file->tlock = t; 769*01a344a2SDavid du Colombier if(t != nil) 770*01a344a2SDavid du Colombier t->file = file; 771*01a344a2SDavid du Colombier file->lastra = 1; 772*01a344a2SDavid du Colombier goto out; 773*01a344a2SDavid du Colombier 774*01a344a2SDavid du Colombier badaccess: 775*01a344a2SDavid du Colombier error = Eaccess; 776*01a344a2SDavid du Colombier file->open = 0; 777*01a344a2SDavid du Colombier 778*01a344a2SDavid du Colombier out: 779*01a344a2SDavid du Colombier if(p != nil) 780*01a344a2SDavid du Colombier putbuf(p); 781*01a344a2SDavid du Colombier if(file != nil) 782*01a344a2SDavid du Colombier qunlock(file); 783*01a344a2SDavid du Colombier 784*01a344a2SDavid du Colombier r->iounit = chan->msize-IOHDRSZ; 785*01a344a2SDavid du Colombier 786*01a344a2SDavid du Colombier return error; 787*01a344a2SDavid du Colombier } 788*01a344a2SDavid du Colombier 789*01a344a2SDavid du Colombier static int 790*01a344a2SDavid du Colombier fs_create(Chan* chan, Fcall* f, Fcall* r) 791*01a344a2SDavid du Colombier { 792*01a344a2SDavid du Colombier Iobuf *p, *p1; 793*01a344a2SDavid du Colombier Dentry *d, *d1; 794*01a344a2SDavid du Colombier File *file; 795*01a344a2SDavid du Colombier int error, slot, slot1, fmod, wok; 796*01a344a2SDavid du Colombier Off addr, addr1, path; 797*01a344a2SDavid du Colombier Tlock *t; 798*01a344a2SDavid du Colombier Wpath *w; 799*01a344a2SDavid du Colombier 800*01a344a2SDavid du Colombier wok = 0; 801*01a344a2SDavid du Colombier p = nil; 802*01a344a2SDavid du Colombier 803*01a344a2SDavid du Colombier if(chan == cons.chan || writeallow) 804*01a344a2SDavid du Colombier wok = 1; 805*01a344a2SDavid du Colombier 806*01a344a2SDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil){ 807*01a344a2SDavid du Colombier error = Efid; 808*01a344a2SDavid du Colombier goto out; 809*01a344a2SDavid du Colombier } 810*01a344a2SDavid du Colombier if(file->fs->dev->type == Devro){ 811*01a344a2SDavid du Colombier error = Eronly; 812*01a344a2SDavid du Colombier goto out; 813*01a344a2SDavid du Colombier } 814*01a344a2SDavid du Colombier if(file->qid.type & QTAUTH){ 815*01a344a2SDavid du Colombier error = Emode; 816*01a344a2SDavid du Colombier goto out; 817*01a344a2SDavid du Colombier } 818*01a344a2SDavid du Colombier 819*01a344a2SDavid du Colombier p = getbuf(file->fs->dev, file->addr, Brd); 820*01a344a2SDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){ 821*01a344a2SDavid du Colombier error = Ealloc; 822*01a344a2SDavid du Colombier goto out; 823*01a344a2SDavid du Colombier } 824*01a344a2SDavid du Colombier d = getdir(p, file->slot); 825*01a344a2SDavid du Colombier if(d == nil || !(d->mode & DALLOC)){ 826*01a344a2SDavid du Colombier error = Ealloc; 827*01a344a2SDavid du Colombier goto out; 828*01a344a2SDavid du Colombier } 829*01a344a2SDavid du Colombier if(error = mkqidcmp(&file->qid, d)) 830*01a344a2SDavid du Colombier goto out; 831*01a344a2SDavid du Colombier if(!(d->mode & DDIR)){ 832*01a344a2SDavid du Colombier error = Edir2; 833*01a344a2SDavid du Colombier goto out; 834*01a344a2SDavid du Colombier } 835*01a344a2SDavid du Colombier if(iaccess(file, d, DWRITE) && !wok) { 836*01a344a2SDavid du Colombier error = Eaccess; 837*01a344a2SDavid du Colombier goto out; 838*01a344a2SDavid du Colombier } 839*01a344a2SDavid du Colombier accessdir(p, d, FREAD, file->uid); 840*01a344a2SDavid du Colombier 841*01a344a2SDavid du Colombier /* 842*01a344a2SDavid du Colombier * Check the name is valid (and will fit in an old 843*01a344a2SDavid du Colombier * directory entry for the moment). 844*01a344a2SDavid du Colombier */ 845*01a344a2SDavid du Colombier if(error = checkname9p2(f->name)) 846*01a344a2SDavid du Colombier goto out; 847*01a344a2SDavid du Colombier 848*01a344a2SDavid du Colombier addr1 = 0; 849*01a344a2SDavid du Colombier slot1 = 0; /* set */ 850*01a344a2SDavid du Colombier for(addr = 0; ; addr++){ 851*01a344a2SDavid du Colombier if((p1 = dnodebuf(p, d, addr, 0, file->uid)) == nil){ 852*01a344a2SDavid du Colombier if(addr1 != 0) 853*01a344a2SDavid du Colombier break; 854*01a344a2SDavid du Colombier p1 = dnodebuf(p, d, addr, Tdir, file->uid); 855*01a344a2SDavid du Colombier } 856*01a344a2SDavid du Colombier if(p1 == nil){ 857*01a344a2SDavid du Colombier error = Efull; 858*01a344a2SDavid du Colombier goto out; 859*01a344a2SDavid du Colombier } 860*01a344a2SDavid du Colombier if(checktag(p1, Tdir, d->qid.path)){ 861*01a344a2SDavid du Colombier putbuf(p1); 862*01a344a2SDavid du Colombier goto phase; 863*01a344a2SDavid du Colombier } 864*01a344a2SDavid du Colombier for(slot = 0; slot < DIRPERBUF; slot++){ 865*01a344a2SDavid du Colombier d1 = getdir(p1, slot); 866*01a344a2SDavid du Colombier if(!(d1->mode & DALLOC)){ 867*01a344a2SDavid du Colombier if(addr1 == 0){ 868*01a344a2SDavid du Colombier addr1 = p1->addr; 869*01a344a2SDavid du Colombier slot1 = slot + addr*DIRPERBUF; 870*01a344a2SDavid du Colombier } 871*01a344a2SDavid du Colombier continue; 872*01a344a2SDavid du Colombier } 873*01a344a2SDavid du Colombier if(strncmp(f->name, d1->name, sizeof(d1->name)) == 0){ 874*01a344a2SDavid du Colombier putbuf(p1); 875*01a344a2SDavid du Colombier error = Eexist; 876*01a344a2SDavid du Colombier goto out; 877*01a344a2SDavid du Colombier } 878*01a344a2SDavid du Colombier } 879*01a344a2SDavid du Colombier putbuf(p1); 880*01a344a2SDavid du Colombier } 881*01a344a2SDavid du Colombier 882*01a344a2SDavid du Colombier switch(f->mode & 7){ 883*01a344a2SDavid du Colombier case OEXEC: 884*01a344a2SDavid du Colombier case OREAD: /* seems only useful to make directories */ 885*01a344a2SDavid du Colombier fmod = FREAD; 886*01a344a2SDavid du Colombier break; 887*01a344a2SDavid du Colombier 888*01a344a2SDavid du Colombier case OWRITE: 889*01a344a2SDavid du Colombier fmod = FWRITE; 890*01a344a2SDavid du Colombier break; 891*01a344a2SDavid du Colombier 892*01a344a2SDavid du Colombier case ORDWR: 893*01a344a2SDavid du Colombier fmod = FREAD+FWRITE; 894*01a344a2SDavid du Colombier break; 895*01a344a2SDavid du Colombier 896*01a344a2SDavid du Colombier default: 897*01a344a2SDavid du Colombier error = Emode; 898*01a344a2SDavid du Colombier goto out; 899*01a344a2SDavid du Colombier } 900*01a344a2SDavid du Colombier if(f->perm & PDIR) 901*01a344a2SDavid du Colombier if((f->mode & OTRUNC) || (f->perm & PAPND) || (fmod & FWRITE)) 902*01a344a2SDavid du Colombier goto badaccess; 903*01a344a2SDavid du Colombier /* 904*01a344a2SDavid du Colombier * do it 905*01a344a2SDavid du Colombier */ 906*01a344a2SDavid du Colombier path = qidpathgen(file->fs->dev); 907*01a344a2SDavid du Colombier if((p1 = getbuf(file->fs->dev, addr1, Brd|Bimm|Bmod)) == nil) 908*01a344a2SDavid du Colombier goto phase; 909*01a344a2SDavid du Colombier d1 = getdir(p1, slot1); 910*01a344a2SDavid du Colombier if(d1 == nil || checktag(p1, Tdir, d->qid.path)) { 911*01a344a2SDavid du Colombier putbuf(p1); 912*01a344a2SDavid du Colombier goto phase; 913*01a344a2SDavid du Colombier } 914*01a344a2SDavid du Colombier if(d1->mode & DALLOC){ 915*01a344a2SDavid du Colombier putbuf(p1); 916*01a344a2SDavid du Colombier goto phase; 917*01a344a2SDavid du Colombier } 918*01a344a2SDavid du Colombier 919*01a344a2SDavid du Colombier strncpy(d1->name, f->name, sizeof(d1->name)); 920*01a344a2SDavid du Colombier if(chan == cons.chan){ 921*01a344a2SDavid du Colombier d1->uid = cons.uid; 922*01a344a2SDavid du Colombier d1->gid = cons.gid; 923*01a344a2SDavid du Colombier } else { 924*01a344a2SDavid du Colombier d1->uid = file->uid; 925*01a344a2SDavid du Colombier d1->gid = d->gid; 926*01a344a2SDavid du Colombier f->perm &= d->mode | ~0666; 927*01a344a2SDavid du Colombier if(f->perm & PDIR) 928*01a344a2SDavid du Colombier f->perm &= d->mode | ~0777; 929*01a344a2SDavid du Colombier } 930*01a344a2SDavid du Colombier d1->qid.path = path; 931*01a344a2SDavid du Colombier d1->qid.version = 0; 932*01a344a2SDavid du Colombier d1->mode = DALLOC | (f->perm & 0777); 933*01a344a2SDavid du Colombier if(f->perm & PDIR) { 934*01a344a2SDavid du Colombier d1->mode |= DDIR; 935*01a344a2SDavid du Colombier d1->qid.path |= QPDIR; 936*01a344a2SDavid du Colombier } 937*01a344a2SDavid du Colombier if(f->perm & PAPND) 938*01a344a2SDavid du Colombier d1->mode |= DAPND; 939*01a344a2SDavid du Colombier t = nil; 940*01a344a2SDavid du Colombier if(f->perm & PLOCK){ 941*01a344a2SDavid du Colombier d1->mode |= DLOCK; 942*01a344a2SDavid du Colombier t = tlocked(p1, d1); 943*01a344a2SDavid du Colombier /* if nil, out of tlock structures */ 944*01a344a2SDavid du Colombier } 945*01a344a2SDavid du Colombier accessdir(p1, d1, FWRITE, file->uid); 946*01a344a2SDavid du Colombier mkqid(&r->qid, d1, 0); 947*01a344a2SDavid du Colombier putbuf(p1); 948*01a344a2SDavid du Colombier accessdir(p, d, FWRITE, file->uid); 949*01a344a2SDavid du Colombier 950*01a344a2SDavid du Colombier /* 951*01a344a2SDavid du Colombier * do a walk to new directory entry 952*01a344a2SDavid du Colombier */ 953*01a344a2SDavid du Colombier if((w = newwp()) == nil){ 954*01a344a2SDavid du Colombier error = Ewalk; 955*01a344a2SDavid du Colombier goto out; 956*01a344a2SDavid du Colombier } 957*01a344a2SDavid du Colombier w->addr = file->addr; 958*01a344a2SDavid du Colombier w->slot = file->slot; 959*01a344a2SDavid du Colombier w->up = file->wpath; 960*01a344a2SDavid du Colombier file->wpath = w; 961*01a344a2SDavid du Colombier file->qid = r->qid; 962*01a344a2SDavid du Colombier file->tlock = t; 963*01a344a2SDavid du Colombier if(t != nil) 964*01a344a2SDavid du Colombier t->file = file; 965*01a344a2SDavid du Colombier file->lastra = 1; 966*01a344a2SDavid du Colombier if(f->mode & ORCLOSE) 967*01a344a2SDavid du Colombier fmod |= FREMOV; 968*01a344a2SDavid du Colombier file->open = fmod; 969*01a344a2SDavid du Colombier file->addr = addr1; 970*01a344a2SDavid du Colombier file->slot = slot1; 971*01a344a2SDavid du Colombier goto out; 972*01a344a2SDavid du Colombier 973*01a344a2SDavid du Colombier badaccess: 974*01a344a2SDavid du Colombier error = Eaccess; 975*01a344a2SDavid du Colombier goto out; 976*01a344a2SDavid du Colombier 977*01a344a2SDavid du Colombier phase: 978*01a344a2SDavid du Colombier error = Ephase; 979*01a344a2SDavid du Colombier 980*01a344a2SDavid du Colombier out: 981*01a344a2SDavid du Colombier if(p != nil) 982*01a344a2SDavid du Colombier putbuf(p); 983*01a344a2SDavid du Colombier if(file != nil) 984*01a344a2SDavid du Colombier qunlock(file); 985*01a344a2SDavid du Colombier 986*01a344a2SDavid du Colombier r->iounit = chan->msize-IOHDRSZ; 987*01a344a2SDavid du Colombier 988*01a344a2SDavid du Colombier return error; 989*01a344a2SDavid du Colombier } 990*01a344a2SDavid du Colombier 991*01a344a2SDavid du Colombier static int 992*01a344a2SDavid du Colombier fs_read(Chan* chan, Fcall* f, Fcall* r, uchar* data) 993*01a344a2SDavid du Colombier { 994*01a344a2SDavid du Colombier Iobuf *p, *p1; 995*01a344a2SDavid du Colombier File *file; 996*01a344a2SDavid du Colombier Dentry *d, *d1; 997*01a344a2SDavid du Colombier Tlock *t; 998*01a344a2SDavid du Colombier Off addr, offset, start; 999*01a344a2SDavid du Colombier Timet tim; 1000*01a344a2SDavid du Colombier int error, iounit, nread, count, n, o, slot; 1001*01a344a2SDavid du Colombier Msgbuf *dmb; 1002*01a344a2SDavid du Colombier Dir dir; 1003*01a344a2SDavid du Colombier 1004*01a344a2SDavid du Colombier p = nil; 1005*01a344a2SDavid du Colombier 1006*01a344a2SDavid du Colombier error = 0; 1007*01a344a2SDavid du Colombier count = f->count; 1008*01a344a2SDavid du Colombier offset = f->offset; 1009*01a344a2SDavid du Colombier nread = 0; 1010*01a344a2SDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil){ 1011*01a344a2SDavid du Colombier error = Efid; 1012*01a344a2SDavid du Colombier goto out; 1013*01a344a2SDavid du Colombier } 1014*01a344a2SDavid du Colombier if(!(file->open & FREAD)){ 1015*01a344a2SDavid du Colombier error = Eopen; 1016*01a344a2SDavid du Colombier goto out; 1017*01a344a2SDavid du Colombier } 1018*01a344a2SDavid du Colombier iounit = chan->msize-IOHDRSZ; 1019*01a344a2SDavid du Colombier if(count < 0 || count > iounit){ 1020*01a344a2SDavid du Colombier error = Ecount; 1021*01a344a2SDavid du Colombier goto out; 1022*01a344a2SDavid du Colombier } 1023*01a344a2SDavid du Colombier if(offset < 0){ 1024*01a344a2SDavid du Colombier error = Eoffset; 1025*01a344a2SDavid du Colombier goto out; 1026*01a344a2SDavid du Colombier } 1027*01a344a2SDavid du Colombier if(file->qid.type & QTAUTH){ 1028*01a344a2SDavid du Colombier nread = authread(file, (uchar*)data, count); 1029*01a344a2SDavid du Colombier if(nread < 0) 1030*01a344a2SDavid du Colombier error = Eauth2; 1031*01a344a2SDavid du Colombier goto out; 1032*01a344a2SDavid du Colombier } 1033*01a344a2SDavid du Colombier p = getbuf(file->fs->dev, file->addr, Brd); 1034*01a344a2SDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){ 1035*01a344a2SDavid du Colombier error = Ealloc; 1036*01a344a2SDavid du Colombier goto out; 1037*01a344a2SDavid du Colombier } 1038*01a344a2SDavid du Colombier d = getdir(p, file->slot); 1039*01a344a2SDavid du Colombier if(d == nil || !(d->mode & DALLOC)){ 1040*01a344a2SDavid du Colombier error = Ealloc; 1041*01a344a2SDavid du Colombier goto out; 1042*01a344a2SDavid du Colombier } 1043*01a344a2SDavid du Colombier if(error = mkqidcmp(&file->qid, d)) 1044*01a344a2SDavid du Colombier goto out; 1045*01a344a2SDavid du Colombier if(t = file->tlock){ 1046*01a344a2SDavid du Colombier tim = toytime(); 1047*01a344a2SDavid du Colombier if(t->time < tim || t->file != file){ 1048*01a344a2SDavid du Colombier error = Ebroken; 1049*01a344a2SDavid du Colombier goto out; 1050*01a344a2SDavid du Colombier } 1051*01a344a2SDavid du Colombier /* renew the lock */ 1052*01a344a2SDavid du Colombier t->time = tim + TLOCK; 1053*01a344a2SDavid du Colombier } 1054*01a344a2SDavid du Colombier accessdir(p, d, FREAD, file->uid); 1055*01a344a2SDavid du Colombier if(d->mode & DDIR) 1056*01a344a2SDavid du Colombier goto dread; 1057*01a344a2SDavid du Colombier if(offset+count > d->size) 1058*01a344a2SDavid du Colombier count = d->size - offset; 1059*01a344a2SDavid du Colombier while(count > 0){ 1060*01a344a2SDavid du Colombier if(p == nil){ 1061*01a344a2SDavid du Colombier p = getbuf(file->fs->dev, file->addr, Brd); 1062*01a344a2SDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){ 1063*01a344a2SDavid du Colombier error = Ealloc; 1064*01a344a2SDavid du Colombier goto out; 1065*01a344a2SDavid du Colombier } 1066*01a344a2SDavid du Colombier d = getdir(p, file->slot); 1067*01a344a2SDavid du Colombier if(d == nil || !(d->mode & DALLOC)){ 1068*01a344a2SDavid du Colombier error = Ealloc; 1069*01a344a2SDavid du Colombier goto out; 1070*01a344a2SDavid du Colombier } 1071*01a344a2SDavid du Colombier } 1072*01a344a2SDavid du Colombier addr = offset / BUFSIZE; 1073*01a344a2SDavid du Colombier file->lastra = dbufread(p, d, addr, file->lastra, file->uid); 1074*01a344a2SDavid du Colombier o = offset % BUFSIZE; 1075*01a344a2SDavid du Colombier n = BUFSIZE - o; 1076*01a344a2SDavid du Colombier if(n > count) 1077*01a344a2SDavid du Colombier n = count; 1078*01a344a2SDavid du Colombier p1 = dnodebuf1(p, d, addr, 0, file->uid); 1079*01a344a2SDavid du Colombier p = nil; 1080*01a344a2SDavid du Colombier if(p1 != nil){ 1081*01a344a2SDavid du Colombier if(checktag(p1, Tfile, QPNONE)){ 1082*01a344a2SDavid du Colombier error = Ephase; 1083*01a344a2SDavid du Colombier putbuf(p1); 1084*01a344a2SDavid du Colombier goto out; 1085*01a344a2SDavid du Colombier } 1086*01a344a2SDavid du Colombier memmove(data+nread, p1->iobuf+o, n); 1087*01a344a2SDavid du Colombier putbuf(p1); 1088*01a344a2SDavid du Colombier } else 1089*01a344a2SDavid du Colombier memset(data+nread, 0, n); 1090*01a344a2SDavid du Colombier count -= n; 1091*01a344a2SDavid du Colombier nread += n; 1092*01a344a2SDavid du Colombier offset += n; 1093*01a344a2SDavid du Colombier } 1094*01a344a2SDavid du Colombier goto out; 1095*01a344a2SDavid du Colombier 1096*01a344a2SDavid du Colombier dread: 1097*01a344a2SDavid du Colombier /* 1098*01a344a2SDavid du Colombier * Pick up where we left off last time if nothing has changed, 1099*01a344a2SDavid du Colombier * otherwise must scan from the beginning. 1100*01a344a2SDavid du Colombier */ 1101*01a344a2SDavid du Colombier if(offset == file->doffset /*&& file->qid.vers == file->dvers*/){ 1102*01a344a2SDavid du Colombier addr = file->dslot/DIRPERBUF; 1103*01a344a2SDavid du Colombier slot = file->dslot%DIRPERBUF; 1104*01a344a2SDavid du Colombier start = offset; 1105*01a344a2SDavid du Colombier } else { 1106*01a344a2SDavid du Colombier addr = 0; 1107*01a344a2SDavid du Colombier slot = 0; 1108*01a344a2SDavid du Colombier start = 0; 1109*01a344a2SDavid du Colombier } 1110*01a344a2SDavid du Colombier 1111*01a344a2SDavid du Colombier dmb = mballoc(iounit, chan, Mbreply1); 1112*01a344a2SDavid du Colombier for (;;) { 1113*01a344a2SDavid du Colombier if(p == nil){ 1114*01a344a2SDavid du Colombier /* 1115*01a344a2SDavid du Colombier * This is just a check to ensure the entry hasn't 1116*01a344a2SDavid du Colombier * gone away during the read of each directory block. 1117*01a344a2SDavid du Colombier */ 1118*01a344a2SDavid du Colombier p = getbuf(file->fs->dev, file->addr, Brd); 1119*01a344a2SDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){ 1120*01a344a2SDavid du Colombier error = Ealloc; 1121*01a344a2SDavid du Colombier goto out1; 1122*01a344a2SDavid du Colombier } 1123*01a344a2SDavid du Colombier d = getdir(p, file->slot); 1124*01a344a2SDavid du Colombier if(d == nil || !(d->mode & DALLOC)){ 1125*01a344a2SDavid du Colombier error = Ealloc; 1126*01a344a2SDavid du Colombier goto out1; 1127*01a344a2SDavid du Colombier } 1128*01a344a2SDavid du Colombier } 1129*01a344a2SDavid du Colombier p1 = dnodebuf1(p, d, addr, 0, file->uid); 1130*01a344a2SDavid du Colombier p = nil; 1131*01a344a2SDavid du Colombier if(p1 == nil) 1132*01a344a2SDavid du Colombier goto out1; 1133*01a344a2SDavid du Colombier if(checktag(p1, Tdir, QPNONE)){ 1134*01a344a2SDavid du Colombier error = Ephase; 1135*01a344a2SDavid du Colombier putbuf(p1); 1136*01a344a2SDavid du Colombier goto out1; 1137*01a344a2SDavid du Colombier } 1138*01a344a2SDavid du Colombier 1139*01a344a2SDavid du Colombier for(; slot < DIRPERBUF; slot++){ 1140*01a344a2SDavid du Colombier d1 = getdir(p1, slot); 1141*01a344a2SDavid du Colombier if(!(d1->mode & DALLOC)) 1142*01a344a2SDavid du Colombier continue; 1143*01a344a2SDavid du Colombier mkdir9p2(&dir, d1, dmb->data); 1144*01a344a2SDavid du Colombier n = convD2M(&dir, data+nread, iounit - nread); 1145*01a344a2SDavid du Colombier if(n <= BIT16SZ){ 1146*01a344a2SDavid du Colombier putbuf(p1); 1147*01a344a2SDavid du Colombier goto out1; 1148*01a344a2SDavid du Colombier } 1149*01a344a2SDavid du Colombier start += n; 1150*01a344a2SDavid du Colombier if(start < offset) 1151*01a344a2SDavid du Colombier continue; 1152*01a344a2SDavid du Colombier if(count < n){ 1153*01a344a2SDavid du Colombier putbuf(p1); 1154*01a344a2SDavid du Colombier goto out1; 1155*01a344a2SDavid du Colombier } 1156*01a344a2SDavid du Colombier count -= n; 1157*01a344a2SDavid du Colombier nread += n; 1158*01a344a2SDavid du Colombier offset += n; 1159*01a344a2SDavid du Colombier } 1160*01a344a2SDavid du Colombier putbuf(p1); 1161*01a344a2SDavid du Colombier slot = 0; 1162*01a344a2SDavid du Colombier addr++; 1163*01a344a2SDavid du Colombier } 1164*01a344a2SDavid du Colombier out1: 1165*01a344a2SDavid du Colombier mbfree(dmb); 1166*01a344a2SDavid du Colombier if(error == 0){ 1167*01a344a2SDavid du Colombier file->doffset = offset; 1168*01a344a2SDavid du Colombier file->dvers = file->qid.vers; 1169*01a344a2SDavid du Colombier file->dslot = slot+DIRPERBUF*addr; 1170*01a344a2SDavid du Colombier } 1171*01a344a2SDavid du Colombier 1172*01a344a2SDavid du Colombier out: 1173*01a344a2SDavid du Colombier /* 1174*01a344a2SDavid du Colombier * Do we need this any more? 1175*01a344a2SDavid du Colombier count = f->count - nread; 1176*01a344a2SDavid du Colombier if(count > 0) 1177*01a344a2SDavid du Colombier memset(data+nread, 0, count); 1178*01a344a2SDavid du Colombier */ 1179*01a344a2SDavid du Colombier if(p != nil) 1180*01a344a2SDavid du Colombier putbuf(p); 1181*01a344a2SDavid du Colombier if(file != nil) 1182*01a344a2SDavid du Colombier qunlock(file); 1183*01a344a2SDavid du Colombier r->count = nread; 1184*01a344a2SDavid du Colombier r->data = (char*)data; 1185*01a344a2SDavid du Colombier 1186*01a344a2SDavid du Colombier return error; 1187*01a344a2SDavid du Colombier } 1188*01a344a2SDavid du Colombier 1189*01a344a2SDavid du Colombier static int 1190*01a344a2SDavid du Colombier fs_write(Chan* chan, Fcall* f, Fcall* r) 1191*01a344a2SDavid du Colombier { 1192*01a344a2SDavid du Colombier Iobuf *p, *p1; 1193*01a344a2SDavid du Colombier Dentry *d; 1194*01a344a2SDavid du Colombier File *file; 1195*01a344a2SDavid du Colombier Tlock *t; 1196*01a344a2SDavid du Colombier Off offset, addr, qpath; 1197*01a344a2SDavid du Colombier Timet tim; 1198*01a344a2SDavid du Colombier int count, error, nwrite, o, n; 1199*01a344a2SDavid du Colombier 1200*01a344a2SDavid du Colombier error = 0; 1201*01a344a2SDavid du Colombier offset = f->offset; 1202*01a344a2SDavid du Colombier count = f->count; 1203*01a344a2SDavid du Colombier 1204*01a344a2SDavid du Colombier nwrite = 0; 1205*01a344a2SDavid du Colombier p = nil; 1206*01a344a2SDavid du Colombier 1207*01a344a2SDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil){ 1208*01a344a2SDavid du Colombier error = Efid; 1209*01a344a2SDavid du Colombier goto out; 1210*01a344a2SDavid du Colombier } 1211*01a344a2SDavid du Colombier if(!(file->open & FWRITE)){ 1212*01a344a2SDavid du Colombier error = Eopen; 1213*01a344a2SDavid du Colombier goto out; 1214*01a344a2SDavid du Colombier } 1215*01a344a2SDavid du Colombier if(count < 0 || count > chan->msize-IOHDRSZ){ 1216*01a344a2SDavid du Colombier error = Ecount; 1217*01a344a2SDavid du Colombier goto out; 1218*01a344a2SDavid du Colombier } 1219*01a344a2SDavid du Colombier if(offset < 0) { 1220*01a344a2SDavid du Colombier error = Eoffset; 1221*01a344a2SDavid du Colombier goto out; 1222*01a344a2SDavid du Colombier } 1223*01a344a2SDavid du Colombier 1224*01a344a2SDavid du Colombier if(file->qid.type & QTAUTH){ 1225*01a344a2SDavid du Colombier nwrite = authwrite(file, (uchar*)f->data, count); 1226*01a344a2SDavid du Colombier if(nwrite < 0) 1227*01a344a2SDavid du Colombier error = Eauth2; 1228*01a344a2SDavid du Colombier goto out; 1229*01a344a2SDavid du Colombier } else if(file->fs->dev->type == Devro){ 1230*01a344a2SDavid du Colombier error = Eronly; 1231*01a344a2SDavid du Colombier goto out; 1232*01a344a2SDavid du Colombier } 1233*01a344a2SDavid du Colombier 1234*01a344a2SDavid du Colombier if ((p = getbuf(file->fs->dev, file->addr, Brd|Bmod)) == nil || 1235*01a344a2SDavid du Colombier (d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)) { 1236*01a344a2SDavid du Colombier error = Ealloc; 1237*01a344a2SDavid du Colombier goto out; 1238*01a344a2SDavid du Colombier } 1239*01a344a2SDavid du Colombier if(error = mkqidcmp(&file->qid, d)) 1240*01a344a2SDavid du Colombier goto out; 1241*01a344a2SDavid du Colombier if(t = file->tlock) { 1242*01a344a2SDavid du Colombier tim = toytime(); 1243*01a344a2SDavid du Colombier if(t->time < tim || t->file != file){ 1244*01a344a2SDavid du Colombier error = Ebroken; 1245*01a344a2SDavid du Colombier goto out; 1246*01a344a2SDavid du Colombier } 1247*01a344a2SDavid du Colombier /* renew the lock */ 1248*01a344a2SDavid du Colombier t->time = tim + TLOCK; 1249*01a344a2SDavid du Colombier } 1250*01a344a2SDavid du Colombier accessdir(p, d, FWRITE, file->uid); 1251*01a344a2SDavid du Colombier if(d->mode & DAPND) 1252*01a344a2SDavid du Colombier offset = d->size; 1253*01a344a2SDavid du Colombier if(offset+count > d->size) 1254*01a344a2SDavid du Colombier d->size = offset+count; 1255*01a344a2SDavid du Colombier while(count > 0){ 1256*01a344a2SDavid du Colombier if(p == nil){ 1257*01a344a2SDavid du Colombier p = getbuf(file->fs->dev, file->addr, Brd|Bmod); 1258*01a344a2SDavid du Colombier if(p == nil){ 1259*01a344a2SDavid du Colombier error = Ealloc; 1260*01a344a2SDavid du Colombier goto out; 1261*01a344a2SDavid du Colombier } 1262*01a344a2SDavid du Colombier d = getdir(p, file->slot); 1263*01a344a2SDavid du Colombier if(d == nil || !(d->mode & DALLOC)){ 1264*01a344a2SDavid du Colombier error = Ealloc; 1265*01a344a2SDavid du Colombier goto out; 1266*01a344a2SDavid du Colombier } 1267*01a344a2SDavid du Colombier } 1268*01a344a2SDavid du Colombier addr = offset / BUFSIZE; 1269*01a344a2SDavid du Colombier o = offset % BUFSIZE; 1270*01a344a2SDavid du Colombier n = BUFSIZE - o; 1271*01a344a2SDavid du Colombier if(n > count) 1272*01a344a2SDavid du Colombier n = count; 1273*01a344a2SDavid du Colombier qpath = d->qid.path; 1274*01a344a2SDavid du Colombier p1 = dnodebuf1(p, d, addr, Tfile, file->uid); 1275*01a344a2SDavid du Colombier p = nil; 1276*01a344a2SDavid du Colombier if(p1 == nil) { 1277*01a344a2SDavid du Colombier error = Efull; 1278*01a344a2SDavid du Colombier goto out; 1279*01a344a2SDavid du Colombier } 1280*01a344a2SDavid du Colombier if(checktag(p1, Tfile, qpath)){ 1281*01a344a2SDavid du Colombier putbuf(p1); 1282*01a344a2SDavid du Colombier error = Ephase; 1283*01a344a2SDavid du Colombier goto out; 1284*01a344a2SDavid du Colombier } 1285*01a344a2SDavid du Colombier memmove(p1->iobuf+o, f->data+nwrite, n); 1286*01a344a2SDavid du Colombier p1->flags |= Bmod; 1287*01a344a2SDavid du Colombier putbuf(p1); 1288*01a344a2SDavid du Colombier count -= n; 1289*01a344a2SDavid du Colombier nwrite += n; 1290*01a344a2SDavid du Colombier offset += n; 1291*01a344a2SDavid du Colombier } 1292*01a344a2SDavid du Colombier 1293*01a344a2SDavid du Colombier out: 1294*01a344a2SDavid du Colombier if(p != nil) 1295*01a344a2SDavid du Colombier putbuf(p); 1296*01a344a2SDavid du Colombier if(file != nil) 1297*01a344a2SDavid du Colombier qunlock(file); 1298*01a344a2SDavid du Colombier r->count = nwrite; 1299*01a344a2SDavid du Colombier 1300*01a344a2SDavid du Colombier return error; 1301*01a344a2SDavid du Colombier } 1302*01a344a2SDavid du Colombier 1303*01a344a2SDavid du Colombier static int 1304*01a344a2SDavid du Colombier _clunk(File* file, int remove, int wok) 1305*01a344a2SDavid du Colombier { 1306*01a344a2SDavid du Colombier Tlock *t; 1307*01a344a2SDavid du Colombier int error; 1308*01a344a2SDavid du Colombier 1309*01a344a2SDavid du Colombier error = 0; 1310*01a344a2SDavid du Colombier if(t = file->tlock){ 1311*01a344a2SDavid du Colombier if(t->file == file) 1312*01a344a2SDavid du Colombier t->time = 0; /* free the lock */ 1313*01a344a2SDavid du Colombier file->tlock = 0; 1314*01a344a2SDavid du Colombier } 1315*01a344a2SDavid du Colombier if(remove && (file->qid.type & QTAUTH) == 0) 1316*01a344a2SDavid du Colombier error = doremove(file, wok); 1317*01a344a2SDavid du Colombier file->open = 0; 1318*01a344a2SDavid du Colombier freewp(file->wpath); 1319*01a344a2SDavid du Colombier authfree(file->auth); 1320*01a344a2SDavid du Colombier freefp(file); 1321*01a344a2SDavid du Colombier qunlock(file); 1322*01a344a2SDavid du Colombier 1323*01a344a2SDavid du Colombier return error; 1324*01a344a2SDavid du Colombier } 1325*01a344a2SDavid du Colombier 1326*01a344a2SDavid du Colombier static int 1327*01a344a2SDavid du Colombier clunk(Chan* chan, Fcall* f, Fcall*) 1328*01a344a2SDavid du Colombier { 1329*01a344a2SDavid du Colombier File *file; 1330*01a344a2SDavid du Colombier 1331*01a344a2SDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil) 1332*01a344a2SDavid du Colombier return Efid; 1333*01a344a2SDavid du Colombier 1334*01a344a2SDavid du Colombier _clunk(file, file->open & FREMOV, 0); 1335*01a344a2SDavid du Colombier return 0; 1336*01a344a2SDavid du Colombier } 1337*01a344a2SDavid du Colombier 1338*01a344a2SDavid du Colombier static int 1339*01a344a2SDavid du Colombier fs_remove(Chan* chan, Fcall* f, Fcall*) 1340*01a344a2SDavid du Colombier { 1341*01a344a2SDavid du Colombier File *file; 1342*01a344a2SDavid du Colombier 1343*01a344a2SDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil) 1344*01a344a2SDavid du Colombier return Efid; 1345*01a344a2SDavid du Colombier 1346*01a344a2SDavid du Colombier return _clunk(file, 1, chan == cons.chan); 1347*01a344a2SDavid du Colombier } 1348*01a344a2SDavid du Colombier 1349*01a344a2SDavid du Colombier static int 1350*01a344a2SDavid du Colombier fs_stat(Chan* chan, Fcall* f, Fcall* r, uchar* data) 1351*01a344a2SDavid du Colombier { 1352*01a344a2SDavid du Colombier Dir dir; 1353*01a344a2SDavid du Colombier Iobuf *p; 1354*01a344a2SDavid du Colombier Dentry *d, dentry; 1355*01a344a2SDavid du Colombier File *file; 1356*01a344a2SDavid du Colombier int error, len; 1357*01a344a2SDavid du Colombier 1358*01a344a2SDavid du Colombier error = 0; 1359*01a344a2SDavid du Colombier p = nil; 1360*01a344a2SDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil) 1361*01a344a2SDavid du Colombier return Efid; 1362*01a344a2SDavid du Colombier if(file->qid.type & QTAUTH){ 1363*01a344a2SDavid du Colombier memset(&dentry, 0, sizeof dentry); 1364*01a344a2SDavid du Colombier d = &dentry; 1365*01a344a2SDavid du Colombier mkqid9p1(&d->qid, &file->qid); 1366*01a344a2SDavid du Colombier strcpy(d->name, "#¿"); 1367*01a344a2SDavid du Colombier d->uid = authuid(file->auth); 1368*01a344a2SDavid du Colombier d->gid = d->uid; 1369*01a344a2SDavid du Colombier d->muid = d->uid; 1370*01a344a2SDavid du Colombier d->atime = time(nil); 1371*01a344a2SDavid du Colombier d->mtime = d->atime; 1372*01a344a2SDavid du Colombier d->size = 0; 1373*01a344a2SDavid du Colombier } else { 1374*01a344a2SDavid du Colombier p = getbuf(file->fs->dev, file->addr, Brd); 1375*01a344a2SDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){ 1376*01a344a2SDavid du Colombier error = Edir1; 1377*01a344a2SDavid du Colombier goto out; 1378*01a344a2SDavid du Colombier } 1379*01a344a2SDavid du Colombier d = getdir(p, file->slot); 1380*01a344a2SDavid du Colombier if(d == nil || !(d->mode & DALLOC)){ 1381*01a344a2SDavid du Colombier error = Ealloc; 1382*01a344a2SDavid du Colombier goto out; 1383*01a344a2SDavid du Colombier } 1384*01a344a2SDavid du Colombier if(error = mkqidcmp(&file->qid, d)) 1385*01a344a2SDavid du Colombier goto out; 1386*01a344a2SDavid du Colombier 1387*01a344a2SDavid du Colombier if(d->qid.path == QPROOT) /* stat of root gives time */ 1388*01a344a2SDavid du Colombier d->atime = time(nil); 1389*01a344a2SDavid du Colombier } 1390*01a344a2SDavid du Colombier len = mkdir9p2(&dir, d, data); 1391*01a344a2SDavid du Colombier data += len; 1392*01a344a2SDavid du Colombier 1393*01a344a2SDavid du Colombier if((r->nstat = convD2M(&dir, data, chan->msize - len)) == 0) 1394*01a344a2SDavid du Colombier error = Eedge; 1395*01a344a2SDavid du Colombier r->stat = data; 1396*01a344a2SDavid du Colombier 1397*01a344a2SDavid du Colombier out: 1398*01a344a2SDavid du Colombier if(p != nil) 1399*01a344a2SDavid du Colombier putbuf(p); 1400*01a344a2SDavid du Colombier if(file != nil) 1401*01a344a2SDavid du Colombier qunlock(file); 1402*01a344a2SDavid du Colombier 1403*01a344a2SDavid du Colombier return error; 1404*01a344a2SDavid du Colombier } 1405*01a344a2SDavid du Colombier 1406*01a344a2SDavid du Colombier static int 1407*01a344a2SDavid du Colombier fs_wstat(Chan* chan, Fcall* f, Fcall*, char* strs) 1408*01a344a2SDavid du Colombier { 1409*01a344a2SDavid du Colombier Iobuf *p, *p1; 1410*01a344a2SDavid du Colombier Dentry *d, *d1; 1411*01a344a2SDavid du Colombier File *file; 1412*01a344a2SDavid du Colombier int error, err, gid, gl, muid, op, slot, tsync, uid; 1413*01a344a2SDavid du Colombier long addr; 1414*01a344a2SDavid du Colombier Dir dir; 1415*01a344a2SDavid du Colombier 1416*01a344a2SDavid du Colombier if(convM2D(f->stat, f->nstat, &dir, strs) == 0) 1417*01a344a2SDavid du Colombier return Econvert; 1418*01a344a2SDavid du Colombier 1419*01a344a2SDavid du Colombier /* 1420*01a344a2SDavid du Colombier * Get the file. 1421*01a344a2SDavid du Colombier * If user 'none' (uid == 0), can't do anything; 1422*01a344a2SDavid du Colombier * if filesystem is read-only, can't change anything. 1423*01a344a2SDavid du Colombier */ 1424*01a344a2SDavid du Colombier if((file = filep(chan, f->fid, 0)) == nil) 1425*01a344a2SDavid du Colombier return Efid; 1426*01a344a2SDavid du Colombier p = p1 = nil; 1427*01a344a2SDavid du Colombier if(file->uid == 0){ 1428*01a344a2SDavid du Colombier error = Eaccess; 1429*01a344a2SDavid du Colombier goto out; 1430*01a344a2SDavid du Colombier } 1431*01a344a2SDavid du Colombier if(file->fs->dev->type == Devro){ 1432*01a344a2SDavid du Colombier error = Eronly; 1433*01a344a2SDavid du Colombier goto out; 1434*01a344a2SDavid du Colombier } 1435*01a344a2SDavid du Colombier if(file->qid.type & QTAUTH){ 1436*01a344a2SDavid du Colombier error = Emode; 1437*01a344a2SDavid du Colombier goto out; 1438*01a344a2SDavid du Colombier } 1439*01a344a2SDavid du Colombier 1440*01a344a2SDavid du Colombier /* 1441*01a344a2SDavid du Colombier * Get the current entry and check it is still valid. 1442*01a344a2SDavid du Colombier */ 1443*01a344a2SDavid du Colombier p = getbuf(file->fs->dev, file->addr, Brd); 1444*01a344a2SDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){ 1445*01a344a2SDavid du Colombier error = Ealloc; 1446*01a344a2SDavid du Colombier goto out; 1447*01a344a2SDavid du Colombier } 1448*01a344a2SDavid du Colombier d = getdir(p, file->slot); 1449*01a344a2SDavid du Colombier if(d == nil || !(d->mode & DALLOC)){ 1450*01a344a2SDavid du Colombier error = Ealloc; 1451*01a344a2SDavid du Colombier goto out; 1452*01a344a2SDavid du Colombier } 1453*01a344a2SDavid du Colombier if(error = mkqidcmp(&file->qid, d)) 1454*01a344a2SDavid du Colombier goto out; 1455*01a344a2SDavid du Colombier 1456*01a344a2SDavid du Colombier /* 1457*01a344a2SDavid du Colombier * Run through each of the (sub-)fields in the provided Dir 1458*01a344a2SDavid du Colombier * checking for validity and whether it's a default: 1459*01a344a2SDavid du Colombier * .type, .dev and .atime are completely ignored and not checked; 1460*01a344a2SDavid du Colombier * .qid.path, .qid.vers and .muid are checked for validity but 1461*01a344a2SDavid du Colombier * any attempt to change them is an error. 1462*01a344a2SDavid du Colombier * .qid.type/.mode, .mtime, .name, .length, .uid and .gid can 1463*01a344a2SDavid du Colombier * possibly be changed. 1464*01a344a2SDavid du Colombier * 1465*01a344a2SDavid du Colombier * 'Op' flags there are changed fields, i.e. it's not a no-op. 1466*01a344a2SDavid du Colombier * 'Tsync' flags all fields are defaulted. 1467*01a344a2SDavid du Colombier * 1468*01a344a2SDavid du Colombier * Wstatallow and writeallow are set to allow changes during the 1469*01a344a2SDavid du Colombier * fileserver bootstrap phase. 1470*01a344a2SDavid du Colombier */ 1471*01a344a2SDavid du Colombier tsync = 1; 1472*01a344a2SDavid du Colombier if(dir.qid.path != ~0){ 1473*01a344a2SDavid du Colombier if(dir.qid.path != file->qid.path){ 1474*01a344a2SDavid du Colombier error = Ewstatp; 1475*01a344a2SDavid du Colombier goto out; 1476*01a344a2SDavid du Colombier } 1477*01a344a2SDavid du Colombier tsync = 0; 1478*01a344a2SDavid du Colombier } 1479*01a344a2SDavid du Colombier if(dir.qid.vers != ~0){ 1480*01a344a2SDavid du Colombier if(dir.qid.vers != file->qid.vers){ 1481*01a344a2SDavid du Colombier error = Ewstatv; 1482*01a344a2SDavid du Colombier goto out; 1483*01a344a2SDavid du Colombier } 1484*01a344a2SDavid du Colombier tsync = 0; 1485*01a344a2SDavid du Colombier } 1486*01a344a2SDavid du Colombier if(dir.muid != nil && *dir.muid != '\0'){ 1487*01a344a2SDavid du Colombier muid = strtouid(dir.muid); 1488*01a344a2SDavid du Colombier if(muid != d->muid && !wstatallow){ 1489*01a344a2SDavid du Colombier error = Ewstatm; 1490*01a344a2SDavid du Colombier goto out; 1491*01a344a2SDavid du Colombier } 1492*01a344a2SDavid du Colombier tsync = 0; 1493*01a344a2SDavid du Colombier } 1494*01a344a2SDavid du Colombier 1495*01a344a2SDavid du Colombier /* 1496*01a344a2SDavid du Colombier * .qid.type and .mode have some bits in common. Only .mode 1497*01a344a2SDavid du Colombier * is currently needed for comparisons with the old mode but 1498*01a344a2SDavid du Colombier * if there are changes to the bits also encoded in .qid.type 1499*01a344a2SDavid du Colombier * then file->qid must be updated appropriately later. 1500*01a344a2SDavid du Colombier */ 1501*01a344a2SDavid du Colombier if(dir.qid.type == (uchar)~0){ 1502*01a344a2SDavid du Colombier if(dir.mode == ~0) 1503*01a344a2SDavid du Colombier dir.qid.type = mktype9p2(d->mode); 1504*01a344a2SDavid du Colombier else 1505*01a344a2SDavid du Colombier dir.qid.type = dir.mode>>24; 1506*01a344a2SDavid du Colombier } else 1507*01a344a2SDavid du Colombier tsync = 0; 1508*01a344a2SDavid du Colombier if(dir.mode == ~0) 1509*01a344a2SDavid du Colombier dir.mode = mkmode9p2(d->mode); 1510*01a344a2SDavid du Colombier else 1511*01a344a2SDavid du Colombier tsync = 0; 1512*01a344a2SDavid du Colombier 1513*01a344a2SDavid du Colombier /* 1514*01a344a2SDavid du Colombier * Check dir.qid.type and dir.mode agree, check for any unknown 1515*01a344a2SDavid du Colombier * type/mode bits, check for an attempt to change the directory bit. 1516*01a344a2SDavid du Colombier */ 1517*01a344a2SDavid du Colombier if(dir.qid.type != ((dir.mode>>24) & 0xFF)){ 1518*01a344a2SDavid du Colombier error = Ewstatq; 1519*01a344a2SDavid du Colombier goto out; 1520*01a344a2SDavid du Colombier } 1521*01a344a2SDavid du Colombier if(dir.mode & ~(DMDIR|DMAPPEND|DMEXCL|0777)){ 1522*01a344a2SDavid du Colombier error = Ewstatb; 1523*01a344a2SDavid du Colombier goto out; 1524*01a344a2SDavid du Colombier } 1525*01a344a2SDavid du Colombier 1526*01a344a2SDavid du Colombier op = dir.mode^mkmode9p2(d->mode); 1527*01a344a2SDavid du Colombier if(op & DMDIR){ 1528*01a344a2SDavid du Colombier error = Ewstatd; 1529*01a344a2SDavid du Colombier goto out; 1530*01a344a2SDavid du Colombier } 1531*01a344a2SDavid du Colombier 1532*01a344a2SDavid du Colombier if(dir.mtime != ~0){ 1533*01a344a2SDavid du Colombier if(dir.mtime != d->mtime) 1534*01a344a2SDavid du Colombier op = 1; 1535*01a344a2SDavid du Colombier tsync = 0; 1536*01a344a2SDavid du Colombier } else 1537*01a344a2SDavid du Colombier dir.mtime = d->mtime; 1538*01a344a2SDavid du Colombier 1539*01a344a2SDavid du Colombier if(dir.length == ~(Off)0) 1540*01a344a2SDavid du Colombier dir.length = d->size; 1541*01a344a2SDavid du Colombier else { 1542*01a344a2SDavid du Colombier if (dir.length < 0) { 1543*01a344a2SDavid du Colombier error = Ewstatl; 1544*01a344a2SDavid du Colombier goto out; 1545*01a344a2SDavid du Colombier } else if(dir.length != d->size) 1546*01a344a2SDavid du Colombier op = 1; 1547*01a344a2SDavid du Colombier tsync = 0; 1548*01a344a2SDavid du Colombier } 1549*01a344a2SDavid du Colombier 1550*01a344a2SDavid du Colombier /* 1551*01a344a2SDavid du Colombier * Check for permission to change .mode, .mtime or .length, 1552*01a344a2SDavid du Colombier * must be owner or leader of either group, for which test gid 1553*01a344a2SDavid du Colombier * is needed; permission checks on gid will be done later. 1554*01a344a2SDavid du Colombier * 'Gl' counts whether neither, one or both groups are led. 1555*01a344a2SDavid du Colombier */ 1556*01a344a2SDavid du Colombier if(dir.gid != nil && *dir.gid != '\0'){ 1557*01a344a2SDavid du Colombier gid = strtouid(dir.gid); 1558*01a344a2SDavid du Colombier tsync = 0; 1559*01a344a2SDavid du Colombier } else 1560*01a344a2SDavid du Colombier gid = d->gid; 1561*01a344a2SDavid du Colombier gl = leadgroup(file->uid, gid) != 0; 1562*01a344a2SDavid du Colombier gl += leadgroup(file->uid, d->gid) != 0; 1563*01a344a2SDavid du Colombier 1564*01a344a2SDavid du Colombier if(op && !wstatallow && d->uid != file->uid && !gl){ 1565*01a344a2SDavid du Colombier error = Ewstato; 1566*01a344a2SDavid du Colombier goto out; 1567*01a344a2SDavid du Colombier } 1568*01a344a2SDavid du Colombier 1569*01a344a2SDavid du Colombier /* 1570*01a344a2SDavid du Colombier * Rename. 1571*01a344a2SDavid du Colombier * Check .name is valid and different to the current. 1572*01a344a2SDavid du Colombier */ 1573*01a344a2SDavid du Colombier if(dir.name != nil && *dir.name != '\0'){ 1574*01a344a2SDavid du Colombier if(error = checkname9p2(dir.name)) 1575*01a344a2SDavid du Colombier goto out; 1576*01a344a2SDavid du Colombier if(strncmp(dir.name, d->name, NAMELEN)) 1577*01a344a2SDavid du Colombier op = 1; 1578*01a344a2SDavid du Colombier else 1579*01a344a2SDavid du Colombier dir.name = d->name; 1580*01a344a2SDavid du Colombier tsync = 0; 1581*01a344a2SDavid du Colombier } else 1582*01a344a2SDavid du Colombier dir.name = d->name; 1583*01a344a2SDavid du Colombier 1584*01a344a2SDavid du Colombier /* 1585*01a344a2SDavid du Colombier * If the name is really to be changed check it's unique 1586*01a344a2SDavid du Colombier * and there is write permission in the parent. 1587*01a344a2SDavid du Colombier */ 1588*01a344a2SDavid du Colombier if(dir.name != d->name){ 1589*01a344a2SDavid du Colombier /* 1590*01a344a2SDavid du Colombier * First get parent. 1591*01a344a2SDavid du Colombier * Must drop current entry to prevent 1592*01a344a2SDavid du Colombier * deadlock when searching that new name 1593*01a344a2SDavid du Colombier * already exists below. 1594*01a344a2SDavid du Colombier */ 1595*01a344a2SDavid du Colombier putbuf(p); 1596*01a344a2SDavid du Colombier p = nil; 1597*01a344a2SDavid du Colombier 1598*01a344a2SDavid du Colombier if(file->wpath == nil){ 1599*01a344a2SDavid du Colombier error = Ephase; 1600*01a344a2SDavid du Colombier goto out; 1601*01a344a2SDavid du Colombier } 1602*01a344a2SDavid du Colombier p1 = getbuf(file->fs->dev, file->wpath->addr, Brd); 1603*01a344a2SDavid du Colombier if(p1 == nil || checktag(p1, Tdir, QPNONE)){ 1604*01a344a2SDavid du Colombier error = Ephase; 1605*01a344a2SDavid du Colombier goto out; 1606*01a344a2SDavid du Colombier } 1607*01a344a2SDavid du Colombier d1 = getdir(p1, file->wpath->slot); 1608*01a344a2SDavid du Colombier if(d1 == nil || !(d1->mode & DALLOC)){ 1609*01a344a2SDavid du Colombier error = Ephase; 1610*01a344a2SDavid du Colombier goto out; 1611*01a344a2SDavid du Colombier } 1612*01a344a2SDavid du Colombier 1613*01a344a2SDavid du Colombier /* 1614*01a344a2SDavid du Colombier * Check entries in parent for new name. 1615*01a344a2SDavid du Colombier */ 1616*01a344a2SDavid du Colombier for(addr = 0; ; addr++){ 1617*01a344a2SDavid du Colombier if((p = dnodebuf(p1, d1, addr, 0, file->uid)) == nil) 1618*01a344a2SDavid du Colombier break; 1619*01a344a2SDavid du Colombier if(checktag(p, Tdir, d1->qid.path)){ 1620*01a344a2SDavid du Colombier putbuf(p); 1621*01a344a2SDavid du Colombier continue; 1622*01a344a2SDavid du Colombier } 1623*01a344a2SDavid du Colombier for(slot = 0; slot < DIRPERBUF; slot++){ 1624*01a344a2SDavid du Colombier d = getdir(p, slot); 1625*01a344a2SDavid du Colombier if(!(d->mode & DALLOC) || 1626*01a344a2SDavid du Colombier strncmp(dir.name, d->name, sizeof d->name)) 1627*01a344a2SDavid du Colombier continue; 1628*01a344a2SDavid du Colombier error = Eexist; 1629*01a344a2SDavid du Colombier goto out; 1630*01a344a2SDavid du Colombier } 1631*01a344a2SDavid du Colombier putbuf(p); 1632*01a344a2SDavid du Colombier } 1633*01a344a2SDavid du Colombier 1634*01a344a2SDavid du Colombier /* 1635*01a344a2SDavid du Colombier * Reacquire entry and check it's still OK. 1636*01a344a2SDavid du Colombier */ 1637*01a344a2SDavid du Colombier p = getbuf(file->fs->dev, file->addr, Brd); 1638*01a344a2SDavid du Colombier if(p == nil || checktag(p, Tdir, QPNONE)){ 1639*01a344a2SDavid du Colombier error = Ephase; 1640*01a344a2SDavid du Colombier goto out; 1641*01a344a2SDavid du Colombier } 1642*01a344a2SDavid du Colombier d = getdir(p, file->slot); 1643*01a344a2SDavid du Colombier if(d == nil || !(d->mode & DALLOC)){ 1644*01a344a2SDavid du Colombier error = Ephase; 1645*01a344a2SDavid du Colombier goto out; 1646*01a344a2SDavid du Colombier } 1647*01a344a2SDavid du Colombier 1648*01a344a2SDavid du Colombier /* 1649*01a344a2SDavid du Colombier * Check write permission in the parent. 1650*01a344a2SDavid du Colombier */ 1651*01a344a2SDavid du Colombier if(!wstatallow && !writeallow && iaccess(file, d1, DWRITE)){ 1652*01a344a2SDavid du Colombier error = Eaccess; 1653*01a344a2SDavid du Colombier goto out; 1654*01a344a2SDavid du Colombier } 1655*01a344a2SDavid du Colombier } 1656*01a344a2SDavid du Colombier 1657*01a344a2SDavid du Colombier /* 1658*01a344a2SDavid du Colombier * Check for permission to change owner - must be god. 1659*01a344a2SDavid du Colombier */ 1660*01a344a2SDavid du Colombier if(dir.uid != nil && *dir.uid != '\0'){ 1661*01a344a2SDavid du Colombier uid = strtouid(dir.uid); 1662*01a344a2SDavid du Colombier if(uid != d->uid){ 1663*01a344a2SDavid du Colombier if(!wstatallow){ 1664*01a344a2SDavid du Colombier error = Ewstatu; 1665*01a344a2SDavid du Colombier goto out; 1666*01a344a2SDavid du Colombier } 1667*01a344a2SDavid du Colombier op = 1; 1668*01a344a2SDavid du Colombier } 1669*01a344a2SDavid du Colombier tsync = 0; 1670*01a344a2SDavid du Colombier } else 1671*01a344a2SDavid du Colombier uid = d->uid; 1672*01a344a2SDavid du Colombier 1673*01a344a2SDavid du Colombier /* 1674*01a344a2SDavid du Colombier * Check for permission to change group, must be 1675*01a344a2SDavid du Colombier * either owner and in new group or leader of both groups. 1676*01a344a2SDavid du Colombier */ 1677*01a344a2SDavid du Colombier if(gid != d->gid){ 1678*01a344a2SDavid du Colombier if(!(wstatallow || writeallow) 1679*01a344a2SDavid du Colombier && !(d->uid == file->uid && ingroup(file->uid, gid)) 1680*01a344a2SDavid du Colombier && !(gl == 2)){ 1681*01a344a2SDavid du Colombier error = Ewstatg; 1682*01a344a2SDavid du Colombier goto out; 1683*01a344a2SDavid du Colombier } 1684*01a344a2SDavid du Colombier op = 1; 1685*01a344a2SDavid du Colombier } 1686*01a344a2SDavid du Colombier 1687*01a344a2SDavid du Colombier /* 1688*01a344a2SDavid du Colombier * Checks all done, update if necessary. 1689*01a344a2SDavid du Colombier */ 1690*01a344a2SDavid du Colombier if(op){ 1691*01a344a2SDavid du Colombier d->mode = mkmode9p1(dir.mode); 1692*01a344a2SDavid du Colombier file->qid.type = mktype9p2(d->mode); 1693*01a344a2SDavid du Colombier d->mtime = dir.mtime; 1694*01a344a2SDavid du Colombier if (dir.length < d->size) { 1695*01a344a2SDavid du Colombier err = dtrunclen(p, d, dir.length, uid); 1696*01a344a2SDavid du Colombier if (error == 0) 1697*01a344a2SDavid du Colombier error = err; 1698*01a344a2SDavid du Colombier } 1699*01a344a2SDavid du Colombier d->size = dir.length; 1700*01a344a2SDavid du Colombier if(dir.name != d->name) 1701*01a344a2SDavid du Colombier strncpy(d->name, dir.name, sizeof(d->name)); 1702*01a344a2SDavid du Colombier d->uid = uid; 1703*01a344a2SDavid du Colombier d->gid = gid; 1704*01a344a2SDavid du Colombier } 1705*01a344a2SDavid du Colombier if(!tsync) 1706*01a344a2SDavid du Colombier accessdir(p, d, FREAD, file->uid); 1707*01a344a2SDavid du Colombier 1708*01a344a2SDavid du Colombier out: 1709*01a344a2SDavid du Colombier if(p != nil) 1710*01a344a2SDavid du Colombier putbuf(p); 1711*01a344a2SDavid du Colombier if(p1 != nil) 1712*01a344a2SDavid du Colombier putbuf(p1); 1713*01a344a2SDavid du Colombier qunlock(file); 1714*01a344a2SDavid du Colombier 1715*01a344a2SDavid du Colombier return error; 1716*01a344a2SDavid du Colombier } 1717*01a344a2SDavid du Colombier 1718*01a344a2SDavid du Colombier int 1719*01a344a2SDavid du Colombier serve9p2(Msgbuf* mb) 1720*01a344a2SDavid du Colombier { 1721*01a344a2SDavid du Colombier Chan *chan; 1722*01a344a2SDavid du Colombier Fcall f, r; 1723*01a344a2SDavid du Colombier Msgbuf *data, *rmb; 1724*01a344a2SDavid du Colombier char ename[64]; 1725*01a344a2SDavid du Colombier int error, n, type; 1726*01a344a2SDavid du Colombier static int once; 1727*01a344a2SDavid du Colombier 1728*01a344a2SDavid du Colombier if(once == 0){ 1729*01a344a2SDavid du Colombier fmtinstall('F', fcallfmt); 1730*01a344a2SDavid du Colombier once = 1; 1731*01a344a2SDavid du Colombier } 1732*01a344a2SDavid du Colombier 1733*01a344a2SDavid du Colombier /* 1734*01a344a2SDavid du Colombier * 0 return means i don't understand this message, 1735*01a344a2SDavid du Colombier * 1 return means i dealt with it, including error 1736*01a344a2SDavid du Colombier * replies. 1737*01a344a2SDavid du Colombier */ 1738*01a344a2SDavid du Colombier if(convM2S(mb->data, mb->count, &f) != mb->count) 1739*01a344a2SDavid du Colombier { 1740*01a344a2SDavid du Colombier print("didn't like %d byte message\n", mb->count); 1741*01a344a2SDavid du Colombier return 0; 1742*01a344a2SDavid du Colombier } 1743*01a344a2SDavid du Colombier type = f.type; 1744*01a344a2SDavid du Colombier if(type < Tversion || type >= Tmax || (type & 1) || type == Terror) 1745*01a344a2SDavid du Colombier return 0; 1746*01a344a2SDavid du Colombier 1747*01a344a2SDavid du Colombier chan = mb->chan; 1748*01a344a2SDavid du Colombier if(CHAT(chan)) 1749*01a344a2SDavid du Colombier print("9p2: f %F\n", &f); 1750*01a344a2SDavid du Colombier r.type = type+1; 1751*01a344a2SDavid du Colombier r.tag = f.tag; 1752*01a344a2SDavid du Colombier error = 0; 1753*01a344a2SDavid du Colombier data = nil; 1754*01a344a2SDavid du Colombier 1755*01a344a2SDavid du Colombier switch(type){ 1756*01a344a2SDavid du Colombier default: 1757*01a344a2SDavid du Colombier r.type = Rerror; 1758*01a344a2SDavid du Colombier snprint(ename, sizeof(ename), "unknown message: %F", &f); 1759*01a344a2SDavid du Colombier r.ename = ename; 1760*01a344a2SDavid du Colombier break; 1761*01a344a2SDavid du Colombier case Tversion: 1762*01a344a2SDavid du Colombier error = version(chan, &f, &r); 1763*01a344a2SDavid du Colombier break; 1764*01a344a2SDavid du Colombier case Tauth: 1765*01a344a2SDavid du Colombier error = auth(chan, &f, &r); 1766*01a344a2SDavid du Colombier break; 1767*01a344a2SDavid du Colombier case Tattach: 1768*01a344a2SDavid du Colombier error = attach(chan, &f, &r); 1769*01a344a2SDavid du Colombier break; 1770*01a344a2SDavid du Colombier case Tflush: 1771*01a344a2SDavid du Colombier error = flush(chan, &f, &r); 1772*01a344a2SDavid du Colombier break; 1773*01a344a2SDavid du Colombier case Twalk: 1774*01a344a2SDavid du Colombier error = walk(chan, &f, &r); 1775*01a344a2SDavid du Colombier break; 1776*01a344a2SDavid du Colombier case Topen: 1777*01a344a2SDavid du Colombier error = fs_open(chan, &f, &r); 1778*01a344a2SDavid du Colombier break; 1779*01a344a2SDavid du Colombier case Tcreate: 1780*01a344a2SDavid du Colombier error = fs_create(chan, &f, &r); 1781*01a344a2SDavid du Colombier break; 1782*01a344a2SDavid du Colombier case Tread: 1783*01a344a2SDavid du Colombier data = mballoc(chan->msize, chan, Mbreply1); 1784*01a344a2SDavid du Colombier error = fs_read(chan, &f, &r, data->data); 1785*01a344a2SDavid du Colombier break; 1786*01a344a2SDavid du Colombier case Twrite: 1787*01a344a2SDavid du Colombier error = fs_write(chan, &f, &r); 1788*01a344a2SDavid du Colombier break; 1789*01a344a2SDavid du Colombier case Tclunk: 1790*01a344a2SDavid du Colombier error = clunk(chan, &f, &r); 1791*01a344a2SDavid du Colombier break; 1792*01a344a2SDavid du Colombier case Tremove: 1793*01a344a2SDavid du Colombier error = fs_remove(chan, &f, &r); 1794*01a344a2SDavid du Colombier break; 1795*01a344a2SDavid du Colombier case Tstat: 1796*01a344a2SDavid du Colombier data = mballoc(chan->msize, chan, Mbreply1); 1797*01a344a2SDavid du Colombier error = fs_stat(chan, &f, &r, data->data); 1798*01a344a2SDavid du Colombier break; 1799*01a344a2SDavid du Colombier case Twstat: 1800*01a344a2SDavid du Colombier data = mballoc(chan->msize, chan, Mbreply1); 1801*01a344a2SDavid du Colombier error = fs_wstat(chan, &f, &r, (char*)data->data); 1802*01a344a2SDavid du Colombier break; 1803*01a344a2SDavid du Colombier } 1804*01a344a2SDavid du Colombier 1805*01a344a2SDavid du Colombier if(error != 0){ 1806*01a344a2SDavid du Colombier r.type = Rerror; 1807*01a344a2SDavid du Colombier if(error >= MAXERR){ 1808*01a344a2SDavid du Colombier snprint(ename, sizeof(ename), "error %d", error); 1809*01a344a2SDavid du Colombier r.ename = ename; 1810*01a344a2SDavid du Colombier } else 1811*01a344a2SDavid du Colombier r.ename = errstr9p[error]; 1812*01a344a2SDavid du Colombier } 1813*01a344a2SDavid du Colombier if(CHAT(chan)) 1814*01a344a2SDavid du Colombier print("9p2: r %F\n", &r); 1815*01a344a2SDavid du Colombier 1816*01a344a2SDavid du Colombier rmb = mballoc(chan->msize, chan, Mbreply2); 1817*01a344a2SDavid du Colombier n = convS2M(&r, rmb->data, chan->msize); 1818*01a344a2SDavid du Colombier if(data != nil) 1819*01a344a2SDavid du Colombier mbfree(data); 1820*01a344a2SDavid du Colombier if(n == 0){ 1821*01a344a2SDavid du Colombier type = r.type; 1822*01a344a2SDavid du Colombier r.type = Rerror; 1823*01a344a2SDavid du Colombier 1824*01a344a2SDavid du Colombier /* 1825*01a344a2SDavid du Colombier * If a Tversion has not been seen on the chan then 1826*01a344a2SDavid du Colombier * chan->msize will be 0. In that case craft a special 1827*01a344a2SDavid du Colombier * Rerror message. It's fortunate that the mballoc above 1828*01a344a2SDavid du Colombier * for rmb will have returned a Msgbuf of MAXMSG size 1829*01a344a2SDavid du Colombier * when given a request with count of 0... 1830*01a344a2SDavid du Colombier */ 1831*01a344a2SDavid du Colombier if(chan->msize == 0){ 1832*01a344a2SDavid du Colombier r.ename = "Tversion not seen"; 1833*01a344a2SDavid du Colombier n = convS2M(&r, rmb->data, MAXMSG); 1834*01a344a2SDavid du Colombier } else { 1835*01a344a2SDavid du Colombier snprint(ename, sizeof(ename), "9p2: convS2M: type %d", 1836*01a344a2SDavid du Colombier type); 1837*01a344a2SDavid du Colombier r.ename = ename; 1838*01a344a2SDavid du Colombier n = convS2M(&r, rmb->data, chan->msize); 1839*01a344a2SDavid du Colombier } 1840*01a344a2SDavid du Colombier print("%s\n", r.ename); 1841*01a344a2SDavid du Colombier if(n == 0){ 1842*01a344a2SDavid du Colombier /* 1843*01a344a2SDavid du Colombier * What to do here, the failure notification failed? 1844*01a344a2SDavid du Colombier */ 1845*01a344a2SDavid du Colombier mbfree(rmb); 1846*01a344a2SDavid du Colombier return 1; 1847*01a344a2SDavid du Colombier } 1848*01a344a2SDavid du Colombier } 1849*01a344a2SDavid du Colombier rmb->count = n; 1850*01a344a2SDavid du Colombier rmb->param = mb->param; 1851*01a344a2SDavid du Colombier 1852*01a344a2SDavid du Colombier /* done 9P processing, write reply to network */ 1853*01a344a2SDavid du Colombier fs_send(chan->reply, rmb); 1854*01a344a2SDavid du Colombier 1855*01a344a2SDavid du Colombier return 1; 1856*01a344a2SDavid du Colombier } 1857