add make_ext4fs to the libext4_utils

Move the bulk of make_ext4fs into libext4_utils, leaving a main() that
does only option parsing.  Add reset functionality so that
make_ext4fs() can be called multiple times within a process.

Change-Id: Ia09a2385eab32bf3ca9eb9257c4f9df2c85e55be
diff --git a/ext4_utils/Android.mk b/ext4_utils/Android.mk
index 5e0a73f..d8a20f9 100644
--- a/ext4_utils/Android.mk
+++ b/ext4_utils/Android.mk
@@ -4,6 +4,7 @@
 include $(CLEAR_VARS)
 
 libext4_utils_src_files := \
+	make_ext4fs.c \
         ext4_utils.c \
         allocate.c \
         backed_block.c \
@@ -45,7 +46,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := make_ext4fs.c
+LOCAL_SRC_FILES := make_ext4fs_main.c
 LOCAL_MODULE := make_ext4fs
 LOCAL_MODULE_TAGS := optional
 LOCAL_SHARED_LIBRARIES += libext4_utils libz
@@ -54,7 +55,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := make_ext4fs.c
+LOCAL_SRC_FILES := make_ext4fs_main.c
 LOCAL_MODULE := make_ext4fs
 LOCAL_STATIC_LIBRARIES += libext4_utils libz
 
diff --git a/ext4_utils/backed_block.c b/ext4_utils/backed_block.c
index 6fb4870..5fa6943 100644
--- a/ext4_utils/backed_block.c
+++ b/ext4_utils/backed_block.c
@@ -122,12 +122,23 @@
 /* Frees the memory used by the linked list of data blocks */
 void free_data_blocks()
 {
+        if (!data_blocks) return;
 	struct data_block *db = data_blocks;
 	while (db) {
 		struct data_block *next = db->next;
 		free((void*)db->filename);
-		free((void*)db->data);
+
+                // There used to be a free() of db->data here, but it
+		// made the function crash since queue_data_block() is
+		// sometimes passed pointers it can't take ownership of
+		// (like a pointer into the middle of an allocated
+		// block).  It's not clear what the queue_data_block
+		// contract is supposed to be, but we'd rather leak
+		// memory than crash.
+
 		free(db);
 		db = next;
 	}
+        data_blocks = NULL;
+        last_used = NULL;
 }
diff --git a/ext4_utils/make_ext4fs.c b/ext4_utils/make_ext4fs.c
index 347943b..4840917 100644
--- a/ext4_utils/make_ext4fs.c
+++ b/ext4_utils/make_ext4fs.c
@@ -203,88 +203,26 @@
 	return DIV_ROUND_UP(info.inodes, block_groups);
 }
 
