summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'libsparse')
-rw-r--r--libsparse/include/sparse/sparse.h31
-rw-r--r--libsparse/output_file.cpp264
-rw-r--r--libsparse/output_file.h10
-rw-r--r--libsparse/sparse.cpp37
4 files changed, 96 insertions, 246 deletions
diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
index 586578633..3d5fb0c53 100644
--- a/libsparse/include/sparse/sparse.h
+++ b/libsparse/include/sparse/sparse.h
@@ -210,37 +210,6 @@ int sparse_file_callback(struct sparse_file *s, bool sparse, bool crc,
210 int (*write)(void *priv, const void *data, size_t len), void *priv); 210 int (*write)(void *priv, const void *data, size_t len), void *priv);
211 211
212/** 212/**
213 * sparse_file_callback_typed - call a callback for blocks based on type
214 *
215 * @s - sparse file cookie
216 * @sparse - write in the Android sparse file format
217 * @data_write - function to call for data blocks. must not be null
218 * @fd_write - function to call for fd blocks
219 * @fill_write - function to call for fill blocks
220 * @skip_write - function to call for skip blocks
221 * @priv - value that will be passed as the first argument to each write
222 *
223 * Writes a sparse file by calling callback functions. If sparse is true, the
224 * file will be written in the Android sparse file format, and fill and skip blocks
225 * along with metadata will be written with data_write. If sparse is false, the file
226 * will be expanded into normal format and fill and skip blocks will be written with
227 * the given callbacks.
228 * If a callback function is provided, the library will not unroll data into a buffer,
229 * and will instead pass it directly to the caller for custom implementation. If a
230 * callback is not provided, that type of block will be converted into a void* and
231 * written with data_write. If no callbacks other than data are provided, the behavior
232 * is the same as sparse_file_callback(). The callback should return negative on error,
233 * 0 on success.
234 *
235 * Returns 0 on success, negative errno on error.
236 */
237int sparse_file_callback_typed(struct sparse_file* s, bool sparse,
238 int (*data_write)(void* priv, const void* data, size_t len),
239 int (*fd_write)(void* priv, int fd, size_t len),
240 int (*fill_write)(void* priv, uint32_t fill_val, size_t len),
241 int (*skip_write)(void* priv, int64_t len), void* priv);
242
243/**
244 * sparse_file_foreach_chunk - call a callback for data blocks in sparse file 213 * sparse_file_foreach_chunk - call a callback for data blocks in sparse file
245 * 214 *
246 * @s - sparse file cookie 215 * @s - sparse file cookie
diff --git a/libsparse/output_file.cpp b/libsparse/output_file.cpp
index 8a21daba1..fe314b30e 100644
--- a/libsparse/output_file.cpp
+++ b/libsparse/output_file.cpp
@@ -29,8 +29,6 @@
29#include <unistd.h> 29#include <unistd.h>
30#include <zlib.h> 30#include <zlib.h>
31 31
32#include <algorithm>
33
34#include "defs.h" 32#include "defs.h"
35#include "output_file.h" 33#include "output_file.h"
36#include "sparse_crc32.h" 34#include "sparse_crc32.h"
@@ -50,6 +48,13 @@
50#define off64_t off_t 48#define off64_t off_t
51#endif 49#endif
52 50
51#define min(a, b) \
52 ({ \
53 typeof(a) _a = (a); \
54 typeof(b) _b = (b); \
55 (_a < _b) ? _a : _b; \
56 })
57
53#define SPARSE_HEADER_MAJOR_VER 1 58#define SPARSE_HEADER_MAJOR_VER 1
54#define SPARSE_HEADER_MINOR_VER 0 59#define SPARSE_HEADER_MINOR_VER 0
55#define SPARSE_HEADER_LEN (sizeof(sparse_header_t)) 60#define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
@@ -62,14 +67,11 @@ struct output_file_ops {
62 int (*skip)(struct output_file*, int64_t); 67 int (*skip)(struct output_file*, int64_t);
63 int (*pad)(struct output_file*, int64_t); 68 int (*pad)(struct output_file*, int64_t);
64 int (*write)(struct output_file*, void*, size_t); 69 int (*write)(struct output_file*, void*, size_t);
65 int (*write_fd)(struct output_file*, int, size_t);
66 int (*write_fill)(struct output_file*, uint32_t, size_t);
67 void (*close)(struct output_file*); 70 void (*close)(struct output_file*);
68}; 71};
69 72
70struct sparse_file_ops { 73struct sparse_file_ops {
71 int (*write_data_chunk)(struct output_file* out, unsigned int len, void* data); 74 int (*write_data_chunk)(struct output_file* out, unsigned int len, void* data);
72 int (*write_fd_chunk)(struct output_file* out, unsigned int len, int fd);
73 int (*write_fill_chunk)(struct output_file* out, unsigned int len, uint32_t fill_val); 75 int (*write_fill_chunk)(struct output_file* out, unsigned int len, uint32_t fill_val);
74 int (*write_skip_chunk)(struct output_file* out, int64_t len); 76 int (*write_skip_chunk)(struct output_file* out, int64_t len);
75 int (*write_end_chunk)(struct output_file* out); 77 int (*write_end_chunk)(struct output_file* out);
@@ -106,96 +108,11 @@ struct output_file_normal {
106struct output_file_callback { 108struct output_file_callback {
107 struct output_file out; 109 struct output_file out;
108 void* priv; 110 void* priv;
109 int (*data_write)(void* priv, const void* data, size_t len); 111 int (*write)(void* priv, const void* buf, size_t len);
110 int (*fd_write)(void* priv, int fd, size_t len);
111 int (*fill_write)(void* priv, uint32_t fill_val, size_t len);
112 int (*skip_write)(void* priv, off64_t len);
113}; 112};
114 113
115#define to_output_file_callback(_o) container_of((_o), struct output_file_callback, out) 114#define to_output_file_callback(_o) container_of((_o), struct output_file_callback, out)
116 115
117union handle_data {
118 void* data_ptr;
119 int fd;
120};
121
122static int default_file_write_fd(struct output_file* out, int fd, size_t len) {
123 int ret;
124 int64_t aligned_offset;
125 int aligned_diff;
126 uint64_t buffer_size;
127 char* ptr;
128 int64_t offset = lseek64(fd, 0, SEEK_CUR);
129
130 if (offset < 0) {
131 return -errno;
132 }
133
134 aligned_offset = offset & ~(4096 - 1);
135 aligned_diff = offset - aligned_offset;
136 buffer_size = (uint64_t)len + (uint64_t)aligned_diff;
137
138#ifndef _WIN32
139 if (buffer_size > SIZE_MAX) {
140 return -E2BIG;
141 }
142 char* data =
143 reinterpret_cast<char*>(mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, fd, aligned_offset));
144 if (data == MAP_FAILED) {
145 return -errno;
146 }
147 ptr = data + aligned_diff;
148#else
149 char* data = reinterpret_cast<char*>(malloc(len));
150 if (!data) {
151 return -errno;
152 }
153 ret = read_all(fd, data, len);
154 if (ret < 0) {
155 free(data);
156 return -errno;
157 }
158 ptr = data;
159#endif
160
161 ret = out->ops->write(out, ptr, len);
162
163 if (out->use_crc) {
164 out->crc32 = sparse_crc32(out->crc32, ptr, len);
165 }
166
167#ifndef _WIN32
168 munmap(data, buffer_size);
169#else
170 free(data);
171#endif
172
173 return ret;
174}
175
176static int default_file_write_fill(struct output_file* out, uint32_t fill_val, size_t len) {
177 int ret;
178 unsigned int i;
179 unsigned int write_len;
180
181 /* Initialize fill_buf with the fill_val */
182 for (i = 0; i < out->block_size / sizeof(uint32_t); i++) {
183 out->fill_buf[i] = fill_val;
184 }
185
186 while (len) {
187 write_len = std::min(len, static_cast<size_t>(out->block_size));
188 ret = out->ops->write(out, out->fill_buf, write_len);
189 if (ret < 0) {
190 return ret;
191 }
192
193 len -= write_len;
194 }
195
196 return 0;
197}
198
199static int file_open(struct output_file* out, int fd) { 116static int file_open(struct output_file* out, int fd) {
200 struct output_file_normal* outn = to_output_file_normal(out); 117 struct output_file_normal* outn = to_output_file_normal(out);
201 118
@@ -259,8 +176,6 @@ static struct output_file_ops file_ops = {
259 .skip = file_skip, 176 .skip = file_skip,
260 .pad = file_pad, 177 .pad = file_pad,
261 .write = file_write, 178 .write = file_write,
262 .write_fd = default_file_write_fd,
263 .write_fill = default_file_write_fill,
264 .close = file_close, 179 .close = file_close,
265}; 180};
266 181
@@ -316,7 +231,7 @@ static int gz_file_write(struct output_file* out, void* data, size_t len) {
316 struct output_file_gz* outgz = to_output_file_gz(out); 231 struct output_file_gz* outgz = to_output_file_gz(out);
317 232
318 while (len > 0) { 233 while (len > 0) {
319 ret = gzwrite(outgz->gz_fd, data, std::min(len, static_cast<size_t>(INT_MAX))); 234 ret = gzwrite(outgz->gz_fd, data, min(len, (unsigned int)INT_MAX));
320 if (ret == 0) { 235 if (ret == 0) {
321 error("gzwrite %s", gzerror(outgz->gz_fd, nullptr)); 236 error("gzwrite %s", gzerror(outgz->gz_fd, nullptr));
322 return -1; 237 return -1;
@@ -340,8 +255,6 @@ static struct output_file_ops gz_file_ops = {
340 .skip = gz_file_skip, 255 .skip = gz_file_skip,
341 .pad = gz_file_pad, 256 .pad = gz_file_pad,
342 .write = gz_file_write, 257 .write = gz_file_write,
343 .write_fd = default_file_write_fd,
344 .write_fill = default_file_write_fill,
345 .close = gz_file_close, 258 .close = gz_file_close,
346}; 259};
347 260
@@ -354,13 +267,9 @@ static int callback_file_skip(struct output_file* out, int64_t off) {
354 int to_write; 267 int to_write;
355 int ret; 268 int ret;
356 269
357 if (outc->skip_write) {
358 return outc->skip_write(outc->priv, off);
359 }
360
361 while (off > 0) { 270 while (off > 0) {
362 to_write = std::min(off, static_cast<int64_t>(INT_MAX)); 271 to_write = min(off, (int64_t)INT_MAX);
363 ret = outc->data_write(outc->priv, nullptr, to_write); 272 ret = outc->write(outc->priv, nullptr, to_write);
364 if (ret < 0) { 273 if (ret < 0) {
365 return ret; 274 return ret;
366 } 275 }
@@ -376,23 +285,8 @@ static int callback_file_pad(struct output_file* out __unused, int64_t len __unu
376 285
377static int callback_file_write(struct output_file* out, void* data, size_t len) { 286static int callback_file_write(struct output_file* out, void* data, size_t len) {
378 struct output_file_callback* outc = to_output_file_callback(out); 287 struct output_file_callback* outc = to_output_file_callback(out);
379 return outc->data_write(outc->priv, data, len);
380}
381
382static int callback_file_write_fd(struct output_file* out, int fd, size_t len) {
383 struct output_file_callback* outc = to_output_file_callback(out);
384 if (outc->fd_write) {
385 return outc->fd_write(outc->priv, fd, len);
386 }
387 return default_file_write_fd(out, fd, len);
388}
389 288
390static int callback_file_write_fill(struct output_file* out, uint32_t fill_val, size_t len) { 289 return outc->write(outc->priv, data, len);
391 struct output_file_callback* outc = to_output_file_callback(out);
392 if (outc->fill_write) {
393 return outc->fill_write(outc->priv, fill_val, len);
394 }
395 return default_file_write_fill(out, fill_val, len);
396} 290}
397 291
398static void callback_file_close(struct output_file* out) { 292static void callback_file_close(struct output_file* out) {
@@ -406,8 +300,6 @@ static struct output_file_ops callback_file_ops = {
406 .skip = callback_file_skip, 300 .skip = callback_file_skip,
407 .pad = callback_file_pad, 301 .pad = callback_file_pad,
408 .write = callback_file_write, 302 .write = callback_file_write,
409 .write_fd = callback_file_write_fd,
410 .write_fill = callback_file_write_fill,
411 .close = callback_file_close, 303 .close = callback_file_close,
412}; 304};
413 305
@@ -484,8 +376,7 @@ static int write_sparse_fill_chunk(struct output_file* out, unsigned int len, ui
484 return 0; 376 return 0;
485} 377}
486 378
487static int write_sparse_data_chunk_variant(struct output_file* out, unsigned int len, 379static int write_sparse_data_chunk(struct output_file* out, unsigned int len, void* data) {
488 handle_data data, bool is_fd) {
489 chunk_header_t chunk_header; 380 chunk_header_t chunk_header;
490 int rnd_up_len, zero_len; 381 int rnd_up_len, zero_len;
491 int ret; 382 int ret;
@@ -502,16 +393,7 @@ static int write_sparse_data_chunk_variant(struct output_file* out, unsigned int
502 ret = out->ops->write(out, &chunk_header, sizeof(chunk_header)); 393 ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
503 394
504 if (ret < 0) return -1; 395 if (ret < 0) return -1;
505 396 ret = out->ops->write(out, data, len);
506 if (is_fd) {
507 // CRC is handled by write_fd
508 ret = out->ops->write_fd(out, data.fd, len);
509 } else {
510 ret = out->ops->write(out, data.data_ptr, len);
511 if (out->use_crc) {
512 out->crc32 = sparse_crc32(out->crc32, data.data_ptr, len);
513 }
514 }
515 if (ret < 0) return -1; 397 if (ret < 0) return -1;
516 if (zero_len) { 398 if (zero_len) {
517 ret = out->ops->write(out, out->zero_buf, zero_len); 399 ret = out->ops->write(out, out->zero_buf, zero_len);
@@ -519,6 +401,7 @@ static int write_sparse_data_chunk_variant(struct output_file* out, unsigned int
519 } 401 }
520 402
521 if (out->use_crc) { 403 if (out->use_crc) {
404 out->crc32 = sparse_crc32(out->crc32, data, len);
522 if (zero_len) out->crc32 = sparse_crc32(out->crc32, out->zero_buf, zero_len); 405 if (zero_len) out->crc32 = sparse_crc32(out->crc32, out->zero_buf, zero_len);
523 } 406 }
524 407
@@ -528,16 +411,6 @@ static int write_sparse_data_chunk_variant(struct output_file* out, unsigned int
528 return 0; 411 return 0;
529} 412}
530 413
531static int write_sparse_data_chunk(struct output_file* out, unsigned int len, void* data_ptr) {
532 handle_data data = {data_ptr};
533 return write_sparse_data_chunk_variant(out, len, data, false /* isFd */);
534}
535
536static int write_sparse_fd_chunk(struct output_file* out, unsigned int len, int fd) {
537 handle_data data = {.fd = fd};
538 return write_sparse_data_chunk_variant(out, len, data, true /* isFd */);
539}
540
541int write_sparse_end_chunk(struct output_file* out) { 414int write_sparse_end_chunk(struct output_file* out) {
542 chunk_header_t chunk_header; 415 chunk_header_t chunk_header;
543 int ret; 416 int ret;
@@ -565,22 +438,16 @@ int write_sparse_end_chunk(struct output_file* out) {
565 438
566static struct sparse_file_ops sparse_file_ops = { 439static struct sparse_file_ops sparse_file_ops = {
567 .write_data_chunk = write_sparse_data_chunk, 440 .write_data_chunk = write_sparse_data_chunk,
568 .write_fd_chunk = write_sparse_fd_chunk,
569 .write_fill_chunk = write_sparse_fill_chunk, 441 .write_fill_chunk = write_sparse_fill_chunk,
570 .write_skip_chunk = write_sparse_skip_chunk, 442 .write_skip_chunk = write_sparse_skip_chunk,
571 .write_end_chunk = write_sparse_end_chunk, 443 .write_end_chunk = write_sparse_end_chunk,
572}; 444};
573 445
574static int write_normal_data_chunk_variant(struct output_file* out, unsigned int len, 446static int write_normal_data_chunk(struct output_file* out, unsigned int len, void* data) {
575 handle_data data, bool isFd) {
576 int ret; 447 int ret;
577 unsigned int rnd_up_len = ALIGN(len, out->block_size); 448 unsigned int rnd_up_len = ALIGN(len, out->block_size);
578 449
579 if (isFd) { 450 ret = out->ops->write(out, data, len);
580 ret = out->ops->write_fd(out, data.fd, len);
581 } else {
582 ret = out->ops->write(out, data.data_ptr, len);
583 }
584 if (ret < 0) { 451 if (ret < 0) {
585 return ret; 452 return ret;
586 } 453 }
@@ -592,18 +459,27 @@ static int write_normal_data_chunk_variant(struct output_file* out, unsigned int
592 return ret; 459 return ret;
593} 460}
594 461
595static int write_normal_data_chunk(struct output_file* out, unsigned int len, void* data_ptr) { 462static int write_normal_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
596 handle_data data = {data_ptr}; 463 int ret;
597 return write_normal_data_chunk_variant(out, len, data, false /* isFd */); 464 unsigned int i;
598} 465 unsigned int write_len;
599 466
600static int write_normal_fd_chunk(struct output_file* out, unsigned int len, int fd) { 467 /* Initialize fill_buf with the fill_val */
601 handle_data data = {.fd = fd}; 468 for (i = 0; i < out->block_size / sizeof(uint32_t); i++) {
602 return write_normal_data_chunk_variant(out, len, data, true /* isFd */); 469 out->fill_buf[i] = fill_val;
603} 470 }
604 471
605static int write_normal_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) { 472 while (len) {
606 return out->ops->write_fill(out, fill_val, len); 473 write_len = min(len, out->block_size);
474 ret = out->ops->write(out, out->fill_buf, write_len);
475 if (ret < 0) {
476 return ret;
477 }
478
479 len -= write_len;
480 }
481
482 return 0;
607} 483}
608 484
609static int write_normal_skip_chunk(struct output_file* out, int64_t len) { 485static int write_normal_skip_chunk(struct output_file* out, int64_t len) {
@@ -616,7 +492,6 @@ int write_normal_end_chunk(struct output_file* out) {
616 492
617static struct sparse_file_ops normal_file_ops = { 493static struct sparse_file_ops normal_file_ops = {
618 .write_data_chunk = write_normal_data_chunk, 494 .write_data_chunk = write_normal_data_chunk,
619 .write_fd_chunk = write_normal_fd_chunk,
620 .write_fill_chunk = write_normal_fill_chunk, 495 .write_fill_chunk = write_normal_fill_chunk,
621 .write_skip_chunk = write_normal_skip_chunk, 496 .write_skip_chunk = write_normal_skip_chunk,
622 .write_end_chunk = write_normal_end_chunk, 497 .write_end_chunk = write_normal_end_chunk,
@@ -714,20 +589,12 @@ static struct output_file* output_file_new_normal(void) {
714 return &outn->out; 589 return &outn->out;
715} 590}
716 591
717struct output_file* output_file_open_callback(int (*data_write)(void*, const void*, size_t), 592struct output_file* output_file_open_callback(int (*write)(void*, const void*, size_t), void* priv,
718 int (*fd_write)(void*, int, size_t), 593 unsigned int block_size, int64_t len, int gz __unused,
719 int (*fill_write)(void*, uint32_t, size_t), 594 int sparse, int chunks, int crc) {
720 int (*skip_write)(void*, off64_t), void* priv,
721 unsigned int block_size, int64_t len, int sparse,
722 int chunks, int crc) {
723 int ret; 595 int ret;
724 struct output_file_callback* outc; 596 struct output_file_callback* outc;
725 597
726 if (!data_write || (crc && (fd_write || fill_write))) {
727 errno = EINVAL;
728 return nullptr;
729 }
730
731 outc = 598 outc =
732 reinterpret_cast<struct output_file_callback*>(calloc(1, sizeof(struct output_file_callback))); 599 reinterpret_cast<struct output_file_callback*>(calloc(1, sizeof(struct output_file_callback)));
733 if (!outc) { 600 if (!outc) {
@@ -737,10 +604,7 @@ struct output_file* output_file_open_callback(int (*data_write)(void*, const voi
737 604
738 outc->out.ops = &callback_file_ops; 605 outc->out.ops = &callback_file_ops;
739 outc->priv = priv; 606 outc->priv = priv;
740 outc->data_write = data_write; 607 outc->write = write;
741 outc->fd_write = fd_write;
742 outc->fill_write = fill_write;
743 outc->skip_write = skip_write;
744 608
745 ret = output_file_init(&outc->out, block_size, len, sparse, chunks, crc); 609 ret = output_file_init(&outc->out, block_size, len, sparse, chunks, crc);
746 if (ret < 0) { 610 if (ret < 0) {
@@ -787,8 +651,52 @@ int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_va
787} 651}
788 652
789int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t offset) { 653int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t offset) {
790 lseek64(fd, offset, SEEK_SET); 654 int ret;
791 return out->sparse_ops->write_fd_chunk(out, len, fd); 655 int64_t aligned_offset;
656 int aligned_diff;
657 uint64_t buffer_size;
658 char* ptr;
659
660 aligned_offset = offset & ~(4096 - 1);
661 aligned_diff = offset - aligned_offset;
662 buffer_size = (uint64_t)len + (uint64_t)aligned_diff;
663
664#ifndef _WIN32
665 if (buffer_size > SIZE_MAX) return -E2BIG;
666 char* data =
667 reinterpret_cast<char*>(mmap64(nullptr, buffer_size, PROT_READ, MAP_SHARED, fd, aligned_offset));
668 if (data == MAP_FAILED) {
669 return -errno;
670 }
671 ptr = data + aligned_diff;
672#else
673 off64_t pos;
674 char* data = reinterpret_cast<char*>(malloc(len));
675 if (!data) {
676 return -errno;
677 }
678 pos = lseek64(fd, offset, SEEK_SET);
679 if (pos < 0) {
680 free(data);
681 return -errno;
682 }
683 ret = read_all(fd, data, len);
684 if (ret < 0) {
685 free(data);
686 return ret;
687 }
688 ptr = data;
689#endif
690
691 ret = out->sparse_ops->write_data_chunk(out, len, ptr);
692
693#ifndef _WIN32
694 munmap(data, buffer_size);
695#else
696 free(data);
697#endif
698
699 return ret;
792} 700}
793 701
794/* Write a contiguous region of data blocks from a file */ 702/* Write a contiguous region of data blocks from a file */
diff --git a/libsparse/output_file.h b/libsparse/output_file.h
index 114582e17..278430b6f 100644
--- a/libsparse/output_file.h
+++ b/libsparse/output_file.h
@@ -22,18 +22,14 @@ extern "C" {
22#endif 22#endif
23 23
24#include <sparse/sparse.h> 24#include <sparse/sparse.h>
25#include <sys/types.h>
26 25
27struct output_file; 26struct output_file;
28 27
29struct output_file* output_file_open_fd(int fd, unsigned int block_size, int64_t len, int gz, 28struct output_file* output_file_open_fd(int fd, unsigned int block_size, int64_t len, int gz,
30 int sparse, int chunks, int crc); 29 int sparse, int chunks, int crc);
31struct output_file* output_file_open_callback(int (*data_write)(void*, const void*, size_t), 30struct output_file* output_file_open_callback(int (*write)(void*, const void*, size_t), void* priv,
32 int (*fd_write)(void*, int, size_t), 31 unsigned int block_size, int64_t len, int gz,
33 int (*fill_write)(void*, uint32_t, size_t), 32 int sparse, int chunks, int crc);
34 int (*skip_write)(void*, off64_t), void* priv,
35 unsigned int block_size, int64_t len, int sparse,
36 int chunks, int crc);
37int write_data_chunk(struct output_file* out, unsigned int len, void* data); 33int write_data_chunk(struct output_file* out, unsigned int len, void* data);
38int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val); 34int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val);
39int write_file_chunk(struct output_file* out, unsigned int len, const char* file, int64_t offset); 35int write_file_chunk(struct output_file* out, unsigned int len, const char* file, int64_t offset);
diff --git a/libsparse/sparse.cpp b/libsparse/sparse.cpp
index f5ca9071d..cb288c555 100644
--- a/libsparse/sparse.cpp
+++ b/libsparse/sparse.cpp
@@ -160,30 +160,7 @@ int sparse_file_callback(struct sparse_file* s, bool sparse, bool crc,
160 struct output_file* out; 160 struct output_file* out;
161 161
162 chunks = sparse_count_chunks(s); 162 chunks = sparse_count_chunks(s);
163 out = output_file_open_callback(write, nullptr, nullptr, nullptr, priv, s->block_size, s->len, 163 out = output_file_open_callback(write, priv, s->block_size, s->len, false, sparse, chunks, crc);
164 sparse, chunks, crc);
165
166 if (!out) return -ENOMEM;
167
168 ret = write_all_blocks(s, out);
169
170 output_file_close(out);
171
172 return ret;
173}
174
175int sparse_file_callback_typed(struct sparse_file* s, bool sparse,
176 int (*data_write)(void* priv, const void* data, size_t len),
177 int (*fd_write)(void* priv, int fd, size_t len),
178 int (*fill_write)(void* priv, uint32_t fill_val, size_t len),
179 int (*skip_write)(void* priv, int64_t len), void* priv) {
180 int ret;
181 int chunks;
182 struct output_file* out;
183
184 chunks = sparse_count_chunks(s);
185 out = output_file_open_callback(data_write, fd_write, fill_write, skip_write, priv, s->block_size,
186 s->len, sparse, chunks, false);
187 164
188 if (!out) return -ENOMEM; 165 if (!out) return -ENOMEM;
189 166
@@ -221,8 +198,8 @@ int sparse_file_foreach_chunk(struct sparse_file* s, bool sparse, bool crc,
221 chk.write = write; 198 chk.write = write;
222 chk.block = chk.nr_blocks = 0; 199 chk.block = chk.nr_blocks = 0;
223 chunks = sparse_count_chunks(s); 200 chunks = sparse_count_chunks(s);
224 out = output_file_open_callback(foreach_chunk_write, nullptr, nullptr, nullptr, &chk, 201 out = output_file_open_callback(foreach_chunk_write, &chk, s->block_size, s->len, false, sparse,
225 s->block_size, s->len, sparse, chunks, crc); 202 chunks, crc);
226 203
227 if (!out) return -ENOMEM; 204 if (!out) return -ENOMEM;
228 205
@@ -250,8 +227,8 @@ int64_t sparse_file_len(struct sparse_file* s, bool sparse, bool crc) {
250 int64_t count = 0; 227 int64_t count = 0;
251 struct output_file* out; 228 struct output_file* out;
252 229
253 out = output_file_open_callback(out_counter_write, nullptr, nullptr, nullptr, &count, 230 out = output_file_open_callback(out_counter_write, &count, s->block_size, s->len, false, sparse,
254 s->block_size, s->len, sparse, chunks, crc); 231 chunks, crc);
255 if (!out) { 232 if (!out) {
256 return -1; 233 return -1;
257 } 234 }
@@ -290,8 +267,8 @@ static struct backed_block* move_chunks_up_to_len(struct sparse_file* from, stru
290 len -= overhead; 267 len -= overhead;
291 268
292 start = backed_block_iter_new(from->backed_block_list); 269 start = backed_block_iter_new(from->backed_block_list);
293 out_counter = output_file_open_callback(out_counter_write, nullptr, nullptr, nullptr, &count, 270 out_counter = output_file_open_callback(out_counter_write, &count, to->block_size, to->len, false,
294 to->block_size, to->len, true, 0, false); 271 true, 0, false);
295 if (!out_counter) { 272 if (!out_counter) {
296 return nullptr; 273 return nullptr;
297 } 274 }