Deleted Added
full compact
walk.c (186335) walk.c (214921)
1/* $NetBSD: walk.c,v 1.17 2004/06/20 22:20:18 jmc Exp $ */
1/* $NetBSD: walk.c,v 1.24 2008/12/28 21:51:46 christos Exp $ */
2
3/*
4 * Copyright (c) 2001 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Luke Mewburn for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without

--- 20 unchanged lines hidden (view full) ---

30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
2
3/*
4 * Copyright (c) 2001 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Luke Mewburn for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without

--- 20 unchanged lines hidden (view full) ---

30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38/*
39 * The function link_check() was inspired from NetBSD's usr.bin/du/du.c,
40 * which has the following copyright notice:
41 *
42 *
43 * Copyright (c) 1989, 1993, 1994
44 * The Regents of the University of California. All rights reserved.
45 *
46 * This code is derived from software contributed to Berkeley by
47 * Chris Newcomb.
48 *
49 * Redistribution and use in source and binary forms, with or without
50 * modification, are permitted provided that the following conditions
51 * are met:
52 * 1. Redistributions of source code must retain the above copyright
53 * notice, this list of conditions and the following disclaimer.
54 * 2. Redistributions in binary form must reproduce the above copyright
55 * notice, this list of conditions and the following disclaimer in the
56 * documentation and/or other materials provided with the distribution.
57 * 3. Neither the name of the University nor the names of its contributors
58 * may be used to endorse or promote products derived from this software
59 * without specific prior written permission.
60 *
61 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
62 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
63 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
65 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
66 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
67 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
68 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
69 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
70 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
71 * SUCH DAMAGE.
72 */
73
74#include <sys/cdefs.h>
38
39#include <sys/cdefs.h>
75__FBSDID("$FreeBSD: head/usr.sbin/makefs/walk.c 186334 2008-12-19 18:45:43Z sam $");
40__FBSDID("$FreeBSD: head/usr.sbin/makefs/walk.c 214921 2010-11-07 16:05:04Z cognet $");
76
77#include <sys/param.h>
78
79#include <assert.h>
80#include <errno.h>
81#include <fcntl.h>
82#include <stdio.h>
83#include <dirent.h>
84#include <stdlib.h>
85#include <string.h>
86#include <unistd.h>
41
42#include <sys/param.h>
43
44#include <assert.h>
45#include <errno.h>
46#include <fcntl.h>
47#include <stdio.h>
48#include <dirent.h>
49#include <stdlib.h>
50#include <string.h>
51#include <unistd.h>
52#include <sys/stat.h>
87
88#include "makefs.h"
53
54#include "makefs.h"
89
90#include "mtree.h"
55#include "mtree.h"
91#include "extern.h" /* NB: mtree */
56#include "extern.h"
92
57
93static void apply_specdir(const char *, NODE *, fsnode *);
58static void apply_specdir(const char *, NODE *, fsnode *, int);
94static void apply_specentry(const char *, NODE *, fsnode *);
95static fsnode *create_fsnode(const char *, struct stat *);
96static fsinode *link_check(fsinode *);
97
98
99/*
100 * walk_dir --
101 * build a tree of fsnodes from `dir', with a parent fsnode of `parent'

--- 57 unchanged lines hidden (view full) ---

159 if (stbuf.st_nlink > 1) {
160 fsinode *curino;
161
162 curino = link_check(cur->inode);
163 if (curino != NULL) {
164 free(cur->inode);
165 cur->inode = curino;
166 cur->inode->nlink++;
59static void apply_specentry(const char *, NODE *, fsnode *);
60static fsnode *create_fsnode(const char *, struct stat *);
61static fsinode *link_check(fsinode *);
62
63
64/*
65 * walk_dir --
66 * build a tree of fsnodes from `dir', with a parent fsnode of `parent'

--- 57 unchanged lines hidden (view full) ---

124 if (stbuf.st_nlink > 1) {
125 fsinode *curino;
126
127 curino = link_check(cur->inode);
128 if (curino != NULL) {
129 free(cur->inode);
130 cur->inode = curino;
131 cur->inode->nlink++;
132 if (debug & DEBUG_WALK_DIR_LINKCHECK)
133 printf("link_check: found [%llu, %llu]\n",
134 (unsigned long long)curino->st.st_dev,
135 (unsigned long long)curino->st.st_ino);
167 }
168 }
169 if (S_ISLNK(cur->type)) {
170 char slink[PATH_MAX+1];
171 int llen;
172
173 llen = readlink(path, slink, sizeof(slink) - 1);
174 if (llen == -1)

--- 21 unchanged lines hidden (view full) ---

196 err(1, "Memory allocation error");
197 cur->type = stbuf->st_mode & S_IFMT;
198 cur->inode->nlink = 1;
199 cur->inode->st = *stbuf;
200 return (cur);
201}
202
203/*
136 }
137 }
138 if (S_ISLNK(cur->type)) {
139 char slink[PATH_MAX+1];
140 int llen;
141
142 llen = readlink(path, slink, sizeof(slink) - 1);
143 if (llen == -1)

--- 21 unchanged lines hidden (view full) ---

165 err(1, "Memory allocation error");
166 cur->type = stbuf->st_mode & S_IFMT;
167 cur->inode->nlink = 1;
168 cur->inode->st = *stbuf;
169 return (cur);
170}
171
172/*
173 * free_fsnodes --
174 * Removes node from tree and frees it and all of
175 * its decendents.
176 */
177void
178free_fsnodes(fsnode *node)
179{
180 fsnode *cur, *next;
181
182 assert(node != NULL);
183
184 /* for ".", start with actual parent node */
185 if (node->first == node) {
186 assert(node->name[0] == '.' && node->name[1] == '\0');
187 if (node->parent) {
188 assert(node->parent->child == node);
189 node = node->parent;
190 }
191 }
192
193 /* Find ourselves in our sibling list and unlink */
194 if (node->first != node) {
195 for (cur = node->first; cur->next; cur = cur->next) {
196 if (cur->next == node) {
197 cur->next = node->next;
198 node->next = NULL;
199 break;
200 }
201 }
202 }
203
204 for (cur = node; cur != NULL; cur = next) {
205 next = cur->next;
206 if (cur->child) {
207 cur->child->parent = NULL;
208 free_fsnodes(cur->child);
209 }
210 if (cur->inode->nlink-- == 1)
211 free(cur->inode);
212 if (cur->symlink)
213 free(cur->symlink);
214 free(cur->name);
215 free(cur);
216 }
217}
218
219/*
204 * apply_specfile --
205 * read in the mtree(8) specfile, and apply it to the tree
206 * at dir,parent. parameters in parent on equivalent types
207 * will be changed to those found in specfile, and missing
208 * entries will be added.
209 */
210void
220 * apply_specfile --
221 * read in the mtree(8) specfile, and apply it to the tree
222 * at dir,parent. parameters in parent on equivalent types
223 * will be changed to those found in specfile, and missing
224 * entries will be added.
225 */
226void
211apply_specfile(const char *specfile, const char *dir, fsnode *parent)
227apply_specfile(const char *specfile, const char *dir, fsnode *parent, int speconly)
212{
213 struct timeval start;
214 FILE *fp;
215 NODE *root;
216
217 assert(specfile != NULL);
218 assert(parent != NULL);
219

--- 11 unchanged lines hidden (view full) ---

231
232 /* perform some sanity checks */
233 if (root == NULL)
234 errx(1, "Specfile `%s' did not contain a tree", specfile);
235 assert(strcmp(root->name, ".") == 0);
236 assert(root->type == F_DIR);
237
238 /* merge in the changes */
228{
229 struct timeval start;
230 FILE *fp;
231 NODE *root;
232
233 assert(specfile != NULL);
234 assert(parent != NULL);
235

--- 11 unchanged lines hidden (view full) ---

247
248 /* perform some sanity checks */
249 if (root == NULL)
250 errx(1, "Specfile `%s' did not contain a tree", specfile);
251 assert(strcmp(root->name, ".") == 0);
252 assert(root->type == F_DIR);
253
254 /* merge in the changes */
239 apply_specdir(dir, root, parent);
255 apply_specdir(dir, root, parent, speconly);
256
240}
241
242static u_int
243nodetoino(u_int type)
244{
245
246 switch (type) {
247 case F_BLOCK:

--- 12 unchanged lines hidden (view full) ---

260 return S_IFSOCK;
261 default:
262 printf("unknown type %d", type);
263 abort();
264 }
265 /* NOTREACHED */
266}
267
257}
258
259static u_int
260nodetoino(u_int type)
261{
262
263 switch (type) {
264 case F_BLOCK:

--- 12 unchanged lines hidden (view full) ---

277 return S_IFSOCK;
278 default:
279 printf("unknown type %d", type);
280 abort();
281 }
282 /* NOTREACHED */
283}
284
285
268static void
286static void
269apply_specdir(const char *dir, NODE *specnode, fsnode *dirnode)
287apply_specdir(const char *dir, NODE *specnode, fsnode *dirnode, int speconly)
270{
271 char path[MAXPATHLEN + 1];
272 NODE *curnode;
273 fsnode *curfsnode;
274
275 assert(specnode != NULL);
276 assert(dirnode != NULL);
277

--- 4 unchanged lines hidden (view full) ---

282 errx(1, "Specfile node `%s/%s' is not a directory",
283 dir, specnode->name);
284 if (dirnode->type != S_IFDIR)
285 errx(1, "Directory node `%s/%s' is not a directory",
286 dir, dirnode->name);
287
288 apply_specentry(dir, specnode, dirnode);
289
288{
289 char path[MAXPATHLEN + 1];
290 NODE *curnode;
291 fsnode *curfsnode;
292
293 assert(specnode != NULL);
294 assert(dirnode != NULL);
295

--- 4 unchanged lines hidden (view full) ---

300 errx(1, "Specfile node `%s/%s' is not a directory",
301 dir, specnode->name);
302 if (dirnode->type != S_IFDIR)
303 errx(1, "Directory node `%s/%s' is not a directory",
304 dir, dirnode->name);
305
306 apply_specentry(dir, specnode, dirnode);
307
308 /* Remove any filesystem nodes not found in specfile */
309 /* XXX inefficient. This is O^2 in each dir and it would
310 * have been better never to have walked this part of the tree
311 * to begin with
312 */
313 if (speconly) {
314 fsnode *next;
315 assert(dirnode->name[0] == '.' && dirnode->name[1] == '\0');
316 for (curfsnode = dirnode->next; curfsnode != NULL; curfsnode = next) {
317 next = curfsnode->next;
318 for (curnode = specnode->child; curnode != NULL;
319 curnode = curnode->next) {
320 if (strcmp(curnode->name, curfsnode->name) == 0)
321 break;
322 }
323 if (curnode == NULL) {
324 if (debug & DEBUG_APPLY_SPECONLY) {
325 printf("apply_specdir: trimming %s/%s %p\n", dir, curfsnode->name, curfsnode);
326 }
327 free_fsnodes(curfsnode);
328 }
329 }
330 }
331
290 /* now walk specnode->child matching up with dirnode */
291 for (curnode = specnode->child; curnode != NULL;
292 curnode = curnode->next) {
293 if (debug & DEBUG_APPLY_SPECENTRY)
294 printf("apply_specdir: spec %s\n",
295 curnode->name);
296 for (curfsnode = dirnode->next; curfsnode != NULL;
297 curfsnode = curfsnode->next) {

--- 25 unchanged lines hidden (view full) ---

323 errx(1, "`%s': %s not provided", path, m)
324 NODETEST(curnode->flags & F_TYPE, "type");
325 NODETEST(curnode->flags & F_MODE, "mode");
326 /* XXX: require F_TIME ? */
327 NODETEST(curnode->flags & F_GID ||
328 curnode->flags & F_GNAME, "group");
329 NODETEST(curnode->flags & F_UID ||
330 curnode->flags & F_UNAME, "user");
332 /* now walk specnode->child matching up with dirnode */
333 for (curnode = specnode->child; curnode != NULL;
334 curnode = curnode->next) {
335 if (debug & DEBUG_APPLY_SPECENTRY)
336 printf("apply_specdir: spec %s\n",
337 curnode->name);
338 for (curfsnode = dirnode->next; curfsnode != NULL;
339 curfsnode = curfsnode->next) {

--- 25 unchanged lines hidden (view full) ---

365 errx(1, "`%s': %s not provided", path, m)
366 NODETEST(curnode->flags & F_TYPE, "type");
367 NODETEST(curnode->flags & F_MODE, "mode");
368 /* XXX: require F_TIME ? */
369 NODETEST(curnode->flags & F_GID ||
370 curnode->flags & F_GNAME, "group");
371 NODETEST(curnode->flags & F_UID ||
372 curnode->flags & F_UNAME, "user");
373/* if (curnode->type == F_BLOCK || curnode->type == F_CHAR)
374 NODETEST(curnode->flags & F_DEV,
375 "device number");*/
331#undef NODETEST
332
333 if (debug & DEBUG_APPLY_SPECFILE)
334 printf("apply_specdir: adding %s\n",
335 curnode->name);
336 /* build minimal fsnode */
337 memset(&stbuf, 0, sizeof(stbuf));
338 stbuf.st_mode = nodetoino(curnode->type);

--- 23 unchanged lines hidden (view full) ---

362 err(1, "Memory allocation error");
363 }
364 }
365 apply_specentry(dir, curnode, curfsnode);
366 if (curnode->type == F_DIR) {
367 if (curfsnode->type != S_IFDIR)
368 errx(1, "`%s' is not a directory", path);
369 assert (curfsnode->child != NULL);
376#undef NODETEST
377
378 if (debug & DEBUG_APPLY_SPECFILE)
379 printf("apply_specdir: adding %s\n",
380 curnode->name);
381 /* build minimal fsnode */
382 memset(&stbuf, 0, sizeof(stbuf));
383 stbuf.st_mode = nodetoino(curnode->type);

--- 23 unchanged lines hidden (view full) ---

407 err(1, "Memory allocation error");
408 }
409 }
410 apply_specentry(dir, curnode, curfsnode);
411 if (curnode->type == F_DIR) {
412 if (curfsnode->type != S_IFDIR)
413 errx(1, "`%s' is not a directory", path);
414 assert (curfsnode->child != NULL);
370 apply_specdir(path, curnode, curfsnode->child);
415 apply_specdir(path, curnode, curfsnode->child, speconly);
371 }
372 }
373}
374
375static void
376apply_specentry(const char *dir, NODE *specnode, fsnode *dirnode)
377{
378

--- 60 unchanged lines hidden (view full) ---

439#if HAVE_STRUCT_STAT_ST_FLAGS
440 if (specnode->flags & F_FLAGS) {
441 ASEPRINT("flags", "%#lX",
442 (unsigned long)dirnode->inode->st.st_flags,
443 (unsigned long)specnode->st_flags);
444 dirnode->inode->st.st_flags = specnode->st_flags;
445 }
446#endif
416 }
417 }
418}
419
420static void
421apply_specentry(const char *dir, NODE *specnode, fsnode *dirnode)
422{
423

--- 60 unchanged lines hidden (view full) ---

484#if HAVE_STRUCT_STAT_ST_FLAGS
485 if (specnode->flags & F_FLAGS) {
486 ASEPRINT("flags", "%#lX",
487 (unsigned long)dirnode->inode->st.st_flags,
488 (unsigned long)specnode->st_flags);
489 dirnode->inode->st.st_flags = specnode->st_flags;
490 }
491#endif
492/* if (specnode->flags & F_DEV) {
493 ASEPRINT("rdev", "%#llx",
494 (unsigned long long)dirnode->inode->st.st_rdev,
495 (unsigned long long)specnode->st_rdev);
496 dirnode->inode->st.st_rdev = specnode->st_rdev;
497 }*/
447#undef ASEPRINT
448
449 dirnode->flags |= FSNODE_F_HASSPEC;
450}
451
452
453/*
454 * dump_fsnodes --

--- 33 unchanged lines hidden (view full) ---

488 }
489 printf("dump_fsnodes: finished %s\n", dir);
490}
491
492
493/*
494 * inode_type --
495 * for a given inode type `mode', return a descriptive string.
498#undef ASEPRINT
499
500 dirnode->flags |= FSNODE_F_HASSPEC;
501}
502
503
504/*
505 * dump_fsnodes --

--- 33 unchanged lines hidden (view full) ---

539 }
540 printf("dump_fsnodes: finished %s\n", dir);
541}
542
543
544/*
545 * inode_type --
546 * for a given inode type `mode', return a descriptive string.
547 * for most cases, uses inotype() from mtree/misc.c
496 */
497const char *
498inode_type(mode_t mode)
499{
548 */
549const char *
550inode_type(mode_t mode)
551{
500
501 if (S_ISREG(mode))
502 return ("file");
503 if (S_ISLNK(mode))
504 return ("symlink");
505 if (S_ISDIR(mode))
506 return ("dir");
507 if (S_ISLNK(mode))
508 return ("link");

--- 7 unchanged lines hidden (view full) ---

516 if (S_ISBLK(mode))
517 return ("block");
518 return ("unknown");
519}
520
521
522/*
523 * link_check --
552 if (S_ISREG(mode))
553 return ("file");
554 if (S_ISLNK(mode))
555 return ("symlink");
556 if (S_ISDIR(mode))
557 return ("dir");
558 if (S_ISLNK(mode))
559 return ("link");

--- 7 unchanged lines hidden (view full) ---

567 if (S_ISBLK(mode))
568 return ("block");
569 return ("unknown");
570}
571
572
573/*
574 * link_check --
524 * return pointer to fsnode matching `entry's st_ino & st_dev if it exists,
575 * return pointer to fsinode matching `entry's st_ino & st_dev if it exists,
525 * otherwise add `entry' to table and return NULL
526 */
576 * otherwise add `entry' to table and return NULL
577 */
578/* This was borrowed from du.c and tweaked to keep an fsnode
579 * pointer instead. -- dbj@netbsd.org
580 */
527static fsinode *
528link_check(fsinode *entry)
529{
581static fsinode *
582link_check(fsinode *entry)
583{
530 static struct dupnode {
531 uint32_t dev;
532 uint64_t ino;
533 fsinode *dup;
534 } *dups, *newdups;
535 static int ndups, maxdups;
584 static struct entry {
585 fsinode *data;
586 } *htable;
587 static int htshift; /* log(allocated size) */
588 static int htmask; /* allocated size - 1 */
589 static int htused; /* 2*number of insertions */
590 int h, h2;
591 uint64_t tmp;
592 /* this constant is (1<<64)/((1+sqrt(5))/2)
593 * aka (word size)/(golden ratio)
594 */
595 const uint64_t HTCONST = 11400714819323198485ULL;
596 const int HTBITS = 64;
597
598 /* Never store zero in hashtable */
599 assert(entry);
536
600
537 int i;
601 /* Extend hash table if necessary, keep load under 0.5 */
602 if (htused<<1 >= htmask) {
603 struct entry *ohtable;
538
604
539 assert (entry != NULL);
605 if (!htable)
606 htshift = 10; /* starting hashtable size */
607 else
608 htshift++; /* exponential hashtable growth */
540
609
541 /* XXX; maybe traverse in reverse for speed? */
542 for (i = 0; i < ndups; i++) {
543 if (dups[i].dev == entry->st.st_dev &&
544 dups[i].ino == entry->st.st_ino) {
545 if (debug & DEBUG_WALK_DIR_LINKCHECK)
546 printf("link_check: found [%d,%d]\n",
547 entry->st.st_dev, entry->st.st_ino);
548 return (dups[i].dup);
610 htmask = (1 << htshift) - 1;
611 htused = 0;
612
613 ohtable = htable;
614 htable = calloc(htmask+1, sizeof(*htable));
615 if (!htable)
616 err(1, "Memory allocation error");
617
618 /* populate newly allocated hashtable */
619 if (ohtable) {
620 int i;
621 for (i = 0; i <= htmask>>1; i++)
622 if (ohtable[i].data)
623 link_check(ohtable[i].data);
624 free(ohtable);
549 }
550 }
551
625 }
626 }
627
552 if (debug & DEBUG_WALK_DIR_LINKCHECK)
553 printf("link_check: no match for [%d, %d]\n",
554 entry->st.st_dev, entry->st.st_ino);
555 if (ndups == maxdups) {
556 if ((newdups = realloc(dups, sizeof(struct dupnode) * (maxdups + 128)))
557 == NULL)
558 err(1, "Memory allocation error");
559 dups = newdups;
560 maxdups += 128;
628 /* multiplicative hashing */
629 tmp = entry->st.st_dev;
630 tmp <<= HTBITS>>1;
631 tmp |= entry->st.st_ino;
632 tmp *= HTCONST;
633 h = tmp >> (HTBITS - htshift);
634 h2 = 1 | ( tmp >> (HTBITS - (htshift<<1) - 1)); /* must be odd */
635
636 /* open address hashtable search with double hash probing */
637 while (htable[h].data) {
638 if ((htable[h].data->st.st_ino == entry->st.st_ino) &&
639 (htable[h].data->st.st_dev == entry->st.st_dev)) {
640 return htable[h].data;
641 }
642 h = (h + h2) & htmask;
561 }
643 }
562 dups[ndups].dev = entry->st.st_dev;
563 dups[ndups].ino = entry->st.st_ino;
564 dups[ndups].dup = entry;
565 ndups++;
566
644
567 return (NULL);
645 /* Insert the current entry into hashtable */
646 htable[h].data = entry;
647 htused++;
648 return NULL;
568}
649}