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 <fcntl.h>
21 #include <inttypes.h>
22 #include <stdarg.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <algorithm>
29 #include <string>
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 #if defined(__APPLE__) && defined(__MACH__)
41 #define lseek64 lseek
42 #define off64_t off_t
43 #endif
44
45 #define SPARSE_HEADER_MAJOR_VER 1
46 #define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
47 #define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
48
49 static constexpr int64_t COPY_BUF_SIZE = 1024 * 1024;
50 static char* copybuf;
51
ErrorString(int err)52 static std::string ErrorString(int err) {
53 if (err == -EOVERFLOW) return "EOF while reading file";
54 if (err == -EINVAL) return "Invalid sparse file format";
55 if (err == -ENOMEM) return "Failed allocation while reading file";
56 return android::base::StringPrintf("Unknown error %d", err);
57 }
58
59 class SparseFileSource {
60 public:
61 /* Seeks the source ahead by the given offset.
62 * Return 0 if successful. */
63 virtual int Seek(int64_t offset) = 0;
64
65 /* Return the current offset. */
66 virtual int64_t GetOffset() = 0;
67
68 /* Rewind to beginning. Return 0 if successful. */
69 virtual int Rewind() = 0;
70
71 /* Adds the given length from the current offset of the source to the file at the given block.
72 * Return 0 if successful. */
73 virtual int AddToSparseFile(struct sparse_file* s, int64_t len, unsigned int block) = 0;
74
75 /* Get data of fixed size from the current offset and seek len bytes. Return 0 if successful. */
76 virtual int ReadValue(void* ptr, int len) = 0;
77
78 /* Find the crc32 of the next len bytes and seek ahead len bytes. Return 0 if successful. */
79 virtual int GetCrc32(uint32_t* crc32, int64_t len) = 0;
80
~SparseFileSource()81 virtual ~SparseFileSource(){};
82 };
83
84 class SparseFileFdSource : public SparseFileSource {
85 private:
86 int fd;
87
88 public:
SparseFileFdSource(int fd)89 SparseFileFdSource(int fd) : fd(fd) {}
~SparseFileFdSource()90 ~SparseFileFdSource() override {}
91
Seek(int64_t off)92 int Seek(int64_t off) override {
93 return lseek64(fd, off, SEEK_CUR) != -1 ? 0 : -errno;
94 }
95
GetOffset()96 int64_t GetOffset() override { return lseek64(fd, 0, SEEK_CUR); }
97
Rewind()98 int Rewind() override {
99 return lseek64(fd, 0, SEEK_SET) == 0 ? 0 : -errno;
100 }
101
AddToSparseFile(struct sparse_file * s,int64_t len,unsigned int block)102 int AddToSparseFile(struct sparse_file* s, int64_t len, unsigned int block) override {
103 return sparse_file_add_fd(s, fd, GetOffset(), len, block);
104 }
105
ReadValue(void * ptr,int len)106 int ReadValue(void* ptr, int len) override { return read_all(fd, ptr, len); }
107
GetCrc32(uint32_t * crc32,int64_t len)108 int GetCrc32(uint32_t* crc32, int64_t len) override {
109 int chunk;
110 int ret;
111 while (len) {
112 chunk = std::min(len, COPY_BUF_SIZE);
113 ret = read_all(fd, copybuf, chunk);
114 if (ret < 0) {
115 return ret;
116 }
117 *crc32 = sparse_crc32(*crc32, copybuf, chunk);
118 len -= chunk;
119 }
120 return 0;
121 }
122 };
123
124 class SparseFileBufSource : public SparseFileSource {
125 private:
126 char* buf_start;
127 char* buf_end;
128 char* buf;
129 int64_t offset;
130
AccessOkay(int64_t len)131 int AccessOkay(int64_t len) {
132 if (len <= 0) return -EINVAL;
133 if (buf < buf_start) return -EOVERFLOW;
134 if (buf >= buf_end) return -EOVERFLOW;
135 if (len > buf_end - buf) return -EOVERFLOW;
136
137 return 0;
138 }
139
140 public:
SparseFileBufSource(char * buf,uint64_t len)141 SparseFileBufSource(char* buf, uint64_t len) {
142 this->buf = buf;
143 this->offset = 0;
144 this->buf_start = buf;
145 this->buf_end = buf + len;
146 }
~SparseFileBufSource()147 ~SparseFileBufSource() override {}
148
Seek(int64_t off)149 int Seek(int64_t off) override {
150 int ret = AccessOkay(off);
151 if (ret < 0) {
152 return ret;
153 }
154 buf += off;
155 offset += off;
156 return 0;
157 }
158
GetOffset()159 int64_t GetOffset() override { return offset; }
160
Rewind()161 int Rewind() override {
162 buf = buf_start;
163 offset = 0;
164 return 0;
165 }
166
AddToSparseFile(struct sparse_file * s,int64_t len,unsigned int block)167 int AddToSparseFile(struct sparse_file* s, int64_t len, unsigned int block) override {
168 int ret = AccessOkay(len);
169 if (ret < 0) {
170 return ret;
171 }
172 return sparse_file_add_data(s, buf, len, block);
173 }
174
ReadValue(void * ptr,int len)175 int ReadValue(void* ptr, int len) override {
176 int ret = AccessOkay(len);
177 if (ret < 0) {
178 return ret;
179 }
180 memcpy(ptr, buf, len);
181 buf += len;
182 offset += len;
183 return 0;
184 }
185
GetCrc32(uint32_t * crc32,int64_t len)186 int GetCrc32(uint32_t* crc32, int64_t len) override {
187 int ret = AccessOkay(len);
188 if (ret < 0) {
189 return ret;
190 }
191 *crc32 = sparse_crc32(*crc32, buf, len);
192 buf += len;
193 offset += len;
194 return 0;
195 }
196 };
197
verbose_error(bool verbose,int err,const char * fmt,...)198 static void verbose_error(bool verbose, int err, const char* fmt, ...) {
199 if (!verbose) return;
200
201 std::string msg = ErrorString(err);
202 if (fmt) {
203 msg += " at ";
204 va_list argp;
205 va_start(argp, fmt);
206 android::base::StringAppendV(&msg, fmt, argp);
207 va_end(argp);
208 }
209 sparse_print_verbose("%s\n", msg.c_str());
210 }
211
process_raw_chunk(struct sparse_file * s,unsigned int chunk_size,SparseFileSource * source,unsigned int blocks,unsigned int block,uint32_t * crc32)212 static int process_raw_chunk(struct sparse_file* s, unsigned int chunk_size,
213 SparseFileSource* source, unsigned int blocks, unsigned int block,
214 uint32_t* crc32) {
215 int ret;
216 int64_t len = (int64_t)blocks * s->block_size;
217
218 if (chunk_size % s->block_size != 0) {
219 return -EINVAL;
220 }
221
222 if (chunk_size / s->block_size != blocks) {
223 return -EINVAL;
224 }
225
226 ret = source->AddToSparseFile(s, len, block);
227 if (ret < 0) {
228 return ret;
229 }
230
231 if (crc32) {
232 ret = source->GetCrc32(crc32, len);
233 if (ret < 0) {
234 return ret;
235 }
236 } else {
237 ret = source->Seek(len);
238 if (ret < 0) {
239 return ret;
240 }
241 }
242
243 return 0;
244 }
245
process_fill_chunk(struct sparse_file * s,unsigned int chunk_size,SparseFileSource * source,unsigned int blocks,unsigned int block,uint32_t * crc32)246 static int process_fill_chunk(struct sparse_file* s, unsigned int chunk_size,
247 SparseFileSource* source, unsigned int blocks, unsigned int block,
248 uint32_t* crc32) {
249 int ret;
250 int chunk;
251 int64_t len = (int64_t)blocks * s->block_size;
252 uint32_t fill_val;
253 uint32_t* fillbuf;
254 unsigned int i;
255
256 if (chunk_size != sizeof(fill_val)) {
257 return -EINVAL;
258 }
259
260 ret = source->ReadValue(&fill_val, sizeof(fill_val));
261 if (ret < 0) {
262 return ret;
263 }
264
265 ret = sparse_file_add_fill(s, fill_val, len, block);
266 if (ret < 0) {
267 return ret;
268 }
269
270 if (crc32) {
271 /* Fill copy_buf with the fill value */
272 fillbuf = (uint32_t*)copybuf;
273 for (i = 0; i < (COPY_BUF_SIZE / sizeof(fill_val)); i++) {
274 fillbuf[i] = fill_val;
275 }
276
277 while (len) {
278 chunk = std::min(len, COPY_BUF_SIZE);
279 *crc32 = sparse_crc32(*crc32, copybuf, chunk);
280 len -= chunk;
281 }
282 }
283
284 return 0;
285 }
286
process_skip_chunk(struct sparse_file * s,unsigned int chunk_size,SparseFileSource * source __unused,unsigned int blocks,unsigned int block __unused,uint32_t * crc32)287 static int process_skip_chunk(struct sparse_file* s, unsigned int chunk_size,
288 SparseFileSource* source __unused, unsigned int blocks,
289 unsigned int block __unused, uint32_t* crc32) {
290 if (chunk_size != 0) {
291 return -EINVAL;
292 }
293
294 if (crc32) {
295 int64_t len = (int64_t)blocks * s->block_size;
296 memset(copybuf, 0, COPY_BUF_SIZE);
297
298 while (len) {
299 int chunk = std::min(len, COPY_BUF_SIZE);
300 *crc32 = sparse_crc32(*crc32, copybuf, chunk);
301 len -= chunk;
302 }
303 }
304
305 return 0;
306 }
307
process_crc32_chunk(SparseFileSource * source,unsigned int chunk_size,uint32_t * crc32)308 static int process_crc32_chunk(SparseFileSource* source, unsigned int chunk_size, uint32_t* crc32) {
309 uint32_t file_crc32;
310
311 if (chunk_size != sizeof(file_crc32)) {
312 return -EINVAL;
313 }
314
315 int ret = source->ReadValue(&file_crc32, sizeof(file_crc32));
316 if (ret < 0) {
317 return ret;
318 }
319
320 if (crc32 != nullptr && file_crc32 != *crc32) {
321 return -EINVAL;
322 }
323
324 return 0;
325 }
326
process_chunk(struct sparse_file * s,SparseFileSource * source,unsigned int chunk_hdr_sz,chunk_header_t * chunk_header,unsigned int cur_block,uint32_t * crc_ptr)327 static int process_chunk(struct sparse_file* s, SparseFileSource* source, unsigned int chunk_hdr_sz,
328 chunk_header_t* chunk_header, unsigned int cur_block, uint32_t* crc_ptr) {
329 int ret;
330 unsigned int chunk_data_size;
331 int64_t offset = source->GetOffset();
332
333 chunk_data_size = chunk_header->total_sz - chunk_hdr_sz;
334
335 switch (chunk_header->chunk_type) {
336 case CHUNK_TYPE_RAW:
337 ret =
338 process_raw_chunk(s, chunk_data_size, source, chunk_header->chunk_sz, cur_block, crc_ptr);
339 if (ret < 0) {
340 verbose_error(s->verbose, ret, "data block at %" PRId64, offset);
341 return ret;
342 }
343 return chunk_header->chunk_sz;
344 case CHUNK_TYPE_FILL:
345 ret = process_fill_chunk(s, chunk_data_size, source, chunk_header->chunk_sz, cur_block,
346 crc_ptr);
347 if (ret < 0) {
348 verbose_error(s->verbose, ret, "fill block at %" PRId64, offset);
349 return ret;
350 }
351 return chunk_header->chunk_sz;
352 case CHUNK_TYPE_DONT_CARE:
353 ret = process_skip_chunk(s, chunk_data_size, source, chunk_header->chunk_sz, cur_block,
354 crc_ptr);
355 if (chunk_data_size != 0) {
356 if (ret < 0) {
357 verbose_error(s->verbose, ret, "skip block at %" PRId64, offset);
358 return ret;
359 }
360 }
361 return chunk_header->chunk_sz;
362 case CHUNK_TYPE_CRC32:
363 ret = process_crc32_chunk(source, chunk_data_size, crc_ptr);
364 if (ret < 0) {
365 verbose_error(s->verbose, -EINVAL, "crc block at %" PRId64, offset);
366 return ret;
367 }
368 return 0;
369 default:
370 verbose_error(s->verbose, -EINVAL, "unknown block %04X at %" PRId64, chunk_header->chunk_type,
371 offset);
372 }
373
374 return 0;
375 }
376
sparse_file_read_sparse(struct sparse_file * s,SparseFileSource * source,bool crc)377 static int sparse_file_read_sparse(struct sparse_file* s, SparseFileSource* source, bool crc) {
378 int ret;
379 unsigned int i;
380 sparse_header_t sparse_header;
381 chunk_header_t chunk_header;
382 uint32_t crc32 = 0;
383 uint32_t* crc_ptr = nullptr;
384 unsigned int cur_block = 0;
385
386 if (!copybuf) {
387 copybuf = (char*)malloc(COPY_BUF_SIZE);
388 }
389
390 if (!copybuf) {
391 return -ENOMEM;
392 }
393
394 if (crc) {
395 crc_ptr = &crc32;
396 }
397
398 ret = source->ReadValue(&sparse_header, sizeof(sparse_header));
399 if (ret < 0) {
400 return ret;
401 }
402
403 if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
404 return -EINVAL;
405 }
406
407 if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
408 return -EINVAL;
409 }
410
411 if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
412 return -EINVAL;
413 }
414
415 if (sparse_header.chunk_hdr_sz < sizeof(chunk_header)) {
416 return -EINVAL;
417 }
418
419 if (sparse_header.file_hdr_sz > SPARSE_HEADER_LEN) {
420 /* Skip the remaining bytes in a header that is longer than
421 * we expected.
422 */
423 ret = source->Seek(sparse_header.file_hdr_sz - SPARSE_HEADER_LEN);
424 if (ret < 0) {
425 return ret;
426 }
427 }
428
429 for (i = 0; i < sparse_header.total_chunks; i++) {
430 ret = source->ReadValue(&chunk_header, sizeof(chunk_header));
431 if (ret < 0) {
432 return ret;
433 }
434
435 if (sparse_header.chunk_hdr_sz > CHUNK_HEADER_LEN) {
436 /* Skip the remaining bytes in a header that is longer than
437 * we expected.
438 */
439 ret = source->Seek(sparse_header.chunk_hdr_sz - CHUNK_HEADER_LEN);
440 if (ret < 0) {
441 return ret;
442 }
443 }
444
445 ret = process_chunk(s, source, sparse_header.chunk_hdr_sz, &chunk_header, cur_block, crc_ptr);
446 if (ret < 0) {
447 return ret;
448 }
449
450 cur_block += ret;
451 }
452
453 if (sparse_header.total_blks != cur_block) {
454 return -EINVAL;
455 }
456
457 return 0;
458 }
459
do_sparse_file_read_normal(struct sparse_file * s,int fd,uint32_t * buf,int64_t offset,int64_t remain)460 static int do_sparse_file_read_normal(struct sparse_file* s, int fd, uint32_t* buf, int64_t offset,
461 int64_t remain) {
462 int ret;
463 unsigned int block = offset / s->block_size;
464 unsigned int to_read;
465 unsigned int i;
466 bool sparse_block;
467
468 if (!buf) {
469 return -ENOMEM;
470 }
471
472 while (remain > 0) {
473 to_read = std::min(remain, (int64_t)(s->block_size));
474 ret = read_all(fd, buf, to_read);
475 if (ret < 0) {
476 error("failed to read sparse file");
477 return ret;
478 }
479
480 if (to_read == s->block_size) {
481 sparse_block = true;
482 for (i = 1; i < s->block_size / sizeof(uint32_t); i++) {
483 if (buf[0] != buf[i]) {
484 sparse_block = false;
485 break;
486 }
487 }
488 } else {
489 sparse_block = false;
490 }
491
492 if (sparse_block) {
493 /* TODO: add flag to use skip instead of fill for buf[0] == 0 */
494 sparse_file_add_fill(s, buf[0], to_read, block);
495 } else {
496 sparse_file_add_fd(s, fd, offset, to_read, block);
497 }
498
499 remain -= to_read;
500 offset += to_read;
501 block++;
502 }
503
504 return 0;
505 }
506
sparse_file_read_normal(struct sparse_file * s,int fd)507 static int sparse_file_read_normal(struct sparse_file* s, int fd) {
508 int ret;
509 uint32_t* buf = (uint32_t*)malloc(s->block_size);
510
511 if (!buf)
512 return -ENOMEM;
513
514 ret = do_sparse_file_read_normal(s, fd, buf, 0, s->len);
515 free(buf);
516 return ret;
517 }
518
519 #ifdef __linux__
sparse_file_read_hole(struct sparse_file * s,int fd)520 static int sparse_file_read_hole(struct sparse_file* s, int fd) {
521 int ret;
522 uint32_t* buf = (uint32_t*)malloc(s->block_size);
523 int64_t end = 0;
524 int64_t start = 0;
525
526 if (!buf) {
527 return -ENOMEM;
528 }
529
530 do {
531 start = lseek(fd, end, SEEK_DATA);
532 if (start < 0) {
533 if (errno == ENXIO)
534 /* The rest of the file is a hole */
535 break;
536
537 error("could not seek to data");
538 free(buf);
539 return -errno;
540 } else if (start > s->len) {
541 break;
542 }
543
544 end = lseek(fd, start, SEEK_HOLE);
545 if (end < 0) {
546 error("could not seek to end");
547 free(buf);
548 return -errno;
549 }
550 end = std::min(end, s->len);
551
552 start = ALIGN_DOWN(start, s->block_size);
553 end = ALIGN(end, s->block_size);
554 if (lseek(fd, start, SEEK_SET) < 0) {
555 free(buf);
556 return -errno;
557 }
558
559 ret = do_sparse_file_read_normal(s, fd, buf, start, end - start);
560 if (ret) {
561 free(buf);
562 return ret;
563 }
564 } while (end < s->len);
565
566 free(buf);
567 return 0;
568 }
569 #else
sparse_file_read_hole(struct sparse_file * s __unused,int fd __unused)570 static int sparse_file_read_hole(struct sparse_file* s __unused, int fd __unused) {
571 return -ENOTSUP;
572 }
573 #endif
574
sparse_file_read(struct sparse_file * s,int fd,enum sparse_read_mode mode,bool crc)575 int sparse_file_read(struct sparse_file* s, int fd, enum sparse_read_mode mode, bool crc) {
576 if (crc && mode != SPARSE_READ_MODE_SPARSE) {
577 return -EINVAL;
578 }
579
580 switch (mode) {
581 case SPARSE_READ_MODE_SPARSE: {
582 SparseFileFdSource source(fd);
583 return sparse_file_read_sparse(s, &source, crc);
584 }
585 case SPARSE_READ_MODE_NORMAL:
586 return sparse_file_read_normal(s, fd);
587 case SPARSE_READ_MODE_HOLE:
588 return sparse_file_read_hole(s, fd);
589 default:
590 return -EINVAL;
591 }
592 }
593
sparse_file_import_source(SparseFileSource * source,bool verbose,bool crc)594 static struct sparse_file* sparse_file_import_source(SparseFileSource* source, bool verbose,
595 bool crc) {
596 int ret;
597 sparse_header_t sparse_header;
598 int64_t len;
599 struct sparse_file* s;
600
601 ret = source->ReadValue(&sparse_header, sizeof(sparse_header));
602 if (ret < 0) {
603 verbose_error(verbose, ret, "header");
604 return nullptr;
605 }
606
607 if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
608 verbose_error(verbose, -EINVAL, "header magic");
609 return nullptr;
610 }
611
612 if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
613 verbose_error(verbose, -EINVAL, "header major version");
614 return nullptr;
615 }
616
617 if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
618 return nullptr;
619 }
620
621 if (sparse_header.chunk_hdr_sz < sizeof(chunk_header_t)) {
622 return nullptr;
623 }
624
625 if (!sparse_header.blk_sz || (sparse_header.blk_sz % 4)) {
626 return nullptr;
627 }
628
629 if (!sparse_header.total_blks) {
630 return nullptr;
631 }
632
633 len = (int64_t)sparse_header.total_blks * sparse_header.blk_sz;
634 s = sparse_file_new(sparse_header.blk_sz, len);
635 if (!s) {
636 verbose_error(verbose, -EINVAL, nullptr);
637 return nullptr;
638 }
639
640 ret = source->Rewind();
641 if (ret < 0) {
642 verbose_error(verbose, ret, "seeking");
643 sparse_file_destroy(s);
644 return nullptr;
645 }
646
647 s->verbose = verbose;
648
649 ret = sparse_file_read_sparse(s, source, crc);
650 if (ret < 0) {
651 sparse_file_destroy(s);
652 return nullptr;
653 }
654
655 return s;
656 }
657
sparse_file_import(int fd,bool verbose,bool crc)658 struct sparse_file* sparse_file_import(int fd, bool verbose, bool crc) {
659 SparseFileFdSource source(fd);
660 return sparse_file_import_source(&source, verbose, crc);
661 }
662
sparse_file_import_buf(char * buf,size_t len,bool verbose,bool crc)663 struct sparse_file* sparse_file_import_buf(char* buf, size_t len, bool verbose, bool crc) {
664 SparseFileBufSource source(buf, len);
665 return sparse_file_import_source(&source, verbose, crc);
666 }
667
sparse_file_import_auto(int fd,bool crc,bool verbose)668 struct sparse_file* sparse_file_import_auto(int fd, bool crc, bool verbose) {
669 struct sparse_file* s;
670 int64_t len;
671 int ret;
672
673 s = sparse_file_import(fd, false, crc);
674 if (s) {
675 return s;
676 }
677
678 len = lseek64(fd, 0, SEEK_END);
679 if (len < 0) {
680 return nullptr;
681 }
682
683 lseek64(fd, 0, SEEK_SET);
684
685 s = sparse_file_new(4096, len);
686 if (!s) {
687 return nullptr;
688 }
689 if (verbose) {
690 sparse_file_verbose(s);
691 }
692
693 ret = sparse_file_read_normal(s, fd);
694 if (ret < 0) {
695 sparse_file_destroy(s);
696 return nullptr;
697 }
698
699 return s;
700 }
701