9p1.c 29 KB

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