9p1.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645
  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. extern Nvrsafe nvr;
  12. typedef struct {
  13. uint8_t chal[CHALLEN]; /* locally generated challenge */
  14. uint8_t rchal[CHALLEN]; /* remotely generated challenge */
  15. Lock idlock;
  16. uint32_t idoffset; /* offset of id vector */
  17. uint32_t idvec; /* vector of acceptable id's */
  18. } Authinfo;
  19. static void
  20. f_nop(Chan *cp, Fcall*, Fcall*)
  21. {
  22. if(CHAT(cp))
  23. print("c_nop %d\n", cp->chan);
  24. }
  25. static void
  26. f_flush(Chan *cp, Fcall*, Fcall*)
  27. {
  28. if(CHAT(cp))
  29. print("c_flush %d\n", cp->chan);
  30. runlock(&cp->reflock);
  31. wlock(&cp->reflock);
  32. wunlock(&cp->reflock);
  33. rlock(&cp->reflock);
  34. }
  35. /*
  36. * create a challenge for a fid space
  37. */
  38. static void
  39. mkchallenge(Authinfo *aip)
  40. {
  41. int i;
  42. srand((uintptr)aip + time(nil));
  43. for(i = 0; i < CHALLEN; i++)
  44. aip->chal[i] = nrand(256);
  45. aip->idoffset = 0;
  46. aip->idvec = 0;
  47. }
  48. static void
  49. f_session(Chan *cp, Fcall *in, Fcall *ou)
  50. {
  51. Authinfo *aip;
  52. aip = (Authinfo*)cp->authinfo;
  53. if(CHAT(cp))
  54. print("c_session %d\n", cp->chan);
  55. memmove(aip->rchal, in->chal, sizeof(aip->rchal));
  56. mkchallenge(aip);
  57. memmove(ou->chal, aip->chal, sizeof(ou->chal));
  58. if(noauth || wstatallow)
  59. memset(ou->authid, 0, sizeof(ou->authid));
  60. else
  61. memmove(ou->authid, nvr.authid, sizeof(ou->authid));
  62. sprint(ou->authdom, "%s.%s", service, nvr.authdom);
  63. fileinit(cp);
  64. }
  65. /*
  66. * match a challenge from an attach
  67. */
  68. static int
  69. authorize(Chan *cp, Fcall *in, Fcall *ou)
  70. {
  71. Ticket t;
  72. Authenticator a;
  73. int x;
  74. uint32_t bit;
  75. Authinfo *aip;
  76. if(noauth || wstatallow) /* set to allow entry during boot */
  77. return 1;
  78. if(strcmp(in->uname, "none") == 0)
  79. return 1;
  80. if(in->type == Toattach)
  81. return 0;
  82. /* decrypt and unpack ticket */
  83. convM2T9p1(in->ticket, &t, nvr.machkey);
  84. if(t.num != AuthTs){
  85. print("9p1: bad AuthTs num\n");
  86. return 0;
  87. }
  88. /* decrypt and unpack authenticator */
  89. convM2A9p1(in->auth, &a, t.key);
  90. if(a.num != AuthAc){
  91. print("9p1: bad AuthAc num\n");
  92. return 0;
  93. }
  94. /* challenges must match */
  95. aip = (Authinfo*)cp->authinfo;
  96. if(memcmp(a.chal, aip->chal, sizeof(a.chal)) != 0){
  97. print("9p1: bad challenge\n");
  98. return 0;
  99. }
  100. /*
  101. * the id must be in a valid range. the range is specified by a
  102. * lower bound (idoffset) and a bit vector (idvec) where a
  103. * bit set to 1 means unusable
  104. */
  105. lock(&aip->idlock);
  106. x = a.id - aip->idoffset;
  107. bit = 1<<x;
  108. if(x < 0 || x > 31 || (bit&aip->idvec)){
  109. unlock(&aip->idlock);
  110. print("9p1: id out of range: idoff %ld idvec %lx id %ld\n",
  111. aip->idoffset, aip->idvec, a.id);
  112. return 0;
  113. }
  114. aip->idvec |= bit;
  115. /* normalize the vector */
  116. while(aip->idvec&0xffff0001){
  117. aip->idvec >>= 1;
  118. aip->idoffset++;
  119. }
  120. unlock(&aip->idlock);
  121. /* ticket name and attach name must match */
  122. if(memcmp(in->uname, t.cuid, sizeof(in->uname)) != 0){
  123. print("9p1: names don't match\n");
  124. return 0;
  125. }
  126. /* copy translated name into input record */
  127. memmove(in->uname, t.suid, sizeof(in->uname));
  128. /* craft a reply */
  129. a.num = AuthAs;
  130. memmove(a.chal, aip->rchal, CHALLEN);
  131. convA2M9p1(&a, ou->rauth, t.key);
  132. return 1;
  133. }
  134. /*
  135. * buggery to give false qid for
  136. * the top 2 levels of the dump fs
  137. */
  138. void
  139. mkqid(Qid* qid, Dentry *d, int buggery)
  140. {
  141. int c;
  142. if(buggery && d->qid.path == (QPDIR|QPROOT)){
  143. c = d->name[0];
  144. if(isascii(c) && isdigit(c)){
  145. qid->path = 3;
  146. qid->vers = d->qid.version;
  147. qid->type = QTDIR;
  148. c = (c-'0')*10 + (d->name[1]-'0');
  149. if(c >= 1 && c <= 12)
  150. qid->path = 4;
  151. return;
  152. }
  153. }
  154. mkqid9p2(qid, &d->qid, d->mode);
  155. }
  156. int
  157. mkqidcmp(Qid* qid, Dentry *d)
  158. {
  159. Qid tmp;
  160. mkqid(&tmp, d, 1);
  161. if(qid->path == tmp.path && qid->type == tmp.type)
  162. return 0;
  163. return Eqid;
  164. }
  165. static void
  166. f_attach(Chan *cp, Fcall *in, Fcall *ou)
  167. {
  168. Iobuf *p;
  169. Dentry *d;
  170. File *f;
  171. int u;
  172. Filsys *fs;
  173. Off raddr;
  174. if(CHAT(cp)) {
  175. print("c_attach %d\n", cp->chan);
  176. print("\tfid = %d\n", in->fid);
  177. print("\tuid = %s\n", in->uname);
  178. print("\targ = %s\n", in->aname);
  179. }
  180. ou->qid = QID9P1(0,0);
  181. ou->fid = in->fid;
  182. if(!in->aname[0]) /* default */
  183. strncpy(in->aname, "main", sizeof(in->aname));
  184. p = 0;
  185. f = filep(cp, in->fid, 1);
  186. if(!f) {
  187. ou->err = Efid;
  188. goto out;
  189. }
  190. u = -1;
  191. if(cp != cons.chan) {
  192. if(noattach && strcmp(in->uname, "none")) {
  193. ou->err = Enoattach;
  194. goto out;
  195. }
  196. if(authorize(cp, in, ou) == 0 || strcmp(in->uname, "adm") == 0) {
  197. ou->err = Eauth;
  198. goto out;
  199. }
  200. u = strtouid(in->uname);
  201. if(u < 0) {
  202. ou->err = Ebadu;
  203. goto out;
  204. }
  205. }
  206. f->uid = u;
  207. fs = fsstr(in->aname);
  208. if(fs == 0) {
  209. ou->err = Ebadspc;
  210. goto out;
  211. }
  212. raddr = getraddr(fs->dev);
  213. p = getbuf(fs->dev, raddr, Brd);
  214. d = getdir(p, 0);
  215. if(!d || checktag(p, Tdir, QPROOT) || !(d->mode & DALLOC)) {
  216. ou->err = Ealloc;
  217. goto out;
  218. }
  219. if (iaccess(f, d, DEXEC) ||
  220. f->uid == 0 && fs->dev->type == Devro) {
  221. /*
  222. * 'none' not allowed on dump
  223. */
  224. ou->err = Eaccess;
  225. goto out;
  226. }
  227. accessdir(p, d, FREAD, f->uid);
  228. mkqid(&f->qid, d, 1);
  229. f->fs = fs;
  230. f->addr = raddr;
  231. f->slot = 0;
  232. f->open = 0;
  233. freewp(f->wpath);
  234. f->wpath = 0;
  235. mkqid9p1(&ou->qid, &f->qid);
  236. strncpy(cp->whoname, in->uname, sizeof(cp->whoname));
  237. cp->whotime = time(nil);
  238. if(cons.flags & attachflag)
  239. print("9p1: attach %s %T to \"%s\" C%d\n",
  240. cp->whoname, cp->whotime, fs->name, cp->chan);
  241. out:
  242. if((cons.flags & attachflag) && ou->err)
  243. print("9p1: attach %s %T SUCK EGGS --- %s\n",
  244. in->uname, time(nil), errstr9p[ou->err]);
  245. if(p)
  246. putbuf(p);
  247. if(f) {
  248. qunlock(f);
  249. if(ou->err)
  250. freefp(f);
  251. }
  252. }
  253. static void
  254. f_clone(Chan *cp, Fcall *in, Fcall *ou)
  255. {
  256. File *f1, *f2;
  257. Wpath *p;
  258. int fid, fid1;
  259. if(CHAT(cp)) {
  260. print("c_clone %d\n", cp->chan);
  261. print("\told fid = %d\n", in->fid);
  262. print("\tnew fid = %d\n", in->newfid);
  263. }
  264. fid = in->fid;
  265. fid1 = in->newfid;
  266. f1 = 0;
  267. f2 = 0;
  268. if(fid < fid1) {
  269. f1 = filep(cp, fid, 0);
  270. f2 = filep(cp, fid1, 1);
  271. } else
  272. if(fid1 < fid) {
  273. f2 = filep(cp, fid1, 1);
  274. f1 = filep(cp, fid, 0);
  275. }
  276. if(!f1 || !f2) {
  277. ou->err = Efid;
  278. goto out;
  279. }
  280. f2->fs = f1->fs;
  281. f2->addr = f1->addr;
  282. f2->open = f1->open & ~FREMOV;
  283. f2->uid = f1->uid;
  284. f2->slot = f1->slot;
  285. f2->qid = f1->qid;
  286. freewp(f2->wpath);
  287. lock(&wpathlock);
  288. f2->wpath = f1->wpath;
  289. for(p = f2->wpath; p; p = p->up)
  290. p->refs++;
  291. unlock(&wpathlock);
  292. out:
  293. ou->fid = fid;
  294. if(f1)
  295. qunlock(f1);
  296. if(f2) {
  297. qunlock(f2);
  298. if(ou->err)
  299. freefp(f2);
  300. }
  301. }
  302. static void
  303. f_walk(Chan *cp, Fcall *in, Fcall *ou)
  304. {
  305. Iobuf *p, *p1;
  306. Dentry *d, *d1;
  307. File *f;
  308. Wpath *w;
  309. int slot;
  310. Off addr, qpath;
  311. if(CHAT(cp)) {
  312. print("c_walk %d\n", cp->chan);
  313. print("\tfid = %d\n", in->fid);
  314. print("\tname = %s\n", in->name);
  315. }
  316. ou->fid = in->fid;
  317. ou->qid = QID9P1(0,0);
  318. p = 0;
  319. f = filep(cp, in->fid, 0);
  320. if(!f) {
  321. ou->err = Efid;
  322. goto out;
  323. }
  324. p = getbuf(f->fs->dev, f->addr, Brd);
  325. d = getdir(p, f->slot);
  326. if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
  327. ou->err = Ealloc;
  328. goto out;
  329. }
  330. if(!(d->mode & DDIR)) {
  331. ou->err = Edir1;
  332. goto out;
  333. }
  334. if(ou->err = mkqidcmp(&f->qid, d))
  335. goto out;
  336. if(cp != cons.chan && iaccess(f, d, DEXEC)) {
  337. ou->err = Eaccess;
  338. goto out;
  339. }
  340. accessdir(p, d, FREAD, f->uid);
  341. if(strcmp(in->name, ".") == 0)
  342. goto setdot;
  343. if(strcmp(in->name, "..") == 0) {
  344. if(f->wpath == 0)
  345. goto setdot;
  346. putbuf(p);
  347. p = 0;
  348. addr = f->wpath->addr;
  349. slot = f->wpath->slot;
  350. p1 = getbuf(f->fs->dev, addr, Brd);
  351. d1 = getdir(p1, slot);
  352. if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
  353. if(p1)
  354. putbuf(p1);
  355. ou->err = Ephase;
  356. goto out;
  357. }
  358. lock(&wpathlock);
  359. f->wpath->refs--;
  360. f->wpath = f->wpath->up;
  361. unlock(&wpathlock);
  362. goto found;
  363. }
  364. for(addr=0;; addr++) {
  365. if(p == 0) {
  366. p = getbuf(f->fs->dev, f->addr, Brd);
  367. d = getdir(p, f->slot);
  368. if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
  369. ou->err = Ealloc;
  370. goto out;
  371. }
  372. }
  373. qpath = d->qid.path;
  374. p1 = dnodebuf1(p, d, addr, 0, f->uid);
  375. p = 0;
  376. if(!p1 || checktag(p1, Tdir, qpath) ) {
  377. if(p1)
  378. putbuf(p1);
  379. ou->err = Eentry;
  380. goto out;
  381. }
  382. for(slot=0; slot<DIRPERBUF; slot++) {
  383. d1 = getdir(p1, slot);
  384. if(!(d1->mode & DALLOC))
  385. continue;
  386. if(strncmp(in->name, d1->name, sizeof(in->name)) != 0)
  387. continue;
  388. /*
  389. * update walk path
  390. */
  391. w = newwp();
  392. if(!w) {
  393. ou->err = Ewalk;
  394. putbuf(p1);
  395. goto out;
  396. }
  397. w->addr = f->addr;
  398. w->slot = f->slot;
  399. w->up = f->wpath;
  400. f->wpath = w;
  401. slot += DIRPERBUF*addr;
  402. goto found;
  403. }
  404. putbuf(p1);
  405. }
  406. found:
  407. f->addr = p1->addr;
  408. mkqid(&f->qid, d1, 1);
  409. putbuf(p1);
  410. f->slot = slot;
  411. setdot:
  412. mkqid9p1(&ou->qid, &f->qid);
  413. f->open = 0;
  414. out:
  415. if(p)
  416. putbuf(p);
  417. if(f)
  418. qunlock(f);
  419. }
  420. static void
  421. f_open(Chan *cp, Fcall *in, Fcall *ou)
  422. {
  423. Iobuf *p;
  424. Dentry *d;
  425. File *f;
  426. Tlock *t;
  427. Qid qid;
  428. int ro, fmod, wok;
  429. if(CHAT(cp)) {
  430. print("c_open %d\n", cp->chan);
  431. print("\tfid = %d\n", in->fid);
  432. print("\tmode = %o\n", in->mode);
  433. }
  434. wok = 0;
  435. if(cp == cons.chan || writeallow)
  436. wok = 1;
  437. p = 0;
  438. f = filep(cp, in->fid, 0);
  439. if(!f) {
  440. ou->err = Efid;
  441. goto out;
  442. }
  443. /*
  444. * if remove on close, check access here
  445. */
  446. ro = f->fs->dev->type == Devro;
  447. if(in->mode & ORCLOSE) {
  448. if(ro) {
  449. ou->err = Eronly;
  450. goto out;
  451. }
  452. /*
  453. * check on parent directory of file to be deleted
  454. */
  455. if(f->wpath == 0 || f->wpath->addr == f->addr) {
  456. ou->err = Ephase;
  457. goto out;
  458. }
  459. p = getbuf(f->fs->dev, f->wpath->addr, Brd);
  460. d = getdir(p, f->wpath->slot);
  461. if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
  462. ou->err = Ephase;
  463. goto out;
  464. }
  465. if(iaccess(f, d, DWRITE)) {
  466. ou->err = Eaccess;
  467. goto out;
  468. }
  469. putbuf(p);
  470. }
  471. p = getbuf(f->fs->dev, f->addr, Brd);
  472. d = getdir(p, f->slot);
  473. if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
  474. ou->err = Ealloc;
  475. goto out;
  476. }
  477. if(ou->err = mkqidcmp(&f->qid, d))
  478. goto out;
  479. mkqid(&qid, d, 1);
  480. switch(in->mode & 7) {
  481. case OREAD:
  482. if(iaccess(f, d, DREAD) && !wok)
  483. goto badaccess;
  484. fmod = FREAD;
  485. break;
  486. case OWRITE:
  487. if((d->mode & DDIR) ||
  488. (iaccess(f, d, DWRITE) && !wok))
  489. goto badaccess;
  490. if(ro) {
  491. ou->err = Eronly;
  492. goto out;
  493. }
  494. fmod = FWRITE;
  495. break;
  496. case ORDWR:
  497. if((d->mode & DDIR) ||
  498. (iaccess(f, d, DREAD) && !wok) ||
  499. (iaccess(f, d, DWRITE) && !wok))
  500. goto badaccess;
  501. if(ro) {
  502. ou->err = Eronly;
  503. goto out;
  504. }
  505. fmod = FREAD+FWRITE;
  506. break;
  507. case OEXEC:
  508. if((d->mode & DDIR) ||
  509. (iaccess(f, d, DEXEC) && !wok))
  510. goto badaccess;
  511. fmod = FREAD;
  512. break;
  513. default:
  514. ou->err = Emode;
  515. goto out;
  516. }
  517. if(in->mode & OTRUNC) {
  518. if((d->mode & DDIR) ||
  519. (iaccess(f, d, DWRITE) && !wok))
  520. goto badaccess;
  521. if(ro) {
  522. ou->err = Eronly;
  523. goto out;
  524. }
  525. }
  526. t = 0;
  527. if(d->mode & DLOCK) {
  528. t = tlocked(p, d);
  529. if(t == nil) {
  530. ou->err = Elocked;
  531. goto out;
  532. }
  533. }
  534. if(in->mode & ORCLOSE)
  535. fmod |= FREMOV;
  536. f->open = fmod;
  537. if(in->mode & OTRUNC)
  538. if(!(d->mode & DAPND)) {
  539. dtrunc(p, d, f->uid);
  540. qid.vers = d->qid.version;
  541. }
  542. f->tlock = t;
  543. if(t)
  544. t->file = f;
  545. f->lastra = 1;
  546. mkqid9p1(&ou->qid, &qid);
  547. goto out;
  548. badaccess:
  549. ou->err = Eaccess;
  550. f->open = 0;
  551. out:
  552. if(p)
  553. putbuf(p);
  554. if(f)
  555. qunlock(f);
  556. ou->fid = in->fid;
  557. }
  558. static void
  559. f_create(Chan *cp, Fcall *in, Fcall *ou)
  560. {
  561. Iobuf *p, *p1;
  562. Dentry *d, *d1;
  563. File *f;
  564. int slot, slot1, fmod, wok;
  565. Off addr, addr1, path;
  566. Qid qid;
  567. Tlock *t;
  568. Wpath *w;
  569. if(CHAT(cp)) {
  570. print("c_create %d\n", cp->chan);
  571. print("\tfid = %d\n", in->fid);
  572. print("\tname = %s\n", in->name);
  573. print("\tperm = %lx+%lo\n", (in->perm>>28)&0xf,
  574. in->perm&0777);
  575. print("\tmode = %o\n", in->mode);
  576. }
  577. wok = 0;
  578. if(cp == cons.chan || writeallow)
  579. wok = 1;
  580. p = 0;
  581. f = filep(cp, in->fid, 0);
  582. if(!f) {
  583. ou->err = Efid;
  584. goto out;
  585. }
  586. if(f->fs->dev->type == Devro) {
  587. ou->err = Eronly;
  588. goto out;
  589. }
  590. p = getbuf(f->fs->dev, f->addr, Brd);
  591. d = getdir(p, f->slot);
  592. if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
  593. ou->err = Ealloc;
  594. goto out;
  595. }
  596. if(ou->err = mkqidcmp(&f->qid, d))
  597. goto out;
  598. if(!(d->mode & DDIR)) {
  599. ou->err = Edir2;
  600. goto out;
  601. }
  602. if(iaccess(f, d, DWRITE) && !wok) {
  603. ou->err = Eaccess;
  604. goto out;
  605. }
  606. accessdir(p, d, FREAD, f->uid);
  607. if(!strncmp(in->name, ".", sizeof(in->name)) ||
  608. !strncmp(in->name, "..", sizeof(in->name))) {
  609. ou->err = Edot;
  610. goto out;
  611. }
  612. if(checkname(in->name)) {
  613. ou->err = Ename;
  614. goto out;
  615. }
  616. addr1 = 0;
  617. slot1 = 0; /* set */
  618. for(addr=0;; addr++) {
  619. p1 = dnodebuf(p, d, addr, 0, f->uid);
  620. if(!p1) {
  621. if(addr1)
  622. break;
  623. p1 = dnodebuf(p, d, addr, Tdir, f->uid);
  624. }
  625. if(p1 == 0) {
  626. ou->err = Efull;
  627. goto out;
  628. }
  629. if(checktag(p1, Tdir, d->qid.path)) {
  630. putbuf(p1);
  631. goto phase;
  632. }
  633. for(slot=0; slot<DIRPERBUF; slot++) {
  634. d1 = getdir(p1, slot);
  635. if(!(d1->mode & DALLOC)) {
  636. if(!addr1) {
  637. addr1 = p1->addr;
  638. slot1 = slot + addr*DIRPERBUF;
  639. }
  640. continue;
  641. }
  642. if(!strncmp(in->name, d1->name, sizeof(in->name))) {
  643. putbuf(p1);
  644. ou->err = Eexist;
  645. goto out;
  646. }
  647. }
  648. putbuf(p1);
  649. }
  650. switch(in->mode & 7) {
  651. case OEXEC:
  652. case OREAD: /* seems only useful to make directories */
  653. fmod = FREAD;
  654. break;
  655. case OWRITE:
  656. fmod = FWRITE;
  657. break;
  658. case ORDWR:
  659. fmod = FREAD+FWRITE;
  660. break;
  661. default:
  662. ou->err = Emode;
  663. goto out;
  664. }
  665. if(in->perm & PDIR)
  666. if((in->mode & OTRUNC) || (in->perm & PAPND) || (fmod & FWRITE))
  667. goto badaccess;
  668. /*
  669. * do it
  670. */
  671. path = qidpathgen(f->fs->dev);
  672. p1 = getbuf(f->fs->dev, addr1, Brd|Bimm|Bmod);
  673. d1 = getdir(p1, slot1);
  674. if(!d1 || checktag(p1, Tdir, d->qid.path)) {
  675. if(p1)
  676. putbuf(p1);
  677. goto phase;
  678. }
  679. if(d1->mode & DALLOC) {
  680. putbuf(p1);
  681. goto phase;
  682. }
  683. strncpy(d1->name, in->name, sizeof(in->name));
  684. if(cp == cons.chan) {
  685. d1->uid = cons.uid;
  686. d1->gid = cons.gid;
  687. } else {
  688. d1->uid = f->uid;
  689. d1->gid = d->gid;
  690. in->perm &= d->mode | ~0666;
  691. if(in->perm & PDIR)
  692. in->perm &= d->mode | ~0777;
  693. }
  694. d1->qid.path = path;
  695. d1->qid.version = 0;
  696. d1->mode = DALLOC | (in->perm & 0777);
  697. if(in->perm & PDIR) {
  698. d1->mode |= DDIR;
  699. d1->qid.path |= QPDIR;
  700. }
  701. if(in->perm & PAPND)
  702. d1->mode |= DAPND;
  703. t = 0;
  704. if(in->perm & PLOCK) {
  705. d1->mode |= DLOCK;
  706. t = tlocked(p1, d1);
  707. /* if nil, out of tlock structures */
  708. }
  709. accessdir(p1, d1, FWRITE, f->uid);
  710. mkqid(&qid, d1, 0);
  711. putbuf(p1);
  712. accessdir(p, d, FWRITE, f->uid);
  713. /*
  714. * do a walk to new directory entry
  715. */
  716. w = newwp();
  717. if(!w) {
  718. ou->err = Ewalk;
  719. goto out;
  720. }
  721. w->addr = f->addr;
  722. w->slot = f->slot;
  723. w->up = f->wpath;
  724. f->wpath = w;
  725. f->qid = qid;
  726. f->tlock = t;
  727. if(t)
  728. t->file = f;
  729. f->lastra = 1;
  730. if(in->mode & ORCLOSE)
  731. fmod |= FREMOV;
  732. f->open = fmod;
  733. f->addr = addr1;
  734. f->slot = slot1;
  735. mkqid9p1(&ou->qid, &qid);
  736. goto out;
  737. badaccess:
  738. ou->err = Eaccess;
  739. goto out;
  740. phase:
  741. ou->err = Ephase;
  742. out:
  743. if(p)
  744. putbuf(p);
  745. if(f)
  746. qunlock(f);
  747. ou->fid = in->fid;
  748. }
  749. static void
  750. f_read(Chan *cp, Fcall *in, Fcall *ou)
  751. {
  752. Iobuf *p, *p1;
  753. File *f;
  754. Dentry *d, *d1;
  755. Tlock *t;
  756. Off addr, offset;
  757. Timet tim;
  758. int nread, count, n, o, slot;
  759. if(CHAT(cp)) {
  760. print("c_read %d\n", cp->chan);
  761. print("\tfid = %d\n", in->fid);
  762. print("\toffset = %lld\n", (Wideoff)in->offset);
  763. print("\tcount = %ld\n", in->count);
  764. }
  765. p = 0;
  766. count = in->count;
  767. offset = in->offset;
  768. nread = 0;
  769. f = filep(cp, in->fid, 0);
  770. if(!f) {
  771. ou->err = Efid;
  772. goto out;
  773. }
  774. if(!(f->open & FREAD)) {
  775. ou->err = Eopen;
  776. goto out;
  777. }
  778. if(count < 0 || count > MAXDAT) {
  779. ou->err = Ecount;
  780. goto out;
  781. }
  782. if(offset < 0) {
  783. ou->err = Eoffset;
  784. goto out;
  785. }
  786. p = getbuf(f->fs->dev, f->addr, Brd);
  787. d = getdir(p, f->slot);
  788. if(!d || !(d->mode & DALLOC)) {
  789. ou->err = Ealloc;
  790. goto out;
  791. }
  792. if(ou->err = mkqidcmp(&f->qid, d))
  793. goto out;
  794. if(t = f->tlock) {
  795. tim = toytime();
  796. if(t->time < tim || t->file != f) {
  797. ou->err = Ebroken;
  798. goto out;
  799. }
  800. /* renew the lock */
  801. t->time = tim + TLOCK;
  802. }
  803. accessdir(p, d, FREAD, f->uid);
  804. if(d->mode & DDIR) {
  805. addr = 0;
  806. goto dread;
  807. }
  808. /* XXXX terrible hack to get at raw data XXXX */
  809. if(rawreadok && strncmp(d->name, "--raw--", 7) == 0) {
  810. Device *dev;
  811. Devsize boff, bsize;
  812. dev = p->dev;
  813. putbuf(p);
  814. p = 0;
  815. boff = number(d->name + 7, 0, 10) * 100000;
  816. if(boff < 0)
  817. boff = 0;
  818. if(boff > devsize(dev))
  819. boff = devsize(dev);
  820. bsize = devsize(dev) - boff;
  821. if(offset+count >= 100000*RBUFSIZE)
  822. count = 100000*RBUFSIZE - offset;
  823. if((offset+count)/RBUFSIZE >= bsize)
  824. /* will not overflow */
  825. count = bsize*RBUFSIZE - offset;
  826. while(count > 0) {
  827. addr = offset / RBUFSIZE;
  828. addr += boff;
  829. o = offset % RBUFSIZE;
  830. n = RBUFSIZE - o;
  831. if(n > count)
  832. n = count;
  833. p1 = getbuf(dev, addr, Brd);
  834. if(p1) {
  835. memmove(ou->data+nread, p1->iobuf+o, n);
  836. putbuf(p1);
  837. } else
  838. memset(ou->data+nread, 0, n);
  839. count -= n;
  840. nread += n;
  841. offset += n;
  842. }
  843. goto out;
  844. }
  845. if(offset+count > d->size)
  846. count = d->size - offset;
  847. while(count > 0) {
  848. if(p == 0) {
  849. p = getbuf(f->fs->dev, f->addr, Brd);
  850. d = getdir(p, f->slot);
  851. if(!d || !(d->mode & DALLOC)) {
  852. ou->err = Ealloc;
  853. goto out;
  854. }
  855. }
  856. addr = offset / BUFSIZE;
  857. f->lastra = dbufread(p, d, addr, f->lastra, f->uid);
  858. o = offset % BUFSIZE;
  859. n = BUFSIZE - o;
  860. if(n > count)
  861. n = count;
  862. p1 = dnodebuf1(p, d, addr, 0, f->uid);
  863. p = 0;
  864. if(p1) {
  865. if(checktag(p1, Tfile, QPNONE)) {
  866. ou->err = Ephase;
  867. putbuf(p1);
  868. goto out;
  869. }
  870. memmove(ou->data+nread, p1->iobuf+o, n);
  871. putbuf(p1);
  872. } else
  873. memset(ou->data+nread, 0, n);
  874. count -= n;
  875. nread += n;
  876. offset += n;
  877. }
  878. goto out;
  879. dread:
  880. for (;;) {
  881. if(p == 0) {
  882. p = getbuf(f->fs->dev, f->addr, Brd);
  883. d = getdir(p, f->slot);
  884. if(!d || !(d->mode & DALLOC)) {
  885. ou->err = Ealloc;
  886. goto out;
  887. }
  888. }
  889. p1 = dnodebuf1(p, d, addr, 0, f->uid);
  890. p = 0;
  891. if(!p1)
  892. goto out;
  893. if(checktag(p1, Tdir, QPNONE)) {
  894. ou->err = Ephase;
  895. putbuf(p1);
  896. goto out;
  897. }
  898. n = DIRREC;
  899. for(slot=0; slot<DIRPERBUF; slot++) {
  900. d1 = getdir(p1, slot);
  901. if(!(d1->mode & DALLOC))
  902. continue;
  903. if(offset >= n) {
  904. offset -= n;
  905. continue;
  906. }
  907. if(count < n) {
  908. putbuf(p1);
  909. goto out;
  910. }
  911. if(convD2M9p1(d1, ou->data+nread) != n)
  912. print("9p1: dirread convD2M1990\n");
  913. nread += n;
  914. count -= n;
  915. }
  916. putbuf(p1);
  917. addr++;
  918. }
  919. out:
  920. count = in->count - nread;
  921. if(count > 0)
  922. memset(ou->data+nread, 0, count);
  923. if(p)
  924. putbuf(p);
  925. if(f)
  926. qunlock(f);
  927. ou->fid = in->fid;
  928. ou->count = nread;
  929. if(CHAT(cp))
  930. print("\tnread = %d\n", nread);
  931. }
  932. static void
  933. f_write(Chan *cp, Fcall *in, Fcall *ou)
  934. {
  935. Iobuf *p, *p1;
  936. Dentry *d;
  937. File *f;
  938. Tlock *t;
  939. Off offset, addr, qpath;
  940. Timet tim;
  941. int count, nwrite, o, n;
  942. if(CHAT(cp)) {
  943. print("c_write %d\n", cp->chan);
  944. print("\tfid = %d\n", in->fid);
  945. print("\toffset = %lld\n", (Wideoff)in->offset);
  946. print("\tcount = %ld\n", in->count);
  947. }
  948. offset = in->offset;
  949. count = in->count;
  950. nwrite = 0;
  951. p = 0;
  952. f = filep(cp, in->fid, 0);
  953. if(!f) {
  954. ou->err = Efid;
  955. goto out;
  956. }
  957. if(!(f->open & FWRITE)) {
  958. ou->err = Eopen;
  959. goto out;
  960. }
  961. if(f->fs->dev->type == Devro) {
  962. ou->err = Eronly;
  963. goto out;
  964. }
  965. if(count < 0 || count > MAXDAT) {
  966. ou->err = Ecount;
  967. goto out;
  968. }
  969. if(offset < 0) {
  970. ou->err = Eoffset;
  971. goto out;
  972. }
  973. p = getbuf(f->fs->dev, f->addr, Brd|Bmod);
  974. d = getdir(p, f->slot);
  975. if(!d || !(d->mode & DALLOC)) {
  976. ou->err = Ealloc;
  977. goto out;
  978. }
  979. if(ou->err = mkqidcmp(&f->qid, d))
  980. goto out;
  981. if(t = f->tlock) {
  982. tim = toytime();
  983. if(t->time < tim || t->file != f) {
  984. ou->err = Ebroken;
  985. goto out;
  986. }
  987. /* renew the lock */
  988. t->time = tim + TLOCK;
  989. }
  990. accessdir(p, d, FWRITE, f->uid);
  991. if(d->mode & DAPND)
  992. offset = d->size;
  993. if(offset+count > d->size)
  994. d->size = offset+count;
  995. while(count > 0) {
  996. if(p == 0) {
  997. p = getbuf(f->fs->dev, f->addr, Brd|Bmod);
  998. d = getdir(p, f->slot);
  999. if(!d || !(d->mode & DALLOC)) {
  1000. ou->err = Ealloc;
  1001. goto out;
  1002. }
  1003. }
  1004. addr = offset / BUFSIZE;
  1005. o = offset % BUFSIZE;
  1006. n = BUFSIZE - o;
  1007. if(n > count)
  1008. n = count;
  1009. qpath = d->qid.path;
  1010. p1 = dnodebuf1(p, d, addr, Tfile, f->uid);
  1011. p = 0;
  1012. if(p1 == 0) {
  1013. ou->err = Efull;
  1014. goto out;
  1015. }
  1016. if(checktag(p1, Tfile, qpath)) {
  1017. putbuf(p1);
  1018. ou->err = Ephase;
  1019. goto out;
  1020. }
  1021. memmove(p1->iobuf+o, in->data+nwrite, n);
  1022. p1->flags |= Bmod;
  1023. putbuf(p1);
  1024. count -= n;
  1025. nwrite += n;
  1026. offset += n;
  1027. }
  1028. if(CHAT(cp))
  1029. print("\tnwrite = %d\n", nwrite);
  1030. out:
  1031. if(p)
  1032. putbuf(p);
  1033. if(f)
  1034. qunlock(f);
  1035. ou->fid = in->fid;
  1036. ou->count = nwrite;
  1037. }
  1038. int
  1039. doremove(File *f, int wok)
  1040. {
  1041. Iobuf *p, *p1;
  1042. Dentry *d, *d1;
  1043. Off addr;
  1044. int slot, err;
  1045. p = 0;
  1046. p1 = 0;
  1047. if(f->fs->dev->type == Devro) {
  1048. err = Eronly;
  1049. goto out;
  1050. }
  1051. /*
  1052. * check on parent directory of file to be deleted
  1053. */
  1054. if(f->wpath == 0 || f->wpath->addr == f->addr) {
  1055. err = Ephase;
  1056. goto out;
  1057. }
  1058. p1 = getbuf(f->fs->dev, f->wpath->addr, Brd);
  1059. d1 = getdir(p1, f->wpath->slot);
  1060. if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
  1061. err = Ephase;
  1062. goto out;
  1063. }
  1064. if(iaccess(f, d1, DWRITE) && !wok) {
  1065. err = Eaccess;
  1066. goto out;
  1067. }
  1068. accessdir(p1, d1, FWRITE, f->uid);
  1069. putbuf(p1);
  1070. p1 = 0;
  1071. /*
  1072. * check on file to be deleted
  1073. */
  1074. p = getbuf(f->fs->dev, f->addr, Brd);
  1075. d = getdir(p, f->slot);
  1076. if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
  1077. err = Ealloc;
  1078. goto out;
  1079. }
  1080. if(err = mkqidcmp(&f->qid, d))
  1081. goto out;
  1082. /*
  1083. * if deleting a directory, make sure it is empty
  1084. */
  1085. if((d->mode & DDIR))
  1086. for(addr=0;; addr++) {
  1087. p1 = dnodebuf(p, d, addr, 0, f->uid);
  1088. if(!p1)
  1089. break;
  1090. if(checktag(p1, Tdir, d->qid.path)) {
  1091. err = Ephase;
  1092. goto out;
  1093. }
  1094. for(slot=0; slot<DIRPERBUF; slot++) {
  1095. d1 = getdir(p1, slot);
  1096. if(!(d1->mode & DALLOC))
  1097. continue;
  1098. err = Eempty;
  1099. goto out;
  1100. }
  1101. putbuf(p1);
  1102. }
  1103. /*
  1104. * do it
  1105. */
  1106. dtrunc(p, d, f->uid);
  1107. memset(d, 0, sizeof(Dentry));
  1108. settag(p, Tdir, QPNONE);
  1109. out:
  1110. if(p1)
  1111. putbuf(p1);
  1112. if(p)
  1113. putbuf(p);
  1114. return err;
  1115. }
  1116. static int
  1117. doclunk(File* f, int remove, int wok)
  1118. {
  1119. Tlock *t;
  1120. int err;
  1121. err = 0;
  1122. if(t = f->tlock) {
  1123. if(t->file == f)
  1124. t->time = 0; /* free the lock */
  1125. f->tlock = 0;
  1126. }
  1127. if(remove)
  1128. err = doremove(f, wok);
  1129. f->open = 0;
  1130. freewp(f->wpath);
  1131. freefp(f);
  1132. return err;
  1133. }
  1134. static void
  1135. f_clunk(Chan *cp, Fcall *in, Fcall *ou)
  1136. {
  1137. File *f;
  1138. if(CHAT(cp)) {
  1139. print("c_clunk %d\n", cp->chan);
  1140. print("\tfid = %d\n", in->fid);
  1141. }
  1142. f = filep(cp, in->fid, 0);
  1143. if(!f)
  1144. ou->err = Efid;
  1145. else {
  1146. doclunk(f, f->open & FREMOV, 0);
  1147. qunlock(f);
  1148. }
  1149. ou->fid = in->fid;
  1150. }
  1151. static void
  1152. f_remove(Chan *cp, Fcall *in, Fcall *ou)
  1153. {
  1154. File *f;
  1155. if(CHAT(cp)) {
  1156. print("c_remove %d\n", cp->chan);
  1157. print("\tfid = %d\n", in->fid);
  1158. }
  1159. f = filep(cp, in->fid, 0);
  1160. if(!f)
  1161. ou->err = Efid;
  1162. else {
  1163. ou->err = doclunk(f, 1, cp==cons.chan);
  1164. qunlock(f);
  1165. }
  1166. ou->fid = in->fid;
  1167. }
  1168. static void
  1169. f_stat(Chan *cp, Fcall *in, Fcall *ou)
  1170. {
  1171. Iobuf *p;
  1172. Dentry *d;
  1173. File *f;
  1174. if(CHAT(cp)) {
  1175. print("c_stat %d\n", cp->chan);
  1176. print("\tfid = %d\n", in->fid);
  1177. }
  1178. p = 0;
  1179. memset(ou->stat, 0, sizeof(ou->stat));
  1180. f = filep(cp, in->fid, 0);
  1181. if(!f) {
  1182. ou->err = Efid;
  1183. goto out;
  1184. }
  1185. p = getbuf(f->fs->dev, f->addr, Brd);
  1186. d = getdir(p, f->slot);
  1187. if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
  1188. ou->err = Ealloc;
  1189. goto out;
  1190. }
  1191. if(ou->err = mkqidcmp(&f->qid, d))
  1192. goto out;
  1193. if(d->qid.path == QPROOT) /* stat of root gives time */
  1194. d->atime = time(nil);
  1195. if(convD2M9p1(d, ou->stat) != DIRREC)
  1196. print("9p1: stat convD2M\n");
  1197. out:
  1198. if(p)
  1199. putbuf(p);
  1200. if(f)
  1201. qunlock(f);
  1202. ou->fid = in->fid;
  1203. }
  1204. static void
  1205. f_wstat(Chan *cp, Fcall *in, Fcall *ou)
  1206. {
  1207. Iobuf *p, *p1;
  1208. Dentry *d, *d1, xd;
  1209. File *f;
  1210. int slot;
  1211. Off addr;
  1212. if(CHAT(cp)) {
  1213. print("c_wstat %d\n", cp->chan);
  1214. print("\tfid = %d\n", in->fid);
  1215. }
  1216. p = 0;
  1217. p1 = 0;
  1218. d1 = 0;
  1219. f = filep(cp, in->fid, 0);
  1220. if(!f) {
  1221. ou->err = Efid;
  1222. goto out;
  1223. }
  1224. if(f->fs->dev->type == Devro) {
  1225. ou->err = Eronly;
  1226. goto out;
  1227. }
  1228. /*
  1229. * first get parent
  1230. */
  1231. if(f->wpath) {
  1232. p1 = getbuf(f->fs->dev, f->wpath->addr, Brd);
  1233. d1 = getdir(p1, f->wpath->slot);
  1234. if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) {
  1235. ou->err = Ephase;
  1236. goto out;
  1237. }
  1238. }
  1239. p = getbuf(f->fs->dev, f->addr, Brd);
  1240. d = getdir(p, f->slot);
  1241. if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
  1242. ou->err = Ealloc;
  1243. goto out;
  1244. }
  1245. if(ou->err = mkqidcmp(&f->qid, d))
  1246. goto out;
  1247. convM2D9p1(in->stat, &xd);
  1248. if(CHAT(cp)) {
  1249. print("\td.name = %s\n", xd.name);
  1250. print("\td.uid = %d\n", xd.uid);
  1251. print("\td.gid = %d\n", xd.gid);
  1252. print("\td.mode = %o\n", xd.mode);
  1253. }
  1254. /*
  1255. * if user none,
  1256. * cant do anything
  1257. */
  1258. if(f->uid == 0) {
  1259. ou->err = Eaccess;
  1260. goto out;
  1261. }
  1262. /*
  1263. * if chown,
  1264. * must be god
  1265. */
  1266. if(xd.uid != d->uid && !wstatallow) { /* set to allow chown during boot */
  1267. ou->err = Ewstatu;
  1268. goto out;
  1269. }
  1270. /*
  1271. * if chgroup,
  1272. * must be either
  1273. * a) owner and in new group
  1274. * b) leader of both groups
  1275. */
  1276. if (xd.gid != d->gid &&
  1277. (!wstatallow && !writeallow && /* set to allow chgrp during boot */
  1278. (d->uid != f->uid || !ingroup(f->uid, xd.gid)) &&
  1279. (!leadgroup(f->uid, xd.gid) || !leadgroup(f->uid, d->gid)))) {
  1280. ou->err = Ewstatg;
  1281. goto out;
  1282. }
  1283. /*
  1284. * if rename,
  1285. * must have write permission in parent
  1286. */
  1287. if (strncmp(d->name, xd.name, sizeof(d->name)) != 0) {
  1288. if (checkname(xd.name) || !d1 ||
  1289. strcmp(xd.name, ".") == 0 || strcmp(xd.name, "..") == 0) {
  1290. ou->err = Ename;
  1291. goto out;
  1292. }
  1293. /*
  1294. * drop entry to prevent lock, then
  1295. * check that destination name is unique,
  1296. */
  1297. putbuf(p);
  1298. for(addr=0;; addr++) {
  1299. p = dnodebuf(p1, d1, addr, 0, f->uid);
  1300. if(!p)
  1301. break;
  1302. if(checktag(p, Tdir, d1->qid.path)) {
  1303. putbuf(p);
  1304. continue;
  1305. }
  1306. for(slot=0; slot<DIRPERBUF; slot++) {
  1307. d = getdir(p, slot);
  1308. if(!(d->mode & DALLOC))
  1309. continue;
  1310. if(!strncmp(xd.name, d->name, sizeof(xd.name))) {
  1311. ou->err = Eexist;
  1312. goto out;
  1313. }
  1314. }
  1315. putbuf(p);
  1316. }
  1317. /*
  1318. * reacquire entry
  1319. */
  1320. p = getbuf(f->fs->dev, f->addr, Brd);
  1321. d = getdir(p, f->slot);
  1322. if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
  1323. ou->err = Ephase;
  1324. goto out;
  1325. }
  1326. if (!wstatallow && !writeallow && /* set to allow rename during boot */
  1327. (!d1 || iaccess(f, d1, DWRITE))) {
  1328. ou->err = Eaccess;
  1329. goto out;
  1330. }
  1331. }
  1332. /*
  1333. * if mode/time, either
  1334. * a) owner
  1335. * b) leader of either group
  1336. */
  1337. if (d->mtime != xd.mtime ||
  1338. ((d->mode^xd.mode) & (DAPND|DLOCK|0777)))
  1339. if (!wstatallow && /* set to allow chmod during boot */
  1340. d->uid != f->uid &&
  1341. !leadgroup(f->uid, xd.gid) &&
  1342. !leadgroup(f->uid, d->gid)) {
  1343. ou->err = Ewstatu;
  1344. goto out;
  1345. }
  1346. d->mtime = xd.mtime;
  1347. d->uid = xd.uid;
  1348. d->gid = xd.gid;
  1349. d->mode = (xd.mode & (DAPND|DLOCK|0777)) | (d->mode & (DALLOC|DDIR));
  1350. strncpy(d->name, xd.name, sizeof(d->name));
  1351. accessdir(p, d, FREAD, f->uid);
  1352. out:
  1353. if(p)
  1354. putbuf(p);
  1355. if(p1)
  1356. putbuf(p1);
  1357. if(f)
  1358. qunlock(f);
  1359. ou->fid = in->fid;
  1360. }
  1361. static void
  1362. f_clwalk(Chan *cp, Fcall *in, Fcall *ou)
  1363. {
  1364. int er, fid;
  1365. if(CHAT(cp))
  1366. print("c_clwalk macro\n");
  1367. f_clone(cp, in, ou); /* sets tag, fid */
  1368. if(ou->err)
  1369. return;
  1370. fid = in->fid;
  1371. in->fid = in->newfid;
  1372. f_walk(cp, in, ou); /* sets tag, fid, qid */
  1373. er = ou->err;
  1374. if(er == Eentry) {
  1375. /*
  1376. * if error is "no entry"
  1377. * return non error and fid
  1378. */
  1379. ou->err = 0;
  1380. f_clunk(cp, in, ou); /* sets tag, fid */
  1381. ou->err = 0;
  1382. ou->fid = fid;
  1383. if(CHAT(cp))
  1384. print("\terror: %s\n", errstr9p[er]);
  1385. } else if(er) {
  1386. /*
  1387. * if any other error
  1388. * return an error
  1389. */
  1390. ou->err = 0;
  1391. f_clunk(cp, in, ou); /* sets tag, fid */
  1392. ou->err = er;
  1393. }
  1394. /*
  1395. * non error
  1396. * return newfid
  1397. */
  1398. }
  1399. void (*call9p1[MAXSYSCALL])(Chan*, Fcall*, Fcall*) =
  1400. {
  1401. [Tnop] f_nop,
  1402. [Tosession] f_session,
  1403. [Tsession] f_session,
  1404. [Tflush] f_flush,
  1405. [Toattach] f_attach,
  1406. [Tattach] f_attach,
  1407. [Tclone] f_clone,
  1408. [Twalk] f_walk,
  1409. [Topen] f_open,
  1410. [Tcreate] f_create,
  1411. [Tread] f_read,
  1412. [Twrite] f_write,
  1413. [Tclunk] f_clunk,
  1414. [Tremove] f_remove,
  1415. [Tstat] f_stat,
  1416. [Twstat] f_wstat,
  1417. [Tclwalk] f_clwalk,
  1418. };
  1419. int
  1420. error9p1(Chan* cp, Msgbuf* mb)
  1421. {
  1422. Msgbuf *mb1;
  1423. print("type=%d count=%d\n", mb->data[0], mb->count);
  1424. print(" %.2x %.2x %.2x %.2x\n",
  1425. mb->data[1]&0xff, mb->data[2]&0xff,
  1426. mb->data[3]&0xff, mb->data[4]&0xff);
  1427. print(" %.2x %.2x %.2x %.2x\n",
  1428. mb->data[5]&0xff, mb->data[6]&0xff,
  1429. mb->data[7]&0xff, mb->data[8]&0xff);
  1430. print(" %.2x %.2x %.2x %.2x\n",
  1431. mb->data[9]&0xff, mb->data[10]&0xff,
  1432. mb->data[11]&0xff, mb->data[12]&0xff);
  1433. mb1 = mballoc(3, cp, Mbreply4);
  1434. mb1->data[0] = Rnop; /* your nop was ok */
  1435. mb1->data[1] = ~0;
  1436. mb1->data[2] = ~0;
  1437. mb1->count = 3;
  1438. mb1->param = mb->param;
  1439. fs_send(cp->reply, mb1);
  1440. return 1;
  1441. }
  1442. int
  1443. serve9p1(Msgbuf* mb)
  1444. {
  1445. int t, n;
  1446. Chan *cp;
  1447. Msgbuf *mb1;
  1448. Fcall fi, fo;
  1449. assert(mb != nil);
  1450. cp = mb->chan;
  1451. assert(mb->data != nil);
  1452. if(convM2S9p1(mb->data, &fi, mb->count) == 0){
  1453. assert(cp != nil);
  1454. if(cp->protocol == nil)
  1455. return 0;
  1456. print("9p1: bad M2S conversion\n");
  1457. return error9p1(cp, mb);
  1458. }
  1459. t = fi.type;
  1460. if(t < 0 || t >= MAXSYSCALL || (t&1) || !call9p1[t]) {
  1461. print("9p1: bad message type\n");
  1462. return error9p1(cp, mb);
  1463. }
  1464. /*
  1465. * allocate reply message
  1466. */
  1467. if(t == Tread) {
  1468. mb1 = mballoc(MAXMSG+MAXDAT, cp, Mbreply2);
  1469. fo.data = (char*)(mb1->data + 8);
  1470. } else
  1471. mb1 = mballoc(MAXMSG, cp, Mbreply3);
  1472. /*
  1473. * call the file system
  1474. */
  1475. assert(cp != nil);
  1476. fo.err = 0;
  1477. (*call9p1[t])(cp, &fi, &fo);
  1478. fo.type = t+1;
  1479. fo.tag = fi.tag;
  1480. if(fo.err) {
  1481. if(cons.flags&errorflag)
  1482. print("\ttype %d: error: %s\n", t, errstr9p[fo.err]);
  1483. if(CHAT(cp))
  1484. print("\terror: %s\n", errstr9p[fo.err]);
  1485. fo.type = Rerror;
  1486. strncpy(fo.ename, errstr9p[fo.err], sizeof(fo.ename));
  1487. }
  1488. n = convS2M9p1(&fo, mb1->data);
  1489. if(n == 0) {
  1490. print("9p1: bad S2M conversion\n");
  1491. mbfree(mb1);
  1492. return error9p1(cp, mb);
  1493. }
  1494. mb1->count = n;
  1495. mb1->param = mb->param;
  1496. fs_send(cp->reply, mb1);
  1497. return 1;
  1498. }