1*9f988b79SJean-Baptiste Boric /* $NetBSD: walk.c,v 1.28 2013/02/03 06:16:53 christos Exp $ */
2*9f988b79SJean-Baptiste Boric
3*9f988b79SJean-Baptiste Boric /*
4*9f988b79SJean-Baptiste Boric * Copyright (c) 2001 Wasabi Systems, Inc.
5*9f988b79SJean-Baptiste Boric * All rights reserved.
6*9f988b79SJean-Baptiste Boric *
7*9f988b79SJean-Baptiste Boric * Written by Luke Mewburn for Wasabi Systems, Inc.
8*9f988b79SJean-Baptiste Boric *
9*9f988b79SJean-Baptiste Boric * Redistribution and use in source and binary forms, with or without
10*9f988b79SJean-Baptiste Boric * modification, are permitted provided that the following conditions
11*9f988b79SJean-Baptiste Boric * are met:
12*9f988b79SJean-Baptiste Boric * 1. Redistributions of source code must retain the above copyright
13*9f988b79SJean-Baptiste Boric * notice, this list of conditions and the following disclaimer.
14*9f988b79SJean-Baptiste Boric * 2. Redistributions in binary form must reproduce the above copyright
15*9f988b79SJean-Baptiste Boric * notice, this list of conditions and the following disclaimer in the
16*9f988b79SJean-Baptiste Boric * documentation and/or other materials provided with the distribution.
17*9f988b79SJean-Baptiste Boric * 3. All advertising materials mentioning features or use of this software
18*9f988b79SJean-Baptiste Boric * must display the following acknowledgement:
19*9f988b79SJean-Baptiste Boric * This product includes software developed for the NetBSD Project by
20*9f988b79SJean-Baptiste Boric * Wasabi Systems, Inc.
21*9f988b79SJean-Baptiste Boric * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22*9f988b79SJean-Baptiste Boric * or promote products derived from this software without specific prior
23*9f988b79SJean-Baptiste Boric * written permission.
24*9f988b79SJean-Baptiste Boric *
25*9f988b79SJean-Baptiste Boric * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26*9f988b79SJean-Baptiste Boric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27*9f988b79SJean-Baptiste Boric * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28*9f988b79SJean-Baptiste Boric * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29*9f988b79SJean-Baptiste Boric * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30*9f988b79SJean-Baptiste Boric * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31*9f988b79SJean-Baptiste Boric * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32*9f988b79SJean-Baptiste Boric * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33*9f988b79SJean-Baptiste Boric * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34*9f988b79SJean-Baptiste Boric * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35*9f988b79SJean-Baptiste Boric * POSSIBILITY OF SUCH DAMAGE.
36*9f988b79SJean-Baptiste Boric */
37*9f988b79SJean-Baptiste Boric
38*9f988b79SJean-Baptiste Boric #if HAVE_NBTOOL_CONFIG_H
39*9f988b79SJean-Baptiste Boric #include "nbtool_config.h"
40*9f988b79SJean-Baptiste Boric #endif
41*9f988b79SJean-Baptiste Boric
42*9f988b79SJean-Baptiste Boric #include <sys/cdefs.h>
43*9f988b79SJean-Baptiste Boric #if defined(__RCSID) && !defined(__lint)
44*9f988b79SJean-Baptiste Boric __RCSID("$NetBSD: walk.c,v 1.28 2013/02/03 06:16:53 christos Exp $");
45*9f988b79SJean-Baptiste Boric #endif /* !__lint */
46*9f988b79SJean-Baptiste Boric
47*9f988b79SJean-Baptiste Boric #include <sys/param.h>
48*9f988b79SJean-Baptiste Boric #include <sys/stat.h>
49*9f988b79SJean-Baptiste Boric
50*9f988b79SJean-Baptiste Boric #include <assert.h>
51*9f988b79SJean-Baptiste Boric #include <errno.h>
52*9f988b79SJean-Baptiste Boric #include <fcntl.h>
53*9f988b79SJean-Baptiste Boric #include <stdio.h>
54*9f988b79SJean-Baptiste Boric #include <dirent.h>
55*9f988b79SJean-Baptiste Boric #include <stdlib.h>
56*9f988b79SJean-Baptiste Boric #include <string.h>
57*9f988b79SJean-Baptiste Boric #include <unistd.h>
58*9f988b79SJean-Baptiste Boric #include <util.h>
59*9f988b79SJean-Baptiste Boric
60*9f988b79SJean-Baptiste Boric #include "makefs.h"
61*9f988b79SJean-Baptiste Boric #include "mtree.h"
62*9f988b79SJean-Baptiste Boric
63*9f988b79SJean-Baptiste Boric static void apply_specdir(const char *, NODE *, fsnode *, int);
64*9f988b79SJean-Baptiste Boric static void apply_specentry(const char *, NODE *, fsnode *);
65*9f988b79SJean-Baptiste Boric static fsnode *create_fsnode(const char *, const char *, const char *,
66*9f988b79SJean-Baptiste Boric struct stat *);
67*9f988b79SJean-Baptiste Boric static fsinode *link_check(fsinode *);
68*9f988b79SJean-Baptiste Boric
69*9f988b79SJean-Baptiste Boric
70*9f988b79SJean-Baptiste Boric /*
71*9f988b79SJean-Baptiste Boric * walk_dir --
72*9f988b79SJean-Baptiste Boric * build a tree of fsnodes from `root' and `dir', with a parent
73*9f988b79SJean-Baptiste Boric * fsnode of `parent' (which may be NULL for the root of the tree).
74*9f988b79SJean-Baptiste Boric * append the tree to a fsnode of `join' if it is not NULL.
75*9f988b79SJean-Baptiste Boric * each "level" is a directory, with the "." entry guaranteed to be
76*9f988b79SJean-Baptiste Boric * at the start of the list, and without ".." entries.
77*9f988b79SJean-Baptiste Boric */
78*9f988b79SJean-Baptiste Boric fsnode *
walk_dir(const char * root,const char * dir,fsnode * parent,fsnode * join,int replace)79*9f988b79SJean-Baptiste Boric walk_dir(const char *root, const char *dir, fsnode *parent, fsnode *join,
80*9f988b79SJean-Baptiste Boric int replace)
81*9f988b79SJean-Baptiste Boric {
82*9f988b79SJean-Baptiste Boric fsnode *first, *cur, *prev, *last;
83*9f988b79SJean-Baptiste Boric DIR *dirp;
84*9f988b79SJean-Baptiste Boric struct dirent *dent;
85*9f988b79SJean-Baptiste Boric char path[MAXPATHLEN + 1];
86*9f988b79SJean-Baptiste Boric struct stat stbuf;
87*9f988b79SJean-Baptiste Boric char *name, *rp;
88*9f988b79SJean-Baptiste Boric int dot, len;
89*9f988b79SJean-Baptiste Boric
90*9f988b79SJean-Baptiste Boric assert(root != NULL);
91*9f988b79SJean-Baptiste Boric assert(dir != NULL);
92*9f988b79SJean-Baptiste Boric
93*9f988b79SJean-Baptiste Boric len = snprintf(path, sizeof(path), "%s/%s", root, dir);
94*9f988b79SJean-Baptiste Boric if (len >= (int)sizeof(path))
95*9f988b79SJean-Baptiste Boric errx(1, "Pathname too long.");
96*9f988b79SJean-Baptiste Boric if (debug & DEBUG_WALK_DIR)
97*9f988b79SJean-Baptiste Boric printf("walk_dir: %s %p\n", path, parent);
98*9f988b79SJean-Baptiste Boric if ((dirp = opendir(path)) == NULL)
99*9f988b79SJean-Baptiste Boric err(1, "Can't opendir `%s'", path);
100*9f988b79SJean-Baptiste Boric rp = path + strlen(root) + 1;
101*9f988b79SJean-Baptiste Boric if (join != NULL) {
102*9f988b79SJean-Baptiste Boric first = cur = join;
103*9f988b79SJean-Baptiste Boric while (cur->next != NULL)
104*9f988b79SJean-Baptiste Boric cur = cur->next;
105*9f988b79SJean-Baptiste Boric prev = last = cur;
106*9f988b79SJean-Baptiste Boric } else
107*9f988b79SJean-Baptiste Boric last = first = prev = NULL;
108*9f988b79SJean-Baptiste Boric while ((dent = readdir(dirp)) != NULL) {
109*9f988b79SJean-Baptiste Boric name = dent->d_name;
110*9f988b79SJean-Baptiste Boric dot = 0;
111*9f988b79SJean-Baptiste Boric if (name[0] == '.')
112*9f988b79SJean-Baptiste Boric switch (name[1]) {
113*9f988b79SJean-Baptiste Boric case '\0': /* "." */
114*9f988b79SJean-Baptiste Boric if (join != NULL)
115*9f988b79SJean-Baptiste Boric continue;
116*9f988b79SJean-Baptiste Boric dot = 1;
117*9f988b79SJean-Baptiste Boric break;
118*9f988b79SJean-Baptiste Boric case '.': /* ".." */
119*9f988b79SJean-Baptiste Boric if (name[2] == '\0')
120*9f988b79SJean-Baptiste Boric continue;
121*9f988b79SJean-Baptiste Boric /* FALLTHROUGH */
122*9f988b79SJean-Baptiste Boric default:
123*9f988b79SJean-Baptiste Boric dot = 0;
124*9f988b79SJean-Baptiste Boric }
125*9f988b79SJean-Baptiste Boric if (debug & DEBUG_WALK_DIR_NODE)
126*9f988b79SJean-Baptiste Boric printf("scanning %s/%s/%s\n", root, dir, name);
127*9f988b79SJean-Baptiste Boric if (snprintf(path + len, sizeof(path) - len, "/%s", name) >=
128*9f988b79SJean-Baptiste Boric (int)sizeof(path) - len)
129*9f988b79SJean-Baptiste Boric errx(1, "Pathname too long.");
130*9f988b79SJean-Baptiste Boric if (lstat(path, &stbuf) == -1)
131*9f988b79SJean-Baptiste Boric err(1, "Can't lstat `%s'", path);
132*9f988b79SJean-Baptiste Boric #ifdef S_ISSOCK
133*9f988b79SJean-Baptiste Boric if (S_ISSOCK(stbuf.st_mode & S_IFMT)) {
134*9f988b79SJean-Baptiste Boric if (debug & DEBUG_WALK_DIR_NODE)
135*9f988b79SJean-Baptiste Boric printf(" skipping socket %s\n", path);
136*9f988b79SJean-Baptiste Boric continue;
137*9f988b79SJean-Baptiste Boric }
138*9f988b79SJean-Baptiste Boric #endif
139*9f988b79SJean-Baptiste Boric
140*9f988b79SJean-Baptiste Boric if (join != NULL) {
141*9f988b79SJean-Baptiste Boric cur = join->next;
142*9f988b79SJean-Baptiste Boric for (;;) {
143*9f988b79SJean-Baptiste Boric if (cur == NULL || strcmp(cur->name, name) == 0)
144*9f988b79SJean-Baptiste Boric break;
145*9f988b79SJean-Baptiste Boric if (cur == last) {
146*9f988b79SJean-Baptiste Boric cur = NULL;
147*9f988b79SJean-Baptiste Boric break;
148*9f988b79SJean-Baptiste Boric }
149*9f988b79SJean-Baptiste Boric cur = cur->next;
150*9f988b79SJean-Baptiste Boric }
151*9f988b79SJean-Baptiste Boric if (cur != NULL) {
152*9f988b79SJean-Baptiste Boric if (S_ISDIR(cur->type) &&
153*9f988b79SJean-Baptiste Boric S_ISDIR(stbuf.st_mode)) {
154*9f988b79SJean-Baptiste Boric if (debug & DEBUG_WALK_DIR_NODE)
155*9f988b79SJean-Baptiste Boric printf("merging %s with %p\n",
156*9f988b79SJean-Baptiste Boric path, cur->child);
157*9f988b79SJean-Baptiste Boric cur->child = walk_dir(root, rp, cur,
158*9f988b79SJean-Baptiste Boric cur->child, replace);
159*9f988b79SJean-Baptiste Boric continue;
160*9f988b79SJean-Baptiste Boric }
161*9f988b79SJean-Baptiste Boric if (!replace)
162*9f988b79SJean-Baptiste Boric errx(1, "Can't merge %s `%s' with "
163*9f988b79SJean-Baptiste Boric "existing %s",
164*9f988b79SJean-Baptiste Boric inode_type(stbuf.st_mode), path,
165*9f988b79SJean-Baptiste Boric inode_type(cur->type));
166*9f988b79SJean-Baptiste Boric else {
167*9f988b79SJean-Baptiste Boric if (debug & DEBUG_WALK_DIR_NODE)
168*9f988b79SJean-Baptiste Boric printf("replacing %s %s\n",
169*9f988b79SJean-Baptiste Boric inode_type(stbuf.st_mode),
170*9f988b79SJean-Baptiste Boric path);
171*9f988b79SJean-Baptiste Boric if (cur == join->next)
172*9f988b79SJean-Baptiste Boric join->next = cur->next;
173*9f988b79SJean-Baptiste Boric else {
174*9f988b79SJean-Baptiste Boric fsnode *p;
175*9f988b79SJean-Baptiste Boric for (p = join->next;
176*9f988b79SJean-Baptiste Boric p->next != cur; p = p->next)
177*9f988b79SJean-Baptiste Boric continue;
178*9f988b79SJean-Baptiste Boric p->next = cur->next;
179*9f988b79SJean-Baptiste Boric }
180*9f988b79SJean-Baptiste Boric free(cur);
181*9f988b79SJean-Baptiste Boric }
182*9f988b79SJean-Baptiste Boric }
183*9f988b79SJean-Baptiste Boric }
184*9f988b79SJean-Baptiste Boric
185*9f988b79SJean-Baptiste Boric cur = create_fsnode(root, dir, name, &stbuf);
186*9f988b79SJean-Baptiste Boric cur->parent = parent;
187*9f988b79SJean-Baptiste Boric if (dot) {
188*9f988b79SJean-Baptiste Boric /* ensure "." is at the start of the list */
189*9f988b79SJean-Baptiste Boric cur->next = first;
190*9f988b79SJean-Baptiste Boric first = cur;
191*9f988b79SJean-Baptiste Boric if (! prev)
192*9f988b79SJean-Baptiste Boric prev = cur;
193*9f988b79SJean-Baptiste Boric cur->first = first;
194*9f988b79SJean-Baptiste Boric } else { /* not "." */
195*9f988b79SJean-Baptiste Boric if (prev)
196*9f988b79SJean-Baptiste Boric prev->next = cur;
197*9f988b79SJean-Baptiste Boric prev = cur;
198*9f988b79SJean-Baptiste Boric if (!first)
199*9f988b79SJean-Baptiste Boric first = cur;
200*9f988b79SJean-Baptiste Boric cur->first = first;
201*9f988b79SJean-Baptiste Boric if (S_ISDIR(cur->type)) {
202*9f988b79SJean-Baptiste Boric cur->child = walk_dir(root, rp, cur, NULL,
203*9f988b79SJean-Baptiste Boric replace);
204*9f988b79SJean-Baptiste Boric continue;
205*9f988b79SJean-Baptiste Boric }
206*9f988b79SJean-Baptiste Boric }
207*9f988b79SJean-Baptiste Boric if (stbuf.st_nlink > 1) {
208*9f988b79SJean-Baptiste Boric fsinode *curino;
209*9f988b79SJean-Baptiste Boric
210*9f988b79SJean-Baptiste Boric curino = link_check(cur->inode);
211*9f988b79SJean-Baptiste Boric if (curino != NULL) {
212*9f988b79SJean-Baptiste Boric free(cur->inode);
213*9f988b79SJean-Baptiste Boric cur->inode = curino;
214*9f988b79SJean-Baptiste Boric cur->inode->nlink++;
215*9f988b79SJean-Baptiste Boric if (debug & DEBUG_WALK_DIR_LINKCHECK)
216*9f988b79SJean-Baptiste Boric printf("link_check: found [%llu, %llu]\n",
217*9f988b79SJean-Baptiste Boric (unsigned long long)curino->st.st_dev,
218*9f988b79SJean-Baptiste Boric (unsigned long long)curino->st.st_ino);
219*9f988b79SJean-Baptiste Boric }
220*9f988b79SJean-Baptiste Boric }
221*9f988b79SJean-Baptiste Boric if (S_ISLNK(cur->type)) {
222*9f988b79SJean-Baptiste Boric char slink[PATH_MAX+1];
223*9f988b79SJean-Baptiste Boric int llen;
224*9f988b79SJean-Baptiste Boric
225*9f988b79SJean-Baptiste Boric llen = readlink(path, slink, sizeof(slink) - 1);
226*9f988b79SJean-Baptiste Boric if (llen == -1)
227*9f988b79SJean-Baptiste Boric err(1, "Readlink `%s'", path);
228*9f988b79SJean-Baptiste Boric slink[llen] = '\0';
229*9f988b79SJean-Baptiste Boric cur->symlink = estrdup(slink);
230*9f988b79SJean-Baptiste Boric }
231*9f988b79SJean-Baptiste Boric }
232*9f988b79SJean-Baptiste Boric assert(first != NULL);
233*9f988b79SJean-Baptiste Boric if (join == NULL)
234*9f988b79SJean-Baptiste Boric for (cur = first->next; cur != NULL; cur = cur->next)
235*9f988b79SJean-Baptiste Boric cur->first = first;
236*9f988b79SJean-Baptiste Boric if (closedir(dirp) == -1)
237*9f988b79SJean-Baptiste Boric err(1, "Can't closedir `%s/%s'", root, dir);
238*9f988b79SJean-Baptiste Boric return (first);
239*9f988b79SJean-Baptiste Boric }
240*9f988b79SJean-Baptiste Boric
241*9f988b79SJean-Baptiste Boric static fsnode *
create_fsnode(const char * root,const char * path,const char * name,struct stat * stbuf)242*9f988b79SJean-Baptiste Boric create_fsnode(const char *root, const char *path, const char *name,
243*9f988b79SJean-Baptiste Boric struct stat *stbuf)
244*9f988b79SJean-Baptiste Boric {
245*9f988b79SJean-Baptiste Boric fsnode *cur;
246*9f988b79SJean-Baptiste Boric
247*9f988b79SJean-Baptiste Boric cur = ecalloc(1, sizeof(*cur));
248*9f988b79SJean-Baptiste Boric cur->path = estrdup(path);
249*9f988b79SJean-Baptiste Boric cur->name = estrdup(name);
250*9f988b79SJean-Baptiste Boric cur->inode = ecalloc(1, sizeof(*cur->inode));
251*9f988b79SJean-Baptiste Boric cur->root = root;
252*9f988b79SJean-Baptiste Boric cur->type = stbuf->st_mode & S_IFMT;
253*9f988b79SJean-Baptiste Boric cur->inode->nlink = 1;
254*9f988b79SJean-Baptiste Boric cur->inode->st = *stbuf;
255*9f988b79SJean-Baptiste Boric return (cur);
256*9f988b79SJean-Baptiste Boric }
257*9f988b79SJean-Baptiste Boric
258*9f988b79SJean-Baptiste Boric /*
259*9f988b79SJean-Baptiste Boric * free_fsnodes --
260*9f988b79SJean-Baptiste Boric * Removes node from tree and frees it and all of
261*9f988b79SJean-Baptiste Boric * its decendents.
262*9f988b79SJean-Baptiste Boric */
263*9f988b79SJean-Baptiste Boric void
free_fsnodes(fsnode * node)264*9f988b79SJean-Baptiste Boric free_fsnodes(fsnode *node)
265*9f988b79SJean-Baptiste Boric {
266*9f988b79SJean-Baptiste Boric fsnode *cur, *next;
267*9f988b79SJean-Baptiste Boric
268*9f988b79SJean-Baptiste Boric assert(node != NULL);
269*9f988b79SJean-Baptiste Boric
270*9f988b79SJean-Baptiste Boric /* for ".", start with actual parent node */
271*9f988b79SJean-Baptiste Boric if (node->first == node) {
272*9f988b79SJean-Baptiste Boric assert(node->name[0] == '.' && node->name[1] == '\0');
273*9f988b79SJean-Baptiste Boric if (node->parent) {
274*9f988b79SJean-Baptiste Boric assert(node->parent->child == node);
275*9f988b79SJean-Baptiste Boric node = node->parent;
276*9f988b79SJean-Baptiste Boric }
277*9f988b79SJean-Baptiste Boric }
278*9f988b79SJean-Baptiste Boric
279*9f988b79SJean-Baptiste Boric /* Find ourselves in our sibling list and unlink */
280*9f988b79SJean-Baptiste Boric if (node->first != node) {
281*9f988b79SJean-Baptiste Boric for (cur = node->first; cur->next; cur = cur->next) {
282*9f988b79SJean-Baptiste Boric if (cur->next == node) {
283*9f988b79SJean-Baptiste Boric cur->next = node->next;
284*9f988b79SJean-Baptiste Boric node->next = NULL;
285*9f988b79SJean-Baptiste Boric break;
286*9f988b79SJean-Baptiste Boric }
287*9f988b79SJean-Baptiste Boric }
288*9f988b79SJean-Baptiste Boric }
289*9f988b79SJean-Baptiste Boric
290*9f988b79SJean-Baptiste Boric for (cur = node; cur != NULL; cur = next) {
291*9f988b79SJean-Baptiste Boric next = cur->next;
292*9f988b79SJean-Baptiste Boric if (cur->child) {
293*9f988b79SJean-Baptiste Boric cur->child->parent = NULL;
294*9f988b79SJean-Baptiste Boric free_fsnodes(cur->child);
295*9f988b79SJean-Baptiste Boric }
296*9f988b79SJean-Baptiste Boric if (cur->inode->nlink-- == 1)
297*9f988b79SJean-Baptiste Boric free(cur->inode);
298*9f988b79SJean-Baptiste Boric if (cur->symlink)
299*9f988b79SJean-Baptiste Boric free(cur->symlink);
300*9f988b79SJean-Baptiste Boric free(cur->path);
301*9f988b79SJean-Baptiste Boric free(cur->name);
302*9f988b79SJean-Baptiste Boric free(cur);
303*9f988b79SJean-Baptiste Boric }
304*9f988b79SJean-Baptiste Boric }
305*9f988b79SJean-Baptiste Boric
306*9f988b79SJean-Baptiste Boric /*
307*9f988b79SJean-Baptiste Boric * apply_specfile --
308*9f988b79SJean-Baptiste Boric * read in the mtree(8) specfile, and apply it to the tree
309*9f988b79SJean-Baptiste Boric * at dir,parent. parameters in parent on equivalent types
310*9f988b79SJean-Baptiste Boric * will be changed to those found in specfile, and missing
311*9f988b79SJean-Baptiste Boric * entries will be added.
312*9f988b79SJean-Baptiste Boric */
313*9f988b79SJean-Baptiste Boric void
apply_specfile(const char * specfile,const char * dir,fsnode * parent,int speconly)314*9f988b79SJean-Baptiste Boric apply_specfile(const char *specfile, const char *dir, fsnode *parent, int speconly)
315*9f988b79SJean-Baptiste Boric {
316*9f988b79SJean-Baptiste Boric struct timeval start;
317*9f988b79SJean-Baptiste Boric FILE *fp;
318*9f988b79SJean-Baptiste Boric NODE *root;
319*9f988b79SJean-Baptiste Boric
320*9f988b79SJean-Baptiste Boric assert(specfile != NULL);
321*9f988b79SJean-Baptiste Boric assert(parent != NULL);
322*9f988b79SJean-Baptiste Boric
323*9f988b79SJean-Baptiste Boric if (debug & DEBUG_APPLY_SPECFILE)
324*9f988b79SJean-Baptiste Boric printf("apply_specfile: %s, %s %p\n", specfile, dir, parent);
325*9f988b79SJean-Baptiste Boric
326*9f988b79SJean-Baptiste Boric /* read in the specfile */
327*9f988b79SJean-Baptiste Boric if ((fp = fopen(specfile, "r")) == NULL)
328*9f988b79SJean-Baptiste Boric err(1, "Can't open `%s'", specfile);
329*9f988b79SJean-Baptiste Boric TIMER_START(start);
330*9f988b79SJean-Baptiste Boric root = spec(fp);
331*9f988b79SJean-Baptiste Boric TIMER_RESULTS(start, "spec");
332*9f988b79SJean-Baptiste Boric if (fclose(fp) == EOF)
333*9f988b79SJean-Baptiste Boric err(1, "Can't close `%s'", specfile);
334*9f988b79SJean-Baptiste Boric
335*9f988b79SJean-Baptiste Boric /* perform some sanity checks */
336*9f988b79SJean-Baptiste Boric if (root == NULL)
337*9f988b79SJean-Baptiste Boric errx(1, "Specfile `%s' did not contain a tree", specfile);
338*9f988b79SJean-Baptiste Boric assert(strcmp(root->name, ".") == 0);
339*9f988b79SJean-Baptiste Boric assert(root->type == F_DIR);
340*9f988b79SJean-Baptiste Boric
341*9f988b79SJean-Baptiste Boric /* merge in the changes */
342*9f988b79SJean-Baptiste Boric apply_specdir(dir, root, parent, speconly);
343*9f988b79SJean-Baptiste Boric
344*9f988b79SJean-Baptiste Boric free_nodes(root);
345*9f988b79SJean-Baptiste Boric }
346*9f988b79SJean-Baptiste Boric
347*9f988b79SJean-Baptiste Boric static void
apply_specdir(const char * dir,NODE * specnode,fsnode * dirnode,int speconly)348*9f988b79SJean-Baptiste Boric apply_specdir(const char *dir, NODE *specnode, fsnode *dirnode, int speconly)
349*9f988b79SJean-Baptiste Boric {
350*9f988b79SJean-Baptiste Boric char path[MAXPATHLEN + 1];
351*9f988b79SJean-Baptiste Boric NODE *curnode;
352*9f988b79SJean-Baptiste Boric fsnode *curfsnode;
353*9f988b79SJean-Baptiste Boric
354*9f988b79SJean-Baptiste Boric assert(specnode != NULL);
355*9f988b79SJean-Baptiste Boric assert(dirnode != NULL);
356*9f988b79SJean-Baptiste Boric
357*9f988b79SJean-Baptiste Boric if (debug & DEBUG_APPLY_SPECFILE)
358*9f988b79SJean-Baptiste Boric printf("apply_specdir: %s %p %p\n", dir, specnode, dirnode);
359*9f988b79SJean-Baptiste Boric
360*9f988b79SJean-Baptiste Boric if (specnode->type != F_DIR)
361*9f988b79SJean-Baptiste Boric errx(1, "Specfile node `%s/%s' is not a directory",
362*9f988b79SJean-Baptiste Boric dir, specnode->name);
363*9f988b79SJean-Baptiste Boric if (dirnode->type != S_IFDIR)
364*9f988b79SJean-Baptiste Boric errx(1, "Directory node `%s/%s' is not a directory",
365*9f988b79SJean-Baptiste Boric dir, dirnode->name);
366*9f988b79SJean-Baptiste Boric
367*9f988b79SJean-Baptiste Boric apply_specentry(dir, specnode, dirnode);
368*9f988b79SJean-Baptiste Boric
369*9f988b79SJean-Baptiste Boric /* Remove any filesystem nodes not found in specfile */
370*9f988b79SJean-Baptiste Boric /* XXX inefficient. This is O^2 in each dir and it would
371*9f988b79SJean-Baptiste Boric * have been better never to have walked this part of the tree
372*9f988b79SJean-Baptiste Boric * to begin with
373*9f988b79SJean-Baptiste Boric */
374*9f988b79SJean-Baptiste Boric if (speconly) {
375*9f988b79SJean-Baptiste Boric fsnode *next;
376*9f988b79SJean-Baptiste Boric assert(dirnode->name[0] == '.' && dirnode->name[1] == '\0');
377*9f988b79SJean-Baptiste Boric for (curfsnode = dirnode->next; curfsnode != NULL; curfsnode = next) {
378*9f988b79SJean-Baptiste Boric next = curfsnode->next;
379*9f988b79SJean-Baptiste Boric for (curnode = specnode->child; curnode != NULL;
380*9f988b79SJean-Baptiste Boric curnode = curnode->next) {
381*9f988b79SJean-Baptiste Boric if (strcmp(curnode->name, curfsnode->name) == 0)
382*9f988b79SJean-Baptiste Boric break;
383*9f988b79SJean-Baptiste Boric }
384*9f988b79SJean-Baptiste Boric if (curnode == NULL) {
385*9f988b79SJean-Baptiste Boric if (debug & DEBUG_APPLY_SPECONLY) {
386*9f988b79SJean-Baptiste Boric printf("apply_specdir: trimming %s/%s %p\n", dir, curfsnode->name, curfsnode);
387*9f988b79SJean-Baptiste Boric }
388*9f988b79SJean-Baptiste Boric free_fsnodes(curfsnode);
389*9f988b79SJean-Baptiste Boric }
390*9f988b79SJean-Baptiste Boric }
391*9f988b79SJean-Baptiste Boric }
392*9f988b79SJean-Baptiste Boric
393*9f988b79SJean-Baptiste Boric /* now walk specnode->child matching up with dirnode */
394*9f988b79SJean-Baptiste Boric for (curnode = specnode->child; curnode != NULL;
395*9f988b79SJean-Baptiste Boric curnode = curnode->next) {
396*9f988b79SJean-Baptiste Boric if (debug & DEBUG_APPLY_SPECENTRY)
397*9f988b79SJean-Baptiste Boric printf("apply_specdir: spec %s\n",
398*9f988b79SJean-Baptiste Boric curnode->name);
399*9f988b79SJean-Baptiste Boric for (curfsnode = dirnode->next; curfsnode != NULL;
400*9f988b79SJean-Baptiste Boric curfsnode = curfsnode->next) {
401*9f988b79SJean-Baptiste Boric #if 0 /* too verbose for now */
402*9f988b79SJean-Baptiste Boric if (debug & DEBUG_APPLY_SPECENTRY)
403*9f988b79SJean-Baptiste Boric printf("apply_specdir: dirent %s\n",
404*9f988b79SJean-Baptiste Boric curfsnode->name);
405*9f988b79SJean-Baptiste Boric #endif
406*9f988b79SJean-Baptiste Boric if (strcmp(curnode->name, curfsnode->name) == 0)
407*9f988b79SJean-Baptiste Boric break;
408*9f988b79SJean-Baptiste Boric }
409*9f988b79SJean-Baptiste Boric if ((size_t)snprintf(path, sizeof(path), "%s/%s",
410*9f988b79SJean-Baptiste Boric dir, curnode->name) >= sizeof(path))
411*9f988b79SJean-Baptiste Boric errx(1, "Pathname too long.");
412*9f988b79SJean-Baptiste Boric if (curfsnode == NULL) { /* need new entry */
413*9f988b79SJean-Baptiste Boric struct stat stbuf;
414*9f988b79SJean-Baptiste Boric
415*9f988b79SJean-Baptiste Boric /*
416*9f988b79SJean-Baptiste Boric * don't add optional spec entries
417*9f988b79SJean-Baptiste Boric * that lack an existing fs entry
418*9f988b79SJean-Baptiste Boric */
419*9f988b79SJean-Baptiste Boric if ((curnode->flags & F_OPT) &&
420*9f988b79SJean-Baptiste Boric lstat(path, &stbuf) == -1)
421*9f988b79SJean-Baptiste Boric continue;
422*9f988b79SJean-Baptiste Boric
423*9f988b79SJean-Baptiste Boric /* check that enough info is provided */
424*9f988b79SJean-Baptiste Boric #define NODETEST(t, m) \
425*9f988b79SJean-Baptiste Boric if (!(t)) \
426*9f988b79SJean-Baptiste Boric errx(1, "`%s': %s not provided", path, m)
427*9f988b79SJean-Baptiste Boric NODETEST(curnode->flags & F_TYPE, "type");
428*9f988b79SJean-Baptiste Boric NODETEST(curnode->flags & F_MODE, "mode");
429*9f988b79SJean-Baptiste Boric /* XXX: require F_TIME ? */
430*9f988b79SJean-Baptiste Boric NODETEST(curnode->flags & F_GID ||
431*9f988b79SJean-Baptiste Boric curnode->flags & F_GNAME, "group");
432*9f988b79SJean-Baptiste Boric NODETEST(curnode->flags & F_UID ||
433*9f988b79SJean-Baptiste Boric curnode->flags & F_UNAME, "user");
434*9f988b79SJean-Baptiste Boric if (curnode->type == F_BLOCK || curnode->type == F_CHAR)
435*9f988b79SJean-Baptiste Boric NODETEST(curnode->flags & F_DEV,
436*9f988b79SJean-Baptiste Boric "device number");
437*9f988b79SJean-Baptiste Boric #undef NODETEST
438*9f988b79SJean-Baptiste Boric
439*9f988b79SJean-Baptiste Boric if (debug & DEBUG_APPLY_SPECFILE)
440*9f988b79SJean-Baptiste Boric printf("apply_specdir: adding %s\n",
441*9f988b79SJean-Baptiste Boric curnode->name);
442*9f988b79SJean-Baptiste Boric /* build minimal fsnode */
443*9f988b79SJean-Baptiste Boric memset(&stbuf, 0, sizeof(stbuf));
444*9f988b79SJean-Baptiste Boric stbuf.st_mode = nodetoino(curnode->type);
445*9f988b79SJean-Baptiste Boric stbuf.st_nlink = 1;
446*9f988b79SJean-Baptiste Boric stbuf.st_mtime = stbuf.st_atime =
447*9f988b79SJean-Baptiste Boric stbuf.st_ctime = start_time.tv_sec;
448*9f988b79SJean-Baptiste Boric #if HAVE_STRUCT_STAT_ST_MTIMENSEC
449*9f988b79SJean-Baptiste Boric stbuf.st_mtimensec = stbuf.st_atimensec =
450*9f988b79SJean-Baptiste Boric stbuf.st_ctimensec = start_time.tv_nsec;
451*9f988b79SJean-Baptiste Boric #endif
452*9f988b79SJean-Baptiste Boric curfsnode = create_fsnode(".", ".", curnode->name,
453*9f988b79SJean-Baptiste Boric &stbuf);
454*9f988b79SJean-Baptiste Boric curfsnode->parent = dirnode->parent;
455*9f988b79SJean-Baptiste Boric curfsnode->first = dirnode;
456*9f988b79SJean-Baptiste Boric curfsnode->next = dirnode->next;
457*9f988b79SJean-Baptiste Boric dirnode->next = curfsnode;
458*9f988b79SJean-Baptiste Boric if (curfsnode->type == S_IFDIR) {
459*9f988b79SJean-Baptiste Boric /* for dirs, make "." entry as well */
460*9f988b79SJean-Baptiste Boric curfsnode->child = create_fsnode(".", ".", ".",
461*9f988b79SJean-Baptiste Boric &stbuf);
462*9f988b79SJean-Baptiste Boric curfsnode->child->parent = curfsnode;
463*9f988b79SJean-Baptiste Boric curfsnode->child->first = curfsnode->child;
464*9f988b79SJean-Baptiste Boric }
465*9f988b79SJean-Baptiste Boric if (curfsnode->type == S_IFLNK) {
466*9f988b79SJean-Baptiste Boric assert(curnode->slink != NULL);
467*9f988b79SJean-Baptiste Boric /* for symlinks, copy the target */
468*9f988b79SJean-Baptiste Boric curfsnode->symlink = estrdup(curnode->slink);
469*9f988b79SJean-Baptiste Boric }
470*9f988b79SJean-Baptiste Boric }
471*9f988b79SJean-Baptiste Boric apply_specentry(dir, curnode, curfsnode);
472*9f988b79SJean-Baptiste Boric if (curnode->type == F_DIR) {
473*9f988b79SJean-Baptiste Boric if (curfsnode->type != S_IFDIR)
474*9f988b79SJean-Baptiste Boric errx(1, "`%s' is not a directory", path);
475*9f988b79SJean-Baptiste Boric assert (curfsnode->child != NULL);
476*9f988b79SJean-Baptiste Boric apply_specdir(path, curnode, curfsnode->child, speconly);
477*9f988b79SJean-Baptiste Boric }
478*9f988b79SJean-Baptiste Boric }
479*9f988b79SJean-Baptiste Boric }
480*9f988b79SJean-Baptiste Boric
481*9f988b79SJean-Baptiste Boric static void
apply_specentry(const char * dir,NODE * specnode,fsnode * dirnode)482*9f988b79SJean-Baptiste Boric apply_specentry(const char *dir, NODE *specnode, fsnode *dirnode)
483*9f988b79SJean-Baptiste Boric {
484*9f988b79SJean-Baptiste Boric
485*9f988b79SJean-Baptiste Boric assert(specnode != NULL);
486*9f988b79SJean-Baptiste Boric assert(dirnode != NULL);
487*9f988b79SJean-Baptiste Boric
488*9f988b79SJean-Baptiste Boric if (nodetoino(specnode->type) != dirnode->type)
489*9f988b79SJean-Baptiste Boric errx(1, "`%s/%s' type mismatch: specfile %s, tree %s",
490*9f988b79SJean-Baptiste Boric dir, specnode->name, inode_type(nodetoino(specnode->type)),
491*9f988b79SJean-Baptiste Boric inode_type(dirnode->type));
492*9f988b79SJean-Baptiste Boric
493*9f988b79SJean-Baptiste Boric if (debug & DEBUG_APPLY_SPECENTRY)
494*9f988b79SJean-Baptiste Boric printf("apply_specentry: %s/%s\n", dir, dirnode->name);
495*9f988b79SJean-Baptiste Boric
496*9f988b79SJean-Baptiste Boric #define ASEPRINT(t, b, o, n) \
497*9f988b79SJean-Baptiste Boric if (debug & DEBUG_APPLY_SPECENTRY) \
498*9f988b79SJean-Baptiste Boric printf("\t\t\tchanging %s from " b " to " b "\n", \
499*9f988b79SJean-Baptiste Boric t, o, n)
500*9f988b79SJean-Baptiste Boric
501*9f988b79SJean-Baptiste Boric if (specnode->flags & (F_GID | F_GNAME)) {
502*9f988b79SJean-Baptiste Boric ASEPRINT("gid", "%d",
503*9f988b79SJean-Baptiste Boric dirnode->inode->st.st_gid, specnode->st_gid);
504*9f988b79SJean-Baptiste Boric dirnode->inode->st.st_gid = specnode->st_gid;
505*9f988b79SJean-Baptiste Boric }
506*9f988b79SJean-Baptiste Boric if (specnode->flags & F_MODE) {
507*9f988b79SJean-Baptiste Boric ASEPRINT("mode", "%#o",
508*9f988b79SJean-Baptiste Boric dirnode->inode->st.st_mode & ALLPERMS, specnode->st_mode);
509*9f988b79SJean-Baptiste Boric dirnode->inode->st.st_mode &= ~ALLPERMS;
510*9f988b79SJean-Baptiste Boric dirnode->inode->st.st_mode |= (specnode->st_mode & ALLPERMS);
511*9f988b79SJean-Baptiste Boric }
512*9f988b79SJean-Baptiste Boric /* XXX: ignoring F_NLINK for now */
513*9f988b79SJean-Baptiste Boric if (specnode->flags & F_SIZE) {
514*9f988b79SJean-Baptiste Boric ASEPRINT("size", "%lld",
515*9f988b79SJean-Baptiste Boric (long long)dirnode->inode->st.st_size,
516*9f988b79SJean-Baptiste Boric (long long)specnode->st_size);
517*9f988b79SJean-Baptiste Boric dirnode->inode->st.st_size = specnode->st_size;
518*9f988b79SJean-Baptiste Boric }
519*9f988b79SJean-Baptiste Boric if (specnode->flags & F_SLINK) {
520*9f988b79SJean-Baptiste Boric assert(dirnode->symlink != NULL);
521*9f988b79SJean-Baptiste Boric assert(specnode->slink != NULL);
522*9f988b79SJean-Baptiste Boric ASEPRINT("symlink", "%s", dirnode->symlink, specnode->slink);
523*9f988b79SJean-Baptiste Boric free(dirnode->symlink);
524*9f988b79SJean-Baptiste Boric dirnode->symlink = estrdup(specnode->slink);
525*9f988b79SJean-Baptiste Boric }
526*9f988b79SJean-Baptiste Boric if (specnode->flags & F_TIME) {
527*9f988b79SJean-Baptiste Boric ASEPRINT("time", "%ld",
528*9f988b79SJean-Baptiste Boric (long)dirnode->inode->st.st_mtime,
529*9f988b79SJean-Baptiste Boric (long)specnode->st_mtimespec.tv_sec);
530*9f988b79SJean-Baptiste Boric dirnode->inode->st.st_mtime = specnode->st_mtimespec.tv_sec;
531*9f988b79SJean-Baptiste Boric dirnode->inode->st.st_atime = specnode->st_mtimespec.tv_sec;
532*9f988b79SJean-Baptiste Boric dirnode->inode->st.st_ctime = start_time.tv_sec;
533*9f988b79SJean-Baptiste Boric #if HAVE_STRUCT_STAT_ST_MTIMENSEC
534*9f988b79SJean-Baptiste Boric dirnode->inode->st.st_mtimensec = specnode->st_mtimespec.tv_nsec;
535*9f988b79SJean-Baptiste Boric dirnode->inode->st.st_atimensec = specnode->st_mtimespec.tv_nsec;
536*9f988b79SJean-Baptiste Boric dirnode->inode->st.st_ctimensec = start_time.tv_nsec;
537*9f988b79SJean-Baptiste Boric #endif
538*9f988b79SJean-Baptiste Boric }
539*9f988b79SJean-Baptiste Boric if (specnode->flags & (F_UID | F_UNAME)) {
540*9f988b79SJean-Baptiste Boric ASEPRINT("uid", "%d",
541*9f988b79SJean-Baptiste Boric dirnode->inode->st.st_uid, specnode->st_uid);
542*9f988b79SJean-Baptiste Boric dirnode->inode->st.st_uid = specnode->st_uid;
543*9f988b79SJean-Baptiste Boric }
544*9f988b79SJean-Baptiste Boric #if HAVE_STRUCT_STAT_ST_FLAGS
545*9f988b79SJean-Baptiste Boric if (specnode->flags & F_FLAGS) {
546*9f988b79SJean-Baptiste Boric ASEPRINT("flags", "%#lX",
547*9f988b79SJean-Baptiste Boric (unsigned long)dirnode->inode->st.st_flags,
548*9f988b79SJean-Baptiste Boric (unsigned long)specnode->st_flags);
549*9f988b79SJean-Baptiste Boric dirnode->inode->st.st_flags = specnode->st_flags;
550*9f988b79SJean-Baptiste Boric }
551*9f988b79SJean-Baptiste Boric #endif
552*9f988b79SJean-Baptiste Boric if (specnode->flags & F_DEV) {
553*9f988b79SJean-Baptiste Boric ASEPRINT("rdev", "%#llx",
554*9f988b79SJean-Baptiste Boric (unsigned long long)dirnode->inode->st.st_rdev,
555*9f988b79SJean-Baptiste Boric (unsigned long long)specnode->st_rdev);
556*9f988b79SJean-Baptiste Boric dirnode->inode->st.st_rdev = specnode->st_rdev;
557*9f988b79SJean-Baptiste Boric }
558*9f988b79SJean-Baptiste Boric #undef ASEPRINT
559*9f988b79SJean-Baptiste Boric
560*9f988b79SJean-Baptiste Boric dirnode->flags |= FSNODE_F_HASSPEC;
561*9f988b79SJean-Baptiste Boric }
562*9f988b79SJean-Baptiste Boric
563*9f988b79SJean-Baptiste Boric
564*9f988b79SJean-Baptiste Boric /*
565*9f988b79SJean-Baptiste Boric * dump_fsnodes --
566*9f988b79SJean-Baptiste Boric * dump the fsnodes from `cur'
567*9f988b79SJean-Baptiste Boric */
568*9f988b79SJean-Baptiste Boric void
dump_fsnodes(fsnode * root)569*9f988b79SJean-Baptiste Boric dump_fsnodes(fsnode *root)
570*9f988b79SJean-Baptiste Boric {
571*9f988b79SJean-Baptiste Boric fsnode *cur;
572*9f988b79SJean-Baptiste Boric char path[MAXPATHLEN + 1];
573*9f988b79SJean-Baptiste Boric
574*9f988b79SJean-Baptiste Boric printf("dump_fsnodes: %s %p\n", root->path, root);
575*9f988b79SJean-Baptiste Boric for (cur = root; cur != NULL; cur = cur->next) {
576*9f988b79SJean-Baptiste Boric if (snprintf(path, sizeof(path), "%s/%s", cur->path,
577*9f988b79SJean-Baptiste Boric cur->name) >= (int)sizeof(path))
578*9f988b79SJean-Baptiste Boric errx(1, "Pathname too long.");
579*9f988b79SJean-Baptiste Boric
580*9f988b79SJean-Baptiste Boric if (debug & DEBUG_DUMP_FSNODES_VERBOSE)
581*9f988b79SJean-Baptiste Boric printf("cur=%8p parent=%8p first=%8p ",
582*9f988b79SJean-Baptiste Boric cur, cur->parent, cur->first);
583*9f988b79SJean-Baptiste Boric printf("%7s: %s", inode_type(cur->type), path);
584*9f988b79SJean-Baptiste Boric if (S_ISLNK(cur->type)) {
585*9f988b79SJean-Baptiste Boric assert(cur->symlink != NULL);
586*9f988b79SJean-Baptiste Boric printf(" -> %s", cur->symlink);
587*9f988b79SJean-Baptiste Boric } else {
588*9f988b79SJean-Baptiste Boric assert (cur->symlink == NULL);
589*9f988b79SJean-Baptiste Boric }
590*9f988b79SJean-Baptiste Boric if (cur->inode->nlink > 1)
591*9f988b79SJean-Baptiste Boric printf(", nlinks=%d", cur->inode->nlink);
592*9f988b79SJean-Baptiste Boric putchar('\n');
593*9f988b79SJean-Baptiste Boric
594*9f988b79SJean-Baptiste Boric if (cur->child) {
595*9f988b79SJean-Baptiste Boric assert (cur->type == S_IFDIR);
596*9f988b79SJean-Baptiste Boric dump_fsnodes(cur->child);
597*9f988b79SJean-Baptiste Boric }
598*9f988b79SJean-Baptiste Boric }
599*9f988b79SJean-Baptiste Boric printf("dump_fsnodes: finished %s/%s\n", root->path, root->name);
600*9f988b79SJean-Baptiste Boric }
601*9f988b79SJean-Baptiste Boric
602*9f988b79SJean-Baptiste Boric
603*9f988b79SJean-Baptiste Boric /*
604*9f988b79SJean-Baptiste Boric * inode_type --
605*9f988b79SJean-Baptiste Boric * for a given inode type `mode', return a descriptive string.
606*9f988b79SJean-Baptiste Boric * for most cases, uses inotype() from mtree/misc.c
607*9f988b79SJean-Baptiste Boric */
608*9f988b79SJean-Baptiste Boric const char *
inode_type(mode_t mode)609*9f988b79SJean-Baptiste Boric inode_type(mode_t mode)
610*9f988b79SJean-Baptiste Boric {
611*9f988b79SJean-Baptiste Boric
612*9f988b79SJean-Baptiste Boric if (S_ISLNK(mode))
613*9f988b79SJean-Baptiste Boric return ("symlink"); /* inotype() returns "link"... */
614*9f988b79SJean-Baptiste Boric return (inotype(mode));
615*9f988b79SJean-Baptiste Boric }
616*9f988b79SJean-Baptiste Boric
617*9f988b79SJean-Baptiste Boric
618*9f988b79SJean-Baptiste Boric /*
619*9f988b79SJean-Baptiste Boric * link_check --
620*9f988b79SJean-Baptiste Boric * return pointer to fsinode matching `entry's st_ino & st_dev if it exists,
621*9f988b79SJean-Baptiste Boric * otherwise add `entry' to table and return NULL
622*9f988b79SJean-Baptiste Boric */
623*9f988b79SJean-Baptiste Boric /* This was borrowed from du.c and tweaked to keep an fsnode
624*9f988b79SJean-Baptiste Boric * pointer instead. -- dbj@netbsd.org
625*9f988b79SJean-Baptiste Boric */
626*9f988b79SJean-Baptiste Boric static fsinode *
link_check(fsinode * entry)627*9f988b79SJean-Baptiste Boric link_check(fsinode *entry)
628*9f988b79SJean-Baptiste Boric {
629*9f988b79SJean-Baptiste Boric static struct entry {
630*9f988b79SJean-Baptiste Boric fsinode *data;
631*9f988b79SJean-Baptiste Boric } *htable;
632*9f988b79SJean-Baptiste Boric static int htshift; /* log(allocated size) */
633*9f988b79SJean-Baptiste Boric static int htmask; /* allocated size - 1 */
634*9f988b79SJean-Baptiste Boric static int htused; /* 2*number of insertions */
635*9f988b79SJean-Baptiste Boric int h, h2;
636*9f988b79SJean-Baptiste Boric uint64_t tmp;
637*9f988b79SJean-Baptiste Boric /* this constant is (1<<64)/((1+sqrt(5))/2)
638*9f988b79SJean-Baptiste Boric * aka (word size)/(golden ratio)
639*9f988b79SJean-Baptiste Boric */
640*9f988b79SJean-Baptiste Boric const uint64_t HTCONST = 11400714819323198485ULL;
641*9f988b79SJean-Baptiste Boric const int HTBITS = 64;
642*9f988b79SJean-Baptiste Boric
643*9f988b79SJean-Baptiste Boric /* Never store zero in hashtable */
644*9f988b79SJean-Baptiste Boric assert(entry);
645*9f988b79SJean-Baptiste Boric
646*9f988b79SJean-Baptiste Boric /* Extend hash table if necessary, keep load under 0.5 */
647*9f988b79SJean-Baptiste Boric if (htused<<1 >= htmask) {
648*9f988b79SJean-Baptiste Boric struct entry *ohtable;
649*9f988b79SJean-Baptiste Boric
650*9f988b79SJean-Baptiste Boric if (!htable)
651*9f988b79SJean-Baptiste Boric htshift = 10; /* starting hashtable size */
652*9f988b79SJean-Baptiste Boric else
653*9f988b79SJean-Baptiste Boric htshift++; /* exponential hashtable growth */
654*9f988b79SJean-Baptiste Boric
655*9f988b79SJean-Baptiste Boric htmask = (1 << htshift) - 1;
656*9f988b79SJean-Baptiste Boric htused = 0;
657*9f988b79SJean-Baptiste Boric
658*9f988b79SJean-Baptiste Boric ohtable = htable;
659*9f988b79SJean-Baptiste Boric htable = ecalloc(htmask+1, sizeof(*htable));
660*9f988b79SJean-Baptiste Boric /* populate newly allocated hashtable */
661*9f988b79SJean-Baptiste Boric if (ohtable) {
662*9f988b79SJean-Baptiste Boric int i;
663*9f988b79SJean-Baptiste Boric for (i = 0; i <= htmask>>1; i++)
664*9f988b79SJean-Baptiste Boric if (ohtable[i].data)
665*9f988b79SJean-Baptiste Boric link_check(ohtable[i].data);
666*9f988b79SJean-Baptiste Boric free(ohtable);
667*9f988b79SJean-Baptiste Boric }
668*9f988b79SJean-Baptiste Boric }
669*9f988b79SJean-Baptiste Boric
670*9f988b79SJean-Baptiste Boric /* multiplicative hashing */
671*9f988b79SJean-Baptiste Boric tmp = entry->st.st_dev;
672*9f988b79SJean-Baptiste Boric tmp <<= HTBITS>>1;
673*9f988b79SJean-Baptiste Boric tmp |= entry->st.st_ino;
674*9f988b79SJean-Baptiste Boric tmp *= HTCONST;
675*9f988b79SJean-Baptiste Boric h = tmp >> (HTBITS - htshift);
676*9f988b79SJean-Baptiste Boric h2 = 1 | ( tmp >> (HTBITS - (htshift<<1) - 1)); /* must be odd */
677*9f988b79SJean-Baptiste Boric
678*9f988b79SJean-Baptiste Boric /* open address hashtable search with double hash probing */
679*9f988b79SJean-Baptiste Boric while (htable[h].data) {
680*9f988b79SJean-Baptiste Boric if ((htable[h].data->st.st_ino == entry->st.st_ino) &&
681*9f988b79SJean-Baptiste Boric (htable[h].data->st.st_dev == entry->st.st_dev)) {
682*9f988b79SJean-Baptiste Boric return htable[h].data;
683*9f988b79SJean-Baptiste Boric }
684*9f988b79SJean-Baptiste Boric h = (h + h2) & htmask;
685*9f988b79SJean-Baptiste Boric }
686*9f988b79SJean-Baptiste Boric
687*9f988b79SJean-Baptiste Boric /* Insert the current entry into hashtable */
688*9f988b79SJean-Baptiste Boric htable[h].data = entry;
689*9f988b79SJean-Baptiste Boric htused++;
690*9f988b79SJean-Baptiste Boric return NULL;
691*9f988b79SJean-Baptiste Boric }
692