xref: /plan9/sys/src/cmd/aux/searchfs.c (revision b85a83648eec38fe82b6f00adfd7828ceec5ee8d)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <auth.h>
47dd7cddfSDavid du Colombier #include <fcall.h>
57dd7cddfSDavid du Colombier 
67dd7cddfSDavid du Colombier /*
77dd7cddfSDavid du Colombier  * caveat:
87dd7cddfSDavid du Colombier  * this stuff is only meant to work for ascii databases
97dd7cddfSDavid du Colombier  */
107dd7cddfSDavid du Colombier 
117dd7cddfSDavid du Colombier typedef struct Fid Fid;
127dd7cddfSDavid du Colombier typedef struct Fs Fs;
137dd7cddfSDavid du Colombier typedef struct Quick Quick;
147dd7cddfSDavid du Colombier typedef struct Match Match;
157dd7cddfSDavid du Colombier typedef struct Search Search;
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier enum
187dd7cddfSDavid du Colombier {
197dd7cddfSDavid du Colombier 	OPERM	= 0x3,		/* mask of all permission types in open mode */
207dd7cddfSDavid du Colombier 	Nfidhash	= 32,
217dd7cddfSDavid du Colombier 
227dd7cddfSDavid du Colombier 	/*
237dd7cddfSDavid du Colombier 	 * qids
247dd7cddfSDavid du Colombier 	 */
25*9a747e4fSDavid du Colombier 	Qroot	= 1,
267dd7cddfSDavid du Colombier 	Qsearch	= 2,
277dd7cddfSDavid du Colombier 	Qstats	= 3,
287dd7cddfSDavid du Colombier };
297dd7cddfSDavid du Colombier 
307dd7cddfSDavid du Colombier /*
317dd7cddfSDavid du Colombier  * boyer-moore quick string matching
327dd7cddfSDavid du Colombier  */
337dd7cddfSDavid du Colombier struct Quick
347dd7cddfSDavid du Colombier {
357dd7cddfSDavid du Colombier 	char	*pat;
367dd7cddfSDavid du Colombier 	char	*up;		/* match string for upper case of pat */
377dd7cddfSDavid du Colombier 	int	len;		/* of pat (and up) -1; used for fast search */
387dd7cddfSDavid du Colombier 	uchar 	jump[256];	/* jump index table */
397dd7cddfSDavid du Colombier 	int	miss;		/* amount to jump if we falsely match the last char */
407dd7cddfSDavid du Colombier };
417dd7cddfSDavid du Colombier extern void	quickmk(Quick*, char*, int);
427dd7cddfSDavid du Colombier extern void	quickfree(Quick*);
437dd7cddfSDavid du Colombier extern char*	quicksearch(Quick*, char*, char*);
447dd7cddfSDavid du Colombier 
457dd7cddfSDavid du Colombier /*
467dd7cddfSDavid du Colombier  * exact matching of a search string
477dd7cddfSDavid du Colombier  */
487dd7cddfSDavid du Colombier struct Match
497dd7cddfSDavid du Colombier {
507dd7cddfSDavid du Colombier 	Match	*next;
517dd7cddfSDavid du Colombier 	char	*pat;				/* null-terminated search string */
527dd7cddfSDavid du Colombier 	char	*up;				/* upper case of pat */
537dd7cddfSDavid du Colombier 	int	len;				/* length of both pat and up */
547dd7cddfSDavid du Colombier 	int	(*op)(Match*, char*, char*);		/* method for this partiticular search */
557dd7cddfSDavid du Colombier };
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier struct Search
587dd7cddfSDavid du Colombier {
597dd7cddfSDavid du Colombier 	Quick		quick;		/* quick match */
607dd7cddfSDavid du Colombier 	Match		*match;		/* exact matches */
617dd7cddfSDavid du Colombier 	int		skip;		/* number of matches to skip */
627dd7cddfSDavid du Colombier };
637dd7cddfSDavid du Colombier 
647dd7cddfSDavid du Colombier extern char*	searchsearch(Search*, char*, char*, int*);
657dd7cddfSDavid du Colombier extern Search*	searchparse(char*, char*);
667dd7cddfSDavid du Colombier extern void	searchfree(Search*);
677dd7cddfSDavid du Colombier 
687dd7cddfSDavid du Colombier struct Fid
697dd7cddfSDavid du Colombier {
707dd7cddfSDavid du Colombier 	Lock;
717dd7cddfSDavid du Colombier 	Fid	*next;
727dd7cddfSDavid du Colombier 	Fid	**last;
737dd7cddfSDavid du Colombier 	uint	fid;
747dd7cddfSDavid du Colombier 	int	ref;		/* number of fcalls using the fid */
757dd7cddfSDavid du Colombier 	int	attached;		/* fid has beed attached or cloned and not clunked */
767dd7cddfSDavid du Colombier 
777dd7cddfSDavid du Colombier 	int	open;
787dd7cddfSDavid du Colombier 	Qid	qid;
797dd7cddfSDavid du Colombier 	Search	*search;		/* search patterns */
807dd7cddfSDavid du Colombier 	char	*where;		/* current location in the database */
817dd7cddfSDavid du Colombier 	int	n;		/* number of bytes left in found item */
827dd7cddfSDavid du Colombier };
837dd7cddfSDavid du Colombier 
84*9a747e4fSDavid du Colombier int			dostat(int, uchar*, int);
857dd7cddfSDavid du Colombier void*			emalloc(uint);
867dd7cddfSDavid du Colombier void			fatal(char*, ...);
877dd7cddfSDavid du Colombier Match*			mkmatch(Match*, int(*)(Match*, char*, char*), char*);
887dd7cddfSDavid du Colombier Match*			mkstrmatch(Match*, char*);
897dd7cddfSDavid du Colombier char*		nextsearch(char*, char*, char**, char**);
907dd7cddfSDavid du Colombier int			strlook(Match*, char*, char*);
917dd7cddfSDavid du Colombier char*			strndup(char*, int);
927dd7cddfSDavid du Colombier int			tolower(int);
937dd7cddfSDavid du Colombier int			toupper(int);
947dd7cddfSDavid du Colombier char*			urlunesc(char*, char*);
957dd7cddfSDavid du Colombier void			usage(void);
967dd7cddfSDavid du Colombier 
977dd7cddfSDavid du Colombier struct Fs
987dd7cddfSDavid du Colombier {
997dd7cddfSDavid du Colombier 	Lock;			/* for fids */
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier 	Fid	*hash[Nfidhash];
102*9a747e4fSDavid du Colombier 	uchar	statbuf[1024];	/* plenty big enough */
1037dd7cddfSDavid du Colombier };
1047dd7cddfSDavid du Colombier extern	void	fsrun(Fs*, int);
1057dd7cddfSDavid du Colombier extern	Fid*	getfid(Fs*, uint);
1067dd7cddfSDavid du Colombier extern	Fid*	mkfid(Fs*, uint);
1077dd7cddfSDavid du Colombier extern	void	putfid(Fs*, Fid*);
108*9a747e4fSDavid du Colombier extern	char*	fsversion(Fs*, Fcall*);
109*9a747e4fSDavid du Colombier extern	char*	fsauth(Fs*, Fcall*);
1107dd7cddfSDavid du Colombier extern	char*	fsattach(Fs*, Fcall*);
1117dd7cddfSDavid du Colombier extern	char*	fswalk(Fs*, Fcall*);
1127dd7cddfSDavid du Colombier extern	char*	fsopen(Fs*, Fcall*);
1137dd7cddfSDavid du Colombier extern	char*	fscreate(Fs*, Fcall*);
1147dd7cddfSDavid du Colombier extern	char*	fsread(Fs*, Fcall*);
1157dd7cddfSDavid du Colombier extern	char*	fswrite(Fs*, Fcall*);
1167dd7cddfSDavid du Colombier extern	char*	fsclunk(Fs*, Fcall*);
1177dd7cddfSDavid du Colombier extern	char*	fsremove(Fs*, Fcall*);
1187dd7cddfSDavid du Colombier extern	char*	fsstat(Fs*, Fcall*);
1197dd7cddfSDavid du Colombier extern	char*	fswstat(Fs*, Fcall*);
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier char	*(*fcalls[])(Fs*, Fcall*) =
1227dd7cddfSDavid du Colombier {
123*9a747e4fSDavid du Colombier 	[Tversion]		fsversion,
1247dd7cddfSDavid du Colombier 	[Tattach]	fsattach,
125*9a747e4fSDavid du Colombier 	[Tauth]	fsauth,
1267dd7cddfSDavid du Colombier 	[Twalk]		fswalk,
1277dd7cddfSDavid du Colombier 	[Topen]		fsopen,
1287dd7cddfSDavid du Colombier 	[Tcreate]	fscreate,
1297dd7cddfSDavid du Colombier 	[Tread]		fsread,
1307dd7cddfSDavid du Colombier 	[Twrite]	fswrite,
1317dd7cddfSDavid du Colombier 	[Tclunk]	fsclunk,
1327dd7cddfSDavid du Colombier 	[Tremove]	fsremove,
1337dd7cddfSDavid du Colombier 	[Tstat]		fsstat,
1347dd7cddfSDavid du Colombier 	[Twstat]	fswstat
1357dd7cddfSDavid du Colombier };
1367dd7cddfSDavid du Colombier 
1377dd7cddfSDavid du Colombier char	Eperm[] =	"permission denied";
1387dd7cddfSDavid du Colombier char	Enotdir[] =	"not a directory";
1397dd7cddfSDavid du Colombier char	Enotexist[] =	"file does not exist";
1407dd7cddfSDavid du Colombier char	Eisopen[] = 	"file already open for I/O";
1417dd7cddfSDavid du Colombier char	Einuse[] =	"fid is already in use";
1427dd7cddfSDavid du Colombier char	Enofid[] = 	"no such fid";
1437dd7cddfSDavid du Colombier char	Enotopen[] =	"file is not open";
1447dd7cddfSDavid du Colombier char	Ebadsearch[] =	"bad search string";
1457dd7cddfSDavid du Colombier 
1467dd7cddfSDavid du Colombier Fs	fs;
1477dd7cddfSDavid du Colombier char	*database;
1487dd7cddfSDavid du Colombier char	*edatabase;
149*9a747e4fSDavid du Colombier int	messagesize = 8192+IOHDRSZ;
1507dd7cddfSDavid du Colombier void
main(int argc,char ** argv)1517dd7cddfSDavid du Colombier main(int argc, char **argv)
1527dd7cddfSDavid du Colombier {
153*9a747e4fSDavid du Colombier 	Dir *d;
1547dd7cddfSDavid du Colombier 	char buf[12], *mnt, *srv;
1557dd7cddfSDavid du Colombier 	int fd, p[2], n;
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier 	mnt = "/tmp";
1587dd7cddfSDavid du Colombier 	srv = nil;
1597dd7cddfSDavid du Colombier 	ARGBEGIN{
1607dd7cddfSDavid du Colombier 		case 's':
1617dd7cddfSDavid du Colombier 			srv = ARGF();
1627dd7cddfSDavid du Colombier 			mnt = nil;
1637dd7cddfSDavid du Colombier 			break;
1647dd7cddfSDavid du Colombier 		case 'm':
1657dd7cddfSDavid du Colombier 			mnt = ARGF();
1667dd7cddfSDavid du Colombier 			break;
1677dd7cddfSDavid du Colombier 	}ARGEND
1687dd7cddfSDavid du Colombier 
169*9a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
170*9a747e4fSDavid du Colombier 
1717dd7cddfSDavid du Colombier 	if(argc != 1)
1727dd7cddfSDavid du Colombier 		usage();
173*9a747e4fSDavid du Colombier 	d = nil;
1747dd7cddfSDavid du Colombier 	fd = open(argv[0], OREAD);
175*9a747e4fSDavid du Colombier 	if(fd < 0 || (d=dirfstat(fd)) == nil)
1767dd7cddfSDavid du Colombier 		fatal("can't open %s: %r", argv[0]);
177*9a747e4fSDavid du Colombier 	n = d->length;
178*9a747e4fSDavid du Colombier 	free(d);
1797dd7cddfSDavid du Colombier 	if(n == 0)
1807dd7cddfSDavid du Colombier 		fatal("zero length database %s", argv[0]);
1817dd7cddfSDavid du Colombier 	database = emalloc(n);
1827dd7cddfSDavid du Colombier 	if(read(fd, database, n) != n)
1837dd7cddfSDavid du Colombier 		fatal("can't read %s: %r", argv[0]);
1847dd7cddfSDavid du Colombier 	close(fd);
1857dd7cddfSDavid du Colombier 	edatabase = database + n;
1867dd7cddfSDavid du Colombier 
1877dd7cddfSDavid du Colombier 	if(pipe(p) < 0)
1887dd7cddfSDavid du Colombier 		fatal("pipe failed");
1897dd7cddfSDavid du Colombier 
1907dd7cddfSDavid du Colombier 	switch(rfork(RFPROC|RFMEM|RFNOTEG|RFNAMEG)){
1917dd7cddfSDavid du Colombier 	case 0:
1927dd7cddfSDavid du Colombier 		fsrun(&fs, p[0]);
1937dd7cddfSDavid du Colombier 		exits(nil);
1947dd7cddfSDavid du Colombier 	case -1:
1957dd7cddfSDavid du Colombier 		fatal("fork failed");
1967dd7cddfSDavid du Colombier 	}
1977dd7cddfSDavid du Colombier 
1987dd7cddfSDavid du Colombier 	if(mnt == nil){
1997dd7cddfSDavid du Colombier 		if(srv == nil)
2007dd7cddfSDavid du Colombier 			usage();
2017dd7cddfSDavid du Colombier 		fd = create(srv, OWRITE, 0666);
2027dd7cddfSDavid du Colombier 		if(fd < 0){
2037dd7cddfSDavid du Colombier 			remove(srv);
2047dd7cddfSDavid du Colombier 			fd = create(srv, OWRITE, 0666);
2057dd7cddfSDavid du Colombier 			if(fd < 0){
2067dd7cddfSDavid du Colombier 				close(p[1]);
2077dd7cddfSDavid du Colombier 				fatal("create of %s failed", srv);
2087dd7cddfSDavid du Colombier 			}
2097dd7cddfSDavid du Colombier 		}
2107dd7cddfSDavid du Colombier 		sprint(buf, "%d", p[1]);
2117dd7cddfSDavid du Colombier 		if(write(fd, buf, strlen(buf)) < 0){
2127dd7cddfSDavid du Colombier 			close(p[1]);
2137dd7cddfSDavid du Colombier 			fatal("writing %s", srv);
2147dd7cddfSDavid du Colombier 		}
2157dd7cddfSDavid du Colombier 		close(p[1]);
2167dd7cddfSDavid du Colombier 		exits(nil);
2177dd7cddfSDavid du Colombier 	}
2187dd7cddfSDavid du Colombier 
219*9a747e4fSDavid du Colombier 	if(mount(p[1], -1, mnt, MREPL, "") < 0){
2207dd7cddfSDavid du Colombier 		close(p[1]);
2217dd7cddfSDavid du Colombier 		fatal("mount failed");
2227dd7cddfSDavid du Colombier 	}
2237dd7cddfSDavid du Colombier 	close(p[1]);
2247dd7cddfSDavid du Colombier 	exits(nil);
2257dd7cddfSDavid du Colombier }
2267dd7cddfSDavid du Colombier 
2277dd7cddfSDavid du Colombier /*
2287dd7cddfSDavid du Colombier  * execute the search
2297dd7cddfSDavid du Colombier  * do a quick match,
2307dd7cddfSDavid du Colombier  * isolate the line in which the occured,
2317dd7cddfSDavid du Colombier  * and try all of the exact matches
2327dd7cddfSDavid du Colombier  */
2337dd7cddfSDavid du Colombier char*
searchsearch(Search * search,char * where,char * end,int * np)2347dd7cddfSDavid du Colombier searchsearch(Search *search, char *where, char *end, int *np)
2357dd7cddfSDavid du Colombier {
2367dd7cddfSDavid du Colombier 	Match *m;
2377dd7cddfSDavid du Colombier 	char *s, *e;
2387dd7cddfSDavid du Colombier 
2397dd7cddfSDavid du Colombier 	*np = 0;
2407dd7cddfSDavid du Colombier 	if(search == nil || where == nil)
2417dd7cddfSDavid du Colombier 		return nil;
2427dd7cddfSDavid du Colombier 	for(;;){
2437dd7cddfSDavid du Colombier 		s = quicksearch(&search->quick, where, end);
2447dd7cddfSDavid du Colombier 		if(s == nil)
2457dd7cddfSDavid du Colombier 			return nil;
2467dd7cddfSDavid du Colombier 		e = memchr(s, '\n', end - s);
2477dd7cddfSDavid du Colombier 		if(e == nil)
2487dd7cddfSDavid du Colombier 			e = end;
2497dd7cddfSDavid du Colombier 		else
2507dd7cddfSDavid du Colombier 			e++;
2517dd7cddfSDavid du Colombier 		while(s > where && s[-1] != '\n')
2527dd7cddfSDavid du Colombier 			s--;
2537dd7cddfSDavid du Colombier 		for(m = search->match; m != nil; m = m->next){
2547dd7cddfSDavid du Colombier 			if((*m->op)(m, s, e) == 0)
2557dd7cddfSDavid du Colombier 				break;
2567dd7cddfSDavid du Colombier 		}
2577dd7cddfSDavid du Colombier 
2587dd7cddfSDavid du Colombier 		if(m == nil){
2597dd7cddfSDavid du Colombier 			if(search->skip > 0)
2607dd7cddfSDavid du Colombier 				search->skip--;
2617dd7cddfSDavid du Colombier 			else{
2627dd7cddfSDavid du Colombier 				*np = e - s;
2637dd7cddfSDavid du Colombier 				return s;
2647dd7cddfSDavid du Colombier 			}
2657dd7cddfSDavid du Colombier 		}
2667dd7cddfSDavid du Colombier 
2677dd7cddfSDavid du Colombier 		where = e;
2687dd7cddfSDavid du Colombier 	}
2697dd7cddfSDavid du Colombier }
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier /*
2727dd7cddfSDavid du Colombier  * parse a search string of the form
2737dd7cddfSDavid du Colombier  * tag=val&tag1=val1...
2747dd7cddfSDavid du Colombier  */
2757dd7cddfSDavid du Colombier Search*
searchparse(char * search,char * esearch)2767dd7cddfSDavid du Colombier searchparse(char *search, char *esearch)
2777dd7cddfSDavid du Colombier {
2787dd7cddfSDavid du Colombier 	Search *s;
2797dd7cddfSDavid du Colombier 	Match *m, *next, **last;
2807dd7cddfSDavid du Colombier 	char *tag, *val, *p;
2817dd7cddfSDavid du Colombier 	int ok;
2827dd7cddfSDavid du Colombier 
2837dd7cddfSDavid du Colombier 	s = emalloc(sizeof *s);
2847dd7cddfSDavid du Colombier 	s->match = nil;
2857dd7cddfSDavid du Colombier 
2867dd7cddfSDavid du Colombier 	/*
2877dd7cddfSDavid du Colombier 	 * acording to the http spec,
2887dd7cddfSDavid du Colombier 	 * repeated search queries are ingored.
2897dd7cddfSDavid du Colombier 	 * the last search given is performed on the original object
2907dd7cddfSDavid du Colombier 	 */
2917dd7cddfSDavid du Colombier 	while((p = memchr(s, '?', esearch - search)) != nil){
2927dd7cddfSDavid du Colombier 		search = p + 1;
2937dd7cddfSDavid du Colombier 	}
2947dd7cddfSDavid du Colombier 	while(search < esearch){
2957dd7cddfSDavid du Colombier 		search = nextsearch(search, esearch, &tag, &val);
2967dd7cddfSDavid du Colombier 		if(tag == nil)
2977dd7cddfSDavid du Colombier 			continue;
2987dd7cddfSDavid du Colombier 
2997dd7cddfSDavid du Colombier 		ok = 0;
3007dd7cddfSDavid du Colombier 		if(strcmp(tag, "skip") == 0){
3017dd7cddfSDavid du Colombier 			s->skip = strtoul(val, &p, 10);
3027dd7cddfSDavid du Colombier 			if(*p == 0)
3037dd7cddfSDavid du Colombier 				ok = 1;
3047dd7cddfSDavid du Colombier 		}else if(strcmp(tag, "search") == 0){
3057dd7cddfSDavid du Colombier 			s->match = mkstrmatch(s->match, val);
3067dd7cddfSDavid du Colombier 			ok = 1;
3077dd7cddfSDavid du Colombier 		}
3087dd7cddfSDavid du Colombier 		free(tag);
3097dd7cddfSDavid du Colombier 		free(val);
3107dd7cddfSDavid du Colombier 		if(!ok){
3117dd7cddfSDavid du Colombier 			searchfree(s);
3127dd7cddfSDavid du Colombier 			return nil;
3137dd7cddfSDavid du Colombier 		}
3147dd7cddfSDavid du Colombier 	}
3157dd7cddfSDavid du Colombier 
3167dd7cddfSDavid du Colombier 	if(s->match == nil){
3177dd7cddfSDavid du Colombier 		free(s);
3187dd7cddfSDavid du Colombier 		return nil;
3197dd7cddfSDavid du Colombier 	}
3207dd7cddfSDavid du Colombier 
3217dd7cddfSDavid du Colombier 	/*
3227dd7cddfSDavid du Colombier 	 * order the matches by probability of occurance
3237dd7cddfSDavid du Colombier 	 * first cut is just by length
3247dd7cddfSDavid du Colombier 	 */
3257dd7cddfSDavid du Colombier 	for(ok = 0; !ok; ){
3267dd7cddfSDavid du Colombier 		ok = 1;
3277dd7cddfSDavid du Colombier 		last = &s->match;
3287dd7cddfSDavid du Colombier 		for(m = *last; m && m->next; m = *last){
3297dd7cddfSDavid du Colombier 			if(m->next->len > m->len){
3307dd7cddfSDavid du Colombier 				next = m->next;
3317dd7cddfSDavid du Colombier 				m->next = next->next;
3327dd7cddfSDavid du Colombier 				next->next = m;
3337dd7cddfSDavid du Colombier 				*last = next;
3347dd7cddfSDavid du Colombier 				ok = 0;
3357dd7cddfSDavid du Colombier 			}
3367dd7cddfSDavid du Colombier 			last = &m->next;
3377dd7cddfSDavid du Colombier 		}
3387dd7cddfSDavid du Colombier 	}
3397dd7cddfSDavid du Colombier 
3407dd7cddfSDavid du Colombier 	/*
3417dd7cddfSDavid du Colombier 	 * convert the best search into a fast lookup
3427dd7cddfSDavid du Colombier 	 */
3437dd7cddfSDavid du Colombier 	m = s->match;
3447dd7cddfSDavid du Colombier 	s->match = m->next;
3457dd7cddfSDavid du Colombier 	quickmk(&s->quick, m->pat, 1);
3467dd7cddfSDavid du Colombier 	free(m->pat);
3477dd7cddfSDavid du Colombier 	free(m->up);
3487dd7cddfSDavid du Colombier 	free(m);
3497dd7cddfSDavid du Colombier 	return s;
3507dd7cddfSDavid du Colombier }
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier void
searchfree(Search * s)3537dd7cddfSDavid du Colombier searchfree(Search *s)
3547dd7cddfSDavid du Colombier {
3557dd7cddfSDavid du Colombier 	Match *m, *next;
3567dd7cddfSDavid du Colombier 
3577dd7cddfSDavid du Colombier 	if(s == nil)
3587dd7cddfSDavid du Colombier 		return;
3597dd7cddfSDavid du Colombier 	for(m = s->match; m; m = next){
3607dd7cddfSDavid du Colombier 		next = m->next;
3617dd7cddfSDavid du Colombier 		free(m->pat);
3627dd7cddfSDavid du Colombier 		free(m->up);
3637dd7cddfSDavid du Colombier 		free(m);
3647dd7cddfSDavid du Colombier 	}
3657dd7cddfSDavid du Colombier 	quickfree(&s->quick);
3667dd7cddfSDavid du Colombier 	free(s);
3677dd7cddfSDavid du Colombier }
3687dd7cddfSDavid du Colombier 
3697dd7cddfSDavid du Colombier char*
nextsearch(char * search,char * esearch,char ** tagp,char ** valp)3707dd7cddfSDavid du Colombier nextsearch(char *search, char *esearch, char **tagp, char **valp)
3717dd7cddfSDavid du Colombier {
3727dd7cddfSDavid du Colombier 	char *tag, *val;
3737dd7cddfSDavid du Colombier 
3747dd7cddfSDavid du Colombier 	*tagp = nil;
3757dd7cddfSDavid du Colombier 	*valp = nil;
3767dd7cddfSDavid du Colombier 	for(tag = search; search < esearch && *search != '='; search++)
3777dd7cddfSDavid du Colombier 		;
3787dd7cddfSDavid du Colombier 	if(search == esearch)
3797dd7cddfSDavid du Colombier 		return search;
3807dd7cddfSDavid du Colombier 	tag = urlunesc(tag, search);
3817dd7cddfSDavid du Colombier 	search++;
3827dd7cddfSDavid du Colombier 	for(val = search; search < esearch && *search != '&'; search++)
3837dd7cddfSDavid du Colombier 		;
3847dd7cddfSDavid du Colombier 	val = urlunesc(val, search);
3857dd7cddfSDavid du Colombier 	if(search != esearch)
3867dd7cddfSDavid du Colombier 		search++;
3877dd7cddfSDavid du Colombier 	*tagp = tag;
3887dd7cddfSDavid du Colombier 	*valp = val;
3897dd7cddfSDavid du Colombier 	return search;
3907dd7cddfSDavid du Colombier }
3917dd7cddfSDavid du Colombier 
3927dd7cddfSDavid du Colombier Match*
mkstrmatch(Match * m,char * pat)3937dd7cddfSDavid du Colombier mkstrmatch(Match *m, char *pat)
3947dd7cddfSDavid du Colombier {
3957dd7cddfSDavid du Colombier 	char *s;
3967dd7cddfSDavid du Colombier 
3977dd7cddfSDavid du Colombier 	for(s = pat; *s; s++){
3987dd7cddfSDavid du Colombier 		if(*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r'){
3997dd7cddfSDavid du Colombier 			*s = 0;
4007dd7cddfSDavid du Colombier 			m = mkmatch(m, strlook, pat);
4017dd7cddfSDavid du Colombier 			pat = s + 1;
4027dd7cddfSDavid du Colombier 		}else
4037dd7cddfSDavid du Colombier 			*s = tolower(*s);
4047dd7cddfSDavid du Colombier 	}
4057dd7cddfSDavid du Colombier 	return mkmatch(m, strlook, pat);
4067dd7cddfSDavid du Colombier }
4077dd7cddfSDavid du Colombier 
4087dd7cddfSDavid du Colombier Match*
mkmatch(Match * next,int (* op)(Match *,char *,char *),char * pat)4097dd7cddfSDavid du Colombier mkmatch(Match *next, int (*op)(Match*, char*, char*), char *pat)
4107dd7cddfSDavid du Colombier {
4117dd7cddfSDavid du Colombier 	Match *m;
4127dd7cddfSDavid du Colombier 	char *p;
4137dd7cddfSDavid du Colombier 	int n;
4147dd7cddfSDavid du Colombier 
4157dd7cddfSDavid du Colombier 	n = strlen(pat);
4167dd7cddfSDavid du Colombier 	if(n == 0)
4177dd7cddfSDavid du Colombier 		return next;
4187dd7cddfSDavid du Colombier 	m = emalloc(sizeof *m);
4197dd7cddfSDavid du Colombier 	m->op = op;
4207dd7cddfSDavid du Colombier 	m->len = n;
4217dd7cddfSDavid du Colombier 	m->pat = strdup(pat);
4227dd7cddfSDavid du Colombier 	m->up = strdup(pat);
4237dd7cddfSDavid du Colombier 	for(p = m->up; *p; p++)
4247dd7cddfSDavid du Colombier 		*p = toupper(*p);
4257dd7cddfSDavid du Colombier 	for(p = m->pat; *p; p++)
4267dd7cddfSDavid du Colombier 		*p = tolower(*p);
4277dd7cddfSDavid du Colombier 	m->next = next;
4287dd7cddfSDavid du Colombier 	return m;
4297dd7cddfSDavid du Colombier }
4307dd7cddfSDavid du Colombier 
4317dd7cddfSDavid du Colombier int
strlook(Match * m,char * str,char * e)4327dd7cddfSDavid du Colombier strlook(Match *m, char *str, char *e)
4337dd7cddfSDavid du Colombier {
4347dd7cddfSDavid du Colombier 	char *pat, *up, *s;
4357dd7cddfSDavid du Colombier 	int c, pc, fc, fuc, n;
4367dd7cddfSDavid du Colombier 
4377dd7cddfSDavid du Colombier 	n = m->len;
4387dd7cddfSDavid du Colombier 	fc = m->pat[0];
4397dd7cddfSDavid du Colombier 	fuc = m->up[0];
4407dd7cddfSDavid du Colombier 	for(; str + n <= e; str++){
4417dd7cddfSDavid du Colombier 		c = *str;
4427dd7cddfSDavid du Colombier 		if(c != fc && c != fuc)
4437dd7cddfSDavid du Colombier 			continue;
4447dd7cddfSDavid du Colombier 		s = str + 1;
4457dd7cddfSDavid du Colombier 		up = m->up + 1;
4467dd7cddfSDavid du Colombier 		for(pat = m->pat + 1; pc = *pat; pat++){
4477dd7cddfSDavid du Colombier 			c = *s;
4487dd7cddfSDavid du Colombier 			if(c != pc && c != *up)
4497dd7cddfSDavid du Colombier 				break;
4507dd7cddfSDavid du Colombier 			up++;
4517dd7cddfSDavid du Colombier 			s++;
4527dd7cddfSDavid du Colombier 		}
4537dd7cddfSDavid du Colombier 		if(pc == 0)
4547dd7cddfSDavid du Colombier 			return 1;
4557dd7cddfSDavid du Colombier 	}
4567dd7cddfSDavid du Colombier 	return 0;
4577dd7cddfSDavid du Colombier }
4587dd7cddfSDavid du Colombier 
4597dd7cddfSDavid du Colombier /*
4607dd7cddfSDavid du Colombier  * boyer-moore style pattern matching
4617dd7cddfSDavid du Colombier  * implements an exact match for ascii
4627dd7cddfSDavid du Colombier  * however, if mulitbyte upper-case and lower-case
4637dd7cddfSDavid du Colombier  * characters differ in length or in more than one byte,
4647dd7cddfSDavid du Colombier  * it only implements an approximate match
4657dd7cddfSDavid du Colombier  */
4667dd7cddfSDavid du Colombier void
quickmk(Quick * q,char * spat,int ignorecase)4677dd7cddfSDavid du Colombier quickmk(Quick *q, char *spat, int ignorecase)
4687dd7cddfSDavid du Colombier {
4697dd7cddfSDavid du Colombier 	char *pat, *up;
4707dd7cddfSDavid du Colombier 	uchar *j;
4717dd7cddfSDavid du Colombier 	int ep, ea, cp, ca, i, c, n;
4727dd7cddfSDavid du Colombier 
4737dd7cddfSDavid du Colombier 	/*
4747dd7cddfSDavid du Colombier 	 * allocate the machine
4757dd7cddfSDavid du Colombier 	 */
4767dd7cddfSDavid du Colombier 	n = strlen(spat);
4777dd7cddfSDavid du Colombier 	if(n == 0){
4787dd7cddfSDavid du Colombier 		q->pat = nil;
4797dd7cddfSDavid du Colombier 		q->up = nil;
4807dd7cddfSDavid du Colombier 		q->len = -1;
4817dd7cddfSDavid du Colombier 		return;
4827dd7cddfSDavid du Colombier 	}
4837dd7cddfSDavid du Colombier 	pat = emalloc(2* n + 2);
4847dd7cddfSDavid du Colombier 	q->pat = pat;
4857dd7cddfSDavid du Colombier 	up = pat;
4867dd7cddfSDavid du Colombier 	if(ignorecase)
4877dd7cddfSDavid du Colombier 		up = pat + n + 1;
4887dd7cddfSDavid du Colombier 	q->up = up;
4897dd7cddfSDavid du Colombier 	while(c = *spat++){
4907dd7cddfSDavid du Colombier 		if(ignorecase){
4917dd7cddfSDavid du Colombier 			*up++ = toupper(c);
4927dd7cddfSDavid du Colombier 			c = tolower(c);
4937dd7cddfSDavid du Colombier 		}
4947dd7cddfSDavid du Colombier 		*pat++ = c;
4957dd7cddfSDavid du Colombier 	}
4967dd7cddfSDavid du Colombier 	pat = q->pat;
4977dd7cddfSDavid du Colombier 	up = q->up;
4987dd7cddfSDavid du Colombier 	pat[n] = up[n] = '\0';
4997dd7cddfSDavid du Colombier 
5007dd7cddfSDavid du Colombier 	/*
5017dd7cddfSDavid du Colombier 	 * make the skipping table
5027dd7cddfSDavid du Colombier 	 */
5037dd7cddfSDavid du Colombier 	if(n > 255)
5047dd7cddfSDavid du Colombier 		n = 255;
5057dd7cddfSDavid du Colombier 	j = q->jump;
5067dd7cddfSDavid du Colombier 	memset(j, n, 256);
5077dd7cddfSDavid du Colombier 	n--;
5087dd7cddfSDavid du Colombier 	q->len = n;
5097dd7cddfSDavid du Colombier 	for(i = 0; i <= n; i++){
5107dd7cddfSDavid du Colombier 		j[(uchar)pat[i]] = n - i;
5117dd7cddfSDavid du Colombier 		j[(uchar)up[i]] = n - i;
5127dd7cddfSDavid du Colombier 	}
5137dd7cddfSDavid du Colombier 
5147dd7cddfSDavid du Colombier 	/*
5157dd7cddfSDavid du Colombier 	 * find the minimum safe amount to skip
5167dd7cddfSDavid du Colombier 	 * if we match the last char but not the whole pat
5177dd7cddfSDavid du Colombier 	 */
5187dd7cddfSDavid du Colombier 	ep = pat[n];
5197dd7cddfSDavid du Colombier 	ea = up[n];
5207dd7cddfSDavid du Colombier 	for(i = n - 1; i >= 0; i--){
5217dd7cddfSDavid du Colombier 		cp = pat[i];
5227dd7cddfSDavid du Colombier 		ca = up[i];
5237dd7cddfSDavid du Colombier 		if(cp == ep || cp == ea || ca == ep || ca == ea)
5247dd7cddfSDavid du Colombier 			break;
5257dd7cddfSDavid du Colombier 	}
5267dd7cddfSDavid du Colombier 	q->miss = n - i;
5277dd7cddfSDavid du Colombier }
5287dd7cddfSDavid du Colombier 
5297dd7cddfSDavid du Colombier void
quickfree(Quick * q)5307dd7cddfSDavid du Colombier quickfree(Quick *q)
5317dd7cddfSDavid du Colombier {
5327dd7cddfSDavid du Colombier 	if(q->pat != nil)
5337dd7cddfSDavid du Colombier 		free(q->pat);
5347dd7cddfSDavid du Colombier 	q->pat = nil;
5357dd7cddfSDavid du Colombier }
5367dd7cddfSDavid du Colombier 
5377dd7cddfSDavid du Colombier char *
quicksearch(Quick * q,char * s,char * e)5387dd7cddfSDavid du Colombier quicksearch(Quick *q, char *s, char *e)
5397dd7cddfSDavid du Colombier {
5407dd7cddfSDavid du Colombier 	char *pat, *up, *m, *ee;
5417dd7cddfSDavid du Colombier 	uchar *j;
5427dd7cddfSDavid du Colombier 	int len, n, c, mc;
5437dd7cddfSDavid du Colombier 
5447dd7cddfSDavid du Colombier 	len = q->len;
5457dd7cddfSDavid du Colombier 	if(len < 0)
5467dd7cddfSDavid du Colombier 		return s;
5477dd7cddfSDavid du Colombier 	j = q->jump;
5487dd7cddfSDavid du Colombier 	pat = q->pat;
5497dd7cddfSDavid du Colombier 	up = q->up;
5507dd7cddfSDavid du Colombier 	s += len;
5517dd7cddfSDavid du Colombier 	ee = e - (len * 4 + 4);
5527dd7cddfSDavid du Colombier 	while(s < e){
5537dd7cddfSDavid du Colombier 		/*
5547dd7cddfSDavid du Colombier 		 * look for a match on the last char
5557dd7cddfSDavid du Colombier 		 */
5567dd7cddfSDavid du Colombier 		while(s < ee && (n = j[(uchar)*s])){
5577dd7cddfSDavid du Colombier 			s += n;
5587dd7cddfSDavid du Colombier 			s += j[(uchar)*s];
5597dd7cddfSDavid du Colombier 			s += j[(uchar)*s];
5607dd7cddfSDavid du Colombier 			s += j[(uchar)*s];
5617dd7cddfSDavid du Colombier 		}
5627dd7cddfSDavid du Colombier 		if(s >= e)
5637dd7cddfSDavid du Colombier 			return nil;
5647dd7cddfSDavid du Colombier 		while(n = j[(uchar)*s]){
5657dd7cddfSDavid du Colombier 			s += n;
5667dd7cddfSDavid du Colombier 			if(s >= e)
5677dd7cddfSDavid du Colombier 				return nil;
5687dd7cddfSDavid du Colombier 		}
5697dd7cddfSDavid du Colombier 
5707dd7cddfSDavid du Colombier 		/*
5717dd7cddfSDavid du Colombier 		 * does the string match?
5727dd7cddfSDavid du Colombier 		 */
5737dd7cddfSDavid du Colombier 		m = s - len;
5747dd7cddfSDavid du Colombier 		for(n = 0; c = pat[n]; n++){
5757dd7cddfSDavid du Colombier 			mc = *m++;
5767dd7cddfSDavid du Colombier 			if(c != mc && mc != up[n])
5777dd7cddfSDavid du Colombier 				break;
5787dd7cddfSDavid du Colombier 		}
5797dd7cddfSDavid du Colombier 		if(!c)
5807dd7cddfSDavid du Colombier 			return s - len;
5817dd7cddfSDavid du Colombier 		s += q->miss;
5827dd7cddfSDavid du Colombier 	}
5837dd7cddfSDavid du Colombier 	return nil;
5847dd7cddfSDavid du Colombier }
5857dd7cddfSDavid du Colombier 
5867dd7cddfSDavid du Colombier void
fsrun(Fs * fs,int fd)5877dd7cddfSDavid du Colombier fsrun(Fs *fs, int fd)
5887dd7cddfSDavid du Colombier {
5897dd7cddfSDavid du Colombier 	Fcall rpc;
590*9a747e4fSDavid du Colombier 	char *err;
591*9a747e4fSDavid du Colombier 	uchar *buf;
5927dd7cddfSDavid du Colombier 	int n;
5937dd7cddfSDavid du Colombier 
594*9a747e4fSDavid du Colombier 	buf = emalloc(messagesize);
5957dd7cddfSDavid du Colombier 	for(;;){
5967dd7cddfSDavid du Colombier 		/*
5977dd7cddfSDavid du Colombier 		 * reading from a pipe or a network device
5987dd7cddfSDavid du Colombier 		 * will give an error after a few eof reads
5997dd7cddfSDavid du Colombier 		 * however, we cannot tell the difference
6007dd7cddfSDavid du Colombier 		 * between a zero-length read and an interrupt
6017dd7cddfSDavid du Colombier 		 * on the processes writing to us,
6027dd7cddfSDavid du Colombier 		 * so we wait for the error
6037dd7cddfSDavid du Colombier 		 */
604*9a747e4fSDavid du Colombier 		n = read9pmsg(fd, buf, messagesize);
6057dd7cddfSDavid du Colombier 		if(n == 0)
6067dd7cddfSDavid du Colombier 			continue;
6077dd7cddfSDavid du Colombier 		if(n < 0)
6087dd7cddfSDavid du Colombier 			fatal("mount read");
6097dd7cddfSDavid du Colombier 
610*9a747e4fSDavid du Colombier 		rpc.data = (char*)buf + IOHDRSZ;
611*9a747e4fSDavid du Colombier 		if(convM2S(buf, n, &rpc) == 0)
6127dd7cddfSDavid du Colombier 			continue;
613*9a747e4fSDavid du Colombier 		// fprint(2, "recv: %F\n", &rpc);
614*9a747e4fSDavid du Colombier 
6157dd7cddfSDavid du Colombier 
6167dd7cddfSDavid du Colombier 		/*
6177dd7cddfSDavid du Colombier 		 * flushes are way too hard.
6187dd7cddfSDavid du Colombier 		 * a reply to the original message seems to work
6197dd7cddfSDavid du Colombier 		 */
6207dd7cddfSDavid du Colombier 		if(rpc.type == Tflush)
6217dd7cddfSDavid du Colombier 			continue;
6227dd7cddfSDavid du Colombier 		else if(rpc.type >= Tmax || !fcalls[rpc.type])
6237dd7cddfSDavid du Colombier 			err = "bad fcall type";
6247dd7cddfSDavid du Colombier 		else
6257dd7cddfSDavid du Colombier 			err = (*fcalls[rpc.type])(fs, &rpc);
6267dd7cddfSDavid du Colombier 		if(err){
6277dd7cddfSDavid du Colombier 			rpc.type = Rerror;
628*9a747e4fSDavid du Colombier 			rpc.ename = err;
629*9a747e4fSDavid du Colombier 		}else
6307dd7cddfSDavid du Colombier 			rpc.type++;
631*9a747e4fSDavid du Colombier 		n = convS2M(&rpc, buf, messagesize);
632*9a747e4fSDavid du Colombier 		// fprint(2, "send: %F\n", &rpc);
6337dd7cddfSDavid du Colombier 		if(write(fd, buf, n) != n)
6347dd7cddfSDavid du Colombier 			fatal("mount write");
6357dd7cddfSDavid du Colombier 	}
6367dd7cddfSDavid du Colombier }
6377dd7cddfSDavid du Colombier 
6387dd7cddfSDavid du Colombier Fid*
mkfid(Fs * fs,uint fid)6397dd7cddfSDavid du Colombier mkfid(Fs *fs, uint fid)
6407dd7cddfSDavid du Colombier {
6417dd7cddfSDavid du Colombier 	Fid *f;
6427dd7cddfSDavid du Colombier 	int h;
6437dd7cddfSDavid du Colombier 
6447dd7cddfSDavid du Colombier 	h = fid % Nfidhash;
6457dd7cddfSDavid du Colombier 	for(f = fs->hash[h]; f; f = f->next){
646*9a747e4fSDavid du Colombier 		if(f->fid == fid)
6477dd7cddfSDavid du Colombier 			return nil;
6487dd7cddfSDavid du Colombier 	}
6497dd7cddfSDavid du Colombier 
6507dd7cddfSDavid du Colombier 	f = emalloc(sizeof *f);
6517dd7cddfSDavid du Colombier 	f->next = fs->hash[h];
6527dd7cddfSDavid du Colombier 	if(f->next != nil)
6537dd7cddfSDavid du Colombier 		f->next->last = &f->next;
6547dd7cddfSDavid du Colombier 	f->last = &fs->hash[h];
6557dd7cddfSDavid du Colombier 	fs->hash[h] = f;
6567dd7cddfSDavid du Colombier 
6577dd7cddfSDavid du Colombier 	f->fid = fid;
6587dd7cddfSDavid du Colombier 	f->ref = 1;
6597dd7cddfSDavid du Colombier 	f->attached = 1;
6607dd7cddfSDavid du Colombier 	f->open = 0;
6617dd7cddfSDavid du Colombier 	return f;
6627dd7cddfSDavid du Colombier }
6637dd7cddfSDavid du Colombier 
6647dd7cddfSDavid du Colombier Fid*
getfid(Fs * fs,uint fid)6657dd7cddfSDavid du Colombier getfid(Fs *fs, uint fid)
6667dd7cddfSDavid du Colombier {
6677dd7cddfSDavid du Colombier 	Fid *f;
6687dd7cddfSDavid du Colombier 	int h;
6697dd7cddfSDavid du Colombier 
6707dd7cddfSDavid du Colombier 	h = fid % Nfidhash;
6717dd7cddfSDavid du Colombier 	for(f = fs->hash[h]; f; f = f->next){
6727dd7cddfSDavid du Colombier 		if(f->fid == fid){
6737dd7cddfSDavid du Colombier 			if(f->attached == 0)
6747dd7cddfSDavid du Colombier 				break;
6757dd7cddfSDavid du Colombier 			f->ref++;
6767dd7cddfSDavid du Colombier 			return f;
6777dd7cddfSDavid du Colombier 		}
6787dd7cddfSDavid du Colombier 	}
6797dd7cddfSDavid du Colombier 	return nil;
6807dd7cddfSDavid du Colombier }
6817dd7cddfSDavid du Colombier 
6827dd7cddfSDavid du Colombier void
putfid(Fs *,Fid * f)683*9a747e4fSDavid du Colombier putfid(Fs *, Fid *f)
6847dd7cddfSDavid du Colombier {
6857dd7cddfSDavid du Colombier 	f->ref--;
6867dd7cddfSDavid du Colombier 	if(f->ref == 0 && f->attached == 0){
6877dd7cddfSDavid du Colombier 		*f->last = f->next;
6887dd7cddfSDavid du Colombier 		if(f->next != nil)
6897dd7cddfSDavid du Colombier 			f->next->last = f->last;
6907dd7cddfSDavid du Colombier 		if(f->search != nil)
6917dd7cddfSDavid du Colombier 			searchfree(f->search);
6927dd7cddfSDavid du Colombier 		free(f);
6937dd7cddfSDavid du Colombier 	}
6947dd7cddfSDavid du Colombier }
6957dd7cddfSDavid du Colombier 
6967dd7cddfSDavid du Colombier char*
fsversion(Fs *,Fcall * rpc)697*9a747e4fSDavid du Colombier fsversion(Fs *, Fcall *rpc)
6987dd7cddfSDavid du Colombier {
699*9a747e4fSDavid du Colombier 	if(rpc->msize < 256)
700*9a747e4fSDavid du Colombier 		return "version: message size too small";
701*9a747e4fSDavid du Colombier 	if(rpc->msize > messagesize)
702*9a747e4fSDavid du Colombier 		rpc->msize = messagesize;
703*9a747e4fSDavid du Colombier 	messagesize = rpc->msize;
704*9a747e4fSDavid du Colombier 	if(strncmp(rpc->version, "9P2000", 6) != 0)
705*9a747e4fSDavid du Colombier 		return "unrecognized 9P version";
706*9a747e4fSDavid du Colombier 	rpc->version = "9P2000";
7077dd7cddfSDavid du Colombier 	return nil;
7087dd7cddfSDavid du Colombier }
7097dd7cddfSDavid du Colombier 
7107dd7cddfSDavid du Colombier char*
fsauth(Fs *,Fcall *)711*9a747e4fSDavid du Colombier fsauth(Fs *, Fcall *)
7127dd7cddfSDavid du Colombier {
713*9a747e4fSDavid du Colombier 	return "searchfs: authentication not required";
7147dd7cddfSDavid du Colombier }
7157dd7cddfSDavid du Colombier 
7167dd7cddfSDavid du Colombier char*
fsattach(Fs * fs,Fcall * rpc)7177dd7cddfSDavid du Colombier fsattach(Fs *fs, Fcall *rpc)
7187dd7cddfSDavid du Colombier {
7197dd7cddfSDavid du Colombier 	Fid *f;
7207dd7cddfSDavid du Colombier 
7217dd7cddfSDavid du Colombier 	f = mkfid(fs, rpc->fid);
7227dd7cddfSDavid du Colombier 	if(f == nil)
7237dd7cddfSDavid du Colombier 		return Einuse;
7247dd7cddfSDavid du Colombier 	f->open = 0;
725*9a747e4fSDavid du Colombier 	f->qid.type = QTDIR;
7267dd7cddfSDavid du Colombier 	f->qid.path = Qroot;
7277dd7cddfSDavid du Colombier 	f->qid.vers = 0;
7287dd7cddfSDavid du Colombier 	rpc->qid = f->qid;
7297dd7cddfSDavid du Colombier 	putfid(fs, f);
7307dd7cddfSDavid du Colombier 	return nil;
7317dd7cddfSDavid du Colombier }
7327dd7cddfSDavid du Colombier 
7337dd7cddfSDavid du Colombier char*
fswalk(Fs * fs,Fcall * rpc)7347dd7cddfSDavid du Colombier fswalk(Fs *fs, Fcall *rpc)
7357dd7cddfSDavid du Colombier {
736*9a747e4fSDavid du Colombier 	Fid *f, *nf;
737*9a747e4fSDavid du Colombier 	int nqid, nwname, type;
738*9a747e4fSDavid du Colombier 	char *err, *name;
739*9a747e4fSDavid du Colombier 	ulong path;
7407dd7cddfSDavid du Colombier 
7417dd7cddfSDavid du Colombier 	f = getfid(fs, rpc->fid);
7427dd7cddfSDavid du Colombier 	if(f == nil)
7437dd7cddfSDavid du Colombier 		return Enofid;
744*9a747e4fSDavid du Colombier 	nf = nil;
745*9a747e4fSDavid du Colombier 	if(rpc->fid != rpc->newfid){
746*9a747e4fSDavid du Colombier 		nf = mkfid(fs, rpc->newfid);
747*9a747e4fSDavid du Colombier 		if(nf == nil){
7487dd7cddfSDavid du Colombier 			putfid(fs, f);
749*9a747e4fSDavid du Colombier 			return Einuse;
7507dd7cddfSDavid du Colombier 		}
751*9a747e4fSDavid du Colombier 		nf->qid = f->qid;
7527dd7cddfSDavid du Colombier 		putfid(fs, f);
753*9a747e4fSDavid du Colombier 		f = nf;	/* walk f */
7547dd7cddfSDavid du Colombier 	}
755*9a747e4fSDavid du Colombier 
756*9a747e4fSDavid du Colombier 	err = nil;
757*9a747e4fSDavid du Colombier 	path = f->qid.path;
758*9a747e4fSDavid du Colombier 	nwname = rpc->nwname;
759*9a747e4fSDavid du Colombier 	for(nqid=0; nqid<nwname; nqid++){
760*9a747e4fSDavid du Colombier 		if(path != Qroot){
761*9a747e4fSDavid du Colombier 			err = Enotdir;
762*9a747e4fSDavid du Colombier 			break;
763*9a747e4fSDavid du Colombier 		}
764*9a747e4fSDavid du Colombier 		name = rpc->wname[nqid];
765*9a747e4fSDavid du Colombier 		if(strcmp(name, "search") == 0){
766*9a747e4fSDavid du Colombier 			type = QTFILE;
767*9a747e4fSDavid du Colombier 			path = Qsearch;
768*9a747e4fSDavid du Colombier 		}else if(strcmp(name, "stats") == 0){
769*9a747e4fSDavid du Colombier 			type = QTFILE;
770*9a747e4fSDavid du Colombier 			path = Qstats;
771*9a747e4fSDavid du Colombier 		}else if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0){
772*9a747e4fSDavid du Colombier 			type = QTDIR;
773*9a747e4fSDavid du Colombier 			path = path;
774*9a747e4fSDavid du Colombier 		}else{
775*9a747e4fSDavid du Colombier 			err = Enotexist;
776*9a747e4fSDavid du Colombier 			break;
777*9a747e4fSDavid du Colombier 		}
778*9a747e4fSDavid du Colombier 		rpc->wqid[nqid] = (Qid){path, 0, type};
779*9a747e4fSDavid du Colombier 	}
780*9a747e4fSDavid du Colombier 
781*9a747e4fSDavid du Colombier 	if(nwname > 0){
782*9a747e4fSDavid du Colombier 		if(nf != nil && nqid < nwname)
783*9a747e4fSDavid du Colombier 			nf->attached = 0;
784*9a747e4fSDavid du Colombier 		if(nqid == nwname)
785*9a747e4fSDavid du Colombier 			f->qid = rpc->wqid[nqid-1];
786*9a747e4fSDavid du Colombier 	}
787*9a747e4fSDavid du Colombier 
788*9a747e4fSDavid du Colombier 	putfid(fs, f);
789*9a747e4fSDavid du Colombier 	rpc->nwqid = nqid;
7907dd7cddfSDavid du Colombier 	f->open = 0;
791*9a747e4fSDavid du Colombier 	return err;
7927dd7cddfSDavid du Colombier }
7937dd7cddfSDavid du Colombier 
7947dd7cddfSDavid du Colombier char *
fsopen(Fs * fs,Fcall * rpc)7957dd7cddfSDavid du Colombier fsopen(Fs *fs, Fcall *rpc)
7967dd7cddfSDavid du Colombier {
7977dd7cddfSDavid du Colombier 	Fid *f;
7987dd7cddfSDavid du Colombier 	int mode;
7997dd7cddfSDavid du Colombier 
8007dd7cddfSDavid du Colombier 	f = getfid(fs, rpc->fid);
8017dd7cddfSDavid du Colombier 	if(f == nil)
8027dd7cddfSDavid du Colombier 		return Enofid;
8037dd7cddfSDavid du Colombier 	if(f->open){
8047dd7cddfSDavid du Colombier 		putfid(fs, f);
8057dd7cddfSDavid du Colombier 		return Eisopen;
8067dd7cddfSDavid du Colombier 	}
8077dd7cddfSDavid du Colombier 	mode = rpc->mode & OPERM;
8087dd7cddfSDavid du Colombier 	if(mode == OEXEC
8097dd7cddfSDavid du Colombier 	|| f->qid.path == Qroot && (mode == OWRITE || mode == ORDWR)){
8107dd7cddfSDavid du Colombier 		putfid(fs, f);
8117dd7cddfSDavid du Colombier 		return Eperm;
8127dd7cddfSDavid du Colombier 	}
8137dd7cddfSDavid du Colombier 	f->open = 1;
8147dd7cddfSDavid du Colombier 	f->where = nil;
8157dd7cddfSDavid du Colombier 	f->n = 0;
8167dd7cddfSDavid du Colombier 	f->search = nil;
8177dd7cddfSDavid du Colombier 	rpc->qid = f->qid;
818*9a747e4fSDavid du Colombier 	rpc->iounit = messagesize-IOHDRSZ;
8197dd7cddfSDavid du Colombier 	putfid(fs, f);
8207dd7cddfSDavid du Colombier 	return nil;
8217dd7cddfSDavid du Colombier }
8227dd7cddfSDavid du Colombier 
8237dd7cddfSDavid du Colombier char *
fscreate(Fs *,Fcall *)8247dd7cddfSDavid du Colombier fscreate(Fs *, Fcall *)
8257dd7cddfSDavid du Colombier {
8267dd7cddfSDavid du Colombier 	return Eperm;
8277dd7cddfSDavid du Colombier }
8287dd7cddfSDavid du Colombier 
8297dd7cddfSDavid du Colombier char*
fsread(Fs * fs,Fcall * rpc)8307dd7cddfSDavid du Colombier fsread(Fs *fs, Fcall *rpc)
8317dd7cddfSDavid du Colombier {
8327dd7cddfSDavid du Colombier 	Fid *f;
8337dd7cddfSDavid du Colombier 	int n, off, count, len;
8347dd7cddfSDavid du Colombier 
8357dd7cddfSDavid du Colombier 	f = getfid(fs, rpc->fid);
8367dd7cddfSDavid du Colombier 	if(f == nil)
8377dd7cddfSDavid du Colombier 		return Enofid;
8387dd7cddfSDavid du Colombier 	if(!f->open){
8397dd7cddfSDavid du Colombier 		putfid(fs, f);
8407dd7cddfSDavid du Colombier 		return Enotopen;
8417dd7cddfSDavid du Colombier 	}
8427dd7cddfSDavid du Colombier 	count = rpc->count;
8437dd7cddfSDavid du Colombier 	off = rpc->offset;
8447dd7cddfSDavid du Colombier 	rpc->count = 0;
8457dd7cddfSDavid du Colombier 	if(f->qid.path == Qroot){
8467dd7cddfSDavid du Colombier 		if(off > 0)
8477dd7cddfSDavid du Colombier 			rpc->count = 0;
848*9a747e4fSDavid du Colombier 		else
849*9a747e4fSDavid du Colombier 			rpc->count = dostat(Qsearch, (uchar*)rpc->data, count);
8507dd7cddfSDavid du Colombier 		putfid(fs, f);
851*9a747e4fSDavid du Colombier 		if(off == 0 && rpc->count <= BIT16SZ)
852*9a747e4fSDavid du Colombier 			return "directory read count too small";
8537dd7cddfSDavid du Colombier 		return nil;
8547dd7cddfSDavid du Colombier 	}
8557dd7cddfSDavid du Colombier 	if(f->qid.path == Qstats){
8567dd7cddfSDavid du Colombier 		len = 0;
8577dd7cddfSDavid du Colombier 	}else{
8587dd7cddfSDavid du Colombier 		for(len = 0; len < count; len += n){
8597dd7cddfSDavid du Colombier 			if(f->where == nil || f->search == nil)
8607dd7cddfSDavid du Colombier 				break;
8617dd7cddfSDavid du Colombier 			if(f->n == 0)
8627dd7cddfSDavid du Colombier 				f->where = searchsearch(f->search, f->where, edatabase, &f->n);
8637dd7cddfSDavid du Colombier 			n = f->n;
8647dd7cddfSDavid du Colombier 			if(n != 0){
8657dd7cddfSDavid du Colombier 				if(n > count-len)
8667dd7cddfSDavid du Colombier 					n = count-len;
8677dd7cddfSDavid du Colombier 				memmove(rpc->data+len, f->where, n);
8687dd7cddfSDavid du Colombier 				f->where += n;
8697dd7cddfSDavid du Colombier 				f->n -= n;
8707dd7cddfSDavid du Colombier 			}
8717dd7cddfSDavid du Colombier 		}
8727dd7cddfSDavid du Colombier 	}
8737dd7cddfSDavid du Colombier 	putfid(fs, f);
8747dd7cddfSDavid du Colombier 	rpc->count = len;
8757dd7cddfSDavid du Colombier 	return nil;
8767dd7cddfSDavid du Colombier }
8777dd7cddfSDavid du Colombier 
8787dd7cddfSDavid du Colombier char*
fswrite(Fs * fs,Fcall * rpc)8797dd7cddfSDavid du Colombier fswrite(Fs *fs, Fcall *rpc)
8807dd7cddfSDavid du Colombier {
8817dd7cddfSDavid du Colombier 	Fid *f;
8827dd7cddfSDavid du Colombier 
8837dd7cddfSDavid du Colombier 	f = getfid(fs, rpc->fid);
8847dd7cddfSDavid du Colombier 	if(f == nil)
8857dd7cddfSDavid du Colombier 		return Enofid;
8867dd7cddfSDavid du Colombier 	if(!f->open || f->qid.path != Qsearch){
8877dd7cddfSDavid du Colombier 		putfid(fs, f);
8887dd7cddfSDavid du Colombier 		return Enotopen;
8897dd7cddfSDavid du Colombier 	}
8907dd7cddfSDavid du Colombier 
8917dd7cddfSDavid du Colombier 	if(f->search != nil)
8927dd7cddfSDavid du Colombier 		searchfree(f->search);
8937dd7cddfSDavid du Colombier 	f->search = searchparse(rpc->data, rpc->data + rpc->count);
8947dd7cddfSDavid du Colombier 	if(f->search == nil){
8957dd7cddfSDavid du Colombier 		putfid(fs, f);
8967dd7cddfSDavid du Colombier 		return Ebadsearch;
8977dd7cddfSDavid du Colombier 	}
8987dd7cddfSDavid du Colombier 	f->where = database;
8997dd7cddfSDavid du Colombier 	f->n = 0;
9007dd7cddfSDavid du Colombier 	putfid(fs, f);
9017dd7cddfSDavid du Colombier 	return nil;
9027dd7cddfSDavid du Colombier }
9037dd7cddfSDavid du Colombier 
9047dd7cddfSDavid du Colombier char *
fsclunk(Fs * fs,Fcall * rpc)9057dd7cddfSDavid du Colombier fsclunk(Fs *fs, Fcall *rpc)
9067dd7cddfSDavid du Colombier {
9077dd7cddfSDavid du Colombier 	Fid *f;
9087dd7cddfSDavid du Colombier 
9097dd7cddfSDavid du Colombier 	f = getfid(fs, rpc->fid);
9107dd7cddfSDavid du Colombier 	if(f != nil){
9117dd7cddfSDavid du Colombier 		f->attached = 0;
9127dd7cddfSDavid du Colombier 		putfid(fs, f);
9137dd7cddfSDavid du Colombier 	}
9147dd7cddfSDavid du Colombier 	return nil;
9157dd7cddfSDavid du Colombier }
9167dd7cddfSDavid du Colombier 
9177dd7cddfSDavid du Colombier char *
fsremove(Fs *,Fcall *)9187dd7cddfSDavid du Colombier fsremove(Fs *, Fcall *)
9197dd7cddfSDavid du Colombier {
9207dd7cddfSDavid du Colombier 	return Eperm;
9217dd7cddfSDavid du Colombier }
9227dd7cddfSDavid du Colombier 
9237dd7cddfSDavid du Colombier char *
fsstat(Fs * fs,Fcall * rpc)9247dd7cddfSDavid du Colombier fsstat(Fs *fs, Fcall *rpc)
9257dd7cddfSDavid du Colombier {
9267dd7cddfSDavid du Colombier 	Fid *f;
9277dd7cddfSDavid du Colombier 
9287dd7cddfSDavid du Colombier 	f = getfid(fs, rpc->fid);
9297dd7cddfSDavid du Colombier 	if(f == nil)
9307dd7cddfSDavid du Colombier 		return Enofid;
931*9a747e4fSDavid du Colombier 	rpc->stat = fs->statbuf;
932*9a747e4fSDavid du Colombier 	rpc->nstat = dostat(f->qid.path, rpc->stat, sizeof fs->statbuf);
9337dd7cddfSDavid du Colombier 	putfid(fs, f);
934*9a747e4fSDavid du Colombier 	if(rpc->nstat <= BIT16SZ)
935*9a747e4fSDavid du Colombier 		return "stat count too small";
9367dd7cddfSDavid du Colombier 	return nil;
9377dd7cddfSDavid du Colombier }
9387dd7cddfSDavid du Colombier 
9397dd7cddfSDavid du Colombier char *
fswstat(Fs *,Fcall *)9407dd7cddfSDavid du Colombier fswstat(Fs *, Fcall *)
9417dd7cddfSDavid du Colombier {
9427dd7cddfSDavid du Colombier 	return Eperm;
9437dd7cddfSDavid du Colombier }
9447dd7cddfSDavid du Colombier 
945*9a747e4fSDavid du Colombier int
dostat(int path,uchar * buf,int nbuf)946*9a747e4fSDavid du Colombier dostat(int path, uchar *buf, int nbuf)
9477dd7cddfSDavid du Colombier {
9487dd7cddfSDavid du Colombier 	Dir d;
9497dd7cddfSDavid du Colombier 
9507dd7cddfSDavid du Colombier 	switch(path){
9517dd7cddfSDavid du Colombier 	case Qroot:
952*9a747e4fSDavid du Colombier 		d.name = ".";
953*9a747e4fSDavid du Colombier 		d.mode = DMDIR|0555;
954*9a747e4fSDavid du Colombier 		d.qid.type = QTDIR;
9557dd7cddfSDavid du Colombier 		break;
9567dd7cddfSDavid du Colombier 	case Qsearch:
957*9a747e4fSDavid du Colombier 		d.name = "search";
9587dd7cddfSDavid du Colombier 		d.mode = 0666;
959*9a747e4fSDavid du Colombier 		d.qid.type = QTFILE;
9607dd7cddfSDavid du Colombier 		break;
9617dd7cddfSDavid du Colombier 	case Qstats:
962*9a747e4fSDavid du Colombier 		d.name = "stats";
9637dd7cddfSDavid du Colombier 		d.mode = 0666;
964*9a747e4fSDavid du Colombier 		d.qid.type = QTFILE;
9657dd7cddfSDavid du Colombier 		break;
9667dd7cddfSDavid du Colombier 	}
9677dd7cddfSDavid du Colombier 	d.qid.path = path;
9687dd7cddfSDavid du Colombier 	d.qid.vers = 0;
9697dd7cddfSDavid du Colombier 	d.length = 0;
970*9a747e4fSDavid du Colombier 	d.uid = d.gid = d.muid = "none";
9717dd7cddfSDavid du Colombier 	d.atime = d.mtime = time(nil);
972*9a747e4fSDavid du Colombier 	return convD2M(&d, buf, nbuf);
9737dd7cddfSDavid du Colombier }
9747dd7cddfSDavid du Colombier 
9757dd7cddfSDavid du Colombier char *
urlunesc(char * s,char * e)9767dd7cddfSDavid du Colombier urlunesc(char *s, char *e)
9777dd7cddfSDavid du Colombier {
9787dd7cddfSDavid du Colombier 	char *t, *v;
9797dd7cddfSDavid du Colombier 	int c, n;
9807dd7cddfSDavid du Colombier 
9817dd7cddfSDavid du Colombier 	v = emalloc((e - s) + 1);
9827dd7cddfSDavid du Colombier 	for(t = v; s < e; s++){
9837dd7cddfSDavid du Colombier 		c = *s;
9847dd7cddfSDavid du Colombier 		if(c == '%'){
9857dd7cddfSDavid du Colombier 			if(s + 2 >= e)
9867dd7cddfSDavid du Colombier 				break;
9877dd7cddfSDavid du Colombier 			n = s[1];
9887dd7cddfSDavid du Colombier 			if(n >= '0' && n <= '9')
9897dd7cddfSDavid du Colombier 				n = n - '0';
9907dd7cddfSDavid du Colombier 			else if(n >= 'A' && n <= 'F')
9917dd7cddfSDavid du Colombier 				n = n - 'A' + 10;
9927dd7cddfSDavid du Colombier 			else if(n >= 'a' && n <= 'f')
9937dd7cddfSDavid du Colombier 				n = n - 'a' + 10;
9947dd7cddfSDavid du Colombier 			else
9957dd7cddfSDavid du Colombier 				break;
9967dd7cddfSDavid du Colombier 			c = n;
9977dd7cddfSDavid du Colombier 			n = s[2];
9987dd7cddfSDavid du Colombier 			if(n >= '0' && n <= '9')
9997dd7cddfSDavid du Colombier 				n = n - '0';
10007dd7cddfSDavid du Colombier 			else if(n >= 'A' && n <= 'F')
10017dd7cddfSDavid du Colombier 				n = n - 'A' + 10;
10027dd7cddfSDavid du Colombier 			else if(n >= 'a' && n <= 'f')
10037dd7cddfSDavid du Colombier 				n = n - 'a' + 10;
10047dd7cddfSDavid du Colombier 			else
10057dd7cddfSDavid du Colombier 				break;
10067dd7cddfSDavid du Colombier 			s += 2;
10077dd7cddfSDavid du Colombier 			c = c * 16 + n;
10087dd7cddfSDavid du Colombier 		}
10097dd7cddfSDavid du Colombier 		*t++ = c;
10107dd7cddfSDavid du Colombier 	}
10117dd7cddfSDavid du Colombier 	*t = 0;
10127dd7cddfSDavid du Colombier 	return v;
10137dd7cddfSDavid du Colombier }
10147dd7cddfSDavid du Colombier 
10157dd7cddfSDavid du Colombier int
toupper(int c)10167dd7cddfSDavid du Colombier toupper(int c)
10177dd7cddfSDavid du Colombier {
10187dd7cddfSDavid du Colombier 	if(c >= 'a' && c <= 'z')
10197dd7cddfSDavid du Colombier 		c += 'A' - 'a';
10207dd7cddfSDavid du Colombier 	return c;
10217dd7cddfSDavid du Colombier }
10227dd7cddfSDavid du Colombier 
10237dd7cddfSDavid du Colombier int
tolower(int c)10247dd7cddfSDavid du Colombier tolower(int c)
10257dd7cddfSDavid du Colombier {
10267dd7cddfSDavid du Colombier 	if(c >= 'A' && c <= 'Z')
10277dd7cddfSDavid du Colombier 		c += 'a' - 'A';
10287dd7cddfSDavid du Colombier 	return c;
10297dd7cddfSDavid du Colombier }
10307dd7cddfSDavid du Colombier 
10317dd7cddfSDavid du Colombier void
fatal(char * fmt,...)10327dd7cddfSDavid du Colombier fatal(char *fmt, ...)
10337dd7cddfSDavid du Colombier {
10347dd7cddfSDavid du Colombier 	va_list arg;
10357dd7cddfSDavid du Colombier 	char buf[1024];
10367dd7cddfSDavid du Colombier 
10377dd7cddfSDavid du Colombier 	write(2, "searchfs: ", 8);
10387dd7cddfSDavid du Colombier 	va_start(arg, fmt);
1039*9a747e4fSDavid du Colombier 	vseprint(buf, buf+1024, fmt, arg);
10407dd7cddfSDavid du Colombier 	va_end(arg);
10417dd7cddfSDavid du Colombier 	write(2, buf, strlen(buf));
10427dd7cddfSDavid du Colombier 	write(2, "\n", 1);
10437dd7cddfSDavid du Colombier 	exits(fmt);
10447dd7cddfSDavid du Colombier }
10457dd7cddfSDavid du Colombier 
10467dd7cddfSDavid du Colombier void *
emalloc(uint n)10477dd7cddfSDavid du Colombier emalloc(uint n)
10487dd7cddfSDavid du Colombier {
10497dd7cddfSDavid du Colombier 	void *p;
10507dd7cddfSDavid du Colombier 
10517dd7cddfSDavid du Colombier 	p = malloc(n);
10527dd7cddfSDavid du Colombier 	if(p == nil)
10537dd7cddfSDavid du Colombier 		fatal("out of memory");
10547dd7cddfSDavid du Colombier 	memset(p, 0, n);
10557dd7cddfSDavid du Colombier 	return p;
10567dd7cddfSDavid du Colombier }
10577dd7cddfSDavid du Colombier 
10587dd7cddfSDavid du Colombier void
usage(void)10597dd7cddfSDavid du Colombier usage(void)
10607dd7cddfSDavid du Colombier {
10617dd7cddfSDavid du Colombier 	fprint(2, "usage: searchfs [-m mountpoint] [-s srvfile] database\n");
10627dd7cddfSDavid du Colombier 	exits("usage");
10637dd7cddfSDavid du Colombier }
1064