Home | History | Annotate | Download | only in libsparse
      1 /*
      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 
     17 #define _GNU_SOURCE
     18 #define _FILE_OFFSET_BITS 64
     19 #define _LARGEFILE64_SOURCE 1
     20 
     21 #include <fcntl.h>
     22 #include <stdarg.h>
     23 #include <stdbool.h>
     24 #include <stdint.h>
     25 #include <stdio.h>
     26 #include <stdlib.h>
     27 #include <string.h>
     28 #include <unistd.h>
     29 
     30 #include <sparse/sparse.h>
     31 
     32 #include "defs.h"
     33 #include "output_file.h"
     34 #include "sparse_crc32.h"
     35 #include "sparse_file.h"
     36 #include "sparse_format.h"
     37 
     38 #if defined(__APPLE__) && defined(__MACH__)
     39 #define lseek64 lseek
     40 #define off64_t off_t
     41 #endif
     42 
     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))
     46 
     47 #define COPY_BUF_SIZE (1024U*1024U)
     48 static char *copybuf;
     49 
     50 #define min(a, b) \
     51 	({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; })
     52 
     53 static void verbose_error(bool verbose, int err, const char *fmt, ...)
     54 {
     55 	char *s = "";
     56 	char *at = "";
     57 	if (fmt) {
     58 		va_list argp;
     59 		int size;
     60 
     61 		va_start(argp, fmt);
     62 		size = vsnprintf(NULL, 0, fmt, argp);
     63 		va_end(argp);
     64 
     65 		if (size < 0) {
     66 			return;
     67 		}
     68 
     69 		at = malloc(size + 1);
     70 		if (at == NULL) {
     71 			return;
     72 		}
     73 
     74 		va_start(argp, fmt);
     75 		vsnprintf(at, size, fmt, argp);
     76 		va_end(argp);
     77 		at[size] = 0;
     78 		s = " at ";
     79 	}
     80 	if (verbose) {
     81 #ifndef USE_MINGW
     82 		if (err == -EOVERFLOW) {
     83 			sparse_print_verbose("EOF while reading file%s%s\n", s, at);
     84 		} else
     85 #endif
     86 		if (err == -EINVAL) {
     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",
     90 					s, at);
     91 		} else {
     92 			sparse_print_verbose("Unknown error %d%s%s\n", err, s, at);
     93 		}
     94 	}
     95 	if (fmt) {
     96 		free(at);
     97 	}
     98 }
     99 
    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,
    102 		uint32_t *crc32)
    103 {
    104 	int ret;
    105 	int chunk;
    106 	unsigned int len = blocks * s->block_size;
    107 
    108 	if (chunk_size % s->block_size != 0) {
    109 		return -EINVAL;
    110 	}
    111 
    112 	if (chunk_size / s->block_size != blocks) {
    113 		return -EINVAL;
    114 	}
    115 
    116 	ret = sparse_file_add_fd(s, fd, offset, len, block);
    117 	if (ret < 0) {
    118 		return ret;
    119 	}
    120 
    121 	if (crc32) {
    122 		while (len) {
    123 			chunk = min(len, COPY_BUF_SIZE);
    124 			ret = read_all(fd, copybuf, chunk);
    125 			if (ret < 0) {
    126 				return ret;
    127 			}
    128 			*crc32 = sparse_crc32(*crc32, copybuf, chunk);
    129 			len -= chunk;
    130 		}
    131 	} else {
    132 		lseek64(fd, len, SEEK_CUR);
    133 	}
    134 
    135 	return 0;
    136 }
    137 
    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)
    140 {
    141 	int ret;
    142 	int chunk;
    143 	int64_t len = (int64_t)blocks * s->block_size;
    144 	uint32_t fill_val;
    145 	uint32_t *fillbuf;
    146 	unsigned int i;
    147 
    148 	if (chunk_size != sizeof(fill_val)) {
    149 		return -EINVAL;
    150 	}
    151 
    152 	ret = read_all(fd, &fill_val, sizeof(fill_val));
    153 	if (ret < 0) {
    154 		return ret;
    155 	}
    156 
    157 	ret = sparse_file_add_fill(s, fill_val, len, block);
    158 	if (ret < 0) {
    159 		return ret;
    160 	}
    161 
    162 	if (crc32) {
    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;
    167 		}
    168 
    169 		while (len) {
    170 			chunk = min(len, COPY_BUF_SIZE);
    171 			*crc32 = sparse_crc32(*crc32, copybuf, chunk);
    172 			len -= chunk;
    173 		}
    174 	}
    175 
    176 	return 0;
    177 }
    178 
    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)
    182 {
    183 	if (chunk_size != 0) {
    184 		return -EINVAL;
    185 	}
    186 
    187 	if (crc32) {
    188 	        int64_t len = (int64_t)blocks * s->block_size;
    189 		memset(copybuf, 0, COPY_BUF_SIZE);
    190 
    191 		while (len) {
    192 			int chunk = min(len, COPY_BUF_SIZE);
    193 			*crc32 = sparse_crc32(*crc32, copybuf, chunk);
    194 			len -= chunk;
    195 		}
    196 	}
    197 
    198 	return 0;
    199 }
    200 
    201 static int process_crc32_chunk(int fd, unsigned int chunk_size, uint32_t crc32)
    202 {
    203 	uint32_t file_crc32;
    204 	int ret;
    205 
    206 	if (chunk_size != sizeof(file_crc32)) {
    207 		return -EINVAL;
    208 	}
    209 
    210 	ret = read_all(fd, &file_crc32, sizeof(file_crc32));
    211 	if (ret < 0) {
    212 		return ret;
    213 	}
    214 
    215 	if (file_crc32 != crc32) {
    216 		return -EINVAL;
    217 	}
    218 
    219 	return 0;
    220 }
    221 
    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)
    225 {
    226 	int ret;
    227 	unsigned int chunk_data_size;
    228 
    229 	chunk_data_size = chunk_header->total_sz - chunk_hdr_sz;
    230 
    231 	switch (chunk_header->chunk_type) {
    232 		case CHUNK_TYPE_RAW:
    233 			ret = process_raw_chunk(s, chunk_data_size, fd, offset,
    234 					chunk_header->chunk_sz, cur_block, crc_ptr);
    235 			if (ret < 0) {
    236 				verbose_error(s->verbose, ret, "data block at %lld", offset);
    237 				return ret;
    238 			}
    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);
    243 			if (ret < 0) {
    244 				verbose_error(s->verbose, ret, "fill block at %lld", offset);
    245 				return ret;
    246 			}
    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) {
    252 				if (ret < 0) {
    253 					verbose_error(s->verbose, ret, "skip block at %lld", offset);
    254 					return ret;
    255 				}
    256 			}
    257 			return chunk_header->chunk_sz;
    258 		case CHUNK_TYPE_CRC32:
    259 			ret = process_crc32_chunk(fd, chunk_data_size, *crc_ptr);
    260 			if (ret < 0) {
    261 				verbose_error(s->verbose, -EINVAL, "crc block at %lld",
    262 						offset);
    263 				return ret;
    264 			}
    265 			return 0;
    266 		default:
    267 			verbose_error(s->verbose, -EINVAL, "unknown block %04X at %lld",
    268 					chunk_header->chunk_type, offset);
    269 	}
    270 
    271 	return 0;
    272 }
    273 
    274 static int sparse_file_read_sparse(struct sparse_file *s, int fd, bool crc)
    275 {
    276 	int ret;
    277 	unsigned int i;
    278 	sparse_header_t sparse_header;
    279 	chunk_header_t chunk_header;
    280 	uint32_t crc32 = 0;
    281 	uint32_t *crc_ptr = 0;
    282 	unsigned int cur_block = 0;
    283 	off64_t offset;
    284 
    285 	if (!copybuf) {
    286 		copybuf = malloc(COPY_BUF_SIZE);
    287 	}
    288 
    289 	if (!copybuf) {
    290 		return -ENOMEM;
    291 	}
    292 
    293 	if (crc) {
    294 		crc_ptr = &crc32;
    295 	}
    296 
    297 	ret = read_all(fd, &sparse_header, sizeof(sparse_header));
    298 	if (ret < 0) {
    299 		return ret;
    300 	}
    301 
    302 	if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
    303 		return -EINVAL;
    304 	}
    305 
    306 	if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
    307 		return -EINVAL;
    308 	}
    309 
    310 	if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
    311 		return -EINVAL;
    312 	}
    313 
    314 	if (sparse_header.chunk_hdr_sz < sizeof(chunk_header)) {
    315 		return -EINVAL;
    316 	}
    317 
    318 	if (sparse_header.file_hdr_sz > SPARSE_HEADER_LEN) {
    319 		/* Skip the remaining bytes in a header that is longer than
    320 		 * we expected.
    321 		 */
    322 		lseek64(fd, sparse_header.file_hdr_sz - SPARSE_HEADER_LEN, SEEK_CUR);
    323 	}
    324 
    325 	for (i = 0; i < sparse_header.total_chunks; i++) {
    326 		ret = read_all(fd, &chunk_header, sizeof(chunk_header));
    327 		if (ret < 0) {
    328 			return ret;
    329 		}
    330 
    331 		if (sparse_header.chunk_hdr_sz > CHUNK_HEADER_LEN) {
    332 			/* Skip the remaining bytes in a header that is longer than
    333 			 * we expected.
    334 			 */
    335 			lseek64(fd, sparse_header.chunk_hdr_sz - CHUNK_HEADER_LEN, SEEK_CUR);
    336 		}
    337 
    338 		offset = lseek64(fd, 0, SEEK_CUR);
    339 
    340 		ret = process_chunk(s, fd, offset, sparse_header.chunk_hdr_sz, &chunk_header,
    341 				cur_block, crc_ptr);
    342 		if (ret < 0) {
    343 			return ret;
    344 		}
    345 
    346 		cur_block += ret;
    347 	}
    348 
    349 	if (sparse_header.total_blks != cur_block) {
    350 		return -EINVAL;
    351 	}
    352 
    353 	return 0;
    354 }
    355 
    356 static int sparse_file_read_normal(struct sparse_file *s, int fd)
    357 {
    358 	int ret;
    359 	uint32_t *buf = malloc(s->block_size);
    360 	unsigned int block = 0;
    361 	int64_t remain = s->len;
    362 	int64_t offset = 0;
    363 	unsigned int to_read;
    364 	unsigned int i;
    365 	bool sparse_block;
    366 
    367 	if (!buf) {
    368 		return -ENOMEM;
    369 	}
    370 
    371 	while (remain > 0) {
    372 		to_read = min(remain, s->block_size);
    373 		ret = read_all(fd, buf, to_read);
    374 		if (ret < 0) {
    375 			error("failed to read sparse file");
    376 			return ret;
    377 		}
    378 
    379 		if (to_read == s->block_size) {
    380 			sparse_block = true;
    381 			for (i = 1; i < s->block_size / sizeof(uint32_t); i++) {
    382 				if (buf[0] != buf[i]) {
    383 					sparse_block = false;
    384 					break;
    385 				}
    386 			}
    387 		} else {
    388 			sparse_block = false;
    389 		}
    390 
    391 		if (sparse_block) {
    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);
    394 		} else {
    395 			sparse_file_add_fd(s, fd, offset, to_read, block);
    396 		}
    397 
    398 		remain -= to_read;
    399 		offset += to_read;
    400 		block++;
    401 	}
    402 
    403 	return 0;
    404 }
    405 
    406 int sparse_file_read(struct sparse_file *s, int fd, bool sparse, bool crc)
    407 {
    408 	if (crc && !sparse) {
    409 		return -EINVAL;
    410 	}
    411 
    412 	if (sparse) {
    413 		return sparse_file_read_sparse(s, fd, crc);
    414 	} else {
    415 		return sparse_file_read_normal(s, fd);
    416 	}
    417 }
    418 
    419 struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc)
    420 {
    421 	int ret;
    422 	sparse_header_t sparse_header;
    423 	int64_t len;
    424 	struct sparse_file *s;
    425 
    426 	ret = read_all(fd, &sparse_header, sizeof(sparse_header));
    427 	if (ret < 0) {
    428 		verbose_error(verbose, ret, "header");
    429 		return NULL;
    430 	}
    431 
    432 	if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
    433 		verbose_error(verbose, -EINVAL, "header magic");
    434 		return NULL;
    435 	}
    436 
    437 	if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
    438 		verbose_error(verbose, -EINVAL, "header major version");
    439 		return NULL;
    440 	}
    441 
    442 	if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
    443 		return NULL;
    444 	}
    445 
    446 	if (sparse_header.chunk_hdr_sz < sizeof(chunk_header_t)) {
    447 		return NULL;
    448 	}
    449 
    450 	len = (int64_t)sparse_header.total_blks * sparse_header.blk_sz;
    451 	s = sparse_file_new(sparse_header.blk_sz, len);
    452 	if (!s) {
    453 		verbose_error(verbose, -EINVAL, NULL);
    454 		return NULL;
    455 	}
    456 
    457 	ret = lseek64(fd, 0, SEEK_SET);
    458 	if (ret < 0) {
    459 		verbose_error(verbose, ret, "seeking");
    460 		sparse_file_destroy(s);
    461 		return NULL;
    462 	}
    463 
    464 	s->verbose = verbose;
    465 
    466 	ret = sparse_file_read(s, fd, true, crc);
    467 	if (ret < 0) {
    468 		sparse_file_destroy(s);
    469 		return NULL;
    470 	}
    471 
    472 	return s;
    473 }
    474 
    475 struct sparse_file *sparse_file_import_auto(int fd, bool crc, bool verbose)
    476 {
    477 	struct sparse_file *s;
    478 	int64_t len;
    479 	int ret;
    480 
    481 	s = sparse_file_import(fd, verbose, crc);
    482 	if (s) {
    483 		return s;
    484 	}
    485 
    486 	len = lseek64(fd, 0, SEEK_END);
    487 	if (len < 0) {
    488 		return NULL;
    489 	}
    490 
    491 	lseek64(fd, 0, SEEK_SET);
    492 
    493 	s = sparse_file_new(4096, len);
    494 	if (!s) {
    495 		return NULL;
    496 	}
    497 
    498 	ret = sparse_file_read_normal(s, fd);
    499 	if (ret < 0) {
    500 		sparse_file_destroy(s);
    501 		return NULL;
    502 	}
    503 
    504 	return s;
    505 }
    506