Blame src/lib/libast/misc/fastfind.c

Packit 992a25
#pragma prototyped
Packit 992a25
/*
Packit 992a25
 * original code
Packit 992a25
 *
Packit 992a25
 *  	James A. Woods, Informatics General Corporation,
Packit 992a25
 *	NASA Ames Research Center, 6/81.
Packit 992a25
 *	Usenix ;login:, February/March, 1983, p. 8.
Packit 992a25
 *
Packit 992a25
 * discipline/method interface
Packit 992a25
 *
Packit 992a25
 *	Glenn Fowler
Packit 992a25
 *	AT&T Research
Packit 992a25
 *	modified from the original BSD source
Packit 992a25
 *
Packit 992a25
 * 'fastfind' scans a file list for the full pathname of a file
Packit 992a25
 * given only a piece of the name.  The list is processed with
Packit 992a25
 * with "front-compression" and bigram coding.  Front compression reduces
Packit 992a25
 * space by a factor of 4-5, bigram coding by a further 20-25%.
Packit 992a25
 *
Packit 992a25
 * there are 4 methods:
Packit 992a25
 *
Packit 992a25
 *	FF_old	original with 7 bit bigram encoding (no magic)
Packit 992a25
 *	FF_gnu	8 bit clean front compression (FF_gnu_magic)
Packit 992a25
 *	FF_dir	FF_gnu with sfgetl/sfputl and trailing / on dirs (FF_dir_magic)
Packit 992a25
 *	FF_typ	FF_dir with (mime) types (FF_typ_magic)
Packit 992a25
 *
Packit 992a25
 * the bigram encoding steals the eighth bit (that's why its FF_old)
Packit 992a25
 * maybe one day we'll limit it to readonly:
Packit 992a25
 *
Packit 992a25
 * 0-2*FF_OFF	 likeliest differential counts + offset to make nonnegative 
Packit 992a25
 * FF_ESC	 4 byte big-endian out-of-range count+FF_OFF follows
Packit 992a25
 * FF_MIN-FF_MAX ascii residue
Packit 992a25
 * >=FF_MAX	 bigram codes
Packit 992a25
 *
Packit 992a25
 * a two-tiered string search technique is employed
Packit 992a25
 *
Packit 992a25
 * a metacharacter-free subpattern and partial pathname is matched
Packit 992a25
 * backwards to avoid full expansion of the pathname list
Packit 992a25
 *
Packit 992a25
 * then the actual shell glob-style regular expression (if in this form)
Packit 992a25
 * is matched against the candidate pathnames using the slower regexec()
Packit 992a25
 *
Packit 992a25
 * The original BSD code is covered by the BSD license:
Packit 992a25
 *
Packit 992a25
 * Copyright (c) 1985, 1993, 1999
Packit 992a25
 *	The Regents of the University of California.  All rights reserved.
Packit 992a25
 *
Packit 992a25
 * Redistribution and use in source and binary forms, with or without
Packit 992a25
 * modification, are permitted provided that the following conditions
Packit 992a25
 * are met:
Packit 992a25
 * 1. Redistributions of source code must retain the above copyright
Packit 992a25
 *    notice, this list of conditions and the following disclaimer.
Packit 992a25
 * 2. Redistributions in binary form must reproduce the above copyright
Packit 992a25
 *    notice, this list of conditions and the following disclaimer in the
Packit 992a25
 *    documentation and/or other materials provided with the distribution.
Packit 992a25
 * 3. Neither the name of the University nor the names of its contributors
Packit 992a25
 *    may be used to endorse or promote products derived from this software
Packit 992a25
 *    without specific prior written permission.
Packit 992a25
 *
Packit 992a25
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
Packit 992a25
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit 992a25
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit 992a25
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
Packit 992a25
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit 992a25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
Packit 992a25
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit 992a25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
Packit 992a25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
Packit 992a25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
Packit 992a25
 * SUCH DAMAGE.
Packit 992a25
 */
Packit 992a25
Packit 992a25
static const char id[] = "\n@(#)$Id: fastfind (AT&T Research) 2002-10-02 $\0\n";
Packit 992a25
Packit 992a25
static const char lib[] = "libast:fastfind";
Packit 992a25
Packit 992a25
#include "findlib.h"
Packit 992a25
Packit 992a25
#define FIND_MATCH	"*/(find|locate)/*"
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * this db could be anywhere
Packit 992a25
 * findcodes[] directories are checked for findnames[i]
Packit 992a25
 */
Packit 992a25
Packit 992a25
static char*		findcodes[] =
Packit 992a25
{
Packit 992a25
	0,
Packit 992a25
	0,
Packit 992a25
	FIND_CODES,
Packit 992a25
	"/usr/local/share/lib",
Packit 992a25
	"/usr/local/lib",
Packit 992a25
	"/usr/share/lib",
Packit 992a25
	"/usr/lib",
Packit 992a25
	"/var/spool",
Packit 992a25
	"/usr/local/var",
Packit 992a25
	"/var/lib",
Packit 992a25
	"/var/lib/slocate",
Packit 992a25
	"/var/db",
Packit 992a25
};
Packit 992a25
Packit 992a25
static char*		findnames[] =
Packit 992a25
{
Packit 992a25
	"find/codes",
Packit 992a25
	"find/find.codes",
Packit 992a25
	"locate/locatedb",
Packit 992a25
	"locatedb",
Packit 992a25
	"locate.database",
Packit 992a25
	"slocate.db",
Packit 992a25
};
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * convert t to lower case and drop leading x- and x- after /
Packit 992a25
 * converted value copied to b of size n
Packit 992a25
 */
