PageRenderTime 66ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/sys/src/cmd/cwfs/9p2.c

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