blob: d6a68b3c7c4400f25cb8fb3ac3914831dc3fafbe [file] [log] [blame]
Colin Cross0c4c47f2012-04-25 19:02:58 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Colin Cross0c4c47f2012-04-25 19:02:58 -070017#define _FILE_OFFSET_BITS 64
18#define _LARGEFILE64_SOURCE 1
19
Chris Friesa7eeb222017-04-17 21:53:16 -050020#include <algorithm>
Daniel Micayaf090a62015-10-13 16:18:45 -040021#include <inttypes.h>
Colin Cross0c4c47f2012-04-25 19:02:58 -070022#include <fcntl.h>
23#include <stdarg.h>
Colin Cross0c4c47f2012-04-25 19:02:58 -070024#include <stdint.h>
25#include <stdio.h>
26#include <stdlib.h>
Xiaolei Yuc39caaf2017-10-11 14:46:29 +080027#include <string.h>
Chris Friesa7eeb222017-04-17 21:53:16 -050028#include <string>
Colin Cross0c4c47f2012-04-25 19:02:58 -070029#include <unistd.h>
30
31#include <sparse/sparse.h>
32
Chris Friesa7eeb222017-04-17 21:53:16 -050033#include "android-base/stringprintf.h"
Mark Salyzyn031a7482014-02-27 16:56:15 -080034#include "defs.h"
35#include "output_file.h"
Colin Cross0c4c47f2012-04-25 19:02:58 -070036#include "sparse_crc32.h"
37#include "sparse_file.h"
38#include "sparse_format.h"
39
Chris Friesa7eeb222017-04-17 21:53:16 -050040
Colin Cross0c4c47f2012-04-25 19:02:58 -070041#if defined(__APPLE__) && defined(__MACH__)
42#define lseek64 lseek
43#define off64_t off_t
44#endif
45
46#define SPARSE_HEADER_MAJOR_VER 1
47#define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
48#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
49
Chris Friesa7eeb222017-04-17 21:53:16 -050050static constexpr int64_t COPY_BUF_SIZE = 1024 * 1024;
Colin Cross0c4c47f2012-04-25 19:02:58 -070051static char *copybuf;
52
Chris Friesa7eeb222017-04-17 21:53:16 -050053static std::string ErrorString(int err)
54{
55 if (err == -EOVERFLOW) return "EOF while reading file";
56 if (err == -EINVAL) return "Invalid sparse file format";
57 if (err == -ENOMEM) return "Failed allocation while reading file";
58 return android::base::StringPrintf("Unknown error %d", err);
59}
Colin Cross0c4c47f2012-04-25 19:02:58 -070060
Jerry Zhang50e60292018-06-05 11:44:52 -070061class SparseFileSource {
62public:
63 /* Seeks the source ahead by the given offset. */
64 virtual void Seek(int64_t offset) = 0;
65
66 /* Return the current offset. */
67 virtual int64_t GetOffset() = 0;
68
69 /* Set the current offset. Return 0 if successful. */
70 virtual int SetOffset(int64_t offset) = 0;
71
72 /* Adds the given length from the current offset of the source to the file at the given
73 * block. Return 0 if successful. */
74 virtual int AddToSparseFile(struct sparse_file *s, int64_t len, unsigned int block) = 0;
75
76 /* Get data of fixed size from the current offset and seek len bytes.
77 * Return 0 if successful. */
78 virtual int ReadValue(void *ptr, int len) = 0;
79
80 /* Find the crc32 of the next len bytes and seek ahead len bytes. Return 0 if successful. */
81 virtual int GetCrc32(uint32_t *crc32, int64_t len) = 0;
82
83 virtual ~SparseFileSource() {};
84};
85
86class SparseFileFdSource : public SparseFileSource {
87private:
88 int fd;
89public:
90 SparseFileFdSource(int fd) : fd(fd) {}
91 ~SparseFileFdSource() override {}
92
93 void Seek(int64_t off) override {
94 lseek64(fd, off, SEEK_CUR);
95 }
96
97 int64_t GetOffset() override {
98 return lseek64(fd, 0, SEEK_CUR);
99 }
100
101 int SetOffset(int64_t offset) override {
102 return lseek64(fd, offset, SEEK_SET) == offset ? 0 : -errno;
103 }
104
105 int AddToSparseFile(struct sparse_file *s, int64_t len, unsigned int block) override {
106 return sparse_file_add_fd(s, fd, GetOffset(), len, block);
107 }
108
109 int ReadValue(void *ptr, int len) override {
110 return read_all(fd, ptr, len);
111 }
112
113 int GetCrc32(uint32_t *crc32, int64_t len) override {
114 int chunk;
115 int ret;
116 while (len) {
117 chunk = std::min(len, COPY_BUF_SIZE);
118 ret = read_all(fd, copybuf, chunk);
119 if (ret < 0) {
120 return ret;
121 }
122 *crc32 = sparse_crc32(*crc32, copybuf, chunk);
123 len -= chunk;
124 }
125 return 0;
126 }
127};
128
129class SparseFileBufSource : public SparseFileSource {
130private:
131 char *buf;
132 int64_t offset;
133public:
134 SparseFileBufSource(char *buf) : buf(buf), offset(0) {}
135 ~SparseFileBufSource() override {}
136
137 void Seek(int64_t off) override {
138 buf += off;
139 offset += off;
140 }
141
142 int64_t GetOffset() override {
143 return offset;
144 }
145
146 int SetOffset(int64_t off) override {
147 buf += off - offset;
148 offset = off;
149 return 0;
150 }
151
152 int AddToSparseFile(struct sparse_file *s, int64_t len, unsigned int block) override {
153 return sparse_file_add_data(s, buf, len, block);
154 }
155
156 int ReadValue(void *ptr, int len) override {
157 memcpy(ptr, buf, len);
158 Seek(len);
159 return 0;
160 }
161
162 int GetCrc32(uint32_t *crc32, int64_t len) override {
163 *crc32 = sparse_crc32(*crc32, buf, len);
164 Seek(len);
165 return 0;
166 }
167};
168
Colin Cross0c4c47f2012-04-25 19:02:58 -0700169static void verbose_error(bool verbose, int err, const char *fmt, ...)
170{
Chris Friesa7eeb222017-04-17 21:53:16 -0500171 if (!verbose) return;
172
173 std::string msg = ErrorString(err);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700174 if (fmt) {
Chris Friesa7eeb222017-04-17 21:53:16 -0500175 msg += " at ";
Colin Cross0c4c47f2012-04-25 19:02:58 -0700176 va_list argp;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700177 va_start(argp, fmt);
Chris Friesa7eeb222017-04-17 21:53:16 -0500178 android::base::StringAppendV(&msg, fmt, argp);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700179 va_end(argp);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700180 }
Chris Friesa7eeb222017-04-17 21:53:16 -0500181 sparse_print_verbose("%s\n", msg.c_str());
Colin Cross0c4c47f2012-04-25 19:02:58 -0700182}
183
184static int process_raw_chunk(struct sparse_file *s, unsigned int chunk_size,
Jerry Zhang50e60292018-06-05 11:44:52 -0700185 SparseFileSource *source, unsigned int blocks, unsigned int block,
Colin Cross0c4c47f2012-04-25 19:02:58 -0700186 uint32_t *crc32)
187{
188 int ret;
Chris Friesa7eeb222017-04-17 21:53:16 -0500189 int64_t len = blocks * s->block_size;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700190
191 if (chunk_size % s->block_size != 0) {
192 return -EINVAL;
193 }
194
195 if (chunk_size / s->block_size != blocks) {
196 return -EINVAL;
197 }
198
Jerry Zhang50e60292018-06-05 11:44:52 -0700199 ret = source->AddToSparseFile(s, len, block);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700200 if (ret < 0) {
201 return ret;
202 }
203
204 if (crc32) {
Jerry Zhang50e60292018-06-05 11:44:52 -0700205 ret = source->GetCrc32(crc32, len);
206 if (ret < 0) {
207 return ret;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700208 }
209 } else {
Jerry Zhang50e60292018-06-05 11:44:52 -0700210 source->Seek(len);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700211 }
212
213 return 0;
214}
215
216static int process_fill_chunk(struct sparse_file *s, unsigned int chunk_size,
Jerry Zhang50e60292018-06-05 11:44:52 -0700217 SparseFileSource *source, unsigned int blocks, unsigned int block, uint32_t *crc32)
Colin Cross0c4c47f2012-04-25 19:02:58 -0700218{
219 int ret;
220 int chunk;
221 int64_t len = (int64_t)blocks * s->block_size;
222 uint32_t fill_val;
223 uint32_t *fillbuf;
224 unsigned int i;
225
226 if (chunk_size != sizeof(fill_val)) {
227 return -EINVAL;
228 }
229
Jerry Zhang50e60292018-06-05 11:44:52 -0700230 ret = source->ReadValue(&fill_val, sizeof(fill_val));
Colin Cross0c4c47f2012-04-25 19:02:58 -0700231 if (ret < 0) {
232 return ret;
233 }
234
235 ret = sparse_file_add_fill(s, fill_val, len, block);
236 if (ret < 0) {
237 return ret;
238 }
239
240 if (crc32) {
241 /* Fill copy_buf with the fill value */
242 fillbuf = (uint32_t *)copybuf;
243 for (i = 0; i < (COPY_BUF_SIZE / sizeof(fill_val)); i++) {
244 fillbuf[i] = fill_val;
245 }
246
247 while (len) {
Chris Friesa7eeb222017-04-17 21:53:16 -0500248 chunk = std::min(len, COPY_BUF_SIZE);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700249 *crc32 = sparse_crc32(*crc32, copybuf, chunk);
250 len -= chunk;
251 }
252 }
253
254 return 0;
255}
256
257static int process_skip_chunk(struct sparse_file *s, unsigned int chunk_size,
Jerry Zhang50e60292018-06-05 11:44:52 -0700258 SparseFileSource *source __unused, unsigned int blocks,
Mark Salyzyn031a7482014-02-27 16:56:15 -0800259 unsigned int block __unused, uint32_t *crc32)
Colin Cross0c4c47f2012-04-25 19:02:58 -0700260{
Colin Cross0c4c47f2012-04-25 19:02:58 -0700261 if (chunk_size != 0) {
262 return -EINVAL;
263 }
264
265 if (crc32) {
Jerry Zhang50e60292018-06-05 11:44:52 -0700266 int64_t len = (int64_t)blocks * s->block_size;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700267 memset(copybuf, 0, COPY_BUF_SIZE);
268
269 while (len) {
Chris Friesa7eeb222017-04-17 21:53:16 -0500270 int chunk = std::min(len, COPY_BUF_SIZE);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700271 *crc32 = sparse_crc32(*crc32, copybuf, chunk);
272 len -= chunk;
273 }
274 }
275
276 return 0;
277}
278
Jerry Zhang50e60292018-06-05 11:44:52 -0700279static int process_crc32_chunk(SparseFileSource *source, unsigned int chunk_size, uint32_t *crc32)
Colin Cross0c4c47f2012-04-25 19:02:58 -0700280{
281 uint32_t file_crc32;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700282
283 if (chunk_size != sizeof(file_crc32)) {
284 return -EINVAL;
285 }
286
Jerry Zhang50e60292018-06-05 11:44:52 -0700287 int ret = source->ReadValue(&file_crc32, sizeof(file_crc32));
Colin Cross0c4c47f2012-04-25 19:02:58 -0700288 if (ret < 0) {
289 return ret;
290 }
291
Colin Cross1eb743b2016-02-01 11:15:30 -0800292 if (crc32 != NULL && file_crc32 != *crc32) {
Colin Cross0c4c47f2012-04-25 19:02:58 -0700293 return -EINVAL;
294 }
295
296 return 0;
297}
298
Jerry Zhang50e60292018-06-05 11:44:52 -0700299static int process_chunk(struct sparse_file *s, SparseFileSource *source,
Colin Cross0c4c47f2012-04-25 19:02:58 -0700300 unsigned int chunk_hdr_sz, chunk_header_t *chunk_header,
301 unsigned int cur_block, uint32_t *crc_ptr)
302{
303 int ret;
304 unsigned int chunk_data_size;
Jerry Zhang50e60292018-06-05 11:44:52 -0700305 int64_t offset = source->GetOffset();
Colin Cross0c4c47f2012-04-25 19:02:58 -0700306
307 chunk_data_size = chunk_header->total_sz - chunk_hdr_sz;
308
309 switch (chunk_header->chunk_type) {
310 case CHUNK_TYPE_RAW:
Jerry Zhang50e60292018-06-05 11:44:52 -0700311 ret = process_raw_chunk(s, chunk_data_size, source,
Colin Cross0c4c47f2012-04-25 19:02:58 -0700312 chunk_header->chunk_sz, cur_block, crc_ptr);
313 if (ret < 0) {
Daniel Micayaf090a62015-10-13 16:18:45 -0400314 verbose_error(s->verbose, ret, "data block at %" PRId64, offset);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700315 return ret;
316 }
317 return chunk_header->chunk_sz;
318 case CHUNK_TYPE_FILL:
Jerry Zhang50e60292018-06-05 11:44:52 -0700319 ret = process_fill_chunk(s, chunk_data_size, source,
Colin Cross0c4c47f2012-04-25 19:02:58 -0700320 chunk_header->chunk_sz, cur_block, crc_ptr);
321 if (ret < 0) {
Daniel Micayaf090a62015-10-13 16:18:45 -0400322 verbose_error(s->verbose, ret, "fill block at %" PRId64, offset);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700323 return ret;
324 }
325 return chunk_header->chunk_sz;
326 case CHUNK_TYPE_DONT_CARE:
Jerry Zhang50e60292018-06-05 11:44:52 -0700327 ret = process_skip_chunk(s, chunk_data_size, source,
Colin Cross0c4c47f2012-04-25 19:02:58 -0700328 chunk_header->chunk_sz, cur_block, crc_ptr);
329 if (chunk_data_size != 0) {
330 if (ret < 0) {
Daniel Micayaf090a62015-10-13 16:18:45 -0400331 verbose_error(s->verbose, ret, "skip block at %" PRId64, offset);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700332 return ret;
333 }
334 }
335 return chunk_header->chunk_sz;
336 case CHUNK_TYPE_CRC32:
Jerry Zhang50e60292018-06-05 11:44:52 -0700337 ret = process_crc32_chunk(source, chunk_data_size, crc_ptr);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700338 if (ret < 0) {
Daniel Micayaf090a62015-10-13 16:18:45 -0400339 verbose_error(s->verbose, -EINVAL, "crc block at %" PRId64,
Colin Cross0c4c47f2012-04-25 19:02:58 -0700340 offset);
341 return ret;
342 }
343 return 0;
344 default:
Daniel Micayaf090a62015-10-13 16:18:45 -0400345 verbose_error(s->verbose, -EINVAL, "unknown block %04X at %" PRId64,
Colin Cross0c4c47f2012-04-25 19:02:58 -0700346 chunk_header->chunk_type, offset);
347 }
348
349 return 0;
350}
351
Jerry Zhang50e60292018-06-05 11:44:52 -0700352static int sparse_file_read_sparse(struct sparse_file *s, SparseFileSource *source, bool crc)
Colin Cross0c4c47f2012-04-25 19:02:58 -0700353{
354 int ret;
355 unsigned int i;
356 sparse_header_t sparse_header;
357 chunk_header_t chunk_header;
358 uint32_t crc32 = 0;
359 uint32_t *crc_ptr = 0;
360 unsigned int cur_block = 0;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700361
362 if (!copybuf) {
Chris Friesa7eeb222017-04-17 21:53:16 -0500363 copybuf = (char *)malloc(COPY_BUF_SIZE);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700364 }
365
366 if (!copybuf) {
367 return -ENOMEM;
368 }
369
370 if (crc) {
371 crc_ptr = &crc32;
372 }
373
Jerry Zhang50e60292018-06-05 11:44:52 -0700374 ret = source->ReadValue(&sparse_header, sizeof(sparse_header));
Colin Cross0c4c47f2012-04-25 19:02:58 -0700375 if (ret < 0) {
376 return ret;
377 }
378
379 if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
380 return -EINVAL;
381 }
382
383 if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
384 return -EINVAL;
385 }
386
387 if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
388 return -EINVAL;
389 }
390
391 if (sparse_header.chunk_hdr_sz < sizeof(chunk_header)) {
392 return -EINVAL;
393 }
394
395 if (sparse_header.file_hdr_sz > SPARSE_HEADER_LEN) {
396 /* Skip the remaining bytes in a header that is longer than
397 * we expected.
398 */
Jerry Zhang50e60292018-06-05 11:44:52 -0700399 source->Seek(sparse_header.file_hdr_sz - SPARSE_HEADER_LEN);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700400 }
401
402 for (i = 0; i < sparse_header.total_chunks; i++) {
Jerry Zhang50e60292018-06-05 11:44:52 -0700403 ret = source->ReadValue(&chunk_header, sizeof(chunk_header));
Colin Cross0c4c47f2012-04-25 19:02:58 -0700404 if (ret < 0) {
405 return ret;
406 }
407
408 if (sparse_header.chunk_hdr_sz > CHUNK_HEADER_LEN) {
409 /* Skip the remaining bytes in a header that is longer than
410 * we expected.
411 */
Jerry Zhang50e60292018-06-05 11:44:52 -0700412 source->Seek(sparse_header.chunk_hdr_sz - CHUNK_HEADER_LEN);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700413 }
414
Jerry Zhang50e60292018-06-05 11:44:52 -0700415 ret = process_chunk(s, source, sparse_header.chunk_hdr_sz, &chunk_header,
Colin Cross0c4c47f2012-04-25 19:02:58 -0700416 cur_block, crc_ptr);
417 if (ret < 0) {
418 return ret;
419 }
420
421 cur_block += ret;
422 }
423
424 if (sparse_header.total_blks != cur_block) {
425 return -EINVAL;
426 }
427
428 return 0;
429}
430
431static int sparse_file_read_normal(struct sparse_file *s, int fd)
432{
433 int ret;
Chris Friesa7eeb222017-04-17 21:53:16 -0500434 uint32_t *buf = (uint32_t *)malloc(s->block_size);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700435 unsigned int block = 0;
436 int64_t remain = s->len;
437 int64_t offset = 0;
438 unsigned int to_read;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700439 unsigned int i;
440 bool sparse_block;
441
442 if (!buf) {
443 return -ENOMEM;
444 }
445
446 while (remain > 0) {
Chris Friesa7eeb222017-04-17 21:53:16 -0500447 to_read = std::min(remain, (int64_t)(s->block_size));
Colin Cross0c4c47f2012-04-25 19:02:58 -0700448 ret = read_all(fd, buf, to_read);
449 if (ret < 0) {
450 error("failed to read sparse file");
Colin Cross1eb743b2016-02-01 11:15:30 -0800451 free(buf);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700452 return ret;
453 }
454
455 if (to_read == s->block_size) {
456 sparse_block = true;
457 for (i = 1; i < s->block_size / sizeof(uint32_t); i++) {
458 if (buf[0] != buf[i]) {
459 sparse_block = false;
460 break;
461 }
462 }
463 } else {
464 sparse_block = false;
465 }
466
467 if (sparse_block) {
468 /* TODO: add flag to use skip instead of fill for buf[0] == 0 */
469 sparse_file_add_fill(s, buf[0], to_read, block);
470 } else {
471 sparse_file_add_fd(s, fd, offset, to_read, block);
472 }
473
474 remain -= to_read;
475 offset += to_read;
476 block++;
477 }
478
Colin Cross1eb743b2016-02-01 11:15:30 -0800479 free(buf);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700480 return 0;
481}
482
483int sparse_file_read(struct sparse_file *s, int fd, bool sparse, bool crc)
484{
485 if (crc && !sparse) {
486 return -EINVAL;
487 }
488
489 if (sparse) {
Jerry Zhang50e60292018-06-05 11:44:52 -0700490 SparseFileFdSource source(fd);
491 return sparse_file_read_sparse(s, &source, crc);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700492 } else {
493 return sparse_file_read_normal(s, fd);
494 }
495}
496
Jerry Zhang50e60292018-06-05 11:44:52 -0700497int sparse_file_read_buf(struct sparse_file *s, char *buf, bool crc)
498{
499 SparseFileBufSource source(buf);
500 return sparse_file_read_sparse(s, &source, crc);
501}
502
503static struct sparse_file *sparse_file_import_source(SparseFileSource *source, bool verbose, bool crc)
Colin Cross0c4c47f2012-04-25 19:02:58 -0700504{
505 int ret;
506 sparse_header_t sparse_header;
507 int64_t len;
508 struct sparse_file *s;
509
Jerry Zhang50e60292018-06-05 11:44:52 -0700510 ret = source->ReadValue(&sparse_header, sizeof(sparse_header));
Colin Cross0c4c47f2012-04-25 19:02:58 -0700511 if (ret < 0) {
512 verbose_error(verbose, ret, "header");
513 return NULL;
514 }
515
516 if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
517 verbose_error(verbose, -EINVAL, "header magic");
518 return NULL;
519 }
520
521 if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
522 verbose_error(verbose, -EINVAL, "header major version");
523 return NULL;
524 }
525
526 if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
527 return NULL;
528 }
529
530 if (sparse_header.chunk_hdr_sz < sizeof(chunk_header_t)) {
531 return NULL;
532 }
533
534 len = (int64_t)sparse_header.total_blks * sparse_header.blk_sz;
535 s = sparse_file_new(sparse_header.blk_sz, len);
536 if (!s) {
537 verbose_error(verbose, -EINVAL, NULL);
538 return NULL;
539 }
540
Jerry Zhang50e60292018-06-05 11:44:52 -0700541 ret = source->SetOffset(0);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700542 if (ret < 0) {
543 verbose_error(verbose, ret, "seeking");
544 sparse_file_destroy(s);
545 return NULL;
546 }
547
548 s->verbose = verbose;
549
Jerry Zhang50e60292018-06-05 11:44:52 -0700550 ret = sparse_file_read_sparse(s, source, crc);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700551 if (ret < 0) {
552 sparse_file_destroy(s);
553 return NULL;
554 }
555
556 return s;
557}
558
Jerry Zhang50e60292018-06-05 11:44:52 -0700559struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc) {
560 SparseFileFdSource source(fd);
561 return sparse_file_import_source(&source, verbose, crc);
562}
563
564struct sparse_file *sparse_file_import_buf(char* buf, bool verbose, bool crc) {
565 SparseFileBufSource source(buf);
566 return sparse_file_import_source(&source, verbose, crc);
567}
568
Mohamad Ayyash80cc1f62015-03-31 12:09:29 -0700569struct sparse_file *sparse_file_import_auto(int fd, bool crc, bool verbose)
Colin Cross0c4c47f2012-04-25 19:02:58 -0700570{
571 struct sparse_file *s;
572 int64_t len;
573 int ret;
574
Mohamad Ayyash80cc1f62015-03-31 12:09:29 -0700575 s = sparse_file_import(fd, verbose, crc);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700576 if (s) {
577 return s;
578 }
579
580 len = lseek64(fd, 0, SEEK_END);
581 if (len < 0) {
582 return NULL;
583 }
584
585 lseek64(fd, 0, SEEK_SET);
586
587 s = sparse_file_new(4096, len);
588 if (!s) {
589 return NULL;
590 }
591
592 ret = sparse_file_read_normal(s, fd);
593 if (ret < 0) {
594 sparse_file_destroy(s);
595 return NULL;
596 }
597
598 return s;
599}