9p2.c 35 KB

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