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: I44146704572c314e1d6cfca7ce918efa7fb92a7a
diff --git a/ext4_utils/ext2simg.c b/ext4_utils/ext2simg.c
index 9332bad..d5fc24f 100644
--- a/ext4_utils/ext2simg.c
+++ b/ext4_utils/ext2simg.c
@@ -169,7 +169,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 +211,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, 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 3d5895e..0016b65 100644
--- a/ext4_utils/ext4_utils.c
+++ b/ext4_utils/ext4_utils.c
@@ -137,11 +137,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)
@@ -446,15 +446,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__)
@@ -464,22 +460,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;
 
@@ -489,7 +483,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 bb9c09e..033e6b7 100644
--- a/ext4_utils/ext4_utils.h
+++ b/ext4_utils/ext4_utils.h
@@ -151,7 +151,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);
@@ -160,7 +160,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 dbffc8d..1c7cb9d 100644
--- a/ext4_utils/make_ext4fs.c
+++ b/ext4_utils/make_ext4fs.c
@@ -23,6 +23,7 @@
 #include "backed_block.h"
 
 #include <dirent.h>
+#include <fcntl.h>
 #include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -252,27 +253,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, 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)
@@ -366,7 +380,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 d616c6d..b83f57e 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>
@@ -49,6 +50,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 +142,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, 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 d7cf91b..eae7e32 100644
--- a/ext4_utils/output_file.c
+++ b/ext4_utils/output_file.c
@@ -20,12 +20,13 @@
 #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 <sys/mman.h>
 #include <unistd.h>
-#include <fcntl.h>
 
 #include <zlib.h>
 
@@ -48,6 +49,7 @@
 struct output_file {
 	int fd;
 	gzFile gz_fd;
+	bool close_fd;
 	int sparse;
 	u64 cur_out_ptr;
 	u32 chunk_cnt;
@@ -85,7 +87,9 @@
 
 static void file_close(struct output_file *out)
 {
-	close(out->fd);
+	if (out->close_fd) {
+		close(out->fd);
+	}
 }
 
 
@@ -343,7 +347,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;
@@ -362,25 +366,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, 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;
@@ -407,6 +403,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, 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,