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