2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #define _FILE_OFFSET_BITS 64
19 #define _LARGEFILE64_SOURCE 1
30 #include <sparse/sparse.h>
33 #include "output_file.h"
34 #include "sparse_crc32.h"
35 #include "sparse_file.h"
36 #include "sparse_format.h"
38 #if defined(__APPLE__) && defined(__MACH__)
43 #define SPARSE_HEADER_MAJOR_VER 1
44 #define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
45 #define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
47 #define COPY_BUF_SIZE (1024U*1024U)
51 ({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; })
53 static void verbose_error(bool verbose
, int err
, const char *fmt
, ...)
62 size
= vsnprintf(NULL
, 0, fmt
, argp
);
69 at
= malloc(size
+ 1);
75 vsnprintf(at
, size
, fmt
, argp
);
82 if (err
== -EOVERFLOW
) {
83 sparse_print_verbose("EOF while reading file%s%s\n", s
, at
);
87 sparse_print_verbose("Invalid sparse file format%s%s\n", s
, at
);
88 } else if (err
== -ENOMEM
) {
89 sparse_print_verbose("Failed allocation while reading file%s%s\n",
92 sparse_print_verbose("Unknown error %d%s%s\n", err
, s
, at
);
100 static int process_raw_chunk(struct sparse_file
*s
, unsigned int chunk_size
,
101 int fd
, int64_t offset
, unsigned int blocks
, unsigned int block
,
106 unsigned int len
= blocks
* s
->block_size
;
108 if (chunk_size
% s
->block_size
!= 0) {
112 if (chunk_size
/ s
->block_size
!= blocks
) {
116 ret
= sparse_file_add_fd(s
, fd
, offset
, len
, block
);
123 chunk
= min(len
, COPY_BUF_SIZE
);
124 ret
= read_all(fd
, copybuf
, chunk
);
128 *crc32
= sparse_crc32(*crc32
, copybuf
, chunk
);
132 lseek64(fd
, len
, SEEK_CUR
);
138 static int process_fill_chunk(struct sparse_file
*s
, unsigned int chunk_size
,
139 int fd
, unsigned int blocks
, unsigned int block
, uint32_t *crc32
)
143 int64_t len
= (int64_t)blocks
* s
->block_size
;
148 if (chunk_size
!= sizeof(fill_val
)) {
152 ret
= read_all(fd
, &fill_val
, sizeof(fill_val
));
157 ret
= sparse_file_add_fill(s
, fill_val
, len
, block
);
163 /* Fill copy_buf with the fill value */
164 fillbuf
= (uint32_t *)copybuf
;
165 for (i
= 0; i
< (COPY_BUF_SIZE
/ sizeof(fill_val
)); i
++) {
166 fillbuf
[i
] = fill_val
;
170 chunk
= min(len
, COPY_BUF_SIZE
);
171 *crc32
= sparse_crc32(*crc32
, copybuf
, chunk
);
179 static int process_skip_chunk(struct sparse_file
*s
, unsigned int chunk_size
,
180 int fd __unused
, unsigned int blocks
,
181 unsigned int block __unused
, uint32_t *crc32
)
183 if (chunk_size
!= 0) {
188 int64_t len
= (int64_t)blocks
* s
->block_size
;
189 memset(copybuf
, 0, COPY_BUF_SIZE
);
192 int chunk
= min(len
, COPY_BUF_SIZE
);
193 *crc32
= sparse_crc32(*crc32
, copybuf
, chunk
);
201 static int process_crc32_chunk(int fd
, unsigned int chunk_size
, uint32_t crc32
)
206 if (chunk_size
!= sizeof(file_crc32
)) {
210 ret
= read_all(fd
, &file_crc32
, sizeof(file_crc32
));
215 if (file_crc32
!= crc32
) {
222 static int process_chunk(struct sparse_file
*s
, int fd
, off64_t offset
,
223 unsigned int chunk_hdr_sz
, chunk_header_t
*chunk_header
,
224 unsigned int cur_block
, uint32_t *crc_ptr
)
227 unsigned int chunk_data_size
;
229 chunk_data_size
= chunk_header
->total_sz
- chunk_hdr_sz
;
231 switch (chunk_header
->chunk_type
) {
233 ret
= process_raw_chunk(s
, chunk_data_size
, fd
, offset
,
234 chunk_header
->chunk_sz
, cur_block
, crc_ptr
);
236 verbose_error(s
->verbose
, ret
, "data block at %lld", offset
);
239 return chunk_header
->chunk_sz
;
240 case CHUNK_TYPE_FILL
:
241 ret
= process_fill_chunk(s
, chunk_data_size
, fd
,
242 chunk_header
->chunk_sz
, cur_block
, crc_ptr
);
244 verbose_error(s
->verbose
, ret
, "fill block at %lld", offset
);
247 return chunk_header
->chunk_sz
;
248 case CHUNK_TYPE_DONT_CARE
:
249 ret
= process_skip_chunk(s
, chunk_data_size
, fd
,
250 chunk_header
->chunk_sz
, cur_block
, crc_ptr
);
251 if (chunk_data_size
!= 0) {
253 verbose_error(s
->verbose
, ret
, "skip block at %lld", offset
);
257 return chunk_header
->chunk_sz
;
258 case CHUNK_TYPE_CRC32
:
259 ret
= process_crc32_chunk(fd
, chunk_data_size
, *crc_ptr
);
261 verbose_error(s
->verbose
, -EINVAL
, "crc block at %lld",
267 verbose_error(s
->verbose
, -EINVAL
, "unknown block %04X at %lld",
268 chunk_header
->chunk_type
, offset
);
274 static int sparse_file_read_sparse(struct sparse_file
*s
, int fd
, bool crc
)
278 sparse_header_t sparse_header
;
279 chunk_header_t chunk_header
;
281 uint32_t *crc_ptr
= 0;
282 unsigned int cur_block
= 0;
286 copybuf
= malloc(COPY_BUF_SIZE
);
297 ret
= read_all(fd
, &sparse_header
, sizeof(sparse_header
));
302 if (sparse_header
.magic
!= SPARSE_HEADER_MAGIC
) {
306 if (sparse_header
.major_version
!= SPARSE_HEADER_MAJOR_VER
) {
310 if (sparse_header
.file_hdr_sz
< SPARSE_HEADER_LEN
) {
314 if (sparse_header
.chunk_hdr_sz
< sizeof(chunk_header
)) {
318 if (sparse_header
.file_hdr_sz
> SPARSE_HEADER_LEN
) {
319 /* Skip the remaining bytes in a header that is longer than
322 lseek64(fd
, sparse_header
.file_hdr_sz
- SPARSE_HEADER_LEN
, SEEK_CUR
);
325 for (i
= 0; i
< sparse_header
.total_chunks
; i
++) {
326 ret
= read_all(fd
, &chunk_header
, sizeof(chunk_header
));
331 if (sparse_header
.chunk_hdr_sz
> CHUNK_HEADER_LEN
) {
332 /* Skip the remaining bytes in a header that is longer than
335 lseek64(fd
, sparse_header
.chunk_hdr_sz
- CHUNK_HEADER_LEN
, SEEK_CUR
);
338 offset
= lseek64(fd
, 0, SEEK_CUR
);
340 ret
= process_chunk(s
, fd
, offset
, sparse_header
.chunk_hdr_sz
, &chunk_header
,
349 if (sparse_header
.total_blks
!= cur_block
) {
356 static int sparse_file_read_normal(struct sparse_file
*s
, int fd
)
359 uint32_t *buf
= malloc(s
->block_size
);
360 unsigned int block
= 0;
361 int64_t remain
= s
->len
;
363 unsigned int to_read
;
372 to_read
= min(remain
, s
->block_size
);
373 ret
= read_all(fd
, buf
, to_read
);
375 error("failed to read sparse file");
379 if (to_read
== s
->block_size
) {
381 for (i
= 1; i
< s
->block_size
/ sizeof(uint32_t); i
++) {
382 if (buf
[0] != buf
[i
]) {
383 sparse_block
= false;
388 sparse_block
= false;
392 /* TODO: add flag to use skip instead of fill for buf[0] == 0 */
393 sparse_file_add_fill(s
, buf
[0], to_read
, block
);
395 sparse_file_add_fd(s
, fd
, offset
, to_read
, block
);
406 int sparse_file_read(struct sparse_file
*s
, int fd
, bool sparse
, bool crc
)
408 if (crc
&& !sparse
) {
413 return sparse_file_read_sparse(s
, fd
, crc
);
415 return sparse_file_read_normal(s
, fd
);
419 struct sparse_file
*sparse_file_import(int fd
, bool verbose
, bool crc
)
422 sparse_header_t sparse_header
;
424 struct sparse_file
*s
;
426 ret
= read_all(fd
, &sparse_header
, sizeof(sparse_header
));
428 verbose_error(verbose
, ret
, "header");
432 if (sparse_header
.magic
!= SPARSE_HEADER_MAGIC
) {
433 verbose_error(verbose
, -EINVAL
, "header magic");
437 if (sparse_header
.major_version
!= SPARSE_HEADER_MAJOR_VER
) {
438 verbose_error(verbose
, -EINVAL
, "header major version");
442 if (sparse_header
.file_hdr_sz
< SPARSE_HEADER_LEN
) {
446 if (sparse_header
.chunk_hdr_sz
< sizeof(chunk_header_t
)) {
450 len
= (int64_t)sparse_header
.total_blks
* sparse_header
.blk_sz
;
451 s
= sparse_file_new(sparse_header
.blk_sz
, len
);
453 verbose_error(verbose
, -EINVAL
, NULL
);
457 ret
= lseek64(fd
, 0, SEEK_SET
);
459 verbose_error(verbose
, ret
, "seeking");
460 sparse_file_destroy(s
);
464 s
->verbose
= verbose
;
466 ret
= sparse_file_read(s
, fd
, true, crc
);
468 sparse_file_destroy(s
);
475 struct sparse_file
*sparse_file_import_auto(int fd
, bool crc
, bool verbose
)
477 struct sparse_file
*s
;
481 s
= sparse_file_import(fd
, verbose
, crc
);
486 len
= lseek64(fd
, 0, SEEK_END
);
491 lseek64(fd
, 0, SEEK_SET
);
493 s
= sparse_file_new(4096, len
);
498 ret
= sparse_file_read_normal(s
, fd
);
500 sparse_file_destroy(s
);