misc: use scandir with alphasort instead of readdir for consistency

During the image generation, When using the e2fsdroid with src_dir,
then dir files are listed with readdir, which will not guarantee
the order across the machines/fielsystems. So instead using the
scandir with alphasort option to list the files in sorted order.

Reported-by: Yasuhiro Kubota <yasuhiro.1.kubota@sony.com>
Signed-off-by: Vikram Dattu Thota <vikram.dattu@sony.com>
Signed-off-by: Takuya Ogawa <takuya.ogawa@sony.com>
Signed-off-by: Yoshitaka Seto <yoshitaka.seto@sony.com>
Tested-by: Yasuhiro Kubota <yasuhiro.1.kubota@sony.com>

Bug: 122874817

Change-Id: I4b946c737319252b82c74a0e10360843503862a1
diff --git a/misc/create_inode.c b/misc/create_inode.c
index 05aa636..0cbbd3b 100644
--- a/misc/create_inode.c
+++ b/misc/create_inode.c
@@ -19,6 +19,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include <limits.h> /* for PATH_MAX */
+#include <dirent.h> /* for scandir() and alphasort() */
 #if defined HAVE_SYS_XATTR_H
 #include <sys/xattr.h>
 #elif defined HAVE_ATTR_XATTR_H
@@ -714,7 +715,69 @@
 	return 0;
 }
 
-/* Copy files from source_dir to fs */
+#ifdef _WIN32
+static int scandir(const char *dir_name, struct dirent ***name_list,
+		   int (*filter)(const struct dirent*),
+		   int (*compar)(const struct dirent**, const struct dirent**)) {
+	DIR *dir;
+	struct dirent *dent;
+	struct dirent **temp_list = NULL;
+	size_t temp_list_size = 0; // unit: num of dirent
+	size_t num_dent = 0;
+
+	dir = opendir(dir_name);
+	if (dir == NULL) {
+		return -1;
+	}
+
+	while ((dent = readdir(dir))) {
+		if (filter != NULL && !(*filter)(dent))
+			continue;
+
+		// re-allocate the list
+		if (num_dent == temp_list_size) {
+			size_t new_list_size = temp_list_size + 32;
+			struct dirent **new_list = (struct dirent**)realloc(
+				temp_list, new_list_size * sizeof(struct dirent*));
+			if (new_list == NULL) {
+				goto out;
+			}
+			temp_list_size = new_list_size;
+			temp_list = new_list;
+		}
+		// add the copy of dirent to the list
+		temp_list[num_dent] = (struct dirent*)malloc((dent->d_reclen + 3) & ~3);
+		memcpy(temp_list[num_dent], dent, dent->d_reclen);
+		num_dent++;
+	}
+
+	if (compar != NULL) {
+		qsort(temp_list, num_dent, sizeof(struct dirent*),
+		      (int (*)(const void*, const void*))compar);
+	}
+
+        // release the temp list
+	*name_list = temp_list;
+	temp_list = NULL;
+
+out:
+	if (temp_list != NULL) {
+		while (num_dent > 0) {
+			free(temp_list[--num_dent]);
+		}
+		free(temp_list);
+		num_dent = -1;
+	}
+	closedir(dir);
+	return num_dent;
+}
+
+static int alphasort(const struct dirent **a, const struct dirent **b) {
+	return strcoll((*a)->d_name, (*b)->d_name);
+}
+#endif
+
+/* Copy files from source_dir to fs in alphabetical order */
 static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
 			       const char *source_dir, ext2_ino_t root,
 			       struct hdlinks_s *hdlinks,
@@ -722,8 +785,7 @@
 			       struct fs_ops_callbacks *fs_callbacks)
 {
 	const char	*name;
-	DIR		*dh;
-	struct dirent	*dent;
+	struct dirent	**dent;
 	struct stat	st;
 	char		*ln_target = NULL;
 	unsigned int	save_inode;
@@ -732,6 +794,7 @@
 	int		read_cnt;
 	int		hdlink;
 	size_t		cur_dir_path_len;
+	int		i, num_dents;
 
 	if (chdir(source_dir) < 0) {
 		retval = errno;
@@ -741,24 +804,25 @@
 		return retval;
 	}
 
-	if (!(dh = opendir("."))) {
+	num_dents = scandir(".", &dent, NULL, alphasort);
+
+	if (num_dents < 0) {
 		retval = errno;
 		com_err(__func__, retval,
-			_("while opening directory \"%s\""), source_dir);
+			_("while scanning directory \"%s\""), source_dir);
 		return retval;
 	}
 
-	while ((dent = readdir(dh))) {
-		if ((!strcmp(dent->d_name, ".")) ||
-		    (!strcmp(dent->d_name, "..")))
+	for (i = 0; i < num_dents; free(dent[i]), i++) {
+		name = dent[i]->d_name;
+		if ((!strcmp(name, ".")) || (!strcmp(name, "..")))
 			continue;
-		if (lstat(dent->d_name, &st)) {
+		if (lstat(name, &st)) {
 			retval = errno;
 			com_err(__func__, retval, _("while lstat \"%s\""),
-				dent->d_name);
+				name);
 			goto out;
 		}
-		name = dent->d_name;
 
 		/* Check for hardlinks */
 		save_inode = 0;
@@ -950,7 +1014,8 @@
 	}
 
 out:
-	closedir(dh);
+	for (; i < num_dents; free(dent[i]), i++);
+	free(dent);
 	return retval;
 }