PageRenderTime 54ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/sys/src/cmd/disk/kfs/9p2.c

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