-static void usage(char *path)
-{
-	fprintf(stderr, "%s [ -l <len> ] [ -j <journal size> ] [ -b <block_size> ]\n", basename(path));
-	fprintf(stderr, "    [ -g <blocks per group> ] [ -i <inodes> ] [ -I <inode size> ]\n");
-	fprintf(stderr, "    [ -L <label> ] [ -f ] [ -a <android mountpoint> ]\n");
-	fprintf(stderr, "    <filename> [<directory>]\n");
+void reset_ext4fs_info() {
+    // Reset all the global data structures used by make_ext4fs so it
+    // can be called again.
+    memset(&info, 0, sizeof(info));
+    memset(&aux_info, 0, sizeof(aux_info));
+    free_data_blocks();
 }
 
-int main(int argc, char **argv)
+int make_ext4fs(const char *filename, const char *directory,
+                char *mountpoint, int android, int gzip)
 {
-	int opt;
-	const char *filename = NULL;
-	const char *directory = NULL;
-	char *mountpoint = "";
-	int android = 0;
-	int gzip = 0;
-	u32 root_inode_num;
-	u16 root_mode;
-
-	while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:fz")) != -1) {
-		switch (opt) {
-		case 'l':
-			info.len = parse_num(optarg);
-			break;
-		case 'j':
-			info.journal_blocks = parse_num(optarg);
-			break;
-		case 'b':
-			info.block_size = parse_num(optarg);
-			break;
-		case 'g':
-			info.blocks_per_group = parse_num(optarg);
-			break;
-		case 'i':
-			info.inodes = parse_num(optarg);
-			break;
-		case 'I':
-			info.inode_size = parse_num(optarg);
-			break;
-		case 'L':
-			info.label = optarg;
-			break;
-		case 'f':
-			force = 1;
-			break;
-		case 'a':
-			android = 1;
-			mountpoint = optarg;
-			break;
-		case 'z':
-			gzip = 1;
-			break;
-		default: /* '?' */
-			usage(argv[0]);
-			exit(EXIT_FAILURE);
-		}
-	}
-
-	if (optind >= argc) {
-		fprintf(stderr, "Expected filename after options\n");
-		usage(argv[0]);
-		exit(EXIT_FAILURE);
-	}
-
-	filename = argv[optind++];
-
-	if (optind < argc)
-		directory = argv[optind++];
-
-	if (optind < argc) {
-		fprintf(stderr, "Unexpected argument: %s\n", argv[optind]);
-		usage(argv[0]);
-		exit(EXIT_FAILURE);
-	}
+        u32 root_inode_num;
+        u16 root_mode;
 
 	if (info.len == 0)
 		info.len = get_file_size(filename);
 
 	if (info.len <= 0) {
 		fprintf(stderr, "Need size of filesystem\n");
-		usage(argv[0]);
-		exit(EXIT_FAILURE);
+                return EXIT_FAILURE;
 	}
 
 	if (info.journal_blocks > 0)
@@ -350,7 +288,7 @@
 		root_inode_num = build_directory_structure(directory, mountpoint, 0, android);
 	else
 		root_inode_num = build_default_directory_structure();
-	
+
 	root_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
 	inode_set_permissions(root_inode_num, root_mode, 0, 0);
 
diff --git a/ext4_utils/make_ext4fs.h b/ext4_utils/make_ext4fs.h
index 11fdf77..4045e6a 100644
--- a/ext4_utils/make_ext4fs.h
+++ b/ext4_utils/make_ext4fs.h
@@ -20,4 +20,8 @@
 #include "ext4_utils.h"
 #include "ext4.h"
 
+void reset_ext4fs_info();
+int make_ext4fs(const char *filename, const char *directory,
+                char *mountpoint, int android, int gzip);
+
 #endif
diff --git a/ext4_utils/make_ext4fs_main.c b/ext4_utils/make_ext4fs_main.c
new file mode 100644
index 0000000..b11d9fe
--- /dev/null
+++ b/ext4_utils/make_ext4fs_main.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <libgen.h>
+
+#if defined(__linux__)
+#include <linux/fs.h>
+#elif defined(__APPLE__) && defined(__MACH__)
+#include <sys/disk.h>
+#endif
+
+#include "make_ext4fs.h"
+
+extern struct fs_info info;
+
+
+static void usage(char *path)
+{
+        fprintf(stderr, "%s [ -l <len> ] [ -j <journal size> ] [ -b <block_size> ]\n", basename(path));
+        fprintf(stderr, "    [ -g <blocks per group> ] [ -i <inodes> ] [ -I <inode size> ]\n");
+        fprintf(stderr, "    [ -L <label> ] [ -f ] [ -a <android mountpoint> ]\n");
+        fprintf(stderr, "    <filename> [<directory>]\n");
+}
+
+int main(int argc, char **argv)
+{
+        int opt;
+        const char *filename = NULL;
+        const char *directory = NULL;
+        char *mountpoint = "";
+        int android = 0;
+        int gzip = 0;
+
+        while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:fz")) != -1) {
+                switch (opt) {
+                case 'l':
+                        info.len = parse_num(optarg);
+                        break;
+                case 'j':
+                        info.journal_blocks = parse_num(optarg);
+                        break;
+                case 'b':
+                        info.block_size = parse_num(optarg);
+                        break;
+                case 'g':
+                        info.blocks_per_group = parse_num(optarg);
+                        break;
+                case 'i':
+                        info.inodes = parse_num(optarg);
+                        break;
+                case 'I':
+                        info.inode_size = parse_num(optarg);
+                        break;
+                case 'L':
+                        info.label = optarg;
+                        break;
+                case 'f':
+                        force = 1;
+                        break;
+                case 'a':
+                        android = 1;
+                        mountpoint = optarg;
+                        break;
+                case 'z':
+                        gzip = 1;
+                        break;
+                default: /* '?' */
+                        usage(argv[0]);
+                        exit(EXIT_FAILURE);
+                }
+        }
+
+        if (optind >= argc) {
+                fprintf(stderr, "Expected filename after options\n");
+                usage(argv[0]);
+                exit(EXIT_FAILURE);
+        }
+
+        filename = argv[optind++];
+
+        if (optind < argc)
+                directory = argv[optind++];
+
+        if (optind < argc) {
+                fprintf(stderr, "Unexpected argument: %s\n", argv[optind]);
+                usage(argv[0]);
+                exit(EXIT_FAILURE);
+        }
+
+        return make_ext4fs(filename, directory, mountpoint, android, gzip);
+}