9p1.c 25 KB

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