summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Cross2012-05-21 18:35:45 -0500
committerColin Cross2012-07-10 00:09:37 -0500
commit1e17b313a6257b7b5081e178e81435c09d60378e (patch)
treeaea5379ca96c99ec14f1c5c8dc202b7b5b36ca47 /libsparse
parentb4cd267db30c152245e6308598e0066d87c5c55d (diff)
downloadplatform-system-core-1e17b313a6257b7b5081e178e81435c09d60378e.tar.gz
platform-system-core-1e17b313a6257b7b5081e178e81435c09d60378e.tar.xz
platform-system-core-1e17b313a6257b7b5081e178e81435c09d60378e.zip
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
Diffstat (limited to 'libsparse')
-rw-r--r--libsparse/include/sparse/sparse.h21
-rw-r--r--libsparse/output_file.c87
-rw-r--r--libsparse/output_file.h3
-rw-r--r--libsparse/sparse.c92
4 files changed, 175 insertions, 28 deletions
diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
index ae5495599..b2152270b 100644
--- a/libsparse/include/sparse/sparse.h
+++ b/libsparse/include/sparse/sparse.h
@@ -158,6 +158,27 @@ int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse,
158 bool crc); 158 bool crc);
159 159
160/** 160/**
161 * sparse_file_callback - call a callback for blocks in sparse file
162 *
163 * @s - sparse file cookie
164 * @sparse - write in the Android sparse file format
165 * @crc - append a crc chunk
166 * @write - function to call for each block
167 * @priv - value that will be passed as the first argument to write
168 *
169 * Writes a sparse file by calling a callback function. If sparse is true, the
170 * file will be written in the Android sparse file format. If crc is true, the
171 * crc of the expanded data will be calculated and appended in a crc chunk.
172 * The callback 'write' will be called with data and length for each data,
173 * and with data==NULL to skip over a region (only used for non-sparse format).
174 * The callback should return negative on error, 0 on success.
175 *
176 * Returns 0 on success, negative errno on error.
177 */
178int sparse_file_callback(struct sparse_file *s, bool sparse, bool crc,
179 int (*write)(void *priv, const void *data, int len), void *priv);
180
181/**
161 * sparse_file_read - read a file into a sparse file cookie 182 * sparse_file_read - read a file into a sparse file cookie
162 * 183 *
163 * @s - sparse file cookie 184 * @s - sparse file cookie
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 @@
18#define _LARGEFILE64_SOURCE 1 18#define _LARGEFILE64_SOURCE 1
19 19
20#include <fcntl.h> 20#include <fcntl.h>
21#include <limits.h>
21#include <stdbool.h> 22#include <stdbool.h>
22#include <stddef.h> 23#include <stddef.h>
23#include <stdlib.h> 24#include <stdlib.h>
@@ -112,6 +113,15 @@ struct output_file_normal {
112#define to_output_file_normal(_o) \ 113#define to_output_file_normal(_o) \
113 container_of((_o), struct output_file_normal, out) 114 container_of((_o), struct output_file_normal, out)
114 115
116struct output_file_callback {
117 struct output_file out;
118 void *priv;
119 int (*write)(void *priv, const void *buf, int len);
120};
121
122#define to_output_file_callback(_o) \
123 container_of((_o), struct output_file_callback, out)
124
115static int file_open(struct output_file *out, int fd) 125static int file_open(struct output_file *out, int fd)
116{ 126{
117 struct output_file_normal *outn = to_output_file_normal(out); 127 struct output_file_normal *outn = to_output_file_normal(out);
@@ -262,6 +272,57 @@ static struct output_file_ops gz_file_ops = {
262 .close = gz_file_close, 272 .close = gz_file_close,
263}; 273};
264 274
275static int callback_file_open(struct output_file *out, int fd)
276{
277 return 0;
278}
279
280static int callback_file_skip(struct output_file *out, int64_t off)
281{
282 struct output_file_callback *outc = to_output_file_callback(out);
283 int to_write;
284 int ret;
285
286 while (off > 0) {
287 to_write = min(off, (int64_t)INT_MAX);
288 ret = outc->write(outc->priv, NULL, to_write);
289 if (ret < 0) {
290 return ret;
291 }
292 off -= to_write;
293 }
294
295 return 0;
296}
297
298static int callback_file_pad(struct output_file *out, int64_t len)
299{
300 return -1;
301}
302
303static int callback_file_write(struct output_file *out, void *data, int len)
304{
305 int ret;
306 struct output_file_callback *outc = to_output_file_callback(out);
307
308 return outc->write(outc->priv, data, len);
309}
310
311static void callback_file_close(struct output_file *out)
312{
313 struct output_file_callback *outc = to_output_file_callback(out);
314
315 free(outc);
316}
317
318static struct output_file_ops callback_file_ops = {
319 .open = callback_file_open,
320 .skip = callback_file_skip,
321 .pad = callback_file_pad,
322 .write = callback_file_write,
323 .close = callback_file_close,
324};
325
265int read_all(int fd, void *buf, size_t len) 326int read_all(int fd, void *buf, size_t len)
266{ 327{
267 size_t total = 0; 328 size_t total = 0;
@@ -577,6 +638,32 @@ static struct output_file *output_file_new_normal(void)
577 return &outn->out; 638 return &outn->out;
578} 639}
579 640
641struct output_file *open_output_callback(int (*write)(void *, const void *, int),
642 void *priv, unsigned int block_size, int64_t len, int gz, int sparse,
643 int chunks, int crc)
644{
645 int ret;
646 struct output_file_callback *outc;
647
648 outc = calloc(1, sizeof(struct output_file_callback));
649 if (!outc) {
650 error_errno("malloc struct outc");
651 return NULL;
652 }
653
654 outc->out.ops = &callback_file_ops;
655 outc->priv = priv;
656 outc->write = write;
657
658 ret = output_file_init(&outc->out, block_size, len, sparse, chunks, crc);
659 if (ret < 0) {
660 free(outc);
661 return NULL;
662 }
663
664 return &outc->out;
665}
666
580struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len, 667struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len,
581 int gz, int sparse, int chunks, int crc) 668 int gz, int sparse, int chunks, int crc)
582{ 669{
diff --git a/libsparse/output_file.h b/libsparse/output_file.h
index 24496f7d4..7a9fa2434 100644
--- a/libsparse/output_file.h
+++ b/libsparse/output_file.h
@@ -23,6 +23,9 @@ struct output_file;
23 23
24struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len, 24struct output_file *open_output_fd(int fd, unsigned int block_size, int64_t len,
25 int gz, int sparse, int chunks, int crc); 25 int gz, int sparse, int chunks, int crc);
26struct output_file *open_output_callback(int (*write)(void *, const void *, int),
27 void *priv, unsigned int block_size, int64_t len, int gz, int sparse,
28 int chunks, int crc);
26int write_data_chunk(struct output_file *out, unsigned int len, void *data); 29int write_data_chunk(struct output_file *out, unsigned int len, void *data);
27int write_fill_chunk(struct output_file *out, unsigned int len, 30int write_fill_chunk(struct output_file *out, unsigned int len,
28 uint32_t fill_val); 31 uint32_t fill_val);
diff --git a/libsparse/sparse.c b/libsparse/sparse.c
index d778e1dc6..c560ec93c 100644
--- a/libsparse/sparse.c
+++ b/libsparse/sparse.c
@@ -99,20 +99,33 @@ unsigned int sparse_count_chunks(struct sparse_file *s)
99 return chunks; 99 return chunks;
100} 100}
101 101
102int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse, 102static void sparse_file_write_block(struct output_file *out,
103 bool crc) 103 struct backed_block *bb)
104{
105 switch (backed_block_type(bb)) {
106 case BACKED_BLOCK_DATA:
107 write_data_chunk(out, backed_block_len(bb), backed_block_data(bb));
108 break;
109 case BACKED_BLOCK_FILE:
110 write_file_chunk(out, backed_block_len(bb),
111 backed_block_filename(bb), backed_block_file_offset(bb));
112 break;
113 case BACKED_BLOCK_FD:
114 write_fd_chunk(out, backed_block_len(bb),
115 backed_block_fd(bb), backed_block_file_offset(bb));
116 break;
117 case BACKED_BLOCK_FILL:
118 write_fill_chunk(out, backed_block_len(bb),
119 backed_block_fill_val(bb));
120 break;
121 }
122}
123
124static int write_all_blocks(struct sparse_file *s, struct output_file *out)
104{ 125{
105 struct backed_block *bb; 126 struct backed_block *bb;
106 unsigned int last_block = 0; 127 unsigned int last_block = 0;
107 int64_t pad; 128 int64_t pad;
108 int chunks;
109 struct output_file *out;
110
111 chunks = sparse_count_chunks(s);
112 out = open_output_fd(fd, s->block_size, s->len, gz, sparse, chunks, crc);
113
114 if (!out)
115 return -ENOMEM;
116 129
117 for (bb = backed_block_iter_new(s->backed_block_list); bb; 130 for (bb = backed_block_iter_new(s->backed_block_list); bb;
118 bb = backed_block_iter_next(bb)) { 131 bb = backed_block_iter_next(bb)) {
@@ -120,23 +133,7 @@ int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse,
120 unsigned int blocks = backed_block_block(bb) - last_block; 133 unsigned int blocks = backed_block_block(bb) - last_block;
121 write_skip_chunk(out, (int64_t)blocks * s->block_size); 134 write_skip_chunk(out, (int64_t)blocks * s->block_size);
122 } 135 }
123 switch (backed_block_type(bb)) { 136 sparse_file_write_block(out, bb);
124 case BACKED_BLOCK_DATA:
125 write_data_chunk(out, backed_block_len(bb), backed_block_data(bb));
126 break;
127 case BACKED_BLOCK_FILE:
128 write_file_chunk(out, backed_block_len(bb),
129 backed_block_filename(bb), backed_block_file_offset(bb));
130 break;
131 case BACKED_BLOCK_FD:
132 write_fd_chunk(out, backed_block_len(bb),
133 backed_block_fd(bb), backed_block_file_offset(bb));
134 break;
135 case BACKED_BLOCK_FILL:
136 write_fill_chunk(out, backed_block_len(bb),
137 backed_block_fill_val(bb));
138 break;
139 }
140 last_block = backed_block_block(bb) + 137 last_block = backed_block_block(bb) +
141 DIV_ROUND_UP(backed_block_len(bb), s->block_size); 138 DIV_ROUND_UP(backed_block_len(bb), s->block_size);
142 } 139 }
@@ -147,9 +144,48 @@ int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse,
147 write_skip_chunk(out, pad); 144 write_skip_chunk(out, pad);
148 } 145 }
149 146
147 return 0;
148}
149
150int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse,
151 bool crc)
152{
153 int ret;
154 int chunks;
155 struct output_file *out;
156
157 chunks = sparse_count_chunks(s);
158 out = open_output_fd(fd, s->block_size, s->len, gz, sparse, chunks, crc);
159
160 if (!out)
161 return -ENOMEM;
162
163 ret = write_all_blocks(s, out);
164
150 close_output_file(out); 165 close_output_file(out);
151 166
152 return 0; 167 return ret;
168}
169
170int sparse_file_callback(struct sparse_file *s, bool sparse, bool crc,
171 int (*write)(void *priv, const void *data, int len), void *priv)
172{
173 int ret;
174 int chunks;
175 struct output_file *out;
176
177 chunks = sparse_count_chunks(s);
178 out = open_output_callback(write, priv, s->block_size, s->len, false,
179 sparse, chunks, crc);
180
181 if (!out)
182 return -ENOMEM;
183
184 ret = write_all_blocks(s, out);
185
186 close_output_file(out);
187
188 return ret;
153} 189}
154 190
155void sparse_file_verbose(struct sparse_file *s) 191void sparse_file_verbose(struct sparse_file *s)