1da2e3ebdSchin #pragma prototyped
2da2e3ebdSchin /*
3da2e3ebdSchin * original code
4da2e3ebdSchin *
5da2e3ebdSchin * James A. Woods, Informatics General Corporation,
6da2e3ebdSchin * NASA Ames Research Center, 6/81.
7da2e3ebdSchin * Usenix ;login:, February/March, 1983, p. 8.
8da2e3ebdSchin *
9da2e3ebdSchin * discipline/method interface
10da2e3ebdSchin *
11da2e3ebdSchin * Glenn Fowler
12da2e3ebdSchin * AT&T Research
13da2e3ebdSchin * modified from the original BSD source
14da2e3ebdSchin *
15da2e3ebdSchin * 'fastfind' scans a file list for the full pathname of a file
16da2e3ebdSchin * given only a piece of the name. The list is processed with
17da2e3ebdSchin * with "front-compression" and bigram coding. Front compression reduces
18da2e3ebdSchin * space by a factor of 4-5, bigram coding by a further 20-25%.
19da2e3ebdSchin *
20da2e3ebdSchin * there are 4 methods:
21da2e3ebdSchin *
22da2e3ebdSchin * FF_old original with 7 bit bigram encoding (no magic)
23da2e3ebdSchin * FF_gnu 8 bit clean front compression (FF_gnu_magic)
24da2e3ebdSchin * FF_dir FF_gnu with sfgetl/sfputl and trailing / on dirs (FF_dir_magic)
25da2e3ebdSchin * FF_typ FF_dir with (mime) types (FF_typ_magic)
26da2e3ebdSchin *
27da2e3ebdSchin * the bigram encoding steals the eighth bit (that's why its FF_old)
28da2e3ebdSchin * maybe one day we'll limit it to readonly:
29da2e3ebdSchin *
30da2e3ebdSchin * 0-2*FF_OFF likeliest differential counts + offset to make nonnegative
31da2e3ebdSchin * FF_ESC 4 byte big-endian out-of-range count+FF_OFF follows
32da2e3ebdSchin * FF_MIN-FF_MAX ascii residue
33da2e3ebdSchin * >=FF_MAX bigram codes
34da2e3ebdSchin *
35da2e3ebdSchin * a two-tiered string search technique is employed
36da2e3ebdSchin *
37da2e3ebdSchin * a metacharacter-free subpattern and partial pathname is matched
38da2e3ebdSchin * backwards to avoid full expansion of the pathname list
39da2e3ebdSchin *
40da2e3ebdSchin * then the actual shell glob-style regular expression (if in this form)
41da2e3ebdSchin * is matched against the candidate pathnames using the slower regexec()
42da2e3ebdSchin *
43da2e3ebdSchin * The original BSD code is covered by the BSD license:
44da2e3ebdSchin *
45da2e3ebdSchin * Copyright (c) 1985, 1993, 1999
46da2e3ebdSchin * The Regents of the University of California. All rights reserved.
47da2e3ebdSchin *
48da2e3ebdSchin * Redistribution and use in source and binary forms, with or without
49da2e3ebdSchin * modification, are permitted provided that the following conditions
50da2e3ebdSchin * are met:
51da2e3ebdSchin * 1. Redistributions of source code must retain the above copyright
52da2e3ebdSchin * notice, this list of conditions and the following disclaimer.
53da2e3ebdSchin * 2. Redistributions in binary form must reproduce the above copyright
54da2e3ebdSchin * notice, this list of conditions and the following disclaimer in the
55da2e3ebdSchin * documentation and/or other materials provided with the distribution.
56da2e3ebdSchin * 3. Neither the name of the University nor the names of its contributors
57da2e3ebdSchin * may be used to endorse or promote products derived from this software
58da2e3ebdSchin * without specific prior written permission.
59da2e3ebdSchin *
60da2e3ebdSchin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61da2e3ebdSchin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62da2e3ebdSchin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63da2e3ebdSchin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64da2e3ebdSchin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65da2e3ebdSchin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66da2e3ebdSchin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67da2e3ebdSchin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68da2e3ebdSchin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69da2e3ebdSchin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70da2e3ebdSchin * SUCH DAMAGE.
71da2e3ebdSchin */
72da2e3ebdSchin
73da2e3ebdSchin static const char id[] = "\n@(#)$Id: fastfind (AT&T Research) 2002-10-02 $\0\n";
74da2e3ebdSchin
75da2e3ebdSchin static const char lib[] = "libast:fastfind";
76da2e3ebdSchin
77da2e3ebdSchin #include "findlib.h"
78da2e3ebdSchin
79da2e3ebdSchin #define FIND_MATCH "*/(find|locate)/*"
80da2e3ebdSchin
81da2e3ebdSchin /*
82da2e3ebdSchin * this db could be anywhere
83da2e3ebdSchin * findcodes[] directories are checked for findnames[i]
84da2e3ebdSchin */
85da2e3ebdSchin
86da2e3ebdSchin static char* findcodes[] =
87da2e3ebdSchin {
88da2e3ebdSchin 0,
89da2e3ebdSchin 0,
90da2e3ebdSchin FIND_CODES,
91da2e3ebdSchin "/usr/local/share/lib",
92da2e3ebdSchin "/usr/local/lib",
93da2e3ebdSchin "/usr/share/lib",
94da2e3ebdSchin "/usr/lib",
95da2e3ebdSchin "/var/spool",
96da2e3ebdSchin "/usr/local/var",
97da2e3ebdSchin "/var/lib",
98da2e3ebdSchin "/var/lib/slocate",
99da2e3ebdSchin "/var/db",
100da2e3ebdSchin };
101da2e3ebdSchin
102da2e3ebdSchin static char* findnames[] =
103da2e3ebdSchin {
104da2e3ebdSchin "find/codes",
105da2e3ebdSchin "find/find.codes",
106da2e3ebdSchin "locate/locatedb",
107da2e3ebdSchin "locatedb",
108da2e3ebdSchin "locate.database",
109da2e3ebdSchin "slocate.db",
110da2e3ebdSchin };
111da2e3ebdSchin
112da2e3ebdSchin /*
113da2e3ebdSchin * convert t to lower case and drop leading x- and x- after /
114da2e3ebdSchin * converted value copied to b of size n
115da2e3ebdSchin */
116da2e3ebdSchin
117da2e3ebdSchin char*
typefix(char * buf,size_t n,register const char * t)118da2e3ebdSchin typefix(char* buf, size_t n, register const char* t)
119da2e3ebdSchin {
120da2e3ebdSchin register int c;
121da2e3ebdSchin register char* b = buf;
122da2e3ebdSchin
123da2e3ebdSchin if ((*t == 'x' || *t == 'X') && *(t + 1) == '-')
124da2e3ebdSchin t += 2;
125da2e3ebdSchin while (c = *t++)
126da2e3ebdSchin {
127da2e3ebdSchin if (isupper(c))
128da2e3ebdSchin c = tolower(c);
129da2e3ebdSchin if ((*b++ = c) == '/' && (*t == 'x' || *t == 'X') && *(t + 1) == '-')
130da2e3ebdSchin t += 2;
131da2e3ebdSchin }
132da2e3ebdSchin *b = 0;
133da2e3ebdSchin return buf;
134da2e3ebdSchin }
135da2e3ebdSchin
136da2e3ebdSchin /*
137da2e3ebdSchin * return a fastfind stream handle for pattern
138da2e3ebdSchin */
139da2e3ebdSchin
140da2e3ebdSchin Find_t*
findopen(const char * file,const char * pattern,const char * type,Finddisc_t * disc)141da2e3ebdSchin findopen(const char* file, const char* pattern, const char* type, Finddisc_t* disc)
142da2e3ebdSchin {
143da2e3ebdSchin register Find_t* fp;
144da2e3ebdSchin register char* p;
145da2e3ebdSchin register char* s;
146da2e3ebdSchin register char* b;
147da2e3ebdSchin register int i;
148da2e3ebdSchin register int j;
149da2e3ebdSchin char* path;
150da2e3ebdSchin int brace = 0;
151da2e3ebdSchin int paren = 0;
152da2e3ebdSchin int k;
153da2e3ebdSchin int q;
154da2e3ebdSchin int fd;
155da2e3ebdSchin int uid;
156da2e3ebdSchin Vmalloc_t* vm;
157da2e3ebdSchin Type_t* tp;
158da2e3ebdSchin struct stat st;
159da2e3ebdSchin
160da2e3ebdSchin
161da2e3ebdSchin if (!(vm = vmopen(Vmdcheap, Vmbest, 0)))
162da2e3ebdSchin goto nospace;
163da2e3ebdSchin
164da2e3ebdSchin /*
165da2e3ebdSchin * NOTE: searching for FIND_CODES would be much simpler if we
166da2e3ebdSchin * just stuck with our own, but we also support GNU
167da2e3ebdSchin * locate codes and have to search for the one of a
168da2e3ebdSchin * bazillion possible names for that file
169da2e3ebdSchin */
170da2e3ebdSchin
171da2e3ebdSchin if (!findcodes[1])
172da2e3ebdSchin findcodes[1] = getenv(FIND_CODES_ENV);
173da2e3ebdSchin if (disc->flags & FIND_GENERATE)
174da2e3ebdSchin {
175da2e3ebdSchin if (!(fp = (Find_t*)vmnewof(vm, 0, Find_t, 1, sizeof(Encode_t) - sizeof(Code_t))))
176da2e3ebdSchin goto nospace;
177da2e3ebdSchin fp->vm = vm;
178da2e3ebdSchin fp->id = lib;
179da2e3ebdSchin fp->disc = disc;
180da2e3ebdSchin fp->generate = 1;
181da2e3ebdSchin if (file && (!*file || streq(file, "-")))
182da2e3ebdSchin file = 0;
183da2e3ebdSchin uid = geteuid();
184da2e3ebdSchin j = (findcodes[0] = (char*)file) && *file == '/' ? 1 : elementsof(findcodes);
185da2e3ebdSchin
186da2e3ebdSchin /*
187da2e3ebdSchin * look for the codes file, but since it may not exist yet,
188da2e3ebdSchin * also look for the containing directory if i<2 or if
189da2e3ebdSchin * it is sufficiently qualified (FIND_MATCH)
190da2e3ebdSchin */
191da2e3ebdSchin
192da2e3ebdSchin for (i = 0; i < j; i++)
193da2e3ebdSchin if (path = findcodes[i])
194da2e3ebdSchin {
195da2e3ebdSchin if (*path == '/')
196da2e3ebdSchin {
197da2e3ebdSchin if (!stat(path, &st))
198da2e3ebdSchin {
199da2e3ebdSchin if (S_ISDIR(st.st_mode))
200da2e3ebdSchin {
201da2e3ebdSchin for (k = 0; k < elementsof(findnames); k++)
202da2e3ebdSchin {
203da2e3ebdSchin sfsprintf(fp->encode.file, sizeof(fp->encode.file), "%s/%s", path, findnames[k]);
204da2e3ebdSchin if (!eaccess(fp->encode.file, R_OK|W_OK))
205da2e3ebdSchin {
206da2e3ebdSchin path = fp->encode.file;
207da2e3ebdSchin break;
208da2e3ebdSchin }
209da2e3ebdSchin if (strchr(findnames[k], '/') && (b = strrchr(fp->encode.file, '/')))
210da2e3ebdSchin {
211da2e3ebdSchin *b = 0;
212da2e3ebdSchin if (!stat(fp->encode.file, &st) && st.st_uid == uid && (st.st_mode & S_IWUSR))
213da2e3ebdSchin {
214da2e3ebdSchin *b = '/';
215da2e3ebdSchin path = fp->encode.file;
216da2e3ebdSchin break;
217da2e3ebdSchin }
218da2e3ebdSchin }
219da2e3ebdSchin }
220da2e3ebdSchin if (k < elementsof(findnames))
221da2e3ebdSchin break;
222da2e3ebdSchin }
223da2e3ebdSchin else if (st.st_uid == uid && (st.st_mode & S_IWUSR))
224da2e3ebdSchin {
225da2e3ebdSchin sfsprintf(fp->encode.file, sizeof(fp->encode.file), "%s", path);
226da2e3ebdSchin path = fp->encode.file;
227da2e3ebdSchin break;
228da2e3ebdSchin }
229da2e3ebdSchin }
230da2e3ebdSchin else if (i < 2 || strmatch(path, FIND_MATCH))
231da2e3ebdSchin {
232da2e3ebdSchin sfsprintf(fp->encode.file, sizeof(fp->encode.file), "%s", path);
233da2e3ebdSchin if (b = strrchr(fp->encode.file, '/'))
234da2e3ebdSchin {
235da2e3ebdSchin *b = 0;
236da2e3ebdSchin if (!stat(fp->encode.file, &st) && st.st_uid == uid && (st.st_mode & S_IWUSR))
237da2e3ebdSchin {
238da2e3ebdSchin *b = '/';
239da2e3ebdSchin path = fp->encode.file;
240da2e3ebdSchin break;
241da2e3ebdSchin }
242da2e3ebdSchin }
243da2e3ebdSchin }
244da2e3ebdSchin }
245*b30d1939SAndy Fiddaman else if (pathpath(path, "", PATH_REGULAR|PATH_READ|PATH_WRITE, fp->encode.file, sizeof(fp->encode.file)))
246da2e3ebdSchin {
247da2e3ebdSchin path = fp->encode.file;
248da2e3ebdSchin break;
249da2e3ebdSchin }
250da2e3ebdSchin else if (b = strrchr(path, '/'))
251da2e3ebdSchin {
252da2e3ebdSchin sfsprintf(fp->encode.file, sizeof(fp->encode.file), "%-.*s", b - path, path);
253*b30d1939SAndy Fiddaman if (pathpath(fp->encode.file, "", PATH_EXECUTE|PATH_READ|PATH_WRITE, fp->encode.temp, sizeof(fp->encode.temp)) &&
254da2e3ebdSchin !stat(fp->encode.temp, &st) && st.st_uid == uid && (st.st_mode & S_IWUSR))
255da2e3ebdSchin {
256da2e3ebdSchin sfsprintf(fp->encode.file, sizeof(fp->encode.file), "%s%s", fp->encode.temp, b);
257da2e3ebdSchin path = fp->encode.file;
258da2e3ebdSchin break;
259da2e3ebdSchin }
260da2e3ebdSchin }
261da2e3ebdSchin }
262da2e3ebdSchin if (i >= j)
263da2e3ebdSchin {
264da2e3ebdSchin if (fp->disc->errorf)
265da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, 2, "%s: cannot locate codes", file ? file : findcodes[2]);
266da2e3ebdSchin goto drop;
267da2e3ebdSchin }
268da2e3ebdSchin if (fp->disc->flags & FIND_OLD)
269da2e3ebdSchin {
270da2e3ebdSchin /*
271da2e3ebdSchin * FF_old generates temp data that is read
272da2e3ebdSchin * in a second pass to generate the real codes
273da2e3ebdSchin */
274da2e3ebdSchin
275da2e3ebdSchin fp->method = FF_old;
276da2e3ebdSchin if (!(fp->fp = sftmp(32 * PATH_MAX)))
277da2e3ebdSchin {
278da2e3ebdSchin if (fp->disc->errorf)
279da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "cannot create tmp file");
280da2e3ebdSchin goto drop;
281da2e3ebdSchin }
282da2e3ebdSchin }
283da2e3ebdSchin else
284da2e3ebdSchin {
285da2e3ebdSchin /*
286da2e3ebdSchin * the rest generate into a temp file that
287da2e3ebdSchin * is simply renamed on completion
288da2e3ebdSchin */
289da2e3ebdSchin
290da2e3ebdSchin if (s = strrchr(path, '/'))
291da2e3ebdSchin {
292da2e3ebdSchin *s = 0;
293da2e3ebdSchin p = path;
294da2e3ebdSchin }
295da2e3ebdSchin else
296da2e3ebdSchin p = ".";
297da2e3ebdSchin if (!pathtemp(fp->encode.temp, sizeof(fp->encode.temp), p, "ff", &fd))
298da2e3ebdSchin {
299da2e3ebdSchin if (fp->disc->errorf)
300da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "%s: cannot create tmp file in this directory", p ? p : ".");
301da2e3ebdSchin goto drop;
302da2e3ebdSchin }
303da2e3ebdSchin if (s)
304da2e3ebdSchin *s = '/';
305da2e3ebdSchin if (!(fp->fp = sfnew(NiL, NiL, (size_t)SF_UNBOUND, fd, SF_WRITE)))
306da2e3ebdSchin {
307da2e3ebdSchin if (fp->disc->errorf)
308da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "%s: cannot open tmp file", fp->encode.temp);
309da2e3ebdSchin close(fd);
310da2e3ebdSchin goto drop;
311da2e3ebdSchin }
312da2e3ebdSchin if (fp->disc->flags & FIND_TYPE)
313da2e3ebdSchin {
314da2e3ebdSchin fp->method = FF_typ;
315da2e3ebdSchin fp->encode.namedisc.key = offsetof(Type_t, name);
316da2e3ebdSchin fp->encode.namedisc.link = offsetof(Type_t, byname);
317da2e3ebdSchin fp->encode.indexdisc.key = offsetof(Type_t, index);
318da2e3ebdSchin fp->encode.indexdisc.size = sizeof(unsigned long);
319da2e3ebdSchin fp->encode.indexdisc.link = offsetof(Type_t, byindex);
320da2e3ebdSchin s = "system/dir";
321*b30d1939SAndy Fiddaman 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)))
322da2e3ebdSchin {
323da2e3ebdSchin if (fp->encode.namedict)
324da2e3ebdSchin dtclose(fp->encode.namedict);
325da2e3ebdSchin if (fp->disc->errorf)
326da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, 2, "cannot allocate type table");
327da2e3ebdSchin goto drop;
328da2e3ebdSchin }
329da2e3ebdSchin
330da2e3ebdSchin /*
331da2e3ebdSchin * type index 1 is always system/dir
332da2e3ebdSchin */
333da2e3ebdSchin
334da2e3ebdSchin tp->index = ++fp->types;
335da2e3ebdSchin strcpy(tp->name, s);
336da2e3ebdSchin dtinsert(fp->encode.namedict, tp);
337da2e3ebdSchin dtinsert(fp->encode.indexdict, tp);
338da2e3ebdSchin }
339da2e3ebdSchin else if (fp->disc->flags & FIND_GNU)
340da2e3ebdSchin {
341da2e3ebdSchin fp->method = FF_gnu;
342da2e3ebdSchin sfputc(fp->fp, 0);
343da2e3ebdSchin sfputr(fp->fp, FF_gnu_magic, 0);
344da2e3ebdSchin }
345da2e3ebdSchin else
346da2e3ebdSchin {
347da2e3ebdSchin fp->method = FF_dir;
348da2e3ebdSchin sfputc(fp->fp, 0);
349da2e3ebdSchin sfputr(fp->fp, FF_dir_magic, 0);
350da2e3ebdSchin }
351da2e3ebdSchin }
352da2e3ebdSchin }
353da2e3ebdSchin else
354da2e3ebdSchin {
355da2e3ebdSchin i = sizeof(Decode_t) + sizeof(Code_t);
356da2e3ebdSchin if (!pattern || !*pattern)
357da2e3ebdSchin pattern = "*";
358da2e3ebdSchin i += (j = 2 * (strlen(pattern) + 1));
359da2e3ebdSchin if (!(fp = (Find_t*)vmnewof(vm, 0, Find_t, 1, i)))
360da2e3ebdSchin {
361da2e3ebdSchin vmclose(vm);
362da2e3ebdSchin return 0;
363da2e3ebdSchin }
364da2e3ebdSchin fp->vm = vm;
365da2e3ebdSchin fp->id = lib;
366da2e3ebdSchin fp->disc = disc;
367da2e3ebdSchin if (disc->flags & FIND_ICASE)
368da2e3ebdSchin fp->decode.ignorecase = 1;
369da2e3ebdSchin j = (findcodes[0] = (char*)file) && *file == '/' ? 1 : elementsof(findcodes);
370da2e3ebdSchin for (i = 0; i < j; i++)
371da2e3ebdSchin if (path = findcodes[i])
372da2e3ebdSchin {
373da2e3ebdSchin if (*path == '/')
374da2e3ebdSchin {
375da2e3ebdSchin if (!stat(path, &st))
376da2e3ebdSchin {
377da2e3ebdSchin if (S_ISDIR(st.st_mode))
378da2e3ebdSchin {
379da2e3ebdSchin for (k = 0; k < elementsof(findnames); k++)
380da2e3ebdSchin {
381da2e3ebdSchin sfsprintf(fp->decode.path, sizeof(fp->decode.path), "%s/%s", path, findnames[k]);
382da2e3ebdSchin if (fp->fp = sfopen(NiL, fp->decode.path, "r"))
383da2e3ebdSchin {
384da2e3ebdSchin path = fp->decode.path;
385da2e3ebdSchin break;
386da2e3ebdSchin }
387da2e3ebdSchin }
388da2e3ebdSchin if (fp->fp)
389da2e3ebdSchin break;
390da2e3ebdSchin }
391da2e3ebdSchin else if (fp->fp = sfopen(NiL, path, "r"))
392da2e3ebdSchin break;
393da2e3ebdSchin }
394da2e3ebdSchin }
395*b30d1939SAndy Fiddaman else if ((path = pathpath(path, "", PATH_REGULAR|PATH_READ, fp->decode.path, sizeof(fp->decode.path))) && (fp->fp = sfopen(NiL, path, "r")))
396da2e3ebdSchin break;
397da2e3ebdSchin }
398da2e3ebdSchin if (!fp->fp)
399da2e3ebdSchin {
400da2e3ebdSchin if (fp->disc->errorf)
401da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, 2, "%s: cannot locate codes", file ? file : findcodes[2]);
402da2e3ebdSchin goto drop;
403da2e3ebdSchin }
404da2e3ebdSchin if (fstat(sffileno(fp->fp), &st))
405da2e3ebdSchin {
406da2e3ebdSchin if (fp->disc->errorf)
407da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, 2, "%s: cannot stat codes", path);
408da2e3ebdSchin goto drop;
409da2e3ebdSchin }
410da2e3ebdSchin if (fp->secure = ((st.st_mode & (S_IRGRP|S_IROTH)) == S_IRGRP) && st.st_gid == getegid() && getegid() != getgid())
411da2e3ebdSchin setgid(getgid());
412da2e3ebdSchin fp->stamp = st.st_mtime;
413da2e3ebdSchin b = (s = fp->decode.temp) + 1;
414da2e3ebdSchin for (i = 0; i < elementsof(fp->decode.bigram1); i++)
415da2e3ebdSchin {
416da2e3ebdSchin if ((j = sfgetc(fp->fp)) == EOF)
417da2e3ebdSchin goto invalid;
418da2e3ebdSchin if (!(*s++ = fp->decode.bigram1[i] = j) && i)
419da2e3ebdSchin {
420da2e3ebdSchin i = -i;
421da2e3ebdSchin break;
422da2e3ebdSchin }
423da2e3ebdSchin if ((j = sfgetc(fp->fp)) == EOF)
424da2e3ebdSchin goto invalid;
425da2e3ebdSchin if (!(*s++ = fp->decode.bigram2[i] = j) && (i || fp->decode.bigram1[0] >= '0' && fp->decode.bigram1[0] <= '1'))
426da2e3ebdSchin break;
427da2e3ebdSchin }
428da2e3ebdSchin if (streq(b, FF_typ_magic))
429da2e3ebdSchin {
430da2e3ebdSchin if (type)
431da2e3ebdSchin {
432da2e3ebdSchin type = (const char*)typefix(fp->decode.bigram2, sizeof(fp->decode.bigram2), type);
433da2e3ebdSchin memset(fp->decode.bigram1, 0, sizeof(fp->decode.bigram1));
434da2e3ebdSchin }
435da2e3ebdSchin fp->method = FF_typ;
436da2e3ebdSchin for (j = 0, i = 1;; i++)
437da2e3ebdSchin {
438da2e3ebdSchin if (!(s = sfgetr(fp->fp, 0, 0)))
439da2e3ebdSchin goto invalid;
440da2e3ebdSchin if (!*s)
441da2e3ebdSchin break;
442da2e3ebdSchin if (type && strmatch(s, type))
443da2e3ebdSchin {
444da2e3ebdSchin FF_SET_TYPE(fp, i);
445da2e3ebdSchin j++;
446da2e3ebdSchin }
447da2e3ebdSchin }
448da2e3ebdSchin if (type && !j)
449da2e3ebdSchin goto drop;
450da2e3ebdSchin fp->types = j;
451da2e3ebdSchin }
452da2e3ebdSchin else if (streq(b, FF_dir_magic))
453da2e3ebdSchin fp->method = FF_dir;
454da2e3ebdSchin else if (streq(b, FF_gnu_magic))
455da2e3ebdSchin fp->method = FF_gnu;
456da2e3ebdSchin else if (!*b && *--b >= '0' && *b <= '1')
457da2e3ebdSchin {
458da2e3ebdSchin fp->method = FF_gnu;
459da2e3ebdSchin while (j = sfgetc(fp->fp))
460da2e3ebdSchin {
461da2e3ebdSchin if (j == EOF || fp->decode.count >= sizeof(fp->decode.path))
462da2e3ebdSchin goto invalid;
463da2e3ebdSchin fp->decode.path[fp->decode.count++] = j;
464da2e3ebdSchin }
465da2e3ebdSchin }
466da2e3ebdSchin else
467da2e3ebdSchin {
468da2e3ebdSchin fp->method = FF_old;
469da2e3ebdSchin if (i < 0)
470da2e3ebdSchin {
471da2e3ebdSchin if ((j = sfgetc(fp->fp)) == EOF)
472da2e3ebdSchin goto invalid;
473da2e3ebdSchin fp->decode.bigram2[i = -i] = j;
474da2e3ebdSchin }
475da2e3ebdSchin while (++i < elementsof(fp->decode.bigram1))
476da2e3ebdSchin {
477da2e3ebdSchin if ((j = sfgetc(fp->fp)) == EOF)
478da2e3ebdSchin goto invalid;
479da2e3ebdSchin fp->decode.bigram1[i] = j;
480da2e3ebdSchin if ((j = sfgetc(fp->fp)) == EOF)
481da2e3ebdSchin goto invalid;
482da2e3ebdSchin fp->decode.bigram2[i] = j;
483da2e3ebdSchin }
484da2e3ebdSchin if ((fp->decode.peek = sfgetc(fp->fp)) != FF_OFF)
485da2e3ebdSchin goto invalid;
486da2e3ebdSchin }
487da2e3ebdSchin
488da2e3ebdSchin /*
489da2e3ebdSchin * set up the physical dir table
490da2e3ebdSchin */
491da2e3ebdSchin
492da2e3ebdSchin if (disc->version >= 19980301L)
493da2e3ebdSchin {
494da2e3ebdSchin fp->verifyf = disc->verifyf;
495da2e3ebdSchin if (disc->dirs && *disc->dirs)
496da2e3ebdSchin {
497da2e3ebdSchin for (k = 0; disc->dirs[k]; k++);
498da2e3ebdSchin if (k == 1 && streq(disc->dirs[0], "/"))
499da2e3ebdSchin k = 0;
500da2e3ebdSchin if (k)
501da2e3ebdSchin {
502da2e3ebdSchin if (!(fp->dirs = vmnewof(fp->vm, 0, char*, 2 * k + 1, 0)))
503da2e3ebdSchin goto drop;
504da2e3ebdSchin if (!(fp->lens = vmnewof(fp->vm, 0, int, 2 * k, 0)))
505da2e3ebdSchin goto drop;
506da2e3ebdSchin p = 0;
507da2e3ebdSchin b = fp->decode.temp;
508da2e3ebdSchin j = fp->method == FF_old || fp->method == FF_gnu;
509da2e3ebdSchin
510da2e3ebdSchin /*
511da2e3ebdSchin * fill the dir list with logical and
512da2e3ebdSchin * physical names since we don't know
513da2e3ebdSchin * which way the db was encoded (it
514da2e3ebdSchin * could be *both* ways)
515da2e3ebdSchin */
516da2e3ebdSchin
517da2e3ebdSchin for (i = q = 0; i < k; i++)
518da2e3ebdSchin {
519da2e3ebdSchin if (*(s = disc->dirs[i]) == '/')
520da2e3ebdSchin sfsprintf(b, sizeof(fp->decode.temp) - 1, "%s", s);
521da2e3ebdSchin else if (!p && !(p = getcwd(fp->decode.path, sizeof(fp->decode.path))))
522da2e3ebdSchin goto nospace;
523da2e3ebdSchin else
524da2e3ebdSchin sfsprintf(b, sizeof(fp->decode.temp) - 1, "%s/%s", p, s);
525*b30d1939SAndy Fiddaman s = pathcanon(b, sizeof(fp->decode.temp), 0);
526da2e3ebdSchin *s = '/';
527da2e3ebdSchin *(s + 1) = 0;
528da2e3ebdSchin if (!(fp->dirs[q] = vmstrdup(fp->vm, b)))
529da2e3ebdSchin goto nospace;
530da2e3ebdSchin if (j)
531da2e3ebdSchin (fp->dirs[q])[s - b] = 0;
532da2e3ebdSchin q++;
533da2e3ebdSchin *s = 0;
534*b30d1939SAndy Fiddaman s = pathcanon(b, sizeof(fp->decode.temp), PATH_PHYSICAL);
535da2e3ebdSchin *s = '/';
536da2e3ebdSchin *(s + 1) = 0;
537da2e3ebdSchin if (!strneq(b, fp->dirs[q - 1], s - b))
538da2e3ebdSchin {
539da2e3ebdSchin if (!(fp->dirs[q] = vmstrdup(fp->vm, b)))
540da2e3ebdSchin goto nospace;
541da2e3ebdSchin if (j)
542da2e3ebdSchin (fp->dirs[q])[s - b] = 0;
543da2e3ebdSchin q++;
544da2e3ebdSchin }
545da2e3ebdSchin }
546da2e3ebdSchin strsort(fp->dirs, q, strcasecmp);
547da2e3ebdSchin for (i = 0; i < q; i++)
548da2e3ebdSchin fp->lens[i] = strlen(fp->dirs[i]);
549da2e3ebdSchin }
550da2e3ebdSchin }
551da2e3ebdSchin }
552da2e3ebdSchin if (fp->verifyf || (disc->flags & FIND_VERIFY))
553da2e3ebdSchin {
554da2e3ebdSchin if (fp->method != FF_dir && fp->method != FF_typ)
555da2e3ebdSchin {
556da2e3ebdSchin if (fp->disc->errorf)
557da2e3ebdSchin (*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");
558da2e3ebdSchin goto drop;
559da2e3ebdSchin }
560da2e3ebdSchin fp->verify = 1;
561da2e3ebdSchin }
562da2e3ebdSchin
563da2e3ebdSchin /*
564da2e3ebdSchin * extract last glob-free subpattern in name for fast pre-match
565da2e3ebdSchin * prepend 0 for backwards match
566da2e3ebdSchin */
567da2e3ebdSchin
568da2e3ebdSchin if (p = s = (char*)pattern)
569da2e3ebdSchin {
570da2e3ebdSchin b = fp->decode.pattern;
571da2e3ebdSchin for (;;)
572da2e3ebdSchin {
573da2e3ebdSchin switch (*b++ = *p++)
574da2e3ebdSchin {
575da2e3ebdSchin case 0:
576da2e3ebdSchin break;
577da2e3ebdSchin case '\\':
578da2e3ebdSchin s = p;
579da2e3ebdSchin if (!*p++)
580da2e3ebdSchin break;
581da2e3ebdSchin continue;
582da2e3ebdSchin case '[':
583da2e3ebdSchin if (!brace)
584da2e3ebdSchin {
585da2e3ebdSchin brace++;
586da2e3ebdSchin if (*p == ']')
587da2e3ebdSchin p++;
588da2e3ebdSchin }
589da2e3ebdSchin continue;
590da2e3ebdSchin case ']':
591da2e3ebdSchin if (brace)
592da2e3ebdSchin {
593da2e3ebdSchin brace--;
594da2e3ebdSchin s = p;
595da2e3ebdSchin }
596da2e3ebdSchin continue;
597da2e3ebdSchin case '(':
598da2e3ebdSchin if (!brace)
599da2e3ebdSchin paren++;
600da2e3ebdSchin continue;
601da2e3ebdSchin case ')':
602da2e3ebdSchin if (!brace && paren > 0 && !--paren)
603da2e3ebdSchin s = p;
604da2e3ebdSchin continue;
605da2e3ebdSchin case '|':
606da2e3ebdSchin case '&':
607da2e3ebdSchin if (!brace && !paren)
608da2e3ebdSchin {
609da2e3ebdSchin s = "";
610da2e3ebdSchin break;
611da2e3ebdSchin }
612da2e3ebdSchin continue;
613da2e3ebdSchin case '*':
614da2e3ebdSchin case '?':
615da2e3ebdSchin s = p;
616da2e3ebdSchin continue;
617da2e3ebdSchin default:
618da2e3ebdSchin continue;
619da2e3ebdSchin }
620da2e3ebdSchin break;
621da2e3ebdSchin }
622da2e3ebdSchin if (s != pattern && !streq(pattern, "*"))
623da2e3ebdSchin {
624da2e3ebdSchin fp->decode.match = 1;
625da2e3ebdSchin if (i = regcomp(&fp->decode.re, pattern, REG_SHELL|REG_AUGMENTED|(fp->decode.ignorecase?REG_ICASE:0)))
626da2e3ebdSchin {
627da2e3ebdSchin if (disc->errorf)
628da2e3ebdSchin {
629da2e3ebdSchin regerror(i, &fp->decode.re, fp->decode.temp, sizeof(fp->decode.temp));
630da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, 2, "%s: %s", pattern, fp->decode.temp);
631da2e3ebdSchin }
632da2e3ebdSchin goto drop;
633da2e3ebdSchin }
634da2e3ebdSchin }
635da2e3ebdSchin if (*s)
636da2e3ebdSchin {
637da2e3ebdSchin *b++ = 0;
638da2e3ebdSchin while (i = *s++)
639da2e3ebdSchin *b++ = i;
640da2e3ebdSchin *b-- = 0;
641da2e3ebdSchin fp->decode.end = b;
642da2e3ebdSchin if (fp->decode.ignorecase)
643da2e3ebdSchin for (s = fp->decode.pattern; s <= b; s++)
644da2e3ebdSchin if (isupper(*s))
645da2e3ebdSchin *s = tolower(*s);
646da2e3ebdSchin }
647da2e3ebdSchin }
648da2e3ebdSchin }
649da2e3ebdSchin return fp;
650da2e3ebdSchin nospace:
651da2e3ebdSchin if (disc->errorf)
652da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, 2, "out of space");
653da2e3ebdSchin if (!vm)
654da2e3ebdSchin return 0;
655da2e3ebdSchin if (!fp)
656da2e3ebdSchin {
657da2e3ebdSchin vmclose(vm);
658da2e3ebdSchin return 0;
659da2e3ebdSchin }
660da2e3ebdSchin goto drop;
661da2e3ebdSchin invalid:
662da2e3ebdSchin if (fp->disc->errorf)
663da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, 2, "%s: invalid codes", path);
664da2e3ebdSchin drop:
665da2e3ebdSchin if (!fp->generate && fp->decode.match)
666da2e3ebdSchin regfree(&fp->decode.re);
667da2e3ebdSchin if (fp->fp)
668da2e3ebdSchin sfclose(fp->fp);
669da2e3ebdSchin vmclose(fp->vm);
670da2e3ebdSchin return 0;
671da2e3ebdSchin }
672da2e3ebdSchin
673da2e3ebdSchin /*
674da2e3ebdSchin * return the next fastfind path
675da2e3ebdSchin * 0 returned when list exhausted
676da2e3ebdSchin */
677da2e3ebdSchin
678da2e3ebdSchin char*
findread(register Find_t * fp)679da2e3ebdSchin findread(register Find_t* fp)
680da2e3ebdSchin {
681da2e3ebdSchin register char* p;
682da2e3ebdSchin register char* q;
683da2e3ebdSchin register char* s;
684da2e3ebdSchin register char* b;
685da2e3ebdSchin register char* e;
686da2e3ebdSchin register int c;
687da2e3ebdSchin register int n;
688da2e3ebdSchin register int m;
689da2e3ebdSchin int ignorecase;
690da2e3ebdSchin int t;
691da2e3ebdSchin unsigned char w[4];
692da2e3ebdSchin struct stat st;
693da2e3ebdSchin
694da2e3ebdSchin if (fp->generate)
695da2e3ebdSchin return 0;
696da2e3ebdSchin if (fp->decode.restore)
697da2e3ebdSchin {
698da2e3ebdSchin *fp->decode.restore = '/';
699da2e3ebdSchin fp->decode.restore = 0;
700da2e3ebdSchin }
701da2e3ebdSchin ignorecase = fp->decode.ignorecase ? STR_ICASE : 0;
702da2e3ebdSchin c = fp->decode.peek;
703da2e3ebdSchin next:
704da2e3ebdSchin for (;;)
705da2e3ebdSchin {
706da2e3ebdSchin switch (fp->method)
707da2e3ebdSchin {
708da2e3ebdSchin case FF_dir:
709da2e3ebdSchin t = 0;
710da2e3ebdSchin n = sfgetl(fp->fp);
711da2e3ebdSchin goto grab;
712da2e3ebdSchin case FF_gnu:
713da2e3ebdSchin if ((c = sfgetc(fp->fp)) == EOF)
714da2e3ebdSchin return 0;
715da2e3ebdSchin if (c == 0x80)
716da2e3ebdSchin {
717da2e3ebdSchin if ((c = sfgetc(fp->fp)) == EOF)
718da2e3ebdSchin return 0;
719da2e3ebdSchin n = c << 8;
720da2e3ebdSchin if ((c = sfgetc(fp->fp)) == EOF)
721da2e3ebdSchin return 0;
722da2e3ebdSchin n |= c;
723da2e3ebdSchin if (n & 0x8000)
724da2e3ebdSchin n = (n - 0xffff) - 1;
725da2e3ebdSchin }
726da2e3ebdSchin else if ((n = c) & 0x80)
727da2e3ebdSchin n = (n - 0xff) - 1;
728da2e3ebdSchin t = 0;
729da2e3ebdSchin goto grab;
730da2e3ebdSchin case FF_typ:
731da2e3ebdSchin t = sfgetu(fp->fp);
732da2e3ebdSchin n = sfgetl(fp->fp);
733da2e3ebdSchin grab:
734da2e3ebdSchin p = fp->decode.path + (fp->decode.count += n);
735da2e3ebdSchin do
736da2e3ebdSchin {
737da2e3ebdSchin if ((c = sfgetc(fp->fp)) == EOF)
738da2e3ebdSchin return 0;
739da2e3ebdSchin } while (*p++ = c);
740da2e3ebdSchin p -= 2;
741da2e3ebdSchin break;
742da2e3ebdSchin case FF_old:
743da2e3ebdSchin if (c == EOF)
744da2e3ebdSchin {
745da2e3ebdSchin fp->decode.peek = c;
746da2e3ebdSchin return 0;
747da2e3ebdSchin }
748da2e3ebdSchin if (c == FF_ESC)
749da2e3ebdSchin {
750da2e3ebdSchin if (sfread(fp->fp, w, sizeof(w)) != sizeof(w))
751da2e3ebdSchin return 0;
752da2e3ebdSchin if (fp->decode.swap >= 0)
753da2e3ebdSchin {
754da2e3ebdSchin c = (int32_t)((w[0] << 24) | (w[1] << 16) | (w[2] << 8) | w[3]);
755da2e3ebdSchin if (!fp->decode.swap)
756da2e3ebdSchin {
757da2e3ebdSchin /*
758da2e3ebdSchin * the old format uses machine
759da2e3ebdSchin * byte order; this test uses
760da2e3ebdSchin * the smallest magnitude of
761da2e3ebdSchin * both byte orders on the
762da2e3ebdSchin * first encoded path motion
763da2e3ebdSchin * to determine the original
764da2e3ebdSchin * byte order
765da2e3ebdSchin */
766da2e3ebdSchin
767da2e3ebdSchin m = c;
768da2e3ebdSchin if (m < 0)
769da2e3ebdSchin m = -m;
770da2e3ebdSchin n = (int32_t)((w[3] << 24) | (w[2] << 16) | (w[1] << 8) | w[0]);
771da2e3ebdSchin if (n < 0)
772da2e3ebdSchin n = -n;
773da2e3ebdSchin if (m < n)
774da2e3ebdSchin fp->decode.swap = 1;
775da2e3ebdSchin else
776da2e3ebdSchin {
777da2e3ebdSchin fp->decode.swap = -1;
778da2e3ebdSchin c = (int32_t)((w[3] << 24) | (w[2] << 16) | (w[1] << 8) | w[0]);
779da2e3ebdSchin }
780da2e3ebdSchin }
781da2e3ebdSchin }
782da2e3ebdSchin else
783da2e3ebdSchin c = (int32_t)((w[3] << 24) | (w[2] << 16) | (w[1] << 8) | w[0]);
784da2e3ebdSchin }
785da2e3ebdSchin fp->decode.count += c - FF_OFF;
786da2e3ebdSchin for (p = fp->decode.path + fp->decode.count; (c = sfgetc(fp->fp)) > FF_ESC;)
787da2e3ebdSchin if (c & (1<<(CHAR_BIT-1)))
788da2e3ebdSchin {
789da2e3ebdSchin *p++ = fp->decode.bigram1[c & ((1<<(CHAR_BIT-1))-1)];
790da2e3ebdSchin *p++ = fp->decode.bigram2[c & ((1<<(CHAR_BIT-1))-1)];
791da2e3ebdSchin }
792da2e3ebdSchin else
793da2e3ebdSchin *p++ = c;
794da2e3ebdSchin *p-- = 0;
795da2e3ebdSchin t = 0;
796da2e3ebdSchin break;
797da2e3ebdSchin }
798da2e3ebdSchin b = fp->decode.path;
799da2e3ebdSchin if (fp->decode.found)
800da2e3ebdSchin fp->decode.found = 0;
801da2e3ebdSchin else
802da2e3ebdSchin b += fp->decode.count;
803da2e3ebdSchin if (fp->dirs)
804da2e3ebdSchin for (;;)
805da2e3ebdSchin {
806da2e3ebdSchin if (!*fp->dirs)
807da2e3ebdSchin return 0;
808da2e3ebdSchin
809da2e3ebdSchin /*
810da2e3ebdSchin * use the ordering and lengths to prune
811da2e3ebdSchin * comparison function calls
812da2e3ebdSchin * (*fp->dirs)[*fp->lens]=='/' if its
813da2e3ebdSchin * already been matched
814da2e3ebdSchin */
815da2e3ebdSchin
816da2e3ebdSchin if ((n = p - fp->decode.path + 1) > (m = *fp->lens))
817da2e3ebdSchin {
818da2e3ebdSchin if (!(*fp->dirs)[m])
819da2e3ebdSchin goto next;
820da2e3ebdSchin if (!strncasecmp(*fp->dirs, fp->decode.path, m))
821da2e3ebdSchin break;
822da2e3ebdSchin }
823da2e3ebdSchin else if (n == m)
824da2e3ebdSchin {
825da2e3ebdSchin if (!(*fp->dirs)[m])
826da2e3ebdSchin {
827da2e3ebdSchin if (!(n = strcasecmp(*fp->dirs, fp->decode.path)) && (ignorecase || !strcmp(*fp->dirs, fp->decode.path)))
828da2e3ebdSchin {
829da2e3ebdSchin if (m > 0)
830da2e3ebdSchin {
831da2e3ebdSchin (*fp->dirs)[m] = '/';
832da2e3ebdSchin if ((*fp->dirs)[m - 1] != '/')
833da2e3ebdSchin (*fp->dirs)[++(*fp->lens)] = '/';
834da2e3ebdSchin }
835da2e3ebdSchin break;
836da2e3ebdSchin }
837da2e3ebdSchin if (n >= 0)
838da2e3ebdSchin goto next;
839da2e3ebdSchin }
840da2e3ebdSchin }
841da2e3ebdSchin else if (!(*fp->dirs)[m])
842da2e3ebdSchin goto next;
843da2e3ebdSchin fp->dirs++;
844da2e3ebdSchin fp->lens++;
845da2e3ebdSchin }
846da2e3ebdSchin if (fp->verify && (*p == '/' || t == 1))
847da2e3ebdSchin {
848da2e3ebdSchin if ((n = p - fp->decode.path))
849da2e3ebdSchin *p = 0;
850da2e3ebdSchin else
851da2e3ebdSchin n = 1;
852da2e3ebdSchin if (fp->verifyf)
853da2e3ebdSchin n = (*fp->verifyf)(fp, fp->decode.path, n, fp->disc);
854da2e3ebdSchin else if (stat(fp->decode.path, &st))
855da2e3ebdSchin n = -1;
856da2e3ebdSchin else if ((unsigned long)st.st_mtime > fp->stamp)
857da2e3ebdSchin n = 1;
858da2e3ebdSchin else
859da2e3ebdSchin n = 0;
860da2e3ebdSchin *p = '/';
861da2e3ebdSchin
862da2e3ebdSchin /*
863da2e3ebdSchin * n<0 skip this subtree
864da2e3ebdSchin * n==0 keep as is
865da2e3ebdSchin * n>0 read this dir now
866da2e3ebdSchin */
867da2e3ebdSchin
868da2e3ebdSchin /* NOT IMPLEMENTED YET */
869da2e3ebdSchin }
870da2e3ebdSchin if (FF_OK_TYPE(fp, t))
871da2e3ebdSchin {
872da2e3ebdSchin if (fp->decode.end)
873da2e3ebdSchin {
874da2e3ebdSchin if (*(s = p) == '/')
875da2e3ebdSchin s--;
876da2e3ebdSchin if (*fp->decode.pattern == '/' && b > fp->decode.path)
877da2e3ebdSchin b--;
878da2e3ebdSchin for (; s >= b; s--)
879da2e3ebdSchin if (*s == *fp->decode.end || ignorecase && tolower(*s) == *fp->decode.end)
880da2e3ebdSchin {
881da2e3ebdSchin if (ignorecase)
882da2e3ebdSchin for (e = fp->decode.end - 1, q = s - 1; *e && (*q == *e || tolower(*q) == *e); e--, q--);
883da2e3ebdSchin else
884da2e3ebdSchin for (e = fp->decode.end - 1, q = s - 1; *e && *q == *e; e--, q--);
885da2e3ebdSchin if (!*e)
886da2e3ebdSchin {
887da2e3ebdSchin fp->decode.found = 1;
888da2e3ebdSchin if (!fp->decode.match || strgrpmatch(fp->decode.path, fp->decode.pattern, NiL, 0, STR_MAXIMAL|STR_LEFT|STR_RIGHT|ignorecase))
889da2e3ebdSchin {
890da2e3ebdSchin fp->decode.peek = c;
891da2e3ebdSchin if (*p == '/')
892da2e3ebdSchin *(fp->decode.restore = p) = 0;
893da2e3ebdSchin if (!fp->secure || !access(fp->decode.path, F_OK))
894da2e3ebdSchin return fp->decode.path;
895da2e3ebdSchin }
896da2e3ebdSchin break;
897da2e3ebdSchin }
898da2e3ebdSchin }
899da2e3ebdSchin }
900da2e3ebdSchin else if (!fp->decode.match || !(n = regexec(&fp->decode.re, fp->decode.path, 0, NiL, 0)))
901da2e3ebdSchin {
902da2e3ebdSchin fp->decode.peek = c;
903da2e3ebdSchin if (*p == '/' && p > fp->decode.path)
904da2e3ebdSchin *(fp->decode.restore = p) = 0;
905da2e3ebdSchin if (!fp->secure || !access(fp->decode.path, F_OK))
906da2e3ebdSchin return fp->decode.path;
907da2e3ebdSchin }
908da2e3ebdSchin else if (n != REG_NOMATCH)
909da2e3ebdSchin {
910da2e3ebdSchin if (fp->disc->errorf)
911da2e3ebdSchin {
912da2e3ebdSchin regerror(n, &fp->decode.re, fp->decode.temp, sizeof(fp->decode.temp));
913da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, 2, "%s: %s", fp->decode.pattern, fp->decode.temp);
914da2e3ebdSchin }
915da2e3ebdSchin return 0;
916da2e3ebdSchin }
917da2e3ebdSchin }
918da2e3ebdSchin }
919da2e3ebdSchin }
920da2e3ebdSchin
921da2e3ebdSchin /*
922da2e3ebdSchin * add path to the code table
923da2e3ebdSchin * paths are assumed to be in sort order
924da2e3ebdSchin */
925da2e3ebdSchin
926da2e3ebdSchin int
findwrite(register Find_t * fp,const char * path,size_t len,const char * type)927da2e3ebdSchin findwrite(register Find_t* fp, const char* path, size_t len, const char* type)
928da2e3ebdSchin {
929da2e3ebdSchin register unsigned char* s;
930da2e3ebdSchin register unsigned char* e;
931da2e3ebdSchin register unsigned char* p;
932da2e3ebdSchin register int n;
933da2e3ebdSchin register int d;
934da2e3ebdSchin register Type_t* x;
935da2e3ebdSchin register unsigned long u;
936da2e3ebdSchin
937da2e3ebdSchin if (!fp->generate)
938da2e3ebdSchin return -1;
939da2e3ebdSchin if (type && fp->method == FF_dir)
940da2e3ebdSchin {
941da2e3ebdSchin len = sfsprintf(fp->encode.mark, sizeof(fp->encode.mark), "%-.*s/", len, path);
942da2e3ebdSchin path = fp->encode.mark;
943da2e3ebdSchin }
944da2e3ebdSchin s = (unsigned char*)path;
945da2e3ebdSchin if (len <= 0)
946da2e3ebdSchin len = strlen(path);
947da2e3ebdSchin if (len < sizeof(fp->encode.path))
948da2e3ebdSchin e = s + len++;
949da2e3ebdSchin else
950da2e3ebdSchin {
951da2e3ebdSchin len = sizeof(fp->encode.path) - 1;
952da2e3ebdSchin e = s + len;
953da2e3ebdSchin }
954da2e3ebdSchin p = (unsigned char*)fp->encode.path;
955da2e3ebdSchin while (s < e)
956da2e3ebdSchin {
957da2e3ebdSchin if (*s != *p++)
958da2e3ebdSchin break;
959da2e3ebdSchin s++;
960da2e3ebdSchin }
961da2e3ebdSchin n = s - (unsigned char*)path;
962da2e3ebdSchin switch (fp->method)
963da2e3ebdSchin {
964da2e3ebdSchin case FF_gnu:
965da2e3ebdSchin d = n - fp->encode.prefix;
966da2e3ebdSchin if (d >= -127 && d <= 127)
967da2e3ebdSchin sfputc(fp->fp, d & 0xff);
968da2e3ebdSchin else
969da2e3ebdSchin {
970da2e3ebdSchin sfputc(fp->fp, 0x80);
971da2e3ebdSchin sfputc(fp->fp, (d >> 8) & 0xff);
972da2e3ebdSchin sfputc(fp->fp, d & 0xff);
973da2e3ebdSchin }
974da2e3ebdSchin fp->encode.prefix = n;
975da2e3ebdSchin sfputr(fp->fp, (char*)s, 0);
976da2e3ebdSchin break;
977da2e3ebdSchin case FF_old:
978da2e3ebdSchin sfprintf(fp->fp, "%ld", n - fp->encode.prefix + FF_OFF);
979da2e3ebdSchin fp->encode.prefix = n;
980da2e3ebdSchin sfputc(fp->fp, ' ');
981da2e3ebdSchin p = s;
982da2e3ebdSchin while (s < e)
983da2e3ebdSchin {
984da2e3ebdSchin n = *s++;
985da2e3ebdSchin if (s >= e)
986da2e3ebdSchin break;
987da2e3ebdSchin fp->encode.code[n][*s++]++;
988da2e3ebdSchin }
989da2e3ebdSchin while (p < e)
990da2e3ebdSchin {
991da2e3ebdSchin if ((n = *p++) < FF_MIN || n >= FF_MAX)
992da2e3ebdSchin n = '?';
993da2e3ebdSchin sfputc(fp->fp, n);
994da2e3ebdSchin }
995da2e3ebdSchin sfputc(fp->fp, 0);
996da2e3ebdSchin break;
997da2e3ebdSchin case FF_typ:
998da2e3ebdSchin if (type)
999da2e3ebdSchin {
1000da2e3ebdSchin type = (const char*)typefix((char*)fp->encode.bigram, sizeof(fp->encode.bigram), type);
1001da2e3ebdSchin if (x = (Type_t*)dtmatch(fp->encode.namedict, type))
1002da2e3ebdSchin u = x->index;
1003da2e3ebdSchin else if (!(x = newof(0, Type_t, 1, strlen(type) + 1)))
1004da2e3ebdSchin u = 0;
1005da2e3ebdSchin else
1006da2e3ebdSchin {
1007da2e3ebdSchin u = x->index = ++fp->types;
1008da2e3ebdSchin strcpy(x->name, type);
1009da2e3ebdSchin dtinsert(fp->encode.namedict, x);
1010da2e3ebdSchin dtinsert(fp->encode.indexdict, x);
1011da2e3ebdSchin }
1012da2e3ebdSchin }
1013da2e3ebdSchin else
1014da2e3ebdSchin u = 0;
1015da2e3ebdSchin sfputu(fp->fp, u);
1016da2e3ebdSchin /*FALLTHROUGH...*/
1017da2e3ebdSchin case FF_dir:
1018da2e3ebdSchin d = n - fp->encode.prefix;
1019da2e3ebdSchin sfputl(fp->fp, d);
1020da2e3ebdSchin fp->encode.prefix = n;
1021da2e3ebdSchin sfputr(fp->fp, (char*)s, 0);
1022da2e3ebdSchin break;
1023da2e3ebdSchin }
1024da2e3ebdSchin memcpy(fp->encode.path, path, len);
1025da2e3ebdSchin return 0;
1026da2e3ebdSchin }
1027da2e3ebdSchin
1028da2e3ebdSchin /*
1029da2e3ebdSchin * findsync() helper
1030da2e3ebdSchin */
1031da2e3ebdSchin
1032da2e3ebdSchin static int
finddone(register Find_t * fp)1033da2e3ebdSchin finddone(register Find_t* fp)
1034da2e3ebdSchin {
1035da2e3ebdSchin int r;
1036da2e3ebdSchin
1037da2e3ebdSchin if (sfsync(fp->fp))
1038da2e3ebdSchin {
1039da2e3ebdSchin if (fp->disc->errorf)
1040da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, 2, "%s: write error [sfsync]", fp->encode.file);
1041da2e3ebdSchin return -1;
1042da2e3ebdSchin }
1043da2e3ebdSchin if (sferror(fp->fp))
1044da2e3ebdSchin {
1045da2e3ebdSchin if (fp->disc->errorf)
1046da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, 2, "%s: write error [sferror]", fp->encode.file);
1047da2e3ebdSchin return -1;
1048da2e3ebdSchin }
1049da2e3ebdSchin r = sfclose(fp->fp);
1050da2e3ebdSchin fp->fp = 0;
1051da2e3ebdSchin if (r)
1052da2e3ebdSchin {
1053da2e3ebdSchin if (fp->disc->errorf)
1054da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, 2, "%s: write error [sfclose]", fp->encode.file);
1055da2e3ebdSchin return -1;
1056da2e3ebdSchin }
1057da2e3ebdSchin return 0;
1058da2e3ebdSchin }
1059da2e3ebdSchin
1060da2e3ebdSchin /*
1061da2e3ebdSchin * finish the code table
1062da2e3ebdSchin */
1063da2e3ebdSchin
1064da2e3ebdSchin static int
findsync(register Find_t * fp)1065da2e3ebdSchin findsync(register Find_t* fp)
1066da2e3ebdSchin {
1067da2e3ebdSchin register char* s;
1068da2e3ebdSchin register int n;
1069da2e3ebdSchin register int m;
1070da2e3ebdSchin register int d;
1071da2e3ebdSchin register Type_t* x;
1072da2e3ebdSchin char* t;
1073da2e3ebdSchin int b;
1074da2e3ebdSchin long z;
1075da2e3ebdSchin Sfio_t* sp;
1076da2e3ebdSchin
1077da2e3ebdSchin switch (fp->method)
1078da2e3ebdSchin {
1079da2e3ebdSchin case FF_dir:
1080da2e3ebdSchin case FF_gnu:
1081da2e3ebdSchin /*
1082da2e3ebdSchin * replace the real file with the temp file
1083da2e3ebdSchin */
1084da2e3ebdSchin
1085da2e3ebdSchin if (finddone(fp))
1086da2e3ebdSchin goto bad;
1087da2e3ebdSchin remove(fp->encode.file);
1088da2e3ebdSchin if (rename(fp->encode.temp, fp->encode.file))
1089da2e3ebdSchin {
1090da2e3ebdSchin if (fp->disc->errorf)
1091da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "%s: cannot rename from tmp file %s", fp->encode.file, fp->encode.temp);
1092da2e3ebdSchin remove(fp->encode.temp);
1093da2e3ebdSchin return -1;
1094da2e3ebdSchin }
1095da2e3ebdSchin break;
1096da2e3ebdSchin case FF_old:
1097da2e3ebdSchin /*
1098da2e3ebdSchin * determine the top FF_MAX bigrams
1099da2e3ebdSchin */
1100da2e3ebdSchin
1101da2e3ebdSchin for (n = 0; n < FF_MAX; n++)
1102da2e3ebdSchin for (m = 0; m < FF_MAX; m++)
1103da2e3ebdSchin fp->encode.hits[fp->encode.code[n][m]]++;
1104da2e3ebdSchin fp->encode.hits[0] = 0;
1105da2e3ebdSchin m = 1;
1106da2e3ebdSchin for (n = USHRT_MAX; n >= 0; n--)
1107da2e3ebdSchin if (d = fp->encode.hits[n])
1108da2e3ebdSchin {
1109da2e3ebdSchin fp->encode.hits[n] = m;
1110da2e3ebdSchin if ((m += d) > FF_MAX)
1111da2e3ebdSchin break;
1112da2e3ebdSchin }
1113da2e3ebdSchin while (--n >= 0)
1114da2e3ebdSchin fp->encode.hits[n] = 0;
1115da2e3ebdSchin for (n = FF_MAX - 1; n >= 0; n--)
1116da2e3ebdSchin for (m = FF_MAX - 1; m >= 0; m--)
1117da2e3ebdSchin if (fp->encode.hits[fp->encode.code[n][m]])
1118da2e3ebdSchin {
1119da2e3ebdSchin d = fp->encode.code[n][m];
1120da2e3ebdSchin b = fp->encode.hits[d] - 1;
1121da2e3ebdSchin fp->encode.code[n][m] = b + FF_MAX;
1122da2e3ebdSchin if (fp->encode.hits[d]++ >= FF_MAX)
1123da2e3ebdSchin fp->encode.hits[d] = 0;
1124da2e3ebdSchin fp->encode.bigram[b *= 2] = n;
1125da2e3ebdSchin fp->encode.bigram[b + 1] = m;
1126da2e3ebdSchin }
1127da2e3ebdSchin else
1128da2e3ebdSchin fp->encode.code[n][m] = 0;
1129da2e3ebdSchin
1130da2e3ebdSchin /*
1131da2e3ebdSchin * commit the real file
1132da2e3ebdSchin */
1133da2e3ebdSchin
1134da2e3ebdSchin if (sfseek(fp->fp, (Sfoff_t)0, SEEK_SET))
1135da2e3ebdSchin {
1136da2e3ebdSchin if (fp->disc->errorf)
1137da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "cannot rewind tmp file");
1138da2e3ebdSchin return -1;
1139da2e3ebdSchin }
1140da2e3ebdSchin if (!(sp = sfopen(NiL, fp->encode.file, "w")))
1141da2e3ebdSchin goto badcreate;
1142da2e3ebdSchin
1143da2e3ebdSchin /*
1144da2e3ebdSchin * dump the bigrams
1145da2e3ebdSchin */
1146da2e3ebdSchin
1147da2e3ebdSchin sfwrite(sp, fp->encode.bigram, sizeof(fp->encode.bigram));
1148da2e3ebdSchin
1149da2e3ebdSchin /*
1150da2e3ebdSchin * encode the massaged paths
1151da2e3ebdSchin */
1152da2e3ebdSchin
1153da2e3ebdSchin while (s = sfgetr(fp->fp, 0, 0))
1154da2e3ebdSchin {
1155da2e3ebdSchin z = strtol(s, &t, 0);
1156da2e3ebdSchin s = t;
1157da2e3ebdSchin if (z < 0 || z > 2 * FF_OFF)
1158da2e3ebdSchin {
1159da2e3ebdSchin sfputc(sp, FF_ESC);
1160da2e3ebdSchin sfputc(sp, (z >> 24));
1161da2e3ebdSchin sfputc(sp, (z >> 16));
1162da2e3ebdSchin sfputc(sp, (z >> 8));
1163da2e3ebdSchin sfputc(sp, z);
1164da2e3ebdSchin }
1165da2e3ebdSchin else
1166da2e3ebdSchin sfputc(sp, z);
1167da2e3ebdSchin while (n = *s++)
1168da2e3ebdSchin {
1169da2e3ebdSchin if (!(m = *s++))
1170da2e3ebdSchin {
1171da2e3ebdSchin sfputc(sp, n);
1172da2e3ebdSchin break;
1173da2e3ebdSchin }
1174da2e3ebdSchin if (d = fp->encode.code[n][m])
1175da2e3ebdSchin sfputc(sp, d);
1176da2e3ebdSchin else
1177da2e3ebdSchin {
1178da2e3ebdSchin sfputc(sp, n);
1179da2e3ebdSchin sfputc(sp, m);
1180da2e3ebdSchin }
1181da2e3ebdSchin }
1182da2e3ebdSchin }
1183da2e3ebdSchin sfclose(fp->fp);
1184da2e3ebdSchin fp->fp = sp;
1185da2e3ebdSchin if (finddone(fp))
1186da2e3ebdSchin goto bad;
1187da2e3ebdSchin break;
1188da2e3ebdSchin case FF_typ:
1189da2e3ebdSchin if (finddone(fp))
1190da2e3ebdSchin goto bad;
1191da2e3ebdSchin if (!(fp->fp = sfopen(NiL, fp->encode.temp, "r")))
1192da2e3ebdSchin {
1193da2e3ebdSchin if (fp->disc->errorf)
1194da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, ERROR_SYSTEM|2, "%s: cannot read tmp file", fp->encode.temp);
1195da2e3ebdSchin remove(fp->encode.temp);
1196da2e3ebdSchin return -1;
1197da2e3ebdSchin }
1198da2e3ebdSchin
1199da2e3ebdSchin /*
1200da2e3ebdSchin * commit the output file
1201da2e3ebdSchin */
1202da2e3ebdSchin
1203da2e3ebdSchin if (!(sp = sfopen(NiL, fp->encode.file, "w")))
1204da2e3ebdSchin goto badcreate;
1205da2e3ebdSchin
1206da2e3ebdSchin /*
1207da2e3ebdSchin * write the header magic
1208da2e3ebdSchin */
1209da2e3ebdSchin
1210da2e3ebdSchin sfputc(sp, 0);
1211da2e3ebdSchin sfputr(sp, FF_typ_magic, 0);
1212da2e3ebdSchin
1213da2e3ebdSchin /*
1214da2e3ebdSchin * write the type table in index order starting with 1
1215da2e3ebdSchin */
1216da2e3ebdSchin
1217da2e3ebdSchin for (x = (Type_t*)dtfirst(fp->encode.indexdict); x; x = (Type_t*)dtnext(fp->encode.indexdict, x))
1218da2e3ebdSchin sfputr(sp, x->name, 0);
1219da2e3ebdSchin sfputc(sp, 0);
1220da2e3ebdSchin
1221da2e3ebdSchin /*
1222da2e3ebdSchin * append the front compressed strings
1223da2e3ebdSchin */
1224da2e3ebdSchin
1225da2e3ebdSchin if (sfmove(fp->fp, sp, SF_UNBOUND, -1) < 0 || !sfeof(fp->fp))
1226da2e3ebdSchin {
1227da2e3ebdSchin sfclose(sp);
1228da2e3ebdSchin if (fp->disc->errorf)
1229da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, 2, "%s: cannot append codes", fp->encode.file);
1230da2e3ebdSchin goto bad;
1231da2e3ebdSchin }
1232da2e3ebdSchin sfclose(fp->fp);
1233da2e3ebdSchin fp->fp = sp;
1234da2e3ebdSchin if (finddone(fp))
1235da2e3ebdSchin goto bad;
1236da2e3ebdSchin remove(fp->encode.temp);
1237da2e3ebdSchin break;
1238da2e3ebdSchin }
1239da2e3ebdSchin return 0;
1240da2e3ebdSchin badcreate:
1241da2e3ebdSchin if (fp->disc->errorf)
1242da2e3ebdSchin (*fp->disc->errorf)(fp, fp->disc, 2, "%s: cannot write codes", fp->encode.file);
1243da2e3ebdSchin bad:
1244da2e3ebdSchin if (fp->fp)
1245da2e3ebdSchin {
1246da2e3ebdSchin sfclose(fp->fp);
1247da2e3ebdSchin fp->fp = 0;
1248da2e3ebdSchin }
1249da2e3ebdSchin remove(fp->encode.temp);
1250da2e3ebdSchin return -1;
1251da2e3ebdSchin }
1252da2e3ebdSchin
1253da2e3ebdSchin /*
1254da2e3ebdSchin * close an open fastfind stream
1255da2e3ebdSchin */
1256da2e3ebdSchin
1257da2e3ebdSchin int
findclose(register Find_t * fp)1258da2e3ebdSchin findclose(register Find_t* fp)
1259da2e3ebdSchin {
1260da2e3ebdSchin int n = 0;
1261da2e3ebdSchin
1262da2e3ebdSchin if (!fp)
1263da2e3ebdSchin return -1;
1264da2e3ebdSchin if (fp->generate)
1265da2e3ebdSchin {
1266da2e3ebdSchin n = findsync(fp);
1267da2e3ebdSchin if (fp->encode.indexdict)
1268da2e3ebdSchin dtclose(fp->encode.indexdict);
1269da2e3ebdSchin if (fp->encode.namedict)
1270da2e3ebdSchin dtclose(fp->encode.namedict);
1271da2e3ebdSchin }
1272da2e3ebdSchin else
1273da2e3ebdSchin {
1274da2e3ebdSchin if (fp->decode.match)
1275da2e3ebdSchin regfree(&fp->decode.re);
1276da2e3ebdSchin n = 0;
1277da2e3ebdSchin }
1278da2e3ebdSchin if (fp->fp)
1279da2e3ebdSchin sfclose(fp->fp);
1280da2e3ebdSchin vmclose(fp->vm);
1281da2e3ebdSchin return n;
1282da2e3ebdSchin }
1283