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
ErrorString(int err)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
verbose_error(bool verbose,int err,const char * fmt,...)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
process_raw_chunk(struct sparse_file * s,unsigned int chunk_size,int fd,int64_t offset,unsigned int blocks,unsigned int block,uint32_t * crc32)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
process_fill_chunk(struct sparse_file * s,unsigned int chunk_size,int fd,unsigned int blocks,unsigned int block,uint32_t * crc32)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
process_skip_chunk(struct sparse_file * s,unsigned int chunk_size,int fd __unused,unsigned int blocks,unsigned int block __unused,uint32_t * crc32)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
process_crc32_chunk(int fd,unsigned int chunk_size,uint32_t * crc32)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
process_chunk(struct sparse_file * s,int fd,off64_t offset,unsigned int chunk_hdr_sz,chunk_header_t * chunk_header,unsigned int cur_block,uint32_t * crc_ptr)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
sparse_file_read_sparse(struct sparse_file * s,int fd,bool crc)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
sparse_file_read_normal(struct sparse_file * s,int fd)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
sparse_file_read(struct sparse_file * s,int fd,bool sparse,bool crc)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
sparse_file_import(int fd,bool verbose,bool crc)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
sparse_file_import_auto(int fd,bool crc,bool verbose)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