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