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/backed_block.c b/libsparse/backed_block.c
index b259190..8c3fab0 100644
--- a/libsparse/backed_block.c
+++ b/libsparse/backed_block.c
@@ -35,6 +35,10 @@
 			int64_t offset;
 		} file;
 		struct {
+			int fd;
+			int64_t offset;
+		} fd;
+		struct {
 			uint32_t val;
 		} fill;
 	};
@@ -78,10 +82,20 @@
 	return bb->file.filename;
 }
 
+int backed_block_fd(struct backed_block *bb)
+{
+	assert(bb->type == BACKED_BLOCK_FD);
+	return bb->fd.fd;
+}
+
 int64_t backed_block_file_offset(struct backed_block *bb)
 {
-	assert(bb->type == BACKED_BLOCK_FILE);
-	return bb->file.offset;
+	assert(bb->type == BACKED_BLOCK_FILE || bb->type == BACKED_BLOCK_FD);
+	if (bb->type == BACKED_BLOCK_FILE) {
+		return bb->file.offset;
+	} else { /* bb->type == BACKED_BLOCK_FD */
+		return bb->fd.offset;
+	}
 }
 
 uint32_t backed_block_fill_val(struct backed_block *bb)
@@ -211,3 +225,22 @@
 
 	return queue_bb(bbl, bb);
 }
+
+/* Queues a chunk of a fd to be written to the specified data blocks */
+int backed_block_add_fd(struct backed_block_list *bbl, int fd, int64_t offset,
+		unsigned int len, unsigned int block)
+{
+	struct backed_block *bb = calloc(1, sizeof(struct backed_block));
+	if (bb == NULL) {
+		return -ENOMEM;
+	}
+
+	bb->block = block;
+	bb->len = len;
+	bb->type = BACKED_BLOCK_FD;
+	bb->fd.fd = fd;
+	bb->fd.offset = offset;
+	bb->next = NULL;
+
+	return queue_bb(bbl, bb);
+}