1a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner/*
2a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner * Copyright (C) 2012 The Android Open Source Project
3a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner *
4a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner * Licensed under the Apache License, Version 2.0 (the "License");
5a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner * you may not use this file except in compliance with the License.
6a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner * You may obtain a copy of the License at
7a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner *
8a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner *      http://www.apache.org/licenses/LICENSE-2.0
9a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner *
10a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner * Unless required by applicable law or agreed to in writing, software
11a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner * distributed under the License is distributed on an "AS IS" BASIS,
12a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner * See the License for the specific language governing permissions and
14a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner * limitations under the License.
15a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner */
16a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
17a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#define _GNU_SOURCE
18a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#define _FILE_OFFSET_BITS 64
19a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#define _LARGEFILE64_SOURCE 1
20a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
21a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#include <fcntl.h>
22a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#include <stdarg.h>
23a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#include <stdbool.h>
24a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#include <stdint.h>
25a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#include <stdio.h>
26a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#include <stdlib.h>
27a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#include <string.h>
28a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#include <unistd.h>
29a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
30a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#include <sparse/sparse.h>
31a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
32a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#include "defs.h"
33a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#include "output_file.h"
34a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#include "sparse_crc32.h"
35a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#include "sparse_file.h"
36a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#include "sparse_format.h"
37a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
38a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#if defined(__APPLE__) && defined(__MACH__)
39a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#define lseek64 lseek
40a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#define off64_t off_t
41a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#endif
42a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
43a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#define SPARSE_HEADER_MAJOR_VER 1
44a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#define SPARSE_HEADER_LEN       (sizeof(sparse_header_t))
45a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
46a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
47a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#define COPY_BUF_SIZE (1024U*1024U)
48a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turnerstatic char *copybuf;
49a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
50a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#define min(a, b) \
51a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; })
52a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
53a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turnerstatic void verbose_error(bool verbose, int err, const char *fmt, ...)
54a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner{
55a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	char *s = "";
56a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	char *at = "";
57a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (fmt) {
58a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		va_list argp;
59a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		int size;
60a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
61a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		va_start(argp, fmt);
62a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		size = vsnprintf(NULL, 0, fmt, argp);
63a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		va_end(argp);
64a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
65a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		if (size < 0) {
66a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			return;
67a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		}
68a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
69a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		at = malloc(size + 1);
70a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		if (at == NULL) {
71a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			return;
72a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		}
73a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
74a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		va_start(argp, fmt);
75a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		vsnprintf(at, size, fmt, argp);
76a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		va_end(argp);
77a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		at[size] = 0;
78a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		s = " at ";
79a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
80a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (verbose) {
81a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#ifndef USE_MINGW
82a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		if (err == -EOVERFLOW) {
83a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			sparse_print_verbose("EOF while reading file%s%s\n", s, at);
84a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		} else
85a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#endif
86a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		if (err == -EINVAL) {
87a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			sparse_print_verbose("Invalid sparse file format%s%s\n", s, at);
88a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		} else if (err == -ENOMEM) {
89a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			sparse_print_verbose("Failed allocation while reading file%s%s\n",
90a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner					s, at);
91a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		} else {
92a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			sparse_print_verbose("Unknown error %d%s%s\n", err, s, at);
93a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		}
94a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
95a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (fmt) {
96a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		free(at);
97a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
98a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner}
99a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
100a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turnerstatic int process_raw_chunk(struct sparse_file *s, unsigned int chunk_size,
101a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		int fd, int64_t offset, unsigned int blocks, unsigned int block,
102a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		uint32_t *crc32)
103a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner{
104a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	int ret;
105a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	int chunk;
106a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	unsigned int len = blocks * s->block_size;
107a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
108a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (chunk_size % s->block_size != 0) {
109a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return -EINVAL;
110a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
111a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
112a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (chunk_size / s->block_size != blocks) {
113a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return -EINVAL;
114a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
115a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
116a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	ret = sparse_file_add_fd(s, fd, offset, len, block);
117a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (ret < 0) {
118a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return ret;
119a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
120a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
121a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (crc32) {
122a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		while (len) {
123a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			chunk = min(len, COPY_BUF_SIZE);
124a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			ret = read_all(fd, copybuf, chunk);
125a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			if (ret < 0) {
126a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner				return ret;
127a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			}
128a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			*crc32 = sparse_crc32(*crc32, copybuf, chunk);
129a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			len -= chunk;
130a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		}
131a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	} else {
132a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		lseek64(fd, len, SEEK_CUR);
133a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
134a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
135a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	return 0;
136a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner}
137a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
138a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turnerstatic int process_fill_chunk(struct sparse_file *s, unsigned int chunk_size,
139a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		int fd, unsigned int blocks, unsigned int block, uint32_t *crc32)
140a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner{
141a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	int ret;
142a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	int chunk;
143a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	int64_t len = (int64_t)blocks * s->block_size;
144a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	uint32_t fill_val;
145a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	uint32_t *fillbuf;
146a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	unsigned int i;
147a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
148a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (chunk_size != sizeof(fill_val)) {
149a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return -EINVAL;
150a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
151a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
152a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	ret = read_all(fd, &fill_val, sizeof(fill_val));
153a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (ret < 0) {
154a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return ret;
155a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
156a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
157a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	ret = sparse_file_add_fill(s, fill_val, len, block);
158a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (ret < 0) {
159a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return ret;
160a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
161a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
162a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (crc32) {
163a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		/* Fill copy_buf with the fill value */
164a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		fillbuf = (uint32_t *)copybuf;
165a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		for (i = 0; i < (COPY_BUF_SIZE / sizeof(fill_val)); i++) {
166a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			fillbuf[i] = fill_val;
167a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		}
168a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
169a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		while (len) {
170a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			chunk = min(len, COPY_BUF_SIZE);
171a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			*crc32 = sparse_crc32(*crc32, copybuf, chunk);
172a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			len -= chunk;
173a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		}
174a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
175a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
176a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	return 0;
177a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner}
178a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
179a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turnerstatic int process_skip_chunk(struct sparse_file *s, unsigned int chunk_size,
180a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		int fd __unused, unsigned int blocks,
181a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		unsigned int block __unused, uint32_t *crc32)
182a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner{
183a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (chunk_size != 0) {
184a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return -EINVAL;
185a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
186a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
187a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (crc32) {
188a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	        int64_t len = (int64_t)blocks * s->block_size;
189a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		memset(copybuf, 0, COPY_BUF_SIZE);
190a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
191a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		while (len) {
192a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			int chunk = min(len, COPY_BUF_SIZE);
193a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			*crc32 = sparse_crc32(*crc32, copybuf, chunk);
194a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			len -= chunk;
195a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		}
196a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
197a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
198a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	return 0;
199a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner}
200a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
201a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turnerstatic int process_crc32_chunk(int fd, unsigned int chunk_size, uint32_t crc32)
202a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner{
203a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	uint32_t file_crc32;
204a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	int ret;
205a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
206a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (chunk_size != sizeof(file_crc32)) {
207a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return -EINVAL;
208a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
209a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
210a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	ret = read_all(fd, &file_crc32, sizeof(file_crc32));
211a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (ret < 0) {
212a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return ret;
213a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
214a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
215a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (file_crc32 != crc32) {
216a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return -EINVAL;
217a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
218a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
219a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	return 0;
220a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner}
221a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
222a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turnerstatic int process_chunk(struct sparse_file *s, int fd, off64_t offset,
223a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		unsigned int chunk_hdr_sz, chunk_header_t *chunk_header,
224a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		unsigned int cur_block, uint32_t *crc_ptr)
225a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner{
226a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	int ret;
227a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	unsigned int chunk_data_size;
228a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
229a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	chunk_data_size = chunk_header->total_sz - chunk_hdr_sz;
230a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
231a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	switch (chunk_header->chunk_type) {
232a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		case CHUNK_TYPE_RAW:
233a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			ret = process_raw_chunk(s, chunk_data_size, fd, offset,
234a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner					chunk_header->chunk_sz, cur_block, crc_ptr);
235a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			if (ret < 0) {
236a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner				verbose_error(s->verbose, ret, "data block at %lld", offset);
237a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner				return ret;
238a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			}
239a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			return chunk_header->chunk_sz;
240a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		case CHUNK_TYPE_FILL:
241a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			ret = process_fill_chunk(s, chunk_data_size, fd,
242a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner					chunk_header->chunk_sz, cur_block, crc_ptr);
243a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			if (ret < 0) {
244a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner				verbose_error(s->verbose, ret, "fill block at %lld", offset);
245a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner				return ret;
246a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			}
247a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			return chunk_header->chunk_sz;
248a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		case CHUNK_TYPE_DONT_CARE:
249a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			ret = process_skip_chunk(s, chunk_data_size, fd,
250a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner					chunk_header->chunk_sz, cur_block, crc_ptr);
251a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			if (chunk_data_size != 0) {
252a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner				if (ret < 0) {
253a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner					verbose_error(s->verbose, ret, "skip block at %lld", offset);
254a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner					return ret;
255a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner				}
256a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			}
257a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			return chunk_header->chunk_sz;
258a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		case CHUNK_TYPE_CRC32:
259a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			ret = process_crc32_chunk(fd, chunk_data_size, *crc_ptr);
260a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			if (ret < 0) {
261a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner				verbose_error(s->verbose, -EINVAL, "crc block at %lld",
262a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner						offset);
263a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner				return ret;
264a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			}
265a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			return 0;
266a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		default:
267a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			verbose_error(s->verbose, -EINVAL, "unknown block %04X at %lld",
268a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner					chunk_header->chunk_type, offset);
269a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
270a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
271a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	return 0;
272a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner}
273a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
274a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turnerstatic int sparse_file_read_sparse(struct sparse_file *s, int fd, bool crc)
275a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner{
276a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	int ret;
277a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	unsigned int i;
278a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	sparse_header_t sparse_header;
279a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	chunk_header_t chunk_header;
280a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	uint32_t crc32 = 0;
281a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	uint32_t *crc_ptr = 0;
282a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	unsigned int cur_block = 0;
283a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	off64_t offset;
284a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
285a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (!copybuf) {
286a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		copybuf = malloc(COPY_BUF_SIZE);
287a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
288a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
289a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (!copybuf) {
290a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return -ENOMEM;
291a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
292a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
293a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (crc) {
294a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		crc_ptr = &crc32;
295a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
296a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
297a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	ret = read_all(fd, &sparse_header, sizeof(sparse_header));
298a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (ret < 0) {
299a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return ret;
300a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
301a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
302a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
303a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return -EINVAL;
304a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
305a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
306a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
307a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return -EINVAL;
308a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
309a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
310a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
311a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return -EINVAL;
312a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
313a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
314a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (sparse_header.chunk_hdr_sz < sizeof(chunk_header)) {
315a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return -EINVAL;
316a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
317a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
318a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (sparse_header.file_hdr_sz > SPARSE_HEADER_LEN) {
319a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		/* Skip the remaining bytes in a header that is longer than
320a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		 * we expected.
321a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		 */
322a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		lseek64(fd, sparse_header.file_hdr_sz - SPARSE_HEADER_LEN, SEEK_CUR);
323a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
324a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
325a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	for (i = 0; i < sparse_header.total_chunks; i++) {
326a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		ret = read_all(fd, &chunk_header, sizeof(chunk_header));
327a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		if (ret < 0) {
328a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			return ret;
329a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		}
330a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
331a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		if (sparse_header.chunk_hdr_sz > CHUNK_HEADER_LEN) {
332a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			/* Skip the remaining bytes in a header that is longer than
333a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			 * we expected.
334a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			 */
335a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			lseek64(fd, sparse_header.chunk_hdr_sz - CHUNK_HEADER_LEN, SEEK_CUR);
336a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		}
337a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
338a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		offset = lseek64(fd, 0, SEEK_CUR);
339a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
340a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		ret = process_chunk(s, fd, offset, sparse_header.chunk_hdr_sz, &chunk_header,
341a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner				cur_block, crc_ptr);
342a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		if (ret < 0) {
343a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			return ret;
344a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		}
345a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
346a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		cur_block += ret;
347a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
348a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
349a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (sparse_header.total_blks != cur_block) {
350a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return -EINVAL;
351a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
352a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
353a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	return 0;
354a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner}
355a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
356a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turnerstatic int sparse_file_read_normal(struct sparse_file *s, int fd)
357a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner{
358a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	int ret;
359a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	uint32_t *buf = malloc(s->block_size);
360a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	unsigned int block = 0;
361a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	int64_t remain = s->len;
362a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	int64_t offset = 0;
363a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	unsigned int to_read;
364a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	unsigned int i;
365a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	bool sparse_block;
366a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
367a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (!buf) {
368a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return -ENOMEM;
369a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
370a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
371a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	while (remain > 0) {
372a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		to_read = min(remain, s->block_size);
373a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		ret = read_all(fd, buf, to_read);
374a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		if (ret < 0) {
375a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			error("failed to read sparse file");
376a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			return ret;
377a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		}
378a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
379a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		if (to_read == s->block_size) {
380a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			sparse_block = true;
381a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			for (i = 1; i < s->block_size / sizeof(uint32_t); i++) {
382a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner				if (buf[0] != buf[i]) {
383a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner					sparse_block = false;
384a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner					break;
385a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner				}
386a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			}
387a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		} else {
388a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			sparse_block = false;
389a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		}
390a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
391a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		if (sparse_block) {
392a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			/* TODO: add flag to use skip instead of fill for buf[0] == 0 */
393a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			sparse_file_add_fill(s, buf[0], to_read, block);
394a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		} else {
395a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner			sparse_file_add_fd(s, fd, offset, to_read, block);
396a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		}
397a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
398a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		remain -= to_read;
399a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		offset += to_read;
400a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		block++;
401a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
402a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
403a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	return 0;
404a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner}
405a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
406a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turnerint sparse_file_read(struct sparse_file *s, int fd, bool sparse, bool crc)
407a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner{
408a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (crc && !sparse) {
409a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return -EINVAL;
410a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
411a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
412a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (sparse) {
413a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return sparse_file_read_sparse(s, fd, crc);
414a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	} else {
415a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return sparse_file_read_normal(s, fd);
416a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
417a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner}
418a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
419a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turnerstruct sparse_file *sparse_file_import(int fd, bool verbose, bool crc)
420a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner{
421a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	int ret;
422a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	sparse_header_t sparse_header;
423a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	int64_t len;
424a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	struct sparse_file *s;
425a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
426a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	ret = read_all(fd, &sparse_header, sizeof(sparse_header));
427a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (ret < 0) {
428a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		verbose_error(verbose, ret, "header");
429a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return NULL;
430a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
431a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
432a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
433a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		verbose_error(verbose, -EINVAL, "header magic");
434a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return NULL;
435a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
436a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
437a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
438a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		verbose_error(verbose, -EINVAL, "header major version");
439a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return NULL;
440a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
441a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
442a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
443a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return NULL;
444a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
445a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
446a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (sparse_header.chunk_hdr_sz < sizeof(chunk_header_t)) {
447a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return NULL;
448a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
449a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
450a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	len = (int64_t)sparse_header.total_blks * sparse_header.blk_sz;
451a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	s = sparse_file_new(sparse_header.blk_sz, len);
452a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (!s) {
453a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		verbose_error(verbose, -EINVAL, NULL);
454a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return NULL;
455a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
456a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
457a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	ret = lseek64(fd, 0, SEEK_SET);
458a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (ret < 0) {
459a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		verbose_error(verbose, ret, "seeking");
460a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		sparse_file_destroy(s);
461a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return NULL;
462a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
463a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
464a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	s->verbose = verbose;
465a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
466a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	ret = sparse_file_read(s, fd, true, crc);
467a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (ret < 0) {
468a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		sparse_file_destroy(s);
469a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return NULL;
470a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
471a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
472a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	return s;
473a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner}
474a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
475a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turnerstruct sparse_file *sparse_file_import_auto(int fd, bool crc)
476a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner{
477a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	struct sparse_file *s;
478a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	int64_t len;
479a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	int ret;
480a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
481a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	s = sparse_file_import(fd, true, crc);
482a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (s) {
483a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return s;
484a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
485a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
486a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	len = lseek64(fd, 0, SEEK_END);
487a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (len < 0) {
488a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return NULL;
489a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
490a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
491a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	lseek64(fd, 0, SEEK_SET);
492a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
493a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	s = sparse_file_new(4096, len);
494a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (!s) {
495a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return NULL;
496a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
497a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
498a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	ret = sparse_file_read_normal(s, fd);
499a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	if (ret < 0) {
500a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		sparse_file_destroy(s);
501a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner		return NULL;
502a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	}
503a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner
504a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner	return s;
505a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner}
506