searchfs.c 18 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #include <fcall.h>
  5. /*
  6. * caveat:
  7. * this stuff is only meant to work for ascii databases
  8. */
  9. typedef struct Fid Fid;
  10. typedef struct Fs Fs;
  11. typedef struct Quick Quick;
  12. typedef struct Match Match;
  13. typedef struct Search Search;
  14. enum
  15. {
  16. OPERM = 0x3, /* mask of all permission types in open mode */
  17. Nfidhash = 32,
  18. /*
  19. * qids
  20. */
  21. Qroot = 1,
  22. Qsearch = 2,
  23. Qstats = 3,
  24. };
  25. /*
  26. * boyer-moore quick string matching
  27. */
  28. struct Quick
  29. {
  30. char *pat;
  31. char *up; /* match string for upper case of pat */
  32. int len; /* of pat (and up) -1; used for fast search */
  33. uchar jump[256]; /* jump index table */
  34. int miss; /* amount to jump if we falsely match the last char */
  35. };
  36. extern void quickmk(Quick*, char*, int);
  37. extern void quickfree(Quick*);
  38. extern char* quicksearch(Quick*, char*, char*);
  39. /*
  40. * exact matching of a search string
  41. */
  42. struct Match
  43. {
  44. Match *next;
  45. char *pat; /* null-terminated search string */
  46. char *up; /* upper case of pat */
  47. int len; /* length of both pat and up */
  48. int (*op)(Match*, char*, char*); /* method for this partiticular search */
  49. };
  50. struct Search
  51. {
  52. Quick quick; /* quick match */
  53. Match *match; /* exact matches */
  54. int skip; /* number of matches to skip */
  55. };
  56. extern char* searchsearch(Search*, char*, char*, int*);
  57. extern Search* searchparse(char*, char*);
  58. extern void searchfree(Search*);
  59. struct Fid
  60. {
  61. Lock;
  62. Fid *next;
  63. Fid **last;
  64. uint fid;
  65. int ref; /* number of fcalls using the fid */
  66. int attached; /* fid has beed attached or cloned and not clunked */
  67. int open;
  68. Qid qid;
  69. Search *search; /* search patterns */
  70. char *where; /* current location in the database */
  71. int n; /* number of bytes left in found item */
  72. };
  73. int dostat(int, uchar*, int);
  74. void* emalloc(uint);
  75. void fatal(char*, ...);
  76. Match* mkmatch(Match*, int(*)(Match*, char*, char*), char*);
  77. Match* mkstrmatch(Match*, char*);
  78. char* nextsearch(char*, char*, char**, char**);
  79. int strlook(Match*, char*, char*);
  80. char* strndup(char*, int);
  81. int tolower(int);
  82. int toupper(int);
  83. char* urlunesc(char*, char*);
  84. void usage(void);
  85. struct Fs
  86. {
  87. Lock; /* for fids */
  88. Fid *hash[Nfidhash];
  89. uchar statbuf[1024]; /* plenty big enough */
  90. };
  91. extern void fsrun(Fs*, int);
  92. extern Fid* getfid(Fs*, uint);
  93. extern Fid* mkfid(Fs*, uint);
  94. extern void putfid(Fs*, Fid*);
  95. extern char* fsversion(Fs*, Fcall*);
  96. extern char* fsauth(Fs*, Fcall*);
  97. extern char* fsattach(Fs*, Fcall*);
  98. extern char* fswalk(Fs*, Fcall*);
  99. extern char* fsopen(Fs*, Fcall*);
  100. extern char* fscreate(Fs*, Fcall*);
  101. extern char* fsread(Fs*, Fcall*);
  102. extern char* fswrite(Fs*, Fcall*);
  103. extern char* fsclunk(Fs*, Fcall*);
  104. extern char* fsremove(Fs*, Fcall*);
  105. extern char* fsstat(Fs*, Fcall*);
  106. extern char* fswstat(Fs*, Fcall*);
  107. char *(*fcalls[])(Fs*, Fcall*) =
  108. {
  109. [Tversion] fsversion,
  110. [Tattach] fsattach,
  111. [Tauth] fsauth,
  112. [Twalk] fswalk,
  113. [Topen] fsopen,
  114. [Tcreate] fscreate,
  115. [Tread] fsread,
  116. [Twrite] fswrite,
  117. [Tclunk] fsclunk,
  118. [Tremove] fsremove,
  119. [Tstat] fsstat,
  120. [Twstat] fswstat
  121. };
  122. char Eperm[] = "permission denied";
  123. char Enotdir[] = "not a directory";
  124. char Enotexist[] = "file does not exist";
  125. char Eisopen[] = "file already open for I/O";
  126. char Einuse[] = "fid is already in use";
  127. char Enofid[] = "no such fid";
  128. char Enotopen[] = "file is not open";
  129. char Ebadsearch[] = "bad search string";
  130. Fs fs;
  131. char *database;
  132. char *edatabase;
  133. int messagesize = 8192+IOHDRSZ;
  134. void
  135. main(int argc, char **argv)
  136. {
  137. Dir *d;
  138. char buf[12], *mnt, *srv;
  139. int fd, p[2], n;
  140. mnt = "/tmp";
  141. srv = nil;
  142. ARGBEGIN{
  143. case 's':
  144. srv = ARGF();
  145. mnt = nil;
  146. break;
  147. case 'm':
  148. mnt = ARGF();
  149. break;
  150. }ARGEND
  151. fmtinstall('F', fcallfmt);
  152. if(argc != 1)
  153. usage();
  154. d = nil;
  155. fd = open(argv[0], OREAD);
  156. if(fd < 0 || (d=dirfstat(fd)) == nil)
  157. fatal("can't open %s: %r", argv[0]);
  158. n = d->length;
  159. free(d);
  160. if(n == 0)
  161. fatal("zero length database %s", argv[0]);
  162. database = emalloc(n);
  163. if(read(fd, database, n) != n)
  164. fatal("can't read %s: %r", argv[0]);
  165. close(fd);
  166. edatabase = database + n;
  167. if(pipe(p) < 0)
  168. fatal("pipe failed");
  169. switch(rfork(RFPROC|RFMEM|RFNOTEG|RFNAMEG)){
  170. case 0:
  171. fsrun(&fs, p[0]);
  172. exits(nil);
  173. case -1:
  174. fatal("fork failed");
  175. }
  176. if(mnt == nil){
  177. if(srv == nil)
  178. usage();
  179. fd = create(srv, OWRITE, 0666);
  180. if(fd < 0){
  181. remove(srv);
  182. fd = create(srv, OWRITE, 0666);
  183. if(fd < 0){
  184. close(p[1]);
  185. fatal("create of %s failed", srv);
  186. }
  187. }
  188. sprint(buf, "%d", p[1]);
  189. if(write(fd, buf, strlen(buf)) < 0){
  190. close(p[1]);
  191. fatal("writing %s", srv);
  192. }
  193. close(p[1]);
  194. exits(nil);
  195. }
  196. if(mount(p[1], -1, mnt, MREPL, "") < 0){
  197. close(p[1]);
  198. fatal("mount failed");
  199. }
  200. close(p[1]);
  201. exits(nil);
  202. }
  203. /*
  204. * execute the search
  205. * do a quick match,
  206. * isolate the line in which the occured,
  207. * and try all of the exact matches
  208. */
  209. char*
  210. searchsearch(Search *search, char *where, char *end, int *np)
  211. {
  212. Match *m;
  213. char *s, *e;
  214. *np = 0;
  215. if(search == nil || where == nil)
  216. return nil;
  217. for(;;){
  218. s = quicksearch(&search->quick, where, end);
  219. if(s == nil)
  220. return nil;
  221. e = memchr(s, '\n', end - s);
  222. if(e == nil)
  223. e = end;
  224. else
  225. e++;
  226. while(s > where && s[-1] != '\n')
  227. s--;
  228. for(m = search->match; m != nil; m = m->next){
  229. if((*m->op)(m, s, e) == 0)
  230. break;
  231. }
  232. if(m == nil){
  233. if(search->skip > 0)
  234. search->skip--;
  235. else{
  236. *np = e - s;
  237. return s;
  238. }
  239. }
  240. where = e;
  241. }
  242. }
  243. /*
  244. * parse a search string of the form
  245. * tag=val&tag1=val1...
  246. */
  247. Search*
  248. searchparse(char *search, char *esearch)
  249. {
  250. Search *s;
  251. Match *m, *next, **last;
  252. char *tag, *val, *p;
  253. int ok;
  254. s = emalloc(sizeof *s);
  255. s->match = nil;
  256. /*
  257. * acording to the http spec,
  258. * repeated search queries are ingored.
  259. * the last search given is performed on the original object
  260. */
  261. while((p = memchr(s, '?', esearch - search)) != nil){
  262. search = p + 1;
  263. }
  264. while(search < esearch){
  265. search = nextsearch(search, esearch, &tag, &val);
  266. if(tag == nil)
  267. continue;
  268. ok = 0;
  269. if(strcmp(tag, "skip") == 0){
  270. s->skip = strtoul(val, &p, 10);
  271. if(*p == 0)
  272. ok = 1;
  273. }else if(strcmp(tag, "search") == 0){
  274. s->match = mkstrmatch(s->match, val);
  275. ok = 1;
  276. }
  277. free(tag);
  278. free(val);
  279. if(!ok){
  280. searchfree(s);
  281. return nil;
  282. }
  283. }
  284. if(s->match == nil){
  285. free(s);
  286. return nil;
  287. }
  288. /*
  289. * order the matches by probability of occurance
  290. * first cut is just by length
  291. */
  292. for(ok = 0; !ok; ){
  293. ok = 1;
  294. last = &s->match;
  295. for(m = *last; m && m->next; m = *last){
  296. if(m->next->len > m->len){
  297. next = m->next;
  298. m->next = next->next;
  299. next->next = m;
  300. *last = next;
  301. ok = 0;
  302. }
  303. last = &m->next;
  304. }
  305. }
  306. /*
  307. * convert the best search into a fast lookup
  308. */
  309. m = s->match;
  310. s->match = m->next;
  311. quickmk(&s->quick, m->pat, 1);
  312. free(m->pat);
  313. free(m->up);
  314. free(m);
  315. return s;
  316. }
  317. void
  318. searchfree(Search *s)
  319. {
  320. Match *m, *next;
  321. if(s == nil)
  322. return;
  323. for(m = s->match; m; m = next){
  324. next = m->next;
  325. free(m->pat);
  326. free(m->up);
  327. free(m);
  328. }
  329. quickfree(&s->quick);
  330. free(s);
  331. }
  332. char*
  333. nextsearch(char *search, char *esearch, char **tagp, char **valp)
  334. {
  335. char *tag, *val;
  336. *tagp = nil;
  337. *valp = nil;
  338. for(tag = search; search < esearch && *search != '='; search++)
  339. ;
  340. if(search == esearch)
  341. return search;
  342. tag = urlunesc(tag, search);
  343. search++;
  344. for(val = search; search < esearch && *search != '&'; search++)
  345. ;
  346. val = urlunesc(val, search);
  347. if(search != esearch)
  348. search++;
  349. *tagp = tag;
  350. *valp = val;
  351. return search;
  352. }
  353. Match*
  354. mkstrmatch(Match *m, char *pat)
  355. {
  356. char *s;
  357. for(s = pat; *s; s++){
  358. if(*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r'){
  359. *s = 0;
  360. m = mkmatch(m, strlook, pat);
  361. pat = s + 1;
  362. }else
  363. *s = tolower(*s);
  364. }
  365. return mkmatch(m, strlook, pat);
  366. }
  367. Match*
  368. mkmatch(Match *next, int (*op)(Match*, char*, char*), char *pat)
  369. {
  370. Match *m;
  371. char *p;
  372. int n;
  373. n = strlen(pat);
  374. if(n == 0)
  375. return next;
  376. m = emalloc(sizeof *m);
  377. m->op = op;
  378. m->len = n;
  379. m->pat = strdup(pat);
  380. m->up = strdup(pat);
  381. for(p = m->up; *p; p++)
  382. *p = toupper(*p);
  383. for(p = m->pat; *p; p++)
  384. *p = tolower(*p);
  385. m->next = next;
  386. return m;
  387. }
  388. int
  389. strlook(Match *m, char *str, char *e)
  390. {
  391. char *pat, *up, *s;
  392. int c, pc, fc, fuc, n;
  393. n = m->len;
  394. fc = m->pat[0];
  395. fuc = m->up[0];
  396. for(; str + n <= e; str++){
  397. c = *str;
  398. if(c != fc && c != fuc)
  399. continue;
  400. s = str + 1;
  401. up = m->up + 1;
  402. for(pat = m->pat + 1; pc = *pat; pat++){
  403. c = *s;
  404. if(c != pc && c != *up)
  405. break;
  406. up++;
  407. s++;
  408. }
  409. if(pc == 0)
  410. return 1;
  411. }
  412. return 0;
  413. }
  414. /*
  415. * boyer-moore style pattern matching
  416. * implements an exact match for ascii
  417. * however, if mulitbyte upper-case and lower-case
  418. * characters differ in length or in more than one byte,
  419. * it only implements an approximate match
  420. */
  421. void
  422. quickmk(Quick *q, char *spat, int ignorecase)
  423. {
  424. char *pat, *up;
  425. uchar *j;
  426. int ep, ea, cp, ca, i, c, n;
  427. /*
  428. * allocate the machine
  429. */
  430. n = strlen(spat);
  431. if(n == 0){
  432. q->pat = nil;
  433. q->up = nil;
  434. q->len = -1;
  435. return;
  436. }
  437. pat = emalloc(2* n + 2);
  438. q->pat = pat;
  439. up = pat;
  440. if(ignorecase)
  441. up = pat + n + 1;
  442. q->up = up;
  443. while(c = *spat++){
  444. if(ignorecase){
  445. *up++ = toupper(c);
  446. c = tolower(c);
  447. }
  448. *pat++ = c;
  449. }
  450. pat = q->pat;
  451. up = q->up;
  452. pat[n] = up[n] = '\0';
  453. /*
  454. * make the skipping table
  455. */
  456. if(n > 255)
  457. n = 255;
  458. j = q->jump;
  459. memset(j, n, 256);
  460. n--;
  461. q->len = n;
  462. for(i = 0; i <= n; i++){
  463. j[(uchar)pat[i]] = n - i;
  464. j[(uchar)up[i]] = n - i;
  465. }
  466. /*
  467. * find the minimum safe amount to skip
  468. * if we match the last char but not the whole pat
  469. */
  470. ep = pat[n];
  471. ea = up[n];
  472. for(i = n - 1; i >= 0; i--){
  473. cp = pat[i];
  474. ca = up[i];
  475. if(cp == ep || cp == ea || ca == ep || ca == ea)
  476. break;
  477. }
  478. q->miss = n - i;
  479. }
  480. void
  481. quickfree(Quick *q)
  482. {
  483. if(q->pat != nil)
  484. free(q->pat);
  485. q->pat = nil;
  486. }
  487. char *
  488. quicksearch(Quick *q, char *s, char *e)
  489. {
  490. char *pat, *up, *m, *ee;
  491. uchar *j;
  492. int len, n, c, mc;
  493. len = q->len;
  494. if(len < 0)
  495. return s;
  496. j = q->jump;
  497. pat = q->pat;
  498. up = q->up;
  499. s += len;
  500. ee = e - (len * 4 + 4);
  501. while(s < e){
  502. /*
  503. * look for a match on the last char
  504. */
  505. while(s < ee && (n = j[(uchar)*s])){
  506. s += n;
  507. s += j[(uchar)*s];
  508. s += j[(uchar)*s];
  509. s += j[(uchar)*s];
  510. }
  511. if(s >= e)
  512. return nil;
  513. while(n = j[(uchar)*s]){
  514. s += n;
  515. if(s >= e)
  516. return nil;
  517. }
  518. /*
  519. * does the string match?
  520. */
  521. m = s - len;
  522. for(n = 0; c = pat[n]; n++){
  523. mc = *m++;
  524. if(c != mc && mc != up[n])
  525. break;
  526. }
  527. if(!c)
  528. return s - len;
  529. s += q->miss;
  530. }
  531. return nil;
  532. }
  533. void
  534. fsrun(Fs *fs, int fd)
  535. {
  536. Fcall rpc;
  537. char *err;
  538. uchar *buf;
  539. int n;
  540. buf = emalloc(messagesize);
  541. for(;;){
  542. /*
  543. * reading from a pipe or a network device
  544. * will give an error after a few eof reads
  545. * however, we cannot tell the difference
  546. * between a zero-length read and an interrupt
  547. * on the processes writing to us,
  548. * so we wait for the error
  549. */
  550. n = read9pmsg(fd, buf, messagesize);
  551. if(n == 0)
  552. continue;
  553. if(n < 0)
  554. fatal("mount read");
  555. rpc.data = (char*)buf + IOHDRSZ;
  556. if(convM2S(buf, n, &rpc) == 0)
  557. continue;
  558. // fprint(2, "recv: %F\n", &rpc);
  559. /*
  560. * flushes are way too hard.
  561. * a reply to the original message seems to work
  562. */
  563. if(rpc.type == Tflush)
  564. continue;
  565. else if(rpc.type >= Tmax || !fcalls[rpc.type])
  566. err = "bad fcall type";
  567. else
  568. err = (*fcalls[rpc.type])(fs, &rpc);
  569. if(err){
  570. rpc.type = Rerror;
  571. rpc.ename = err;
  572. }else
  573. rpc.type++;
  574. n = convS2M(&rpc, buf, messagesize);
  575. // fprint(2, "send: %F\n", &rpc);
  576. if(write(fd, buf, n) != n)
  577. fatal("mount write");
  578. }
  579. }
  580. Fid*
  581. mkfid(Fs *fs, uint fid)
  582. {
  583. Fid *f;
  584. int h;
  585. h = fid % Nfidhash;
  586. for(f = fs->hash[h]; f; f = f->next){
  587. if(f->fid == fid)
  588. return nil;
  589. }
  590. f = emalloc(sizeof *f);
  591. f->next = fs->hash[h];
  592. if(f->next != nil)
  593. f->next->last = &f->next;
  594. f->last = &fs->hash[h];
  595. fs->hash[h] = f;
  596. f->fid = fid;
  597. f->ref = 1;
  598. f->attached = 1;
  599. f->open = 0;
  600. return f;
  601. }
  602. Fid*
  603. getfid(Fs *fs, uint fid)
  604. {
  605. Fid *f;
  606. int h;
  607. h = fid % Nfidhash;
  608. for(f = fs->hash[h]; f; f = f->next){
  609. if(f->fid == fid){
  610. if(f->attached == 0)
  611. break;
  612. f->ref++;
  613. return f;
  614. }
  615. }
  616. return nil;
  617. }
  618. void
  619. putfid(Fs *, Fid *f)
  620. {
  621. f->ref--;
  622. if(f->ref == 0 && f->attached == 0){
  623. *f->last = f->next;
  624. if(f->next != nil)
  625. f->next->last = f->last;
  626. if(f->search != nil)
  627. searchfree(f->search);
  628. free(f);
  629. }
  630. }
  631. char*
  632. fsversion(Fs *, Fcall *rpc)
  633. {
  634. if(rpc->msize < 256)
  635. return "version: message size too small";
  636. if(rpc->msize > messagesize)
  637. rpc->msize = messagesize;
  638. messagesize = rpc->msize;
  639. if(strncmp(rpc->version, "9P2000", 6) != 0)
  640. return "unrecognized 9P version";
  641. rpc->version = "9P2000";
  642. return nil;
  643. }
  644. char*
  645. fsauth(Fs *, Fcall *)
  646. {
  647. return "searchfs: authentication not required";
  648. }
  649. char*
  650. fsattach(Fs *fs, Fcall *rpc)
  651. {
  652. Fid *f;
  653. f = mkfid(fs, rpc->fid);
  654. if(f == nil)
  655. return Einuse;
  656. f->open = 0;
  657. f->qid.type = QTDIR;
  658. f->qid.path = Qroot;
  659. f->qid.vers = 0;
  660. rpc->qid = f->qid;
  661. putfid(fs, f);
  662. return nil;
  663. }
  664. char*
  665. fswalk(Fs *fs, Fcall *rpc)
  666. {
  667. Fid *f, *nf;
  668. int nqid, nwname, type;
  669. char *err, *name;
  670. ulong path;
  671. f = getfid(fs, rpc->fid);
  672. if(f == nil)
  673. return Enofid;
  674. nf = nil;
  675. if(rpc->fid != rpc->newfid){
  676. nf = mkfid(fs, rpc->newfid);
  677. if(nf == nil){
  678. putfid(fs, f);
  679. return Einuse;
  680. }
  681. nf->qid = f->qid;
  682. putfid(fs, f);
  683. f = nf; /* walk f */
  684. }
  685. err = nil;
  686. path = f->qid.path;
  687. nwname = rpc->nwname;
  688. for(nqid=0; nqid<nwname; nqid++){
  689. if(path != Qroot){
  690. err = Enotdir;
  691. break;
  692. }
  693. name = rpc->wname[nqid];
  694. if(strcmp(name, "search") == 0){
  695. type = QTFILE;
  696. path = Qsearch;
  697. }else if(strcmp(name, "stats") == 0){
  698. type = QTFILE;
  699. path = Qstats;
  700. }else if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0){
  701. type = QTDIR;
  702. path = path;
  703. }else{
  704. err = Enotexist;
  705. break;
  706. }
  707. rpc->wqid[nqid] = (Qid){path, 0, type};
  708. }
  709. if(nwname > 0){
  710. if(nf != nil && nqid < nwname)
  711. nf->attached = 0;
  712. if(nqid == nwname)
  713. f->qid = rpc->wqid[nqid-1];
  714. }
  715. putfid(fs, f);
  716. rpc->nwqid = nqid;
  717. f->open = 0;
  718. return err;
  719. }
  720. char *
  721. fsopen(Fs *fs, Fcall *rpc)
  722. {
  723. Fid *f;
  724. int mode;
  725. f = getfid(fs, rpc->fid);
  726. if(f == nil)
  727. return Enofid;
  728. if(f->open){
  729. putfid(fs, f);
  730. return Eisopen;
  731. }
  732. mode = rpc->mode & OPERM;
  733. if(mode == OEXEC
  734. || f->qid.path == Qroot && (mode == OWRITE || mode == ORDWR)){
  735. putfid(fs, f);
  736. return Eperm;
  737. }
  738. f->open = 1;
  739. f->where = nil;
  740. f->n = 0;
  741. f->search = nil;
  742. rpc->qid = f->qid;
  743. rpc->iounit = messagesize-IOHDRSZ;
  744. putfid(fs, f);
  745. return nil;
  746. }
  747. char *
  748. fscreate(Fs *, Fcall *)
  749. {
  750. return Eperm;
  751. }
  752. char*
  753. fsread(Fs *fs, Fcall *rpc)
  754. {
  755. Fid *f;
  756. int n, off, count, len;
  757. f = getfid(fs, rpc->fid);
  758. if(f == nil)
  759. return Enofid;
  760. if(!f->open){
  761. putfid(fs, f);
  762. return Enotopen;
  763. }
  764. count = rpc->count;
  765. off = rpc->offset;
  766. rpc->count = 0;
  767. if(f->qid.path == Qroot){
  768. if(off > 0)
  769. rpc->count = 0;
  770. else
  771. rpc->count = dostat(Qsearch, (uchar*)rpc->data, count);
  772. putfid(fs, f);
  773. if(off == 0 && rpc->count <= BIT16SZ)
  774. return "directory read count too small";
  775. return nil;
  776. }
  777. if(f->qid.path == Qstats){
  778. len = 0;
  779. }else{
  780. for(len = 0; len < count; len += n){
  781. if(f->where == nil || f->search == nil)
  782. break;
  783. if(f->n == 0)
  784. f->where = searchsearch(f->search, f->where, edatabase, &f->n);
  785. n = f->n;
  786. if(n != 0){
  787. if(n > count-len)
  788. n = count-len;
  789. memmove(rpc->data+len, f->where, n);
  790. f->where += n;
  791. f->n -= n;
  792. }
  793. }
  794. }
  795. putfid(fs, f);
  796. rpc->count = len;
  797. return nil;
  798. }
  799. char*
  800. fswrite(Fs *fs, Fcall *rpc)
  801. {
  802. Fid *f;
  803. f = getfid(fs, rpc->fid);
  804. if(f == nil)
  805. return Enofid;
  806. if(!f->open || f->qid.path != Qsearch){
  807. putfid(fs, f);
  808. return Enotopen;
  809. }
  810. if(f->search != nil)
  811. searchfree(f->search);
  812. f->search = searchparse(rpc->data, rpc->data + rpc->count);
  813. if(f->search == nil){
  814. putfid(fs, f);
  815. return Ebadsearch;
  816. }
  817. f->where = database;
  818. f->n = 0;
  819. putfid(fs, f);
  820. return nil;
  821. }
  822. char *
  823. fsclunk(Fs *fs, Fcall *rpc)
  824. {
  825. Fid *f;
  826. f = getfid(fs, rpc->fid);
  827. if(f != nil){
  828. f->attached = 0;
  829. putfid(fs, f);
  830. }
  831. return nil;
  832. }
  833. char *
  834. fsremove(Fs *, Fcall *)
  835. {
  836. return Eperm;
  837. }
  838. char *
  839. fsstat(Fs *fs, Fcall *rpc)
  840. {
  841. Fid *f;
  842. f = getfid(fs, rpc->fid);
  843. if(f == nil)
  844. return Enofid;
  845. rpc->stat = fs->statbuf;
  846. rpc->nstat = dostat(f->qid.path, rpc->stat, sizeof fs->statbuf);
  847. putfid(fs, f);
  848. if(rpc->nstat <= BIT16SZ)
  849. return "stat count too small";
  850. return nil;
  851. }
  852. char *
  853. fswstat(Fs *, Fcall *)
  854. {
  855. return Eperm;
  856. }
  857. int
  858. dostat(int path, uchar *buf, int nbuf)
  859. {
  860. Dir d;
  861. switch(path){
  862. case Qroot:
  863. d.name = ".";
  864. d.mode = DMDIR|0555;
  865. d.qid.type = QTDIR;
  866. break;
  867. case Qsearch:
  868. d.name = "search";
  869. d.mode = 0666;
  870. d.qid.type = QTFILE;
  871. break;
  872. case Qstats:
  873. d.name = "stats";
  874. d.mode = 0666;
  875. d.qid.type = QTFILE;
  876. break;
  877. }
  878. d.qid.path = path;
  879. d.qid.vers = 0;
  880. d.length = 0;
  881. d.uid = d.gid = d.muid = "none";
  882. d.atime = d.mtime = time(nil);
  883. return convD2M(&d, buf, nbuf);
  884. }
  885. char *
  886. urlunesc(char *s, char *e)
  887. {
  888. char *t, *v;
  889. int c, n;
  890. v = emalloc((e - s) + 1);
  891. for(t = v; s < e; s++){
  892. c = *s;
  893. if(c == '%'){
  894. if(s + 2 >= e)
  895. break;
  896. n = s[1];
  897. if(n >= '0' && n <= '9')
  898. n = n - '0';
  899. else if(n >= 'A' && n <= 'F')
  900. n = n - 'A' + 10;
  901. else if(n >= 'a' && n <= 'f')
  902. n = n - 'a' + 10;
  903. else
  904. break;
  905. c = n;
  906. n = s[2];
  907. if(n >= '0' && n <= '9')
  908. n = n - '0';
  909. else if(n >= 'A' && n <= 'F')
  910. n = n - 'A' + 10;
  911. else if(n >= 'a' && n <= 'f')
  912. n = n - 'a' + 10;
  913. else
  914. break;
  915. s += 2;
  916. c = c * 16 + n;
  917. }
  918. *t++ = c;
  919. }
  920. *t = 0;
  921. return v;
  922. }
  923. int
  924. toupper(int c)
  925. {
  926. if(c >= 'a' && c <= 'z')
  927. c += 'A' - 'a';
  928. return c;
  929. }
  930. int
  931. tolower(int c)
  932. {
  933. if(c >= 'A' && c <= 'Z')
  934. c += 'a' - 'A';
  935. return c;
  936. }
  937. void
  938. fatal(char *fmt, ...)
  939. {
  940. va_list arg;
  941. char buf[1024];
  942. write(2, "searchfs: ", 8);
  943. va_start(arg, fmt);
  944. vseprint(buf, buf+1024, fmt, arg);
  945. va_end(arg);
  946. write(2, buf, strlen(buf));
  947. write(2, "\n", 1);
  948. exits(fmt);
  949. }
  950. void *
  951. emalloc(uint n)
  952. {
  953. void *p;
  954. p = malloc(n);
  955. if(p == nil)
  956. fatal("out of memory");
  957. memset(p, 0, n);
  958. return p;
  959. }
  960. void
  961. usage(void)
  962. {
  963. fprint(2, "usage: searchfs [-m mountpoint] [-s srvfile] database\n");
  964. exits("usage");
  965. }