Pass file descriptor instead of file name

Passing a file descriptor to make_ext4fs_internal() is more flexible.
We can use tmpfile() to create a temporary file.
tmpfile() is better than other solutions because it unlinks the file
right after creating it, so closing fd effectively removes temp file.
Thus we don't have to worry about large temp files accidently left
on the filesystem in case of the program crash.

Change-Id: Iba3758a0e13a898920d30d7fa5da696c22daa2b7
diff --git a/ext4_utils/ext2simg.c b/ext4_utils/ext2simg.c
index 9332bad..1fe085a 100644
--- a/ext4_utils/ext2simg.c
+++ b/ext4_utils/ext2simg.c
@@ -28,6 +28,10 @@
 #include <libgen.h>
 #include <unistd.h>
 
+#ifndef USE_MINGW /* O_BINARY is windows-specific flag */
+#define O_BINARY 0
+#endif
+
 extern struct fs_info info;
 
 static int verbose = 0;
@@ -169,7 +173,7 @@
 	const char *out = NULL;
 	int gzip = 0;
 	int sparse = 1;
-	int fd;
+	int infd, outfd;
 	int crc = 0;
 
 	while ((opt = getopt(argc, argv, "cvzS")) != -1) {
@@ -211,18 +215,29 @@
 		exit(EXIT_FAILURE);
 	}
 
-	fd = open(in, O_RDONLY);
+	infd = open(in, O_RDONLY);
 
-	if (fd < 0)
+	if (infd < 0)
 		critical_error_errno("failed to open input image");
 
-	read_ext(fd);
+	read_ext(infd);
 
-	build_sparse_ext(fd, in);
+	build_sparse_ext(infd, in);
 
-	close(fd);
+	close(infd);
 
-	write_ext4_image(out, gzip, sparse, crc, 0);
+	if (strcmp(out, "-")) {
+		outfd = open(out, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+		if (outfd < 0) {
+			error_errno("open");
+			return EXIT_FAILURE;
+		}
+	} else {
+		outfd = STDOUT_FILENO;
+	}
+
+	write_ext4_image(outfd, gzip, sparse, crc, 0);
+	close(outfd);
 
 	return 0;
 }
diff --git a/ext4_utils/ext4_utils.c b/ext4_utils/ext4_utils.c
index 9bb523f..7f226c8 100644
--- a/ext4_utils/ext4_utils.c
+++ b/ext4_utils/ext4_utils.c
@@ -142,11 +142,11 @@
 }
 
 /* Write the filesystem image to a file */
-void write_ext4_image(const char *filename, int gz, int sparse, int crc,
-		int wipe)
+void write_ext4_image(int fd, int gz, int sparse, int crc, int wipe)
 {
 	int ret = 0;
-	struct output_file *out = open_output_file(filename, gz, sparse,
+
+	struct output_file *out = open_output_fd(fd, gz, sparse,
 	        count_sparse_chunks(), crc, wipe);
 
 	if (!out)
@@ -451,15 +451,11 @@
 	}
 }
 
-static u64 get_block_device_size(const char *filename)
+static u64 get_block_device_size(int fd)
 {
-	int fd = open(filename, O_RDONLY);
 	u64 size = 0;
 	int ret;
 
-	if (fd < 0)
-		return 0;
-
 #if defined(__linux__)
 	ret = ioctl(fd, BLKGETSIZE64, &size);
 #elif defined(__APPLE__) && defined(__MACH__)
@@ -469,22 +465,20 @@
 	return 0;
 #endif
 
-	close(fd);
-
 	if (ret)
 		return 0;
 
 	return size;
 }
 
-u64 get_file_size(const char *filename)
+u64 get_file_size(int fd)
 {
 	struct stat buf;
 	int ret;
 	u64 reserve_len = 0;
 	s64 computed_size;
 
-	ret = stat(filename, &buf);
+	ret = fstat(fd, &buf);
 	if (ret)
 		return 0;
 
@@ -494,7 +488,7 @@
 	if (S_ISREG(buf.st_mode))
 		computed_size = buf.st_size - reserve_len;
 	else if (S_ISBLK(buf.st_mode))
-		computed_size = get_block_device_size(filename) - reserve_len;
+		computed_size = get_block_device_size(fd) - reserve_len;
 	else
 		computed_size = 0;
 
diff --git a/ext4_utils/ext4_utils.h b/ext4_utils/ext4_utils.h
index 5b835ed..1d701d0 100644
--- a/ext4_utils/ext4_utils.h
+++ b/ext4_utils/ext4_utils.h
@@ -153,7 +153,7 @@
 }
 
 int ext4_bg_has_super_block(int bg);
