From 1e17b313a6257b7b5081e178e81435c09d60378e Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 21 May 2012 16:35:45 -0700 Subject: libsparse: add callback output file type Add a new output file subclass that will call a callback for each block as it is written. Will be used to measure the space used by each sparse block to allow resparsing files. Also add sparse_file_callback, which will write out a sparse file by calling the provided write function. Change-Id: I18707bd9c357b68da319cc07982e93d1c2b2bee2 --- libsparse/output_file.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) (limited to 'libsparse/output_file.c') diff --git a/libsparse/output_file.c b/libsparse/output_file.c index 14b057a9e..dc56149e7 100644 --- a/libsparse/output_file.c +++ b/libsparse/output_file.c @@ -18,6 +18,7 @@ #define _LARGEFILE64_SOURCE 1 #include +#include #include #include #include @@ -112,6 +113,15 @@ struct output_file_normal { #define to_output_file_normal(_o) \ container_of((_o), struct output_file_normal, out) +struct output_file_callback { + struct output_file out; + void *priv; + int (*write)(void *priv, const void *buf, int len); +}; + +#define to_output_file_callback(_o) \ + container_of((_o), struct output_file_callback, out) + static int file_open(struct output_file *out, int fd) { struct output_file_normal *outn = to_output_file_normal(out); @@ -262,6 +272,57 @@ static struct output_file_ops gz_file_ops = { .close = gz_file_close, }; +static int callback_file_open(struct output_file *out, int fd) +{ + return 0; +} + +static int callback_file_skip(struct output_file *out, int64_t off) +{ + struct output_file_callback *outc = to_output_file_callback(out); + int to_write; + int ret; + + while (off > 0) { + to_write = min(off, (int64_t)INT_MAX); + ret = outc->write(outc->priv, NULL, to_write); + if (ret < 0) { + return ret; + } + off -= to_write; + } + + return 0; +} + +static int callback_file_pad(struct output_file *out, int64_t len) +{ + return -1; +} + +static int callback_file_write(struct output_file *out, void *data, int len) +{ + int ret; + struct output_file_callback *outc = to_output_file_callback(out); + + return outc->write(outc->priv, data, len); +} + +static void callback_file_close(struct output_file *out) +{ + struct output_file_callback *outc = to_output_file_callback(out); + + free(outc); +} + +static struct output_file_ops callback_file_ops = { + .open = callback_file_open, + .skip = callback_file_skip, + .pad = callback_file_pad, + .write = callback_file_write, + .close = callback_file_close, +}; + int read_all(int fd, void *buf, size_t len) { size_t total = 0; @@ -577,6 +638,32 @@ static struct output_file *output_file_new_normal(void) return &outn->out; } +struct output_file *open_output_callback(int (*write)(void *, const void *, int), + void *priv, unsigned int block_size, int64_t len, int gz, int sparse, + int chunks, int crc) +{ + int ret; + struct output_file_callback *outc; + + outc = calloc(1, sizeof(struct output_file_callback)); + if (!outc) { + error_errno("malloc struct outc"); + return NULL; + } + + outc->out.ops = &callback_file_ops; + outc->priv = priv; + outc->write = write; + + ret = output_file_init(&outc->out, block_size, len, sparse, chunks, crc); + if (ret < 0) { + free(outc); + return NULL; + } + + return &outc->out; +} + struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len, int gz, int sparse, int chunks, int crc) { -- cgit v1.2.3