searchfs.c 18 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064
  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. return nil;
  243. }
  244. /*
  245. * parse a search string of the form
  246. * tag=val&tag1=val1...
  247. */
  248. Search*
  249. searchparse(char *search, char *esearch)
  250. {
  251. Search *s;
  252. Match *m, *next, **last;
  253. char *tag, *val, *p;
  254. int ok;
  255. s = emalloc(sizeof *s);
  256. s->match = nil;
  257. /*
  258. * acording to the http spec,
  259. * repeated search queries are ingored.
  260. * the last search given is performed on the original object
  261. */
  262. while((p = memchr(s, '?', esearch - search)) != nil){
  263. search = p + 1;
  264. }
  265. while(search < esearch){
  266. search = nextsearch(search, esearch, &tag, &val);
  267. if(tag == nil)
  268. continue;
  269. ok = 0;
  270. if(strcmp(tag, "skip") == 0){
  271. s->skip = strtoul(val, &p, 10);
  272. if(*p == 0)
  273. ok = 1;
  274. }else if(strcmp(tag, "search") == 0){
  275. s->match = mkstrmatch(s->match, val);
  276. ok = 1;
  277. }
  278. free(tag);
  279. free(val);
  280. if(!ok){
  281. searchfree(s);
  282. return nil;
  283. }
  284. }
  285. if(s->match == nil){
  286. free(s);
  287. return nil;
  288. }
  289. /*
  290. * order the matches by probability of occurance
  291. * first cut is just by length
  292. */
  293. for(ok = 0; !ok; ){
  294. ok = 1;
  295. last = &s->match;
  296. for(m = *last; m && m->next; m = *last){
  297. if(m->next->len > m->len){
  298. next = m->next;
  299. m->next = next->next;
  300. next->next = m;
  301. *last = next;
  302. ok = 0;
  303. }
  304. last = &m->next;
  305. }
  306. }
  307. /*
  308. * convert the best search into a fast lookup
  309. */
  310. m = s->match;
  311. s->match = m->next;
  312. quickmk(&s->quick, m->pat, 1);
  313. free(m->pat);
  314. free(m->up);
  315. free(m);
  316. return s;
  317. }
  318. void
  319. searchfree(Search *s)
  320. {
  321. Match *m, *next;
  322. if(s == nil)
  323. return;
  324. for(m = s->match; m; m = next){
  325. next = m->next;
  326. free(m->pat);
  327. free(m->up);
  328. free(m);
  329. }
  330. quickfree(&s->quick);
  331. free(s);
  332. }
  333. char*
  334. nextsearch(char *search, char *esearch, char **tagp, char **valp)
  335. {
  336. char *tag, *val;
  337. *tagp = nil;
  338. *valp = nil;
  339. for(tag = search; search < esearch && *search != '='; search++)
  340. ;
  341. if(search == esearch)
  342. return search;
  343. tag = urlunesc(tag, search);
  344. search++;
  345. for(val = search; search < esearch && *search != '&'; search++)
  346. ;
  347. val = urlunesc(val, search);
  348. if(search != esearch)
  349. search++;
  350. *tagp = tag;
  351. *valp = val;
  352. return search;
  353. }
  354. Match*
  355. mkstrmatch(Match *m, char *pat)
  356. {
  357. char *s;
  358. for(s = pat; *s; s++){
  359. if(*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r'){
  360. *s = 0;
  361. m = mkmatch(m, strlook, pat);
  362. pat = s + 1;
  363. }else
  364. *s = tolower(*s);
  365. }
  366. return mkmatch(m, strlook, pat);
  367. }
  368. Match*
  369. mkmatch(Match *next, int (*op)(Match*, char*, char*), char *pat)
  370. {
  371. Match *m;
  372. char *p;
  373. int n;
  374. n = strlen(pat);
  375. if(n == 0)
  376. return next;
  377. m = emalloc(sizeof *m);
  378. m->op = op;
  379. m->len = n;
  380. m->pat = strdup(pat);
  381. m->up = strdup(pat);
  382. for(p = m->up; *p; p++)
  383. *p = toupper(*p);
  384. for(p = m->pat; *p; p++)
  385. *p = tolower(*p);
  386. m->next = next;
  387. return m;
  388. }
  389. int
  390. strlook(Match *m, char *str, char *e)
  391. {
  392. char *pat, *up, *s;
  393. int c, pc, fc, fuc, n;
  394. n = m->len;
  395. fc = m->pat[0];
  396. fuc = m->up[0];
  397. for(; str + n <= e; str++){
  398. c = *str;
  399. if(c != fc && c != fuc)
  400. continue;
  401. s = str + 1;
  402. up = m->up + 1;
  403. for(pat = m->pat + 1; pc = *pat; pat++){
  404. c = *s;
  405. if(c != pc && c != *up)
  406. break;
  407. up++;
  408. s++;
  409. }
  410. if(pc == 0)
  411. return 1;
  412. }
  413. return 0;
  414. }
  415. /*
  416. * boyer-moore style pattern matching
  417. * implements an exact match for ascii
  418. * however, if mulitbyte upper-case and lower-case
  419. * characters differ in length or in more than one byte,
  420. * it only implements an approximate match
  421. */
  422. void
  423. quickmk(Quick *q, char *spat, int ignorecase)
  424. {
  425. char *pat, *up;
  426. uchar *j;
  427. int ep, ea, cp, ca, i, c, n;
  428. /*
  429. * allocate the machine
  430. */
  431. n = strlen(spat);
  432. if(n == 0){
  433. q->pat = nil;
  434. q->up = nil;
  435. q->len = -1;
  436. return;
  437. }
  438. pat = emalloc(2* n + 2);
  439. q->pat = pat;
  440. up = pat;
  441. if(ignorecase)
  442. up = pat + n + 1;
  443. q->up = up;
  444. while(c = *spat++){
  445. if(ignorecase){
  446. *up++ = toupper(c);
  447. c = tolower(c);
  448. }
  449. *pat++ = c;
  450. }
  451. pat = q->pat;
  452. up = q->up;
  453. pat[n] = up[n] = '\0';
  454. /*
  455. * make the skipping table
  456. */
  457. if(n > 255)
  458. n = 255;
  459. j = q->jump;
  460. memset(j, n, 256);
  461. n--;
  462. q->len = n;
  463. for(i = 0; i <= n; i++){
  464. j[(uchar)pat[i]] = n - i;
  465. j[(uchar)up[i]] = n - i;
  466. }
  467. /*
  468. * find the minimum safe amount to skip
  469. * if we match the last char but not the whole pat
  470. */
  471. ep = pat[n];
  472. ea = up[n];
  473. for(i = n - 1; i >= 0; i--){
  474. cp = pat[i];
  475. ca = up[i];
  476. if(cp == ep || cp == ea || ca == ep || ca == ea)
  477. break;
  478. }
  479. q->miss = n - i;
  480. }
  481. void
  482. quickfree(Quick *q)
  483. {
  484. if(q->pat != nil)
  485. free(q->pat);
  486. q->pat = nil;
  487. }
  488. char *
  489. quicksearch(Quick *q, char *s, char *e)
  490. {
  491. char *pat, *up, *m, *ee;
  492. uchar *j;
  493. int len, n, c, mc;
  494. len = q->len;
  495. if(len < 0)
  496. return s;
  497. j = q->jump;
  498. pat = q->pat;
  499. up = q->up;
  500. s += len;
  501. ee = e - (len * 4 + 4);
  502. while(s < e){
  503. /*
  504. * look for a match on the last char
  505. */
  506. while(s < ee && (n = j[(uchar)*s])){
  507. s += n;
  508. s += j[(uchar)*s];
  509. s += j[(uchar)*s];
  510. s += j[(uchar)*s];
  511. }
  512. if(s >= e)
  513. return nil;
  514. while(n = j[(uchar)*s]){
  515. s += n;
  516. if(s >= e)
  517. return nil;
  518. }
  519. /*
  520. * does the string match?
  521. */
  522. m = s - len;
  523. for(n = 0; c = pat[n]; n++){
  524. mc = *m++;
  525. if(c != mc && mc != up[n])
  526. break;
  527. }
  528. if(!c)
  529. return s - len;
  530. s += q->miss;
  531. }
  532. return nil;
  533. }
  534. void
  535. fsrun(Fs *fs, int fd)
  536. {
  537. Fcall rpc;
  538. char *err;
  539. uchar *buf;
  540. int n;
  541. buf = emalloc(messagesize);
  542. for(;;){
  543. /*
  544. * reading from a pipe or a network device
  545. * will give an error after a few eof reads
  546. * however, we cannot tell the difference
  547. * between a zero-length read and an interrupt
  548. * on the processes writing to us,
  549. * so we wait for the error
  550. */
  551. n = read9pmsg(fd, buf, messagesize);
  552. if(n == 0)
  553. continue;
  554. if(n < 0)
  555. fatal("mount read");
  556. rpc.data = (char*)buf + IOHDRSZ;
  557. if(convM2S(buf, n, &rpc) == 0)
  558. continue;
  559. // fprint(2, "recv: %F\n", &rpc);
  560. /*
  561. * flushes are way too hard.
  562. * a reply to the original message seems to work
  563. */
  564. if(rpc.type == Tflush)
  565. continue;
  566. else if(rpc.type >= Tmax || !fcalls[rpc.type])
  567. err = "bad fcall type";
  568. else
  569. err = (*fcalls[rpc.type])(fs, &rpc);
  570. if(err){
  571. rpc.type = Rerror;
  572. rpc.ename = err;
  573. }else
  574. rpc.type++;
  575. n = convS2M(&rpc, buf, messagesize);
  576. // fprint(2, "send: %F\n", &rpc);
  577. if(write(fd, buf, n) != n)
  578. fatal("mount write");
  579. }
  580. }
  581. Fid*
  582. mkfid(Fs *fs, uint fid)
  583. {
  584. Fid *f;
  585. int h;
  586. h = fid % Nfidhash;
  587. for(f = fs->hash[h]; f; f = f->next){
  588. if(f->fid == fid)
  589. return nil;
  590. }
  591. f = emalloc(sizeof *f);
  592. f->next = fs->hash[h];
  593. if(f->next != nil)
  594. f->next->last = &f->next;
  595. f->last = &fs->hash[h];
  596. fs->hash[h] = f;
  597. f->fid = fid;
  598. f->ref = 1;
  599. f->attached = 1;
  600. f->open = 0;
  601. return f;
  602. }
  603. Fid*
  604. getfid(Fs *fs, uint fid)
  605. {
  606. Fid *f;
  607. int h;
  608. h = fid % Nfidhash;
  609. for(f = fs->hash[h]; f; f = f->next){
  610. if(f->fid == fid){
  611. if(f->attached == 0)
  612. break;
  613. f->ref++;
  614. return f;
  615. }
  616. }
  617. return nil;
  618. }
  619. void
  620. putfid(Fs *, Fid *f)
  621. {
  622. f->ref--;
  623. if(f->ref == 0 && f->attached == 0){
  624. *f->last = f->next;
  625. if(f->next != nil)
  626. f->next->last = f->last;
  627. if(f->search != nil)
  628. searchfree(f->search);
  629. free(f);
  630. }
  631. }
  632. char*
  633. fsversion(Fs *, Fcall *rpc)
  634. {
  635. if(rpc->msize < 256)
  636. return "version: message size too small";
  637. if(rpc->msize > messagesize)
  638. rpc->msize = messagesize;
  639. messagesize = rpc->msize;
  640. if(strncmp(rpc->version, "9P2000", 6) != 0)
  641. return "unrecognized 9P version";
  642. rpc->version = "9P2000";
  643. return nil;
  644. }
  645. char*
  646. fsauth(Fs *, Fcall *)
  647. {
  648. return "searchfs: authentication not required";
  649. }
  650. char*
  651. fsattach(Fs *fs, Fcall *rpc)
  652. {
  653. Fid *f;
  654. f = mkfid(fs, rpc->fid);
  655. if(f == nil)
  656. return Einuse;
  657. f->open = 0;
  658. f->qid.type = QTDIR;
  659. f->qid.path = Qroot;
  660. f->qid.vers = 0;
  661. rpc->qid = f->qid;
  662. putfid(fs, f);
  663. return nil;
  664. }
  665. char*
  666. fswalk(Fs *fs, Fcall *rpc)
  667. {
  668. Fid *f, *nf;
  669. int nqid, nwname, type;
  670. char *err, *name;
  671. ulong path;
  672. f = getfid(fs, rpc->fid);
  673. if(f == nil)
  674. return Enofid;
  675. nf = nil;
  676. if(rpc->fid != rpc->newfid){
  677. nf = mkfid(fs, rpc->newfid);
  678. if(nf == nil){
  679. putfid(fs, f);
  680. return Einuse;
  681. }
  682. nf->qid = f->qid;
  683. putfid(fs, f);
  684. f = nf; /* walk f */
  685. }
  686. err = nil;
  687. path = f->qid.path;
  688. nwname = rpc->nwname;
  689. for(nqid=0; nqid<nwname; nqid++){
  690. if(path != Qroot){
  691. err = Enotdir;
  692. break;
  693. }
  694. name = rpc->wname[nqid];
  695. if(strcmp(name, "search") == 0){
  696. type = QTFILE;
  697. path = Qsearch;
  698. }else if(strcmp(name, "stats") == 0){
  699. type = QTFILE;
  700. path = Qstats;
  701. }else if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0){
  702. type = QTDIR;
  703. path = path;
  704. }else{
  705. err = Enotexist;
  706. break;
  707. }
  708. rpc->wqid[nqid] = (Qid){path, 0, type};
  709. }
  710. if(nwname > 0){
  711. if(nf != nil && nqid < nwname)
  712. nf->attached = 0;
  713. if(nqid == nwname)
  714. f->qid = rpc->wqid[nqid-1];
  715. }
  716. putfid(fs, f);
  717. rpc->nwqid = nqid;
  718. f->open = 0;
  719. return err;
  720. }
  721. char *
  722. fsopen(Fs *fs, Fcall *rpc)
  723. {
  724. Fid *f;
  725. int mode;
  726. f = getfid(fs, rpc->fid);
  727. if(f == nil)
  728. return Enofid;
  729. if(f->open){
  730. putfid(fs, f);
  731. return Eisopen;
  732. }
  733. mode = rpc->mode & OPERM;
  734. if(mode == OEXEC
  735. || f->qid.path == Qroot && (mode == OWRITE || mode == ORDWR)){
  736. putfid(fs, f);
  737. return Eperm;
  738. }
  739. f->open = 1;
  740. f->where = nil;
  741. f->n = 0;
  742. f->search = nil;
  743. rpc->qid = f->qid;
  744. rpc->iounit = messagesize-IOHDRSZ;
  745. putfid(fs, f);
  746. return nil;
  747. }
  748. char *
  749. fscreate(Fs *, Fcall *)
  750. {
  751. return Eperm;
  752. }
  753. char*
  754. fsread(Fs *fs, Fcall *rpc)
  755. {
  756. Fid *f;
  757. int n, off, count, len;
  758. f = getfid(fs, rpc->fid);
  759. if(f == nil)
  760. return Enofid;
  761. if(!f->open){
  762. putfid(fs, f);
  763. return Enotopen;
  764. }
  765. count = rpc->count;
  766. off = rpc->offset;
  767. rpc->count = 0;
  768. if(f->qid.path == Qroot){
  769. if(off > 0)
  770. rpc->count = 0;
  771. else
  772. rpc->count = dostat(Qsearch, (uchar*)rpc->data, count);
  773. putfid(fs, f);
  774. if(off == 0 && rpc->count <= BIT16SZ)
  775. return "directory read count too small";
  776. return nil;
  777. }
  778. if(f->qid.path == Qstats){
  779. len = 0;
  780. }else{
  781. for(len = 0; len < count; len += n){
  782. if(f->where == nil || f->search == nil)
  783. break;
  784. if(f->n == 0)
  785. f->where = searchsearch(f->search, f->where, edatabase, &f->n);
  786. n = f->n;
  787. if(n != 0){
  788. if(n > count-len)
  789. n = count-len;
  790. memmove(rpc->data+len, f->where, n);
  791. f->where += n;
  792. f->n -= n;
  793. }
  794. }
  795. }
  796. putfid(fs, f);
  797. rpc->count = len;
  798. return nil;
  799. }
  800. char*
  801. fswrite(Fs *fs, Fcall *rpc)
  802. {
  803. Fid *f;
  804. f = getfid(fs, rpc->fid);
  805. if(f == nil)
  806. return Enofid;
  807. if(!f->open || f->qid.path != Qsearch){
  808. putfid(fs, f);
  809. return Enotopen;
  810. }
  811. if(f->search != nil)
  812. searchfree(f->search);
  813. f->search = searchparse(rpc->data, rpc->data + rpc->count);
  814. if(f->search == nil){
  815. putfid(fs, f);
  816. return Ebadsearch;
  817. }
  818. f->where = database;
  819. f->n = 0;
  820. putfid(fs, f);
  821. return nil;
  822. }
  823. char *
  824. fsclunk(Fs *fs, Fcall *rpc)
  825. {
  826. Fid *f;
  827. f = getfid(fs, rpc->fid);
  828. if(f != nil){
  829. f->attached = 0;
  830. putfid(fs, f);
  831. }
  832. return nil;
  833. }
  834. char *
  835. fsremove(Fs *, Fcall *)
  836. {
  837. return Eperm;
  838. }
  839. char *
  840. fsstat(Fs *fs, Fcall *rpc)
  841. {
  842. Fid *f;
  843. f = getfid(fs, rpc->fid);
  844. if(f == nil)
  845. return Enofid;
  846. rpc->stat = fs->statbuf;
  847. rpc->nstat = dostat(f->qid.path, rpc->stat, sizeof fs->statbuf);
  848. putfid(fs, f);
  849. if(rpc->nstat <= BIT16SZ)
  850. return "stat count too small";
  851. return nil;
  852. }
  853. char *
  854. fswstat(Fs *, Fcall *)
  855. {
  856. return Eperm;
  857. }
  858. int
  859. dostat(int path, uchar *buf, int nbuf)
  860. {
  861. Dir d;
  862. switch(path){
  863. case Qroot:
  864. d.name = ".";
  865. d.mode = DMDIR|0555;
  866. d.qid.type = QTDIR;
  867. break;
  868. case Qsearch:
  869. d.name = "search";
  870. d.mode = 0666;
  871. d.qid.type = QTFILE;
  872. break;
  873. case Qstats:
  874. d.name = "stats";
  875. d.mode = 0666;
  876. d.qid.type = QTFILE;
  877. break;
  878. }
  879. d.qid.path = path;
  880. d.qid.vers = 0;
  881. d.length = 0;
  882. d.uid = d.gid = d.muid = "none";
  883. d.atime = d.mtime = time(nil);
  884. return convD2M(&d, buf, nbuf);
  885. }
  886. char *
  887. urlunesc(char *s, char *e)
  888. {
  889. char *t, *v;
  890. int c, n;
  891. v = emalloc((e - s) + 1);
  892. for(t = v; s < e; s++){
  893. c = *s;
  894. if(c == '%'){
  895. if(s + 2 >= e)
  896. break;
  897. n = s[1];
  898. if(n >= '0' && n <= '9')
  899. n = n - '0';
  900. else if(n >= 'A' && n <= 'F')
  901. n = n - 'A' + 10;
  902. else if(n >= 'a' && n <= 'f')
  903. n = n - 'a' + 10;
  904. else
  905. break;
  906. c = n;
  907. n = s[2];
  908. if(n >= '0' && n <= '9')
  909. n = n - '0';
  910. else if(n >= 'A' && n <= 'F')
  911. n = n - 'A' + 10;
  912. else if(n >= 'a' && n <= 'f')
  913. n = n - 'a' + 10;
  914. else
  915. break;
  916. s += 2;
  917. c = c * 16 + n;
  918. }
  919. *t++ = c;
  920. }
  921. *t = 0;
  922. return v;
  923. }
  924. int
  925. toupper(int c)
  926. {
  927. if(c >= 'a' && c <= 'z')
  928. c += 'A' - 'a';
  929. return c;
  930. }
  931. int
  932. tolower(int c)
  933. {
  934. if(c >= 'A' && c <= 'Z')
  935. c += 'a' - 'A';
  936. return c;
  937. }
  938. void
  939. fatal(char *fmt, ...)
  940. {
  941. va_list arg;
  942. char buf[1024];
  943. write(2, "searchfs: ", 8);
  944. va_start(arg, fmt);
  945. vseprint(buf, buf+1024, fmt, arg);
  946. va_end(arg);
  947. write(2, buf, strlen(buf));
  948. write(2, "\n", 1);
  949. exits(fmt);
  950. }
  951. void *
  952. emalloc(uint n)
  953. {
  954. void *p;
  955. p = malloc(n);
  956. if(p == nil)
  957. fatal("out of memory");
  958. memset(p, 0, n);
  959. return p;
  960. }
  961. void
  962. usage(void)
  963. {
  964. fprint(2, "usage: searchfs [-m mountpoint] [-s srvfile] database\n");
  965. exits("usage");
  966. }