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

Gao Xiang hsiangkao at linux.alibaba.com
Tue Dec 3 12:38:29 AEDT 2024


Hi Jooyung,

On 2024/12/3 08:27, Jooyung Han wrote:
> 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>

Thanks for the patch.  I haven't tested the current behavior (1.8.2),
but EROFS will sort all dirents in a directory in
erofs_prepare_dir_file(). And then dump all subdirs in
erofs_mkfs_dump_tree().

It seems both dirents and inodes are sorted in the alphabetical
order, could you give more hints about this?

Thanks,
Gao Xiang

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



More information about the Linux-erofs mailing list