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)
49 static char *copybuf;
50
51 #define min(a, b) \
52 ({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; })
53
verbose_error(bool verbose,int err,const char * fmt,...)54 static 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 USE_MINGW
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
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)101 static 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
process_fill_chunk(struct sparse_file * s,unsigned int chunk_size,int fd,unsigned int blocks,unsigned int block,uint32_t * crc32)139 static 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
process_skip_chunk(struct sparse_file * s,unsigned int chunk_size,int fd __unused,unsigned int blocks,unsigned int block __unused,uint32_t * crc32)180 static 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
process_crc32_chunk(int fd,unsigned int chunk_size,uint32_t * crc32)202 static 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
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)223 static 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
sparse_file_read_sparse(struct sparse_file * s,int fd,bool crc)275 static 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
sparse_file_read_normal(struct sparse_file * s,int fd)357 static 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
sparse_file_read(struct sparse_file * s,int fd,bool sparse,bool crc)409 int 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
sparse_file_import(int fd,bool verbose,bool crc)422 struct 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
sparse_file_import_auto(int fd,bool crc,bool verbose)478 struct 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