libsparse: make API sane
Replaces the libsparse API with a sane one based on an opaque
pointer.
Change-Id: I93bc9cf9a6b912a993ef554dbe6ffe2f0f723383
diff --git a/ext4_utils/allocate.c b/ext4_utils/allocate.c
index dfc3f16..adf91ba 100644
--- a/ext4_utils/allocate.c
+++ b/ext4_utils/allocate.c
@@ -155,8 +155,8 @@
if (bg->inode_table == NULL)
critical_error_errno("calloc");
- queue_data_block(bg->inode_table, aux_info.inode_table_blocks
- * info.block_size, block);
+ sparse_file_add_data(info.sparse_file, bg->inode_table,
+ aux_info.inode_table_blocks * info.block_size, block);
}
void init_unused_inode_tables(void)
@@ -171,9 +171,10 @@
block = bg->first_block + 2;
if (bg->has_superblock)
block += aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks + 1;
- queue_fill_block(0, aux_info.inode_table_blocks * info.block_size, block);
- }
- }
+ sparse_file_add_fill(info.sparse_file, 0,
+ aux_info.inode_table_blocks * info.block_size, block);
+ }
+ }
}
static int bitmap_set_bit(u8 *bitmap, u32 bit)
@@ -288,7 +289,8 @@
u32 block = bg->first_block;
if (bg->has_superblock)
block += 1 + aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks;
- queue_data_block(bg->bitmaps, 2 * info.block_size, block);
+ sparse_file_add_data(info.sparse_file, bg->bitmaps, 2 * info.block_size,
+ block);
bg->data_blocks_used = 0;
bg->free_blocks = info.blocks_per_group;
diff --git a/ext4_utils/ext2simg.c b/ext4_utils/ext2simg.c
index e8f26c6..f4b6c93 100644
--- a/ext4_utils/ext2simg.c
+++ b/ext4_utils/ext2simg.c
@@ -14,11 +14,8 @@
* limitations under the License.
*/
-#include <sparse/sparse.h>
-
-#include "ext4_utils.h"
-#include "make_ext4fs.h"
-#include "allocate.h"
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE64_SOURCE 1
#include <sys/types.h>
#include <sys/stat.h>
@@ -28,6 +25,16 @@
#include <libgen.h>
#include <unistd.h>
+#include <sparse/sparse.h>
+
+#include "ext4_utils.h"
+#include "make_ext4fs.h"
+#include "allocate.h"
+
+#if defined(__APPLE__) && defined(__MACH__)
+#define off64_t off_t
+#endif
+
#ifndef USE_MINGW /* O_BINARY is windows-specific flag */
#define O_BINARY 0
#endif
@@ -120,7 +127,7 @@
critical_error("failed to allocate block bitmap");
if (aux_info.first_data_block > 0)
- queue_data_file(filename, 0,
+ sparse_file_add_file(info.sparse_file, filename, 0,
info.block_size * aux_info.first_data_block, 0);
for (i = 0; i < aux_info.groups; i++) {
@@ -145,7 +152,8 @@
u32 start_block = first_block + start_contiguous_block;
u32 len_blocks = block - start_contiguous_block;
- queue_data_file(filename, (u64)info.block_size * start_block,
+ sparse_file_add_file(info.sparse_file, filename,
+ (u64)info.block_size * start_block,
info.block_size * len_blocks, start_block);
start_contiguous_block = -1;
}
@@ -158,7 +166,8 @@
if (start_contiguous_block >= 0) {
u32 start_block = first_block + start_contiguous_block;
u32 len_blocks = last_block - start_contiguous_block;
- queue_data_file(filename, (u64)info.block_size * start_block,
+ sparse_file_add_file(info.sparse_file, filename,
+ (u64)info.block_size * start_block,
info.block_size * len_blocks, start_block);
}
}
@@ -222,6 +231,8 @@
read_ext(infd);
+ info.sparse_file = sparse_file_new(info.block_size, info.len);
+
build_sparse_ext(infd, in);
close(infd);
@@ -239,5 +250,7 @@
write_ext4_image(outfd, gzip, sparse, crc);
close(outfd);
+ sparse_file_destroy(info.sparse_file);
+
return 0;
}
diff --git a/ext4_utils/ext4_utils.c b/ext4_utils/ext4_utils.c
index a210281..43b4480 100644
--- a/ext4_utils/ext4_utils.c
+++ b/ext4_utils/ext4_utils.c
@@ -83,7 +83,7 @@
/* Write the filesystem image to a file */
void write_ext4_image(int fd, int gz, int sparse, int crc)
{
- write_sparse_image(fd, gz, sparse, crc, info.block_size, info.len);
+ sparse_file_write(info.sparse_file, fd, gz, sparse, crc);
}
/* Compute the rest of the parameters of the filesystem from the basic info */
@@ -226,10 +226,10 @@
memcpy(aux_info.backup_sb[i], sb, info.block_size);
/* Update the block group nr of this backup superblock */
aux_info.backup_sb[i]->s_block_group_nr = i;
- queue_data_block((u8 *)aux_info.backup_sb[i],
- info.block_size, group_start_block);
+ sparse_file_add_data(info.sparse_file, aux_info.backup_sb[i],
+ info.block_size, group_start_block);
}
- queue_data_block((u8 *)aux_info.bg_desc,
+ sparse_file_add_data(info.sparse_file, aux_info.bg_desc,
aux_info.bg_desc_blocks * info.block_size,
group_start_block + 1);
header_size = 1 + aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks;
@@ -255,9 +255,9 @@
if (info.block_size > 1024) {
u8 *buf = calloc(info.block_size, 1);
memcpy(buf + 1024, (u8*)aux_info.sb, 1024);
- queue_data_block(buf, info.block_size, 0);
+ sparse_file_add_data(info.sparse_file, buf, info.block_size, 0);
} else {
- queue_data_block((u8*)aux_info.sb, 1024, 1);
+ sparse_file_add_data(info.sparse_file, aux_info.sb, 1024, 1);
}
}
diff --git a/ext4_utils/ext4_utils.h b/ext4_utils/ext4_utils.h
index 9ee6929..cad2eae 100644
--- a/ext4_utils/ext4_utils.h
+++ b/ext4_utils/ext4_utils.h
@@ -119,6 +119,8 @@
u32 bg_desc_reserve_blocks;
const char *label;
u8 no_journal;
+
+ struct sparse_file *sparse_file;
};
struct fs_aux_info {
diff --git a/ext4_utils/extent.c b/ext4_utils/extent.c
index 905a378..948bf41 100644
--- a/ext4_utils/extent.c
+++ b/ext4_utils/extent.c
@@ -43,7 +43,7 @@
len = min(region_len * info.block_size, backing_len);
- queue_data_block(ptr, len, region_block);
+ sparse_file_add_data(info.sparse_file, ptr, len, region_block);
ptr += len;
backing_len -= len;
}
@@ -65,7 +65,8 @@
len = min(region_len * info.block_size, backing_len);
- queue_data_file(filename, offset, len, region_block);
+ sparse_file_add_file(info.sparse_file, filename, offset, len,
+ region_block);
offset += len;
backing_len -= len;
}
@@ -124,7 +125,8 @@
if (!data)
critical_error_errno("calloc");
- queue_data_block(data, info.block_size, extent_block);
+ sparse_file_add_data(info.sparse_file, data, info.block_size,
+ extent_block);
if (((int)(info.block_size - sizeof(struct ext4_extent_header) /
sizeof(struct ext4_extent))) < allocation_len) {
diff --git a/ext4_utils/indirect.c b/ext4_utils/indirect.c
index d0490f2..3d97ec8 100644
--- a/ext4_utils/indirect.c
+++ b/ext4_utils/indirect.c
@@ -46,7 +46,7 @@
len = min(region_len * info.block_size, backing_len);
- queue_data_block(ptr, len, region_block);
+ sparse_file_add_data(info.sparse_file, ptr, len, region_block);
ptr += len;
backing_len -= len;
}
@@ -123,7 +123,8 @@
dind_block[i] = ind_block;
u32 *ind_block_data = calloc(info.block_size, 1);
- queue_data_block((u8*)ind_block_data, info.block_size, ind_block);
+ sparse_file_add_data(info.sparse_file, ind_block_data, info.block_size,
+ ind_block);
int ind_block_len = min((int)aux_info.blocks_per_ind, len);
fill_indirect_block(ind_block_data, ind_block_len, alloc);
@@ -152,7 +153,8 @@
tind_block[i] = dind_block;
u32 *dind_block_data = calloc(info.block_size, 1);
- queue_data_block((u8*)dind_block_data, info.block_size, dind_block);
+ sparse_file_add_data(info.sparse_file, dind_block_data, info.block_size,
+ dind_block);
int dind_block_len = min((int)aux_info.blocks_per_dind, len);
fill_dindirect_block(dind_block_data, dind_block_len, alloc);
@@ -200,7 +202,8 @@
}
u32 *ind_block_data = calloc(info.block_size, 1);
- queue_data_block((u8*)ind_block_data, info.block_size, ind_block);
+ sparse_file_add_data(info.sparse_file, ind_block_data, info.block_size,
+ ind_block);
fill_indirect_block(ind_block_data, len, alloc);
@@ -231,7 +234,8 @@
}
u32 *dind_block_data = calloc(info.block_size, 1);
- queue_data_block((u8*)dind_block_data, info.block_size, dind_block);
+ sparse_file_add_data(info.sparse_file, dind_block_data, info.block_size,
+ dind_block);
fill_dindirect_block(dind_block_data, len, alloc);
@@ -262,7 +266,8 @@
}
u32 *tind_block_data = calloc(info.block_size, 1);
- queue_data_block((u8*)tind_block_data, info.block_size, tind_block);
+ sparse_file_add_data(info.sparse_file, tind_block_data, info.block_size,
+ tind_block);
fill_tindirect_block(tind_block_data, len, alloc);
@@ -441,12 +446,13 @@
u32 *dind_block_data = calloc(info.block_size, 1);
if (!dind_block_data)
critical_error_errno("calloc");
- queue_data_block((u8 *)dind_block_data, info.block_size, dind_block);
+ sparse_file_add_data(info.sparse_file, dind_block_data, info.block_size,
+ dind_block);
u32 *ind_block_data = calloc(info.block_size, info.bg_desc_reserve_blocks);
if (!ind_block_data)
critical_error_errno("calloc");
- queue_data_block((u8 *)ind_block_data,
+ sparse_file_add_data(info.sparse_file, ind_block_data,
info.block_size * info.bg_desc_reserve_blocks,
get_block(alloc, 0));
diff --git a/ext4_utils/libsparse/backed_block.c b/ext4_utils/libsparse/backed_block.c
index 2975b7d..2548138 100644
--- a/ext4_utils/libsparse/backed_block.c
+++ b/ext4_utils/libsparse/backed_block.c
@@ -14,20 +14,18 @@
* limitations under the License.
*/
-#include <sparse/sparse.h>
+#include <stdlib.h>
+#include <string.h>
#include "backed_block.h"
#include "sparse_defs.h"
-#include <stdlib.h>
-#include <string.h>
-
struct data_block {
u32 block;
u32 len;
void *data;
const char *filename;
- off64_t offset;
+ int64_t offset;
struct data_block *next;
u32 fill_val;
u8 fill;
@@ -113,7 +111,7 @@
}
/* Queues a chunk of a file on disk to be written to the specified data blocks */
-void queue_data_file(const char *filename, off64_t offset, unsigned int len,
+void queue_data_file(const char *filename, int64_t offset, unsigned int len,
unsigned int block)
{
struct data_block *db = malloc(sizeof(struct data_block));
diff --git a/ext4_utils/libsparse/backed_block.h b/ext4_utils/libsparse/backed_block.h
index bcacc55..7b7c90a 100644
--- a/ext4_utils/libsparse/backed_block.h
+++ b/ext4_utils/libsparse/backed_block.h
@@ -19,14 +19,21 @@
#include <sparse/sparse.h>
-typedef void (*data_block_callback_t)(void *priv, off64_t off, void *data, int len);
-typedef void (*data_block_fill_callback_t)(void *priv, off64_t off, unsigned int fill_val, int len);
-typedef void (*data_block_file_callback_t)(void *priv, off64_t off,
- const char *file, off64_t offset,
+typedef void (*data_block_callback_t)(void *priv, int64_t off, void *data, int len);
+typedef void (*data_block_fill_callback_t)(void *priv, int64_t off, unsigned int fill_val, int len);
+typedef void (*data_block_file_callback_t)(void *priv, int64_t off,
+ const char *file, int64_t offset,
int len);
void for_each_data_block(data_block_callback_t data_func,
data_block_file_callback_t file_func,
data_block_fill_callback_t fill_func, void *priv, unsigned int);
+void queue_data_block(void *data, unsigned int len, unsigned int block);
+void queue_fill_block(unsigned int fill_val, unsigned int len, unsigned int block);
+void queue_data_file(const char *filename, int64_t offset, unsigned int len,
+ unsigned int block);
+
+void free_data_blocks();
+
#endif
diff --git a/ext4_utils/libsparse/include/sparse/sparse.h b/ext4_utils/libsparse/include/sparse/sparse.h
index 1109374..db06884 100644
--- a/ext4_utils/libsparse/include/sparse/sparse.h
+++ b/ext4_utils/libsparse/include/sparse/sparse.h
@@ -17,20 +17,118 @@
#ifndef _LIBSPARSE_SPARSE_H_
#define _LIBSPARSE_SPARSE_H_
-#define _FILE_OFFSET_BITS 64
-#define _LARGEFILE64_SOURCE 1
-#include <sys/types.h>
-#include <unistd.h>
+#include <stdbool.h>
+#include <stdint.h>
-#if defined(__APPLE__) && defined(__MACH__)
-#define off64_t off_t
-#endif
+struct sparse_file;
-void write_sparse_image(int fd, int gz, int sparse, int crc, unsigned int block_size, off64_t len);
-void queue_data_block(void *data, unsigned int len, unsigned int block);
-void queue_fill_block(unsigned int fill_val, unsigned int len, unsigned int block);
-void queue_data_file(const char *filename, off64_t offset, unsigned int len,
+/**
+ * sparse_file_new - create a new sparse file cookie
+ *
+ * @block_size - minimum size of a chunk
+ * @len - size of the expanded sparse file.
+ *
+ * Creates a new sparse_file cookie that can be used to associate data
+ * blocks. Can later be written to a file with a variety of options.
+ * block_size specifies the minimum size of a chunk in the file. The maximum
+ * size of the file is 2**32 * block_size (16TB for 4k block size).
+ *
+ * Returns the sparse file cookie, or NULL on error.
+ */
+struct sparse_file *sparse_file_new(unsigned int block_size, int64_t len);
+
+/**
+ * sparse_file_destroy - destroy a sparse file cookie
+ *
+ * @s - sparse file cookie
+ *
+ * Destroys a sparse file cookie. After destroy, all memory passed in to
+ * sparse_file_add_data can be freed by the caller
+ */
+void sparse_file_destroy(struct sparse_file *s);
+
+/**
+ * sparse_file_add_data - associate a data chunk with a sparse file
+ *
+ * @s - sparse file cookie
+ * @data - pointer to data block
+ * @len - length of the data block
+ * @block - offset in blocks into the sparse file to place the data chunk
+ *
+ * Associates a data chunk with a sparse file cookie. The region
+ * [block * block_size : block * block_size + len) must not already be used in
+ * the sparse file. If len is not a multiple of the block size the data
+ * will be padded with zeros.
+ *
+ * The data pointer must remain valid until the sparse file is closed or the
+ * data block is removed from the sparse file.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+int sparse_file_add_data(struct sparse_file *s,
+ void *data, unsigned int len, unsigned int block);
+
+/**
+ * sparse_file_add_fill - associate a fill chunk with a sparse file
+ *
+ * @s - sparse file cookie
+ * @fill_val - 32 bit fill data
+ * @len - length of the fill block
+ * @block - offset in blocks into the sparse file to place the fill chunk
+ *
+ * Associates a chunk filled with fill_val with a sparse file cookie.
+ * The region [block * block_size : block * block_size + len) must not already
+ * be used in the sparse file. If len is not a multiple of the block size the
+ * data will be padded with zeros.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+int sparse_file_add_fill(struct sparse_file *s,
+ uint32_t fill_val, unsigned int len, unsigned int block);
+
+/**
+ * sparse_file_add_file - associate a chunk of a file with a sparse file
+ *
+ * @s - sparse file cookie
+ * @filename - filename of the file to be copied
+ * @file_offset - offset into the copied file
+ * @len - length of the copied block
+ * @block - offset in blocks into the sparse file to place the file chunk
+ *
+ * Associates a chunk of an existing file with a sparse file cookie.
+ * The region [block * block_size : block * block_size + len) must not already
+ * be used in the sparse file. If len is not a multiple of the block size the
+ * data will be padded with zeros.
+ *
+ * Allows adding large amounts of data to a sparse file without needing to keep
+ * it all mapped. File size is limited by available virtual address space,
+ * exceptionally large files may need to be added in multiple chunks.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+int sparse_file_add_file(struct sparse_file *s,
+ const char *filename, int64_t file_offset, unsigned int len,
unsigned int block);
-void free_data_blocks();
+
+/**
+ * sparse_file_write - write a sparse file to a file
+ *
+ * @s - sparse file cookie
+ * @fd - file descriptor to write to
+ * @gz - write a gzipped file
+ * @sparse - write in the Android sparse file format
+ * @crc - append a crc chunk
+ *
+ * Writes a sparse file to a file. If gz is true, the data will be passed
+ * through zlib. If sparse is true, the file will be written in the Android
+ * sparse file format. If sparse is false, the file will be written by seeking
+ * over unused chunks, producing a smaller file if the filesystem supports
+ * sparse files. If crc is true, the crc of the expanded data will be
+ * calculated and appended in a crc chunk.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse,
+ bool crc);
#endif
diff --git a/ext4_utils/libsparse/output_file.c b/ext4_utils/libsparse/output_file.c
index 6520e63..2c4b557 100644
--- a/ext4_utils/libsparse/output_file.c
+++ b/ext4_utils/libsparse/output_file.c
@@ -14,11 +14,8 @@
* limitations under the License.
*/
-#include <sparse/sparse.h>
-
-#include "output_file.h"
-#include "sparse_format.h"
-#include "sparse_crc32.h"
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE64_SOURCE 1
#include <fcntl.h>
#include <stdbool.h>
@@ -29,6 +26,10 @@
#include <unistd.h>
#include <zlib.h>
+#include "output_file.h"
+#include "sparse_format.h"
+#include "sparse_crc32.h"
+
#ifndef USE_MINGW
#include <sys/mman.h>
#define O_BINARY 0
@@ -38,6 +39,7 @@
#define lseek64 lseek
#define ftruncate64 ftruncate
#define mmap64 mmap
+#define off64_t off_t
#endif
#ifdef __BIONIC__
@@ -55,7 +57,7 @@
#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
struct output_file_ops {
- int (*seek)(struct output_file *, off64_t);
+ int (*seek)(struct output_file *, int64_t);
int (*write)(struct output_file *, u8 *, int);
void (*close)(struct output_file *);
};
@@ -65,16 +67,16 @@
gzFile gz_fd;
bool close_fd;
int sparse;
- off64_t cur_out_ptr;
+ int64_t cur_out_ptr;
u32 chunk_cnt;
u32 crc32;
struct output_file_ops *ops;
int use_crc;
unsigned int block_size;
- off64_t len;
+ int64_t len;
};
-static int file_seek(struct output_file *out, off64_t off)
+static int file_seek(struct output_file *out, int64_t off)
{
off64_t ret;
@@ -115,7 +117,7 @@
.close = file_close,
};
-static int gz_file_seek(struct output_file *out, off64_t off)
+static int gz_file_seek(struct output_file *out, int64_t off)
{
off64_t ret;
@@ -195,7 +197,7 @@
return 0;
}
-static int write_chunk_fill(struct output_file *out, off64_t off, u32 fill_val, int len)
+static int write_chunk_fill(struct output_file *out, int64_t off, u32 fill_val, int len)
{
chunk_header_t chunk_header;
int rnd_up_len, zero_len, count;
@@ -268,7 +270,7 @@
return 0;
}
-static int write_chunk_raw(struct output_file *out, off64_t off, u8 *data, int len)
+static int write_chunk_raw(struct output_file *out, int64_t off, u8 *data, int len)
{
chunk_header_t chunk_header;
int rnd_up_len, zero_len;
@@ -363,7 +365,7 @@
out->ops->close(out);
}
-struct output_file *open_output_fd(int fd, unsigned int block_size, off64_t len,
+struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len,
int gz, int sparse, int chunks, int crc)
{
int ret;
@@ -420,7 +422,7 @@
}
struct output_file *open_output_file(const char *filename,
- unsigned int block_size, off64_t len,
+ unsigned int block_size, int64_t len,
int gz, int sparse, int chunks, int crc)
{
int fd;
@@ -447,7 +449,7 @@
return file;
}
-void pad_output_file(struct output_file *out, off64_t len)
+void pad_output_file(struct output_file *out, int64_t len)
{
int ret;
@@ -484,7 +486,7 @@
}
/* Write a contiguous region of data blocks from a memory buffer */
-void write_data_block(struct output_file *out, off64_t off, void *data, int len)
+void write_data_block(struct output_file *out, int64_t off, void *data, int len)
{
int ret;
@@ -508,7 +510,7 @@
}
/* Write a contiguous region of data blocks with a fill value */
-void write_fill_block(struct output_file *out, off64_t off, unsigned int fill_val, int len)
+void write_fill_block(struct output_file *out, int64_t off, unsigned int fill_val, int len)
{
int ret;
unsigned int i;
@@ -546,11 +548,11 @@
}
/* Write a contiguous region of data blocks from a file */
-void write_data_file(struct output_file *out, off64_t off, const char *file,
- off64_t offset, int len)
+void write_data_file(struct output_file *out, int64_t off, const char *file,
+ int64_t offset, int len)
{
int ret;
- off64_t aligned_offset;
+ int64_t aligned_offset;
int aligned_diff;
int buffer_size;
diff --git a/ext4_utils/libsparse/output_file.h b/ext4_utils/libsparse/output_file.h
index 9e822e3..b12194f 100644
--- a/ext4_utils/libsparse/output_file.h
+++ b/ext4_utils/libsparse/output_file.h
@@ -22,15 +22,15 @@
struct output_file;
struct output_file *open_output_file(const char *filename,
- unsigned int block_size, off64_t len,
+ unsigned int block_size, int64_t len,
int gz, int sparse, int chunks, int crc);
-struct output_file *open_output_fd(int fd, unsigned int block_size, off64_t len,
+struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len,
int gz, int sparse, int chunks, int crc);
-void write_data_block(struct output_file *out, off64_t off, void *data, int len);
-void write_fill_block(struct output_file *out, off64_t off, unsigned int fill_val, int len);
-void write_data_file(struct output_file *out, off64_t off, const char *file,
- off64_t offset, int len);
-void pad_output_file(struct output_file *out, off64_t len);
+void write_data_block(struct output_file *out, int64_t off, void *data, int len);
+void write_fill_block(struct output_file *out, int64_t off, unsigned int fill_val, int len);
+void write_data_file(struct output_file *out, int64_t off, const char *file,
+ int64_t offset, int len);
+void pad_output_file(struct output_file *out, int64_t len);
void close_output_file(struct output_file *out);
#endif
diff --git a/ext4_utils/libsparse/sparse.c b/ext4_utils/libsparse/sparse.c
index 2c91a8e..d6f5561 100644
--- a/ext4_utils/libsparse/sparse.c
+++ b/ext4_utils/libsparse/sparse.c
@@ -14,17 +14,70 @@
* limitations under the License.
*/
+#include <stdlib.h>
+
+#include <sparse/sparse.h>
+
+#include "sparse_file.h"
+
#include "output_file.h"
#include "backed_block.h"
#include "sparse_defs.h"
+
+struct sparse_file *sparse_file_new(unsigned int block_size, int64_t len)
+{
+ struct sparse_file *s = calloc(sizeof(struct sparse_file), 1);
+ if (!s) {
+ return NULL;
+ }
+
+ /* TODO: allocate backed block list */
+
+ s->block_size = block_size;
+ s->len = len;
+
+ return s;
+}
+
+void sparse_file_destroy(struct sparse_file *s)
+{
+ free_data_blocks();
+ free(s);
+}
+
+int sparse_file_add_data(struct sparse_file *s,
+ void *data, unsigned int len, unsigned int block)
+{
+ queue_data_block(data, len, block);
+
+ return 0;
+}
+
+int sparse_file_add_fill(struct sparse_file *s,
+ uint32_t fill_val, unsigned int len, unsigned int block)
+{
+ queue_fill_block(fill_val, len, block);
+
+ return 0;
+}
+
+int sparse_file_add_file(struct sparse_file *s,
+ const char *filename, int64_t file_offset, unsigned int len,
+ unsigned int block)
+{
+ queue_data_file(filename, file_offset, len, block);
+
+ return 0;
+}
+
struct count_chunks {
unsigned int chunks;
- off64_t cur_ptr;
+ int64_t cur_ptr;
unsigned int block_size;
};
-static void count_data_block(void *priv, off64_t off, void *data, int len)
+static void count_data_block(void *priv, int64_t off, void *data, int len)
{
struct count_chunks *count_chunks = priv;
if (off > count_chunks->cur_ptr)
@@ -33,7 +86,7 @@
count_chunks->chunks++;
}
-static void count_fill_block(void *priv, off64_t off, unsigned int fill_val, int len)
+static void count_fill_block(void *priv, int64_t off, unsigned int fill_val, int len)
{
struct count_chunks *count_chunks = priv;
if (off > count_chunks->cur_ptr)
@@ -42,8 +95,8 @@
count_chunks->chunks++;
}
-static void count_file_block(void *priv, off64_t off, const char *file,
- off64_t offset, int len)
+static void count_file_block(void *priv, int64_t off, const char *file,
+ int64_t offset, int len)
{
struct count_chunks *count_chunks = priv;
if (off > count_chunks->cur_ptr)
@@ -52,7 +105,7 @@
count_chunks->chunks++;
}
-static int count_sparse_chunks(unsigned int block_size, off64_t len)
+static int count_sparse_chunks(unsigned int block_size, int64_t len)
{
struct count_chunks count_chunks = {0, 0, block_size};
@@ -64,35 +117,38 @@
return count_chunks.chunks;
}
-static void ext4_write_data_block(void *priv, off64_t off, void *data, int len)
+static void ext4_write_data_block(void *priv, int64_t off, void *data, int len)
{
write_data_block(priv, off, data, len);
}
-static void ext4_write_fill_block(void *priv, off64_t off, unsigned int fill_val, int len)
+static void ext4_write_fill_block(void *priv, int64_t off, unsigned int fill_val, int len)
{
write_fill_block(priv, off, fill_val, len);
}
-static void ext4_write_data_file(void *priv, off64_t off, const char *file,
- off64_t offset, int len)
+static void ext4_write_data_file(void *priv, int64_t off, const char *file,
+ int64_t offset, int len)
{
write_data_file(priv, off, file, offset, len);
}
-/* Write the filesystem image to a file */
-void write_sparse_image(int fd, int gz, int sparse, int crc, unsigned int block_size, off64_t len)
+int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse,
+ bool crc)
{
- int chunks = count_sparse_chunks(block_size, len);
- struct output_file *out = open_output_fd(fd, block_size, len,
+ int chunks = count_sparse_chunks(s->block_size, s->len);
+ struct output_file *out = open_output_fd(fd, s->block_size, s->len,
gz, sparse, chunks, crc);
if (!out)
- return;
+ return -ENOMEM;
- for_each_data_block(ext4_write_data_block, ext4_write_data_file, ext4_write_fill_block, out, block_size);
+ for_each_data_block(ext4_write_data_block, ext4_write_data_file, ext4_write_fill_block, out, s->block_size);
- pad_output_file(out, len);
+ if (s->len)
+ pad_output_file(out, s->len);
close_output_file(out);
+
+ return 0;
}
diff --git a/ext4_utils/libsparse/sparse_file.h b/ext4_utils/libsparse/sparse_file.h
new file mode 100644
index 0000000..05a78d9
--- /dev/null
+++ b/ext4_utils/libsparse/sparse_file.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef _LIBSPARSE_SPARSE_FILE_H_
+#define _LIBSPARSE_SPARSE_FILE_H_
+
+#include <sparse/sparse.h>
+
+struct sparse_file {
+ unsigned int block_size;
+ int64_t len;
+
+ struct output_file *out;
+};
+
+
+#endif /* _LIBSPARSE_SPARSE_FILE_H_ */
diff --git a/ext4_utils/make_ext4fs.c b/ext4_utils/make_ext4fs.c
index 228c421..be63e27 100644
--- a/ext4_utils/make_ext4fs.c
+++ b/ext4_utils/make_ext4fs.c
@@ -294,7 +294,11 @@
// can be called again.
memset(&info, 0, sizeof(info));
memset(&aux_info, 0, sizeof(aux_info));
- free_data_blocks();
+
+ if (info.sparse_file) {
+ sparse_file_destroy(info.sparse_file);
+ info.sparse_file = NULL;
+ }
}
int make_ext4fs(const char *filename, s64 len,
@@ -393,6 +397,8 @@
printf(" Block groups: %d\n", aux_info.groups);
printf(" Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
+ info.sparse_file = sparse_file_new(info.block_size, info.len);
+
block_allocator_init();
ext4_fill_in_sb();
@@ -462,5 +468,8 @@
write_ext4_image(fd, gzip, sparse, crc);
+ sparse_file_destroy(info.sparse_file);
+ info.sparse_file = NULL;
+
return 0;
}