fs.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <authsrv.h>
  12. #include <fcall.h>
  13. #include "tapefs.h"
  14. Fid *fids;
  15. Ram *ram;
  16. int mfd[2];
  17. char *user;
  18. uint8_t mdata[Maxbuf+IOHDRSZ];
  19. int messagesize = Maxbuf+IOHDRSZ;
  20. Fcall rhdr;
  21. Fcall thdr;
  22. uint32_t path;
  23. Idmap *uidmap;
  24. Idmap *gidmap;
  25. int replete;
  26. int blocksize; /* for 32v */
  27. int verbose;
  28. int newtap; /* tap with time in sec */
  29. int blocksize;
  30. Fid * newfid(int);
  31. int ramstat(Ram*, uint8_t*, int);
  32. void io(void);
  33. void usage(void);
  34. int perm(int);
  35. char *rflush(Fid*), *rversion(Fid*), *rauth(Fid*),
  36. *rattach(Fid*), *rwalk(Fid*),
  37. *ropen(Fid*), *rcreate(Fid*),
  38. *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
  39. *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
  40. char *(*fcalls[])(Fid*) = {
  41. [Tflush] rflush,
  42. [Tversion] rversion,
  43. [Tauth] rauth,
  44. [Tattach] rattach,
  45. [Twalk] rwalk,
  46. [Topen] ropen,
  47. [Tcreate] rcreate,
  48. [Tread] rread,
  49. [Twrite] rwrite,
  50. [Tclunk] rclunk,
  51. [Tremove] rremove,
  52. [Tstat] rstat,
  53. [Twstat] rwstat,
  54. };
  55. char Eperm[] = "permission denied";
  56. char Enotdir[] = "not a directory";
  57. char Enoauth[] = "tapefs: authentication not required";
  58. char Enotexist[] = "file does not exist";
  59. char Einuse[] = "file in use";
  60. char Eexist[] = "file exists";
  61. char Enotowner[] = "not owner";
  62. char Eisopen[] = "file already open for I/O";
  63. char Excl[] = "exclusive use file already open";
  64. char Ename[] = "illegal name";
  65. void
  66. notifyf(void *a, char *s)
  67. {
  68. USED(a);
  69. if(strncmp(s, "interrupt", 9) == 0)
  70. noted(NCONT);
  71. noted(NDFLT);
  72. }
  73. void
  74. main(int argc, char *argv[])
  75. {
  76. Ram *r;
  77. char *defmnt;
  78. int p[2];
  79. char buf[TICKREQLEN];
  80. fmtinstall('F', fcallfmt);
  81. defmnt = "/n/tapefs";
  82. ARGBEGIN{
  83. case 'm':
  84. defmnt = EARGF(usage());
  85. break;
  86. case 'p': /* password file */
  87. uidmap = getpass(EARGF(usage()));
  88. break;
  89. case 'g': /* group file */
  90. gidmap = getpass(EARGF(usage()));
  91. break;
  92. case 'v':
  93. verbose++;
  94. break;
  95. case 'n':
  96. newtap++;
  97. break;
  98. case 'b':
  99. blocksize = atoi(EARGF(usage()));
  100. break;
  101. default:
  102. usage();
  103. }ARGEND
  104. if(argc==0)
  105. error("no file to mount");
  106. user = getuser();
  107. if(user == nil)
  108. user = "dmr";
  109. ram = r = (Ram *)emalloc(sizeof(Ram));
  110. r->busy = 1;
  111. r->data = 0;
  112. r->ndata = 0;
  113. r->perm = DMDIR | 0775;
  114. r->qid.path = 0;
  115. r->qid.vers = 0;
  116. r->qid.type = QTDIR;
  117. r->parent = 0;
  118. r->child = 0;
  119. r->next = 0;
  120. r->user = user;
  121. r->group = user;
  122. r->atime = time(0);
  123. r->mtime = r->atime;
  124. r->replete = 0;
  125. r->name = estrdup(".");
  126. populate(argv[0]);
  127. r->replete |= replete;
  128. if(pipe(p) < 0)
  129. error("pipe failed");
  130. mfd[0] = mfd[1] = p[0];
  131. notify(notifyf);
  132. switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
  133. case -1:
  134. error("fork");
  135. case 0:
  136. close(p[1]);
  137. notify(notifyf);
  138. io();
  139. break;
  140. default:
  141. close(p[0]); /* don't deadlock if child fails */
  142. if(mount(p[1], -1, defmnt, MREPL|MCREATE, "") < 0) {
  143. sprint(buf, "mount on `%s' failed", defmnt);
  144. error(buf);
  145. }
  146. }
  147. exits(0);
  148. }
  149. char*
  150. rversion(Fid *unused)
  151. {
  152. Fid *f;
  153. USED(unused);
  154. if(rhdr.msize < 256)
  155. return "version: message too small";
  156. if(rhdr.msize > messagesize)
  157. rhdr.msize = messagesize;
  158. else
  159. messagesize = rhdr.msize;
  160. thdr.msize = messagesize;
  161. if(strncmp(rhdr.version, "9P2000", 6) != 0)
  162. return "unrecognized 9P version";
  163. thdr.version = "9P2000";
  164. for(f = fids; f; f = f->next)
  165. if(f->busy)
  166. rclunk(f);
  167. return 0;
  168. }
  169. char*
  170. rauth(Fid *unused)
  171. {
  172. USED(unused);
  173. return Enoauth;
  174. }
  175. char*
  176. rflush(Fid *f)
  177. {
  178. USED(f);
  179. return 0;
  180. }
  181. char*
  182. rattach(Fid *f)
  183. {
  184. /* no authentication! */
  185. f->busy = 1;
  186. f->rclose = 0;
  187. f->ram = ram;
  188. thdr.qid = f->ram->qid;
  189. if(rhdr.uname[0])
  190. f->user = strdup(rhdr.uname);
  191. else
  192. f->user = "none";
  193. return 0;
  194. }
  195. char*
  196. rwalk(Fid *f)
  197. {
  198. Fid *nf;
  199. Ram *r;
  200. char *err;
  201. char *name;
  202. Ram *dir;
  203. int i;
  204. nf = nil;
  205. if(f->ram->busy == 0)
  206. return Enotexist;
  207. if(f->open)
  208. return Eisopen;
  209. if(rhdr.newfid != rhdr.fid){
  210. nf = newfid(rhdr.newfid);
  211. nf->busy = 1;
  212. nf->open = 0;
  213. nf->rclose = 0;
  214. nf->ram = f->ram;
  215. nf->user = f->user; /* no ref count; the leakage is minor */
  216. f = nf;
  217. }
  218. thdr.nwqid = 0;
  219. err = nil;
  220. r = f->ram;
  221. if(rhdr.nwname > 0){
  222. for(i=0; i<rhdr.nwname; i++){
  223. if((r->qid.type & QTDIR) == 0){
  224. err = Enotdir;
  225. break;
  226. }
  227. if(r->busy == 0){
  228. err = Enotexist;
  229. break;
  230. }
  231. r->atime = time(0);
  232. name = rhdr.wname[i];
  233. dir = r;
  234. if(!perm(Pexec)){
  235. err = Eperm;
  236. break;
  237. }
  238. if(strcmp(name, "..") == 0){
  239. r = dir->parent;
  240. Accept:
  241. if(i == MAXWELEM){
  242. err = "name too long";
  243. break;
  244. }
  245. thdr.wqid[thdr.nwqid++] = r->qid;
  246. continue;
  247. }
  248. if(!dir->replete)
  249. popdir(dir);
  250. for(r=dir->child; r; r=r->next)
  251. if(r->busy && strcmp(name, r->name)==0)
  252. goto Accept;
  253. break; /* file not found */
  254. }
  255. if(i==0 && err == nil)
  256. err = Enotexist;
  257. }
  258. if(err!=nil || thdr.nwqid<rhdr.nwname){
  259. if(nf){
  260. nf->busy = 0;
  261. nf->open = 0;
  262. nf->ram = 0;
  263. }
  264. }else if(thdr.nwqid == rhdr.nwname)
  265. f->ram = r;
  266. return err;
  267. }
  268. char *
  269. ropen(Fid *f)
  270. {
  271. Ram *r;
  272. int mode, trunc;
  273. if(f->open)
  274. return Eisopen;
  275. r = f->ram;
  276. if(r->busy == 0)
  277. return Enotexist;
  278. if(r->perm & DMEXCL)
  279. if(r->open)
  280. return Excl;
  281. mode = rhdr.mode;
  282. if(r->qid.type & QTDIR){
  283. if(mode != OREAD)
  284. return Eperm;
  285. thdr.qid = r->qid;
  286. return 0;
  287. }
  288. if(mode & ORCLOSE)
  289. return Eperm;
  290. trunc = mode & OTRUNC;
  291. mode &= OPERM;
  292. if(mode==OWRITE || mode==ORDWR || trunc)
  293. if(!perm(Pwrite))
  294. return Eperm;
  295. if(mode==OREAD || mode==ORDWR)
  296. if(!perm(Pread))
  297. return Eperm;
  298. if(mode==OEXEC)
  299. if(!perm(Pexec))
  300. return Eperm;
  301. if(trunc && (r->perm&DMAPPEND)==0){
  302. r->ndata = 0;
  303. dotrunc(r);
  304. r->qid.vers++;
  305. }
  306. thdr.qid = r->qid;
  307. thdr.iounit = messagesize-IOHDRSZ;
  308. f->open = 1;
  309. r->open++;
  310. return 0;
  311. }
  312. char *
  313. rcreate(Fid *f)
  314. {
  315. USED(f);
  316. return Eperm;
  317. }
  318. char*
  319. rread(Fid *f)
  320. {
  321. int i, len;
  322. Ram *r;
  323. char *buf;
  324. uint64_t off, end;
  325. int n, cnt;
  326. if(f->ram->busy == 0)
  327. return Enotexist;
  328. n = 0;
  329. thdr.count = 0;
  330. off = rhdr.offset;
  331. end = rhdr.offset + rhdr.count;
  332. cnt = rhdr.count;
  333. if(cnt > messagesize-IOHDRSZ)
  334. cnt = messagesize-IOHDRSZ;
  335. buf = thdr.data;
  336. if(f->ram->qid.type & QTDIR){
  337. if(!f->ram->replete)
  338. popdir(f->ram);
  339. for(i=0,r=f->ram->child; r!=nil && i<end; r=r->next){
  340. if(!r->busy)
  341. continue;
  342. len = ramstat(r, (uint8_t*)buf+n, cnt-n);
  343. if(len <= BIT16SZ)
  344. break;
  345. if(i >= off)
  346. n += len;
  347. i += len;
  348. }
  349. thdr.count = n;
  350. return 0;
  351. }
  352. r = f->ram;
  353. if(off >= r->ndata)
  354. return 0;
  355. r->atime = time(0);
  356. n = cnt;
  357. if(off+n > r->ndata)
  358. n = r->ndata - off;
  359. thdr.data = doread(r, off, n);
  360. thdr.count = n;
  361. return 0;
  362. }
  363. char*
  364. rwrite(Fid *f)
  365. {
  366. Ram *r;
  367. uint32_t off;
  368. int cnt;
  369. r = f->ram;
  370. if(dopermw(f->ram)==0)
  371. return Eperm;
  372. if(r->busy == 0)
  373. return Enotexist;
  374. off = rhdr.offset;
  375. if(r->perm & DMAPPEND)
  376. off = r->ndata;
  377. cnt = rhdr.count;
  378. if(r->qid.type & QTDIR)
  379. return "file is a directory";
  380. if(off > 100*1024*1024) /* sanity check */
  381. return "write too big";
  382. dowrite(r, rhdr.data, off, cnt);
  383. r->qid.vers++;
  384. r->mtime = time(0);
  385. thdr.count = cnt;
  386. return 0;
  387. }
  388. char *
  389. rclunk(Fid *f)
  390. {
  391. if(f->open)
  392. f->ram->open--;
  393. f->busy = 0;
  394. f->open = 0;
  395. f->ram = 0;
  396. return 0;
  397. }
  398. char *
  399. rremove(Fid *f)
  400. {
  401. USED(f);
  402. return Eperm;
  403. }
  404. char *
  405. rstat(Fid *f)
  406. {
  407. if(f->ram->busy == 0)
  408. return Enotexist;
  409. thdr.nstat = ramstat(f->ram, thdr.stat, messagesize-IOHDRSZ);
  410. return 0;
  411. }
  412. char *
  413. rwstat(Fid *f)
  414. {
  415. if(f->ram->busy == 0)
  416. return Enotexist;
  417. return Eperm;
  418. }
  419. int
  420. ramstat(Ram *r, uint8_t *buf, int nbuf)
  421. {
  422. Dir dir;
  423. dir.name = r->name;
  424. dir.qid = r->qid;
  425. dir.mode = r->perm;
  426. dir.length = r->ndata;
  427. dir.uid = r->user;
  428. dir.gid = r->group;
  429. dir.muid = r->user;
  430. dir.atime = r->atime;
  431. dir.mtime = r->mtime;
  432. return convD2M(&dir, buf, nbuf);
  433. }
  434. Fid *
  435. newfid(int fid)
  436. {
  437. Fid *f, *ff;
  438. ff = 0;
  439. for(f = fids; f; f = f->next)
  440. if(f->fid == fid)
  441. return f;
  442. else if(!ff && !f->busy)
  443. ff = f;
  444. if(ff){
  445. ff->fid = fid;
  446. ff->open = 0;
  447. ff->busy = 1;
  448. }
  449. f = emalloc(sizeof *f);
  450. f->ram = 0;
  451. f->fid = fid;
  452. f->busy = 1;
  453. f->open = 0;
  454. f->next = fids;
  455. fids = f;
  456. return f;
  457. }
  458. void
  459. io(void)
  460. {
  461. char *err;
  462. int n, nerr;
  463. char buf[ERRMAX];
  464. errstr(buf, sizeof buf);
  465. for(nerr=0, buf[0]='\0'; nerr<100; nerr++){
  466. /*
  467. * reading from a pipe or a network device
  468. * will give an error after a few eof reads
  469. * however, we cannot tell the difference
  470. * between a zero-length read and an interrupt
  471. * on the processes writing to us,
  472. * so we wait for the error
  473. */
  474. n = read9pmsg(mfd[0], mdata, sizeof mdata);
  475. if(n==0)
  476. continue;
  477. if(n < 0){
  478. if(buf[0]=='\0')
  479. errstr(buf, sizeof buf);
  480. continue;
  481. }
  482. nerr = 0;
  483. buf[0] = '\0';
  484. if(convM2S(mdata, n, &rhdr) != n)
  485. error("convert error in convM2S");
  486. if(verbose)
  487. fprint(2, "tapefs: <=%F\n", &rhdr);/**/
  488. thdr.data = (char*)mdata + IOHDRSZ;
  489. thdr.stat = mdata + IOHDRSZ;
  490. if(!fcalls[rhdr.type])
  491. err = "bad fcall type";
  492. else
  493. err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
  494. if(err){
  495. thdr.type = Rerror;
  496. thdr.ename = err;
  497. }else{
  498. thdr.type = rhdr.type + 1;
  499. thdr.fid = rhdr.fid;
  500. }
  501. thdr.tag = rhdr.tag;
  502. n = convS2M(&thdr, mdata, messagesize);
  503. if(n <= 0)
  504. error("convert error in convS2M");
  505. if(verbose)
  506. fprint(2, "tapefs: =>%F\n", &thdr);/**/
  507. if(write(mfd[1], mdata, n) != n)
  508. error("mount write");
  509. }
  510. if(buf[0]=='\0' || strstr(buf, "hungup"))
  511. exits("");
  512. fprint(2, "%s: mount read: %s\n", argv0, buf);
  513. exits(buf);
  514. }
  515. int
  516. perm(int p)
  517. {
  518. if(p==Pwrite)
  519. return 0;
  520. return 1;
  521. }
  522. void
  523. error(char *s)
  524. {
  525. fprint(2, "%s: %s: ", argv0, s);
  526. perror("");
  527. exits(s);
  528. }
  529. char*
  530. estrdup(char *s)
  531. {
  532. char *t;
  533. t = emalloc(strlen(s)+1);
  534. strcpy(t, s);
  535. return t;
  536. }
  537. void *
  538. emalloc(uint32_t n)
  539. {
  540. void *p;
  541. p = mallocz(n, 1);
  542. if(!p)
  543. error("out of memory");
  544. return p;
  545. }
  546. void *
  547. erealloc(void *p, uint32_t n)
  548. {
  549. p = realloc(p, n);
  550. if(!p)
  551. error("out of memory");
  552. return p;
  553. }
  554. void
  555. usage(void)
  556. {
  557. fprint(2, "usage: %s [-s] [-m mountpoint]\n", argv0);
  558. exits("usage");
  559. }