fsys.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <thread.h>
  5. #include <cursor.h>
  6. #include <mouse.h>
  7. #include <keyboard.h>
  8. #include <frame.h>
  9. #include <fcall.h>
  10. #include <plumb.h>
  11. #include "dat.h"
  12. #include "fns.h"
  13. static int cfd;
  14. static int sfd;
  15. enum
  16. {
  17. Nhash = 16,
  18. DEBUG = 0
  19. };
  20. static Fid *fids[Nhash];
  21. Fid *newfid(int);
  22. static Xfid* fsysflush(Xfid*, Fid*);
  23. static Xfid* fsysauth(Xfid*, Fid*);
  24. static Xfid* fsysversion(Xfid*, Fid*);
  25. static Xfid* fsysattach(Xfid*, Fid*);
  26. static Xfid* fsyswalk(Xfid*, Fid*);
  27. static Xfid* fsysopen(Xfid*, Fid*);
  28. static Xfid* fsyscreate(Xfid*, Fid*);
  29. static Xfid* fsysread(Xfid*, Fid*);
  30. static Xfid* fsyswrite(Xfid*, Fid*);
  31. static Xfid* fsysclunk(Xfid*, Fid*);
  32. static Xfid* fsysremove(Xfid*, Fid*);
  33. static Xfid* fsysstat(Xfid*, Fid*);
  34. static Xfid* fsyswstat(Xfid*, Fid*);
  35. Xfid* (*fcall[Tmax])(Xfid*, Fid*) =
  36. {
  37. [Tflush] = fsysflush,
  38. [Tversion] = fsysversion,
  39. [Tauth] = fsysauth,
  40. [Tattach] = fsysattach,
  41. [Twalk] = fsyswalk,
  42. [Topen] = fsysopen,
  43. [Tcreate] = fsyscreate,
  44. [Tread] = fsysread,
  45. [Twrite] = fsyswrite,
  46. [Tclunk] = fsysclunk,
  47. [Tremove]= fsysremove,
  48. [Tstat] = fsysstat,
  49. [Twstat] = fsyswstat,
  50. };
  51. char Eperm[] = "permission denied";
  52. char Eexist[] = "file does not exist";
  53. char Enotdir[] = "not a directory";
  54. Dirtab dirtab[]=
  55. {
  56. { ".", QTDIR, Qdir, 0500|DMDIR },
  57. { "acme", QTDIR, Qacme, 0500|DMDIR },
  58. { "cons", QTFILE, Qcons, 0600 },
  59. { "consctl", QTFILE, Qconsctl, 0000 },
  60. { "draw", QTDIR, Qdraw, 0000|DMDIR }, /* to suppress graphics progs started in acme */
  61. { "editout", QTFILE, Qeditout, 0200 },
  62. { "index", QTFILE, Qindex, 0400 },
  63. { "label", QTFILE, Qlabel, 0600 },
  64. { "new", QTDIR, Qnew, 0500|DMDIR },
  65. { nil, }
  66. };
  67. Dirtab dirtabw[]=
  68. {
  69. { ".", QTDIR, Qdir, 0500|DMDIR },
  70. { "addr", QTFILE, QWaddr, 0600 },
  71. { "body", QTAPPEND, QWbody, 0600|DMAPPEND },
  72. { "ctl", QTFILE, QWctl, 0600 },
  73. { "data", QTFILE, QWdata, 0600 },
  74. { "editout", QTFILE, QWeditout, 0200 },
  75. { "errors", QTFILE, QWerrors, 0200 },
  76. { "event", QTFILE, QWevent, 0600 },
  77. { "rdsel", QTFILE, QWrdsel, 0400 },
  78. { "wrsel", QTFILE, QWwrsel, 0200 },
  79. { "tag", QTAPPEND, QWtag, 0600|DMAPPEND },
  80. { "xdata", QTFILE, QWxdata, 0600 },
  81. { nil, }
  82. };
  83. typedef struct Mnt Mnt;
  84. struct Mnt
  85. {
  86. QLock;
  87. int id;
  88. Mntdir *md;
  89. };
  90. Mnt mnt;
  91. Xfid* respond(Xfid*, Fcall*, char*);
  92. int dostat(int, Dirtab*, uchar*, int, uint);
  93. uint getclock(void);
  94. char *user = "Wile E. Coyote";
  95. int clockfd;
  96. static int closing = 0;
  97. int messagesize = Maxblock+IOHDRSZ; /* good start */
  98. void fsysproc(void *);
  99. void
  100. fsysinit(void)
  101. {
  102. int p[2];
  103. int n, fd;
  104. char buf[256];
  105. if(pipe(p) < 0)
  106. error("can't create pipe");
  107. cfd = p[0];
  108. sfd = p[1];
  109. fmtinstall('F', fcallfmt);
  110. clockfd = open("/dev/time", OREAD|OCEXEC);
  111. fd = open("/dev/user", OREAD);
  112. if(fd >= 0){
  113. n = read(fd, buf, sizeof buf-1);
  114. if(n > 0){
  115. buf[n] = 0;
  116. user = estrdup(buf);
  117. }
  118. close(fd);
  119. }
  120. proccreate(fsysproc, nil, STACK);
  121. }
  122. void
  123. fsysproc(void *)
  124. {
  125. int n;
  126. Xfid *x;
  127. Fid *f;
  128. Fcall t;
  129. uchar *buf;
  130. threadsetname("fsysproc");
  131. x = nil;
  132. for(;;){
  133. buf = emalloc(messagesize+UTFmax); /* overflow for appending partial rune in xfidwrite */
  134. n = read9pmsg(sfd, buf, messagesize);
  135. if(n <= 0){
  136. if(closing)
  137. break;
  138. error("i/o error on server channel");
  139. }
  140. if(x == nil){
  141. sendp(cxfidalloc, nil);
  142. x = recvp(cxfidalloc);
  143. }
  144. x->buf = buf;
  145. if(convM2S(buf, n, x) != n)
  146. error("convert error in convM2S");
  147. if(DEBUG)
  148. fprint(2, "%F\n", &x->Fcall);
  149. if(fcall[x->type] == nil)
  150. x = respond(x, &t, "bad fcall type");
  151. else{
  152. switch(x->type){
  153. case Tversion:
  154. case Tauth:
  155. case Tflush:
  156. f = nil;
  157. break;
  158. case Tattach:
  159. f = newfid(x->fid);
  160. break;
  161. default:
  162. f = newfid(x->fid);
  163. if(!f->busy){
  164. x->f = f;
  165. x = respond(x, &t, "fid not in use");
  166. continue;
  167. }
  168. break;
  169. }
  170. x->f = f;
  171. x = (*fcall[x->type])(x, f);
  172. }
  173. }
  174. }
  175. Mntdir*
  176. fsysaddid(Rune *dir, int ndir, Rune **incl, int nincl)
  177. {
  178. Mntdir *m;
  179. int id;
  180. qlock(&mnt);
  181. id = ++mnt.id;
  182. m = emalloc(sizeof *m);
  183. m->id = id;
  184. m->dir = dir;
  185. m->ref = 1; /* one for Command, one will be incremented in attach */
  186. m->ndir = ndir;
  187. m->next = mnt.md;
  188. m->incl = incl;
  189. m->nincl = nincl;
  190. mnt.md = m;
  191. qunlock(&mnt);
  192. return m;
  193. }
  194. void
  195. fsysincid(Mntdir *m)
  196. {
  197. qlock(&mnt);
  198. m->ref++;
  199. qunlock(&mnt);
  200. }
  201. void
  202. fsysdelid(Mntdir *idm)
  203. {
  204. Mntdir *m, *prev;
  205. int i;
  206. char buf[64];
  207. if(idm == nil)
  208. return;
  209. qlock(&mnt);
  210. if(--idm->ref > 0){
  211. qunlock(&mnt);
  212. return;
  213. }
  214. prev = nil;
  215. for(m=mnt.md; m; m=m->next){
  216. if(m == idm){
  217. if(prev)
  218. prev->next = m->next;
  219. else
  220. mnt.md = m->next;
  221. for(i=0; i<m->nincl; i++)
  222. free(m->incl[i]);
  223. free(m->incl);
  224. free(m->dir);
  225. free(m);
  226. qunlock(&mnt);
  227. return;
  228. }
  229. prev = m;
  230. }
  231. qunlock(&mnt);
  232. sprint(buf, "fsysdelid: can't find id %d\n", idm->id);
  233. sendp(cerr, estrdup(buf));
  234. }
  235. /*
  236. * Called only in exec.c:/^run(), from a different FD group
  237. */
  238. Mntdir*
  239. fsysmount(Rune *dir, int ndir, Rune **incl, int nincl)
  240. {
  241. char buf[256];
  242. Mntdir *m;
  243. /* close server side so don't hang if acme is half-exited */
  244. close(sfd);
  245. m = fsysaddid(dir, ndir, incl, nincl);
  246. sprint(buf, "%d", m->id);
  247. if(mount(cfd, -1, "/mnt/acme", MREPL, buf) < 0){
  248. fsysdelid(m);
  249. return nil;
  250. }
  251. close(cfd);
  252. bind("/mnt/acme", "/mnt/wsys", MREPL);
  253. if(bind("/mnt/acme", "/dev", MBEFORE) < 0){
  254. fsysdelid(m);
  255. return nil;
  256. }
  257. return m;
  258. }
  259. void
  260. fsysclose(void)
  261. {
  262. closing = 1;
  263. close(cfd);
  264. close(sfd);
  265. }
  266. Xfid*
  267. respond(Xfid *x, Fcall *t, char *err)
  268. {
  269. int n;
  270. if(err){
  271. t->type = Rerror;
  272. t->ename = err;
  273. }else
  274. t->type = x->type+1;
  275. t->fid = x->fid;
  276. t->tag = x->tag;
  277. if(x->buf == nil)
  278. x->buf = emalloc(messagesize);
  279. n = convS2M(t, x->buf, messagesize);
  280. if(n <= 0)
  281. error("convert error in convS2M");
  282. if(write(sfd, x->buf, n) != n)
  283. error("write error in respond");
  284. free(x->buf);
  285. x->buf = nil;
  286. if(DEBUG)
  287. fprint(2, "r: %F\n", t);
  288. return x;
  289. }
  290. static
  291. Xfid*
  292. fsysversion(Xfid *x, Fid*)
  293. {
  294. Fcall t;
  295. if(x->msize < 256)
  296. return respond(x, &t, "version: message size too small");
  297. if(x->msize < messagesize)
  298. messagesize = x->msize;
  299. t.msize = messagesize;
  300. if(strncmp(x->version, "9P2000", 6) != 0)
  301. return respond(x, &t, "unrecognized 9P version");
  302. t.version = "9P2000";
  303. return respond(x, &t, nil);
  304. }
  305. static
  306. Xfid*
  307. fsysauth(Xfid *x, Fid*)
  308. {
  309. Fcall t;
  310. return respond(x, &t, "acme: authentication not required");
  311. }
  312. static
  313. Xfid*
  314. fsysflush(Xfid *x, Fid*)
  315. {
  316. sendp(x->c, xfidflush);
  317. return nil;
  318. }
  319. static
  320. Xfid*
  321. fsysattach(Xfid *x, Fid *f)
  322. {
  323. Fcall t;
  324. int id;
  325. Mntdir *m;
  326. if(strcmp(x->uname, user) != 0)
  327. return respond(x, &t, Eperm);
  328. f->busy = TRUE;
  329. f->open = FALSE;
  330. f->qid.path = Qdir;
  331. f->qid.type = QTDIR;
  332. f->qid.vers = 0;
  333. f->dir = dirtab;
  334. f->nrpart = 0;
  335. f->w = nil;
  336. t.qid = f->qid;
  337. f->mntdir = nil;
  338. id = atoi(x->aname);
  339. qlock(&mnt);
  340. for(m=mnt.md; m; m=m->next)
  341. if(m->id == id){
  342. f->mntdir = m;
  343. m->ref++;
  344. break;
  345. }
  346. if(m == nil)
  347. sendp(cerr, estrdup("unknown id in attach"));
  348. qunlock(&mnt);
  349. return respond(x, &t, nil);
  350. }
  351. static
  352. Xfid*
  353. fsyswalk(Xfid *x, Fid *f)
  354. {
  355. Fcall t;
  356. int c, i, j, id;
  357. Qid q;
  358. uchar type;
  359. ulong path;
  360. Fid *nf;
  361. Dirtab *d, *dir;
  362. Window *w;
  363. char *err;
  364. nf = nil;
  365. w = nil;
  366. if(f->open)
  367. return respond(x, &t, "walk of open file");
  368. if(x->fid != x->newfid){
  369. nf = newfid(x->newfid);
  370. if(nf->busy)
  371. return respond(x, &t, "newfid already in use");
  372. nf->busy = TRUE;
  373. nf->open = FALSE;
  374. nf->mntdir = f->mntdir;
  375. if(f->mntdir)
  376. f->mntdir->ref++;
  377. nf->dir = f->dir;
  378. nf->qid = f->qid;
  379. nf->w = f->w;
  380. nf->nrpart = 0; /* not open, so must be zero */
  381. if(nf->w)
  382. incref(nf->w);
  383. f = nf; /* walk f */
  384. }
  385. t.nwqid = 0;
  386. err = nil;
  387. dir = nil;
  388. id = WIN(f->qid);
  389. q = f->qid;
  390. if(x->nwname > 0){
  391. for(i=0; i<x->nwname; i++){
  392. if((q.type & QTDIR) == 0){
  393. err = Enotdir;
  394. break;
  395. }
  396. if(strcmp(x->wname[i], "..") == 0){
  397. type = QTDIR;
  398. path = Qdir;
  399. id = 0;
  400. if(w){
  401. winclose(w);
  402. w = nil;
  403. }
  404. Accept:
  405. if(i == MAXWELEM){
  406. err = "name too long";
  407. break;
  408. }
  409. q.type = type;
  410. q.vers = 0;
  411. q.path = QID(id, path);
  412. t.wqid[t.nwqid++] = q;
  413. continue;
  414. }
  415. /* is it a numeric name? */
  416. for(j=0; (c=x->wname[i][j]); j++)
  417. if(c<'0' || '9'<c)
  418. goto Regular;
  419. /* yes: it's a directory */
  420. if(w) /* name has form 27/23; get out before losing w */
  421. break;
  422. id = atoi(x->wname[i]);
  423. qlock(&row);
  424. w = lookid(id, FALSE);
  425. if(w == nil){
  426. qunlock(&row);
  427. break;
  428. }
  429. incref(w); /* we'll drop reference at end if there's an error */
  430. path = Qdir;
  431. type = QTDIR;
  432. qunlock(&row);
  433. dir = dirtabw;
  434. goto Accept;
  435. Regular:
  436. // if(FILE(f->qid) == Qacme) /* empty directory */
  437. // break;
  438. if(strcmp(x->wname[i], "new") == 0){
  439. if(w)
  440. error("w set in walk to new");
  441. sendp(cnewwindow, nil); /* signal newwindowthread */
  442. w = recvp(cnewwindow); /* receive new window */
  443. incref(w);
  444. type = QTDIR;
  445. path = QID(w->id, Qdir);
  446. id = w->id;
  447. dir = dirtabw;
  448. goto Accept;
  449. }
  450. if(id == 0)
  451. d = dirtab;
  452. else
  453. d = dirtabw;
  454. d++; /* skip '.' */
  455. for(; d->name; d++)
  456. if(strcmp(x->wname[i], d->name) == 0){
  457. path = d->qid;
  458. type = d->type;
  459. dir = d;
  460. goto Accept;
  461. }
  462. break; /* file not found */
  463. }
  464. if(i==0 && err == nil)
  465. err = Eexist;
  466. }
  467. if(err!=nil || t.nwqid<x->nwname){
  468. if(nf){
  469. nf->busy = FALSE;
  470. fsysdelid(nf->mntdir);
  471. }
  472. }else if(t.nwqid == x->nwname){
  473. if(w){
  474. f->w = w;
  475. w = nil; /* don't drop the reference */
  476. }
  477. if(dir)
  478. f->dir = dir;
  479. f->qid = q;
  480. }
  481. if(w != nil)
  482. winclose(w);
  483. return respond(x, &t, err);
  484. }
  485. static
  486. Xfid*
  487. fsysopen(Xfid *x, Fid *f)
  488. {
  489. Fcall t;
  490. int m;
  491. /* can't truncate anything, so just disregard */
  492. x->mode &= ~(OTRUNC|OCEXEC);
  493. /* can't execute or remove anything */
  494. if(x->mode==OEXEC || (x->mode&ORCLOSE))
  495. goto Deny;
  496. switch(x->mode){
  497. default:
  498. goto Deny;
  499. case OREAD:
  500. m = 0400;
  501. break;
  502. case OWRITE:
  503. m = 0200;
  504. break;
  505. case ORDWR:
  506. m = 0600;
  507. break;
  508. }
  509. if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)
  510. goto Deny;
  511. sendp(x->c, xfidopen);
  512. return nil;
  513. Deny:
  514. return respond(x, &t, Eperm);
  515. }
  516. static
  517. Xfid*
  518. fsyscreate(Xfid *x, Fid*)
  519. {
  520. Fcall t;
  521. return respond(x, &t, Eperm);
  522. }
  523. static
  524. int
  525. idcmp(void *a, void *b)
  526. {
  527. return *(int*)a - *(int*)b;
  528. }
  529. static
  530. Xfid*
  531. fsysread(Xfid *x, Fid *f)
  532. {
  533. Fcall t;
  534. uchar *b;
  535. int i, id, n, o, e, j, k, *ids, nids;
  536. Dirtab *d, dt;
  537. Column *c;
  538. uint clock, len;
  539. char buf[16];
  540. if(f->qid.type & QTDIR){
  541. if(FILE(f->qid) == Qacme){ /* empty dir */
  542. t.data = nil;
  543. t.count = 0;
  544. respond(x, &t, nil);
  545. return x;
  546. }
  547. o = x->offset;
  548. e = x->offset+x->count;
  549. clock = getclock();
  550. b = emalloc(messagesize);
  551. id = WIN(f->qid);
  552. n = 0;
  553. if(id > 0)
  554. d = dirtabw;
  555. else
  556. d = dirtab;
  557. d++; /* first entry is '.' */
  558. for(i=0; d->name!=nil && i<e; i+=len){
  559. len = dostat(WIN(x->f->qid), d, b+n, x->count-n, clock);
  560. if(len <= BIT16SZ)
  561. break;
  562. if(i >= o)
  563. n += len;
  564. d++;
  565. }
  566. if(id == 0){
  567. qlock(&row);
  568. nids = 0;
  569. ids = nil;
  570. for(j=0; j<row.ncol; j++){
  571. c = row.col[j];
  572. for(k=0; k<c->nw; k++){
  573. ids = erealloc(ids, (nids+1)*sizeof(int));
  574. ids[nids++] = c->w[k]->id;
  575. }
  576. }
  577. qunlock(&row);
  578. qsort(ids, nids, sizeof ids[0], idcmp);
  579. j = 0;
  580. dt.name = buf;
  581. for(; j<nids && i<e; i+=len){
  582. k = ids[j];
  583. sprint(dt.name, "%d", k);
  584. dt.qid = QID(k, Qdir);
  585. dt.type = QTDIR;
  586. dt.perm = DMDIR|0700;
  587. len = dostat(k, &dt, b+n, x->count-n, clock);
  588. if(len == 0)
  589. break;
  590. if(i >= o)
  591. n += len;
  592. j++;
  593. }
  594. free(ids);
  595. }
  596. t.data = (char*)b;
  597. t.count = n;
  598. respond(x, &t, nil);
  599. free(b);
  600. return x;
  601. }
  602. sendp(x->c, xfidread);
  603. return nil;
  604. }
  605. static
  606. Xfid*
  607. fsyswrite(Xfid *x, Fid*)
  608. {
  609. sendp(x->c, xfidwrite);
  610. return nil;
  611. }
  612. static
  613. Xfid*
  614. fsysclunk(Xfid *x, Fid *f)
  615. {
  616. fsysdelid(f->mntdir);
  617. sendp(x->c, xfidclose);
  618. return nil;
  619. }
  620. static
  621. Xfid*
  622. fsysremove(Xfid *x, Fid*)
  623. {
  624. Fcall t;
  625. return respond(x, &t, Eperm);
  626. }
  627. static
  628. Xfid*
  629. fsysstat(Xfid *x, Fid *f)
  630. {
  631. Fcall t;
  632. t.stat = emalloc(messagesize-IOHDRSZ);
  633. t.nstat = dostat(WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock());
  634. x = respond(x, &t, nil);
  635. free(t.stat);
  636. return x;
  637. }
  638. static
  639. Xfid*
  640. fsyswstat(Xfid *x, Fid*)
  641. {
  642. Fcall t;
  643. return respond(x, &t, Eperm);
  644. }
  645. Fid*
  646. newfid(int fid)
  647. {
  648. Fid *f, *ff, **fh;
  649. ff = nil;
  650. fh = &fids[fid&(Nhash-1)];
  651. for(f=*fh; f; f=f->next)
  652. if(f->fid == fid)
  653. return f;
  654. else if(ff==nil && f->busy==FALSE)
  655. ff = f;
  656. if(ff){
  657. ff->fid = fid;
  658. return ff;
  659. }
  660. f = emalloc(sizeof *f);
  661. f->fid = fid;
  662. f->next = *fh;
  663. *fh = f;
  664. return f;
  665. }
  666. uint
  667. getclock()
  668. {
  669. char buf[32];
  670. buf[0] = '\0';
  671. pread(clockfd, buf, sizeof buf, 0);
  672. return atoi(buf);
  673. }
  674. int
  675. dostat(int id, Dirtab *dir, uchar *buf, int nbuf, uint clock)
  676. {
  677. Dir d;
  678. d.qid.path = QID(id, dir->qid);
  679. d.qid.vers = 0;
  680. d.qid.type = dir->type;
  681. d.mode = dir->perm;
  682. d.length = 0; /* would be nice to do better */
  683. d.name = dir->name;
  684. d.uid = user;
  685. d.gid = user;
  686. d.muid = user;
  687. d.atime = clock;
  688. d.mtime = clock;
  689. return convD2M(&d, buf, nbuf);
  690. }