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