Module Name:    src
Committed By:   christos
Date:           Tue Apr 23 22:12:16 UTC 2024

Modified Files:
        src/usr.sbin/makefs: walk.c

Log Message:
makefs: Sort directory contents by name (Jan-Benedict Glaw)

`makefs` inserts nodes into its internal data structures in the order as
returned by `readdir()` calls. As this is unpredictable, sort entries by
name before creating the target filesystem.

  This is done by first converting the (per-directory) linked list into
a plain array, sort it, finally re-link the list. Special case for the
sorting function: The "." directory entry seems to be ment to be always
at the front, so always check that first.


To generate a diff of this commit:
cvs rdiff -u -r1.33 -r1.34 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.33 src/usr.sbin/makefs/walk.c:1.34
--- src/usr.sbin/makefs/walk.c:1.33	Thu Dec 28 07:13:55 2023
+++ src/usr.sbin/makefs/walk.c	Tue Apr 23 18:12:16 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: walk.c,v 1.33 2023/12/28 12:13:55 tsutsui Exp $	*/
+/*	$NetBSD: walk.c,v 1.34 2024/04/23 22:12:16 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.33 2023/12/28 12:13:55 tsutsui Exp $");
+__RCSID("$NetBSD: walk.c,v 1.34 2024/04/23 22:12:16 christos Exp $");
 #endif	/* !__lint */
 
 #include <sys/param.h>
@@ -66,6 +66,24 @@ static	fsnode	*create_fsnode(const char 
 			       struct stat *);
 static	fsinode	*link_check(fsinode *);
 
+/*
+ * fsnode_cmp --
+ *	This function is used by `qsort` so sort one directory's
+ *	entries.  `.` is always first, sollowed by anything else
+ *	as compared by `strcmp()`.
+ */
+static int
+fsnode_cmp (const void *_left, const void *_right)
+{
+	const fsnode * const left  = *(const fsnode * const *)_left;
+	const fsnode * const right = *(const fsnode * const *)_right;
+
+	if (strcmp (left->name, ".") == 0)
+		return -1;
+	if (strcmp (right->name, ".") == 0)
+		return 1;
+	return strcmp (left->name, right->name);
+}
 
 /*
  * walk_dir --
@@ -87,6 +105,9 @@ walk_dir(const char *root, const char *d
 	char		*name, *rp;
 	int		dot, len;
 
+	fsnode **list, **listptr;
+	int num = 0;
+
 	assert(root != NULL);
 	assert(dir != NULL);
 
@@ -241,7 +262,36 @@ walk_dir(const char *root, const char *d
 			cur->first = first;
 	if (closedir(dirp) == -1)
 		err(EXIT_FAILURE, "Can't closedir `%s/%s'", root, dir);
-	return (first);
+
+	/*
+	 * Sort entries.
+	 */
+	/* Create a plain list: Count, alloc, add.  */
+	for (fsnode *tmp = first; tmp; tmp = tmp->next) {
+		num++;
+		if (debug & DEBUG_DUMP_FSNODES_VERBOSE)
+			printf ("pre sort: %s %s %s\n", root, dir, tmp->name);
+	}
+	list = listptr = ecalloc (num, sizeof (*list));
+	for (fsnode *tmp = first; tmp; tmp = tmp->next)
+		*listptr++ = tmp;
+	/* Sort plain list.  */
+	qsort (list, num, sizeof (*list), &fsnode_cmp);
+	/* Rewire.  */
+	for (int i = 0; i < num - 1; ++i)
+		list[i]->next = list[i+1];
+	list[num - 1]->next = NULL;
+	first = list[0];
+	/* Check `first` to be ".".  */
+	assert (strcmp (first->name, ".") == 0);
+	/* Free.  */
+	free (list);
+	/* Dump sorted state.  */
+	if (debug & DEBUG_DUMP_FSNODES_VERBOSE)
+		for (fsnode *tmp = first; tmp; tmp = tmp->next)
+			printf ("post sort: %s %s %s\n", root, dir, tmp->name);
+
+	return first;
 }
 
 static fsnode *

Reply via email to