| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: walk.c,v 1.35 2024/04/23 22:12:48 christos Exp $ */ | | 1 | /* $NetBSD: walk.c,v 1.36 2024/04/23 22:18:56 christos Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2001 Wasabi Systems, Inc. | | 4 | * Copyright (c) 2001 Wasabi Systems, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Written by Luke Mewburn for Wasabi Systems, Inc. | | 7 | * Written by Luke Mewburn for Wasabi Systems, Inc. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
| @@ -31,27 +31,27 @@ | | | @@ -31,27 +31,27 @@ |
31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 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 | | 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 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 | | 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
35 | * POSSIBILITY OF SUCH DAMAGE. | | 35 | * POSSIBILITY OF SUCH DAMAGE. |
36 | */ | | 36 | */ |
37 | | | 37 | |
38 | #if HAVE_NBTOOL_CONFIG_H | | 38 | #if HAVE_NBTOOL_CONFIG_H |
39 | #include "nbtool_config.h" | | 39 | #include "nbtool_config.h" |
40 | #endif | | 40 | #endif |
41 | | | 41 | |
42 | #include <sys/cdefs.h> | | 42 | #include <sys/cdefs.h> |
43 | #if defined(__RCSID) && !defined(__lint) | | 43 | #if defined(__RCSID) && !defined(__lint) |
44 | __RCSID("$NetBSD: walk.c,v 1.35 2024/04/23 22:12:48 christos Exp $"); | | 44 | __RCSID("$NetBSD: walk.c,v 1.36 2024/04/23 22:18:56 christos Exp $"); |
45 | #endif /* !__lint */ | | 45 | #endif /* !__lint */ |
46 | | | 46 | |
47 | #include <sys/param.h> | | 47 | #include <sys/param.h> |
48 | #include <sys/stat.h> | | 48 | #include <sys/stat.h> |
49 | | | 49 | |
50 | #include <assert.h> | | 50 | #include <assert.h> |
51 | #include <errno.h> | | 51 | #include <errno.h> |
52 | #include <fcntl.h> | | 52 | #include <fcntl.h> |
53 | #include <stdio.h> | | 53 | #include <stdio.h> |
54 | #include <dirent.h> | | 54 | #include <dirent.h> |
55 | #include <stdlib.h> | | 55 | #include <stdlib.h> |
56 | #include <string.h> | | 56 | #include <string.h> |
57 | #include <unistd.h> | | 57 | #include <unistd.h> |
| @@ -63,36 +63,37 @@ __RCSID("$NetBSD: walk.c,v 1.35 2024/04/ | | | @@ -63,36 +63,37 @@ __RCSID("$NetBSD: walk.c,v 1.35 2024/04/ |
63 | static void apply_specdir(const char *, NODE *, fsnode *, int); | | 63 | static void apply_specdir(const char *, NODE *, fsnode *, int); |
64 | static void apply_specentry(const char *, NODE *, fsnode *); | | 64 | static void apply_specentry(const char *, NODE *, fsnode *); |
65 | static fsnode *create_fsnode(const char *, const char *, const char *, | | 65 | static fsnode *create_fsnode(const char *, const char *, const char *, |
66 | struct stat *); | | 66 | struct stat *); |
67 | static fsinode *link_check(fsinode *); | | 67 | static fsinode *link_check(fsinode *); |
68 | | | 68 | |
69 | /* | | 69 | /* |
70 | * fsnode_cmp -- | | 70 | * fsnode_cmp -- |
71 | * This function is used by `qsort` so sort one directory's | | 71 | * This function is used by `qsort` so sort one directory's |
72 | * entries. `.` is always first, sollowed by anything else | | 72 | * entries. `.` is always first, sollowed by anything else |
73 | * as compared by `strcmp()`. | | 73 | * as compared by `strcmp()`. |
74 | */ | | 74 | */ |
75 | static int | | 75 | static int |
76 | fsnode_cmp (const void *_left, const void *_right) | | 76 | fsnode_cmp(const void *vleft, const void *vright) |
77 | { | | 77 | { |
78 | const fsnode * const left = *(const fsnode * const *)_left; | | 78 | const fsnode * const *left = vleft; |
79 | const fsnode * const right = *(const fsnode * const *)_right; | | 79 | const fsnode * const *right = vright; |
| | | 80 | const char *lname = (*left)->name, *rname = (*right)->name; |
80 | | | 81 | |
81 | if (strcmp (left->name, ".") == 0) | | 82 | if (strcmp(lname, ".") == 0) |
82 | return -1; | | 83 | return -1; |
83 | if (strcmp (right->name, ".") == 0) | | 84 | if (strcmp(rname, ".") == 0) |
84 | return 1; | | 85 | return 1; |
85 | return strcmp (left->name, right->name); | | 86 | return strcmp(lname, rname); |
86 | } | | 87 | } |
87 | | | 88 | |
88 | /* | | 89 | /* |
89 | * walk_dir -- | | 90 | * walk_dir -- |
90 | * build a tree of fsnodes from `root' and `dir', with a parent | | 91 | * build a tree of fsnodes from `root' and `dir', with a parent |
91 | * fsnode of `parent' (which may be NULL for the root of the tree). | | 92 | * fsnode of `parent' (which may be NULL for the root of the tree). |
92 | * append the tree to a fsnode of `join' if it is not NULL. | | 93 | * append the tree to a fsnode of `join' if it is not NULL. |
93 | * each "level" is a directory, with the "." entry guaranteed to be | | 94 | * each "level" is a directory, with the "." entry guaranteed to be |
94 | * at the start of the list, and without ".." entries. | | 95 | * at the start of the list, and without ".." entries. |
95 | */ | | 96 | */ |
96 | fsnode * | | 97 | fsnode * |
97 | walk_dir(const char *root, const char *dir, fsnode *parent, fsnode *join, | | 98 | walk_dir(const char *root, const char *dir, fsnode *parent, fsnode *join, |
98 | int replace, int follow) | | 99 | int replace, int follow) |
| @@ -239,34 +240,34 @@ walk_dir(const char *root, const char *d | | | @@ -239,34 +240,34 @@ walk_dir(const char *root, const char *d |
239 | replace, follow); | | 240 | replace, follow); |
240 | continue; | | 241 | continue; |
241 | } | | 242 | } |
242 | } | | 243 | } |
243 | if (stbuf.st_nlink > 1) { | | 244 | if (stbuf.st_nlink > 1) { |
244 | fsinode *curino; | | 245 | fsinode *curino; |
245 | | | 246 | |
246 | curino = link_check(cur->inode); | | 247 | curino = link_check(cur->inode); |
247 | if (curino != NULL) { | | 248 | if (curino != NULL) { |
248 | free(cur->inode); | | 249 | free(cur->inode); |
249 | cur->inode = curino; | | 250 | cur->inode = curino; |
250 | cur->inode->nlink++; | | 251 | cur->inode->nlink++; |
251 | if (debug & DEBUG_WALK_DIR_LINKCHECK) | | 252 | if (debug & DEBUG_WALK_DIR_LINKCHECK) |
252 | printf("link_check: found [%llu, %llu]\n", | | 253 | printf("link_check: found [%ju, %ju]\n", |
253 | (unsigned long long)curino->st.st_dev, | | 254 | (uintmax_t)curino->st.st_dev, |
254 | (unsigned long long)curino->st.st_ino); | | 255 | (uintmax_t)curino->st.st_ino); |
255 | } | | 256 | } |
256 | } | | 257 | } |
257 | if (S_ISLNK(cur->type)) { | | 258 | if (S_ISLNK(cur->type)) { |
258 | char slink[PATH_MAX+1]; | | 259 | char slink[PATH_MAX+1]; |
259 | int llen; | | 260 | ssize_t llen; |
260 | | | 261 | |
261 | llen = readlink(path, slink, sizeof(slink) - 1); | | 262 | llen = readlink(path, slink, sizeof(slink) - 1); |
262 | if (llen == -1) | | 263 | if (llen == -1) |
263 | err(EXIT_FAILURE, "Readlink `%s'", path); | | 264 | err(EXIT_FAILURE, "Readlink `%s'", path); |
264 | slink[llen] = '\0'; | | 265 | slink[llen] = '\0'; |
265 | cur->symlink = estrdup(slink); | | 266 | cur->symlink = estrdup(slink); |
266 | } | | 267 | } |
267 | } | | 268 | } |
268 | assert(first != NULL); | | 269 | assert(first != NULL); |
269 | if (join == NULL) | | 270 | if (join == NULL) |
270 | for (cur = first->next; cur != NULL; cur = cur->next) | | 271 | for (cur = first->next; cur != NULL; cur = cur->next) |
271 | cur->first = first; | | 272 | cur->first = first; |
272 | if (closedir(dirp) == -1) | | 273 | if (closedir(dirp) == -1) |
| @@ -584,29 +585,29 @@ apply_specentry(const char *dir, NODE *s | | | @@ -584,29 +585,29 @@ apply_specentry(const char *dir, NODE *s |
584 | if (specnode->flags & (F_GID | F_GNAME)) { | | 585 | if (specnode->flags & (F_GID | F_GNAME)) { |
585 | ASEPRINT("gid", "%d", | | 586 | ASEPRINT("gid", "%d", |
586 | dirnode->inode->st.st_gid, specnode->st_gid); | | 587 | dirnode->inode->st.st_gid, specnode->st_gid); |
587 | dirnode->inode->st.st_gid = specnode->st_gid; | | 588 | dirnode->inode->st.st_gid = specnode->st_gid; |
588 | } | | 589 | } |
589 | if (specnode->flags & F_MODE) { | | 590 | if (specnode->flags & F_MODE) { |
590 | ASEPRINT("mode", "%#o", | | 591 | ASEPRINT("mode", "%#o", |
591 | dirnode->inode->st.st_mode & ALLPERMS, specnode->st_mode); | | 592 | dirnode->inode->st.st_mode & ALLPERMS, specnode->st_mode); |
592 | dirnode->inode->st.st_mode &= ~ALLPERMS; | | 593 | dirnode->inode->st.st_mode &= ~ALLPERMS; |
593 | dirnode->inode->st.st_mode |= (specnode->st_mode & ALLPERMS); | | 594 | dirnode->inode->st.st_mode |= (specnode->st_mode & ALLPERMS); |
594 | } | | 595 | } |
595 | /* XXX: ignoring F_NLINK for now */ | | 596 | /* XXX: ignoring F_NLINK for now */ |
596 | if (specnode->flags & F_SIZE) { | | 597 | if (specnode->flags & F_SIZE) { |
597 | ASEPRINT("size", "%lld", | | 598 | ASEPRINT("size", "%jd", |
598 | (long long)dirnode->inode->st.st_size, | | 599 | (intmax_t)dirnode->inode->st.st_size, |
599 | (long long)specnode->st_size); | | 600 | (intmax_t)specnode->st_size); |
600 | dirnode->inode->st.st_size = specnode->st_size; | | 601 | dirnode->inode->st.st_size = specnode->st_size; |
601 | } | | 602 | } |
602 | if (specnode->flags & F_SLINK) { | | 603 | if (specnode->flags & F_SLINK) { |
603 | assert(dirnode->symlink != NULL); | | 604 | assert(dirnode->symlink != NULL); |
604 | assert(specnode->slink != NULL); | | 605 | assert(specnode->slink != NULL); |
605 | ASEPRINT("symlink", "%s", dirnode->symlink, specnode->slink); | | 606 | ASEPRINT("symlink", "%s", dirnode->symlink, specnode->slink); |
606 | free(dirnode->symlink); | | 607 | free(dirnode->symlink); |
607 | dirnode->symlink = estrdup(specnode->slink); | | 608 | dirnode->symlink = estrdup(specnode->slink); |
608 | } | | 609 | } |
609 | if (specnode->flags & F_TIME) { | | 610 | if (specnode->flags & F_TIME) { |
610 | ASEPRINT("time", "%ld", | | 611 | ASEPRINT("time", "%ld", |
611 | (long)dirnode->inode->st.st_mtime, | | 612 | (long)dirnode->inode->st.st_mtime, |
612 | (long)specnode->st_mtimespec.tv_sec); | | 613 | (long)specnode->st_mtimespec.tv_sec); |
| @@ -619,33 +620,33 @@ apply_specentry(const char *dir, NODE *s | | | @@ -619,33 +620,33 @@ apply_specentry(const char *dir, NODE *s |
619 | dirnode->inode->st.st_ctimensec = start_time.tv_nsec; | | 620 | dirnode->inode->st.st_ctimensec = start_time.tv_nsec; |
620 | #endif | | 621 | #endif |
621 | } | | 622 | } |
622 | if (specnode->flags & (F_UID | F_UNAME)) { | | 623 | if (specnode->flags & (F_UID | F_UNAME)) { |
623 | ASEPRINT("uid", "%d", | | 624 | ASEPRINT("uid", "%d", |
624 | dirnode->inode->st.st_uid, specnode->st_uid); | | 625 | dirnode->inode->st.st_uid, specnode->st_uid); |
625 | dirnode->inode->st.st_uid = specnode->st_uid; | | 626 | dirnode->inode->st.st_uid = specnode->st_uid; |
626 | } | | 627 | } |
627 | #if HAVE_STRUCT_STAT_ST_FLAGS | | 628 | #if HAVE_STRUCT_STAT_ST_FLAGS |
628 | if (specnode->flags & F_FLAGS) { | | 629 | if (specnode->flags & F_FLAGS) { |
629 | ASEPRINT("flags", "%#lX", | | 630 | ASEPRINT("flags", "%#lX", |
630 | (unsigned long)dirnode->inode->st.st_flags, | | 631 | (unsigned long)dirnode->inode->st.st_flags, |
631 | (unsigned long)specnode->st_flags); | | 632 | (unsigned long)specnode->st_flags); |
632 | dirnode->inode->st.st_flags = specnode->st_flags; | | 633 | dirnode->inode->st.st_flags = (unsigned int)specnode->st_flags; |
633 | } | | 634 | } |
634 | #endif | | 635 | #endif |
635 | if (specnode->flags & F_DEV) { | | 636 | if (specnode->flags & F_DEV) { |
636 | ASEPRINT("rdev", "%#llx", | | 637 | ASEPRINT("rdev", "%#jx", |
637 | (unsigned long long)dirnode->inode->st.st_rdev, | | 638 | (uintmax_t)dirnode->inode->st.st_rdev, |
638 | (unsigned long long)specnode->st_rdev); | | 639 | (uintmax_t)specnode->st_rdev); |
639 | dirnode->inode->st.st_rdev = specnode->st_rdev; | | 640 | dirnode->inode->st.st_rdev = specnode->st_rdev; |
640 | } | | 641 | } |
641 | #undef ASEPRINT | | 642 | #undef ASEPRINT |
642 | | | 643 | |
643 | dirnode->flags |= FSNODE_F_HASSPEC; | | 644 | dirnode->flags |= FSNODE_F_HASSPEC; |
644 | } | | 645 | } |
645 | | | 646 | |
646 | | | 647 | |
647 | /* | | 648 | /* |
648 | * dump_fsnodes -- | | 649 | * dump_fsnodes -- |
649 | * dump the fsnodes from `cur' | | 650 | * dump the fsnodes from `cur' |
650 | */ | | 651 | */ |
651 | void | | 652 | void |
| @@ -702,58 +703,57 @@ inode_type(mode_t mode) | | | @@ -702,58 +703,57 @@ inode_type(mode_t mode) |
702 | * link_check -- | | 703 | * link_check -- |
703 | * return pointer to fsinode matching `entry's st_ino & st_dev if it exists, | | 704 | * return pointer to fsinode matching `entry's st_ino & st_dev if it exists, |
704 | * otherwise add `entry' to table and return NULL | | 705 | * otherwise add `entry' to table and return NULL |
705 | */ | | 706 | */ |
706 | /* This was borrowed from du.c and tweaked to keep an fsnode | | 707 | /* This was borrowed from du.c and tweaked to keep an fsnode |
707 | * pointer instead. -- dbj@netbsd.org | | 708 | * pointer instead. -- dbj@netbsd.org |
708 | */ | | 709 | */ |
709 | static fsinode * | | 710 | static fsinode * |
710 | link_check(fsinode *entry) | | 711 | link_check(fsinode *entry) |
711 | { | | 712 | { |
712 | static struct entry { | | 713 | static struct entry { |
713 | fsinode *data; | | 714 | fsinode *data; |
714 | } *htable; | | 715 | } *htable; |
715 | static int htshift; /* log(allocated size) */ | | 716 | static size_t htshift; /* log(allocated size) */ |
716 | static int htmask; /* allocated size - 1 */ | | 717 | static size_t htmask; /* allocated size - 1 */ |
717 | static int htused; /* 2*number of insertions */ | | 718 | static size_t htused; /* 2*number of insertions */ |
718 | int h, h2; | | 719 | size_t h, h2; |
719 | uint64_t tmp; | | 720 | uint64_t tmp; |
720 | /* this constant is (1<<64)/((1+sqrt(5))/2) | | 721 | /* this constant is (1<<64)/((1+sqrt(5))/2) |
721 | * aka (word size)/(golden ratio) | | 722 | * aka (word size)/(golden ratio) |
722 | */ | | 723 | */ |
723 | const uint64_t HTCONST = 11400714819323198485ULL; | | 724 | const uint64_t HTCONST = 11400714819323198485ULL; |
724 | const int HTBITS = 64; | | 725 | const size_t HTBITS = 64; |
725 | | | 726 | |
726 | /* Never store zero in hashtable */ | | 727 | /* Never store zero in hashtable */ |
727 | assert(entry); | | 728 | assert(entry); |
728 | | | 729 | |
729 | /* Extend hash table if necessary, keep load under 0.5 */ | | 730 | /* Extend hash table if necessary, keep load under 0.5 */ |
730 | if (htused<<1 >= htmask) { | | 731 | if (htused<<1 >= htmask) { |
731 | struct entry *ohtable; | | 732 | struct entry *ohtable; |
732 | | | 733 | |
733 | if (!htable) | | 734 | if (!htable) |
734 | htshift = 10; /* starting hashtable size */ | | 735 | htshift = 10; /* starting hashtable size */ |
735 | else | | 736 | else |
736 | htshift++; /* exponential hashtable growth */ | | 737 | htshift++; /* exponential hashtable growth */ |
737 | | | 738 | |
738 | htmask = (1 << htshift) - 1; | | 739 | htmask = (1 << htshift) - 1; |
739 | htused = 0; | | 740 | htused = 0; |
740 | | | 741 | |
741 | ohtable = htable; | | 742 | ohtable = htable; |
742 | htable = ecalloc(htmask+1, sizeof(*htable)); | | 743 | htable = ecalloc(htmask+1, sizeof(*htable)); |
743 | /* populate newly allocated hashtable */ | | 744 | /* populate newly allocated hashtable */ |
744 | if (ohtable) { | | 745 | if (ohtable) { |
745 | int i; | | 746 | for (size_t i = 0; i <= htmask>>1; i++) |
746 | for (i = 0; i <= htmask>>1; i++) | | | |
747 | if (ohtable[i].data) | | 747 | if (ohtable[i].data) |
748 | link_check(ohtable[i].data); | | 748 | link_check(ohtable[i].data); |
749 | free(ohtable); | | 749 | free(ohtable); |
750 | } | | 750 | } |
751 | } | | 751 | } |
752 | | | 752 | |
753 | /* multiplicative hashing */ | | 753 | /* multiplicative hashing */ |
754 | tmp = entry->st.st_dev; | | 754 | tmp = entry->st.st_dev; |
755 | tmp <<= HTBITS>>1; | | 755 | tmp <<= HTBITS>>1; |
756 | tmp |= entry->st.st_ino; | | 756 | tmp |= entry->st.st_ino; |
757 | tmp *= HTCONST; | | 757 | tmp *= HTCONST; |
758 | h = tmp >> (HTBITS - htshift); | | 758 | h = tmp >> (HTBITS - htshift); |
759 | h2 = 1 | ( tmp >> (HTBITS - (htshift<<1) - 1)); /* must be odd */ | | 759 | h2 = 1 | ( tmp >> (HTBITS - (htshift<<1) - 1)); /* must be odd */ |