-void write_ext4_image(const char *filename, int gz, int sparse, int crc,
+void write_ext4_image(int fd, int gz, int sparse, int crc,
 		int wipe);
 void ext4_create_fs_aux_info(void);
 void ext4_free_fs_aux_info(void);
@@ -162,7 +162,7 @@
 void ext4_create_journal_inode(void);
 void ext4_update_free(void);
 void ext4_queue_sb(void);
-u64 get_file_size(const char *filename);
+u64 get_file_size(int fd);
 u64 parse_num(const char *arg);
 void ext4_parse_sb(struct ext4_super_block *sb);
 
diff --git a/ext4_utils/make_ext4fs.c b/ext4_utils/make_ext4fs.c
index c11bebb..c6fb14a 100644
--- a/ext4_utils/make_ext4fs.c
+++ b/ext4_utils/make_ext4fs.c
@@ -24,6 +24,7 @@
 
 #include <assert.h>
 #include <dirent.h>
+#include <fcntl.h>
 #include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -59,6 +60,10 @@
 #define S_ISGID 0002000
 #define S_ISVTX 0001000
 
+#else
+
+#define O_BINARY 0
+
 #endif
 
 /* TODO: Not implemented:
@@ -280,27 +285,40 @@
 
 int make_ext4fs(const char *filename, s64 len)
 {
-    reset_ext4fs_info();
-    info.len = len;
-    return make_ext4fs_internal(filename, NULL, NULL, 0, 0, 0, 0, 1, 0);
+	int fd;
+	int status;
+
+	reset_ext4fs_info();
+	info.len = len;
+
+	fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+	if (fd < 0) {
+		error_errno("open");
+		return EXIT_FAILURE;
+	}
+
+	status = make_ext4fs_internal(fd, NULL, NULL, 0, 0, 0, 0, 1, 0);
+	close(fd);
+
+	return status;
 }
 
-int make_ext4fs_internal(const char *filename, const char *directory,
+int make_ext4fs_internal(int fd, const char *directory,
                          char *mountpoint, int android, int gzip, int sparse,
                          int crc, int wipe, int init_itabs)
 {
-        u32 root_inode_num;
-        u16 root_mode;
+	u32 root_inode_num;
+	u16 root_mode;
 
 	if (setjmp(setjmp_env))
 		return EXIT_FAILURE; /* Handle a call to longjmp() */
 
 	if (info.len <= 0)
-		info.len = get_file_size(filename);
+		info.len = get_file_size(fd);
 
 	if (info.len <= 0) {
 		fprintf(stderr, "Need size of filesystem\n");
-                return EXIT_FAILURE;
+		return EXIT_FAILURE;
 	}
 
 	if (info.block_size <= 0)
@@ -400,7 +418,7 @@
 			aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
 			aux_info.sb->s_blocks_count_lo);
 
-	write_ext4_image(filename, gzip, sparse, crc, wipe);
+	write_ext4_image(fd, gzip, sparse, crc, wipe);
 
 	return 0;
 }
diff --git a/ext4_utils/make_ext4fs.h b/ext4_utils/make_ext4fs.h
index 3053d71..bda9c68 100644
--- a/ext4_utils/make_ext4fs.h
+++ b/ext4_utils/make_ext4fs.h
@@ -26,7 +26,7 @@
 
 void reset_ext4fs_info();
 int make_ext4fs(const char *filename, s64 len);
