fs.c 9.7 KB

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