vacfs.c 13 KB

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