vacfs.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. #include "stdinc.h"
  2. #include <fcall.h>
  3. #include "vac.h"
  4. #define convM2Su(a, b, c, d) convM2S(a, b, c)
  5. #define convS2Mu(a, b, c, d) convS2M(a, b, c)
  6. #define convM2Du(a, b, c, d) convM2D(a, b, c)
  7. #define convD2Mu(a, b, c, d) convD2M(a, b, c)
  8. typedef struct Fid Fid;
  9. enum
  10. {
  11. Stacksize = 320 * 1024, /* was 32K */
  12. OPERM = 0x3 /* mask of all permission types in open mode */
  13. };
  14. struct Fid
  15. {
  16. short busy;
  17. short open;
  18. int fid;
  19. char *user;
  20. Qid qid;
  21. VacFile *file;
  22. VacDirEnum *vde;
  23. Fid *next;
  24. };
  25. enum
  26. {
  27. Pexec = 1,
  28. Pwrite = 2,
  29. Pread = 4,
  30. Pother = 1,
  31. Pgroup = 8,
  32. Powner = 64
  33. };
  34. Fid *fids;
  35. uchar *data;
  36. int mfd[2];
  37. int srvfd = -1;
  38. char *user;
  39. uchar mdata[8192+IOHDRSZ];
  40. int messagesize = sizeof mdata;
  41. Fcall rhdr;
  42. Fcall thdr;
  43. VacFs *fs;
  44. VtConn *conn;
  45. int noperm;
  46. int dotu;
  47. char *defmnt;
  48. Fid * newfid(int);
  49. void error(char*);
  50. void io(void);
  51. void vacshutdown(void);
  52. void usage(void);
  53. int perm(Fid*, int);
  54. int permf(VacFile*, char*, int);
  55. ulong getl(void *p);
  56. void init(char*, char*, long, int);
  57. int vacdirread(Fid *f, char *p, long off, long cnt);
  58. int vacstat(VacFile *parent, VacDir *vd, uchar *p, int np);
  59. void srv(void* a);
  60. char *rflush(Fid*), *rversion(Fid*),
  61. *rauth(Fid*), *rattach(Fid*), *rwalk(Fid*),
  62. *ropen(Fid*), *rcreate(Fid*),
  63. *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
  64. *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
  65. char *(*fcalls[Tmax])(Fid*);
  66. void
  67. initfcalls(void)
  68. {
  69. fcalls[Tflush]= rflush;
  70. fcalls[Tversion]= rversion;
  71. fcalls[Tattach]= rattach;
  72. fcalls[Tauth]= rauth;
  73. fcalls[Twalk]= rwalk;
  74. fcalls[Topen]= ropen;
  75. fcalls[Tcreate]= rcreate;
  76. fcalls[Tread]= rread;
  77. fcalls[Twrite]= rwrite;
  78. fcalls[Tclunk]= rclunk;
  79. fcalls[Tremove]= rremove;
  80. fcalls[Tstat]= rstat;
  81. fcalls[Twstat]= rwstat;
  82. }
  83. char Eperm[] = "permission denied";
  84. char Enotdir[] = "not a directory";
  85. char Enotexist[] = "file does not exist";
  86. char Einuse[] = "file in use";
  87. char Eexist[] = "file exists";
  88. char Enotowner[] = "not owner";
  89. char Eisopen[] = "file already open for I/O";
  90. char Excl[] = "exclusive use file already open";
  91. char Ename[] = "illegal name";
  92. char Erdonly[] = "read only file system";
  93. char Eio[] = "i/o error";
  94. char Eempty[] = "directory is not empty";
  95. char Emode[] = "illegal mode";
  96. int dflag;
  97. void
  98. notifyf(void *a, char *s)
  99. {
  100. USED(a);
  101. if(strncmp(s, "interrupt", 9) == 0)
  102. noted(NCONT);
  103. noted(NDFLT);
  104. }
  105. void
  106. threadmain(int argc, char *argv[])
  107. {
  108. char *defsrv, *srvname;
  109. int p[2], fd;
  110. int stdio;
  111. char *host = nil;
  112. long ncache;
  113. stdio = 0;
  114. ncache = 256;
  115. fmtinstall('H', encodefmt);
  116. fmtinstall('V', vtscorefmt);
  117. fmtinstall('F', vtfcallfmt);
  118. defmnt = nil;
  119. defsrv = nil;
  120. ARGBEGIN{
  121. case 'd':
  122. fmtinstall('F', fcallfmt);
  123. dflag = 1;
  124. break;
  125. case 'c':
  126. ncache = atoi(EARGF(usage()));
  127. break;
  128. case 'i':
  129. defmnt = nil;
  130. stdio = 1;
  131. mfd[0] = 0;
  132. mfd[1] = 1;
  133. break;
  134. case 'h':
  135. host = EARGF(usage());
  136. break;
  137. case 'S':
  138. defsrv = EARGF(usage());
  139. break;
  140. case 's':
  141. defsrv = "vacfs";
  142. break;
  143. case 'm':
  144. defmnt = EARGF(usage());
  145. break;
  146. case 'p':
  147. noperm = 1;
  148. break;
  149. case 'V':
  150. chattyventi = 1;
  151. break;
  152. default:
  153. usage();
  154. }ARGEND
  155. if(argc != 1)
  156. usage();
  157. if(defsrv == nil && defmnt == nil && !stdio)
  158. defmnt = "/n/vac";
  159. if(stdio && defmnt)
  160. sysfatal("cannot use -m with -i");
  161. initfcalls();
  162. notify(notifyf);
  163. user = getuser();
  164. conn = vtdial(host);
  165. if(conn == nil)
  166. sysfatal("could not connect to server: %r");
  167. if(vtconnect(conn) < 0)
  168. sysfatal("vtconnect: %r");
  169. fs = vacfsopen(conn, argv[0], VtOREAD, ncache);
  170. if(fs == nil)
  171. sysfatal("vacfsopen: %r");
  172. if(!stdio){
  173. if(pipe(p) < 0)
  174. sysfatal("pipe failed: %r");
  175. mfd[0] = p[0];
  176. mfd[1] = p[0];
  177. srvfd = p[1];
  178. }
  179. procrfork(srv, 0, Stacksize, RFFDG|RFNAMEG|RFNOTEG);
  180. if(!stdio){
  181. close(p[0]);
  182. if(defsrv){
  183. srvname = smprint("/srv/%s", defsrv);
  184. fd = create(srvname, OWRITE|ORCLOSE, 0666);
  185. if(fd < 0)
  186. sysfatal("create %s: %r", srvname);
  187. if(fprint(fd, "%d", srvfd) < 0)
  188. sysfatal("write %s: %r", srvname);
  189. free(srvname);
  190. }
  191. if(defmnt){
  192. if(mount(srvfd, -1, defmnt, MREPL|MCREATE, "") < 0)
  193. sysfatal("mount %s: %r", defmnt);
  194. }
  195. }
  196. threadexits(0);
  197. }
  198. void
  199. srv(void *a)
  200. {
  201. USED(a);
  202. io();
  203. vacshutdown();
  204. }
  205. void
  206. usage(void)
  207. {
  208. fprint(2, "usage: %s [-sd] [-h host] [-c ncache] [-m mountpoint] vacfile\n", argv0);
  209. threadexitsall("usage");
  210. }
  211. char*
  212. rversion(Fid *unused)
  213. {
  214. Fid *f;
  215. USED(unused);
  216. for(f = fids; f; f = f->next)
  217. if(f->busy)
  218. rclunk(f);
  219. if(rhdr.msize < 256)
  220. return vtstrdup("version: message size too small");
  221. messagesize = rhdr.msize;
  222. if(messagesize > sizeof mdata)
  223. messagesize = sizeof mdata;
  224. thdr.msize = messagesize;
  225. if(strncmp(rhdr.version, "9P2000", 6) != 0)
  226. return vtstrdup("unrecognized 9P version");
  227. thdr.version = "9P2000";
  228. if(strncmp(rhdr.version, "9P2000.u", 8) == 0){
  229. dotu = 1;
  230. thdr.version = "9P2000.u";
  231. }
  232. return nil;
  233. }
  234. char*
  235. rflush(Fid *f)
  236. {
  237. USED(f);
  238. return 0;
  239. }
  240. char*
  241. rauth(Fid *f)
  242. {
  243. USED(f);
  244. return vtstrdup("vacfs: authentication not required");
  245. }
  246. char*
  247. rattach(Fid *f)
  248. {
  249. /* no authentication for the momment */
  250. VacFile *file;
  251. char err[80];
  252. file = vacfsgetroot(fs);
  253. if(file == nil) {
  254. rerrstr(err, sizeof err);
  255. return vtstrdup(err);
  256. }
  257. f->busy = 1;
  258. f->file = file;
  259. f->qid.path = vacfilegetid(f->file);
  260. f->qid.vers = 0;
  261. f->qid.type = QTDIR;
  262. thdr.qid = f->qid;
  263. if(rhdr.uname[0])
  264. f->user = vtstrdup(rhdr.uname);
  265. else
  266. f->user = "none";
  267. return 0;
  268. }
  269. char*
  270. rwalk(Fid *f)
  271. {
  272. VacFile *file, *nfile;
  273. Fid *nf;
  274. int nqid, nwname;
  275. Qid qid;
  276. char *err = nil;
  277. if(f->busy == 0)
  278. return Enotexist;
  279. nf = nil;
  280. if(rhdr.fid != rhdr.newfid){
  281. if(f->open)
  282. return vtstrdup(Eisopen);
  283. if(f->busy == 0)
  284. return vtstrdup(Enotexist);
  285. nf = newfid(rhdr.newfid);
  286. if(nf->busy)
  287. return vtstrdup(Eisopen);
  288. nf->busy = 1;
  289. nf->open = 0;
  290. nf->qid = f->qid;
  291. nf->file = vacfileincref(f->file);
  292. nf->user = vtstrdup(f->user);
  293. f = nf;
  294. }
  295. nwname = rhdr.nwname;
  296. /* easy case */
  297. if(nwname == 0) {
  298. thdr.nwqid = 0;
  299. return 0;
  300. }
  301. file = f->file;
  302. vacfileincref(file);
  303. qid = f->qid;
  304. for(nqid = 0; nqid < nwname; nqid++){
  305. if((qid.type & QTDIR) == 0){
  306. err = Enotdir;
  307. break;
  308. }
  309. if(!permf(file, f->user, Pexec)) {
  310. err = Eperm;
  311. break;
  312. }
  313. nfile = vacfilewalk(file, rhdr.wname[nqid]);
  314. if(nfile == nil)
  315. break;
  316. vacfiledecref(file);
  317. file = nfile;
  318. qid.type = QTFILE;
  319. if(vacfileisdir(file))
  320. qid.type = QTDIR;
  321. qid.vers = vacfilegetmcount(file);
  322. qid.path = vacfilegetid(file);
  323. thdr.wqid[nqid] = qid;
  324. }
  325. thdr.nwqid = nqid;
  326. if(nqid == nwname){
  327. /* success */
  328. f->qid = thdr.wqid[nqid-1];
  329. vacfiledecref(f->file);
  330. f->file = file;
  331. return 0;
  332. }
  333. vacfiledecref(file);
  334. if(nf != nil)
  335. rclunk(nf);
  336. /* only error on the first element */
  337. if(nqid == 0)
  338. return vtstrdup(err);
  339. return 0;
  340. }
  341. char *
  342. ropen(Fid *f)
  343. {
  344. int mode, trunc;
  345. if(f->open)
  346. return vtstrdup(Eisopen);
  347. if(!f->busy)
  348. return vtstrdup(Enotexist);
  349. mode = rhdr.mode;
  350. thdr.iounit = messagesize - IOHDRSZ;
  351. if(f->qid.type & QTDIR){
  352. if(mode != OREAD)
  353. return vtstrdup(Eperm);
  354. if(!perm(f, Pread))
  355. return vtstrdup(Eperm);
  356. thdr.qid = f->qid;
  357. f->vde = nil;
  358. f->open = 1;
  359. return 0;
  360. }
  361. if(mode & ORCLOSE)
  362. return vtstrdup(Erdonly);
  363. trunc = mode & OTRUNC;
  364. mode &= OPERM;
  365. if(mode==OWRITE || mode==ORDWR || trunc)
  366. if(!perm(f, Pwrite))
  367. return vtstrdup(Eperm);
  368. if(mode==OREAD || mode==ORDWR)
  369. if(!perm(f, Pread))
  370. return vtstrdup(Eperm);
  371. if(mode==OEXEC)
  372. if(!perm(f, Pexec))
  373. return vtstrdup(Eperm);
  374. thdr.qid = f->qid;
  375. thdr.iounit = messagesize - IOHDRSZ;
  376. f->open = 1;
  377. return 0;
  378. }
  379. char*
  380. rcreate(Fid* fid)
  381. {
  382. VacFile *vf;
  383. ulong mode;
  384. if(fid->open)
  385. return vtstrdup(Eisopen);
  386. if(!fid->busy)
  387. return vtstrdup(Enotexist);
  388. if(fs->mode & ModeSnapshot)
  389. return vtstrdup(Erdonly);
  390. vf = fid->file;
  391. if(!vacfileisdir(vf))
  392. return vtstrdup(Enotdir);
  393. if(!permf(vf, fid->user, Pwrite))
  394. return vtstrdup(Eperm);
  395. mode = rhdr.perm & 0777;
  396. if(rhdr.perm & DMDIR){
  397. if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND))
  398. return vtstrdup(Emode);
  399. switch(rhdr.mode & OPERM){
  400. default:
  401. return vtstrdup(Emode);
  402. case OEXEC:
  403. case OREAD:
  404. break;
  405. case OWRITE:
  406. case ORDWR:
  407. return vtstrdup(Eperm);
  408. }
  409. mode |= ModeDir;
  410. }
  411. vf = vacfilecreate(vf, rhdr.name, mode);
  412. if(vf == nil) {
  413. char err[80];
  414. rerrstr(err, sizeof err);
  415. return vtstrdup(err);
  416. }
  417. vacfiledecref(fid->file);
  418. fid->file = vf;
  419. fid->qid.type = QTFILE;
  420. if(vacfileisdir(vf))
  421. fid->qid.type = QTDIR;
  422. fid->qid.vers = vacfilegetmcount(vf);
  423. fid->qid.path = vacfilegetid(vf);
  424. thdr.qid = fid->qid;
  425. thdr.iounit = messagesize - IOHDRSZ;
  426. return 0;
  427. }
  428. char*
  429. rread(Fid *f)
  430. {
  431. char *buf;
  432. vlong off;
  433. int cnt;
  434. VacFile *vf;
  435. char err[80];
  436. int n;
  437. if(!f->busy)
  438. return vtstrdup(Enotexist);
  439. vf = f->file;
  440. thdr.count = 0;
  441. off = rhdr.offset;
  442. buf = thdr.data;
  443. cnt = rhdr.count;
  444. if(f->qid.type & QTDIR)
  445. n = vacdirread(f, buf, off, cnt);
  446. else if(vacfilegetmode(f->file)&ModeDevice)
  447. return vtstrdup("device");
  448. else if(vacfilegetmode(f->file)&ModeLink)
  449. return vtstrdup("symbolic link");
  450. else if(vacfilegetmode(f->file)&ModeNamedPipe)
  451. return vtstrdup("named pipe");
  452. else
  453. n = vacfileread(vf, buf, cnt, off);
  454. if(n < 0) {
  455. rerrstr(err, sizeof err);
  456. return vtstrdup(err);
  457. }
  458. thdr.count = n;
  459. return 0;
  460. }
  461. char*
  462. rwrite(Fid *f)
  463. {
  464. USED(f);
  465. return vtstrdup(Erdonly);
  466. }
  467. char *
  468. rclunk(Fid *f)
  469. {
  470. f->busy = 0;
  471. f->open = 0;
  472. vtfree(f->user);
  473. f->user = nil;
  474. if(f->file)
  475. vacfiledecref(f->file);
  476. f->file = nil;
  477. vdeclose(f->vde);
  478. f->vde = nil;
  479. return 0;
  480. }
  481. char *
  482. rremove(Fid *f)
  483. {
  484. VacFile *vf, *vfp;
  485. char errbuf[80];
  486. char *err = nil;
  487. if(!f->busy)
  488. return vtstrdup(Enotexist);
  489. vf = f->file;
  490. vfp = vacfilegetparent(vf);
  491. if(!permf(vfp, f->user, Pwrite)) {
  492. err = Eperm;
  493. goto Exit;
  494. }
  495. if(!vacfileremove(vf)) {
  496. rerrstr(errbuf, sizeof errbuf);
  497. err = errbuf;
  498. }
  499. Exit:
  500. vacfiledecref(vfp);
  501. rclunk(f);
  502. return vtstrdup(err);
  503. }
  504. char *
  505. rstat(Fid *f)
  506. {
  507. VacDir dir;
  508. static uchar statbuf[1024];
  509. VacFile *parent;
  510. if(!f->busy)
  511. return vtstrdup(Enotexist);
  512. parent = vacfilegetparent(f->file);
  513. vacfilegetdir(f->file, &dir);
  514. thdr.stat = statbuf;
  515. thdr.nstat = vacstat(parent, &dir, thdr.stat, sizeof statbuf);
  516. vdcleanup(&dir);
  517. vacfiledecref(parent);
  518. return 0;
  519. }
  520. char *
  521. rwstat(Fid *f)
  522. {
  523. if(!f->busy)
  524. return vtstrdup(Enotexist);
  525. return vtstrdup(Erdonly);
  526. }
  527. int
  528. vacstat(VacFile *parent, VacDir *vd, uchar *p, int np)
  529. {
  530. int ret;
  531. Dir dir;
  532. memset(&dir, 0, sizeof(dir));
  533. dir.qid.path = vd->qid + vacfilegetqidoffset(parent);
  534. if(vd->qidspace)
  535. dir.qid.path += vd->qidoffset;
  536. dir.qid.vers = vd->mcount;
  537. dir.mode = vd->mode & 0777;
  538. if(vd->mode & ModeAppend){
  539. dir.qid.type |= QTAPPEND;
  540. dir.mode |= DMAPPEND;
  541. }
  542. if(vd->mode & ModeExclusive){
  543. dir.qid.type |= QTEXCL;
  544. dir.mode |= DMEXCL;
  545. }
  546. if(vd->mode & ModeDir){
  547. dir.qid.type |= QTDIR;
  548. dir.mode |= DMDIR;
  549. }
  550. dir.atime = vd->atime;
  551. dir.mtime = vd->mtime;
  552. dir.length = vd->size;
  553. dir.name = vd->elem;
  554. dir.uid = vd->uid;
  555. dir.gid = vd->gid;
  556. dir.muid = vd->mid;
  557. ret = convD2Mu(&dir, p, np, dotu);
  558. return ret;
  559. }
  560. int
  561. vacdirread(Fid *f, char *p, long off, long cnt)
  562. {
  563. int i, n, nb;
  564. VacDir vd;
  565. /*
  566. * special case of rewinding a directory
  567. * otherwise ignore the offset
  568. */
  569. if(off == 0 && f->vde){
  570. vdeclose(f->vde);
  571. f->vde = nil;
  572. }
  573. if(f->vde == nil){
  574. f->vde = vdeopen(f->file);
  575. if(f->vde == nil)
  576. return -1;
  577. }
  578. for(nb = 0; nb < cnt; nb += n) {
  579. i = vderead(f->vde, &vd);
  580. if(i < 0)
  581. return -1;
  582. if(i == 0)
  583. break;
  584. n = vacstat(f->file, &vd, (uchar*)p, cnt-nb);
  585. if(n <= BIT16SZ) {
  586. vdeunread(f->vde);
  587. break;
  588. }
  589. vdcleanup(&vd);
  590. p += n;
  591. }
  592. return nb;
  593. }
  594. Fid *
  595. newfid(int fid)
  596. {
  597. Fid *f, *ff;
  598. ff = 0;
  599. for(f = fids; f; f = f->next)
  600. if(f->fid == fid)
  601. return f;
  602. else if(!ff && !f->busy)
  603. ff = f;
  604. if(ff){
  605. ff->fid = fid;
  606. return ff;
  607. }
  608. f = vtmallocz(sizeof *f);
  609. f->fid = fid;
  610. f->next = fids;
  611. fids = f;
  612. return f;
  613. }
  614. void
  615. io(void)
  616. {
  617. char *err;
  618. int n;
  619. for(;;){
  620. n = read9pmsg(mfd[0], mdata, sizeof mdata);
  621. if(n <= 0)
  622. break;
  623. if(convM2Su(mdata, n, &rhdr, dotu) != n)
  624. sysfatal("convM2S conversion error");
  625. if(dflag)
  626. fprint(2, "vacfs:<-%F\n", &rhdr);
  627. thdr.data = (char*)mdata + IOHDRSZ;
  628. if(!fcalls[rhdr.type])
  629. err = "bad fcall type";
  630. else
  631. err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
  632. if(err){
  633. thdr.type = Rerror;
  634. thdr.ename = err;
  635. }else{
  636. thdr.type = rhdr.type + 1;
  637. thdr.fid = rhdr.fid;
  638. }
  639. thdr.tag = rhdr.tag;
  640. if(dflag)
  641. fprint(2, "vacfs:->%F\n", &thdr);
  642. n = convS2Mu(&thdr, mdata, messagesize, dotu);
  643. if(n <= BIT16SZ)
  644. sysfatal("convS2Mu conversion error");
  645. if(err)
  646. vtfree(err);
  647. if(write(mfd[1], mdata, n) != n)
  648. sysfatal("mount write: %r");
  649. }
  650. }
  651. int
  652. permf(VacFile *vf, char *user, int p)
  653. {
  654. VacDir dir;
  655. ulong perm;
  656. if(vacfilegetdir(vf, &dir))
  657. return 0;
  658. perm = dir.mode & 0777;
  659. if(noperm)
  660. goto Good;
  661. if((p*Pother) & perm)
  662. goto Good;
  663. if(strcmp(user, dir.gid)==0 && ((p*Pgroup) & perm))
  664. goto Good;
  665. if(strcmp(user, dir.uid)==0 && ((p*Powner) & perm))
  666. goto Good;
  667. vdcleanup(&dir);
  668. return 0;
  669. Good:
  670. vdcleanup(&dir);
  671. return 1;
  672. }
  673. int
  674. perm(Fid *f, int p)
  675. {
  676. return permf(f->file, f->user, p);
  677. }
  678. void
  679. vacshutdown(void)
  680. {
  681. Fid *f;
  682. for(f = fids; f; f = f->next) {
  683. if(!f->busy)
  684. continue;
  685. rclunk(f);
  686. }
  687. vacfsclose(fs);
  688. vthangup(conn);
  689. }