libsparse: add support for including fds

Add sparse_file_add_fd to include all or part of the contents
of an fd in the output file.  Will be useful for re-sparsing files
where fd will point to the input sparse file.

Change-Id: I5d4ab07fb37231e8e9c1912f62a2968c8b0a00ef
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index f911f8c..4193fd1 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -511,38 +511,28 @@
 	return out->sparse_ops->write_fill_chunk(out, len, fill_val);
 }
 
-/* Write a contiguous region of data blocks from a file */
-int write_file_chunk(struct output_file *out, unsigned int len,
-		const char *file, int64_t offset)
+int write_fd_chunk(struct output_file *out, unsigned int len,
+		int fd, int64_t offset)
 {
 	int ret;
 	int64_t aligned_offset;
 	int aligned_diff;
 	int buffer_size;
 
-	int file_fd = open(file, O_RDONLY | O_BINARY);
-	if (file_fd < 0) {
-		return -errno;
-	}
-
 	aligned_offset = offset & ~(4096 - 1);
 	aligned_diff = offset - aligned_offset;
 	buffer_size = len + aligned_diff;
 
 #ifndef USE_MINGW
-	char *data = mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, file_fd,
+	char *data = mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, fd,
 			aligned_offset);
 	if (data == MAP_FAILED) {
-		ret = -errno;
-		close(file_fd);
-		return ret;
+		return -errno;
 	}
 #else
 	char *data = malloc(buffer_size);
 	if (!data) {
-		ret = -errno;
-		close(file_fd);
-		return ret;
+		return -errno;
 	}
 	memset(data, 0, buffer_size);
 #endif
@@ -554,6 +544,23 @@
 #else
 	free(data);
 #endif
+
+	return ret;
+}
+
+/* Write a contiguous region of data blocks from a file */
+int write_file_chunk(struct output_file *out, unsigned int len,
+		const char *file, int64_t offset)
+{
+	int ret;
+
+	int file_fd = open(file, O_RDONLY | O_BINARY);
+	if (file_fd < 0) {
+		return -errno;
+	}
+
+	ret = write_fd_chunk(out, len, file_fd, offset);
+
 	close(file_fd);
 
 	return ret;