Packit 992a25
Packit 992a25
char*
Packit 992a25
typefix(char* buf, size_t n, register const char* t)
Packit 992a25
{
Packit 992a25
	register int	c;
Packit 992a25
	register char*	b = buf;
Packit 992a25
Packit 992a25
	if ((*t == 'x' || *t == 'X') && *(t + 1) == '-')
Packit 992a25
		t += 2;
Packit 992a25
	while (c = *t++)
Packit 992a25
	{
Packit 992a25
		if (isupper(c))
Packit 992a25
			c = tolower(c);
Packit 992a25
		if ((*b++ = c) == '/' && (*t == 'x' || *t == 'X') && *(t + 1) == '-')
Packit 992a25
			t += 2;
Packit 992a25
	}
Packit 992a25
	*b = 0;
Packit 992a25
	return buf;
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * return a fastfind stream handle for pattern
Packit 992a25
 */
Packit 992a25
Packit 992a25
Find_t*
Packit 992a25
findopen(const char* file, const char* pattern, const char* type, Finddisc_t* disc)
Packit 992a25
{
Packit 992a25
	register Find_t*	fp;
Packit 992a25
	register char*		p;
Packit 992a25
	register char*		s;
Packit 992a25
	register char*		b;
Packit 992a25
	register int		i; 
Packit 992a25
	register int		j;
Packit 992a25
	char*			path;
Packit 992a25
	int			brace = 0;
Packit 992a25
	int			paren = 0;
Packit 992a25
	int			k;
Packit 992a25
	int			q;
Packit 992a25
	int			fd;
Packit 992a25
	int			uid;
Packit 992a25
	Vmalloc_t*		vm;
Packit 992a25
	Type_t*			tp;
Packit 992a25
	struct stat		st;
Packit 992a25
Packit 992a25
Packit 992a25
	if (!(vm = vmopen(Vmdcheap, Vmbest, 0)))
Packit 992a25
		goto nospace;
Packit 992a25
Packit 992a25
	/*
Packit 992a25
	 * NOTE: searching for FIND_CODES would be much simpler if we
Packit 992a25
	 *       just stuck with our own, but we also support GNU
Packit 992a25
	 *	 locate codes and have to search for the one of a
Packit 992a25
	 *	 bazillion possible names for that file
Packit 992a25
	 */
Packit 992a25
Packit 992a25
	if (!findcodes[1])
Packit 992a25
		findcodes[1] = getenv(FIND_CODES_ENV);
Packit 992a25
	if (disc->flags & FIND_GENERATE)
Packit 992a25
	{
Packit 992a25
		if (!(fp = (Find_t*)vmnewof(vm, 0, Find_t, 1, sizeof(Encode_t) - sizeof(Code_t))))
Packit 992a25
			goto nospace;
Packit 992a25
		fp->vm = vm;
Packit 992a25
		fp->id = lib;
Packit 992a25
		fp->disc = disc;
Packit 992a25
		fp->generate = 1;
Packit 992a25
		if (file && (!*file || streq(file, "-")))
Packit 992a25
			file = 0;
Packit 992a25
		uid = geteuid();
Packit 992a25
		j = (findcodes[0] = (char*)file) && *file == '/' ? 1 : elementsof(findcodes);
Packit 992a25
Packit 992a25
		/*
Packit 992a25
		 * look for the codes file, but since it may not exist yet,
Packit 992a25
		 * also look for the containing directory if i<2 or if
Packit 992a25
		 * it is sufficiently qualified (FIND_MATCH)
Packit 992a25
		 */
Packit 992a25
Packit 992a25
		for (i = 0; i < j; i++)
Packit 992a25
			if (path = findcodes[i])
Packit 992a25
			{
Packit 992a25
				if (*path == '/')
Packit 992a25
				{
Packit 992a25
					if (!stat(path, &st))
Packit 992a25
					{
Packit 992a25
						if (S_ISDIR(st.st_mode))
Packit 992a25
						{
Packit 992a25
							for (k = 0; k < elementsof(findnames); k++)
Packit 992a25
							{
Packit 992a25
								sfsprintf(fp->encode.file, sizeof(fp->encode.file), "%s/%s", path, findnames[k]);
Packit 992a25
								if (!eaccess(fp->encode.file, R_OK|W_OK))
Packit 992a25
								{
Packit 992a25
									path = fp->encode.file;
Packit 992a25
									break;
Packit 992a25
								}
Packit 992a25
								if (strchr(findnames[k], '/') && (b = strrchr(fp->encode.file, '/')))
Packit 992a25
								{
Packit 992a25
									*b = 0;
Packit 992a25
									if (!stat(fp->encode.file, &st) && st.st_uid == uid && (st.st_mode & S_IWUSR))
Packit 992a25
									{
Packit 992a25
										*b = '/';
Packit 992a25
										path = fp->encode.file;
Packit 992a25
										break;
Packit 992a25
									}
Packit 992a25
								}
Packit 992a25
							}
Packit 992a25
							if (k < elementsof(findnames))
Packit 992a25
								break;
Packit 992a25
						}
Packit 992a25
						else if (st.st_uid == uid && (st.st_mode & S_IWUSR))
Packit 992a25
						{
Packit 992a25
							sfsprintf(fp->encode.file, sizeof(fp->encode.file), "%s", path);
Packit 992a25
							path = fp->encode.file;
Packit 992a25
							break;
Packit 992a25
						}
Packit 992a25
					}
Packit 992a25
					else if (i < 2 || strmatch(path, FIND_MATCH))
Packit 992a25
					{
Packit 992a25
						sfsprintf(fp->encode.file, sizeof(fp->encode.file), "%s", path);
Packit 992a25
						if (b = strrchr(fp->encode.file, '/'))
Packit 992a25
						{
Packit 992a25
							*b = 0;
Packit 992a25
							if (!stat(fp->encode.file, &st) && st.st_uid == uid && (st.st_mode & S_IWUSR))
Packit 992a25
							{
Packit 992a25
								*b = '/';
Packit 992a25
								path = fp->encode.file;
Packit 992a25
								break;
Packit 992a25
							}
Packit 992a25
						}
Packit 992a25
					}
Packit 992a25
				}
Packit 992a25
				else if (pathpath(path, "", PATH_REGULAR|PATH_READ|PATH_WRITE, fp->encode.file, sizeof(fp->encode.file)))
Packit 992a25
				{
Packit 992a25
					path = fp->encode.file;
Packit 992a25
					break;
Packit 992a25
				}
Packit 992a25
				else if (b = strrchr(path, '/'))
Packit 992a25
				{
Packit 992a25
					sfsprintf(fp->encode.file, sizeof(fp->encode.file), "%-.*s", b - path, path);
Packit 992a25
					if (pathpath(fp->encode.file, "", PATH_EXECUTE|PATH_READ|PATH_WRITE, fp->encode.temp, sizeof(fp->encode.temp)) &&
Packit 992a25
					    !stat(fp->encode.temp, &st) && st.st_uid == uid && (st.st_mode & S_IWUSR))
Packit 992a25
					{
Packit 992a25
						sfsprintf(fp->encode.file, sizeof(fp->encode.file), "%s%s", fp->encode.temp, b);
Packit 992a25
						path = fp->encode.file;
Packit 992a25
						break;
Packit 992a25
					}
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
		if (i >= j)
Packit 992a25
		{
Packit 992a25
			if (fp->disc->errorf)
Packit 992a25
				(*fp->disc->errorf)(fp, fp->disc, 2, "%s: cannot locate codes", file ? file : findcodes[2]);
Packit 992a25
			goto drop;
Packit 992a25
		}
Packit 992a25
		if (fp->disc->flags & FIND_OLD)
Packit 992a25
		{
Packit 992a25
			/*
Packit 992a25
			 * FF_old generates temp data that is read
Packit 992a25
			 * in a second pass to generate the real codes
Packit 992a25
			 */
Packit 992a25
Packit 992a25
			fp->method = FF_old;
Packit 992a25
			if (!(fp->fp = sftmp(32 * PATH_MAX)))
Packit 992a25
			{
Packit 992a25
				if (fp->disc->errorf)
Packit 992a25
					(*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "cannot create tmp file");
Packit 992a25
				goto drop;
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		else
Packit 992a25
		{
Packit 992a25
			/*
Packit 992a25
			 * the rest generate into a temp file that
Packit 992a25
			 * is simply renamed on completion
Packit 992a25
			 */
Packit 992a25
Packit 992a25
			if (s = strrchr(path, '/'))
Packit 992a25
			{
Packit 992a25
				*s = 0;
Packit 992a25
				p = path;
Packit 992a25
			}
Packit 992a25
			else
Packit 992a25
				p = ".";
Packit 992a25
			if (!pathtemp(fp->encode.temp, sizeof(fp->encode.temp), p, "ff", &fd))
Packit 992a25
			{
Packit 992a25
				if (fp->disc->errorf)
Packit 992a25
					(*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "%s: cannot create tmp file in this directory", p ? p : ".");
Packit 992a25
				goto drop;
Packit 992a25
			}
Packit 992a25
			if (s)
Packit 992a25
				*s = '/';
Packit 992a25
			if (!(fp->fp = sfnew(NiL, NiL, (size_t)SF_UNBOUND, fd, SF_WRITE)))
Packit 992a25
			{
Packit 992a25
				if (fp->disc->errorf)
Packit 992a25
					(*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "%s: cannot open tmp file", fp->encode.temp);
Packit 992a25
				close(fd);
Packit 992a25
				goto drop;
Packit 992a25
			}
Packit 992a25
			if (fp->disc->flags & FIND_TYPE)
Packit 992a25
			{
Packit 992a25
				fp->method = FF_typ;
Packit 992a25
				fp->encode.namedisc.key = offsetof(Type_t, name);
Packit 992a25
				fp->encode.namedisc.link = offsetof(Type_t, byname);
Packit 992a25
				fp->encode.indexdisc.key = offsetof(Type_t, index);
Packit 992a25
				fp->encode.indexdisc.size = sizeof(unsigned long);
Packit 992a25
				fp->encode.indexdisc.link = offsetof(Type_t, byindex);
Packit 992a25
				s = "system/dir";
Packit 992a25
				if (!(fp->encode.namedict = dtopen(&fp->encode.namedisc, Dtoset)) || !(fp->encode.indexdict = dtopen(&fp->encode.indexdisc, Dtoset)) || !(tp = newof(0, Type_t, 1, strlen(s) + 1)))
Packit 992a25
				{
Packit 992a25
					if (fp->encode.namedict)
Packit 992a25
						dtclose(fp->encode.namedict);
Packit 992a25
					if (fp->disc->errorf)
Packit 992a25
						(*fp->disc->errorf)(fp, fp->disc, 2, "cannot allocate type table");
Packit 992a25
					goto drop;
Packit 992a25
				}
Packit 992a25
Packit 992a25
				/*
Packit 992a25
				 * type index 1 is always system/dir
Packit 992a25
				 */
Packit 992a25
Packit 992a25
				tp->index = ++fp->types;
Packit 992a25
				strcpy(tp->name, s);
Packit 992a25
				dtinsert(fp->encode.namedict, tp);
Packit 992a25
				dtinsert(fp->encode.indexdict, tp);
Packit 992a25
			}
Packit 992a25
			else if (fp->disc->flags & FIND_GNU)
Packit 992a25
			{
Packit 992a25
				fp->method = FF_gnu;
Packit 992a25
				sfputc(fp->fp, 0);
Packit 992a25
				sfputr(fp->fp, FF_gnu_magic, 0);
Packit 992a25
			}
Packit 992a25
			else
Packit 992a25
			{
Packit 992a25
				fp->method = FF_dir;
Packit 992a25
				sfputc(fp->fp, 0);
Packit 992a25
				sfputr(fp->fp, FF_dir_magic, 0);
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	else
Packit 992a25
	{
Packit 992a25
		i = sizeof(Decode_t) + sizeof(Code_t);
Packit 992a25
		if (!pattern || !*pattern)
Packit 992a25
			pattern = "*";
Packit 992a25
		i += (j = 2 * (strlen(pattern) + 1));
Packit 992a25
		if (!(fp = (Find_t*)vmnewof(vm, 0, Find_t, 1, i)))
Packit 992a25
		{
Packit 992a25
			vmclose(vm);
Packit 992a25
			return 0;
Packit 992a25
		}
Packit 992a25
		fp->vm = vm;
Packit 992a25
		fp->id = lib;
Packit 992a25
		fp->disc = disc;
Packit 992a25
		if (disc->flags & FIND_ICASE)
Packit 992a25
			fp->decode.ignorecase = 1;
Packit 992a25
		j = (findcodes[0] = (char*)file) && *file == '/' ? 1 : elementsof(findcodes);
Packit 992a25
		for (i = 0; i < j; i++)
Packit 992a25
			if (path = findcodes[i])
Packit 992a25
			{
Packit 992a25
				if (*path == '/')
Packit 992a25
				{
Packit 992a25
					if (!stat(path, &st))
Packit 992a25
					{
Packit 992a25
						if (S_ISDIR(st.st_mode))
Packit 992a25
						{
Packit 992a25
							for (k = 0; k < elementsof(findnames); k++)
Packit 992a25
							{
Packit 992a25
								sfsprintf(fp->decode.path, sizeof(fp->decode.path), "%s/%s", path, findnames[k]);
Packit 992a25
								if (fp->fp = sfopen(NiL, fp->decode.path, "r"))
Packit 992a25
								{
Packit 992a25
									path = fp->decode.path;
Packit 992a25
									break;
Packit 992a25
								}
Packit 992a25
							}
Packit 992a25
							if (fp->fp)
Packit 992a25
								break;
Packit 992a25
						}
Packit 992a25
						else if (fp->fp = sfopen(NiL, path, "r"))
Packit 992a25
							break;
Packit 992a25
					}
Packit 992a25
				}
Packit 992a25
				else if ((path = pathpath(path, "", PATH_REGULAR|PATH_READ, fp->decode.path, sizeof(fp->decode.path))) && (fp->fp = sfopen(NiL, path, "r")))
Packit 992a25
					break;
Packit 992a25
			}
Packit 992a25
		if (!fp->fp)
Packit 992a25
		{
Packit 992a25
			if (fp->disc->errorf)
Packit 992a25
				(*fp->disc->errorf)(fp, fp->disc, 2, "%s: cannot locate codes", file ? file : findcodes[2]);
Packit 992a25
			goto drop;
Packit 992a25
		}
Packit 992a25
		if (fstat(sffileno(fp->fp), &st))
Packit 992a25
		{
Packit 992a25
			if (fp->disc->errorf)
Packit 992a25
				(*fp->disc->errorf)(fp, fp->disc, 2, "%s: cannot stat codes", path);
Packit 992a25
			goto drop;
Packit 992a25
		}
Packit 992a25
		if (fp->secure = ((st.st_mode & (S_IRGRP|S_IROTH)) == S_IRGRP) && st.st_gid == getegid() && getegid() != getgid())
Packit 992a25
			setgid(getgid());
Packit 992a25
		fp->stamp = st.st_mtime;
Packit 992a25
		b = (s = fp->decode.temp) + 1;
Packit 992a25
		for (i = 0; i < elementsof(fp->decode.bigram1); i++) 
Packit 992a25
		{
Packit 992a25
			if ((j = sfgetc(fp->fp)) == EOF)
Packit 992a25
				goto invalid;
Packit 992a25
			if (!(*s++ = fp->decode.bigram1[i] = j) && i)
Packit 992a25
			{
Packit 992a25
				i = -i;
Packit 992a25
				break;
Packit 992a25
			}
Packit 992a25
			if ((j = sfgetc(fp->fp)) == EOF)
Packit 992a25
				goto invalid;
Packit 992a25
			if (!(*s++ = fp->decode.bigram2[i] = j) && (i || fp->decode.bigram1[0] >= '0' && fp->decode.bigram1[0] <= '1'))
Packit 992a25
				break;
Packit 992a25
		}
Packit 992a25
		if (streq(b, FF_typ_magic))
Packit 992a25
		{
Packit 992a25
			if (type)
Packit 992a25
			{
Packit 992a25
				type = (const char*)typefix(fp->decode.bigram2, sizeof(fp->decode.bigram2), type);
Packit 992a25
				memset(fp->decode.bigram1, 0, sizeof(fp->decode.bigram1));
Packit 992a25
			}
Packit 992a25
			fp->method = FF_typ;
Packit 992a25
			for (j = 0, i = 1;; i++)
Packit 992a25
			{
Packit 992a25
				if (!(s = sfgetr(fp->fp, 0, 0)))
Packit 992a25
					goto invalid;
Packit 992a25
				if (!*s)
Packit 992a25
					break;
Packit 992a25
				if (type && strmatch(s, type))
Packit 992a25
				{
Packit 992a25
					FF_SET_TYPE(fp, i);
Packit 992a25
					j++;
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
			if (type && !j)
Packit 992a25
				goto drop;
Packit 992a25
			fp->types = j;
Packit 992a25
		}
Packit 992a25
		else if (streq(b, FF_dir_magic))
Packit 992a25
			fp->method = FF_dir;
Packit 992a25
		else if (streq(b, FF_gnu_magic))
Packit 992a25
			fp->method = FF_gnu;
Packit 992a25
		else if (!*b && *--b >= '0' && *b <= '1')
Packit 992a25
		{
Packit 992a25
			fp->method = FF_gnu;
Packit 992a25
			while (j = sfgetc(fp->fp))
Packit 992a25
			{
Packit 992a25
				if (j == EOF || fp->decode.count >= sizeof(fp->decode.path))
Packit 992a25
					goto invalid;
Packit 992a25
				fp->decode.path[fp->decode.count++] = j;
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		else
Packit 992a25
		{
Packit 992a25
			fp->method = FF_old;
Packit 992a25
			if (i < 0)
Packit 992a25
			{
Packit 992a25
				if ((j = sfgetc(fp->fp)) == EOF)
Packit 992a25
					goto invalid;
Packit 992a25
				fp->decode.bigram2[i = -i] = j;
Packit 992a25
			}
Packit 992a25
			while (++i < elementsof(fp->decode.bigram1))
Packit 992a25
			{
Packit 992a25
				if ((j = sfgetc(fp->fp)) == EOF)
Packit 992a25
					goto invalid;
Packit 992a25
				fp->decode.bigram1[i] = j;
Packit 992a25
				if ((j = sfgetc(fp->fp)) == EOF)
Packit 992a25
					goto invalid;
Packit 992a25
				fp->decode.bigram2[i] = j;
Packit 992a25
			}
Packit 992a25
			if ((fp->decode.peek = sfgetc(fp->fp)) != FF_OFF)
Packit 992a25
				goto invalid;
Packit 992a25
		}
Packit 992a25
Packit 992a25
		/*
Packit 992a25
		 * set up the physical dir table
Packit 992a25
		 */
Packit 992a25
Packit 992a25
		if (disc->version >= 19980301L)
Packit 992a25
		{
Packit 992a25
			fp->verifyf = disc->verifyf;
Packit 992a25
			if (disc->dirs && *disc->dirs)
Packit 992a25
			{
Packit 992a25
				for (k = 0; disc->dirs[k]; k++);
Packit 992a25
				if (k == 1 && streq(disc->dirs[0], "/"))
Packit 992a25
					k = 0;
Packit 992a25
				if (k)
Packit 992a25
				{
Packit 992a25
					if (!(fp->dirs = vmnewof(fp->vm, 0, char*, 2 * k + 1, 0)))
Packit 992a25
						goto drop;
Packit 992a25
					if (!(fp->lens = vmnewof(fp->vm, 0, int, 2 * k, 0)))
Packit 992a25
						goto drop;
Packit 992a25
					p = 0;
Packit 992a25
					b = fp->decode.temp;
Packit 992a25
					j = fp->method == FF_old || fp->method == FF_gnu;
Packit 992a25
Packit 992a25
					/*
Packit 992a25
					 * fill the dir list with logical and
Packit 992a25
					 * physical names since we don't know
Packit 992a25
					 * which way the db was encoded (it
Packit 992a25
					 * could be *both* ways)
Packit 992a25
					 */
Packit 992a25
Packit 992a25
					for (i = q = 0; i < k; i++)
Packit 992a25
					{
Packit 992a25
						if (*(s = disc->dirs[i]) == '/')
Packit 992a25
							sfsprintf(b, sizeof(fp->decode.temp) - 1, "%s", s);
Packit 992a25
						else if (!p && !(p = getcwd(fp->decode.path, sizeof(fp->decode.path))))
Packit 992a25
							goto nospace;
Packit 992a25
						else
Packit 992a25
							sfsprintf(b, sizeof(fp->decode.temp) - 1, "%s/%s", p, s);
Packit 992a25
						s = pathcanon(b, sizeof(fp->decode.temp), 0);
Packit 992a25
						*s = '/';
Packit 992a25
						*(s + 1) = 0;
Packit 992a25
						if (!(fp->dirs[q] = vmstrdup(fp->vm, b)))
Packit 992a25
							goto nospace;
Packit 992a25
						if (j)
Packit 992a25
							(fp->dirs[q])[s - b] = 0;
Packit 992a25
						q++;
Packit 992a25
						*s = 0;
Packit 992a25
						s = pathcanon(b, sizeof(fp->decode.temp), PATH_PHYSICAL);
Packit 992a25
						*s = '/';
Packit 992a25
						*(s + 1) = 0;
Packit 992a25
						if (!strneq(b, fp->dirs[q - 1], s - b))
Packit 992a25
						{
Packit 992a25
							if (!(fp->dirs[q] = vmstrdup(fp->vm, b)))
Packit 992a25
								goto nospace;
Packit 992a25
							if (j)
Packit 992a25
								(fp->dirs[q])[s - b] = 0;
Packit 992a25
							q++;
Packit 992a25
						}
Packit 992a25
					}
Packit 992a25
					strsort(fp->dirs, q, strcasecmp);
Packit 992a25
					for (i = 0; i < q; i++)
Packit 992a25
						fp->lens[i] = strlen(fp->dirs[i]);
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		if (fp->verifyf || (disc->flags & FIND_VERIFY))
Packit 992a25
		{
Packit 992a25
			if (fp->method != FF_dir && fp->method != FF_typ)
Packit 992a25
			{
Packit 992a25
				if (fp->disc->errorf)
Packit 992a25
					(*fp->disc->errorf)(fp, fp->disc, 2, "%s: %s code format does not support directory verification", path, fp->method == FF_gnu ? FF_gnu_magic : "OLD-BIGRAM");
Packit 992a25
				goto drop;
Packit 992a25
			}
Packit 992a25
			fp->verify = 1;
Packit 992a25
		}
Packit 992a25
Packit 992a25
		/*
Packit 992a25
		 * extract last glob-free subpattern in name for fast pre-match
Packit 992a25
		 * prepend 0 for backwards match
Packit 992a25
		 */
Packit 992a25
Packit 992a25
		if (p = s = (char*)pattern)
Packit 992a25
		{
Packit 992a25
			b = fp->decode.pattern;
Packit 992a25
			for (;;)
Packit 992a25
			{
Packit 992a25
				switch (*b++ = *p++)
Packit 992a25
				{
Packit 992a25
				case 0:
Packit 992a25
					break;
Packit 992a25
				case '\\':
Packit 992a25
					s = p;
Packit 992a25
					if (!*p++)
Packit 992a25
						break;
Packit 992a25
					continue;
Packit 992a25
				case '[':
Packit 992a25
					if (!brace)
Packit 992a25
					{
Packit 992a25
						brace++;
Packit 992a25
						if (*p == ']')
Packit 992a25
							p++;
Packit 992a25
					}
Packit 992a25
					continue;
Packit 992a25
				case ']':
Packit 992a25
					if (brace)
Packit 992a25
					{
Packit 992a25
						brace--;
Packit 992a25
						s = p;
Packit 992a25
					}
Packit 992a25
					continue;
Packit 992a25
				case '(':
Packit 992a25
					if (!brace)
Packit 992a25
						paren++;
Packit 992a25
					continue;
Packit 992a25
				case ')':
Packit 992a25
					if (!brace && paren > 0 && !--paren)
Packit 992a25
						s = p;
Packit 992a25
					continue;
Packit 992a25
				case '|':
Packit 992a25
				case '&':
Packit 992a25
					if (!brace && !paren)
Packit 992a25
					{
Packit 992a25
						s = "";
Packit 992a25
						break;
Packit 992a25
					}
Packit 992a25
					continue;
Packit 992a25
				case '*':
Packit 992a25
				case '?':
Packit 992a25
					s = p;
Packit 992a25
					continue;
Packit 992a25
				default:
Packit 992a25
					continue;
Packit 992a25
				}
Packit 992a25
				break;
Packit 992a25
			}
Packit 992a25
			if (s != pattern && !streq(pattern, "*"))
Packit 992a25
			{
Packit 992a25
				fp->decode.match = 1;
Packit 992a25
				if (i = regcomp(&fp->decode.re, pattern, REG_SHELL|REG_AUGMENTED|(fp->decode.ignorecase?REG_ICASE:0)))
Packit 992a25
				{
Packit 992a25
					if (disc->errorf)
Packit 992a25
					{
Packit 992a25
						regerror(i, &fp->decode.re, fp->decode.temp, sizeof(fp->decode.temp));
Packit 992a25
						(*fp->disc->errorf)(fp, fp->disc, 2, "%s: %s", pattern, fp->decode.temp);
Packit 992a25
					}
Packit 992a25
					goto drop;
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
			if (*s)
Packit 992a25
			{
Packit 992a25
				*b++ = 0;
Packit 992a25
				while (i = *s++)
Packit 992a25
					*b++ = i;
Packit 992a25
				*b-- = 0;
Packit 992a25
				fp->decode.end = b;
Packit 992a25
				if (fp->decode.ignorecase)
Packit 992a25
					for (s = fp->decode.pattern; s <= b; s++)
Packit 992a25
						if (isupper(*s))
Packit 992a25
							*s = tolower(*s);
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	return fp;
Packit 992a25
 nospace:
Packit 992a25
	if (disc->errorf)
Packit 992a25
		(*fp->disc->errorf)(fp, fp->disc, 2, "out of space");
Packit 992a25
	if (!vm)
Packit 992a25
		return 0;
Packit 992a25
	if (!fp)
Packit 992a25
	{
Packit 992a25
		vmclose(vm);
Packit 992a25
		return 0;
Packit 992a25
	}
Packit 992a25
	goto drop;
Packit 992a25
 invalid:
Packit 992a25
	if (fp->disc->errorf)
Packit 992a25
		(*fp->disc->errorf)(fp, fp->disc, 2, "%s: invalid codes", path);
Packit 992a25
 drop:
Packit 992a25
	if (!fp->generate && fp->decode.match)
Packit 992a25
		regfree(&fp->decode.re);
Packit 992a25
	if (fp->fp)
Packit 992a25
		sfclose(fp->fp);
Packit 992a25
	vmclose(fp->vm);
Packit 992a25
	return 0;
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * return the next fastfind path
Packit 992a25
 * 0 returned when list exhausted
Packit 992a25
 */
Packit 992a25
Packit 992a25
char*
Packit 992a25
findread(register Find_t* fp)
Packit 992a25
{
Packit 992a25
	register char*		p;
Packit 992a25
	register char*		q;
Packit 992a25
	register char*		s;
Packit 992a25
	register char*		b;
Packit 992a25
	register char*		e;
Packit 992a25
	register int		c;
Packit 992a25
	register int		n;
Packit 992a25
	register int		m;
Packit 992a25
	int			ignorecase;
Packit 992a25
	int			t;
Packit 992a25
	unsigned char		w[4];
Packit 992a25
	struct stat		st;
Packit 992a25
Packit 992a25
	if (fp->generate)
Packit 992a25
		return 0;
Packit 992a25
	if (fp->decode.restore)
Packit 992a25
	{
Packit 992a25
		*fp->decode.restore = '/';
Packit 992a25
		fp->decode.restore = 0;
Packit 992a25
	}
Packit 992a25
	ignorecase = fp->decode.ignorecase ? STR_ICASE : 0;
Packit 992a25
	c = fp->decode.peek;
Packit 992a25
 next:
Packit 992a25
	for (;;)
Packit 992a25
	{
Packit 992a25
		switch (fp->method)
Packit 992a25
		{
Packit 992a25
		case FF_dir:
Packit 992a25
			t = 0;
Packit 992a25
			n = sfgetl(fp->fp);
Packit 992a25
			goto grab;
Packit 992a25
		case FF_gnu:
Packit 992a25
			if ((c = sfgetc(fp->fp)) == EOF)
Packit 992a25
				return 0;
Packit 992a25
			if (c == 0x80)
Packit 992a25
			{
Packit 992a25
				if ((c = sfgetc(fp->fp)) == EOF)
Packit 992a25
					return 0;
Packit 992a25
				n = c << 8;
Packit 992a25
				if ((c = sfgetc(fp->fp)) == EOF)
Packit 992a25
					return 0;
Packit 992a25
				n |= c;
Packit 992a25
				if (n & 0x8000)
Packit 992a25
					n = (n - 0xffff) - 1;
Packit 992a25
			}
Packit 992a25
			else if ((n = c) & 0x80)
Packit 992a25
				n = (n - 0xff) - 1;
Packit 992a25
			t = 0;
Packit 992a25
			goto grab;
Packit 992a25
		case FF_typ:
Packit 992a25
			t = sfgetu(fp->fp);
Packit 992a25
			n = sfgetl(fp->fp);
Packit 992a25
		grab:
Packit 992a25
			p = fp->decode.path + (fp->decode.count += n);
Packit 992a25
			do
Packit 992a25
			{
Packit 992a25
				if ((c = sfgetc(fp->fp)) == EOF)
Packit 992a25
					return 0;
Packit 992a25
			} while (*p++ = c);
Packit 992a25
			p -= 2;
Packit 992a25
			break;
Packit 992a25
		case FF_old:
Packit 992a25
			if (c == EOF)
Packit 992a25
			{
Packit 992a25
				fp->decode.peek = c;
Packit 992a25
				return 0;
Packit 992a25
			}
Packit 992a25
			if (c == FF_ESC)
Packit 992a25
			{
Packit 992a25
				if (sfread(fp->fp, w, sizeof(w)) != sizeof(w))
Packit 992a25
					return 0;
Packit 992a25
				if (fp->decode.swap >= 0)
Packit 992a25
				{
Packit 992a25
					c = (int32_t)((w[0] << 24) | (w[1] << 16) | (w[2] << 8) | w[3]);
Packit 992a25
					if (!fp->decode.swap)
Packit 992a25
					{
Packit 992a25
						/*
Packit 992a25
						 * the old format uses machine
Packit 992a25
						 * byte order; this test uses
Packit 992a25
						 * the smallest magnitude of
Packit 992a25
						 * both byte orders on the
Packit 992a25
						 * first encoded path motion
Packit 992a25
						 * to determine the original
Packit 992a25
						 * byte order
Packit 992a25
						 */
Packit 992a25
Packit 992a25
						m = c;
Packit 992a25
						if (m < 0)
Packit 992a25
							m = -m;
Packit 992a25
						n = (int32_t)((w[3] << 24) | (w[2] << 16) | (w[1] << 8) | w[0]);
Packit 992a25
						if (n < 0)
Packit 992a25
							n = -n;
Packit 992a25
						if (m < n)
Packit 992a25
							fp->decode.swap = 1;
Packit 992a25
						else
Packit 992a25
						{
Packit 992a25
							fp->decode.swap = -1;
Packit 992a25
							c = (int32_t)((w[3] << 24) | (w[2] << 16) | (w[1] << 8) | w[0]);
Packit 992a25
						}
Packit 992a25
					}
Packit 992a25
				}
Packit 992a25
				else
Packit 992a25
					c = (int32_t)((w[3] << 24) | (w[2] << 16) | (w[1] << 8) | w[0]);
Packit 992a25
			}
Packit 992a25
			fp->decode.count += c - FF_OFF;
Packit 992a25
			for (p = fp->decode.path + fp->decode.count; (c = sfgetc(fp->fp)) > FF_ESC;)
Packit 992a25
				if (c & (1<<(CHAR_BIT-1)))
Packit 992a25
				{
Packit 992a25
					*p++ = fp->decode.bigram1[c & ((1<<(CHAR_BIT-1))-1)];
Packit 992a25
					*p++ = fp->decode.bigram2[c & ((1<<(CHAR_BIT-1))-1)];
Packit 992a25
				}
Packit 992a25
				else
Packit 992a25
					*p++ = c;
Packit 992a25
			*p-- = 0;
Packit 992a25
			t = 0;
Packit 992a25
			break;
Packit 992a25
		}
Packit 992a25
		b = fp->decode.path;
Packit 992a25
		if (fp->decode.found)
Packit 992a25
			fp->decode.found = 0;
Packit 992a25
		else
Packit 992a25
			b += fp->decode.count;
Packit 992a25
		if (fp->dirs)
Packit 992a25
			for (;;)
Packit 992a25
			{
Packit 992a25
				if (!*fp->dirs)
Packit 992a25
					return 0;
Packit 992a25
Packit 992a25
				/*
Packit 992a25
				 * use the ordering and lengths to prune
Packit 992a25
				 * comparison function calls
Packit 992a25
				 * (*fp->dirs)[*fp->lens]=='/' if its
Packit 992a25
				 * already been matched
Packit 992a25
				 */
Packit 992a25
Packit 992a25
				if ((n = p - fp->decode.path + 1) > (m = *fp->lens))
Packit 992a25
				{
Packit 992a25
					if (!(*fp->dirs)[m])
Packit 992a25
						goto next;
Packit 992a25
					if (!strncasecmp(*fp->dirs, fp->decode.path, m))
Packit 992a25
						break;
Packit 992a25
				}
Packit 992a25
				else if (n == m)
Packit 992a25
				{
Packit 992a25
					if (!(*fp->dirs)[m])
Packit 992a25
					{
Packit 992a25
						if (!(n = strcasecmp(*fp->dirs, fp->decode.path)) && (ignorecase || !strcmp(*fp->dirs, fp->decode.path)))
Packit 992a25
						{
Packit 992a25
							if (m > 0)
Packit 992a25
							{
Packit 992a25
								(*fp->dirs)[m] = '/';
Packit 992a25
								if ((*fp->dirs)[m - 1] != '/')
Packit 992a25
									(*fp->dirs)[++(*fp->lens)] = '/';
Packit 992a25
							}
Packit 992a25
							break;
Packit 992a25
						}
Packit 992a25
						if (n >= 0)
Packit 992a25
							goto next;
Packit 992a25
					}
Packit 992a25
				}
Packit 992a25
				else if (!(*fp->dirs)[m])
Packit 992a25
					goto next;
Packit 992a25
				fp->dirs++;
Packit 992a25
				fp->lens++;
Packit 992a25
			}
Packit 992a25
		if (fp->verify && (*p == '/' || t == 1))
Packit 992a25
		{
Packit 992a25
			if ((n = p - fp->decode.path))
Packit 992a25
				*p = 0;
Packit 992a25
			else
Packit 992a25
				n = 1;
Packit 992a25
			if (fp->verifyf)
Packit 992a25
				n = (*fp->verifyf)(fp, fp->decode.path, n, fp->disc);
Packit 992a25
			else if (stat(fp->decode.path, &st))
Packit 992a25
				n = -1;
Packit 992a25
			else if ((unsigned long)st.st_mtime > fp->stamp)
Packit 992a25
				n = 1;
Packit 992a25
			else
Packit 992a25
				n = 0;
Packit 992a25
			*p = '/';
Packit 992a25
Packit 992a25
			/*
Packit 992a25
			 * n<0	skip this subtree
Packit 992a25
			 * n==0 keep as is
Packit 992a25
			 * n>0	read this dir now
Packit 992a25
			 */
Packit 992a25
Packit 992a25
			/* NOT IMPLEMENTED YET */
Packit 992a25
		}
Packit 992a25
		if (FF_OK_TYPE(fp, t))
Packit 992a25
		{
Packit 992a25
			if (fp->decode.end)
Packit 992a25
			{
Packit 992a25
				if (*(s = p) == '/')
Packit 992a25
					s--;
Packit 992a25
				if (*fp->decode.pattern == '/' && b > fp->decode.path)
Packit 992a25
					b--;
Packit 992a25
				for (; s >= b; s--) 
Packit 992a25
					if (*s == *fp->decode.end || ignorecase && tolower(*s) == *fp->decode.end)
Packit 992a25
					{
Packit 992a25
						if (ignorecase)
Packit 992a25
							for (e = fp->decode.end - 1, q = s - 1; *e && (*q == *e || tolower(*q) == *e); e--, q--);
Packit 992a25
						else
Packit 992a25
							for (e = fp->decode.end - 1, q = s - 1; *e && *q == *e; e--, q--);
Packit 992a25
						if (!*e)
Packit 992a25
						{
Packit 992a25
							fp->decode.found = 1;
Packit 992a25
							if (!fp->decode.match || strgrpmatch(fp->decode.path, fp->decode.pattern, NiL, 0, STR_MAXIMAL|STR_LEFT|STR_RIGHT|ignorecase))
Packit 992a25
							{
Packit 992a25
								fp->decode.peek = c;
Packit 992a25
								if (*p == '/')
Packit 992a25
									*(fp->decode.restore = p) = 0;
Packit 992a25
								if (!fp->secure || !access(fp->decode.path, F_OK))
Packit 992a25
									return fp->decode.path;
Packit 992a25
							}
Packit 992a25
							break;
Packit 992a25
						}
Packit 992a25
					}
Packit 992a25
			}
Packit 992a25
			else if (!fp->decode.match || !(n = regexec(&fp->decode.re, fp->decode.path, 0, NiL, 0)))
Packit 992a25
			{
Packit 992a25
				fp->decode.peek = c;
Packit 992a25
				if (*p == '/' && p > fp->decode.path)
Packit 992a25
					*(fp->decode.restore = p) = 0;
Packit 992a25
				if (!fp->secure || !access(fp->decode.path, F_OK))
Packit 992a25
					return fp->decode.path;
Packit 992a25
			}
Packit 992a25
			else if (n != REG_NOMATCH)
Packit 992a25
			{
Packit 992a25
				if (fp->disc->errorf)
Packit 992a25
				{
Packit 992a25
					regerror(n, &fp->decode.re, fp->decode.temp, sizeof(fp->decode.temp));
Packit 992a25
					(*fp->disc->errorf)(fp, fp->disc, 2, "%s: %s", fp->decode.pattern, fp->decode.temp);
Packit 992a25
				}
Packit 992a25
				return 0;
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * add path to the code table
Packit 992a25
 * paths are assumed to be in sort order
Packit 992a25
 */
Packit 992a25
Packit 992a25
int
Packit 992a25
findwrite(register Find_t* fp, const char* path, size_t len, const char* type)
Packit 992a25
{
Packit 992a25
	register unsigned char*	s;
Packit 992a25
	register unsigned char*	e;
Packit 992a25
	register unsigned char*	p;
Packit 992a25
	register int		n;
Packit 992a25
	register int		d;
Packit 992a25
	register Type_t*	x;
Packit 992a25
	register unsigned long	u;
Packit 992a25
Packit 992a25
	if (!fp->generate)
Packit 992a25
		return -1;
Packit 992a25
	if (type && fp->method == FF_dir)
Packit 992a25
	{
Packit 992a25
		len = sfsprintf(fp->encode.mark, sizeof(fp->encode.mark), "%-.*s/", len, path);
Packit 992a25
		path = fp->encode.mark;
Packit 992a25
	}
Packit 992a25
	s = (unsigned char*)path;
Packit 992a25
	if (len <= 0)
Packit 992a25
		len = strlen(path);
Packit 992a25
	if (len < sizeof(fp->encode.path))
Packit 992a25
		e = s + len++;
Packit 992a25
	else
Packit 992a25
	{
Packit 992a25
		len = sizeof(fp->encode.path) - 1;
Packit 992a25
		e = s + len;
Packit 992a25
	}
Packit 992a25
	p = (unsigned char*)fp->encode.path;
Packit 992a25
	while (s < e)
Packit 992a25
	{
Packit 992a25
		if (*s != *p++)
Packit 992a25
			break;
Packit 992a25
		s++;
Packit 992a25
	}
Packit 992a25
	n = s - (unsigned char*)path;
Packit 992a25
	switch (fp->method)
Packit 992a25
	{
Packit 992a25
	case FF_gnu:
Packit 992a25
		d = n - fp->encode.prefix;
Packit 992a25
		if (d >= -127 && d <= 127)
Packit 992a25
			sfputc(fp->fp, d & 0xff);
Packit 992a25
		else
Packit 992a25
		{
Packit 992a25
			sfputc(fp->fp, 0x80);
Packit 992a25
			sfputc(fp->fp, (d >> 8) & 0xff);
Packit 992a25
			sfputc(fp->fp, d & 0xff);
Packit 992a25
		}
Packit 992a25
		fp->encode.prefix = n;
Packit 992a25
		sfputr(fp->fp, (char*)s, 0);
Packit 992a25
		break;
Packit 992a25
	case FF_old:
Packit 992a25
		sfprintf(fp->fp, "%ld", n - fp->encode.prefix + FF_OFF);
Packit 992a25
		fp->encode.prefix = n;
Packit 992a25
		sfputc(fp->fp, ' ');
Packit 992a25
		p = s;
Packit 992a25
		while (s < e)
Packit 992a25
		{
Packit 992a25
			n = *s++;
Packit 992a25
			if (s >= e)
Packit 992a25
				break;
Packit 992a25
			fp->encode.code[n][*s++]++;
Packit 992a25
		}
Packit 992a25
		while (p < e)
Packit 992a25
		{
Packit 992a25
			if ((n = *p++) < FF_MIN || n >= FF_MAX)
Packit 992a25
				n = '?';
Packit 992a25
			sfputc(fp->fp, n);
Packit 992a25
		}
Packit 992a25
		sfputc(fp->fp, 0);
Packit 992a25
		break;
Packit 992a25
	case FF_typ:
Packit 992a25
		if (type)
Packit 992a25
		{
Packit 992a25
			type = (const char*)typefix((char*)fp->encode.bigram, sizeof(fp->encode.bigram), type);
Packit 992a25
			if (x = (Type_t*)dtmatch(fp->encode.namedict, type))
Packit 992a25
				u = x->index;
Packit 992a25
			else if (!(x = newof(0, Type_t, 1, strlen(type) + 1)))
Packit 992a25
				u = 0;
Packit 992a25
			else
Packit 992a25
			{
Packit 992a25
				u = x->index = ++fp->types;
Packit 992a25
				strcpy(x->name, type);
Packit 992a25
				dtinsert(fp->encode.namedict, x);
Packit 992a25
				dtinsert(fp->encode.indexdict, x);
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		else
Packit 992a25
			u = 0;
Packit 992a25
		sfputu(fp->fp, u);
Packit 992a25
		/*FALLTHROUGH...*/
Packit 992a25
	case FF_dir:
Packit 992a25
		d = n - fp->encode.prefix;
Packit 992a25
		sfputl(fp->fp, d);
Packit 992a25
		fp->encode.prefix = n;
Packit 992a25
		sfputr(fp->fp, (char*)s, 0);
Packit 992a25
		break;
Packit 992a25
	}
Packit 992a25
	memcpy(fp->encode.path, path, len);
Packit 992a25
	return 0;
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * findsync() helper
Packit 992a25
 */
Packit 992a25
Packit 992a25
static int
Packit 992a25
finddone(register Find_t* fp)
Packit 992a25
{
Packit 992a25
	int	r;
Packit 992a25
Packit 992a25
	if (sfsync(fp->fp))
Packit 992a25
	{
Packit 992a25
		if (fp->disc->errorf)
Packit 992a25
			(*fp->disc->errorf)(fp, fp->disc, 2, "%s: write error [sfsync]", fp->encode.file);
Packit 992a25
		return -1;
Packit 992a25
	}
Packit 992a25
	if (sferror(fp->fp))
Packit 992a25
	{
Packit 992a25
		if (fp->disc->errorf)
Packit 992a25
			(*fp->disc->errorf)(fp, fp->disc, 2, "%s: write error [sferror]", fp->encode.file);
Packit 992a25
		return -1;
Packit 992a25
	}
Packit 992a25
	r = sfclose(fp->fp);
Packit 992a25
	fp->fp = 0;
Packit 992a25
	if (r)
Packit 992a25
	{
Packit 992a25
		if (fp->disc->errorf)
Packit 992a25
			(*fp->disc->errorf)(fp, fp->disc, 2, "%s: write error [sfclose]", fp->encode.file);
Packit 992a25
		return -1;
Packit 992a25
	}
Packit 992a25
	return 0;
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * finish the code table
Packit 992a25
 */
Packit 992a25
Packit 992a25
static int
Packit 992a25
findsync(register Find_t* fp)
Packit 992a25
{
Packit 992a25
	register char*		s;
Packit 992a25
	register int		n;
Packit 992a25
	register int		m;
Packit 992a25
	register int		d;
Packit 992a25
	register Type_t*	x;
Packit 992a25
	char*			t;
Packit 992a25
	int			b;
Packit 992a25
	long			z;
Packit 992a25
	Sfio_t*			sp;
Packit 992a25
Packit 992a25
	switch (fp->method)
Packit 992a25
	{
Packit 992a25
	case FF_dir:
Packit 992a25
	case FF_gnu:
Packit 992a25
		/*
Packit 992a25
		 * replace the real file with the temp file
Packit 992a25
		 */
Packit 992a25
Packit 992a25
		if (finddone(fp))
Packit 992a25
			goto bad;
Packit 992a25
		remove(fp->encode.file);
Packit 992a25
		if (rename(fp->encode.temp, fp->encode.file))
Packit 992a25
		{
Packit 992a25
			if (fp->disc->errorf)
Packit 992a25
				(*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "%s: cannot rename from tmp file %s", fp->encode.file, fp->encode.temp);
Packit 992a25
			remove(fp->encode.temp);
Packit 992a25
			return -1;
Packit 992a25
		}
Packit 992a25
		break;
Packit 992a25
	case FF_old:
Packit 992a25
		/*
Packit 992a25
		 * determine the top FF_MAX bigrams
Packit 992a25
		 */
Packit 992a25
Packit 992a25
		for (n = 0; n < FF_MAX; n++)
Packit 992a25
			for (m = 0; m < FF_MAX; m++)
Packit 992a25
				fp->encode.hits[fp->encode.code[n][m]]++;
Packit 992a25
		fp->encode.hits[0] = 0;
Packit 992a25
		m = 1;
Packit 992a25
		for (n = USHRT_MAX; n >= 0; n--)
Packit 992a25
			if (d = fp->encode.hits[n])
Packit 992a25
			{
Packit 992a25
				fp->encode.hits[n] = m;
Packit 992a25
				if ((m += d) > FF_MAX)
Packit 992a25
					break;
Packit 992a25
			}
Packit 992a25
		while (--n >= 0)
Packit 992a25
			fp->encode.hits[n] = 0;
Packit 992a25
		for (n = FF_MAX - 1; n >= 0; n--)
Packit 992a25
			for (m = FF_MAX - 1; m >= 0; m--)
Packit 992a25
				if (fp->encode.hits[fp->encode.code[n][m]])
Packit 992a25
				{
Packit 992a25
					d = fp->encode.code[n][m];
Packit 992a25
					b = fp->encode.hits[d] - 1;
Packit 992a25
					fp->encode.code[n][m] = b + FF_MAX;
Packit 992a25
					if (fp->encode.hits[d]++ >= FF_MAX)
Packit 992a25
						fp->encode.hits[d] = 0;
Packit 992a25
					fp->encode.bigram[b *= 2] = n;
Packit 992a25
					fp->encode.bigram[b + 1] = m;
Packit 992a25
				}
Packit 992a25
				else
Packit 992a25
					fp->encode.code[n][m] = 0;
Packit 992a25
Packit 992a25
		/*
Packit 992a25
		 * commit the real file 
Packit 992a25
		 */
Packit 992a25
Packit 992a25
		if (sfseek(fp->fp, (Sfoff_t)0, SEEK_SET))
Packit 992a25
		{
Packit 992a25
			if (fp->disc->errorf)
Packit 992a25
				(*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "cannot rewind tmp file");
Packit 992a25
			return -1;
Packit 992a25
		}
Packit 992a25
		if (!(sp = sfopen(NiL, fp->encode.file, "w")))
Packit 992a25
			goto badcreate;
Packit 992a25
Packit 992a25
		/*
Packit 992a25
		 * dump the bigrams
Packit 992a25
		 */
Packit 992a25
Packit 992a25
		sfwrite(sp, fp->encode.bigram, sizeof(fp->encode.bigram));
Packit 992a25
Packit 992a25
		/*
Packit 992a25
		 * encode the massaged paths
Packit 992a25
		 */
Packit 992a25
Packit 992a25
		while (s = sfgetr(fp->fp, 0, 0))
Packit 992a25
		{
Packit 992a25
			z = strtol(s, &t, 0);
Packit 992a25
			s = t;
Packit 992a25
			if (z < 0 || z > 2 * FF_OFF)
Packit 992a25
			{
Packit 992a25
				sfputc(sp, FF_ESC);
Packit 992a25
				sfputc(sp, (z >> 24));
Packit 992a25
				sfputc(sp, (z >> 16));
Packit 992a25
				sfputc(sp, (z >> 8));
Packit 992a25
				sfputc(sp, z);
Packit 992a25
			}
Packit 992a25
			else
Packit 992a25
				sfputc(sp, z);
Packit 992a25
			while (n = *s++)
Packit 992a25
			{
Packit 992a25
				if (!(m = *s++))
Packit 992a25
				{
Packit 992a25
					sfputc(sp, n);
Packit 992a25
					break;
Packit 992a25
				}
Packit 992a25
				if (d = fp->encode.code[n][m])
Packit 992a25
					sfputc(sp, d);
Packit 992a25
				else
Packit 992a25
				{
Packit 992a25
					sfputc(sp, n);
Packit 992a25
					sfputc(sp, m);
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		sfclose(fp->fp);
Packit 992a25
		fp->fp = sp;
Packit 992a25
		if (finddone(fp))
Packit 992a25
			goto bad;
Packit 992a25
		break;
Packit 992a25
	case FF_typ:
Packit 992a25
		if (finddone(fp))
Packit 992a25
			goto bad;
Packit 992a25
		if (!(fp->fp = sfopen(NiL, fp->encode.temp, "r")))
Packit 992a25
		{
Packit 992a25
			if (fp->disc->errorf)
Packit 992a25
				(*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "%s: cannot read tmp file", fp->encode.temp);
Packit 992a25
			remove(fp->encode.temp);
Packit 992a25
			return -1;
Packit 992a25
		}
Packit 992a25
Packit 992a25
		/*
Packit 992a25
		 * commit the output file
Packit 992a25
		 */
Packit 992a25
Packit 992a25
		if (!(sp = sfopen(NiL, fp->encode.file, "w")))
Packit 992a25
			goto badcreate;
Packit 992a25
Packit 992a25
		/*
Packit 992a25
		 * write the header magic
Packit 992a25
		 */
Packit 992a25
Packit 992a25
		sfputc(sp, 0);
Packit 992a25
		sfputr(sp, FF_typ_magic, 0);
Packit 992a25
Packit 992a25
		/*
Packit 992a25
		 * write the type table in index order starting with 1
Packit 992a25
		 */
Packit 992a25
Packit 992a25
		for (x = (Type_t*)dtfirst(fp->encode.indexdict); x; x = (Type_t*)dtnext(fp->encode.indexdict, x))
Packit 992a25
			sfputr(sp, x->name, 0);
Packit 992a25
		sfputc(sp, 0);
Packit 992a25
Packit 992a25
		/*
Packit 992a25
		 * append the front compressed strings
Packit 992a25
		 */
Packit 992a25
Packit 992a25
		if (sfmove(fp->fp, sp, SF_UNBOUND, -1) < 0 || !sfeof(fp->fp))
Packit 992a25
		{
Packit 992a25
			sfclose(sp);
Packit 992a25
			if (fp->disc->errorf)
Packit 992a25
				(*fp->disc->errorf)(fp, fp->disc, 2, "%s: cannot append codes", fp->encode.file);
Packit 992a25
			goto bad;
Packit 992a25
		}
Packit 992a25
		sfclose(fp->fp);
Packit 992a25
		fp->fp = sp;
Packit 992a25
		if (finddone(fp))
Packit 992a25
			goto bad;
Packit 992a25
		remove(fp->encode.temp);
Packit 992a25
		break;
Packit 992a25
	}
Packit 992a25
	return 0;
Packit 992a25
 badcreate:
Packit 992a25
	if (fp->disc->errorf)
Packit 992a25
		(*fp->disc->errorf)(fp, fp->disc, 2, "%s: cannot write codes", fp->encode.file);
Packit 992a25
 bad:
Packit 992a25
	if (fp->fp)
Packit 992a25
	{
Packit 992a25
		sfclose(fp->fp);
Packit 992a25
		fp->fp = 0;
Packit 992a25
	}
Packit 992a25
	remove(fp->encode.temp);
Packit 992a25
	return -1;
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * close an open fastfind stream
Packit 992a25
 */
Packit 992a25
Packit 992a25
int
Packit 992a25
findclose(register Find_t* fp)
Packit 992a25
{
Packit 992a25
	int	n = 0;
Packit 992a25
Packit 992a25
	if (!fp)
Packit 992a25
		return -1;
Packit 992a25
	if (fp->generate)
Packit 992a25
	{
Packit 992a25
		n = findsync(fp);
Packit 992a25
		if (fp->encode.indexdict)
Packit 992a25
			dtclose(fp->encode.indexdict);
Packit 992a25
		if (fp->encode.namedict)
Packit 992a25
			dtclose(fp->encode.namedict);
Packit 992a25
	}
Packit 992a25
	else
Packit 992a25
	{
Packit 992a25
		if (fp->decode.match)
Packit 992a25
			regfree(&fp->decode.re);
Packit 992a25
		n = 0;
Packit 992a25
	}
Packit 992a25
	if (fp->fp)
Packit 992a25
		sfclose(fp->fp);
Packit 992a25
	vmclose(fp->vm);
Packit 992a25
	return n;
Packit 992a25
}