diff options
Diffstat (limited to 'libsparse')
-rw-r--r-- | libsparse/include/sparse/sparse.h | 31 | ||||
-rw-r--r-- | libsparse/output_file.cpp | 264 | ||||
-rw-r--r-- | libsparse/output_file.h | 10 | ||||
-rw-r--r-- | libsparse/sparse.cpp | 37 |
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 | */ | ||
237 | int 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 | ||
70 | struct sparse_file_ops { | 73 | struct 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 { | |||
106 | struct output_file_callback { | 108 | struct 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 | ||
117 | union handle_data { | ||
118 | void* data_ptr; | ||
119 | int fd; | ||
120 | }; | ||
121 | |||
122 | static 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 | |||
176 | static 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 | |||
199 | static int file_open(struct output_file* out, int fd) { | 116 | static 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 | ||
377 | static int callback_file_write(struct output_file* out, void* data, size_t len) { | 286 | static 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 | |||
382 | static 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 | ||
390 | static 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 | ||
398 | static void callback_file_close(struct output_file* out) { | 292 | static 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 | ||
487 | static int write_sparse_data_chunk_variant(struct output_file* out, unsigned int len, | 379 | static 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 | ||
531 | static 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 | |||
536 | static 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 | |||
541 | int write_sparse_end_chunk(struct output_file* out) { | 414 | int 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 | ||
566 | static struct sparse_file_ops sparse_file_ops = { | 439 | static 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 | ||
574 | static int write_normal_data_chunk_variant(struct output_file* out, unsigned int len, | 446 | static 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 | ||
595 | static int write_normal_data_chunk(struct output_file* out, unsigned int len, void* data_ptr) { | 462 | static 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 | ||
600 | static 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 | ||
605 | static 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 | ||
609 | static int write_normal_skip_chunk(struct output_file* out, int64_t len) { | 485 | static 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 | ||
617 | static struct sparse_file_ops normal_file_ops = { | 493 | static 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 | ||
717 | struct output_file* output_file_open_callback(int (*data_write)(void*, const void*, size_t), | 592 | struct 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 | ||
789 | int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t offset) { | 653 | int 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 | ||
27 | struct output_file; | 26 | struct output_file; |
28 | 27 | ||
29 | struct output_file* output_file_open_fd(int fd, unsigned int block_size, int64_t len, int gz, | 28 | struct 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); |
31 | struct output_file* output_file_open_callback(int (*data_write)(void*, const void*, size_t), | 30 | struct 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); | ||
37 | int write_data_chunk(struct output_file* out, unsigned int len, void* data); | 33 | int write_data_chunk(struct output_file* out, unsigned int len, void* data); |
38 | int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val); | 34 | int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val); |
39 | int write_file_chunk(struct output_file* out, unsigned int len, const char* file, int64_t offset); | 35 | int 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 | |||
175 | int 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 | } |