[PATCH v2] erofs-utils: mkfs: use scandir for stable output

Jooyung Han jooyung at google.com
Tue Dec 3 11:27:20 AEDT 2024


The iteration order of opendir/readdir depends on filesystem
implementation. Hence, even with the same contents, the filesystem of
the input directory affects the output.

In this change, opendir/readdir is replaced with scandir for stable
order of iteration. This produces the same output regardless of the
filesystem of the input directory.

Test: mkfs.erofs ... inputdir(ext3)
Test: mkfs.erofs ... inputdir(tmpfs)
  # should generate the same output
Signed-off-by: Jooyung Han <jooyung at google.com>
---

v1: https://lore.kernel.org/linux-erofs/20241202232620.3604736-1-jooyung@google.com/
change since v1:
 - modify commit msg (no change-id/bug/typo)
 - rename the label to err_cleanup

 lib/inode.c | 39 ++++++++++++++-------------------------
 1 file changed, 14 insertions(+), 25 deletions(-)

diff --git a/lib/inode.c b/lib/inode.c
index f553bec..097deef 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -1422,37 +1422,25 @@ static void erofs_mkfs_flushjobs(struct erofs_sb_info *sbi)
 static int erofs_mkfs_handle_directory(struct erofs_inode *dir)
 {
 	struct erofs_sb_info *sbi = dir->sbi;
-	DIR *_dir;
-	struct dirent *dp;
+	struct dirent *dp, **dent;
+	int i, num_entries;
 	struct erofs_dentry *d;
 	unsigned int nr_subdirs, i_nlink;
 	int ret;
 
-	_dir = opendir(dir->i_srcpath);
-	if (!_dir) {
-		erofs_err("failed to opendir at %s: %s",
+	num_entries = scandir(dir->i_srcpath, &dent, NULL, alphasort);
+	if (num_entries == -1) {
+		erofs_err("failed to scandir at %s: %s",
 			  dir->i_srcpath, erofs_strerror(-errno));
 		return -errno;
 	}
 
 	nr_subdirs = 0;
 	i_nlink = 0;
-	while (1) {
+	for (i = 0; i < num_entries; free(dent[i]), i++) {
 		char buf[PATH_MAX];
 		struct erofs_inode *inode;
-
-		/*
-		 * set errno to 0 before calling readdir() in order to
-		 * distinguish end of stream and from an error.
-		 */
-		errno = 0;
-		dp = readdir(_dir);
-		if (!dp) {
-			if (!errno)
-				break;
-			ret = -errno;
-			goto err_closedir;
-		}
+		dp = dent[i];
 
 		if (is_dot_dotdot(dp->d_name)) {
 			++i_nlink;
@@ -1466,17 +1454,17 @@ static int erofs_mkfs_handle_directory(struct erofs_inode *dir)
 		d = erofs_d_alloc(dir, dp->d_name);
 		if (IS_ERR(d)) {
 			ret = PTR_ERR(d);
-			goto err_closedir;
+			goto err_cleanup;
 		}
 
 		ret = snprintf(buf, PATH_MAX, "%s/%s", dir->i_srcpath, d->name);
 		if (ret < 0 || ret >= PATH_MAX)
-			goto err_closedir;
+			goto err_cleanup;
 
 		inode = erofs_iget_from_srcpath(sbi, buf);
 		if (IS_ERR(inode)) {
 			ret = PTR_ERR(inode);
-			goto err_closedir;
+			goto err_cleanup;
 		}
 		d->inode = inode;
 		d->type = erofs_mode_to_ftype(inode->i_mode);
@@ -1484,7 +1472,7 @@ static int erofs_mkfs_handle_directory(struct erofs_inode *dir)
 		erofs_dbg("file %s added (type %u)", buf, d->type);
 		nr_subdirs++;
 	}
-	closedir(_dir);
+	free(dent);
 
 	ret = erofs_init_empty_dir(dir);
 	if (ret)
@@ -1506,8 +1494,9 @@ static int erofs_mkfs_handle_directory(struct erofs_inode *dir)
 
 	return erofs_mkfs_go(sbi, EROFS_MKFS_JOB_DIR, &dir, sizeof(dir));
 
-err_closedir:
-	closedir(_dir);
+err_cleanup:
+	for (; i < num_entries; free(dent[i]), i++);
+	free(dent);
 	return ret;
 }
 
-- 
2.47.0.338.g60cca15819-goog



More information about the Linux-erofs mailing list