9p1.c 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444
  1. #include "all.h"
  2. #include "9p1.h"
  3. /*
  4. * buggery to give false qid for
  5. * the top 2 levels of the dump fs
  6. */
  7. void
  8. mkqid(Qid* qid, Dentry *d, int buggery)
  9. {
  10. int c;
  11. if(buggery && d->qid.path == QPROOT && (d->qid.path & QPDIR)){
  12. c = d->name[0];
  13. if(c >= '0' && c <= '9'){
  14. qid->path = 3;
  15. qid->vers = d->qid.version;
  16. qid->type = QTDIR;
  17. c = (c-'0')*10 + (d->name[1]-'0');
  18. if(c >= 1 && c <= 12)
  19. qid->path = 4;
  20. return;
  21. }
  22. }
  23. mkqid9p2(qid, &d->qid, d->mode);
  24. }
  25. int
  26. mkqidcmp(Qid* qid, Dentry *d)
  27. {
  28. Qid tmp;
  29. mkqid(&tmp, d, 1);
  30. if(qid->path==tmp.path && (qid->type&QTDIR)==(tmp.type&QTDIR))
  31. return 0;
  32. return Eqid;
  33. }
  34. void
  35. f_nop(Chan *cp, Oldfcall *in, Oldfcall *ou)
  36. {
  37. USED(in);
  38. USED(ou);
  39. if(CHAT(cp))
  40. print("c_nop %d\n", cp->chan);
  41. }
  42. void
  43. f_flush(Chan *cp, Oldfcall *in, Oldfcall *ou)
  44. {
  45. USED(in);
  46. USED(ou);
  47. if(CHAT(cp))
  48. print("c_flush %d\n", cp->chan);
  49. runlock(&cp->reflock);
  50. wlock(&cp->reflock);
  51. wunlock(&cp->reflock);
  52. rlock(&cp->reflock);
  53. }
  54. void
  55. f_session(Chan *cp, Oldfcall *in, Oldfcall *ou)
  56. {
  57. if(CHAT(cp))
  58. print("c_session %d\n", cp->chan);
  59. memmove(cp->rchal, in->chal, sizeof(cp->rchal));
  60. if(wstatallow || cp == cons.srvchan){
  61. memset(ou->chal, 0, sizeof(ou->chal));
  62. memset(ou->authid, 0, sizeof(ou->authid));
  63. }else{
  64. mkchallenge(cp);
  65. memmove(ou->chal, cp->chal, sizeof(ou->chal));
  66. memmove(ou->authid, nvr.authid, sizeof(ou->authid));
  67. }
  68. sprint(ou->authdom, "%s.%s", service, nvr.authdom);
  69. fileinit(cp);
  70. }
  71. void
  72. f_attach(Chan *cp, Oldfcall *in, Oldfcall *ou)
  73. {
  74. Iobuf *p;
  75. Dentry *d;
  76. File *f;
  77. int u;
  78. Filsys *fs;
  79. long raddr;
  80. if(CHAT(cp)) {
  81. print("c_attach %d\n", cp->chan);
  82. print(" fid = %d\n", in->fid);
  83. print(" uid = %s\n", in->uname);
  84. print(" arg = %s\n", in->aname);
  85. }
  86. ou->qid = QID9P1(0,0);
  87. ou->fid = in->fid;
  88. if(!in->aname[0]) /* default */
  89. strncpy(in->aname, filesys[0].name, sizeof(in->aname));
  90. p = 0;
  91. f = filep(cp, in->fid, 1);
  92. if(!f) {
  93. ou->err = Efid;
  94. goto out;
  95. }
  96. u = -1;
  97. if(cp != cons.chan){
  98. if(authorize(cp, in, ou) == 0 || strcmp(in->uname, "adm") == 0){
  99. ou->err = Eauth;
  100. goto out;
  101. }
  102. u = strtouid(in->uname);
  103. if(u < 0){
  104. ou->err = Ebadu;
  105. goto out;
  106. }
  107. }
  108. fs = fsstr(in->aname);
  109. if(fs == 0) {
  110. ou->err = Ebadspc;
  111. goto out;
  112. }
  113. raddr = getraddr(fs->dev);
  114. p = getbuf(fs->dev, raddr, Bread);
  115. d = getdir(p, 0);
  116. if(!d || checktag(p, Tdir, QPROOT) || !(d->mode & DALLOC)) {
  117. ou->err = Ealloc;
  118. goto out;
  119. }
  120. f->uid = u;
  121. if(iaccess(f, d, DREAD)) {
  122. ou->err = Eaccess;
  123. goto out;
  124. }
  125. accessdir(p, d, FREAD);
  126. mkqid(&f->qid, d, 1);
  127. f->fs = fs;
  128. f->addr = raddr;
  129. f->slot = 0;
  130. f->open = 0;
  131. freewp(f->wpath);
  132. f->wpath = 0;
  133. mkqid9p1(&ou->qid, &f->qid);
  134. out:
  135. if(p)
  136. putbuf(p);
  137. if(f) {
  138. qunlock(f);
  139. if(ou->err)
  140. freefp(f);
  141. }
  142. }
  143. void
  144. f_clone(Chan *cp, Oldfcall *in, Oldfcall *ou)
  145. {
  146. File *f1, *f2;
  147. int fid, fid1;
  148. if(CHAT(cp)) {
  149. print("c_clone %d\n", cp->chan);
  150. print(" old fid = %d\n", in->fid);
  151. print(" new fid = %d\n", in->newfid);
  152. }
  153. fid = in->fid;
  154. fid1 = in->newfid;
  155. f1 = 0;
  156. f2 = 0;
  157. if(fid < fid1) {
  158. f1 = filep(cp, fid, 0);
  159. f2 = filep(cp, fid1, 1);
  160. } else
  161. if(fid1 < fid) {
  162. f2 = filep(cp, fid1, 1);
  163. f1 = filep(cp, fid, 0);
  164. }
  165. if(!f1 || !f2) {
  166. ou->err = Efid;
  167. goto out;
  168. }
  169. f2->fs = f1->fs;
  170. f2->addr = f1->addr;
  171. f2->open = f1->open & ~FREMOV;
  172. f2->uid = f1->uid;
  173. f2->slot = f1->slot;
  174. f2->qid = f1->qid;
  175. freewp(f2->wpath);
  176. f2->wpath = getwp(f1->wpath);
  177. out:
  178. ou->fid = fid;
  179. if(f1)
  180. qunlock(f1);
  181. if(f2)
  182. qunlock(f2);
  183. }
  184. void
  185. f_walk(Chan *cp, Oldfcall *in, Oldfcall *ou)
  186. {
  187. Iobuf *p, *p1;
  188. Dentry *d, *d1;
  189. File *f;
  190. Wpath *w, *ow;
  191. int slot;
  192. long addr;
  193. if(CHAT(cp)) {
  194. print("c_walk %d\n", cp->chan);
  195. print(" fid = %d\n", in->fid);
  196. print(" name = %s\n", in->name);
  197. }
  198. ou->fid = in->fid;
  199. ou->qid = QID9P1(0,0);
  200. p = 0;
  201. f = filep(cp, in->fid, 0);
  202. if(!f) {
  203. ou->err = Efid;
  204. goto out;
  205. }
  206. p = getbuf(f->fs->dev, f->addr, Bread);
  207. d = getdir(p, f->slot);
  208. if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
  209. ou->err = Ealloc;
  210. goto out;
  211. }
  212. if(!(d->mode & DDIR)) {
  213. ou->err = Edir1;
  214. goto out;
  215. }
  216. if(ou->err = mkqidcmp(&f->qid, d))
  217. goto out;
  218. if(cp != cons.chan && iaccess(f, d, DEXEC)) {
  219. ou->err = Eaccess;
  220. goto out;
  221. }
  222. accessdir(p, d, FREAD);
  223. if(strcmp(in->name, ".") == 0)
  224. goto setdot;
  225. if(strcmp(in->name, "..") == 0) {
  226. if(f->wpath == 0)
  227. goto setdot;
  228. putbuf(p);
  229. p = 0;
  230. addr = f->wpath->addr;
  231. slot = f->wpath->slot;
  232. p1 = getbuf(f->fs->dev, addr, Bread);
  233. d1 = getdir(p1, slot);
  234. if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
  235. if(p1)
  236. putbuf(p1);
  237. ou->err = Ephase;
  238. goto out;
  239. }
  240. ow = f->wpath;
  241. f->wpath = ow->up;
  242. putwp(ow);
  243. goto found;
  244. }
  245. for(addr=0;; addr++) {
  246. p1 = dnodebuf(p, d, addr, 0);
  247. if(!p1 || checktag(p1, Tdir, d->qid.path) ) {
  248. if(p1)
  249. putbuf(p1);
  250. ou->err = Eentry;
  251. goto out;
  252. }
  253. for(slot=0; slot<DIRPERBUF; slot++) {
  254. d1 = getdir(p1, slot);
  255. if(!(d1->mode & DALLOC))
  256. continue;
  257. if(strncmp(in->name, d1->name, sizeof(in->name)))
  258. continue;
  259. /*
  260. * update walk path
  261. */
  262. w = newwp();
  263. if(!w) {
  264. ou->err = Ewalk;
  265. putbuf(p1);
  266. goto out;
  267. }
  268. w->addr = f->addr;
  269. w->slot = f->slot;
  270. w->up = f->wpath;
  271. f->wpath = w;
  272. slot += DIRPERBUF*addr;
  273. goto found;
  274. }
  275. putbuf(p1);
  276. }
  277. found:
  278. f->addr = p1->addr;
  279. mkqid(&f->qid, d1, 1);
  280. putbuf(p1);
  281. f->slot = slot;
  282. setdot:
  283. mkqid9p1(&ou->qid, &f->qid);
  284. f->open = 0;
  285. out:
  286. if(p)
  287. putbuf(p);
  288. if(f)
  289. qunlock(f);
  290. }
  291. void
  292. f_clunk(Chan *cp, Oldfcall *in, Oldfcall *ou)
  293. {
  294. File *f;
  295. Tlock *t;
  296. long tim;
  297. if(CHAT(cp)) {
  298. print("c_clunk %d\n", cp->chan);
  299. print(" fid = %d\n", in->fid);
  300. }
  301. f = filep(cp, in->fid, 0);
  302. if(!f) {
  303. print("%p\n", f);
  304. ou->err = Efid;
  305. goto out;
  306. }
  307. if(t = f->tlock) {
  308. tim = time(0);
  309. if(t->time < tim || t->file != f)
  310. ou->err = Ebroken;
  311. t->time = 0; /* free the lock */
  312. f->tlock = 0;
  313. }
  314. if(f->open & FREMOV)
  315. ou->err = doremove(f, 0);
  316. f->open = 0;
  317. freewp(f->wpath);
  318. freefp(f);
  319. out:
  320. if(f)
  321. qunlock(f);
  322. ou->fid = in->fid;
  323. }
  324. void
  325. f_clwalk(Chan *cp, Oldfcall *in, Oldfcall *ou)
  326. {
  327. int er, fid;
  328. if(CHAT(cp))
  329. print("c_clwalk macro\n");
  330. f_clone(cp, in, ou); /* sets tag, fid */
  331. if(ou->err)
  332. return;
  333. fid = in->fid;
  334. in->fid = in->newfid;
  335. f_walk(cp, in, ou); /* sets tag, fid, qid */
  336. er = ou->err;
  337. if(er == Eentry) {
  338. /*
  339. * if error is "no entry"
  340. * return non error and fid
  341. */
  342. ou->err = 0;
  343. f_clunk(cp, in, ou); /* sets tag, fid */
  344. ou->err = 0;
  345. ou->fid = fid;
  346. if(CHAT(cp))
  347. print(" error: %s\n", errstring[er]);
  348. return;
  349. }
  350. if(er) {
  351. /*
  352. * if any other error
  353. * return an error
  354. */
  355. ou->err = 0;
  356. f_clunk(cp, in, ou); /* sets tag, fid */
  357. ou->err = er;
  358. return;
  359. }
  360. /*
  361. * non error
  362. * return newfid
  363. */
  364. }
  365. void
  366. f_open(Chan *cp, Oldfcall *in, Oldfcall *ou)
  367. {
  368. Iobuf *p;
  369. Dentry *d;
  370. File *f;
  371. Tlock *t;
  372. Qid qid;
  373. int ro, fmod;
  374. if(CHAT(cp)) {
  375. print("c_open %d\n", cp->chan);
  376. print(" fid = %d\n", in->fid);
  377. print(" mode = %o\n", in->mode);
  378. }
  379. p = 0;
  380. f = filep(cp, in->fid, 0);
  381. if(!f) {
  382. ou->err = Efid;
  383. goto out;
  384. }
  385. /*
  386. * if remove on close, check access here
  387. */
  388. ro = isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup));
  389. if(in->mode & MRCLOSE) {
  390. if(ro) {
  391. ou->err = Eronly;
  392. goto out;
  393. }
  394. /*
  395. * check on parent directory of file to be deleted
  396. */
  397. if(f->wpath == 0 || f->wpath->addr == f->addr) {
  398. ou->err = Ephase;
  399. goto out;
  400. }
  401. p = getbuf(f->fs->dev, f->wpath->addr, Bread);
  402. d = getdir(p, f->wpath->slot);
  403. if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
  404. ou->err = Ephase;
  405. goto out;
  406. }
  407. if(iaccess(f, d, DWRITE)) {
  408. ou->err = Eaccess;
  409. goto out;
  410. }
  411. putbuf(p);
  412. }
  413. p = getbuf(f->fs->dev, f->addr, Bread);
  414. d = getdir(p, f->slot);
  415. if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
  416. ou->err = Ealloc;
  417. goto out;
  418. }
  419. if(ou->err = mkqidcmp(&f->qid, d))
  420. goto out;
  421. mkqid(&qid, d, 1);
  422. switch(in->mode & 7) {
  423. case MREAD:
  424. if(iaccess(f, d, DREAD) && !writeallow)
  425. goto badaccess;
  426. fmod = FREAD;
  427. break;
  428. case MWRITE:
  429. if((d->mode & DDIR) ||
  430. (iaccess(f, d, DWRITE) && !writeallow))
  431. goto badaccess;
  432. if(ro) {
  433. ou->err = Eronly;
  434. goto out;
  435. }
  436. fmod = FWRITE;
  437. break;
  438. case MBOTH:
  439. if((d->mode & DDIR) ||
  440. (iaccess(f, d, DREAD) && !writeallow) ||
  441. (iaccess(f, d, DWRITE) && !writeallow))
  442. goto badaccess;
  443. if(ro) {
  444. ou->err = Eronly;
  445. goto out;
  446. }
  447. fmod = FREAD+FWRITE;
  448. break;
  449. case MEXEC:
  450. if((d->mode & DDIR) ||
  451. iaccess(f, d, DEXEC))
  452. goto badaccess;
  453. fmod = FREAD;
  454. break;
  455. default:
  456. ou->err = Emode;
  457. goto out;
  458. }
  459. if(in->mode & MTRUNC) {
  460. if((d->mode & DDIR) ||
  461. (iaccess(f, d, DWRITE) && !writeallow))
  462. goto badaccess;
  463. if(ro) {
  464. ou->err = Eronly;
  465. goto out;
  466. }
  467. }
  468. t = 0;
  469. if(d->mode & DLOCK) {
  470. t = tlocked(p, d);
  471. if(t == 0) {
  472. ou->err = Elocked;
  473. goto out;
  474. }
  475. t->file = f;
  476. }
  477. if(in->mode & MRCLOSE)
  478. fmod |= FREMOV;
  479. f->open = fmod;
  480. if(in->mode & MTRUNC)
  481. if(!(d->mode & DAPND))
  482. dtrunc(p, d);
  483. f->tlock = t;
  484. f->lastra = 0;
  485. mkqid9p1(&ou->qid, &qid);
  486. goto out;
  487. badaccess:
  488. ou->err = Eaccess;
  489. f->open = 0;
  490. out:
  491. if(p)
  492. putbuf(p);
  493. if(f)
  494. qunlock(f);
  495. ou->fid = in->fid;
  496. }
  497. void
  498. f_create(Chan *cp, Oldfcall *in, Oldfcall *ou)
  499. {
  500. Iobuf *p, *p1;
  501. Dentry *d, *d1;
  502. File *f;
  503. int slot, slot1, fmod;
  504. long addr, addr1, path;
  505. Qid qid;
  506. Tlock *t;
  507. Wpath *w;
  508. if(CHAT(cp)) {
  509. print("c_create %d\n", cp->chan);
  510. print(" fid = %d\n", in->fid);
  511. print(" name = %s\n", in->name);
  512. print(" perm = %lx+%lo\n", (in->perm>>28)&0xf,
  513. in->perm&0777);
  514. print(" mode = %d\n", in->mode);
  515. }
  516. p = 0;
  517. f = filep(cp, in->fid, 0);
  518. if(!f) {
  519. ou->err = Efid;
  520. goto out;
  521. }
  522. if(isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) {
  523. ou->err = Eronly;
  524. goto out;
  525. }
  526. p = getbuf(f->fs->dev, f->addr, Bread);
  527. d = getdir(p, f->slot);
  528. if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
  529. ou->err = Ealloc;
  530. goto out;
  531. }
  532. if(ou->err = mkqidcmp(&f->qid, d))
  533. goto out;
  534. if(!(d->mode & DDIR)) {
  535. ou->err = Edir2;
  536. goto out;
  537. }
  538. if(cp != cons.chan && iaccess(f, d, DWRITE) && !writeallow) {
  539. ou->err = Eaccess;
  540. goto out;
  541. }
  542. accessdir(p, d, FREAD);
  543. if(!strncmp(in->name, ".", sizeof(in->name)) ||
  544. !strncmp(in->name, "..", sizeof(in->name))) {
  545. ou->err = Edot;
  546. goto out;
  547. }
  548. if(checkname(in->name)) {
  549. ou->err = Ename;
  550. goto out;
  551. }
  552. addr1 = 0;
  553. slot1 = 0; /* set */
  554. for(addr=0;; addr++) {
  555. p1 = dnodebuf(p, d, addr, 0);
  556. if(!p1) {
  557. if(addr1)
  558. break;
  559. p1 = dnodebuf(p, d, addr, Tdir);
  560. }
  561. if(p1 == 0) {
  562. ou->err = Efull;
  563. goto out;
  564. }
  565. if(checktag(p1, Tdir, d->qid.path)) {
  566. putbuf(p1);
  567. goto phase;
  568. }
  569. for(slot=0; slot<DIRPERBUF; slot++) {
  570. d1 = getdir(p1, slot);
  571. if(!(d1->mode & DALLOC)) {
  572. if(!addr1) {
  573. addr1 = p1->addr;
  574. slot1 = slot + addr*DIRPERBUF;
  575. }
  576. continue;
  577. }
  578. if(!strncmp(in->name, d1->name, sizeof(in->name))) {
  579. putbuf(p1);
  580. ou->err = Eexist;
  581. goto out;
  582. }
  583. }
  584. putbuf(p1);
  585. }
  586. switch(in->mode & 7) {
  587. case MEXEC:
  588. case MREAD: /* seems only useful to make directories */
  589. fmod = FREAD;
  590. break;
  591. case MWRITE:
  592. fmod = FWRITE;
  593. break;
  594. case MBOTH:
  595. fmod = FREAD+FWRITE;
  596. break;
  597. default:
  598. ou->err = Emode;
  599. goto out;
  600. }
  601. if(in->perm & PDIR)
  602. if((in->mode & MTRUNC) || (in->perm & PAPND) || (fmod & FWRITE))
  603. goto badaccess;
  604. /*
  605. * do it
  606. */
  607. path = qidpathgen(&f->fs->dev);
  608. p1 = getbuf(f->fs->dev, addr1, Bread|Bimm|Bmod);
  609. d1 = getdir(p1, slot1);
  610. if(!d1 || checktag(p1, Tdir, d->qid.path)) {
  611. if(p1)
  612. putbuf(p1);
  613. goto phase;
  614. }
  615. if(d1->mode & DALLOC) {
  616. putbuf(p1);
  617. goto phase;
  618. }
  619. strncpy(d1->name, in->name, sizeof(in->name));
  620. /*
  621. * bogus argument passing -- see console.c
  622. */
  623. if(cp == cons.chan) {
  624. d1->uid = cons.uid;
  625. d1->gid = cons.gid;
  626. } else {
  627. d1->uid = f->uid;
  628. d1->gid = d->gid;
  629. in->perm &= d->mode | ~0666;
  630. if(in->perm & PDIR)
  631. in->perm &= d->mode | ~0777;
  632. }
  633. d1->qid.path = path;
  634. d1->qid.version = 0;
  635. d1->mode = DALLOC | (in->perm & 0777);
  636. if(in->perm & PDIR) {
  637. d1->mode |= DDIR;
  638. d1->qid.path |= QPDIR;
  639. }
  640. if(in->perm & PAPND)
  641. d1->mode |= DAPND;
  642. t = 0;
  643. if(in->perm & PLOCK) {
  644. d1->mode |= DLOCK;
  645. t = tlocked(p1, d1);
  646. }
  647. accessdir(p1, d1, FWRITE);
  648. mkqid(&qid, d1, 0);
  649. putbuf(p1);
  650. accessdir(p, d, FWRITE);
  651. /*
  652. * do a walk to new directory entry
  653. */
  654. w = newwp();
  655. if(!w) {
  656. ou->err = Ewalk;
  657. goto out;
  658. }
  659. w->addr = f->addr;
  660. w->slot = f->slot;
  661. w->up = f->wpath;
  662. f->wpath = w;
  663. f->qid = qid;
  664. f->tlock = t;
  665. f->lastra = 0;
  666. if(in->mode & MRCLOSE)
  667. fmod |= FREMOV;
  668. f->open = fmod;
  669. f->addr = addr1;
  670. f->slot = slot1;
  671. if(t)
  672. t->file = f;
  673. mkqid9p1(&ou->qid, &qid);
  674. goto out;
  675. badaccess:
  676. ou->err = Eaccess;
  677. goto out;
  678. phase:
  679. ou->err = Ephase;
  680. out:
  681. if(p)
  682. putbuf(p);
  683. if(f)
  684. qunlock(f);
  685. ou->fid = in->fid;
  686. }
  687. void
  688. f_read(Chan *cp, Oldfcall *in, Oldfcall *ou)
  689. {
  690. Iobuf *p, *p1;
  691. File *f;
  692. Dentry *d, *d1;
  693. Tlock *t;
  694. long addr, offset, tim;
  695. int nread, count, n, o, slot;
  696. if(CHAT(cp)) {
  697. print("c_read %d\n", cp->chan);
  698. print(" fid = %d\n", in->fid);
  699. print(" offset = %ld\n", in->offset);
  700. print(" count = %ld\n", in->count);
  701. }
  702. p = 0;
  703. count = in->count;
  704. offset = in->offset;
  705. nread = 0;
  706. f = filep(cp, in->fid, 0);
  707. if(!f) {
  708. ou->err = Efid;
  709. goto out;
  710. }
  711. if(!(f->open & FREAD)) {
  712. ou->err = Eopen;
  713. goto out;
  714. }
  715. if(count < 0 || count > MAXDAT) {
  716. ou->err = Ecount;
  717. goto out;
  718. }
  719. if(offset < 0) {
  720. ou->err = Eoffset;
  721. goto out;
  722. }
  723. p = getbuf(f->fs->dev, f->addr, Bread);
  724. d = getdir(p, f->slot);
  725. if(!d || !(d->mode & DALLOC)) {
  726. ou->err = Ealloc;
  727. goto out;
  728. }
  729. if(ou->err = mkqidcmp(&f->qid, d))
  730. goto out;
  731. if(t = f->tlock) {
  732. tim = time(0);
  733. if(t->time < tim || t->file != f) {
  734. ou->err = Ebroken;
  735. goto out;
  736. }
  737. /* renew the lock */
  738. t->time = tim + TLOCK;
  739. }
  740. accessdir(p, d, FREAD);
  741. if(d->mode & DDIR) {
  742. addr = 0;
  743. goto dread;
  744. }
  745. if(offset+count > d->size)
  746. count = d->size - offset;
  747. while(count > 0) {
  748. addr = offset / BUFSIZE;
  749. if(addr == f->lastra+1)
  750. dbufread(p, d, addr+1);
  751. f->lastra = addr;
  752. o = offset % BUFSIZE;
  753. n = BUFSIZE - o;
  754. if(n > count)
  755. n = count;
  756. p1 = dnodebuf(p, d, addr, 0);
  757. if(p1) {
  758. if(checktag(p1, Tfile, QPNONE)) {
  759. ou->err = Ephase;
  760. putbuf(p1);
  761. goto out;
  762. }
  763. memmove(ou->data+nread, p1->iobuf+o, n);
  764. putbuf(p1);
  765. } else
  766. memset(ou->data+nread, 0, n);
  767. count -= n;
  768. nread += n;
  769. offset += n;
  770. }
  771. goto out;
  772. dread:
  773. p1 = dnodebuf(p, d, addr, 0);
  774. if(!p1)
  775. goto out;
  776. if(checktag(p1, Tdir, QPNONE)) {
  777. ou->err = Ephase;
  778. putbuf(p1);
  779. goto out;
  780. }
  781. n = DIRREC;
  782. for(slot=0; slot<DIRPERBUF; slot++) {
  783. d1 = getdir(p1, slot);
  784. if(!(d1->mode & DALLOC))
  785. continue;
  786. if(offset >= n) {
  787. offset -= n;
  788. continue;
  789. }
  790. if(count < n) {
  791. putbuf(p1);
  792. goto out;
  793. }
  794. if(convD2M9p1(d1, ou->data+nread) != n)
  795. print("dirread convD2M\n");
  796. nread += n;
  797. count -= n;
  798. }
  799. putbuf(p1);
  800. addr++;
  801. goto dread;
  802. out:
  803. count = in->count - nread;
  804. if(count > 0)
  805. memset(ou->data+nread, 0, count);
  806. if(p)
  807. putbuf(p);
  808. if(f)
  809. qunlock(f);
  810. ou->fid = in->fid;
  811. ou->count = nread;
  812. if(CHAT(cp))
  813. print(" nread = %d\n", nread);
  814. }
  815. void
  816. f_write(Chan *cp, Oldfcall *in, Oldfcall *ou)
  817. {
  818. Iobuf *p, *p1;
  819. Dentry *d;
  820. File *f;
  821. Tlock *t;
  822. long offset, addr, tim;
  823. int count, nwrite, o, n;
  824. if(CHAT(cp)) {
  825. print("c_write %d\n", cp->chan);
  826. print(" fid = %d\n", in->fid);
  827. print(" offset = %ld\n", in->offset);
  828. print(" count = %ld\n", in->count);
  829. }
  830. offset = in->offset;
  831. count = in->count;
  832. nwrite = 0;
  833. p = 0;
  834. f = filep(cp, in->fid, 0);
  835. if(!f) {
  836. ou->err = Efid;
  837. goto out;
  838. }
  839. if(!(f->open & FWRITE)) {
  840. ou->err = Eopen;
  841. goto out;
  842. }
  843. if(isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) {
  844. ou->err = Eronly;
  845. goto out;
  846. }
  847. if(count < 0 || count > MAXDAT) {
  848. ou->err = Ecount;
  849. goto out;
  850. }
  851. if(offset < 0) {
  852. ou->err = Eoffset;
  853. goto out;
  854. }
  855. p = getbuf(f->fs->dev, f->addr, Bread|Bmod);
  856. d = getdir(p, f->slot);
  857. if(!d || !(d->mode & DALLOC)) {
  858. ou->err = Ealloc;
  859. goto out;
  860. }
  861. if(ou->err = mkqidcmp(&f->qid, d))
  862. goto out;
  863. if(t = f->tlock) {
  864. tim = time(0);
  865. if(t->time < tim || t->file != f) {
  866. ou->err = Ebroken;
  867. goto out;
  868. }
  869. /* renew the lock */
  870. t->time = tim + TLOCK;
  871. }
  872. accessdir(p, d, FWRITE);
  873. if(d->mode & DAPND)
  874. offset = d->size;
  875. if(offset+count > d->size)
  876. d->size = offset+count;
  877. while(count > 0) {
  878. addr = offset / BUFSIZE;
  879. o = offset % BUFSIZE;
  880. n = BUFSIZE - o;
  881. if(n > count)
  882. n = count;
  883. p1 = dnodebuf(p, d, addr, Tfile);
  884. if(p1 == 0) {
  885. ou->err = Efull;
  886. goto out;
  887. }
  888. if(checktag(p1, Tfile, d->qid.path)) {
  889. putbuf(p1);
  890. ou->err = Ephase;
  891. goto out;
  892. }
  893. memmove(p1->iobuf+o, in->data+nwrite, n);
  894. p1->flags |= Bmod;
  895. putbuf(p1);
  896. count -= n;
  897. nwrite += n;
  898. offset += n;
  899. }
  900. if(CHAT(cp))
  901. print(" nwrite = %d\n", nwrite);
  902. out:
  903. if(p)
  904. putbuf(p);
  905. if(f)
  906. qunlock(f);
  907. ou->fid = in->fid;
  908. ou->count = nwrite;
  909. }
  910. int
  911. doremove(File *f, int iscon)
  912. {
  913. Iobuf *p, *p1;
  914. Dentry *d, *d1;
  915. long addr;
  916. int slot, err;
  917. p = 0;
  918. p1 = 0;
  919. if(isro(f->fs->dev) || (f->cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) {
  920. err = Eronly;
  921. goto out;
  922. }
  923. /*
  924. * check on parent directory of file to be deleted
  925. */
  926. if(f->wpath == 0 || f->wpath->addr == f->addr) {
  927. err = Ephase;
  928. goto out;
  929. }
  930. p1 = getbuf(f->fs->dev, f->wpath->addr, Bread);
  931. d1 = getdir(p1, f->wpath->slot);
  932. if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
  933. err = Ephase;
  934. goto out;
  935. }
  936. if(!iscon && iaccess(f, d1, DWRITE)) {
  937. err = Eaccess;
  938. goto out;
  939. }
  940. accessdir(p1, d1, FWRITE);
  941. putbuf(p1);
  942. p1 = 0;
  943. /*
  944. * check on file to be deleted
  945. */
  946. p = getbuf(f->fs->dev, f->addr, Bread);
  947. d = getdir(p, f->slot);
  948. if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
  949. err = Ealloc;
  950. goto out;
  951. }
  952. if(err = mkqidcmp(&f->qid, d))
  953. goto out;
  954. /*
  955. * if deleting a directory, make sure it is empty
  956. */
  957. if((d->mode & DDIR))
  958. for(addr=0;; addr++) {
  959. p1 = dnodebuf(p, d, addr, 0);
  960. if(!p1)
  961. break;
  962. if(checktag(p1, Tdir, d->qid.path)) {
  963. err = Ephase;
  964. goto out;
  965. }
  966. for(slot=0; slot<DIRPERBUF; slot++) {
  967. d1 = getdir(p1, slot);
  968. if(!(d1->mode & DALLOC))
  969. continue;
  970. err = Eempty;
  971. goto out;
  972. }
  973. putbuf(p1);
  974. }
  975. /*
  976. * do it
  977. */
  978. dtrunc(p, d);
  979. memset(d, 0, sizeof(Dentry));
  980. settag(p, Tdir, QPNONE);
  981. out:
  982. if(p1)
  983. putbuf(p1);
  984. if(p)
  985. putbuf(p);
  986. return err;
  987. }
  988. void
  989. f_remove(Chan *cp, Oldfcall *in, Oldfcall *ou)
  990. {
  991. File *f;
  992. if(CHAT(cp)) {
  993. print("c_remove %d\n", cp->chan);
  994. print(" fid = %d\n", in->fid);
  995. }
  996. f = filep(cp, in->fid, 0);
  997. if(!f) {
  998. ou->err = Efid;
  999. goto out;
  1000. }
  1001. ou->err = doremove(f, cp==cons.chan);
  1002. out:
  1003. ou->fid = in->fid;
  1004. if(f)
  1005. qunlock(f);
  1006. }
  1007. void
  1008. f_stat(Chan *cp, Oldfcall *in, Oldfcall *ou)
  1009. {
  1010. Iobuf *p;
  1011. Dentry *d;
  1012. File *f;
  1013. if(CHAT(cp)) {
  1014. print("c_stat %d\n", cp->chan);
  1015. print(" fid = %d\n", in->fid);
  1016. }
  1017. p = 0;
  1018. memset(ou->stat, 0, sizeof(ou->stat));
  1019. f = filep(cp, in->fid, 0);
  1020. if(!f) {
  1021. ou->err = Efid;
  1022. goto out;
  1023. }
  1024. p = getbuf(f->fs->dev, f->addr, Bread);
  1025. d = getdir(p, f->slot);
  1026. if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
  1027. ou->err = Ealloc;
  1028. goto out;
  1029. }
  1030. if(ou->err = mkqidcmp(&f->qid, d))
  1031. goto out;
  1032. if(d->qid.path == QPROOT) /* stat of root gives time */
  1033. d->atime = time(0);
  1034. if(convD2M9p1(d, ou->stat) != DIRREC)
  1035. print("stat convD2M\n");
  1036. out:
  1037. if(p)
  1038. putbuf(p);
  1039. if(f)
  1040. qunlock(f);
  1041. ou->fid = in->fid;
  1042. }
  1043. void
  1044. f_wstat(Chan *cp, Oldfcall *in, Oldfcall *ou)
  1045. {
  1046. Iobuf *p, *p1;
  1047. Dentry *d, *d1, xd;
  1048. File *f;
  1049. int slot;
  1050. long addr;
  1051. if(CHAT(cp)) {
  1052. print("c_wstat %d\n", cp->chan);
  1053. print(" fid = %d\n", in->fid);
  1054. }
  1055. p = 0;
  1056. p1 = 0;
  1057. d1 = 0;
  1058. f = filep(cp, in->fid, 0);
  1059. if(!f) {
  1060. ou->err = Efid;
  1061. goto out;
  1062. }
  1063. if(isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) {
  1064. ou->err = Eronly;
  1065. goto out;
  1066. }
  1067. /*
  1068. * first get parent
  1069. */
  1070. if(f->wpath) {
  1071. p1 = getbuf(f->fs->dev, f->wpath->addr, Bread);
  1072. d1 = getdir(p1, f->wpath->slot);
  1073. if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
  1074. ou->err = Ephase;
  1075. goto out;
  1076. }
  1077. }
  1078. p = getbuf(f->fs->dev, f->addr, Bread);
  1079. d = getdir(p, f->slot);
  1080. if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
  1081. ou->err = Ealloc;
  1082. goto out;
  1083. }
  1084. if(ou->err = mkqidcmp(&f->qid, d))
  1085. goto out;
  1086. convM2D9p1(in->stat, &xd);
  1087. if(CHAT(cp)) {
  1088. print(" d.name = %s\n", xd.name);
  1089. print(" d.uid = %d\n", xd.uid);
  1090. print(" d.gid = %d\n", xd.gid);
  1091. print(" d.mode = %.4x\n", xd.mode);
  1092. }
  1093. /*
  1094. * if chown,
  1095. * must be god
  1096. */
  1097. while(xd.uid != d->uid) {
  1098. if(wstatallow) /* set to allow chown during boot */
  1099. break;
  1100. ou->err = Enotu;
  1101. goto out;
  1102. }
  1103. /*
  1104. * if chgroup,
  1105. * must be either
  1106. * a) owner and in new group
  1107. * b) leader of both groups
  1108. */
  1109. while(xd.gid != d->gid) {
  1110. if(wstatallow || writeallow) /* set to allow chgrp during boot */
  1111. break;
  1112. if(d->uid == f->uid && ingroup(f->uid, xd.gid))
  1113. break;
  1114. if(leadgroup(f->uid, xd.gid))
  1115. if(leadgroup(f->uid, d->gid))
  1116. break;
  1117. ou->err = Enotg;
  1118. goto out;
  1119. }
  1120. /*
  1121. * if rename,
  1122. * must have write permission in parent
  1123. */
  1124. if(xd.name[0] == 0)
  1125. strncpy(xd.name, d->name, sizeof(xd.name));
  1126. while(strncmp(d->name, xd.name, sizeof(d->name)) != 0) {
  1127. if(checkname(xd.name)) {
  1128. ou->err = Ename;
  1129. goto out;
  1130. }
  1131. if(strcmp(xd.name, ".") == 0 || strcmp(xd.name, "..") == 0) {
  1132. ou->err = Ename;
  1133. goto out;
  1134. }
  1135. /*
  1136. * drop entry to prevent lock, then
  1137. * check that destination name is unique,
  1138. */
  1139. putbuf(p);
  1140. for(addr=0;; addr++) {
  1141. p = dnodebuf(p1, d1, addr, 0);
  1142. if(!p)
  1143. break;
  1144. if(checktag(p, Tdir, d1->qid.path)) {
  1145. putbuf(p);
  1146. continue;
  1147. }
  1148. for(slot=0; slot<DIRPERBUF; slot++) {
  1149. d = getdir(p, slot);
  1150. if(!(d->mode & DALLOC))
  1151. continue;
  1152. if(!strncmp(xd.name, d->name, sizeof(xd.name))) {
  1153. ou->err = Eexist;
  1154. goto out;
  1155. }
  1156. }
  1157. putbuf(p);
  1158. }
  1159. /*
  1160. * reacquire entry
  1161. */
  1162. p = getbuf(f->fs->dev, f->addr, Bread);
  1163. d = getdir(p, f->slot);
  1164. if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
  1165. ou->err = Ephase;
  1166. goto out;
  1167. }
  1168. if(wstatallow || writeallow) /* set to allow rename during boot */
  1169. break;
  1170. if(!d1 || iaccess(f, d1, DWRITE)) {
  1171. ou->err = Eaccess;
  1172. goto out;
  1173. }
  1174. break;
  1175. }
  1176. /*
  1177. * if mode/time, either
  1178. * a) owner
  1179. * b) leader of either group
  1180. */
  1181. while(d->mtime != xd.mtime ||
  1182. ((d->mode^xd.mode) & (DAPND|DLOCK|0777))) {
  1183. if(wstatallow) /* set to allow chmod during boot */
  1184. break;
  1185. if(d->uid == f->uid)
  1186. break;
  1187. if(leadgroup(f->uid, xd.gid))
  1188. break;
  1189. if(leadgroup(f->uid, d->gid))
  1190. break;
  1191. ou->err = Enotu;
  1192. goto out;
  1193. }
  1194. d->mtime = xd.mtime;
  1195. d->uid = xd.uid;
  1196. d->gid = xd.gid;
  1197. d->mode = (xd.mode & (DAPND|DLOCK|0777)) | (d->mode & (DALLOC|DDIR));
  1198. strncpy(d->name, xd.name, sizeof(d->name));
  1199. if(wstatallow) {
  1200. p->flags |= Bmod;
  1201. if(xd.atime)
  1202. d->atime = xd.atime;
  1203. if(xd.mtime)
  1204. d->mtime = xd.mtime;
  1205. } else
  1206. accessdir(p, d, FWSTAT);
  1207. out:
  1208. if(p)
  1209. putbuf(p);
  1210. if(p1)
  1211. putbuf(p1);
  1212. if(f)
  1213. qunlock(f);
  1214. ou->fid = in->fid;
  1215. }
  1216. void
  1217. (*call9p1[MAXSYSCALL])(Chan*, Oldfcall*, Oldfcall*) =
  1218. {
  1219. [Tnop9p1] f_nop,
  1220. [Tosession9p1] f_session,
  1221. [Tsession9p1] f_session,
  1222. [Tflush9p1] f_flush,
  1223. [Toattach9p1] f_attach,
  1224. [Tattach9p1] f_attach,
  1225. [Tclone9p1] f_clone,
  1226. [Twalk9p1] f_walk,
  1227. [Topen9p1] f_open,
  1228. [Tcreate9p1] f_create,
  1229. [Tread9p1] f_read,
  1230. [Twrite9p1] f_write,
  1231. [Tclunk9p1] f_clunk,
  1232. [Tremove9p1] f_remove,
  1233. [Tstat9p1] f_stat,
  1234. [Twstat9p1] f_wstat,
  1235. [Tclwalk9p1] f_clwalk,
  1236. };
  1237. static void
  1238. send(Chan *c, uchar *buf, int n)
  1239. {
  1240. int fd, m;
  1241. fd = c->chan;
  1242. m = write(fd, buf, n);
  1243. if(m == n)
  1244. return;
  1245. panic("write failed");
  1246. }
  1247. void
  1248. error9p1(Chan *c, uchar *buf)
  1249. {
  1250. buf[0] = Rnop9p1;
  1251. buf[1] = ~0;
  1252. buf[2] = ~0;
  1253. send(c, buf, 3);
  1254. }
  1255. void
  1256. serve9p1(Chan *chan, uchar *ib, int nib)
  1257. {
  1258. int n, t;
  1259. uchar inbuf[MAXMSG+MAXDAT], outbuf[MAXMSG+MAXDAT];
  1260. Oldfcall fi, fo;
  1261. for(;;){
  1262. if(nib){
  1263. memmove(inbuf, ib, nib);
  1264. n = nib;
  1265. nib = 0;
  1266. }else
  1267. n = read(chan->chan, inbuf, sizeof inbuf);
  1268. if(chat)
  1269. print("read msg %d\n", n);
  1270. if(n == 0 && (chan == cons.srvchan || chan == cons.chan))
  1271. continue;
  1272. if(n <= 0)
  1273. return;
  1274. if(convM2S9p1(inbuf, &fi, n) != n){
  1275. error9p1(chan, outbuf);
  1276. continue;
  1277. }
  1278. t = fi.type;
  1279. if(t < 0 || t >= MAXSYSCALL || (t&1) || !call9p1[t]) {
  1280. print("9p1: bad message type\n");
  1281. error9p1(chan, outbuf);
  1282. continue;
  1283. }
  1284. if(CHAT(chan))
  1285. print("9p1: fi %O\n", &fi);
  1286. /*
  1287. * set up reply message
  1288. */
  1289. fo.err = 0;
  1290. if(t == Tread9p1)
  1291. fo.data = (char*)outbuf + 8;
  1292. /*
  1293. * call the file system
  1294. */
  1295. cons.work.count++;
  1296. cons.rate.count += n;
  1297. /*
  1298. * call the file system
  1299. */
  1300. rlock(&mainlock);
  1301. rlock(&chan->reflock);
  1302. (*call9p1[t])(chan, &fi, &fo);
  1303. runlock(&chan->reflock);
  1304. runlock(&mainlock);
  1305. fo.type = t+1;
  1306. fo.tag = fi.tag;
  1307. if(chat)
  1308. print("9p1: fo %O\n", &fo);
  1309. if(fo.err) {
  1310. strcpy(fo.ename, errstring[fo.err]);
  1311. if(CHAT(cp))
  1312. print(" error: %s\n", fo.ename);
  1313. fo.type = Terror9p1+1;
  1314. }
  1315. n = convS2M9p1(&fo, outbuf);
  1316. if(n == 0) {
  1317. print("9p1: bad S2M conversion\n");
  1318. error9p1(chan, outbuf);
  1319. continue;
  1320. }
  1321. cons.rate.count += n;
  1322. send(chan, outbuf, n);
  1323. }
  1324. }