-int make_ext4fs_internal(const char *filename, const char *directory,
+int make_ext4fs_internal(int fd, const char *directory,
                          char *mountpoint, int android, int gzip, int sparse,
                          int crc, int wipe, int init_itabs);
 
diff --git a/ext4_utils/make_ext4fs_main.c b/ext4_utils/make_ext4fs_main.c
index 4e13ffa..d9e1de7 100644
--- a/ext4_utils/make_ext4fs_main.c
+++ b/ext4_utils/make_ext4fs_main.c
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-#include <unistd.h>
+#include <fcntl.h>
 #include <libgen.h>
+#include <unistd.h>
 
 #if defined(__linux__)
 #include <linux/fs.h>
@@ -25,6 +26,10 @@
 
 #include "make_ext4fs.h"
 
+#ifndef USE_MINGW /* O_BINARY is windows-specific flag */
+#define O_BINARY 0
+#endif
+
 extern struct fs_info info;
 
 
@@ -49,6 +54,8 @@
 	int crc = 0;
 	int wipe = 0;
 	int init_itabs = 0;
+	int fd;
+	int exitcode;
 
 	while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:fwzJsct")) != -1) {
 		switch (opt) {
@@ -139,6 +146,19 @@
 		exit(EXIT_FAILURE);
 	}
 
-	return make_ext4fs_internal(filename, directory, mountpoint, android, gzip,
+	if (strcmp(filename, "-")) {
+		fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+		if (fd < 0) {
+			error_errno("open");
+			return EXIT_FAILURE;
+		}
+	} else {
+		fd = STDOUT_FILENO;
+	}
+
+	exitcode = make_ext4fs_internal(fd, directory, mountpoint, android, gzip,
 			sparse, crc, wipe, init_itabs);
+	close(fd);
+
+	return exitcode;
 }
diff --git a/ext4_utils/output_file.c b/ext4_utils/output_file.c
index 7af48de..40655a9 100644
--- a/ext4_utils/output_file.c
+++ b/ext4_utils/output_file.c
@@ -20,11 +20,12 @@
 #include "sparse_crc32.h"
 #include "wipe.h"
 
+#include <fcntl.h>
+#include <stdbool.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
-#include <fcntl.h>
 #include <zlib.h>
 
 #ifndef USE_MINGW
@@ -52,6 +53,7 @@
 struct output_file {
 	int fd;
 	gzFile gz_fd;
+	bool close_fd;
 	int sparse;
 	u64 cur_out_ptr;
 	u32 chunk_cnt;
@@ -89,7 +91,9 @@
 
 static void file_close(struct output_file *out)
 {
-	close(out->fd);
+	if (out->close_fd) {
+		close(out->fd);
+	}
 }
 
 
@@ -347,7 +351,7 @@
 	out->ops->close(out);
 }
 
-struct output_file *open_output_file(const char *filename, int gz, int sparse,
+struct output_file *open_output_fd(int fd, int gz, int sparse,
         int chunks, int crc, int wipe)
 {
 	int ret;
@@ -366,25 +370,17 @@
 
 	if (gz) {
 		out->ops = &gz_file_ops;
-		out->gz_fd = gzopen(filename, "wb9");
+		out->gz_fd = gzdopen(fd, "wb9");
 		if (!out->gz_fd) {
 			error_errno("gzopen");
 			free(out);
 			return NULL;
 		}
 	} else {
-		if (strcmp(filename, "-")) {
-			out->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
-			if (out->fd < 0) {
-				error_errno("open");
-				free(out);
-				return NULL;
-			}
-		} else {
-			out->fd = STDOUT_FILENO;
-		}
+		out->fd = fd;
 		out->ops = &file_ops;
 	}
+	out->close_fd = false;
 	out->sparse = sparse;
 	out->cur_out_ptr = 0ll;
 	out->chunk_cnt = 0;
@@ -411,6 +407,33 @@
 	return out;
 }
 
+struct output_file *open_output_file(const char *filename, int gz, int sparse,
+        int chunks, int crc, int wipe) {
+
+	int fd;
+	struct output_file *file;
+
+	if (strcmp(filename, "-")) {
+		fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+		if (fd < 0) {
+			error_errno("open");
+			return NULL;
+		}
+	} else {
+		fd = STDOUT_FILENO;
+	}
+
+	file = open_output_fd(fd, gz, sparse, chunks, crc, wipe);
+	if (!file) {
+		close(fd);
+		return NULL;
+	}
+
+	file->close_fd = true; // we opened descriptor thus we responsible for closing it
+
+	return file;
+}
+
 void pad_output_file(struct output_file *out, u64 len)
 {
 	int ret;
diff --git a/ext4_utils/output_file.h b/ext4_utils/output_file.h
index b448706..a578c80 100644
--- a/ext4_utils/output_file.h
+++ b/ext4_utils/output_file.h
@@ -21,6 +21,8 @@
 
 struct output_file *open_output_file(const char *filename, int gz, int sparse,
         int chunks, int crc, int wipe);
+struct output_file *open_output_fd(int fd, int gz, int sparse,
+        int chunks, int crc, int wipe);
 void write_data_block(struct output_file *out, u64 off, u8 *data, int len);
 void write_fill_block(struct output_file *out, u64 off, u32 fill_val, int len);
 void write_data_file(struct output_file *out, u64 off, const char *file,