blob: 0f39172e256c0e27608c3ebe4c46659734e4a400 [file] [log] [blame]
Colin Cross0c4c47f2012-04-25 19:02:58 -07001/*
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
Colin Cross0c4c47f2012-04-25 19:02:58 -070017#define _FILE_OFFSET_BITS 64
18#define _LARGEFILE64_SOURCE 1
19
20#include <fcntl.h>
Jerry Zhang7b444f02018-06-12 16:42:09 -070021#include <inttypes.h>
Colin Cross0c4c47f2012-04-25 19:02:58 -070022#include <stdarg.h>
Colin Cross0c4c47f2012-04-25 19:02:58 -070023#include <stdint.h>
24#include <stdio.h>
25#include <stdlib.h>
Xiaolei Yuc39caaf2017-10-11 14:46:29 +080026#include <string.h>
Colin Cross0c4c47f2012-04-25 19:02:58 -070027#include <unistd.h>
Jerry Zhang7b444f02018-06-12 16:42:09 -070028#include <algorithm>
29#include <string>
Colin Cross0c4c47f2012-04-25 19:02:58 -070030
31#include <sparse/sparse.h>
32
Chris Friesa7eeb222017-04-17 21:53:16 -050033#include "android-base/stringprintf.h"
Mark Salyzyn031a7482014-02-27 16:56:15 -080034#include "defs.h"
35#include "output_file.h"
Colin Cross0c4c47f2012-04-25 19:02:58 -070036#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
Jerry Zhang7b444f02018-06-12 16:42:09 -070046#define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
Colin Cross0c4c47f2012-04-25 19:02:58 -070047#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
48
Chris Friesa7eeb222017-04-17 21:53:16 -050049static constexpr int64_t COPY_BUF_SIZE = 1024 * 1024;
Jerry Zhang7b444f02018-06-12 16:42:09 -070050static char* copybuf;
Colin Cross0c4c47f2012-04-25 19:02:58 -070051
Jerry Zhang7b444f02018-06-12 16:42:09 -070052static 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);
Chris Friesa7eeb222017-04-17 21:53:16 -050057}
Colin Cross0c4c47f2012-04-25 19:02:58 -070058
Jerry Zhang50e60292018-06-05 11:44:52 -070059class SparseFileSource {
Jerry Zhang7b444f02018-06-12 16:42:09 -070060 public:
Keith Moka3b72062021-12-31 05:09:32 +000061 /* Seeks the source ahead by the given offset.
62 * Return 0 if successful. */
63 virtual int Seek(int64_t offset) = 0;
Jerry Zhang50e60292018-06-05 11:44:52 -070064
Jerry Zhang7b444f02018-06-12 16:42:09 -070065 /* Return the current offset. */
66 virtual int64_t GetOffset() = 0;
Jerry Zhang50e60292018-06-05 11:44:52 -070067
Keith Moka3b72062021-12-31 05:09:32 +000068 /* Rewind to beginning. Return 0 if successful. */
69 virtual int Rewind() = 0;
Jerry Zhang50e60292018-06-05 11:44:52 -070070
Jerry Zhang7b444f02018-06-12 16:42:09 -070071 /* 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;
Jerry Zhang50e60292018-06-05 11:44:52 -070074
Jerry Zhang7b444f02018-06-12 16:42:09 -070075 /* 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;
Jerry Zhang50e60292018-06-05 11:44:52 -070077
Jerry Zhang7b444f02018-06-12 16:42:09 -070078 /* 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;
Jerry Zhang50e60292018-06-05 11:44:52 -070080
Jerry Zhang7b444f02018-06-12 16:42:09 -070081 virtual ~SparseFileSource(){};
Jerry Zhang50e60292018-06-05 11:44:52 -070082};
83
84class SparseFileFdSource : public SparseFileSource {
Jerry Zhang7b444f02018-06-12 16:42:09 -070085 private:
86 int fd;
Jerry Zhang50e60292018-06-05 11:44:52 -070087
Jerry Zhang7b444f02018-06-12 16:42:09 -070088 public:
89 SparseFileFdSource(int fd) : fd(fd) {}
90 ~SparseFileFdSource() override {}
Jerry Zhang50e60292018-06-05 11:44:52 -070091
Keith Moka3b72062021-12-31 05:09:32 +000092 int Seek(int64_t off) override {
93 return lseek64(fd, off, SEEK_CUR) != -1 ? 0 : -errno;
94 }
Jerry Zhang50e60292018-06-05 11:44:52 -070095
Jerry Zhang7b444f02018-06-12 16:42:09 -070096 int64_t GetOffset() override { return lseek64(fd, 0, SEEK_CUR); }
Jerry Zhang50e60292018-06-05 11:44:52 -070097
Keith Moka3b72062021-12-31 05:09:32 +000098 int Rewind() override {
99 return lseek64(fd, 0, SEEK_SET) == 0 ? 0 : -errno;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700100 }
Jerry Zhang50e60292018-06-05 11:44:52 -0700101
Jerry Zhang7b444f02018-06-12 16:42:09 -0700102 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 }
Jerry Zhang50e60292018-06-05 11:44:52 -0700105
Jerry Zhang7b444f02018-06-12 16:42:09 -0700106 int ReadValue(void* ptr, int len) override { return read_all(fd, ptr, len); }
107
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 }
Jerry Zhang50e60292018-06-05 11:44:52 -0700122};
123
124class SparseFileBufSource : public SparseFileSource {
Jerry Zhang7b444f02018-06-12 16:42:09 -0700125 private:
Keith Moka3b72062021-12-31 05:09:32 +0000126 char* buf_start;
127 char* buf_end;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700128 char* buf;
129 int64_t offset;
Jerry Zhang50e60292018-06-05 11:44:52 -0700130
Keith Moka3b72062021-12-31 05:09:32 +0000131 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
Jerry Zhang7b444f02018-06-12 16:42:09 -0700140 public:
Keith Moka3b72062021-12-31 05:09:32 +0000141 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 }
Jerry Zhang7b444f02018-06-12 16:42:09 -0700147 ~SparseFileBufSource() override {}
Jerry Zhang50e60292018-06-05 11:44:52 -0700148
Keith Moka3b72062021-12-31 05:09:32 +0000149 int Seek(int64_t off) override {
150 int ret = AccessOkay(off);
151 if (ret < 0) {
152 return ret;
153 }
Jerry Zhang7b444f02018-06-12 16:42:09 -0700154 buf += off;
155 offset += off;
Keith Moka3b72062021-12-31 05:09:32 +0000156 return 0;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700157 }
Jerry Zhang50e60292018-06-05 11:44:52 -0700158
Jerry Zhang7b444f02018-06-12 16:42:09 -0700159 int64_t GetOffset() override { return offset; }
Jerry Zhang50e60292018-06-05 11:44:52 -0700160
Keith Moka3b72062021-12-31 05:09:32 +0000161 int Rewind() override {
162 buf = buf_start;
163 offset = 0;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700164 return 0;
165 }
Jerry Zhang50e60292018-06-05 11:44:52 -0700166
Jerry Zhang7b444f02018-06-12 16:42:09 -0700167 int AddToSparseFile(struct sparse_file* s, int64_t len, unsigned int block) override {
Keith Moka3b72062021-12-31 05:09:32 +0000168 int ret = AccessOkay(len);
169 if (ret < 0) {
170 return ret;
171 }
Jerry Zhang7b444f02018-06-12 16:42:09 -0700172 return sparse_file_add_data(s, buf, len, block);
173 }
Jerry Zhang50e60292018-06-05 11:44:52 -0700174
Jerry Zhang7b444f02018-06-12 16:42:09 -0700175 int ReadValue(void* ptr, int len) override {
Keith Moka3b72062021-12-31 05:09:32 +0000176 int ret = AccessOkay(len);
177 if (ret < 0) {
178 return ret;
179 }
Jerry Zhang7b444f02018-06-12 16:42:09 -0700180 memcpy(ptr, buf, len);
Keith Moka3b72062021-12-31 05:09:32 +0000181 buf += len;
182 offset += len;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700183 return 0;
184 }
185
186 int GetCrc32(uint32_t* crc32, int64_t len) override {
Keith Moka3b72062021-12-31 05:09:32 +0000187 int ret = AccessOkay(len);
188 if (ret < 0) {
189 return ret;
190 }
Jerry Zhang7b444f02018-06-12 16:42:09 -0700191 *crc32 = sparse_crc32(*crc32, buf, len);
Keith Moka3b72062021-12-31 05:09:32 +0000192 buf += len;
193 offset += len;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700194 return 0;
195 }
Jerry Zhang50e60292018-06-05 11:44:52 -0700196};
197
Jerry Zhang7b444f02018-06-12 16:42:09 -0700198static void verbose_error(bool verbose, int err, const char* fmt, ...) {
199 if (!verbose) return;
Chris Friesa7eeb222017-04-17 21:53:16 -0500200
Jerry Zhang7b444f02018-06-12 16:42:09 -0700201 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());
Colin Cross0c4c47f2012-04-25 19:02:58 -0700210}
211
Jerry Zhang7b444f02018-06-12 16:42:09 -0700212static 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;
Keith Moka3b72062021-12-31 05:09:32 +0000216 int64_t len = (int64_t)blocks * s->block_size;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700217
Jerry Zhang7b444f02018-06-12 16:42:09 -0700218 if (chunk_size % s->block_size != 0) {
219 return -EINVAL;
220 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700221
Jerry Zhang7b444f02018-06-12 16:42:09 -0700222 if (chunk_size / s->block_size != blocks) {
223 return -EINVAL;
224 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700225
Jerry Zhang7b444f02018-06-12 16:42:09 -0700226 ret = source->AddToSparseFile(s, len, block);
227 if (ret < 0) {
228 return ret;
229 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700230
Jerry Zhang7b444f02018-06-12 16:42:09 -0700231 if (crc32) {
232 ret = source->GetCrc32(crc32, len);
233 if (ret < 0) {
234 return ret;
235 }
236 } else {
Keith Moka3b72062021-12-31 05:09:32 +0000237 ret = source->Seek(len);
238 if (ret < 0) {
239 return ret;
240 }
Jerry Zhang7b444f02018-06-12 16:42:09 -0700241 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700242
Jerry Zhang7b444f02018-06-12 16:42:09 -0700243 return 0;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700244}
245
Jerry Zhang7b444f02018-06-12 16:42:09 -0700246static 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;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700255
Jerry Zhang7b444f02018-06-12 16:42:09 -0700256 if (chunk_size != sizeof(fill_val)) {
257 return -EINVAL;
258 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700259
Jerry Zhang7b444f02018-06-12 16:42:09 -0700260 ret = source->ReadValue(&fill_val, sizeof(fill_val));
261 if (ret < 0) {
262 return ret;
263 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700264
Jerry Zhang7b444f02018-06-12 16:42:09 -0700265 ret = sparse_file_add_fill(s, fill_val, len, block);
266 if (ret < 0) {
267 return ret;
268 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700269
Jerry Zhang7b444f02018-06-12 16:42:09 -0700270 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 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700276
Jerry Zhang7b444f02018-06-12 16:42:09 -0700277 while (len) {
278 chunk = std::min(len, COPY_BUF_SIZE);
279 *crc32 = sparse_crc32(*crc32, copybuf, chunk);
280 len -= chunk;
281 }
282 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700283
Jerry Zhang7b444f02018-06-12 16:42:09 -0700284 return 0;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700285}
286
Jerry Zhang7b444f02018-06-12 16:42:09 -0700287static 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 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700293
Jerry Zhang7b444f02018-06-12 16:42:09 -0700294 if (crc32) {
295 int64_t len = (int64_t)blocks * s->block_size;
296 memset(copybuf, 0, COPY_BUF_SIZE);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700297
Jerry Zhang7b444f02018-06-12 16:42:09 -0700298 while (len) {
299 int chunk = std::min(len, COPY_BUF_SIZE);
300 *crc32 = sparse_crc32(*crc32, copybuf, chunk);
301 len -= chunk;
302 }
303 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700304
Jerry Zhang7b444f02018-06-12 16:42:09 -0700305 return 0;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700306}
307
Jerry Zhang7b444f02018-06-12 16:42:09 -0700308static int process_crc32_chunk(SparseFileSource* source, unsigned int chunk_size, uint32_t* crc32) {
309 uint32_t file_crc32;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700310
Jerry Zhang7b444f02018-06-12 16:42:09 -0700311 if (chunk_size != sizeof(file_crc32)) {
312 return -EINVAL;
313 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700314
Jerry Zhang7b444f02018-06-12 16:42:09 -0700315 int ret = source->ReadValue(&file_crc32, sizeof(file_crc32));
316 if (ret < 0) {
317 return ret;
318 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700319
Yi Kong17ba95e2018-07-23 16:31:11 -0700320 if (crc32 != nullptr && file_crc32 != *crc32) {
Jerry Zhang7b444f02018-06-12 16:42:09 -0700321 return -EINVAL;
322 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700323
Jerry Zhang7b444f02018-06-12 16:42:09 -0700324 return 0;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700325}
326
Jerry Zhang7b444f02018-06-12 16:42:09 -0700327static 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();
Colin Cross0c4c47f2012-04-25 19:02:58 -0700332
Jerry Zhang7b444f02018-06-12 16:42:09 -0700333 chunk_data_size = chunk_header->total_sz - chunk_hdr_sz;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700334
Jerry Zhang7b444f02018-06-12 16:42:09 -0700335 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 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700373
Jerry Zhang7b444f02018-06-12 16:42:09 -0700374 return 0;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700375}
376
Jerry Zhang7b444f02018-06-12 16:42:09 -0700377static 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;
Yi Kong17ba95e2018-07-23 16:31:11 -0700383 uint32_t* crc_ptr = nullptr;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700384 unsigned int cur_block = 0;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700385
Jerry Zhang7b444f02018-06-12 16:42:09 -0700386 if (!copybuf) {
387 copybuf = (char*)malloc(COPY_BUF_SIZE);
388 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700389
Jerry Zhang7b444f02018-06-12 16:42:09 -0700390 if (!copybuf) {
391 return -ENOMEM;
392 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700393
Jerry Zhang7b444f02018-06-12 16:42:09 -0700394 if (crc) {
395 crc_ptr = &crc32;
396 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700397
Jerry Zhang7b444f02018-06-12 16:42:09 -0700398 ret = source->ReadValue(&sparse_header, sizeof(sparse_header));
399 if (ret < 0) {
400 return ret;
401 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700402
Jerry Zhang7b444f02018-06-12 16:42:09 -0700403 if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
404 return -EINVAL;
405 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700406
Jerry Zhang7b444f02018-06-12 16:42:09 -0700407 if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
408 return -EINVAL;
409 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700410
Jerry Zhang7b444f02018-06-12 16:42:09 -0700411 if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
412 return -EINVAL;
413 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700414
Jerry Zhang7b444f02018-06-12 16:42:09 -0700415 if (sparse_header.chunk_hdr_sz < sizeof(chunk_header)) {
416 return -EINVAL;
417 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700418
Jerry Zhang7b444f02018-06-12 16:42:09 -0700419 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 */
Keith Moka3b72062021-12-31 05:09:32 +0000423 ret = source->Seek(sparse_header.file_hdr_sz - SPARSE_HEADER_LEN);
424 if (ret < 0) {
425 return ret;
426 }
Jerry Zhang7b444f02018-06-12 16:42:09 -0700427 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700428
Jerry Zhang7b444f02018-06-12 16:42:09 -0700429 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 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700434
Jerry Zhang7b444f02018-06-12 16:42:09 -0700435 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 */
Keith Moka3b72062021-12-31 05:09:32 +0000439 ret = source->Seek(sparse_header.chunk_hdr_sz - CHUNK_HEADER_LEN);
440 if (ret < 0) {
441 return ret;
442 }
Jerry Zhang7b444f02018-06-12 16:42:09 -0700443 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700444
Jerry Zhang7b444f02018-06-12 16:42:09 -0700445 ret = process_chunk(s, source, sparse_header.chunk_hdr_sz, &chunk_header, cur_block, crc_ptr);
446 if (ret < 0) {
447 return ret;
448 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700449
Jerry Zhang7b444f02018-06-12 16:42:09 -0700450 cur_block += ret;
451 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700452
Jerry Zhang7b444f02018-06-12 16:42:09 -0700453 if (sparse_header.total_blks != cur_block) {
454 return -EINVAL;
455 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700456
Jerry Zhang7b444f02018-06-12 16:42:09 -0700457 return 0;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700458}
459
Jerry Zhang7b444f02018-06-12 16:42:09 -0700460static int sparse_file_read_normal(struct sparse_file* s, int fd) {
461 int ret;
462 uint32_t* buf = (uint32_t*)malloc(s->block_size);
463 unsigned int block = 0;
464 int64_t remain = s->len;
465 int64_t offset = 0;
466 unsigned int to_read;
467 unsigned int i;
468 bool sparse_block;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700469
Jerry Zhang7b444f02018-06-12 16:42:09 -0700470 if (!buf) {
471 return -ENOMEM;
472 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700473
Jerry Zhang7b444f02018-06-12 16:42:09 -0700474 while (remain > 0) {
475 to_read = std::min(remain, (int64_t)(s->block_size));
476 ret = read_all(fd, buf, to_read);
477 if (ret < 0) {
478 error("failed to read sparse file");
479 free(buf);
480 return ret;
481 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700482
Jerry Zhang7b444f02018-06-12 16:42:09 -0700483 if (to_read == s->block_size) {
484 sparse_block = true;
485 for (i = 1; i < s->block_size / sizeof(uint32_t); i++) {
486 if (buf[0] != buf[i]) {
487 sparse_block = false;
488 break;
489 }
490 }
491 } else {
492 sparse_block = false;
493 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700494
Jerry Zhang7b444f02018-06-12 16:42:09 -0700495 if (sparse_block) {
496 /* TODO: add flag to use skip instead of fill for buf[0] == 0 */
497 sparse_file_add_fill(s, buf[0], to_read, block);
498 } else {
499 sparse_file_add_fd(s, fd, offset, to_read, block);
500 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700501
Jerry Zhang7b444f02018-06-12 16:42:09 -0700502 remain -= to_read;
503 offset += to_read;
504 block++;
505 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700506
Jerry Zhang7b444f02018-06-12 16:42:09 -0700507 free(buf);
508 return 0;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700509}
510
Jerry Zhang7b444f02018-06-12 16:42:09 -0700511int sparse_file_read(struct sparse_file* s, int fd, bool sparse, bool crc) {
512 if (crc && !sparse) {
513 return -EINVAL;
514 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700515
Jerry Zhang7b444f02018-06-12 16:42:09 -0700516 if (sparse) {
517 SparseFileFdSource source(fd);
518 return sparse_file_read_sparse(s, &source, crc);
519 } else {
520 return sparse_file_read_normal(s, fd);
521 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700522}
523
Jerry Zhang7b444f02018-06-12 16:42:09 -0700524static struct sparse_file* sparse_file_import_source(SparseFileSource* source, bool verbose,
525 bool crc) {
526 int ret;
527 sparse_header_t sparse_header;
528 int64_t len;
529 struct sparse_file* s;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700530
Jerry Zhang7b444f02018-06-12 16:42:09 -0700531 ret = source->ReadValue(&sparse_header, sizeof(sparse_header));
532 if (ret < 0) {
533 verbose_error(verbose, ret, "header");
Yi Kong17ba95e2018-07-23 16:31:11 -0700534 return nullptr;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700535 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700536
Jerry Zhang7b444f02018-06-12 16:42:09 -0700537 if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
538 verbose_error(verbose, -EINVAL, "header magic");
Yi Kong17ba95e2018-07-23 16:31:11 -0700539 return nullptr;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700540 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700541
Jerry Zhang7b444f02018-06-12 16:42:09 -0700542 if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
543 verbose_error(verbose, -EINVAL, "header major version");
Yi Kong17ba95e2018-07-23 16:31:11 -0700544 return nullptr;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700545 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700546
Jerry Zhang7b444f02018-06-12 16:42:09 -0700547 if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
Yi Kong17ba95e2018-07-23 16:31:11 -0700548 return nullptr;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700549 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700550
Jerry Zhang7b444f02018-06-12 16:42:09 -0700551 if (sparse_header.chunk_hdr_sz < sizeof(chunk_header_t)) {
Yi Kong17ba95e2018-07-23 16:31:11 -0700552 return nullptr;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700553 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700554
Keith Moka3b72062021-12-31 05:09:32 +0000555 if (!sparse_header.blk_sz || (sparse_header.blk_sz % 4)) {
556 return nullptr;
557 }
558
559 if (!sparse_header.total_blks) {
560 return nullptr;
561 }
562
Jerry Zhang7b444f02018-06-12 16:42:09 -0700563 len = (int64_t)sparse_header.total_blks * sparse_header.blk_sz;
564 s = sparse_file_new(sparse_header.blk_sz, len);
565 if (!s) {
Yi Kong17ba95e2018-07-23 16:31:11 -0700566 verbose_error(verbose, -EINVAL, nullptr);
567 return nullptr;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700568 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700569
Keith Moka3b72062021-12-31 05:09:32 +0000570 ret = source->Rewind();
Jerry Zhang7b444f02018-06-12 16:42:09 -0700571 if (ret < 0) {
572 verbose_error(verbose, ret, "seeking");
573 sparse_file_destroy(s);
Yi Kong17ba95e2018-07-23 16:31:11 -0700574 return nullptr;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700575 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700576
Jerry Zhang7b444f02018-06-12 16:42:09 -0700577 s->verbose = verbose;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700578
Jerry Zhang7b444f02018-06-12 16:42:09 -0700579 ret = sparse_file_read_sparse(s, source, crc);
580 if (ret < 0) {
581 sparse_file_destroy(s);
Yi Kong17ba95e2018-07-23 16:31:11 -0700582 return nullptr;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700583 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700584
Jerry Zhang7b444f02018-06-12 16:42:09 -0700585 return s;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700586}
587
Jerry Zhang7b444f02018-06-12 16:42:09 -0700588struct sparse_file* sparse_file_import(int fd, bool verbose, bool crc) {
589 SparseFileFdSource source(fd);
590 return sparse_file_import_source(&source, verbose, crc);
Jerry Zhang50e60292018-06-05 11:44:52 -0700591}
592
Keith Moka3b72062021-12-31 05:09:32 +0000593struct sparse_file* sparse_file_import_buf(char* buf, size_t len, bool verbose, bool crc) {
594 SparseFileBufSource source(buf, len);
Jerry Zhang7b444f02018-06-12 16:42:09 -0700595 return sparse_file_import_source(&source, verbose, crc);
Jerry Zhang50e60292018-06-05 11:44:52 -0700596}
597
Jerry Zhang7b444f02018-06-12 16:42:09 -0700598struct sparse_file* sparse_file_import_auto(int fd, bool crc, bool verbose) {
599 struct sparse_file* s;
600 int64_t len;
601 int ret;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700602
Jerry Zhang7b444f02018-06-12 16:42:09 -0700603 s = sparse_file_import(fd, verbose, crc);
604 if (s) {
605 return s;
606 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700607
Jerry Zhang7b444f02018-06-12 16:42:09 -0700608 len = lseek64(fd, 0, SEEK_END);
609 if (len < 0) {
Yi Kong17ba95e2018-07-23 16:31:11 -0700610 return nullptr;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700611 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700612
Jerry Zhang7b444f02018-06-12 16:42:09 -0700613 lseek64(fd, 0, SEEK_SET);
Colin Cross0c4c47f2012-04-25 19:02:58 -0700614
Jerry Zhang7b444f02018-06-12 16:42:09 -0700615 s = sparse_file_new(4096, len);
616 if (!s) {
Yi Kong17ba95e2018-07-23 16:31:11 -0700617 return nullptr;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700618 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700619
Jerry Zhang7b444f02018-06-12 16:42:09 -0700620 ret = sparse_file_read_normal(s, fd);
621 if (ret < 0) {
622 sparse_file_destroy(s);
Yi Kong17ba95e2018-07-23 16:31:11 -0700623 return nullptr;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700624 }
Colin Cross0c4c47f2012-04-25 19:02:58 -0700625
Jerry Zhang7b444f02018-06-12 16:42:09 -0700626 return s;
Colin Cross0c4c47f2012-04-25 19:02:58 -0700627}