Module Name: src Committed By: christos Date: Fri Oct 18 23:28:03 UTC 2024
Modified Files: src/usr.sbin/makefs: walk.c Log Message: PR/58759: Kenichi Hashimoto: failed merge with extra-directory using -r option To generate a diff of this commit: cvs rdiff -u -r1.40 -r1.41 src/usr.sbin/makefs/walk.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.sbin/makefs/walk.c diff -u src/usr.sbin/makefs/walk.c:1.40 src/usr.sbin/makefs/walk.c:1.41 --- src/usr.sbin/makefs/walk.c:1.40 Wed May 8 11:57:56 2024 +++ src/usr.sbin/makefs/walk.c Fri Oct 18 19:28:03 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: walk.c,v 1.40 2024/05/08 15:57:56 christos Exp $ */ +/* $NetBSD: walk.c,v 1.41 2024/10/18 23:28:03 christos Exp $ */ /* * Copyright (c) 2001 Wasabi Systems, Inc. @@ -41,7 +41,7 @@ #include <sys/cdefs.h> #if defined(__RCSID) && !defined(__lint) -__RCSID("$NetBSD: walk.c,v 1.40 2024/05/08 15:57:56 christos Exp $"); +__RCSID("$NetBSD: walk.c,v 1.41 2024/10/18 23:28:03 christos Exp $"); #endif /* !__lint */ #include <sys/param.h> @@ -120,6 +120,72 @@ fsnode_sort(fsnode *first, const char *r } /* + * join current entry with the list. Return the current entry to replace + * in cur, and 1 if it is a directory and we need to add or 0 if we need + * to replace it. + */ +static int +fsnode_join(fsnode **curp, fsnode *join, fsnode *last, const char *path, + const char *name, const struct stat *st, int replace) +{ + fsnode *cur; + + /* Look for the entry to replace by name */ + cur = join->next; + for (;;) { + if (cur == NULL || strcmp(cur->name, name) == 0) + break; + if (cur == last) { + cur = NULL; + break; + } + cur = cur->next; + } + if (cur == NULL) { + /* Not found */ + *curp = NULL; + return 0; + } + if (S_ISDIR(cur->type) && S_ISDIR(st->st_mode)) { + /* + * both the entry to join and this entry are directories + * need to merge the two directories + */ + if (debug & DEBUG_WALK_DIR_NODE) + printf("%s: merging %s with %p\n", + __func__, path, cur->child); + *curp = cur; + return 1; + } + if (!replace) { + /* + * if they are not both directories and replace is not + * specified, bail out + */ + errx(EXIT_FAILURE, "Can't merge %s `%s' with existing %s", + inode_type(st->st_mode), path, inode_type(cur->type)); + } + + if (debug & DEBUG_WALK_DIR_NODE) + printf("%s: replacing %s %s\n", + __func__, inode_type(st->st_mode), path); + + /* merge the join list */ + if (cur == join->next) + join->next = cur->next; + else { + fsnode *p; + for (p = join->next; + p->next != cur; p = p->next) + continue; + p->next = cur->next; + } + /* return the entry to be replaced */ + *curp = cur; + return 0; +} + +/* * walk_dir -- * build a tree of fsnodes from `root' and `dir', with a parent * fsnode of `parent' (which may be NULL for the root of the tree). @@ -201,55 +267,28 @@ walk_dir(const char *root, const char *d #ifdef S_ISSOCK if (S_ISSOCK(stbuf.st_mode & S_IFMT)) { if (debug & DEBUG_WALK_DIR_NODE) - printf("%s: skipping socket %s\n", __func__, path); + printf("%s: skipping socket %s\n", __func__, + path); continue; } #endif if (join != NULL) { - cur = join->next; - for (;;) { - if (cur == NULL || strcmp(cur->name, name) == 0) - break; - if (cur == last) { - cur = NULL; - break; - } - cur = cur->next; - } - if (cur != NULL) { - if (S_ISDIR(cur->type) && - S_ISDIR(stbuf.st_mode)) { - if (debug & DEBUG_WALK_DIR_NODE) - printf("%s: merging %s with %p\n", - __func__, path, cur->child); - cur->child = walk_dir(root, rp, cur, - cur->child, replace, follow); - continue; - } - if (!replace) - errx(EXIT_FAILURE, - "Can't merge %s `%s' with " - "existing %s", - inode_type(stbuf.st_mode), path, - inode_type(cur->type)); - else { - if (debug & DEBUG_WALK_DIR_NODE) - printf("%s: replacing %s %s\n", - __func__, - inode_type(stbuf.st_mode), - path); - if (cur == join->next) - join->next = cur->next; - else { - fsnode *p; - for (p = join->next; - p->next != cur; p = p->next) - continue; - p->next = cur->next; - } - free(cur); + if (fsnode_join(&cur, join, last, path, name, &stbuf, + replace)) { + cur->child = walk_dir(root, rp, cur, + cur->child, replace, follow); + continue; + } else if (cur) { + if (prev == cur) { + fsnode *p = join; + while (p->next != NULL) + p = p->next; + prev = p; } + free(cur->name); + free(cur->path); + free(cur); } }