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);
 			}
 		}
 

Reply via email to