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 #define SPARSE_HEADER_MAJOR_VER 1
39 #define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
40 #define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
42 #define COPY_BUF_SIZE (1024U*1024U)
46 ({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; })
48 static void verbose_error(bool verbose
, int err
, const char *fmt
, ...)
57 size
= vsnprintf(NULL
, 0, fmt
, argp
);
64 at
= malloc(size
+ 1);
70 vsnprintf(at
, size
, fmt
, argp
);
76 if (err
== -EOVERFLOW
) {
77 sparse_print_verbose("EOF while reading file%s%s\n", s
, at
);
78 } else if (err
== -EINVAL
) {
79 sparse_print_verbose("Invalid sparse file format%s%s\n", s
, at
);
80 } else if (err
== -ENOMEM
) {
81 sparse_print_verbose("Failed allocation while reading file%s%s\n",
84 sparse_print_verbose("Unknown error %d%s%s\n", err
, s
, at
);
92 static int process_raw_chunk(struct sparse_file
*s
, unsigned int chunk_size
,
93 int fd
, int64_t offset
, unsigned int blocks
, unsigned int block
,
98 unsigned int len
= blocks
* s
->block_size
;
100 if (chunk_size
% s
->block_size
!= 0) {
104 if (chunk_size
/ s
->block_size
!= blocks
) {
108 ret
= sparse_file_add_fd(s
, fd
, offset
, len
, block
);
115 chunk
= min(len
, COPY_BUF_SIZE
);
116 ret
= read_all(fd
, copybuf
, chunk
);
120 *crc32
= sparse_crc32(*crc32
, copybuf
, chunk
);
124 lseek(fd
, len
, SEEK_CUR
);
130 static int process_fill_chunk(struct sparse_file
*s
, unsigned int chunk_size
,
131 int fd
, unsigned int blocks
, unsigned int block
, uint32_t *crc32
)
135 int64_t len
= (int64_t)blocks
* s
->block_size
;
140 if (chunk_size
!= sizeof(fill_val
)) {
144 ret
= read_all(fd
, &fill_val
, sizeof(fill_val
));
149 ret
= sparse_file_add_fill(s
, fill_val
, len
, block
);
155 /* Fill copy_buf with the fill value */
156 fillbuf
= (uint32_t *)copybuf
;
157 for (i
= 0; i
< (COPY_BUF_SIZE
/ sizeof(fill_val
)); i
++) {
158 fillbuf
[i
] = fill_val
;
162 chunk
= min(len
, COPY_BUF_SIZE
);
163 *crc32
= sparse_crc32(*crc32
, copybuf
, chunk
);
171 static int process_skip_chunk(struct sparse_file
*s
, unsigned int chunk_size
,
172 int fd __unused
, unsigned int blocks
,
173 unsigned int block __unused
, uint32_t *crc32
)
175 if (chunk_size
!= 0) {
180 int64_t len
= (int64_t)blocks
* s
->block_size
;
181 memset(copybuf
, 0, COPY_BUF_SIZE
);
184 int chunk
= min(len
, COPY_BUF_SIZE
);
185 *crc32
= sparse_crc32(*crc32
, copybuf
, chunk
);
193 static int process_crc32_chunk(int fd
, unsigned int chunk_size
, uint32_t crc32
)
198 if (chunk_size
!= sizeof(file_crc32
)) {
202 ret
= read_all(fd
, &file_crc32
, sizeof(file_crc32
));
207 if (file_crc32
!= crc32
) {
214 static int process_chunk(struct sparse_file
*s
, int fd
, off_t offset
,
215 unsigned int chunk_hdr_sz
, chunk_header_t
*chunk_header
,
216 unsigned int cur_block
, uint32_t *crc_ptr
)
219 unsigned int chunk_data_size
;
221 chunk_data_size
= chunk_header
->total_sz
- chunk_hdr_sz
;
223 switch (chunk_header
->chunk_type
) {
225 ret
= process_raw_chunk(s
, chunk_data_size
, fd
, offset
,
226 chunk_header
->chunk_sz
, cur_block
, crc_ptr
);
228 verbose_error(s
->verbose
, ret
, "data block at %lld", offset
);
231 return chunk_header
->chunk_sz
;
232 case CHUNK_TYPE_FILL
:
233 ret
= process_fill_chunk(s
, chunk_data_size
, fd
,
234 chunk_header
->chunk_sz
, cur_block
, crc_ptr
);
236 verbose_error(s
->verbose
, ret
, "fill block at %lld", offset
);
239 return chunk_header
->chunk_sz
;
240 case CHUNK_TYPE_DONT_CARE
:
241 ret
= process_skip_chunk(s
, chunk_data_size
, fd
,
242 chunk_header
->chunk_sz
, cur_block
, crc_ptr
);
243 if (chunk_data_size
!= 0) {
245 verbose_error(s
->verbose
, ret
, "skip block at %lld", offset
);
249 return chunk_header
->chunk_sz
;
250 case CHUNK_TYPE_CRC32
:
251 ret
= process_crc32_chunk(fd
, chunk_data_size
, *crc_ptr
);
253 verbose_error(s
->verbose
, -EINVAL
, "crc block at %lld",
259 verbose_error(s
->verbose
, -EINVAL
, "unknown block %04X at %lld",
260 chunk_header
->chunk_type
, offset
);
266 static int sparse_file_read_sparse(struct sparse_file
*s
, int fd
, bool crc
)
270 sparse_header_t sparse_header
;
271 chunk_header_t chunk_header
;
273 uint32_t *crc_ptr
= 0;
274 unsigned int cur_block
= 0;
278 copybuf
= malloc(COPY_BUF_SIZE
);
289 ret
= read_all(fd
, &sparse_header
, sizeof(sparse_header
));
294 if (sparse_header
.magic
!= SPARSE_HEADER_MAGIC
) {
298 if (sparse_header
.major_version
!= SPARSE_HEADER_MAJOR_VER
) {
302 if (sparse_header
.file_hdr_sz
< SPARSE_HEADER_LEN
) {
306 if (sparse_header
.chunk_hdr_sz
< sizeof(chunk_header
)) {
310 if (sparse_header
.file_hdr_sz
> SPARSE_HEADER_LEN
) {
311 /* Skip the remaining bytes in a header that is longer than
314 lseek(fd
, sparse_header
.file_hdr_sz
- SPARSE_HEADER_LEN
, SEEK_CUR
);
317 for (i
= 0; i
< sparse_header
.total_chunks
; i
++) {
318 ret
= read_all(fd
, &chunk_header
, sizeof(chunk_header
));
323 if (sparse_header
.chunk_hdr_sz
> CHUNK_HEADER_LEN
) {
324 /* Skip the remaining bytes in a header that is longer than
327 lseek(fd
, sparse_header
.chunk_hdr_sz
- CHUNK_HEADER_LEN
, SEEK_CUR
);
330 offset
= lseek(fd
, 0, SEEK_CUR
);
332 ret
= process_chunk(s
, fd
, offset
, sparse_header
.chunk_hdr_sz
, &chunk_header
,
341 if (sparse_header
.total_blks
!= cur_block
) {
348 static int sparse_file_read_normal(struct sparse_file
*s
, int fd
)
351 uint32_t *buf
= malloc(s
->block_size
);
352 unsigned int block
= 0;
353 int64_t remain
= s
->len
;
355 unsigned int to_read
;
364 to_read
= min(remain
, s
->block_size
);
365 ret
= read_all(fd
, buf
, to_read
);
367 error("failed to read sparse file");
371 if (to_read
== s
->block_size
) {
373 for (i
= 1; i
< s
->block_size
/ sizeof(uint32_t); i
++) {
374 if (buf
[0] != buf
[i
]) {
375 sparse_block
= false;
380 sparse_block
= false;
384 /* TODO: add flag to use skip instead of fill for buf[0] == 0 */
385 sparse_file_add_fill(s
, buf
[0], to_read
, block
);
387 sparse_file_add_fd(s
, fd
, offset
, to_read
, block
);
398 int sparse_file_read(struct sparse_file
*s
, int fd
, bool sparse
, bool crc
)
400 if (crc
&& !sparse
) {
405 return sparse_file_read_sparse(s
, fd
, crc
);
407 return sparse_file_read_normal(s
, fd
);
411 struct sparse_file
*sparse_file_import(int fd
, bool verbose
, bool crc
)
414 sparse_header_t sparse_header
;
416 struct sparse_file
*s
;
418 ret
= read_all(fd
, &sparse_header
, sizeof(sparse_header
));
420 verbose_error(verbose
, ret
, "header");
424 if (sparse_header
.magic
!= SPARSE_HEADER_MAGIC
) {
425 verbose_error(verbose
, -EINVAL
, "header magic");
429 if (sparse_header
.major_version
!= SPARSE_HEADER_MAJOR_VER
) {
430 verbose_error(verbose
, -EINVAL
, "header major version");
434 if (sparse_header
.file_hdr_sz
< SPARSE_HEADER_LEN
) {
438 if (sparse_header
.chunk_hdr_sz
< sizeof(chunk_header_t
)) {
442 len
= (int64_t)sparse_header
.total_blks
* sparse_header
.blk_sz
;
443 s
= sparse_file_new(sparse_header
.blk_sz
, len
);
445 verbose_error(verbose
, -EINVAL
, NULL
);
449 ret
= lseek(fd
, 0, SEEK_SET
);
451 verbose_error(verbose
, ret
, "seeking");
452 sparse_file_destroy(s
);
456 s
->verbose
= verbose
;
458 ret
= sparse_file_read(s
, fd
, true, crc
);
460 sparse_file_destroy(s
);
467 struct sparse_file
*sparse_file_import_auto(int fd
, bool crc
, bool verbose
)
469 struct sparse_file
*s
;
473 s
= sparse_file_import(fd
, verbose
, crc
);
478 len
= lseek(fd
, 0, SEEK_END
);
483 lseek(fd
, 0, SEEK_SET
);
485 s
= sparse_file_new(4096, len
);
490 ret
= sparse_file_read_normal(s
, fd
);
492 sparse_file_destroy(s
);