fs.c 9.5 KB

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