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) 49static char *copybuf; 50 51#define min(a, b) \ 52 ({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; }) 53 54static 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 _WIN32 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 101static 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 139static 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 180static 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 202static 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 223static 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 275static 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 357static 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 409int 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 422struct 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 478struct 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