15e96a66cSDavid du Colombier #include "stdinc.h" 25e96a66cSDavid du Colombier 35e96a66cSDavid du Colombier #include "9.h" 45e96a66cSDavid du Colombier 55e96a66cSDavid du Colombier enum { 65e96a66cSDavid du Colombier OMODE = 0x7, /* Topen/Tcreate mode */ 75e96a66cSDavid du Colombier }; 85e96a66cSDavid du Colombier 95e96a66cSDavid du Colombier enum { 105e96a66cSDavid du Colombier PermX = 1, 115e96a66cSDavid du Colombier PermW = 2, 125e96a66cSDavid du Colombier PermR = 4, 135e96a66cSDavid du Colombier }; 145e96a66cSDavid du Colombier 155e96a66cSDavid du Colombier static char EPermission[] = "permission denied"; 165e96a66cSDavid du Colombier 175e96a66cSDavid du Colombier static int 185e96a66cSDavid du Colombier permFile(File* file, Fid* fid, int perm) 195e96a66cSDavid du Colombier { 205e96a66cSDavid du Colombier char *u; 215e96a66cSDavid du Colombier DirEntry de; 225e96a66cSDavid du Colombier 235e96a66cSDavid du Colombier if(!fileGetDir(file, &de)) 245e96a66cSDavid du Colombier return 0; 255e96a66cSDavid du Colombier 265e96a66cSDavid du Colombier /* 275e96a66cSDavid du Colombier * User none only gets other permissions. 285e96a66cSDavid du Colombier */ 295e96a66cSDavid du Colombier if(strcmp(fid->uname, unamenone) != 0){ 305e96a66cSDavid du Colombier /* 315e96a66cSDavid du Colombier * There is only one uid<->uname mapping 325e96a66cSDavid du Colombier * and it's already cached in the Fid, but 335e96a66cSDavid du Colombier * it might have changed during the lifetime 345e96a66cSDavid du Colombier * if this Fid. 355e96a66cSDavid du Colombier */ 365e96a66cSDavid du Colombier if((u = unameByUid(de.uid)) != nil){ 375e96a66cSDavid du Colombier if(strcmp(fid->uname, u) == 0 && ((perm<<6) & de.mode)){ 385e96a66cSDavid du Colombier vtMemFree(u); 395e96a66cSDavid du Colombier deCleanup(&de); 405e96a66cSDavid du Colombier return 1; 415e96a66cSDavid du Colombier } 425e96a66cSDavid du Colombier vtMemFree(u); 435e96a66cSDavid du Colombier } 445e96a66cSDavid du Colombier if(groupMember(de.gid, fid->uname) && ((perm<<3) & de.mode)){ 455e96a66cSDavid du Colombier deCleanup(&de); 465e96a66cSDavid du Colombier return 1; 475e96a66cSDavid du Colombier } 485e96a66cSDavid du Colombier } 495e96a66cSDavid du Colombier if(perm & de.mode){ 505e96a66cSDavid du Colombier if(perm == PermX && (de.mode & ModeDir)){ 515e96a66cSDavid du Colombier deCleanup(&de); 525e96a66cSDavid du Colombier return 1; 535e96a66cSDavid du Colombier } 545e96a66cSDavid du Colombier if(!groupMember(uidnoworld, fid->uname)){ 555e96a66cSDavid du Colombier deCleanup(&de); 565e96a66cSDavid du Colombier return 1; 575e96a66cSDavid du Colombier } 585e96a66cSDavid du Colombier } 59dc5a79c1SDavid du Colombier if(fsysNoPermCheck(fid->fsys) || fid->con->noperm){ 605e96a66cSDavid du Colombier deCleanup(&de); 615e96a66cSDavid du Colombier return 1; 625e96a66cSDavid du Colombier } 635e96a66cSDavid du Colombier vtSetError(EPermission); 645e96a66cSDavid du Colombier 655e96a66cSDavid du Colombier deCleanup(&de); 665e96a66cSDavid du Colombier return 0; 675e96a66cSDavid du Colombier } 685e96a66cSDavid du Colombier 695e96a66cSDavid du Colombier static int 705e96a66cSDavid du Colombier permFid(Fid* fid, int p) 715e96a66cSDavid du Colombier { 725e96a66cSDavid du Colombier return permFile(fid->file, fid, p); 735e96a66cSDavid du Colombier } 745e96a66cSDavid du Colombier 755e96a66cSDavid du Colombier static int 765e96a66cSDavid du Colombier permParent(Fid* fid, int p) 775e96a66cSDavid du Colombier { 785e96a66cSDavid du Colombier int r; 795e96a66cSDavid du Colombier File *parent; 805e96a66cSDavid du Colombier 815e96a66cSDavid du Colombier parent = fileGetParent(fid->file); 825e96a66cSDavid du Colombier r = permFile(parent, fid, p); 835e96a66cSDavid du Colombier fileDecRef(parent); 845e96a66cSDavid du Colombier 855e96a66cSDavid du Colombier return r; 865e96a66cSDavid du Colombier } 875e96a66cSDavid du Colombier 885e96a66cSDavid du Colombier int 895e96a66cSDavid du Colombier validFileName(char* name) 905e96a66cSDavid du Colombier { 915e96a66cSDavid du Colombier char *p; 925e96a66cSDavid du Colombier 935e96a66cSDavid du Colombier if(name == nil || name[0] == '\0'){ 945e96a66cSDavid du Colombier vtSetError("no file name"); 955e96a66cSDavid du Colombier return 0; 965e96a66cSDavid du Colombier } 975e96a66cSDavid du Colombier if(name[0] == '.'){ 985e96a66cSDavid du Colombier if(name[1] == '\0' || (name[1] == '.' && name[2] == '\0')){ 995e96a66cSDavid du Colombier vtSetError(". and .. illegal as file name"); 1005e96a66cSDavid du Colombier return 0; 1015e96a66cSDavid du Colombier } 1025e96a66cSDavid du Colombier } 1035e96a66cSDavid du Colombier 1045e96a66cSDavid du Colombier for(p = name; *p != '\0'; p++){ 1055e96a66cSDavid du Colombier if((*p & 0xFF) < 040){ 1065e96a66cSDavid du Colombier vtSetError("bad character in file name"); 1075e96a66cSDavid du Colombier return 0; 1085e96a66cSDavid du Colombier } 1095e96a66cSDavid du Colombier } 1105e96a66cSDavid du Colombier 1115e96a66cSDavid du Colombier return 1; 1125e96a66cSDavid du Colombier } 1135e96a66cSDavid du Colombier 1145e96a66cSDavid du Colombier static int 1155e96a66cSDavid du Colombier rTwstat(Msg* m) 1165e96a66cSDavid du Colombier { 1175e96a66cSDavid du Colombier Dir dir; 1185e96a66cSDavid du Colombier Fid *fid; 1190827824dSDavid du Colombier ulong mode, oldmode; 1205e96a66cSDavid du Colombier DirEntry de; 1215e96a66cSDavid du Colombier char *gid, *strs, *uid; 1225e96a66cSDavid du Colombier int gl, op, retval, tsync; 1235e96a66cSDavid du Colombier 1245e96a66cSDavid du Colombier if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil) 1255e96a66cSDavid du Colombier return 0; 1265e96a66cSDavid du Colombier 1275e96a66cSDavid du Colombier gid = uid = nil; 1285e96a66cSDavid du Colombier retval = 0; 1295e96a66cSDavid du Colombier 1305e96a66cSDavid du Colombier if(strcmp(fid->uname, unamenone) == 0 || (fid->qid.type & QTAUTH)){ 1315e96a66cSDavid du Colombier vtSetError(EPermission); 1325e96a66cSDavid du Colombier goto error0; 1335e96a66cSDavid du Colombier } 1345e96a66cSDavid du Colombier if(fileIsRoFs(fid->file) || !groupWriteMember(fid->uname)){ 1355e96a66cSDavid du Colombier vtSetError("read-only filesystem"); 1365e96a66cSDavid du Colombier goto error0; 1375e96a66cSDavid du Colombier } 1385e96a66cSDavid du Colombier 1395e96a66cSDavid du Colombier if(!fileGetDir(fid->file, &de)) 1405e96a66cSDavid du Colombier goto error0; 1415e96a66cSDavid du Colombier 1425e96a66cSDavid du Colombier strs = vtMemAlloc(m->t.nstat); 1435e96a66cSDavid du Colombier if(convM2D(m->t.stat, m->t.nstat, &dir, strs) == 0){ 1445e96a66cSDavid du Colombier vtSetError("wstat -- protocol botch"); 1455e96a66cSDavid du Colombier goto error; 1465e96a66cSDavid du Colombier } 1475e96a66cSDavid du Colombier 1485e96a66cSDavid du Colombier /* 1495e96a66cSDavid du Colombier * Run through each of the (sub-)fields in the provided Dir 1505e96a66cSDavid du Colombier * checking for validity and whether it's a default: 1515e96a66cSDavid du Colombier * .type, .dev and .atime are completely ignored and not checked; 1525e96a66cSDavid du Colombier * .qid.path, .qid.vers and .muid are checked for validity but 1535e96a66cSDavid du Colombier * any attempt to change them is an error. 1545e96a66cSDavid du Colombier * .qid.type/.mode, .mtime, .name, .length, .uid and .gid can 1555e96a66cSDavid du Colombier * possibly be changed. 1565e96a66cSDavid du Colombier * 1575e96a66cSDavid du Colombier * 'Op' flags there are changed fields, i.e. it's not a no-op. 1585e96a66cSDavid du Colombier * 'Tsync' flags all fields are defaulted. 1595e96a66cSDavid du Colombier */ 1605e96a66cSDavid du Colombier tsync = 1; 1615e96a66cSDavid du Colombier if(dir.qid.path != ~0){ 1625e96a66cSDavid du Colombier if(dir.qid.path != de.qid){ 1635e96a66cSDavid du Colombier vtSetError("wstat -- attempt to change qid.path"); 1645e96a66cSDavid du Colombier goto error; 1655e96a66cSDavid du Colombier } 1665e96a66cSDavid du Colombier tsync = 0; 1675e96a66cSDavid du Colombier } 1685e96a66cSDavid du Colombier if(dir.qid.vers != ~0){ 1695e96a66cSDavid du Colombier if(dir.qid.vers != de.mcount){ 1705e96a66cSDavid du Colombier vtSetError("wstat -- attempt to change qid.vers"); 1715e96a66cSDavid du Colombier goto error; 1725e96a66cSDavid du Colombier } 1735e96a66cSDavid du Colombier tsync = 0; 1745e96a66cSDavid du Colombier } 1755e96a66cSDavid du Colombier if(dir.muid != nil && *dir.muid != '\0'){ 1765e96a66cSDavid du Colombier if((uid = uidByUname(dir.muid)) == nil){ 1775e96a66cSDavid du Colombier vtSetError("wstat -- unknown muid"); 1785e96a66cSDavid du Colombier goto error; 1795e96a66cSDavid du Colombier } 1805e96a66cSDavid du Colombier if(strcmp(uid, de.mid) != 0){ 1815e96a66cSDavid du Colombier vtSetError("wstat -- attempt to change muid"); 1825e96a66cSDavid du Colombier goto error; 1835e96a66cSDavid du Colombier } 1845e96a66cSDavid du Colombier vtMemFree(uid); 1855e96a66cSDavid du Colombier uid = nil; 1865e96a66cSDavid du Colombier tsync = 0; 1875e96a66cSDavid du Colombier } 1885e96a66cSDavid du Colombier 1895e96a66cSDavid du Colombier /* 1905e96a66cSDavid du Colombier * Check .qid.type and .mode agree if neither is defaulted. 1915e96a66cSDavid du Colombier */ 1925e96a66cSDavid du Colombier if(dir.qid.type != (uchar)~0 && dir.mode != ~0){ 1935e96a66cSDavid du Colombier if(dir.qid.type != ((dir.mode>>24) & 0xFF)){ 1945e96a66cSDavid du Colombier vtSetError("wstat -- qid.type/mode mismatch"); 1955e96a66cSDavid du Colombier goto error; 1965e96a66cSDavid du Colombier } 1975e96a66cSDavid du Colombier } 1985e96a66cSDavid du Colombier 1995e96a66cSDavid du Colombier op = 0; 2005e96a66cSDavid du Colombier 201fb7f0c93SDavid du Colombier oldmode = de.mode; 2025e96a66cSDavid du Colombier if(dir.qid.type != (uchar)~0 || dir.mode != ~0){ 2035e96a66cSDavid du Colombier /* 2045e96a66cSDavid du Colombier * .qid.type or .mode isn't defaulted, check for unknown bits. 2055e96a66cSDavid du Colombier */ 2065e96a66cSDavid du Colombier if(dir.mode == ~0) 2075e96a66cSDavid du Colombier dir.mode = (dir.qid.type<<24)|(de.mode & 0777); 208*fe853e23SDavid du Colombier if(dir.mode & ~(DMDIR|DMAPPEND|DMEXCL|DMTMP|0777)){ 2095e96a66cSDavid du Colombier vtSetError("wstat -- unknown bits in qid.type/mode"); 2105e96a66cSDavid du Colombier goto error; 2115e96a66cSDavid du Colombier } 2125e96a66cSDavid du Colombier 2135e96a66cSDavid du Colombier /* 2145e96a66cSDavid du Colombier * Synthesise a mode to check against the current settings. 2155e96a66cSDavid du Colombier */ 2165e96a66cSDavid du Colombier mode = dir.mode & 0777; 2175e96a66cSDavid du Colombier if(dir.mode & DMEXCL) 2185e96a66cSDavid du Colombier mode |= ModeExclusive; 2195e96a66cSDavid du Colombier if(dir.mode & DMAPPEND) 2205e96a66cSDavid du Colombier mode |= ModeAppend; 2215e96a66cSDavid du Colombier if(dir.mode & DMDIR) 2225e96a66cSDavid du Colombier mode |= ModeDir; 223*fe853e23SDavid du Colombier if(dir.mode & DMTMP) 224*fe853e23SDavid du Colombier mode |= ModeTemporary; 2255e96a66cSDavid du Colombier 2265e96a66cSDavid du Colombier if((de.mode^mode) & ModeDir){ 2275e96a66cSDavid du Colombier vtSetError("wstat -- attempt to change directory bit"); 2285e96a66cSDavid du Colombier goto error; 2295e96a66cSDavid du Colombier } 2305e96a66cSDavid du Colombier 231*fe853e23SDavid du Colombier if((de.mode & (ModeAppend|ModeExclusive|ModeTemporary|0777)) != mode){ 232*fe853e23SDavid du Colombier de.mode &= ~(ModeAppend|ModeExclusive|ModeTemporary|0777); 2335e96a66cSDavid du Colombier de.mode |= mode; 2345e96a66cSDavid du Colombier op = 1; 2355e96a66cSDavid du Colombier } 2365e96a66cSDavid du Colombier tsync = 0; 2375e96a66cSDavid du Colombier } 2385e96a66cSDavid du Colombier 2395e96a66cSDavid du Colombier if(dir.mtime != ~0){ 2405e96a66cSDavid du Colombier if(dir.mtime != de.mtime){ 2415e96a66cSDavid du Colombier de.mtime = dir.mtime; 2425e96a66cSDavid du Colombier op = 1; 2435e96a66cSDavid du Colombier } 2445e96a66cSDavid du Colombier tsync = 0; 2455e96a66cSDavid du Colombier } 2465e96a66cSDavid du Colombier 2475e96a66cSDavid du Colombier if(dir.length != ~0){ 248f5736e95SDavid du Colombier if(dir.length != de.size){ 2490827824dSDavid du Colombier /* 2500827824dSDavid du Colombier * Cannot change length on append-only files. 2510827824dSDavid du Colombier * If we're changing the append bit, it's okay. 2520827824dSDavid du Colombier */ 253fb7f0c93SDavid du Colombier if(de.mode & oldmode & ModeAppend){ 2540827824dSDavid du Colombier vtSetError("wstat -- attempt to change length of append-only file"); 2550827824dSDavid du Colombier goto error; 2560827824dSDavid du Colombier } 2575e96a66cSDavid du Colombier if(de.mode & ModeDir){ 2585e96a66cSDavid du Colombier vtSetError("wstat -- attempt to change length of directory"); 2595e96a66cSDavid du Colombier goto error; 2605e96a66cSDavid du Colombier } 2615e96a66cSDavid du Colombier de.size = dir.length; 2625e96a66cSDavid du Colombier op = 1; 2635e96a66cSDavid du Colombier } 2645e96a66cSDavid du Colombier tsync = 0; 2655e96a66cSDavid du Colombier } 2665e96a66cSDavid du Colombier 2675e96a66cSDavid du Colombier /* 2685e96a66cSDavid du Colombier * Check for permission to change .mode, .mtime or .length, 2695e96a66cSDavid du Colombier * must be owner or leader of either group, for which test gid 2705e96a66cSDavid du Colombier * is needed; permission checks on gid will be done later. 2715e96a66cSDavid du Colombier */ 2725e96a66cSDavid du Colombier if(dir.gid != nil && *dir.gid != '\0'){ 2735e96a66cSDavid du Colombier if((gid = uidByUname(dir.gid)) == nil){ 2745e96a66cSDavid du Colombier vtSetError("wstat -- unknown gid"); 2755e96a66cSDavid du Colombier goto error; 2765e96a66cSDavid du Colombier } 2775e96a66cSDavid du Colombier tsync = 0; 2785e96a66cSDavid du Colombier } 2795e96a66cSDavid du Colombier else 2805e96a66cSDavid du Colombier gid = vtStrDup(de.gid); 2815e96a66cSDavid du Colombier 2825e96a66cSDavid du Colombier /* 2835e96a66cSDavid du Colombier * 'Gl' counts whether neither, one or both groups are led. 2845e96a66cSDavid du Colombier */ 2855e96a66cSDavid du Colombier gl = groupLeader(gid, fid->uname) != 0; 2865e96a66cSDavid du Colombier gl += groupLeader(de.gid, fid->uname) != 0; 2875e96a66cSDavid du Colombier 288d58da526SDavid du Colombier if(op && !(fsysWstatAllow(fid->fsys) || m->con->wstatallow)){ 2895e96a66cSDavid du Colombier if(strcmp(fid->uid, de.uid) != 0 && !gl){ 2905e96a66cSDavid du Colombier vtSetError("wstat -- not owner or group leader"); 2915e96a66cSDavid du Colombier goto error; 2925e96a66cSDavid du Colombier } 2935e96a66cSDavid du Colombier } 2945e96a66cSDavid du Colombier 2955e96a66cSDavid du Colombier /* 2965e96a66cSDavid du Colombier * Check for permission to change group, must be 2975e96a66cSDavid du Colombier * either owner and in new group or leader of both groups. 2985e96a66cSDavid du Colombier * If gid is nil here then 2995e96a66cSDavid du Colombier */ 3005e96a66cSDavid du Colombier if(strcmp(gid, de.gid) != 0){ 301d58da526SDavid du Colombier if(!(fsysWstatAllow(fid->fsys) || m->con->wstatallow) 3025e96a66cSDavid du Colombier && !(strcmp(fid->uid, de.uid) == 0 && groupMember(gid, fid->uname)) 3035e96a66cSDavid du Colombier && !(gl == 2)){ 3045e96a66cSDavid du Colombier vtSetError("wstat -- not owner and not group leaders"); 3055e96a66cSDavid du Colombier goto error; 3065e96a66cSDavid du Colombier } 3075e96a66cSDavid du Colombier vtMemFree(de.gid); 3085e96a66cSDavid du Colombier de.gid = gid; 3095e96a66cSDavid du Colombier gid = nil; 3105e96a66cSDavid du Colombier op = 1; 311fb7f0c93SDavid du Colombier tsync = 0; 3125e96a66cSDavid du Colombier } 3135e96a66cSDavid du Colombier 3145e96a66cSDavid du Colombier /* 3155e96a66cSDavid du Colombier * Rename. 3165e96a66cSDavid du Colombier * Check .name is valid and different to the current. 3175e96a66cSDavid du Colombier * If so, check write permission in parent. 3185e96a66cSDavid du Colombier */ 3195e96a66cSDavid du Colombier if(dir.name != nil && *dir.name != '\0'){ 3205e96a66cSDavid du Colombier if(!validFileName(dir.name)) 3215e96a66cSDavid du Colombier goto error; 3225e96a66cSDavid du Colombier if(strcmp(dir.name, de.elem) != 0){ 3235e96a66cSDavid du Colombier if(!permParent(fid, PermW)) 3245e96a66cSDavid du Colombier goto error; 3255e96a66cSDavid du Colombier vtMemFree(de.elem); 3265e96a66cSDavid du Colombier de.elem = vtStrDup(dir.name); 3275e96a66cSDavid du Colombier op = 1; 3285e96a66cSDavid du Colombier } 3295e96a66cSDavid du Colombier tsync = 0; 3305e96a66cSDavid du Colombier } 3315e96a66cSDavid du Colombier 3325e96a66cSDavid du Colombier /* 3335e96a66cSDavid du Colombier * Check for permission to change owner - must be god. 3345e96a66cSDavid du Colombier */ 3355e96a66cSDavid du Colombier if(dir.uid != nil && *dir.uid != '\0'){ 3365e96a66cSDavid du Colombier if((uid = uidByUname(dir.uid)) == nil){ 3375e96a66cSDavid du Colombier vtSetError("wstat -- unknown uid"); 3385e96a66cSDavid du Colombier goto error; 3395e96a66cSDavid du Colombier } 3405e96a66cSDavid du Colombier if(strcmp(uid, de.uid) != 0){ 341d58da526SDavid du Colombier if(!(fsysWstatAllow(fid->fsys) || m->con->wstatallow)){ 3425e96a66cSDavid du Colombier vtSetError("wstat -- not owner"); 3435e96a66cSDavid du Colombier goto error; 3445e96a66cSDavid du Colombier } 3455e96a66cSDavid du Colombier if(strcmp(uid, uidnoworld) == 0){ 3465e96a66cSDavid du Colombier vtSetError(EPermission); 3475e96a66cSDavid du Colombier goto error; 3485e96a66cSDavid du Colombier } 3495e96a66cSDavid du Colombier vtMemFree(de.uid); 3505e96a66cSDavid du Colombier de.uid = uid; 3515e96a66cSDavid du Colombier uid = nil; 3525e96a66cSDavid du Colombier op = 1; 3535e96a66cSDavid du Colombier } 3545e96a66cSDavid du Colombier tsync = 0; 3555e96a66cSDavid du Colombier } 3565e96a66cSDavid du Colombier 3575e96a66cSDavid du Colombier if(op) 3585e96a66cSDavid du Colombier retval = fileSetDir(fid->file, &de, fid->uid); 3595e96a66cSDavid du Colombier else 3605e96a66cSDavid du Colombier retval = 1; 3615e96a66cSDavid du Colombier 3625e96a66cSDavid du Colombier if(tsync){ 3635e96a66cSDavid du Colombier /* 3645e96a66cSDavid du Colombier * All values were defaulted, 3655e96a66cSDavid du Colombier * make the state of the file exactly what it 3665e96a66cSDavid du Colombier * claims to be before returning... 3675e96a66cSDavid du Colombier */ 3685e96a66cSDavid du Colombier USED(tsync); 3695e96a66cSDavid du Colombier } 3705e96a66cSDavid du Colombier 3715e96a66cSDavid du Colombier error: 3725e96a66cSDavid du Colombier deCleanup(&de); 3735e96a66cSDavid du Colombier vtMemFree(strs); 3745e96a66cSDavid du Colombier if(gid != nil) 3755e96a66cSDavid du Colombier vtMemFree(gid); 3765e96a66cSDavid du Colombier if(uid != nil) 3775e96a66cSDavid du Colombier vtMemFree(uid); 3785e96a66cSDavid du Colombier error0: 3795e96a66cSDavid du Colombier fidPut(fid); 3805e96a66cSDavid du Colombier return retval; 3815e96a66cSDavid du Colombier }; 3825e96a66cSDavid du Colombier 3835e96a66cSDavid du Colombier static int 3845e96a66cSDavid du Colombier rTstat(Msg* m) 3855e96a66cSDavid du Colombier { 3865e96a66cSDavid du Colombier Dir dir; 3875e96a66cSDavid du Colombier Fid *fid; 3885e96a66cSDavid du Colombier DirEntry de; 3895e96a66cSDavid du Colombier 3905e96a66cSDavid du Colombier if((fid = fidGet(m->con, m->t.fid, 0)) == nil) 3915e96a66cSDavid du Colombier return 0; 3925e96a66cSDavid du Colombier if(fid->qid.type & QTAUTH){ 3935e96a66cSDavid du Colombier memset(&dir, 0, sizeof(Dir)); 3945e96a66cSDavid du Colombier dir.qid = fid->qid; 3955e96a66cSDavid du Colombier dir.mode = DMAUTH; 3965e96a66cSDavid du Colombier dir.atime = time(0L); 3975e96a66cSDavid du Colombier dir.mtime = dir.atime; 3985e96a66cSDavid du Colombier dir.length = 0; 3995e96a66cSDavid du Colombier dir.name = "#¿"; 4005e96a66cSDavid du Colombier dir.uid = fid->uname; 4015e96a66cSDavid du Colombier dir.gid = fid->uname; 4025e96a66cSDavid du Colombier dir.muid = fid->uname; 4035e96a66cSDavid du Colombier 4045e96a66cSDavid du Colombier if((m->r.nstat = convD2M(&dir, m->data, m->con->msize)) == 0){ 4055e96a66cSDavid du Colombier vtSetError("stat QTAUTH botch"); 4065e96a66cSDavid du Colombier fidPut(fid); 4075e96a66cSDavid du Colombier return 0; 4085e96a66cSDavid du Colombier } 4095e96a66cSDavid du Colombier m->r.stat = m->data; 4105e96a66cSDavid du Colombier 4115e96a66cSDavid du Colombier fidPut(fid); 4125e96a66cSDavid du Colombier return 1; 4135e96a66cSDavid du Colombier } 4145e96a66cSDavid du Colombier if(!fileGetDir(fid->file, &de)){ 4155e96a66cSDavid du Colombier fidPut(fid); 4165e96a66cSDavid du Colombier return 0; 4175e96a66cSDavid du Colombier } 4185e96a66cSDavid du Colombier fidPut(fid); 4195e96a66cSDavid du Colombier 4205e96a66cSDavid du Colombier /* 4215e96a66cSDavid du Colombier * TODO: optimise this copy (in convS2M) away somehow. 4225e96a66cSDavid du Colombier * This pettifoggery with m->data will do for the moment. 4235e96a66cSDavid du Colombier */ 4245e96a66cSDavid du Colombier m->r.nstat = dirDe2M(&de, m->data, m->con->msize); 4255e96a66cSDavid du Colombier m->r.stat = m->data; 4265e96a66cSDavid du Colombier deCleanup(&de); 4275e96a66cSDavid du Colombier 4285e96a66cSDavid du Colombier return 1; 4295e96a66cSDavid du Colombier } 4305e96a66cSDavid du Colombier 4315e96a66cSDavid du Colombier static int 4325e96a66cSDavid du Colombier _rTclunk(Fid* fid, int remove) 4335e96a66cSDavid du Colombier { 4345e96a66cSDavid du Colombier int rok; 4355e96a66cSDavid du Colombier 4365e96a66cSDavid du Colombier if(fid->excl) 4375e96a66cSDavid du Colombier exclFree(fid); 4385e96a66cSDavid du Colombier 4395e96a66cSDavid du Colombier rok = 1; 4405e96a66cSDavid du Colombier if(remove && !(fid->qid.type & QTAUTH)){ 4415e96a66cSDavid du Colombier if((rok = permParent(fid, PermW)) != 0) 4425e96a66cSDavid du Colombier rok = fileRemove(fid->file, fid->uid); 4435e96a66cSDavid du Colombier } 4445e96a66cSDavid du Colombier fidClunk(fid); 4455e96a66cSDavid du Colombier 4465e96a66cSDavid du Colombier return rok; 4475e96a66cSDavid du Colombier } 4485e96a66cSDavid du Colombier 4495e96a66cSDavid du Colombier static int 4505e96a66cSDavid du Colombier rTremove(Msg* m) 4515e96a66cSDavid du Colombier { 4525e96a66cSDavid du Colombier Fid *fid; 4535e96a66cSDavid du Colombier 4545e96a66cSDavid du Colombier if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil) 4555e96a66cSDavid du Colombier return 0; 4565e96a66cSDavid du Colombier return _rTclunk(fid, 1); 4575e96a66cSDavid du Colombier } 4585e96a66cSDavid du Colombier 4595e96a66cSDavid du Colombier static int 4605e96a66cSDavid du Colombier rTclunk(Msg* m) 4615e96a66cSDavid du Colombier { 4625e96a66cSDavid du Colombier Fid *fid; 4635e96a66cSDavid du Colombier 4645e96a66cSDavid du Colombier if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil) 4655e96a66cSDavid du Colombier return 0; 4665e96a66cSDavid du Colombier _rTclunk(fid, (fid->open & FidORclose)); 4675e96a66cSDavid du Colombier 4685e96a66cSDavid du Colombier return 1; 4695e96a66cSDavid du Colombier } 4705e96a66cSDavid du Colombier 4715e96a66cSDavid du Colombier static int 4725e96a66cSDavid du Colombier rTwrite(Msg* m) 4735e96a66cSDavid du Colombier { 4745e96a66cSDavid du Colombier Fid *fid; 4755e96a66cSDavid du Colombier int count, n; 4765e96a66cSDavid du Colombier 4775e96a66cSDavid du Colombier if((fid = fidGet(m->con, m->t.fid, 0)) == nil) 4785e96a66cSDavid du Colombier return 0; 4795e96a66cSDavid du Colombier if(!(fid->open & FidOWrite)){ 4805e96a66cSDavid du Colombier vtSetError("fid not open for write"); 4815e96a66cSDavid du Colombier goto error; 4825e96a66cSDavid du Colombier } 4835e96a66cSDavid du Colombier 4845e96a66cSDavid du Colombier count = m->t.count; 4855e96a66cSDavid du Colombier if(count < 0 || count > m->con->msize-IOHDRSZ){ 4865e96a66cSDavid du Colombier vtSetError("write count too big"); 4875e96a66cSDavid du Colombier goto error; 4885e96a66cSDavid du Colombier } 4895e96a66cSDavid du Colombier if(m->t.offset < 0){ 4905e96a66cSDavid du Colombier vtSetError("write offset negative"); 4915e96a66cSDavid du Colombier goto error; 4925e96a66cSDavid du Colombier } 4935e96a66cSDavid du Colombier if(fid->excl != nil && !exclUpdate(fid)) 4945e96a66cSDavid du Colombier goto error; 4955e96a66cSDavid du Colombier 4965e96a66cSDavid du Colombier if(fid->qid.type & QTDIR){ 4975e96a66cSDavid du Colombier vtSetError("is a directory"); 4985e96a66cSDavid du Colombier goto error; 4995e96a66cSDavid du Colombier } 5005e96a66cSDavid du Colombier else if(fid->qid.type & QTAUTH) 5015e96a66cSDavid du Colombier n = authWrite(fid, m->t.data, count); 5025e96a66cSDavid du Colombier else 5035e96a66cSDavid du Colombier n = fileWrite(fid->file, m->t.data, count, m->t.offset, fid->uid); 5045e96a66cSDavid du Colombier if(n < 0) 5055e96a66cSDavid du Colombier goto error; 5065e96a66cSDavid du Colombier 5075e96a66cSDavid du Colombier 5085e96a66cSDavid du Colombier m->r.count = n; 5095e96a66cSDavid du Colombier 5105e96a66cSDavid du Colombier fidPut(fid); 5115e96a66cSDavid du Colombier return 1; 5125e96a66cSDavid du Colombier 5135e96a66cSDavid du Colombier error: 5145e96a66cSDavid du Colombier fidPut(fid); 5155e96a66cSDavid du Colombier return 0; 5165e96a66cSDavid du Colombier } 5175e96a66cSDavid du Colombier 5185e96a66cSDavid du Colombier static int 5195e96a66cSDavid du Colombier rTread(Msg* m) 5205e96a66cSDavid du Colombier { 5215e96a66cSDavid du Colombier Fid *fid; 5225e96a66cSDavid du Colombier uchar *data; 5235e96a66cSDavid du Colombier int count, n; 5245e96a66cSDavid du Colombier 5255e96a66cSDavid du Colombier if((fid = fidGet(m->con, m->t.fid, 0)) == nil) 5265e96a66cSDavid du Colombier return 0; 5275e96a66cSDavid du Colombier if(!(fid->open & FidORead)){ 5285e96a66cSDavid du Colombier vtSetError("fid not open for read"); 5295e96a66cSDavid du Colombier goto error; 5305e96a66cSDavid du Colombier } 5315e96a66cSDavid du Colombier 5325e96a66cSDavid du Colombier count = m->t.count; 5335e96a66cSDavid du Colombier if(count < 0 || count > m->con->msize-IOHDRSZ){ 5345e96a66cSDavid du Colombier vtSetError("read count too big"); 5355e96a66cSDavid du Colombier goto error; 5365e96a66cSDavid du Colombier } 5375e96a66cSDavid du Colombier if(m->t.offset < 0){ 5385e96a66cSDavid du Colombier vtSetError("read offset negative"); 5395e96a66cSDavid du Colombier goto error; 5405e96a66cSDavid du Colombier } 5415e96a66cSDavid du Colombier if(fid->excl != nil && !exclUpdate(fid)) 5425e96a66cSDavid du Colombier goto error; 5435e96a66cSDavid du Colombier 5445e96a66cSDavid du Colombier /* 5455e96a66cSDavid du Colombier * TODO: optimise this copy (in convS2M) away somehow. 5465e96a66cSDavid du Colombier * This pettifoggery with m->data will do for the moment. 5475e96a66cSDavid du Colombier */ 5485e96a66cSDavid du Colombier data = m->data+IOHDRSZ; 5495e96a66cSDavid du Colombier if(fid->qid.type & QTDIR) 5505e96a66cSDavid du Colombier n = dirRead(fid, data, count, m->t.offset); 5515e96a66cSDavid du Colombier else if(fid->qid.type & QTAUTH) 5525e96a66cSDavid du Colombier n = authRead(fid, data, count); 5535e96a66cSDavid du Colombier else 5545e96a66cSDavid du Colombier n = fileRead(fid->file, data, count, m->t.offset); 5555e96a66cSDavid du Colombier if(n < 0) 5565e96a66cSDavid du Colombier goto error; 5575e96a66cSDavid du Colombier 5585e96a66cSDavid du Colombier m->r.count = n; 5595e96a66cSDavid du Colombier m->r.data = (char*)data; 5605e96a66cSDavid du Colombier 5615e96a66cSDavid du Colombier fidPut(fid); 5625e96a66cSDavid du Colombier return 1; 5635e96a66cSDavid du Colombier 5645e96a66cSDavid du Colombier error: 5655e96a66cSDavid du Colombier fidPut(fid); 5665e96a66cSDavid du Colombier return 0; 5675e96a66cSDavid du Colombier } 5685e96a66cSDavid du Colombier 5695e96a66cSDavid du Colombier static int 5705e96a66cSDavid du Colombier rTcreate(Msg* m) 5715e96a66cSDavid du Colombier { 5725e96a66cSDavid du Colombier Fid *fid; 5735e96a66cSDavid du Colombier File *file; 5745e96a66cSDavid du Colombier ulong mode; 5755e96a66cSDavid du Colombier int omode, open, perm; 5765e96a66cSDavid du Colombier 5775e96a66cSDavid du Colombier if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil) 5785e96a66cSDavid du Colombier return 0; 5795e96a66cSDavid du Colombier if(fid->open){ 5805e96a66cSDavid du Colombier vtSetError("fid open for I/O"); 5815e96a66cSDavid du Colombier goto error; 5825e96a66cSDavid du Colombier } 5835e96a66cSDavid du Colombier if(fileIsRoFs(fid->file) || !groupWriteMember(fid->uname)){ 5845e96a66cSDavid du Colombier vtSetError("read-only filesystem"); 5855e96a66cSDavid du Colombier goto error; 5865e96a66cSDavid du Colombier } 5875e96a66cSDavid du Colombier if(!fileIsDir(fid->file)){ 5885e96a66cSDavid du Colombier vtSetError("not a directory"); 5895e96a66cSDavid du Colombier goto error; 5905e96a66cSDavid du Colombier } 5915e96a66cSDavid du Colombier if(!permFid(fid, PermW)) 5925e96a66cSDavid du Colombier goto error; 5935e96a66cSDavid du Colombier if(!validFileName(m->t.name)) 5945e96a66cSDavid du Colombier goto error; 5955e96a66cSDavid du Colombier if(strcmp(fid->uid, uidnoworld) == 0){ 5965e96a66cSDavid du Colombier vtSetError(EPermission); 5975e96a66cSDavid du Colombier goto error; 5985e96a66cSDavid du Colombier } 5995e96a66cSDavid du Colombier 6005e96a66cSDavid du Colombier omode = m->t.mode & OMODE; 6015e96a66cSDavid du Colombier open = 0; 6025e96a66cSDavid du Colombier 6035e96a66cSDavid du Colombier if(omode == OREAD || omode == ORDWR || omode == OEXEC) 6045e96a66cSDavid du Colombier open |= FidORead; 6055e96a66cSDavid du Colombier if(omode == OWRITE || omode == ORDWR) 6065e96a66cSDavid du Colombier open |= FidOWrite; 6075e96a66cSDavid du Colombier if((open & (FidOWrite|FidORead)) == 0){ 6085e96a66cSDavid du Colombier vtSetError("unknown mode"); 6095e96a66cSDavid du Colombier goto error; 6105e96a66cSDavid du Colombier } 6115e96a66cSDavid du Colombier if(m->t.perm & DMDIR){ 6125e96a66cSDavid du Colombier if((m->t.mode & (ORCLOSE|OTRUNC)) || (open & FidOWrite)){ 6135e96a66cSDavid du Colombier vtSetError("illegal mode"); 6145e96a66cSDavid du Colombier goto error; 6155e96a66cSDavid du Colombier } 6165e96a66cSDavid du Colombier if(m->t.perm & DMAPPEND){ 6175e96a66cSDavid du Colombier vtSetError("illegal perm"); 6185e96a66cSDavid du Colombier goto error; 6195e96a66cSDavid du Colombier } 6205e96a66cSDavid du Colombier } 6215e96a66cSDavid du Colombier 6225e96a66cSDavid du Colombier mode = fileGetMode(fid->file); 6235e96a66cSDavid du Colombier perm = m->t.perm; 6245e96a66cSDavid du Colombier if(m->t.perm & DMDIR) 6255e96a66cSDavid du Colombier perm &= ~0777|(mode & 0777); 6265e96a66cSDavid du Colombier else 6275e96a66cSDavid du Colombier perm &= ~0666|(mode & 0666); 6285e96a66cSDavid du Colombier mode = perm & 0777; 6295e96a66cSDavid du Colombier if(m->t.perm & DMDIR) 6305e96a66cSDavid du Colombier mode |= ModeDir; 6315e96a66cSDavid du Colombier if(m->t.perm & DMAPPEND) 6325e96a66cSDavid du Colombier mode |= ModeAppend; 6335e96a66cSDavid du Colombier if(m->t.perm & DMEXCL) 6345e96a66cSDavid du Colombier mode |= ModeExclusive; 635*fe853e23SDavid du Colombier if(m->t.perm & DMTMP) 636*fe853e23SDavid du Colombier mode |= ModeTemporary; 6375e96a66cSDavid du Colombier 6385e96a66cSDavid du Colombier if((file = fileCreate(fid->file, m->t.name, mode, fid->uid)) == nil){ 6395e96a66cSDavid du Colombier fidPut(fid); 6405e96a66cSDavid du Colombier return 0; 6415e96a66cSDavid du Colombier } 6425e96a66cSDavid du Colombier fileDecRef(fid->file); 6435e96a66cSDavid du Colombier 64434e04225SDavid du Colombier fid->qid.vers = fileGetMcount(file); 64534e04225SDavid du Colombier fid->qid.path = fileGetId(file); 6465e96a66cSDavid du Colombier fid->file = file; 6475e96a66cSDavid du Colombier mode = fileGetMode(fid->file); 6485e96a66cSDavid du Colombier if(mode & ModeDir) 6495e96a66cSDavid du Colombier fid->qid.type = QTDIR; 6505e96a66cSDavid du Colombier else 6515e96a66cSDavid du Colombier fid->qid.type = QTFILE; 6525e96a66cSDavid du Colombier if(mode & ModeAppend) 6535e96a66cSDavid du Colombier fid->qid.type |= QTAPPEND; 6545e96a66cSDavid du Colombier if(mode & ModeExclusive){ 6555e96a66cSDavid du Colombier fid->qid.type |= QTEXCL; 6565e96a66cSDavid du Colombier assert(exclAlloc(fid) != 0); 6575e96a66cSDavid du Colombier } 6585e96a66cSDavid du Colombier if(m->t.mode & ORCLOSE) 6595e96a66cSDavid du Colombier open |= FidORclose; 6605e96a66cSDavid du Colombier fid->open = open; 6615e96a66cSDavid du Colombier 6625e96a66cSDavid du Colombier m->r.qid = fid->qid; 6635e96a66cSDavid du Colombier m->r.iounit = m->con->msize-IOHDRSZ; 6645e96a66cSDavid du Colombier 6655e96a66cSDavid du Colombier fidPut(fid); 6665e96a66cSDavid du Colombier return 1; 6675e96a66cSDavid du Colombier 6685e96a66cSDavid du Colombier error: 6695e96a66cSDavid du Colombier fidPut(fid); 6705e96a66cSDavid du Colombier return 0; 6715e96a66cSDavid du Colombier } 6725e96a66cSDavid du Colombier 6735e96a66cSDavid du Colombier static int 6745e96a66cSDavid du Colombier rTopen(Msg* m) 6755e96a66cSDavid du Colombier { 6765e96a66cSDavid du Colombier Fid *fid; 6775e96a66cSDavid du Colombier int isdir, mode, omode, open, rofs; 6785e96a66cSDavid du Colombier 6795e96a66cSDavid du Colombier if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil) 6805e96a66cSDavid du Colombier return 0; 6815e96a66cSDavid du Colombier if(fid->open){ 6825e96a66cSDavid du Colombier vtSetError("fid open for I/O"); 6835e96a66cSDavid du Colombier goto error; 6845e96a66cSDavid du Colombier } 6855e96a66cSDavid du Colombier 6865e96a66cSDavid du Colombier isdir = fileIsDir(fid->file); 6875e96a66cSDavid du Colombier open = 0; 6885e96a66cSDavid du Colombier rofs = fileIsRoFs(fid->file) || !groupWriteMember(fid->uname); 6895e96a66cSDavid du Colombier 6905e96a66cSDavid du Colombier if(m->t.mode & ORCLOSE){ 6915e96a66cSDavid du Colombier if(isdir){ 6925e96a66cSDavid du Colombier vtSetError("is a directory"); 6935e96a66cSDavid du Colombier goto error; 6945e96a66cSDavid du Colombier } 6955e96a66cSDavid du Colombier if(rofs){ 6965e96a66cSDavid du Colombier vtSetError("read-only filesystem"); 6975e96a66cSDavid du Colombier goto error; 6985e96a66cSDavid du Colombier } 6995e96a66cSDavid du Colombier if(!permParent(fid, PermW)) 7005e96a66cSDavid du Colombier goto error; 7015e96a66cSDavid du Colombier 7025e96a66cSDavid du Colombier open |= FidORclose; 7035e96a66cSDavid du Colombier } 7045e96a66cSDavid du Colombier 7055e96a66cSDavid du Colombier omode = m->t.mode & OMODE; 7065e96a66cSDavid du Colombier if(omode == OREAD || omode == ORDWR){ 7075e96a66cSDavid du Colombier if(!permFid(fid, PermR)) 7085e96a66cSDavid du Colombier goto error; 7095e96a66cSDavid du Colombier open |= FidORead; 7105e96a66cSDavid du Colombier } 7115e96a66cSDavid du Colombier if(omode == OWRITE || omode == ORDWR || (m->t.mode & OTRUNC)){ 7125e96a66cSDavid du Colombier if(isdir){ 7135e96a66cSDavid du Colombier vtSetError("is a directory"); 7145e96a66cSDavid du Colombier goto error; 7155e96a66cSDavid du Colombier } 7165e96a66cSDavid du Colombier if(rofs){ 7175e96a66cSDavid du Colombier vtSetError("read-only filesystem"); 7185e96a66cSDavid du Colombier goto error; 7195e96a66cSDavid du Colombier } 7205e96a66cSDavid du Colombier if(!permFid(fid, PermW)) 7215e96a66cSDavid du Colombier goto error; 7225e96a66cSDavid du Colombier open |= FidOWrite; 7235e96a66cSDavid du Colombier } 7245e96a66cSDavid du Colombier if(omode == OEXEC){ 7255e96a66cSDavid du Colombier if(isdir){ 7265e96a66cSDavid du Colombier vtSetError("is a directory"); 7275e96a66cSDavid du Colombier goto error; 7285e96a66cSDavid du Colombier } 7295e96a66cSDavid du Colombier if(!permFid(fid, PermX)) 7305e96a66cSDavid du Colombier goto error; 7315e96a66cSDavid du Colombier open |= FidORead; 7325e96a66cSDavid du Colombier } 7335e96a66cSDavid du Colombier if((open & (FidOWrite|FidORead)) == 0){ 7345e96a66cSDavid du Colombier vtSetError("unknown mode"); 7355e96a66cSDavid du Colombier goto error; 7365e96a66cSDavid du Colombier } 7375e96a66cSDavid du Colombier 7385e96a66cSDavid du Colombier mode = fileGetMode(fid->file); 7395e96a66cSDavid du Colombier if((mode & ModeExclusive) && exclAlloc(fid) == 0) 7405e96a66cSDavid du Colombier goto error; 7415e96a66cSDavid du Colombier 7425e96a66cSDavid du Colombier /* 7435e96a66cSDavid du Colombier * Everything checks out, try to commit any changes. 7445e96a66cSDavid du Colombier */ 7455e96a66cSDavid du Colombier if((m->t.mode & OTRUNC) && !(mode & ModeAppend)){ 7465e96a66cSDavid du Colombier if(!fileTruncate(fid->file, fid->uid)) 7475e96a66cSDavid du Colombier goto error; 7485e96a66cSDavid du Colombier fid->qid.vers = fileGetMcount(fid->file); 7495e96a66cSDavid du Colombier } 7505e96a66cSDavid du Colombier if(isdir && fid->db != nil){ 7515e96a66cSDavid du Colombier dirBufFree(fid->db); 7525e96a66cSDavid du Colombier fid->db = nil; 7535e96a66cSDavid du Colombier } 7545e96a66cSDavid du Colombier 7555e96a66cSDavid du Colombier m->r.qid = fid->qid; 7565e96a66cSDavid du Colombier m->r.iounit = m->con->msize-IOHDRSZ; 7575e96a66cSDavid du Colombier 7585e96a66cSDavid du Colombier fid->open = open; 7595e96a66cSDavid du Colombier 7605e96a66cSDavid du Colombier fidPut(fid); 7615e96a66cSDavid du Colombier return 1; 7625e96a66cSDavid du Colombier 7635e96a66cSDavid du Colombier error: 7645e96a66cSDavid du Colombier if(fid->excl != nil) 7655e96a66cSDavid du Colombier exclFree(fid); 7665e96a66cSDavid du Colombier fidPut(fid); 7675e96a66cSDavid du Colombier return 0; 7685e96a66cSDavid du Colombier } 7695e96a66cSDavid du Colombier 7705e96a66cSDavid du Colombier static int 7715e96a66cSDavid du Colombier rTwalk(Msg* m) 7725e96a66cSDavid du Colombier { 7735e96a66cSDavid du Colombier Qid qid; 7745e96a66cSDavid du Colombier Fcall *r, *t; 7755e96a66cSDavid du Colombier int nwname, wlock; 7765e96a66cSDavid du Colombier File *file, *nfile; 7775e96a66cSDavid du Colombier Fid *fid, *ofid, *nfid; 7785e96a66cSDavid du Colombier 7795e96a66cSDavid du Colombier t = &m->t; 7805e96a66cSDavid du Colombier if(t->fid == t->newfid) 7815e96a66cSDavid du Colombier wlock = FidFWlock; 7825e96a66cSDavid du Colombier else 7835e96a66cSDavid du Colombier wlock = 0; 7845e96a66cSDavid du Colombier 7855e96a66cSDavid du Colombier /* 7865e96a66cSDavid du Colombier * The file identified by t->fid must be valid in the 7875e96a66cSDavid du Colombier * current session and must not have been opened for I/O 7885e96a66cSDavid du Colombier * by an open or create message. 7895e96a66cSDavid du Colombier */ 7905e96a66cSDavid du Colombier if((ofid = fidGet(m->con, t->fid, wlock)) == nil) 7915e96a66cSDavid du Colombier return 0; 7925e96a66cSDavid du Colombier if(ofid->open){ 7935e96a66cSDavid du Colombier vtSetError("file open for I/O"); 7945e96a66cSDavid du Colombier fidPut(ofid); 7955e96a66cSDavid du Colombier return 0; 7965e96a66cSDavid du Colombier } 7975e96a66cSDavid du Colombier 7985e96a66cSDavid du Colombier /* 7995e96a66cSDavid du Colombier * If newfid is not the same as fid, allocate a new file; 8005e96a66cSDavid du Colombier * a side effect is checking newfid is not already in use (error); 8015e96a66cSDavid du Colombier * if there are no names to walk this will be equivalent to a 8025e96a66cSDavid du Colombier * simple 'clone' operation. 8035e96a66cSDavid du Colombier * It's a no-op if newfid is the same as fid and t->nwname is 0. 8045e96a66cSDavid du Colombier */ 8055e96a66cSDavid du Colombier nfid = nil; 8065e96a66cSDavid du Colombier if(t->fid != t->newfid){ 8075e96a66cSDavid du Colombier nfid = fidGet(m->con, t->newfid, FidFWlock|FidFCreate); 8085e96a66cSDavid du Colombier if(nfid == nil){ 809d58da526SDavid du Colombier vtSetError("fid in use"); 8105e96a66cSDavid du Colombier fidPut(ofid); 8115e96a66cSDavid du Colombier return 0; 8125e96a66cSDavid du Colombier } 8135e96a66cSDavid du Colombier nfid->open = ofid->open & ~FidORclose; 8145e96a66cSDavid du Colombier nfid->file = fileIncRef(ofid->file); 8155e96a66cSDavid du Colombier nfid->qid = ofid->qid; 8165e96a66cSDavid du Colombier nfid->uid = vtStrDup(ofid->uid); 8175e96a66cSDavid du Colombier nfid->uname = vtStrDup(ofid->uname); 8185e96a66cSDavid du Colombier nfid->fsys = fsysIncRef(ofid->fsys); 8195e96a66cSDavid du Colombier fid = nfid; 8205e96a66cSDavid du Colombier } 8215e96a66cSDavid du Colombier else 8225e96a66cSDavid du Colombier fid = ofid; 8235e96a66cSDavid du Colombier 8245e96a66cSDavid du Colombier r = &m->r; 8255e96a66cSDavid du Colombier r->nwqid = 0; 8265e96a66cSDavid du Colombier 8275e96a66cSDavid du Colombier if(t->nwname == 0){ 8285e96a66cSDavid du Colombier if(nfid != nil) 8295e96a66cSDavid du Colombier fidPut(nfid); 8305e96a66cSDavid du Colombier fidPut(ofid); 8315e96a66cSDavid du Colombier 8325e96a66cSDavid du Colombier return 1; 8335e96a66cSDavid du Colombier } 8345e96a66cSDavid du Colombier 8355e96a66cSDavid du Colombier file = fid->file; 8365e96a66cSDavid du Colombier fileIncRef(file); 8375e96a66cSDavid du Colombier qid = fid->qid; 8385e96a66cSDavid du Colombier 8395e96a66cSDavid du Colombier for(nwname = 0; nwname < t->nwname; nwname++){ 8405e96a66cSDavid du Colombier /* 8415e96a66cSDavid du Colombier * Walked elements must represent a directory and 8425e96a66cSDavid du Colombier * the implied user must have permission to search 8435e96a66cSDavid du Colombier * the directory. Walking .. is always allowed, so that 8445e96a66cSDavid du Colombier * you can't walk into a directory and then not be able 8455e96a66cSDavid du Colombier * to walk out of it. 8465e96a66cSDavid du Colombier */ 8475e96a66cSDavid du Colombier if(!(qid.type & QTDIR)){ 8485e96a66cSDavid du Colombier vtSetError("not a directory"); 8495e96a66cSDavid du Colombier break; 8505e96a66cSDavid du Colombier } 8515e96a66cSDavid du Colombier if(!permFile(file, fid, PermX) && strcmp(t->wname[nwname], "..") != 0) 8525e96a66cSDavid du Colombier break; 8535e96a66cSDavid du Colombier if((nfile = fileWalk(file, t->wname[nwname])) == nil) 8545e96a66cSDavid du Colombier break; 8555e96a66cSDavid du Colombier fileDecRef(file); 8565e96a66cSDavid du Colombier file = nfile; 8575e96a66cSDavid du Colombier qid.type = QTFILE; 8585e96a66cSDavid du Colombier if(fileIsDir(file)) 8595e96a66cSDavid du Colombier qid.type = QTDIR; 8605e96a66cSDavid du Colombier qid.vers = fileGetMcount(file); 8615e96a66cSDavid du Colombier qid.path = fileGetId(file); 8625e96a66cSDavid du Colombier r->wqid[r->nwqid++] = qid; 8635e96a66cSDavid du Colombier } 8645e96a66cSDavid du Colombier 8655e96a66cSDavid du Colombier if(nwname == t->nwname){ 8665e96a66cSDavid du Colombier /* 8675e96a66cSDavid du Colombier * Walked all elements. Update the target fid 8685e96a66cSDavid du Colombier * from the temporary qid used during the walk, 8695e96a66cSDavid du Colombier * and tidy up. 8705e96a66cSDavid du Colombier */ 8715e96a66cSDavid du Colombier fid->qid = r->wqid[r->nwqid-1]; 8725e96a66cSDavid du Colombier fileDecRef(fid->file); 8735e96a66cSDavid du Colombier fid->file = file; 8745e96a66cSDavid du Colombier 8755e96a66cSDavid du Colombier if(nfid != nil) 8765e96a66cSDavid du Colombier fidPut(nfid); 8775e96a66cSDavid du Colombier 8785e96a66cSDavid du Colombier fidPut(ofid); 8795e96a66cSDavid du Colombier return 1; 8805e96a66cSDavid du Colombier } 8815e96a66cSDavid du Colombier 8825e96a66cSDavid du Colombier /* 8835e96a66cSDavid du Colombier * Didn't walk all elements, 'clunk' nfid if it exists 8845e96a66cSDavid du Colombier * and leave fid untouched. 8855e96a66cSDavid du Colombier * It's not an error if some of the elements were walked OK. 8865e96a66cSDavid du Colombier */ 8875e96a66cSDavid du Colombier fileDecRef(file); 8885e96a66cSDavid du Colombier if(nfid != nil) 8895e96a66cSDavid du Colombier fidClunk(nfid); 8905e96a66cSDavid du Colombier 8915e96a66cSDavid du Colombier fidPut(ofid); 8925e96a66cSDavid du Colombier if(nwname == 0) 8935e96a66cSDavid du Colombier return 0; 8945e96a66cSDavid du Colombier return 1; 8955e96a66cSDavid du Colombier } 8965e96a66cSDavid du Colombier 8975e96a66cSDavid du Colombier static int 8985e96a66cSDavid du Colombier rTflush(Msg* m) 8995e96a66cSDavid du Colombier { 90034e04225SDavid du Colombier if(m->t.oldtag != NOTAG) 90134e04225SDavid du Colombier msgFlush(m); 9025e96a66cSDavid du Colombier return 1; 9035e96a66cSDavid du Colombier } 9045e96a66cSDavid du Colombier 9055e96a66cSDavid du Colombier static void 9065e96a66cSDavid du Colombier parseAname(char *aname, char **fsname, char **path) 9075e96a66cSDavid du Colombier { 9085e96a66cSDavid du Colombier char *s; 9095e96a66cSDavid du Colombier 9105e96a66cSDavid du Colombier if(aname && aname[0]) 9115e96a66cSDavid du Colombier s = vtStrDup(aname); 9125e96a66cSDavid du Colombier else 9135e96a66cSDavid du Colombier s = vtStrDup("main/active"); 9145e96a66cSDavid du Colombier *fsname = s; 9155e96a66cSDavid du Colombier if((*path = strchr(s, '/')) != nil) 9165e96a66cSDavid du Colombier *(*path)++ = '\0'; 9175e96a66cSDavid du Colombier else 9185e96a66cSDavid du Colombier *path = ""; 9195e96a66cSDavid du Colombier } 9205e96a66cSDavid du Colombier 9215e96a66cSDavid du Colombier static int 9225e96a66cSDavid du Colombier rTattach(Msg* m) 9235e96a66cSDavid du Colombier { 9245e96a66cSDavid du Colombier Fid *fid; 9255e96a66cSDavid du Colombier Fsys *fsys; 9265e96a66cSDavid du Colombier char *fsname, *path; 9275e96a66cSDavid du Colombier 9285e96a66cSDavid du Colombier if((fid = fidGet(m->con, m->t.fid, FidFWlock|FidFCreate)) == nil) 9295e96a66cSDavid du Colombier return 0; 9305e96a66cSDavid du Colombier 9315e96a66cSDavid du Colombier parseAname(m->t.aname, &fsname, &path); 9325e96a66cSDavid du Colombier if((fsys = fsysGet(fsname)) == nil){ 9335e96a66cSDavid du Colombier fidClunk(fid); 9345e96a66cSDavid du Colombier vtMemFree(fsname); 9355e96a66cSDavid du Colombier return 0; 9365e96a66cSDavid du Colombier } 9375e96a66cSDavid du Colombier fid->fsys = fsys; 9385e96a66cSDavid du Colombier 9395e96a66cSDavid du Colombier if(m->t.uname[0] != '\0') 9405e96a66cSDavid du Colombier fid->uname = vtStrDup(m->t.uname); 9415e96a66cSDavid du Colombier else 9425e96a66cSDavid du Colombier fid->uname = vtStrDup(unamenone); 9435e96a66cSDavid du Colombier 944dc5a79c1SDavid du Colombier if(fsysNoAuthCheck(fsys) || m->con->noauth){ 9455e96a66cSDavid du Colombier if((fid->uid = uidByUname(fid->uname)) == nil) 9465e96a66cSDavid du Colombier fid->uid = vtStrDup(unamenone); 9475e96a66cSDavid du Colombier } 9485e96a66cSDavid du Colombier else if(!authCheck(&m->t, fid, fsys)){ 9495e96a66cSDavid du Colombier fidClunk(fid); 9505e96a66cSDavid du Colombier vtMemFree(fsname); 9515e96a66cSDavid du Colombier vtSetError("authentication failed"); 9525e96a66cSDavid du Colombier return 0; 9535e96a66cSDavid du Colombier } 9545e96a66cSDavid du Colombier 9555e96a66cSDavid du Colombier fsysFsRlock(fsys); 9565e96a66cSDavid du Colombier if((fid->file = fsysGetRoot(fsys, path)) == nil){ 9575e96a66cSDavid du Colombier fsysFsRUnlock(fsys); 9585e96a66cSDavid du Colombier fidClunk(fid); 9595e96a66cSDavid du Colombier vtMemFree(fsname); 9605e96a66cSDavid du Colombier return 0; 9615e96a66cSDavid du Colombier } 9625e96a66cSDavid du Colombier fsysFsRUnlock(fsys); 9635e96a66cSDavid du Colombier vtMemFree(fsname); 9645e96a66cSDavid du Colombier 9655e96a66cSDavid du Colombier fid->qid = (Qid){fileGetId(fid->file), 0, QTDIR}; 9665e96a66cSDavid du Colombier m->r.qid = fid->qid; 9675e96a66cSDavid du Colombier 9685e96a66cSDavid du Colombier fidPut(fid); 9695e96a66cSDavid du Colombier return 1; 9705e96a66cSDavid du Colombier } 9715e96a66cSDavid du Colombier 9725e96a66cSDavid du Colombier static int 9735e96a66cSDavid du Colombier rTauth(Msg* m) 9745e96a66cSDavid du Colombier { 9755e96a66cSDavid du Colombier int afd; 9765e96a66cSDavid du Colombier Con *con; 9775e96a66cSDavid du Colombier Fid *afid; 9785e96a66cSDavid du Colombier Fsys *fsys; 9795e96a66cSDavid du Colombier char *fsname, *path; 9805e96a66cSDavid du Colombier 9815e96a66cSDavid du Colombier parseAname(m->t.aname, &fsname, &path); 9825e96a66cSDavid du Colombier if((fsys = fsysGet(fsname)) == nil){ 9835e96a66cSDavid du Colombier vtMemFree(fsname); 9845e96a66cSDavid du Colombier return 0; 9855e96a66cSDavid du Colombier } 9865e96a66cSDavid du Colombier vtMemFree(fsname); 9875e96a66cSDavid du Colombier 988dc5a79c1SDavid du Colombier if(fsysNoAuthCheck(fsys) || m->con->noauth){ 9895e96a66cSDavid du Colombier m->con->aok = 1; 9905e96a66cSDavid du Colombier vtSetError("authentication disabled"); 9915e96a66cSDavid du Colombier fsysPut(fsys); 9925e96a66cSDavid du Colombier return 0; 9935e96a66cSDavid du Colombier } 9945e96a66cSDavid du Colombier if(strcmp(m->t.uname, unamenone) == 0){ 9955e96a66cSDavid du Colombier vtSetError("user 'none' requires no authentication"); 9965e96a66cSDavid du Colombier fsysPut(fsys); 9975e96a66cSDavid du Colombier return 0; 9985e96a66cSDavid du Colombier } 9995e96a66cSDavid du Colombier 10005e96a66cSDavid du Colombier con = m->con; 10015e96a66cSDavid du Colombier if((afid = fidGet(con, m->t.afid, FidFWlock|FidFCreate)) == nil){ 10025e96a66cSDavid du Colombier fsysPut(fsys); 10035e96a66cSDavid du Colombier return 0; 10045e96a66cSDavid du Colombier } 10055e96a66cSDavid du Colombier afid->fsys = fsys; 10065e96a66cSDavid du Colombier 10075e96a66cSDavid du Colombier if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0){ 10085e96a66cSDavid du Colombier vtSetError("can't open \"/mnt/factotum/rpc\""); 10095e96a66cSDavid du Colombier fidClunk(afid); 10105e96a66cSDavid du Colombier return 0; 10115e96a66cSDavid du Colombier } 10125e96a66cSDavid du Colombier if((afid->rpc = auth_allocrpc(afd)) == nil){ 10135e96a66cSDavid du Colombier close(afd); 10145e96a66cSDavid du Colombier vtSetError("can't auth_allocrpc"); 10155e96a66cSDavid du Colombier fidClunk(afid); 10165e96a66cSDavid du Colombier return 0; 10175e96a66cSDavid du Colombier } 10185e96a66cSDavid du Colombier if(auth_rpc(afid->rpc, "start", "proto=p9any role=server", 23) != ARok){ 10195e96a66cSDavid du Colombier vtSetError("can't auth_rpc"); 10205e96a66cSDavid du Colombier fidClunk(afid); 10215e96a66cSDavid du Colombier return 0; 10225e96a66cSDavid du Colombier } 10235e96a66cSDavid du Colombier 10245e96a66cSDavid du Colombier afid->open = FidOWrite|FidORead; 10255e96a66cSDavid du Colombier afid->qid.type = QTAUTH; 10265e96a66cSDavid du Colombier afid->qid.path = m->t.afid; 10275e96a66cSDavid du Colombier afid->uname = vtStrDup(m->t.uname); 10285e96a66cSDavid du Colombier 10295e96a66cSDavid du Colombier m->r.qid = afid->qid; 10305e96a66cSDavid du Colombier 10315e96a66cSDavid du Colombier fidPut(afid); 10325e96a66cSDavid du Colombier return 1; 10335e96a66cSDavid du Colombier } 10345e96a66cSDavid du Colombier 10355e96a66cSDavid du Colombier static int 10365e96a66cSDavid du Colombier rTversion(Msg* m) 10375e96a66cSDavid du Colombier { 10385e96a66cSDavid du Colombier int v; 10395e96a66cSDavid du Colombier Con *con; 10405e96a66cSDavid du Colombier Fcall *r, *t; 10415e96a66cSDavid du Colombier 10425e96a66cSDavid du Colombier t = &m->t; 10435e96a66cSDavid du Colombier r = &m->r; 10445e96a66cSDavid du Colombier con = m->con; 10455e96a66cSDavid du Colombier 10465e96a66cSDavid du Colombier vtLock(con->lock); 104734e04225SDavid du Colombier if(con->state != ConInit){ 10485e96a66cSDavid du Colombier vtUnlock(con->lock); 10495e96a66cSDavid du Colombier vtSetError("Tversion: down"); 10505e96a66cSDavid du Colombier return 0; 10515e96a66cSDavid du Colombier } 105234e04225SDavid du Colombier con->state = ConNew; 10535e96a66cSDavid du Colombier 10545e96a66cSDavid du Colombier /* 10555e96a66cSDavid du Colombier * Release the karma of past lives and suffering. 105634e04225SDavid du Colombier * Should this be done before or after checking the 105734e04225SDavid du Colombier * validity of the Tversion? 10585e96a66cSDavid du Colombier */ 105934e04225SDavid du Colombier fidClunkAll(con); 10605e96a66cSDavid du Colombier 10615e96a66cSDavid du Colombier if(t->tag != NOTAG){ 10625e96a66cSDavid du Colombier vtUnlock(con->lock); 10635e96a66cSDavid du Colombier vtSetError("Tversion: invalid tag"); 10645e96a66cSDavid du Colombier return 0; 10655e96a66cSDavid du Colombier } 10665e96a66cSDavid du Colombier 10675e96a66cSDavid du Colombier if(t->msize < 256){ 10685e96a66cSDavid du Colombier vtUnlock(con->lock); 10695e96a66cSDavid du Colombier vtSetError("Tversion: message size too small"); 10705e96a66cSDavid du Colombier return 0; 10715e96a66cSDavid du Colombier } 10725e96a66cSDavid du Colombier if(t->msize < con->msize) 10735e96a66cSDavid du Colombier r->msize = t->msize; 10745e96a66cSDavid du Colombier else 10755e96a66cSDavid du Colombier r->msize = con->msize; 10765e96a66cSDavid du Colombier 10775e96a66cSDavid du Colombier r->version = "unknown"; 10785e96a66cSDavid du Colombier if(t->version[0] == '9' && t->version[1] == 'P'){ 10795e96a66cSDavid du Colombier /* 10805e96a66cSDavid du Colombier * Currently, the only defined version 10815e96a66cSDavid du Colombier * is "9P2000"; ignore any later versions. 10825e96a66cSDavid du Colombier */ 10835e96a66cSDavid du Colombier v = strtol(&t->version[2], 0, 10); 10845e96a66cSDavid du Colombier if(v >= 2000){ 10855e96a66cSDavid du Colombier r->version = VERSION9P; 10865e96a66cSDavid du Colombier con->msize = r->msize; 108734e04225SDavid du Colombier con->state = ConUp; 10885e96a66cSDavid du Colombier } 10895e96a66cSDavid du Colombier else if(strcmp(t->version, "9PEoF") == 0){ 10905e96a66cSDavid du Colombier r->version = "9PEoF"; 10915e96a66cSDavid du Colombier con->msize = r->msize; 109234e04225SDavid du Colombier con->state = ConMoribund; 10935e96a66cSDavid du Colombier } 10945e96a66cSDavid du Colombier } 10955e96a66cSDavid du Colombier vtUnlock(con->lock); 10965e96a66cSDavid du Colombier 10975e96a66cSDavid du Colombier return 1; 10985e96a66cSDavid du Colombier } 10995e96a66cSDavid du Colombier 11005e96a66cSDavid du Colombier int (*rFcall[Tmax])(Msg*) = { 11015e96a66cSDavid du Colombier [Tversion] = rTversion, 11025e96a66cSDavid du Colombier [Tauth] = rTauth, 11035e96a66cSDavid du Colombier [Tattach] = rTattach, 11045e96a66cSDavid du Colombier [Tflush] = rTflush, 11055e96a66cSDavid du Colombier [Twalk] = rTwalk, 11065e96a66cSDavid du Colombier [Topen] = rTopen, 11075e96a66cSDavid du Colombier [Tcreate] = rTcreate, 11085e96a66cSDavid du Colombier [Tread] = rTread, 11095e96a66cSDavid du Colombier [Twrite] = rTwrite, 11105e96a66cSDavid du Colombier [Tclunk] = rTclunk, 11115e96a66cSDavid du Colombier [Tremove] = rTremove, 11125e96a66cSDavid du Colombier [Tstat] = rTstat, 11135e96a66cSDavid du Colombier [Twstat] = rTwstat, 11145e96a66cSDavid du Colombier }; 1115