summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJerry Zhang2018-06-12 18:42:09 -0500
committerJerry Zhang2018-06-13 15:32:24 -0500
commit7b444f08c17ed1b82ea1a1560e109c0a173e700f (patch)
treeb73fa22396eefbd3e71d151c581ae957383aaf7c /libsparse
parent5a755077958dd4f7fb668a125b57dea8d85cd9a8 (diff)
downloadplatform-system-core-7b444f08c17ed1b82ea1a1560e109c0a173e700f.tar.gz
platform-system-core-7b444f08c17ed1b82ea1a1560e109c0a173e700f.tar.xz
platform-system-core-7b444f08c17ed1b82ea1a1560e109c0a173e700f.zip
libsparse: Add .clang-format and reformat to google3 style
Bug: 78793464 Test: compiles Change-Id: I8e44ba77195a12fc2bac7d4276bbc4aa95149b31
Diffstat (limited to 'libsparse')
l---------libsparse/.clang-format1
-rw-r--r--libsparse/append2simg.cpp188
-rw-r--r--libsparse/backed_block.cpp629
-rw-r--r--libsparse/backed_block.h68
-rw-r--r--libsparse/defs.h2
-rw-r--r--libsparse/img2simg.cpp143
-rw-r--r--libsparse/output_file.cpp1071
-rw-r--r--libsparse/output_file.h30
-rw-r--r--libsparse/simg2img.cpp90
-rw-r--r--libsparse/simg2simg.cpp149
-rw-r--r--libsparse/sparse.cpp547
-rw-r--r--libsparse/sparse_crc32.cpp91
-rw-r--r--libsparse/sparse_crc32.h2
-rw-r--r--libsparse/sparse_defs.h9
-rw-r--r--libsparse/sparse_err.cpp15
-rw-r--r--libsparse/sparse_file.h10
-rw-r--r--libsparse/sparse_format.h40
-rw-r--r--libsparse/sparse_read.cpp978
18 files changed, 1940 insertions, 2123 deletions
diff --git a/libsparse/.clang-format b/libsparse/.clang-format
new file mode 120000
index 000000000..fd0645fdf
--- /dev/null
+++ b/libsparse/.clang-format
@@ -0,0 +1 @@
../.clang-format-2 \ No newline at end of file
diff --git a/libsparse/append2simg.cpp b/libsparse/append2simg.cpp
index 83450a0d9..99f433981 100644
--- a/libsparse/append2simg.cpp
+++ b/libsparse/append2simg.cpp
@@ -25,8 +25,8 @@
25#include <unistd.h> 25#include <unistd.h>
26 26
27#include <sparse/sparse.h> 27#include <sparse/sparse.h>
28#include "sparse_file.h"
29#include "backed_block.h" 28#include "backed_block.h"
29#include "sparse_file.h"
30 30
31#ifndef O_BINARY 31#ifndef O_BINARY
32#define O_BINARY 0 32#define O_BINARY 0
@@ -40,100 +40,98 @@
40#define off64_t off_t 40#define off64_t off_t
41#endif 41#endif
42 42
43void usage() 43void usage() {
44{ 44 fprintf(stderr, "Usage: append2simg <output> <input>\n");
45 fprintf(stderr, "Usage: append2simg <output> <input>\n");
46} 45}
47 46
48int main(int argc, char *argv[]) 47int main(int argc, char* argv[]) {
49{ 48 int output;
50 int output; 49 int output_block;
51 int output_block; 50 char* output_path;
52 char *output_path; 51 struct sparse_file* sparse_output;
53 struct sparse_file *sparse_output; 52
54 53 int input;
55 int input; 54 char* input_path;
56 char *input_path; 55 off64_t input_len;
57 off64_t input_len; 56
58 57 int tmp_fd;
59 int tmp_fd; 58 char* tmp_path;
60 char *tmp_path; 59
61 60 int ret;
62 int ret; 61
63 62 if (argc == 3) {
64 if (argc == 3) { 63 output_path = argv[1];
65 output_path = argv[1]; 64 input_path = argv[2];
66 input_path = argv[2]; 65 } else {
67 } else { 66 usage();
68 usage(); 67 exit(-1);
69 exit(-1); 68 }
70 } 69
71 70 ret = asprintf(&tmp_path, "%s.append2simg", output_path);
72 ret = asprintf(&tmp_path, "%s.append2simg", output_path); 71 if (ret < 0) {
73 if (ret < 0) { 72 fprintf(stderr, "Couldn't allocate filename\n");
74 fprintf(stderr, "Couldn't allocate filename\n"); 73 exit(-1);
75 exit(-1); 74 }
76 } 75
77 76 output = open(output_path, O_RDWR | O_BINARY);
78 output = open(output_path, O_RDWR | O_BINARY); 77 if (output < 0) {
79 if (output < 0) { 78 fprintf(stderr, "Couldn't open output file (%s)\n", strerror(errno));
80 fprintf(stderr, "Couldn't open output file (%s)\n", strerror(errno)); 79 exit(-1);
81 exit(-1); 80 }
82 } 81
83 82 sparse_output = sparse_file_import_auto(output, false, true);
84 sparse_output = sparse_file_import_auto(output, false, true); 83 if (!sparse_output) {
85 if (!sparse_output) { 84 fprintf(stderr, "Couldn't import output file\n");
86 fprintf(stderr, "Couldn't import output file\n"); 85 exit(-1);
87 exit(-1); 86 }
88 } 87
89 88 input = open(input_path, O_RDONLY | O_BINARY);
90 input = open(input_path, O_RDONLY | O_BINARY); 89 if (input < 0) {
91 if (input < 0) { 90 fprintf(stderr, "Couldn't open input file (%s)\n", strerror(errno));
92 fprintf(stderr, "Couldn't open input file (%s)\n", strerror(errno)); 91 exit(-1);
93 exit(-1); 92 }
94 } 93
95 94 input_len = lseek64(input, 0, SEEK_END);
96 input_len = lseek64(input, 0, SEEK_END); 95 if (input_len < 0) {
97 if (input_len < 0) { 96 fprintf(stderr, "Couldn't get input file length (%s)\n", strerror(errno));
98 fprintf(stderr, "Couldn't get input file length (%s)\n", strerror(errno)); 97 exit(-1);
99 exit(-1); 98 } else if (input_len % sparse_output->block_size) {
100 } else if (input_len % sparse_output->block_size) { 99 fprintf(stderr, "Input file is not a multiple of the output file's block size");
101 fprintf(stderr, "Input file is not a multiple of the output file's block size"); 100 exit(-1);
102 exit(-1); 101 }
103 } 102 lseek64(input, 0, SEEK_SET);
104 lseek64(input, 0, SEEK_SET); 103
105 104 output_block = sparse_output->len / sparse_output->block_size;
106 output_block = sparse_output->len / sparse_output->block_size; 105 if (sparse_file_add_fd(sparse_output, input, 0, input_len, output_block) < 0) {
107 if (sparse_file_add_fd(sparse_output, input, 0, input_len, output_block) < 0) { 106 fprintf(stderr, "Couldn't add input file\n");
108 fprintf(stderr, "Couldn't add input file\n"); 107 exit(-1);
109 exit(-1); 108 }
110 } 109 sparse_output->len += input_len;
111 sparse_output->len += input_len; 110
112 111 tmp_fd = open(tmp_path, O_WRONLY | O_CREAT | O_BINARY, 0664);
113 tmp_fd = open(tmp_path, O_WRONLY | O_CREAT | O_BINARY, 0664); 112 if (tmp_fd < 0) {
114 if (tmp_fd < 0) { 113 fprintf(stderr, "Couldn't open temporary file (%s)\n", strerror(errno));
115 fprintf(stderr, "Couldn't open temporary file (%s)\n", strerror(errno)); 114 exit(-1);
116 exit(-1); 115 }
117 } 116
118 117 lseek64(output, 0, SEEK_SET);
119 lseek64(output, 0, SEEK_SET); 118 if (sparse_file_write(sparse_output, tmp_fd, false, true, false) < 0) {
120 if (sparse_file_write(sparse_output, tmp_fd, false, true, false) < 0) { 119 fprintf(stderr, "Failed to write sparse file\n");
121 fprintf(stderr, "Failed to write sparse file\n"); 120 exit(-1);
122 exit(-1); 121 }
123 } 122
124 123 sparse_file_destroy(sparse_output);
125 sparse_file_destroy(sparse_output); 124 close(tmp_fd);
126 close(tmp_fd); 125 close(output);
127 close(output); 126 close(input);
128 close(input); 127
129 128 ret = rename(tmp_path, output_path);
130 ret = rename(tmp_path, output_path); 129 if (ret < 0) {
131 if (ret < 0) { 130 fprintf(stderr, "Failed to rename temporary file (%s)\n", strerror(errno));
132 fprintf(stderr, "Failed to rename temporary file (%s)\n", strerror(errno)); 131 exit(-1);
133 exit(-1); 132 }
134 } 133
135 134 free(tmp_path);
136 free(tmp_path); 135
137 136 exit(0);
138 exit(0);
139} 137}
diff --git a/libsparse/backed_block.cpp b/libsparse/backed_block.cpp
index fb26d1a6e..7f5632eea 100644
--- a/libsparse/backed_block.cpp
+++ b/libsparse/backed_block.cpp
@@ -24,382 +24,357 @@
24#include "sparse_defs.h" 24#include "sparse_defs.h"
25 25
26struct backed_block { 26struct backed_block {
27 unsigned int block; 27 unsigned int block;
28 unsigned int len; 28 unsigned int len;
29 enum backed_block_type type; 29 enum backed_block_type type;
30 union { 30 union {
31 struct { 31 struct {
32 void *data; 32 void* data;
33 } data; 33 } data;
34 struct { 34 struct {
35 char *filename; 35 char* filename;
36 int64_t offset; 36 int64_t offset;
37 } file; 37 } file;
38 struct { 38 struct {
39 int fd; 39 int fd;
40 int64_t offset; 40 int64_t offset;
41 } fd; 41 } fd;
42 struct { 42 struct {
43 uint32_t val; 43 uint32_t val;
44 } fill; 44 } fill;
45 }; 45 };
46 struct backed_block *next; 46 struct backed_block* next;
47}; 47};
48 48
49struct backed_block_list { 49struct backed_block_list {
50 struct backed_block *data_blocks; 50 struct backed_block* data_blocks;
51 struct backed_block *last_used; 51 struct backed_block* last_used;
52 unsigned int block_size; 52 unsigned int block_size;
53}; 53};
54 54
55struct backed_block *backed_block_iter_new(struct backed_block_list *bbl) 55struct backed_block* backed_block_iter_new(struct backed_block_list* bbl) {
56{ 56 return bbl->data_blocks;
57 return bbl->data_blocks;
58} 57}
59 58
60struct backed_block *backed_block_iter_next(struct backed_block *bb) 59struct backed_block* backed_block_iter_next(struct backed_block* bb) {
61{ 60 return bb->next;
62 return bb->next;
63} 61}
64 62
65unsigned int backed_block_len(struct backed_block *bb) 63unsigned int backed_block_len(struct backed_block* bb) {
66{ 64 return bb->len;
67 return bb->len;
68} 65}
69 66
70unsigned int backed_block_block(struct backed_block *bb) 67unsigned int backed_block_block(struct backed_block* bb) {
71{ 68 return bb->block;
72 return bb->block;
73} 69}
74 70
75void *backed_block_data(struct backed_block *bb) 71void* backed_block_data(struct backed_block* bb) {
76{ 72 assert(bb->type == BACKED_BLOCK_DATA);
77 assert(bb->type == BACKED_BLOCK_DATA); 73 return bb->data.data;
78 return bb->data.data;
79} 74}
80 75
81const char *backed_block_filename(struct backed_block *bb) 76const char* backed_block_filename(struct backed_block* bb) {
82{ 77 assert(bb->type == BACKED_BLOCK_FILE);
83 assert(bb->type == BACKED_BLOCK_FILE); 78 return bb->file.filename;
84 return bb->file.filename;
85} 79}
86 80
87int backed_block_fd(struct backed_block *bb) 81int backed_block_fd(struct backed_block* bb) {
88{ 82 assert(bb->type == BACKED_BLOCK_FD);
89 assert(bb->type == BACKED_BLOCK_FD); 83 return bb->fd.fd;
90 return bb->fd.fd;
91} 84}
92 85
93int64_t backed_block_file_offset(struct backed_block *bb) 86int64_t backed_block_file_offset(struct backed_block* bb) {
94{ 87 assert(bb->type == BACKED_BLOCK_FILE || bb->type == BACKED_BLOCK_FD);
95 assert(bb->type == BACKED_BLOCK_FILE || bb->type == BACKED_BLOCK_FD); 88 if (bb->type == BACKED_BLOCK_FILE) {
96 if (bb->type == BACKED_BLOCK_FILE) { 89 return bb->file.offset;
97 return bb->file.offset; 90 } else { /* bb->type == BACKED_BLOCK_FD */
98 } else { /* bb->type == BACKED_BLOCK_FD */ 91 return bb->fd.offset;
99 return bb->fd.offset; 92 }
100 }
101} 93}
102 94
103uint32_t backed_block_fill_val(struct backed_block *bb) 95uint32_t backed_block_fill_val(struct backed_block* bb) {
104{ 96 assert(bb->type == BACKED_BLOCK_FILL);
105 assert(bb->type == BACKED_BLOCK_FILL); 97 return bb->fill.val;
106 return bb->fill.val;
107} 98}
108 99
109enum backed_block_type backed_block_type(struct backed_block *bb) 100enum backed_block_type backed_block_type(struct backed_block* bb) {
110{ 101 return bb->type;
111 return bb->type;
112} 102}
113 103
114void backed_block_destroy(struct backed_block *bb) 104void backed_block_destroy(struct backed_block* bb) {
115{ 105 if (bb->type == BACKED_BLOCK_FILE) {
116 if (bb->type == BACKED_BLOCK_FILE) { 106 free(bb->file.filename);
117 free(bb->file.filename); 107 }
118 }
119 108
120 free(bb); 109 free(bb);
121} 110}
122 111
123struct backed_block_list *backed_block_list_new(unsigned int block_size) 112struct backed_block_list* backed_block_list_new(unsigned int block_size) {
124{ 113 struct backed_block_list* b =
125 struct backed_block_list *b = reinterpret_cast<backed_block_list*>( 114 reinterpret_cast<backed_block_list*>(calloc(sizeof(struct backed_block_list), 1));
126 calloc(sizeof(struct backed_block_list), 1)); 115 b->block_size = block_size;
127 b->block_size = block_size; 116 return b;
128 return b;
129} 117}
130 118
131void backed_block_list_destroy(struct backed_block_list *bbl) 119void backed_block_list_destroy(struct backed_block_list* bbl) {
132{ 120 if (bbl->data_blocks) {
133 if (bbl->data_blocks) { 121 struct backed_block* bb = bbl->data_blocks;
134 struct backed_block *bb = bbl->data_blocks; 122 while (bb) {
135 while (bb) { 123 struct backed_block* next = bb->next;
136 struct backed_block *next = bb->next; 124 backed_block_destroy(bb);
137 backed_block_destroy(bb); 125 bb = next;
138 bb = next; 126 }
139 } 127 }
140 } 128
141 129 free(bbl);
142 free(bbl);
143} 130}
144 131
145void backed_block_list_move(struct backed_block_list *from, 132void backed_block_list_move(struct backed_block_list* from, struct backed_block_list* to,
146 struct backed_block_list *to, struct backed_block *start, 133 struct backed_block* start, struct backed_block* end) {
147 struct backed_block *end) 134 struct backed_block* bb;
148{ 135
149 struct backed_block *bb; 136 if (start == NULL) {
150 137 start = from->data_blocks;
151 if (start == NULL) { 138 }
152 start = from->data_blocks; 139
153 } 140 if (!end) {
154 141 for (end = start; end && end->next; end = end->next)
155 if (!end) { 142 ;
156 for (end = start; end && end->next; end = end->next) 143 }
157 ; 144
158 } 145 if (start == NULL || end == NULL) {
159 146 return;
160 if (start == NULL || end == NULL) { 147 }
161 return; 148
162 } 149 from->last_used = NULL;
163 150 to->last_used = NULL;
164 from->last_used = NULL; 151 if (from->data_blocks == start) {
165 to->last_used = NULL; 152 from->data_blocks = end->next;
166 if (from->data_blocks == start) { 153 } else {
167 from->data_blocks = end->next; 154 for (bb = from->data_blocks; bb; bb = bb->next) {
168 } else { 155 if (bb->next == start) {
169 for (bb = from->data_blocks; bb; bb = bb->next) { 156 bb->next = end->next;
170 if (bb->next == start) { 157 break;
171 bb->next = end->next; 158 }
172 break; 159 }
173 } 160 }
174 } 161
175 } 162 if (!to->data_blocks) {
176 163 to->data_blocks = start;
177 if (!to->data_blocks) { 164 end->next = NULL;
178 to->data_blocks = start; 165 } else {
179 end->next = NULL; 166 for (bb = to->data_blocks; bb; bb = bb->next) {
180 } else { 167 if (!bb->next || bb->next->block > start->block) {
181 for (bb = to->data_blocks; bb; bb = bb->next) { 168 end->next = bb->next;
182 if (!bb->next || bb->next->block > start->block) { 169 bb->next = start;
183 end->next = bb->next; 170 break;
184 bb->next = start; 171 }
185 break; 172 }
186 } 173 }
187 }
188 }
189} 174}
190 175
191/* may free b */ 176/* may free b */
192static int merge_bb(struct backed_block_list *bbl, 177static int merge_bb(struct backed_block_list* bbl, struct backed_block* a, struct backed_block* b) {
193 struct backed_block *a, struct backed_block *b) 178 unsigned int block_len;
194{ 179
195 unsigned int block_len; 180 /* Block doesn't exist (possible if one block is the last block) */
196 181 if (!a || !b) {
197 /* Block doesn't exist (possible if one block is the last block) */ 182 return -EINVAL;
198 if (!a || !b) { 183 }
199 return -EINVAL; 184
200 } 185 assert(a->block < b->block);
201 186
202 assert(a->block < b->block); 187 /* Blocks are of different types */
203 188 if (a->type != b->type) {
204 /* Blocks are of different types */ 189 return -EINVAL;
205 if (a->type != b->type) { 190 }
206 return -EINVAL; 191
207 } 192 /* Blocks are not adjacent */
208 193 block_len = a->len / bbl->block_size; /* rounds down */
209 /* Blocks are not adjacent */ 194 if (a->block + block_len != b->block) {
210 block_len = a->len / bbl->block_size; /* rounds down */ 195 return -EINVAL;
211 if (a->block + block_len != b->block) { 196 }
212 return -EINVAL; 197
213 } 198 switch (a->type) {
214 199 case BACKED_BLOCK_DATA:
215 switch (a->type) { 200 /* Don't support merging data for now */
216 case BACKED_BLOCK_DATA: 201 return -EINVAL;
217 /* Don't support merging data for now */ 202 case BACKED_BLOCK_FILL:
218 return -EINVAL; 203 if (a->fill.val != b->fill.val) {
219 case BACKED_BLOCK_FILL: 204 return -EINVAL;
220 if (a->fill.val != b->fill.val) { 205 }
221 return -EINVAL; 206 break;
222 } 207 case BACKED_BLOCK_FILE:
223 break; 208 /* Already make sure b->type is BACKED_BLOCK_FILE */
224 case BACKED_BLOCK_FILE: 209 if (strcmp(a->file.filename, b->file.filename) || a->file.offset + a->len != b->file.offset) {
225 /* Already make sure b->type is BACKED_BLOCK_FILE */ 210 return -EINVAL;
226 if (strcmp(a->file.filename, b->file.filename) || 211 }
227 a->file.offset + a->len != b->file.offset) { 212 break;
228 return -EINVAL; 213 case BACKED_BLOCK_FD:
229 } 214 if (a->fd.fd != b->fd.fd || a->fd.offset + a->len != b->fd.offset) {
230 break; 215 return -EINVAL;
231 case BACKED_BLOCK_FD: 216 }
232 if (a->fd.fd != b->fd.fd || 217 break;
233 a->fd.offset + a->len != b->fd.offset) { 218 }
234 return -EINVAL; 219
235 } 220 /* Blocks are compatible and adjacent, with a before b. Merge b into a,
236 break; 221 * and free b */
237 } 222 a->len += b->len;
238 223 a->next = b->next;
239 /* Blocks are compatible and adjacent, with a before b. Merge b into a, 224
240 * and free b */ 225 backed_block_destroy(b);
241 a->len += b->len; 226
242 a->next = b->next; 227 return 0;
243
244 backed_block_destroy(b);
245
246 return 0;
247} 228}
248 229
249static int queue_bb(struct backed_block_list *bbl, struct backed_block *new_bb) 230static int queue_bb(struct backed_block_list* bbl, struct backed_block* new_bb) {
250{ 231 struct backed_block* bb;
251 struct backed_block *bb; 232
252 233 if (bbl->data_blocks == NULL) {
253 if (bbl->data_blocks == NULL) { 234 bbl->data_blocks = new_bb;
254 bbl->data_blocks = new_bb; 235 return 0;
255 return 0; 236 }
256 } 237
257 238 if (bbl->data_blocks->block > new_bb->block) {
258 if (bbl->data_blocks->block > new_bb->block) { 239 new_bb->next = bbl->data_blocks;
259 new_bb->next = bbl->data_blocks; 240 bbl->data_blocks = new_bb;
260 bbl->data_blocks = new_bb; 241 return 0;
261 return 0; 242 }
262 } 243
263 244 /* Optimization: blocks are mostly queued in sequence, so save the
264 /* Optimization: blocks are mostly queued in sequence, so save the 245 pointer to the last bb that was added, and start searching from
265 pointer to the last bb that was added, and start searching from 246 there if the next block number is higher */
266 there if the next block number is higher */ 247 if (bbl->last_used && new_bb->block > bbl->last_used->block)
267 if (bbl->last_used && new_bb->block > bbl->last_used->block) 248 bb = bbl->last_used;
268 bb = bbl->last_used; 249 else
269 else 250 bb = bbl->data_blocks;
270 bb = bbl->data_blocks; 251 bbl->last_used = new_bb;
271 bbl->last_used = new_bb; 252
272 253 for (; bb->next && bb->next->block < new_bb->block; bb = bb->next)
273 for (; bb->next && bb->next->block < new_bb->block; bb = bb->next) 254 ;
274 ; 255
275 256 if (bb->next == NULL) {
276 if (bb->next == NULL) { 257 bb->next = new_bb;
277 bb->next = new_bb; 258 } else {
278 } else { 259 new_bb->next = bb->next;
279 new_bb->next = bb->next; 260 bb->next = new_bb;
280 bb->next = new_bb; 261 }
281 } 262
282 263 merge_bb(bbl, new_bb, new_bb->next);
283 merge_bb(bbl, new_bb, new_bb->next); 264 if (!merge_bb(bbl, bb, new_bb)) {
284 if (!merge_bb(bbl, bb, new_bb)) { 265 /* new_bb destroyed, point to retained as last_used */
285 /* new_bb destroyed, point to retained as last_used */ 266 bbl->last_used = bb;
286 bbl->last_used = bb; 267 }
287 } 268
288 269 return 0;
289 return 0;
290} 270}
291 271
292/* Queues a fill block of memory to be written to the specified data blocks */ 272/* Queues a fill block of memory to be written to the specified data blocks */
293int backed_block_add_fill(struct backed_block_list *bbl, unsigned int fill_val, 273int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, unsigned int len,
294 unsigned int len, unsigned int block) 274 unsigned int block) {
295{ 275 struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
296 struct backed_block *bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block))); 276 if (bb == NULL) {
297 if (bb == NULL) { 277 return -ENOMEM;
298 return -ENOMEM; 278 }
299 } 279
300 280 bb->block = block;
301 bb->block = block; 281 bb->len = len;
302 bb->len = len; 282 bb->type = BACKED_BLOCK_FILL;
303 bb->type = BACKED_BLOCK_FILL; 283 bb->fill.val = fill_val;
304 bb->fill.val = fill_val; 284 bb->next = NULL;
305 bb->next = NULL; 285
306 286 return queue_bb(bbl, bb);
307 return queue_bb(bbl, bb);
308} 287}
309 288
310/* Queues a block of memory to be written to the specified data blocks */ 289/* Queues a block of memory to be written to the specified data blocks */
311int backed_block_add_data(struct backed_block_list *bbl, void *data, 290int backed_block_add_data(struct backed_block_list* bbl, void* data, unsigned int len,
312 unsigned int len, unsigned int block) 291 unsigned int block) {
313{ 292 struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
314 struct backed_block *bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block))); 293 if (bb == NULL) {
315 if (bb == NULL) { 294 return -ENOMEM;
316 return -ENOMEM; 295 }
317 } 296
318 297 bb->block = block;
319 bb->block = block; 298 bb->len = len;
320 bb->len = len; 299 bb->type = BACKED_BLOCK_DATA;
321 bb->type = BACKED_BLOCK_DATA; 300 bb->data.data = data;
322 bb->data.data = data; 301 bb->next = NULL;
323 bb->next = NULL; 302
324 303 return queue_bb(bbl, bb);
325 return queue_bb(bbl, bb);
326} 304}
327 305
328/* Queues a chunk of a file on disk to be written to the specified data blocks */ 306/* Queues a chunk of a file on disk to be written to the specified data blocks */
329int backed_block_add_file(struct backed_block_list *bbl, const char *filename, 307int backed_block_add_file(struct backed_block_list* bbl, const char* filename, int64_t offset,
330 int64_t offset, unsigned int len, unsigned int block) 308 unsigned int len, unsigned int block) {
331{ 309 struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
332 struct backed_block *bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block))); 310 if (bb == NULL) {
333 if (bb == NULL) { 311 return -ENOMEM;
334 return -ENOMEM; 312 }
335 } 313
336 314 bb->block = block;
337 bb->block = block; 315 bb->len = len;
338 bb->len = len; 316 bb->type = BACKED_BLOCK_FILE;
339 bb->type = BACKED_BLOCK_FILE; 317 bb->file.filename = strdup(filename);
340 bb->file.filename = strdup(filename); 318 bb->file.offset = offset;
341 bb->file.offset = offset; 319 bb->next = NULL;
342 bb->next = NULL; 320
343 321 return queue_bb(bbl, bb);
344 return queue_bb(bbl, bb);
345} 322}
346 323
347/* Queues a chunk of a fd to be written to the specified data blocks */ 324/* Queues a chunk of a fd to be written to the specified data blocks */
348int backed_block_add_fd(struct backed_block_list *bbl, int fd, int64_t offset, 325int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, unsigned int len,
349 unsigned int len, unsigned int block) 326 unsigned int block) {
350{ 327 struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
351 struct backed_block *bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block))); 328 if (bb == NULL) {
352 if (bb == NULL) { 329 return -ENOMEM;
353 return -ENOMEM; 330 }
354 } 331
355 332 bb->block = block;
356 bb->block = block; 333 bb->len = len;
357 bb->len = len; 334 bb->type = BACKED_BLOCK_FD;
358 bb->type = BACKED_BLOCK_FD; 335 bb->fd.fd = fd;
359 bb->fd.fd = fd; 336 bb->fd.offset = offset;
360 bb->fd.offset = offset; 337 bb->next = NULL;
361 bb->next = NULL; 338
362 339 return queue_bb(bbl, bb);
363 return queue_bb(bbl, bb);
364} 340}
365 341
366int backed_block_split(struct backed_block_list *bbl, struct backed_block *bb, 342int backed_block_split(struct backed_block_list* bbl, struct backed_block* bb,
367 unsigned int max_len) 343 unsigned int max_len) {
368{ 344 struct backed_block* new_bb;
369 struct backed_block *new_bb; 345
370 346 max_len = ALIGN_DOWN(max_len, bbl->block_size);
371 max_len = ALIGN_DOWN(max_len, bbl->block_size); 347
372 348 if (bb->len <= max_len) {
373 if (bb->len <= max_len) { 349 return 0;
374 return 0; 350 }
375 } 351
376 352 new_bb = reinterpret_cast<backed_block*>(malloc(sizeof(struct backed_block)));
377 new_bb = reinterpret_cast<backed_block*>(malloc(sizeof(struct backed_block))); 353 if (new_bb == NULL) {
378 if (new_bb == NULL) { 354 return -ENOMEM;
379 return -ENOMEM; 355 }
380 } 356
381 357 *new_bb = *bb;
382 *new_bb = *bb; 358
383 359 new_bb->len = bb->len - max_len;
384 new_bb->len = bb->len - max_len; 360 new_bb->block = bb->block + max_len / bbl->block_size;
385 new_bb->block = bb->block + max_len / bbl->block_size; 361 new_bb->next = bb->next;
386 new_bb->next = bb->next; 362 bb->next = new_bb;
387 bb->next = new_bb; 363 bb->len = max_len;
388 bb->len = max_len; 364
389 365 switch (bb->type) {
390 switch (bb->type) { 366 case BACKED_BLOCK_DATA:
391 case BACKED_BLOCK_DATA: 367 new_bb->data.data = (char*)bb->data.data + max_len;
392 new_bb->data.data = (char *)bb->data.data + max_len; 368 break;
393 break; 369 case BACKED_BLOCK_FILE:
394 case BACKED_BLOCK_FILE: 370 new_bb->file.offset += max_len;
395 new_bb->file.offset += max_len; 371 break;
396 break; 372 case BACKED_BLOCK_FD:
397 case BACKED_BLOCK_FD: 373 new_bb->fd.offset += max_len;
398 new_bb->fd.offset += max_len; 374 break;
399 break; 375 case BACKED_BLOCK_FILL:
400 case BACKED_BLOCK_FILL: 376 break;
401 break; 377 }
402 } 378
403 379 return 0;
404 return 0;
405} 380}
diff --git a/libsparse/backed_block.h b/libsparse/backed_block.h
index 1a159be1e..3a7546065 100644
--- a/libsparse/backed_block.h
+++ b/libsparse/backed_block.h
@@ -23,42 +23,40 @@ struct backed_block_list;
23struct backed_block; 23struct backed_block;
24 24
25enum backed_block_type { 25enum backed_block_type {
26 BACKED_BLOCK_DATA, 26 BACKED_BLOCK_DATA,
27 BACKED_BLOCK_FILE, 27 BACKED_BLOCK_FILE,
28 BACKED_BLOCK_FD, 28 BACKED_BLOCK_FD,
29 BACKED_BLOCK_FILL, 29 BACKED_BLOCK_FILL,
30}; 30};
31 31
32int backed_block_add_data(struct backed_block_list *bbl, void *data, 32int backed_block_add_data(struct backed_block_list* bbl, void* data, unsigned int len,
33 unsigned int len, unsigned int block); 33 unsigned int block);
34int backed_block_add_fill(struct backed_block_list *bbl, unsigned int fill_val, 34int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, unsigned int len,
35 unsigned int len, unsigned int block); 35 unsigned int block);
36int backed_block_add_file(struct backed_block_list *bbl, const char *filename, 36int backed_block_add_file(struct backed_block_list* bbl, const char* filename, int64_t offset,
37 int64_t offset, unsigned int len, unsigned int block); 37 unsigned int len, unsigned int block);
38int backed_block_add_fd(struct backed_block_list *bbl, int fd, 38int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, unsigned int len,
39 int64_t offset, unsigned int len, unsigned int block); 39 unsigned int block);
40 40
41struct backed_block *backed_block_iter_new(struct backed_block_list *bbl); 41struct backed_block* backed_block_iter_new(struct backed_block_list* bbl);
42struct backed_block *backed_block_iter_next(struct backed_block *bb); 42struct backed_block* backed_block_iter_next(struct backed_block* bb);
43unsigned int backed_block_len(struct backed_block *bb); 43unsigned int backed_block_len(struct backed_block* bb);
44unsigned int backed_block_block(struct backed_block *bb); 44unsigned int backed_block_block(struct backed_block* bb);
45void *backed_block_data(struct backed_block *bb); 45void* backed_block_data(struct backed_block* bb);
46const char *backed_block_filename(struct backed_block *bb); 46const char* backed_block_filename(struct backed_block* bb);
47int backed_block_fd(struct backed_block *bb); 47int backed_block_fd(struct backed_block* bb);
48int64_t backed_block_file_offset(struct backed_block *bb); 48int64_t backed_block_file_offset(struct backed_block* bb);
49uint32_t backed_block_fill_val(struct backed_block *bb); 49uint32_t backed_block_fill_val(struct backed_block* bb);
50enum backed_block_type backed_block_type(struct backed_block *bb); 50enum backed_block_type backed_block_type(struct backed_block* bb);
51int backed_block_split(struct backed_block_list *bbl, struct backed_block *bb, 51int backed_block_split(struct backed_block_list* bbl, struct backed_block* bb, unsigned int max_len);
52 unsigned int max_len); 52
53 53struct backed_block* backed_block_iter_new(struct backed_block_list* bbl);
54struct backed_block *backed_block_iter_new(struct backed_block_list *bbl); 54struct backed_block* backed_block_iter_next(struct backed_block* bb);
55struct backed_block *backed_block_iter_next(struct backed_block *bb); 55
56 56struct backed_block_list* backed_block_list_new(unsigned int block_size);
57struct backed_block_list *backed_block_list_new(unsigned int block_size); 57void backed_block_list_destroy(struct backed_block_list* bbl);
58void backed_block_list_destroy(struct backed_block_list *bbl); 58
59 59void backed_block_list_move(struct backed_block_list* from, struct backed_block_list* to,
60void backed_block_list_move(struct backed_block_list *from, 60 struct backed_block* start, struct backed_block* end);
61 struct backed_block_list *to, struct backed_block *start,
62 struct backed_block *end);
63 61
64#endif 62#endif
diff --git a/libsparse/defs.h b/libsparse/defs.h
index 34e63c57c..28e5cab0e 100644
--- a/libsparse/defs.h
+++ b/libsparse/defs.h
@@ -17,7 +17,7 @@
17#ifndef _LIBSPARSE_DEFS_H_ 17#ifndef _LIBSPARSE_DEFS_H_
18 18
19#ifndef __unused 19#ifndef __unused
20#define __unused __attribute__((__unused__)) 20#define __unused __attribute__((__unused__))
21#endif 21#endif
22 22
23#endif /* _LIBSPARSE_DEFS_H_ */ 23#endif /* _LIBSPARSE_DEFS_H_ */
diff --git a/libsparse/img2simg.cpp b/libsparse/img2simg.cpp
index a0db36f45..4c2c6ca6f 100644
--- a/libsparse/img2simg.cpp
+++ b/libsparse/img2simg.cpp
@@ -22,7 +22,6 @@
22#include <stdio.h> 22#include <stdio.h>
23#include <stdlib.h> 23#include <stdlib.h>
24#include <string.h> 24#include <string.h>
25#include <sys/types.h>
26#include <sys/stat.h> 25#include <sys/stat.h>
27#include <sys/types.h> 26#include <sys/types.h>
28#include <unistd.h> 27#include <unistd.h>
@@ -38,78 +37,76 @@
38#define off64_t off_t 37#define off64_t off_t
39#endif 38#endif
40 39
41void usage() 40void usage() {
42{ 41 fprintf(stderr, "Usage: img2simg <raw_image_file> <sparse_image_file> [<block_size>]\n");
43 fprintf(stderr, "Usage: img2simg <raw_image_file> <sparse_image_file> [<block_size>]\n");
44} 42}
45 43
46int main(int argc, char *argv[]) 44int main(int argc, char* argv[]) {
47{ 45 int in;
48 int in; 46 int out;
49 int out; 47 int ret;
50 int ret; 48 struct sparse_file* s;
51 struct sparse_file *s; 49 unsigned int block_size = 4096;
52 unsigned int block_size = 4096; 50 off64_t len;
53 off64_t len; 51
54 52 if (argc < 3 || argc > 4) {
55 if (argc < 3 || argc > 4) { 53 usage();
56 usage(); 54 exit(-1);
57 exit(-1); 55 }
58 } 56
59 57 if (argc == 4) {
60 if (argc == 4) { 58 block_size = atoi(argv[3]);
61 block_size = atoi(argv[3]); 59 }
62 } 60
63 61 if (block_size < 1024 || block_size % 4 != 0) {
64 if (block_size < 1024 || block_size % 4 != 0) { 62 usage();
65 usage(); 63 exit(-1);
66 exit(-1); 64 }
67 } 65
68 66 if (strcmp(argv[1], "-") == 0) {
69 if (strcmp(argv[1], "-") == 0) { 67 in = STDIN_FILENO;
70 in = STDIN_FILENO; 68 } else {
71 } else { 69 in = open(argv[1], O_RDONLY | O_BINARY);
72 in = open(argv[1], O_RDONLY | O_BINARY); 70 if (in < 0) {
73 if (in < 0) { 71 fprintf(stderr, "Cannot open input file %s\n", argv[1]);
74 fprintf(stderr, "Cannot open input file %s\n", argv[1]); 72 exit(-1);
75 exit(-1); 73 }
76 } 74 }
77 } 75
78 76 if (strcmp(argv[2], "-") == 0) {
79 if (strcmp(argv[2], "-") == 0) { 77 out = STDOUT_FILENO;
80 out = STDOUT_FILENO; 78 } else {
81 } else { 79 out = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0664);
82 out = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0664); 80 if (out < 0) {
83 if (out < 0) { 81 fprintf(stderr, "Cannot open output file %s\n", argv[2]);
84 fprintf(stderr, "Cannot open output file %s\n", argv[2]); 82 exit(-1);
85 exit(-1); 83 }
86 } 84 }
87 } 85
88 86 len = lseek64(in, 0, SEEK_END);
89 len = lseek64(in, 0, SEEK_END); 87 lseek64(in, 0, SEEK_SET);
90 lseek64(in, 0, SEEK_SET); 88
91 89 s = sparse_file_new(block_size, len);
92 s = sparse_file_new(block_size, len); 90 if (!s) {
93 if (!s) { 91 fprintf(stderr, "Failed to create sparse file\n");
94 fprintf(stderr, "Failed to create sparse file\n"); 92 exit(-1);
95 exit(-1); 93 }
96 } 94
97 95 sparse_file_verbose(s);
98 sparse_file_verbose(s); 96 ret = sparse_file_read(s, in, false, false);
99 ret = sparse_file_read(s, in, false, false); 97 if (ret) {
100 if (ret) { 98 fprintf(stderr, "Failed to read file\n");
101 fprintf(stderr, "Failed to read file\n"); 99 exit(-1);
102 exit(-1); 100 }
103 } 101
104 102 ret = sparse_file_write(s, out, false, true, false);
105 ret = sparse_file_write(s, out, false, true, false); 103 if (ret) {
106 if (ret) { 104 fprintf(stderr, "Failed to write sparse file\n");
107 fprintf(stderr, "Failed to write sparse file\n"); 105 exit(-1);
108 exit(-1); 106 }
109 } 107
110 108 close(in);
111 close(in); 109 close(out);
112 close(out); 110
113 111 exit(0);
114 exit(0);
115} 112}
diff --git a/libsparse/output_file.cpp b/libsparse/output_file.cpp
index 8d915508c..5388e7742 100644
--- a/libsparse/output_file.cpp
+++ b/libsparse/output_file.cpp
@@ -48,732 +48,673 @@
48#define off64_t off_t 48#define off64_t off_t
49#endif 49#endif
50 50
51#define min(a, b) \ 51#define min(a, b) \
52 ({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; }) 52 ({ \
53 typeof(a) _a = (a); \
54 typeof(b) _b = (b); \
55 (_a < _b) ? _a : _b; \
56 })
53 57
54#define SPARSE_HEADER_MAJOR_VER 1 58#define SPARSE_HEADER_MAJOR_VER 1
55#define SPARSE_HEADER_MINOR_VER 0 59#define SPARSE_HEADER_MINOR_VER 0
56#define SPARSE_HEADER_LEN (sizeof(sparse_header_t)) 60#define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
57#define CHUNK_HEADER_LEN (sizeof(chunk_header_t)) 61#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
58 62
59#define container_of(inner, outer_t, elem) \ 63#define container_of(inner, outer_t, elem) ((outer_t*)((char*)(inner)-offsetof(outer_t, elem)))
60 ((outer_t *)((char *)(inner) - offsetof(outer_t, elem)))
61 64
62struct output_file_ops { 65struct output_file_ops {
63 int (*open)(struct output_file *, int fd); 66 int (*open)(struct output_file*, int fd);
64 int (*skip)(struct output_file *, int64_t); 67 int (*skip)(struct output_file*, int64_t);
65 int (*pad)(struct output_file *, int64_t); 68 int (*pad)(struct output_file*, int64_t);
66 int (*write)(struct output_file *, void *, size_t); 69 int (*write)(struct output_file*, void*, size_t);
67 void (*close)(struct output_file *); 70 void (*close)(struct output_file*);
68}; 71};
69 72
70struct sparse_file_ops { 73struct sparse_file_ops {
71 int (*write_data_chunk)(struct output_file *out, unsigned int len, 74 int (*write_data_chunk)(struct output_file* out, unsigned int len, void* data);
72 void *data); 75 int (*write_fill_chunk)(struct output_file* out, unsigned int len, uint32_t fill_val);
73 int (*write_fill_chunk)(struct output_file *out, unsigned int len, 76 int (*write_skip_chunk)(struct output_file* out, int64_t len);
74 uint32_t fill_val); 77 int (*write_end_chunk)(struct output_file* out);
75 int (*write_skip_chunk)(struct output_file *out, int64_t len);
76 int (*write_end_chunk)(struct output_file *out);
77}; 78};
78 79
79struct output_file { 80struct output_file {
80 int64_t cur_out_ptr; 81 int64_t cur_out_ptr;
81 unsigned int chunk_cnt; 82 unsigned int chunk_cnt;
82 uint32_t crc32; 83 uint32_t crc32;
83 struct output_file_ops *ops; 84 struct output_file_ops* ops;
84 struct sparse_file_ops *sparse_ops; 85 struct sparse_file_ops* sparse_ops;
85 int use_crc; 86 int use_crc;
86 unsigned int block_size; 87 unsigned int block_size;
87 int64_t len; 88 int64_t len;
88 char *zero_buf; 89 char* zero_buf;
89 uint32_t *fill_buf; 90 uint32_t* fill_buf;
90 char *buf; 91 char* buf;
91}; 92};
92 93
93struct output_file_gz { 94struct output_file_gz {
94 struct output_file out; 95 struct output_file out;
95 gzFile gz_fd; 96 gzFile gz_fd;
96}; 97};
97 98
98#define to_output_file_gz(_o) \ 99#define to_output_file_gz(_o) container_of((_o), struct output_file_gz, out)
99 container_of((_o), struct output_file_gz, out)
100 100
101struct output_file_normal { 101struct output_file_normal {
102 struct output_file out; 102 struct output_file out;
103 int fd; 103 int fd;
104}; 104};
105 105
106#define to_output_file_normal(_o) \ 106#define to_output_file_normal(_o) container_of((_o), struct output_file_normal, out)
107 container_of((_o), struct output_file_normal, out)
108 107
109struct output_file_callback { 108struct output_file_callback {
110 struct output_file out; 109 struct output_file out;
111 void *priv; 110 void* priv;
112 int (*write)(void *priv, const void *buf, size_t len); 111 int (*write)(void* priv, const void* buf, size_t len);
113}; 112};
114 113
115#define to_output_file_callback(_o) \ 114#define to_output_file_callback(_o) container_of((_o), struct output_file_callback, out)
116 container_of((_o), struct output_file_callback, out)
117 115
118static int file_open(struct output_file *out, int fd) 116static int file_open(struct output_file* out, int fd) {
119{ 117 struct output_file_normal* outn = to_output_file_normal(out);
120 struct output_file_normal *outn = to_output_file_normal(out);
121 118
122 outn->fd = fd; 119 outn->fd = fd;
123 return 0; 120 return 0;
124} 121}
125 122
126static int file_skip(struct output_file *out, int64_t cnt) 123static int file_skip(struct output_file* out, int64_t cnt) {
127{ 124 off64_t ret;
128 off64_t ret; 125 struct output_file_normal* outn = to_output_file_normal(out);
129 struct output_file_normal *outn = to_output_file_normal(out);
130 126
131 ret = lseek64(outn->fd, cnt, SEEK_CUR); 127 ret = lseek64(outn->fd, cnt, SEEK_CUR);
132 if (ret < 0) { 128 if (ret < 0) {
133 error_errno("lseek64"); 129 error_errno("lseek64");
134 return -1; 130 return -1;
135 } 131 }
136 return 0; 132 return 0;
137} 133}
138 134
139static int file_pad(struct output_file *out, int64_t len) 135static int file_pad(struct output_file* out, int64_t len) {
140{ 136 int ret;
141 int ret; 137 struct output_file_normal* outn = to_output_file_normal(out);
142 struct output_file_normal *outn = to_output_file_normal(out);
143 138
144 ret = ftruncate64(outn->fd, len); 139 ret = ftruncate64(outn->fd, len);
145 if (ret < 0) { 140 if (ret < 0) {
146 return -errno; 141 return -errno;
147 } 142 }
148 143
149 return 0; 144 return 0;
150} 145}
151 146
152static int file_write(struct output_file *out, void *data, size_t len) 147static int file_write(struct output_file* out, void* data, size_t len) {
153{ 148 ssize_t ret;
154 ssize_t ret; 149 struct output_file_normal* outn = to_output_file_normal(out);
155 struct output_file_normal *outn = to_output_file_normal(out);
156 150
157 while (len > 0) { 151 while (len > 0) {
158 ret = write(outn->fd, data, len); 152 ret = write(outn->fd, data, len);
159 if (ret < 0) { 153 if (ret < 0) {
160 if (errno == EINTR) { 154 if (errno == EINTR) {
161 continue; 155 continue;
162 } 156 }
163 error_errno("write"); 157 error_errno("write");
164 return -1; 158 return -1;
165 } 159 }
166 160
167 data = (char *)data + ret; 161 data = (char*)data + ret;
168 len -= ret; 162 len -= ret;
169 } 163 }
170 164
171 return 0; 165 return 0;
172} 166}
173 167
174static void file_close(struct output_file *out) 168static void file_close(struct output_file* out) {
175{ 169 struct output_file_normal* outn = to_output_file_normal(out);
176 struct output_file_normal *outn = to_output_file_normal(out);
177 170
178 free(outn); 171 free(outn);
179} 172}
180 173
181static struct output_file_ops file_ops = { 174static struct output_file_ops file_ops = {
182 .open = file_open, 175 .open = file_open,
183 .skip = file_skip, 176 .skip = file_skip,
184 .pad = file_pad, 177 .pad = file_pad,
185 .write = file_write, 178 .write = file_write,
186 .close = file_close, 179 .close = file_close,
187}; 180};
188 181
189static int gz_file_open(struct output_file *out, int fd) 182static int gz_file_open(struct output_file* out, int fd) {
190{ 183 struct output_file_gz* outgz = to_output_file_gz(out);
191 struct output_file_gz *outgz = to_output_file_gz(out);
192 184
193 outgz->gz_fd = gzdopen(fd, "wb9"); 185 outgz->gz_fd = gzdopen(fd, "wb9");
194 if (!outgz->gz_fd) { 186 if (!outgz->gz_fd) {
195 error_errno("gzopen"); 187 error_errno("gzopen");
196 return -errno; 188 return -errno;
197 } 189 }
198 190
199 return 0; 191 return 0;
200} 192}
201 193
194static int gz_file_skip(struct output_file* out, int64_t cnt) {
195 off64_t ret;
196 struct output_file_gz* outgz = to_output_file_gz(out);
202 197
203static int gz_file_skip(struct output_file *out, int64_t cnt) 198 ret = gzseek(outgz->gz_fd, cnt, SEEK_CUR);
204{ 199 if (ret < 0) {
205 off64_t ret; 200 error_errno("gzseek");
206 struct output_file_gz *outgz = to_output_file_gz(out); 201 return -1;
207 202 }
208 ret = gzseek(outgz->gz_fd, cnt, SEEK_CUR); 203 return 0;
209 if (ret < 0) {
210 error_errno("gzseek");
211 return -1;
212 }
213 return 0;
214} 204}
215 205
216static int gz_file_pad(struct output_file *out, int64_t len) 206static int gz_file_pad(struct output_file* out, int64_t len) {
217{ 207 off64_t ret;
218 off64_t ret; 208 struct output_file_gz* outgz = to_output_file_gz(out);
219 struct output_file_gz *outgz = to_output_file_gz(out);
220 209
221 ret = gztell(outgz->gz_fd); 210 ret = gztell(outgz->gz_fd);
222 if (ret < 0) { 211 if (ret < 0) {
223 return -1; 212 return -1;
224 } 213 }
225 214
226 if (ret >= len) { 215 if (ret >= len) {
227 return 0; 216 return 0;
228 } 217 }
229 218
230 ret = gzseek(outgz->gz_fd, len - 1, SEEK_SET); 219 ret = gzseek(outgz->gz_fd, len - 1, SEEK_SET);
231 if (ret < 0) { 220 if (ret < 0) {
232 return -1; 221 return -1;
233 } 222 }
234 223
235 gzwrite(outgz->gz_fd, "", 1); 224 gzwrite(outgz->gz_fd, "", 1);
236 225
237 return 0; 226 return 0;
238} 227}
239 228
240static int gz_file_write(struct output_file *out, void *data, size_t len) 229static int gz_file_write(struct output_file* out, void* data, size_t len) {
241{ 230 int ret;
242 int ret; 231 struct output_file_gz* outgz = to_output_file_gz(out);
243 struct output_file_gz *outgz = to_output_file_gz(out);
244 232
245 while (len > 0) { 233 while (len > 0) {
246 ret = gzwrite(outgz->gz_fd, data, 234 ret = gzwrite(outgz->gz_fd, data, min(len, (unsigned int)INT_MAX));
247 min(len, (unsigned int)INT_MAX)); 235 if (ret == 0) {
248 if (ret == 0) { 236 error("gzwrite %s", gzerror(outgz->gz_fd, NULL));
249 error("gzwrite %s", gzerror(outgz->gz_fd, NULL)); 237 return -1;
250 return -1; 238 }
251 } 239 len -= ret;
252 len -= ret; 240 data = (char*)data + ret;
253 data = (char *)data + ret; 241 }
254 }
255 242
256 return 0; 243 return 0;
257} 244}
258 245
259static void gz_file_close(struct output_file *out) 246static void gz_file_close(struct output_file* out) {
260{ 247 struct output_file_gz* outgz = to_output_file_gz(out);
261 struct output_file_gz *outgz = to_output_file_gz(out);
262 248
263 gzclose(outgz->gz_fd); 249 gzclose(outgz->gz_fd);
264 free(outgz); 250 free(outgz);
265} 251}
266 252
267static struct output_file_ops gz_file_ops = { 253static struct output_file_ops gz_file_ops = {
268 .open = gz_file_open, 254 .open = gz_file_open,
269 .skip = gz_file_skip, 255 .skip = gz_file_skip,
270 .pad = gz_file_pad, 256 .pad = gz_file_pad,
271 .write = gz_file_write, 257 .write = gz_file_write,
272 .close = gz_file_close, 258 .close = gz_file_close,
273}; 259};
274 260
275static int callback_file_open(struct output_file *out __unused, int fd __unused) 261static int callback_file_open(struct output_file* out __unused, int fd __unused) {
276{ 262 return 0;
277 return 0;
278} 263}
279 264
280static int callback_file_skip(struct output_file *out, int64_t off) 265static int callback_file_skip(struct output_file* out, int64_t off) {
281{ 266 struct output_file_callback* outc = to_output_file_callback(out);
282 struct output_file_callback *outc = to_output_file_callback(out); 267 int to_write;
283 int to_write; 268 int ret;
284 int ret;
285 269
286 while (off > 0) { 270 while (off > 0) {
287 to_write = min(off, (int64_t)INT_MAX); 271 to_write = min(off, (int64_t)INT_MAX);
288 ret = outc->write(outc->priv, NULL, to_write); 272 ret = outc->write(outc->priv, NULL, to_write);
289 if (ret < 0) { 273 if (ret < 0) {
290 return ret; 274 return ret;
291 } 275 }
292 off -= to_write; 276 off -= to_write;
293 } 277 }
294 278
295 return 0; 279 return 0;
296} 280}
297 281
298static int callback_file_pad(struct output_file *out __unused, int64_t len __unused) 282static int callback_file_pad(struct output_file* out __unused, int64_t len __unused) {
299{ 283 return -1;
300 return -1;
301} 284}
302 285
303static int callback_file_write(struct output_file *out, void *data, size_t len) 286static int callback_file_write(struct output_file* out, void* data, size_t len) {
304{ 287 struct output_file_callback* outc = to_output_file_callback(out);
305 struct output_file_callback *outc = to_output_file_callback(out);
306 288
307 return outc->write(outc->priv, data, len); 289 return outc->write(outc->priv, data, len);
308} 290}
309 291
310static void callback_file_close(struct output_file *out) 292static void callback_file_close(struct output_file* out) {
311{ 293 struct output_file_callback* outc = to_output_file_callback(out);
312 struct output_file_callback *outc = to_output_file_callback(out);
313 294
314 free(outc); 295 free(outc);
315} 296}
316 297
317static struct output_file_ops callback_file_ops = { 298static struct output_file_ops callback_file_ops = {
318 .open = callback_file_open, 299 .open = callback_file_open,
319 .skip = callback_file_skip, 300 .skip = callback_file_skip,
320 .pad = callback_file_pad, 301 .pad = callback_file_pad,
321 .write = callback_file_write, 302 .write = callback_file_write,
322 .close = callback_file_close, 303 .close = callback_file_close,
323}; 304};
324 305
325int read_all(int fd, void *buf, size_t len) 306int read_all(int fd, void* buf, size_t len) {
326{ 307 size_t total = 0;
327 size_t total = 0; 308 int ret;
328 int ret; 309 char* ptr = reinterpret_cast<char*>(buf);
329 char *ptr = reinterpret_cast<char*>(buf); 310
330 311 while (total < len) {
331 while (total < len) { 312 ret = read(fd, ptr, len - total);
332 ret = read(fd, ptr, len - total); 313
333 314 if (ret < 0) return -errno;
334 if (ret < 0) 315
335 return -errno; 316 if (ret == 0) return -EINVAL;
336 317
337 if (ret == 0) 318 ptr += ret;
338 return -EINVAL; 319 total += ret;
339 320 }
340 ptr += ret; 321
341 total += ret; 322 return 0;
342 } 323}
343 324
344 return 0; 325static int write_sparse_skip_chunk(struct output_file* out, int64_t skip_len) {
345} 326 chunk_header_t chunk_header;
346 327 int ret;
347static int write_sparse_skip_chunk(struct output_file *out, int64_t skip_len) 328
348{ 329 if (skip_len % out->block_size) {
349 chunk_header_t chunk_header; 330 error("don't care size %" PRIi64 " is not a multiple of the block size %u", skip_len,
350 int ret; 331 out->block_size);
351 332 return -1;
352 if (skip_len % out->block_size) { 333 }
353 error("don't care size %" PRIi64 " is not a multiple of the block size %u", 334
354 skip_len, out->block_size); 335 /* We are skipping data, so emit a don't care chunk. */
355 return -1; 336 chunk_header.chunk_type = CHUNK_TYPE_DONT_CARE;
356 } 337 chunk_header.reserved1 = 0;
357 338 chunk_header.chunk_sz = skip_len / out->block_size;
358 /* We are skipping data, so emit a don't care chunk. */ 339 chunk_header.total_sz = CHUNK_HEADER_LEN;
359 chunk_header.chunk_type = CHUNK_TYPE_DONT_CARE; 340 ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
360 chunk_header.reserved1 = 0; 341 if (ret < 0) return -1;
361 chunk_header.chunk_sz = skip_len / out->block_size; 342
362 chunk_header.total_sz = CHUNK_HEADER_LEN; 343 out->cur_out_ptr += skip_len;
363 ret = out->ops->write(out, &chunk_header, sizeof(chunk_header)); 344 out->chunk_cnt++;
364 if (ret < 0) 345
365 return -1; 346 return 0;
366 347}
367 out->cur_out_ptr += skip_len; 348
368 out->chunk_cnt++; 349static int write_sparse_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
369 350 chunk_header_t chunk_header;
370 return 0; 351 int rnd_up_len, count;
371} 352 int ret;
372 353
373static int write_sparse_fill_chunk(struct output_file *out, unsigned int len, 354 /* Round up the fill length to a multiple of the block size */
374 uint32_t fill_val) 355 rnd_up_len = ALIGN(len, out->block_size);
375{ 356
376 chunk_header_t chunk_header; 357 /* Finally we can safely emit a chunk of data */
377 int rnd_up_len, count; 358 chunk_header.chunk_type = CHUNK_TYPE_FILL;
378 int ret; 359 chunk_header.reserved1 = 0;
379 360 chunk_header.chunk_sz = rnd_up_len / out->block_size;
380 /* Round up the fill length to a multiple of the block size */ 361 chunk_header.total_sz = CHUNK_HEADER_LEN + sizeof(fill_val);
381 rnd_up_len = ALIGN(len, out->block_size); 362 ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
382 363
383 /* Finally we can safely emit a chunk of data */ 364 if (ret < 0) return -1;
384 chunk_header.chunk_type = CHUNK_TYPE_FILL; 365 ret = out->ops->write(out, &fill_val, sizeof(fill_val));
385 chunk_header.reserved1 = 0; 366 if (ret < 0) return -1;
386 chunk_header.chunk_sz = rnd_up_len / out->block_size; 367
387 chunk_header.total_sz = CHUNK_HEADER_LEN + sizeof(fill_val); 368 if (out->use_crc) {
388 ret = out->ops->write(out, &chunk_header, sizeof(chunk_header)); 369 count = out->block_size / sizeof(uint32_t);
389 370 while (count--) out->crc32 = sparse_crc32(out->crc32, &fill_val, sizeof(uint32_t));
390 if (ret < 0) 371 }
391 return -1; 372
392 ret = out->ops->write(out, &fill_val, sizeof(fill_val)); 373 out->cur_out_ptr += rnd_up_len;
393 if (ret < 0) 374 out->chunk_cnt++;
394 return -1; 375
395 376 return 0;
396 if (out->use_crc) { 377}
397 count = out->block_size / sizeof(uint32_t); 378
398 while (count--) 379static int write_sparse_data_chunk(struct output_file* out, unsigned int len, void* data) {
399 out->crc32 = sparse_crc32(out->crc32, &fill_val, sizeof(uint32_t)); 380 chunk_header_t chunk_header;
400 } 381 int rnd_up_len, zero_len;
401 382 int ret;
402 out->cur_out_ptr += rnd_up_len; 383
403 out->chunk_cnt++; 384 /* Round up the data length to a multiple of the block size */
404 385 rnd_up_len = ALIGN(len, out->block_size);
405 return 0; 386 zero_len = rnd_up_len - len;
406} 387
407 388 /* Finally we can safely emit a chunk of data */
408static int write_sparse_data_chunk(struct output_file *out, unsigned int len, 389 chunk_header.chunk_type = CHUNK_TYPE_RAW;
409 void *data) 390 chunk_header.reserved1 = 0;
410{ 391 chunk_header.chunk_sz = rnd_up_len / out->block_size;
411 chunk_header_t chunk_header; 392 chunk_header.total_sz = CHUNK_HEADER_LEN + rnd_up_len;
412 int rnd_up_len, zero_len; 393 ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
413 int ret; 394
414 395 if (ret < 0) return -1;
415 /* Round up the data length to a multiple of the block size */ 396 ret = out->ops->write(out, data, len);
416 rnd_up_len = ALIGN(len, out->block_size); 397 if (ret < 0) return -1;
417 zero_len = rnd_up_len - len; 398 if (zero_len) {
418 399 ret = out->ops->write(out, out->zero_buf, zero_len);
419 /* Finally we can safely emit a chunk of data */ 400 if (ret < 0) return -1;
420 chunk_header.chunk_type = CHUNK_TYPE_RAW; 401 }
421 chunk_header.reserved1 = 0; 402
422 chunk_header.chunk_sz = rnd_up_len / out->block_size; 403 if (out->use_crc) {
423 chunk_header.total_sz = CHUNK_HEADER_LEN + rnd_up_len; 404 out->crc32 = sparse_crc32(out->crc32, data, len);
424 ret = out->ops->write(out, &chunk_header, sizeof(chunk_header)); 405 if (zero_len) out->crc32 = sparse_crc32(out->crc32, out->zero_buf, zero_len);
425 406 }
426 if (ret < 0) 407
427 return -1; 408 out->cur_out_ptr += rnd_up_len;
428 ret = out->ops->write(out, data, len); 409 out->chunk_cnt++;
429 if (ret < 0) 410
430 return -1; 411 return 0;
431 if (zero_len) { 412}
432 ret = out->ops->write(out, out->zero_buf, zero_len); 413
433 if (ret < 0) 414int write_sparse_end_chunk(struct output_file* out) {
434 return -1; 415 chunk_header_t chunk_header;
435 } 416 int ret;
436 417
437 if (out->use_crc) { 418 if (out->use_crc) {
438 out->crc32 = sparse_crc32(out->crc32, data, len); 419 chunk_header.chunk_type = CHUNK_TYPE_CRC32;
439 if (zero_len) 420 chunk_header.reserved1 = 0;
440 out->crc32 = sparse_crc32(out->crc32, out->zero_buf, zero_len); 421 chunk_header.chunk_sz = 0;
441 } 422 chunk_header.total_sz = CHUNK_HEADER_LEN + 4;
442 423
443 out->cur_out_ptr += rnd_up_len; 424 ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
444 out->chunk_cnt++; 425 if (ret < 0) {
445 426 return ret;
446 return 0; 427 }
447} 428 out->ops->write(out, &out->crc32, 4);
448 429 if (ret < 0) {
449int write_sparse_end_chunk(struct output_file *out) 430 return ret;
450{ 431 }
451 chunk_header_t chunk_header; 432
452 int ret; 433 out->chunk_cnt++;
453 434 }
454 if (out->use_crc) { 435
455 chunk_header.chunk_type = CHUNK_TYPE_CRC32; 436 return 0;
456 chunk_header.reserved1 = 0;
457 chunk_header.chunk_sz = 0;
458 chunk_header.total_sz = CHUNK_HEADER_LEN + 4;
459
460 ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
461 if (ret < 0) {
462 return ret;
463 }
464 out->ops->write(out, &out->crc32, 4);
465 if (ret < 0) {
466 return ret;
467 }
468
469 out->chunk_cnt++;
470 }
471
472 return 0;
473} 437}
474 438
475static struct sparse_file_ops sparse_file_ops = { 439static struct sparse_file_ops sparse_file_ops = {
476 .write_data_chunk = write_sparse_data_chunk, 440 .write_data_chunk = write_sparse_data_chunk,
477 .write_fill_chunk = write_sparse_fill_chunk, 441 .write_fill_chunk = write_sparse_fill_chunk,
478 .write_skip_chunk = write_sparse_skip_chunk, 442 .write_skip_chunk = write_sparse_skip_chunk,
479 .write_end_chunk = write_sparse_end_chunk, 443 .write_end_chunk = write_sparse_end_chunk,
480}; 444};
481 445
482static int write_normal_data_chunk(struct output_file *out, unsigned int len, 446static int write_normal_data_chunk(struct output_file* out, unsigned int len, void* data) {
483 void *data) 447 int ret;
484{ 448 unsigned int rnd_up_len = ALIGN(len, out->block_size);
485 int ret;
486 unsigned int rnd_up_len = ALIGN(len, out->block_size);
487 449
488 ret = out->ops->write(out, data, len); 450 ret = out->ops->write(out, data, len);
489 if (ret < 0) { 451 if (ret < 0) {
490 return ret; 452 return ret;
491 } 453 }
492 454
493 if (rnd_up_len > len) { 455 if (rnd_up_len > len) {
494 ret = out->ops->skip(out, rnd_up_len - len); 456 ret = out->ops->skip(out, rnd_up_len - len);
495 } 457 }
496 458
497 return ret; 459 return ret;
498} 460}
499 461
500static int write_normal_fill_chunk(struct output_file *out, unsigned int len, 462static int write_normal_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
501 uint32_t fill_val) 463 int ret;
502{ 464 unsigned int i;
503 int ret; 465 unsigned int write_len;
504 unsigned int i;
505 unsigned int write_len;
506 466
507 /* Initialize fill_buf with the fill_val */ 467 /* Initialize fill_buf with the fill_val */
508 for (i = 0; i < out->block_size / sizeof(uint32_t); i++) { 468 for (i = 0; i < out->block_size / sizeof(uint32_t); i++) {
509 out->fill_buf[i] = fill_val; 469 out->fill_buf[i] = fill_val;
510 } 470 }
511 471
512 while (len) { 472 while (len) {
513 write_len = min(len, out->block_size); 473 write_len = min(len, out->block_size);
514 ret = out->ops->write(out, out->fill_buf, write_len); 474 ret = out->ops->write(out, out->fill_buf, write_len);
515 if (ret < 0) { 475 if (ret < 0) {
516 return ret; 476 return ret;
517 } 477 }
518 478
519 len -= write_len; 479 len -= write_len;
520 } 480 }
521 481
522 return 0; 482 return 0;
523} 483}
524 484
525static int write_normal_skip_chunk(struct output_file *out, int64_t len) 485static int write_normal_skip_chunk(struct output_file* out, int64_t len) {
526{ 486 return out->ops->skip(out, len);
527 return out->ops->skip(out, len);
528} 487}
529 488
530int write_normal_end_chunk(struct output_file *out) 489int write_normal_end_chunk(struct output_file* out) {
531{ 490 return out->ops->pad(out, out->len);
532 return out->ops->pad(out, out->len);
533} 491}
534 492
535static struct sparse_file_ops normal_file_ops = { 493static struct sparse_file_ops normal_file_ops = {
536 .write_data_chunk = write_normal_data_chunk, 494 .write_data_chunk = write_normal_data_chunk,
537 .write_fill_chunk = write_normal_fill_chunk, 495 .write_fill_chunk = write_normal_fill_chunk,
538 .write_skip_chunk = write_normal_skip_chunk, 496 .write_skip_chunk = write_normal_skip_chunk,
539 .write_end_chunk = write_normal_end_chunk, 497 .write_end_chunk = write_normal_end_chunk,
540}; 498};
541 499
542void output_file_close(struct output_file *out) 500void output_file_close(struct output_file* out) {
543{ 501 out->sparse_ops->write_end_chunk(out);
544 out->sparse_ops->write_end_chunk(out); 502 out->ops->close(out);
545 out->ops->close(out); 503}
546} 504
547 505static int output_file_init(struct output_file* out, int block_size, int64_t len, bool sparse,
548static int output_file_init(struct output_file *out, int block_size, 506 int chunks, bool crc) {
549 int64_t len, bool sparse, int chunks, bool crc) 507 int ret;
550{ 508
551 int ret; 509 out->len = len;
552 510 out->block_size = block_size;
553 out->len = len; 511 out->cur_out_ptr = 0ll;
554 out->block_size = block_size; 512 out->chunk_cnt = 0;
555 out->cur_out_ptr = 0ll; 513 out->crc32 = 0;
556 out->chunk_cnt = 0; 514 out->use_crc = crc;
557 out->crc32 = 0; 515
558 out->use_crc = crc; 516 out->zero_buf = reinterpret_cast<char*>(calloc(block_size, 1));
559 517 if (!out->zero_buf) {
560 out->zero_buf = reinterpret_cast<char*>(calloc(block_size, 1)); 518 error_errno("malloc zero_buf");
561 if (!out->zero_buf) { 519 return -ENOMEM;
562 error_errno("malloc zero_buf"); 520 }
563 return -ENOMEM; 521
564 } 522 out->fill_buf = reinterpret_cast<uint32_t*>(calloc(block_size, 1));
565 523 if (!out->fill_buf) {
566 out->fill_buf = reinterpret_cast<uint32_t*>(calloc(block_size, 1)); 524 error_errno("malloc fill_buf");
567 if (!out->fill_buf) { 525 ret = -ENOMEM;
568 error_errno("malloc fill_buf"); 526 goto err_fill_buf;
569 ret = -ENOMEM; 527 }
570 goto err_fill_buf; 528
571 } 529 if (sparse) {
572 530 out->sparse_ops = &sparse_file_ops;
573 if (sparse) { 531 } else {
574 out->sparse_ops = &sparse_file_ops; 532 out->sparse_ops = &normal_file_ops;
575 } else { 533 }
576 out->sparse_ops = &normal_file_ops; 534
577 } 535 if (sparse) {
578 536 sparse_header_t sparse_header = {
579 if (sparse) { 537 .magic = SPARSE_HEADER_MAGIC,
580 sparse_header_t sparse_header = { 538 .major_version = SPARSE_HEADER_MAJOR_VER,
581 .magic = SPARSE_HEADER_MAGIC, 539 .minor_version = SPARSE_HEADER_MINOR_VER,
582 .major_version = SPARSE_HEADER_MAJOR_VER, 540 .file_hdr_sz = SPARSE_HEADER_LEN,
583 .minor_version = SPARSE_HEADER_MINOR_VER, 541 .chunk_hdr_sz = CHUNK_HEADER_LEN,
584 .file_hdr_sz = SPARSE_HEADER_LEN, 542 .blk_sz = out->block_size,
585 .chunk_hdr_sz = CHUNK_HEADER_LEN, 543 .total_blks = static_cast<unsigned>(DIV_ROUND_UP(out->len, out->block_size)),
586 .blk_sz = out->block_size, 544 .total_chunks = static_cast<unsigned>(chunks),
587 .total_blks = static_cast<unsigned>(DIV_ROUND_UP(out->len, out->block_size)), 545 .image_checksum = 0};
588 .total_chunks = static_cast<unsigned>(chunks), 546
589 .image_checksum = 0 547 if (out->use_crc) {
590 }; 548 sparse_header.total_chunks++;
591 549 }
592 if (out->use_crc) { 550
593 sparse_header.total_chunks++; 551 ret = out->ops->write(out, &sparse_header, sizeof(sparse_header));
594 } 552 if (ret < 0) {
595 553 goto err_write;
596 ret = out->ops->write(out, &sparse_header, sizeof(sparse_header)); 554 }
597 if (ret < 0) { 555 }
598 goto err_write; 556
599 } 557 return 0;
600 }
601
602 return 0;
603 558
604err_write: 559err_write:
605 free(out->fill_buf); 560 free(out->fill_buf);
606err_fill_buf: 561err_fill_buf:
607 free(out->zero_buf); 562 free(out->zero_buf);
608 return ret; 563 return ret;
609} 564}
610 565
611static struct output_file *output_file_new_gz(void) 566static struct output_file* output_file_new_gz(void) {
612{ 567 struct output_file_gz* outgz =
613 struct output_file_gz *outgz = reinterpret_cast<struct output_file_gz*>( 568 reinterpret_cast<struct output_file_gz*>(calloc(1, sizeof(struct output_file_gz)));
614 calloc(1, sizeof(struct output_file_gz))); 569 if (!outgz) {
615 if (!outgz) { 570 error_errno("malloc struct outgz");
616 error_errno("malloc struct outgz"); 571 return NULL;
617 return NULL; 572 }
618 }
619 573
620 outgz->out.ops = &gz_file_ops; 574 outgz->out.ops = &gz_file_ops;
621 575
622 return &outgz->out; 576 return &outgz->out;
623} 577}
624 578
625static struct output_file *output_file_new_normal(void) 579static struct output_file* output_file_new_normal(void) {
626{ 580 struct output_file_normal* outn =
627 struct output_file_normal *outn = reinterpret_cast<struct output_file_normal*>( 581 reinterpret_cast<struct output_file_normal*>(calloc(1, sizeof(struct output_file_normal)));
628 calloc(1, sizeof(struct output_file_normal))); 582 if (!outn) {
629 if (!outn) { 583 error_errno("malloc struct outn");
630 error_errno("malloc struct outn"); 584 return NULL;
631 return NULL; 585 }
632 }
633 586
634 outn->out.ops = &file_ops; 587 outn->out.ops = &file_ops;
635 588
636 return &outn->out; 589 return &outn->out;
637} 590}
638 591
639struct output_file *output_file_open_callback( 592struct output_file* output_file_open_callback(int (*write)(void*, const void*, size_t), void* priv,
640 int (*write)(void *, const void *, size_t), 593 unsigned int block_size, int64_t len, int gz __unused,
641 void *priv, unsigned int block_size, int64_t len, 594 int sparse, int chunks, int crc) {
642 int gz __unused, int sparse, int chunks, int crc) 595 int ret;
643{ 596 struct output_file_callback* outc;
644 int ret;
645 struct output_file_callback *outc;
646 597
647 outc = reinterpret_cast<struct output_file_callback*>( 598 outc =
648 calloc(1, sizeof(struct output_file_callback))); 599 reinterpret_cast<struct output_file_callback*>(calloc(1, sizeof(struct output_file_callback)));
649 if (!outc) { 600 if (!outc) {
650 error_errno("malloc struct outc"); 601 error_errno("malloc struct outc");
651 return NULL; 602 return NULL;
652 } 603 }
653 604
654 outc->out.ops = &callback_file_ops; 605 outc->out.ops = &callback_file_ops;
655 outc->priv = priv; 606 outc->priv = priv;
656 outc->write = write; 607 outc->write = write;
657 608
658 ret = output_file_init(&outc->out, block_size, len, sparse, chunks, crc); 609 ret = output_file_init(&outc->out, block_size, len, sparse, chunks, crc);
659 if (ret < 0) { 610 if (ret < 0) {
660 free(outc); 611 free(outc);
661 return NULL; 612 return NULL;
662 } 613 }
663 614
664 return &outc->out; 615 return &outc->out;
665} 616}
666 617
667struct output_file *output_file_open_fd(int fd, unsigned int block_size, int64_t len, 618struct output_file* output_file_open_fd(int fd, unsigned int block_size, int64_t len, int gz,
668 int gz, int sparse, int chunks, int crc) 619 int sparse, int chunks, int crc) {
669{ 620 int ret;
670 int ret; 621 struct output_file* out;
671 struct output_file *out;
672 622
673 if (gz) { 623 if (gz) {
674 out = output_file_new_gz(); 624 out = output_file_new_gz();
675 } else { 625 } else {
676 out = output_file_new_normal(); 626 out = output_file_new_normal();
677 } 627 }
678 if (!out) { 628 if (!out) {
679 return NULL; 629 return NULL;
680 } 630 }
681 631
682 out->ops->open(out, fd); 632 out->ops->open(out, fd);
683 633
684 ret = output_file_init(out, block_size, len, sparse, chunks, crc); 634 ret = output_file_init(out, block_size, len, sparse, chunks, crc);
685 if (ret < 0) { 635 if (ret < 0) {
686 free(out); 636 free(out);
687 return NULL; 637 return NULL;
688 } 638 }
689 639
690 return out; 640 return out;
691} 641}
692 642
693/* Write a contiguous region of data blocks from a memory buffer */ 643/* Write a contiguous region of data blocks from a memory buffer */
694int write_data_chunk(struct output_file *out, unsigned int len, void *data) 644int write_data_chunk(struct output_file* out, unsigned int len, void* data) {
695{ 645 return out->sparse_ops->write_data_chunk(out, len, data);
696 return out->sparse_ops->write_data_chunk(out, len, data);
697} 646}
698 647
699/* Write a contiguous region of data blocks with a fill value */ 648/* Write a contiguous region of data blocks with a fill value */
700int write_fill_chunk(struct output_file *out, unsigned int len, 649int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
701 uint32_t fill_val) 650 return out->sparse_ops->write_fill_chunk(out, len, fill_val);
702{
703 return out->sparse_ops->write_fill_chunk(out, len, fill_val);
704} 651}
705 652
706int write_fd_chunk(struct output_file *out, unsigned int len, 653int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t offset) {
707 int fd, int64_t offset) 654 int ret;
708{ 655 int64_t aligned_offset;
709 int ret; 656 int aligned_diff;
710 int64_t aligned_offset; 657 uint64_t buffer_size;
711 int aligned_diff; 658 char* ptr;
712 uint64_t buffer_size;
713 char *ptr;
714 659
715 aligned_offset = offset & ~(4096 - 1); 660 aligned_offset = offset & ~(4096 - 1);
716 aligned_diff = offset - aligned_offset; 661 aligned_diff = offset - aligned_offset;
717 buffer_size = (uint64_t)len + (uint64_t)aligned_diff; 662 buffer_size = (uint64_t)len + (uint64_t)aligned_diff;
718 663
719#ifndef _WIN32 664#ifndef _WIN32
720 if (buffer_size > SIZE_MAX) 665 if (buffer_size > SIZE_MAX) return -E2BIG;
721 return -E2BIG; 666 char* data =
722 char *data = reinterpret_cast<char*>(mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, fd, 667 reinterpret_cast<char*>(mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, fd, aligned_offset));
723 aligned_offset)); 668 if (data == MAP_FAILED) {
724 if (data == MAP_FAILED) { 669 return -errno;
725 return -errno; 670 }
726 } 671 ptr = data + aligned_diff;
727 ptr = data + aligned_diff;
728#else 672#else
729 off64_t pos; 673 off64_t pos;
730 char *data = reinterpret_cast<char*>(malloc(len)); 674 char* data = reinterpret_cast<char*>(malloc(len));
731 if (!data) { 675 if (!data) {
732 return -errno; 676 return -errno;
733 } 677 }
734 pos = lseek64(fd, offset, SEEK_SET); 678 pos = lseek64(fd, offset, SEEK_SET);
735 if (pos < 0) { 679 if (pos < 0) {
736 free(data); 680 free(data);
737 return -errno; 681 return -errno;
738 } 682 }
739 ret = read_all(fd, data, len); 683 ret = read_all(fd, data, len);
740 if (ret < 0) { 684 if (ret < 0) {
741 free(data); 685 free(data);
742 return ret; 686 return ret;
743 } 687 }
744 ptr = data; 688 ptr = data;
745#endif 689#endif
746 690
747 ret = out->sparse_ops->write_data_chunk(out, len, ptr); 691 ret = out->sparse_ops->write_data_chunk(out, len, ptr);
748 692
749#ifndef _WIN32 693#ifndef _WIN32
750 munmap(data, buffer_size); 694 munmap(data, buffer_size);
751#else 695#else
752 free(data); 696 free(data);
753#endif 697#endif
754 698
755 return ret; 699 return ret;
756} 700}
757 701
758/* Write a contiguous region of data blocks from a file */ 702/* Write a contiguous region of data blocks from a file */
759int write_file_chunk(struct output_file *out, unsigned int len, 703int write_file_chunk(struct output_file* out, unsigned int len, const char* file, int64_t offset) {
760 const char *file, int64_t offset) 704 int ret;
761{
762 int ret;
763 705
764 int file_fd = open(file, O_RDONLY | O_BINARY); 706 int file_fd = open(file, O_RDONLY | O_BINARY);
765 if (file_fd < 0) { 707 if (file_fd < 0) {
766 return -errno; 708 return -errno;
767 } 709 }
768 710
769 ret = write_fd_chunk(out, len, file_fd, offset); 711 ret = write_fd_chunk(out, len, file_fd, offset);
770 712
771 close(file_fd); 713 close(file_fd);
772 714
773 return ret; 715 return ret;
774} 716}
775 717
776int write_skip_chunk(struct output_file *out, int64_t len) 718int write_skip_chunk(struct output_file* out, int64_t len) {
777{ 719 return out->sparse_ops->write_skip_chunk(out, len);
778 return out->sparse_ops->write_skip_chunk(out, len);
779} 720}
diff --git a/libsparse/output_file.h b/libsparse/output_file.h
index 690f61057..278430b6f 100644
--- a/libsparse/output_file.h
+++ b/libsparse/output_file.h
@@ -25,23 +25,19 @@ extern "C" {
25 25
26struct output_file; 26struct output_file;
27 27
28struct output_file *output_file_open_fd(int fd, unsigned int block_size, int64_t len, 28struct output_file* output_file_open_fd(int fd, unsigned int block_size, int64_t len, int gz,
29 int gz, int sparse, int chunks, int crc); 29 int sparse, int chunks, int crc);
30struct output_file *output_file_open_callback( 30struct output_file* output_file_open_callback(int (*write)(void*, const void*, size_t), void* priv,
31 int (*write)(void *, const void *, size_t), 31 unsigned int block_size, int64_t len, int gz,
32 void *priv, unsigned int block_size, int64_t len, int gz, int sparse, 32 int sparse, int chunks, int crc);
33 int chunks, int crc); 33int write_data_chunk(struct output_file* out, unsigned int len, void* data);
34int write_data_chunk(struct output_file *out, unsigned int len, void *data); 34int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val);
35int write_fill_chunk(struct output_file *out, unsigned int len, 35int write_file_chunk(struct output_file* out, unsigned int len, const char* file, int64_t offset);
36 uint32_t fill_val); 36int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t offset);
37int write_file_chunk(struct output_file *out, unsigned int len, 37int write_skip_chunk(struct output_file* out, int64_t len);
38 const char *file, int64_t offset); 38void output_file_close(struct output_file* out);
39int write_fd_chunk(struct output_file *out, unsigned int len, 39
40 int fd, int64_t offset); 40int read_all(int fd, void* buf, size_t len);
41int write_skip_chunk(struct output_file *out, int64_t len);
42void output_file_close(struct output_file *out);
43
44int read_all(int fd, void *buf, size_t len);
45 41
46#ifdef __cplusplus 42#ifdef __cplusplus
47} 43}
diff --git a/libsparse/simg2img.cpp b/libsparse/simg2img.cpp
index b9b438e63..8ba5f6989 100644
--- a/libsparse/simg2img.cpp
+++ b/libsparse/simg2img.cpp
@@ -21,7 +21,6 @@
21#include <stdio.h> 21#include <stdio.h>
22#include <stdlib.h> 22#include <stdlib.h>
23#include <string.h> 23#include <string.h>
24#include <sys/types.h>
25#include <sys/stat.h> 24#include <sys/stat.h>
26#include <sys/types.h> 25#include <sys/types.h>
27#include <unistd.h> 26#include <unistd.h>
@@ -30,61 +29,58 @@
30#define O_BINARY 0 29#define O_BINARY 0
31#endif 30#endif
32 31
33void usage() 32void usage() {
34{
35 fprintf(stderr, "Usage: simg2img <sparse_image_files> <raw_image_file>\n"); 33 fprintf(stderr, "Usage: simg2img <sparse_image_files> <raw_image_file>\n");
36} 34}
37 35
38int main(int argc, char *argv[]) 36int main(int argc, char* argv[]) {
39{ 37 int in;
40 int in; 38 int out;
41 int out; 39 int i;
42 int i; 40 struct sparse_file* s;
43 struct sparse_file *s;
44 41
45 if (argc < 3) { 42 if (argc < 3) {
46 usage(); 43 usage();
47 exit(-1); 44 exit(-1);
48 } 45 }
49 46
50 out = open(argv[argc - 1], O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0664); 47 out = open(argv[argc - 1], O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0664);
51 if (out < 0) { 48 if (out < 0) {
52 fprintf(stderr, "Cannot open output file %s\n", argv[argc - 1]); 49 fprintf(stderr, "Cannot open output file %s\n", argv[argc - 1]);
53 exit(-1); 50 exit(-1);
54 } 51 }
55 52
56 for (i = 1; i < argc - 1; i++) { 53 for (i = 1; i < argc - 1; i++) {
57 if (strcmp(argv[i], "-") == 0) { 54 if (strcmp(argv[i], "-") == 0) {
58 in = STDIN_FILENO; 55 in = STDIN_FILENO;
59 } else { 56 } else {
60 in = open(argv[i], O_RDONLY | O_BINARY); 57 in = open(argv[i], O_RDONLY | O_BINARY);
61 if (in < 0) { 58 if (in < 0) {
62 fprintf(stderr, "Cannot open input file %s\n", argv[i]); 59 fprintf(stderr, "Cannot open input file %s\n", argv[i]);
63 exit(-1); 60 exit(-1);
64 } 61 }
65 } 62 }
66 63
67 s = sparse_file_import(in, true, false); 64 s = sparse_file_import(in, true, false);
68 if (!s) { 65 if (!s) {
69 fprintf(stderr, "Failed to read sparse file\n"); 66 fprintf(stderr, "Failed to read sparse file\n");
70 exit(-1); 67 exit(-1);
71 } 68 }
72 69
73 if (lseek(out, 0, SEEK_SET) == -1) { 70 if (lseek(out, 0, SEEK_SET) == -1) {
74 perror("lseek failed"); 71 perror("lseek failed");
75 exit(EXIT_FAILURE); 72 exit(EXIT_FAILURE);
76 } 73 }
77 74
78 if (sparse_file_write(s, out, false, false, false) < 0) { 75 if (sparse_file_write(s, out, false, false, false) < 0) {
79 fprintf(stderr, "Cannot write output file\n"); 76 fprintf(stderr, "Cannot write output file\n");
80 exit(-1); 77 exit(-1);
81 } 78 }
82 sparse_file_destroy(s); 79 sparse_file_destroy(s);
83 close(in); 80 close(in);
84 } 81 }
85 82
86 close(out); 83 close(out);
87 84
88 exit(0); 85 exit(0);
89} 86}
90
diff --git a/libsparse/simg2simg.cpp b/libsparse/simg2simg.cpp
index 6f02f4fcc..7e6570159 100644
--- a/libsparse/simg2simg.cpp
+++ b/libsparse/simg2simg.cpp
@@ -22,7 +22,6 @@
22#include <stdio.h> 22#include <stdio.h>
23#include <stdlib.h> 23#include <stdlib.h>
24#include <string.h> 24#include <string.h>
25#include <sys/types.h>
26#include <sys/stat.h> 25#include <sys/stat.h>
27#include <sys/types.h> 26#include <sys/types.h>
28#include <unistd.h> 27#include <unistd.h>
@@ -33,82 +32,80 @@
33#define O_BINARY 0 32#define O_BINARY 0
34#endif 33#endif
35 34
36void usage() 35void usage() {
37{
38 fprintf(stderr, "Usage: simg2simg <sparse image file> <sparse_image_file> <max_size>\n"); 36 fprintf(stderr, "Usage: simg2simg <sparse image file> <sparse_image_file> <max_size>\n");
39} 37}
40 38
41int main(int argc, char *argv[]) 39int main(int argc, char* argv[]) {
42{ 40 int in;
43 int in; 41 int out;
44 int out; 42 int i;
45 int i; 43 int ret;
46 int ret; 44 struct sparse_file* s;
47 struct sparse_file *s; 45 int64_t max_size;
48 int64_t max_size; 46 struct sparse_file** out_s;
49 struct sparse_file **out_s; 47 int files;
50 int files; 48 char filename[4096];
51 char filename[4096]; 49
52 50 if (argc != 4) {
53 if (argc != 4) { 51 usage();
54 usage(); 52 exit(-1);
55 exit(-1); 53 }
56 } 54
57 55 max_size = atoll(argv[3]);
58 max_size = atoll(argv[3]); 56
59 57 in = open(argv[1], O_RDONLY | O_BINARY);
60 in = open(argv[1], O_RDONLY | O_BINARY); 58 if (in < 0) {
61 if (in < 0) { 59 fprintf(stderr, "Cannot open input file %s\n", argv[1]);
62 fprintf(stderr, "Cannot open input file %s\n", argv[1]); 60 exit(-1);
63 exit(-1); 61 }
64 } 62
65 63 s = sparse_file_import(in, true, false);
66 s = sparse_file_import(in, true, false); 64 if (!s) {
67 if (!s) { 65 fprintf(stderr, "Failed to import sparse file\n");
68 fprintf(stderr, "Failed to import sparse file\n"); 66 exit(-1);
69 exit(-1); 67 }
70 } 68
71 69 files = sparse_file_resparse(s, max_size, NULL, 0);
72 files = sparse_file_resparse(s, max_size, NULL, 0); 70 if (files < 0) {
73 if (files < 0) { 71 fprintf(stderr, "Failed to resparse\n");
74 fprintf(stderr, "Failed to resparse\n"); 72 exit(-1);
75 exit(-1); 73 }
76 } 74
77 75 out_s = calloc(sizeof(struct sparse_file*), files);
78 out_s = calloc(sizeof(struct sparse_file *), files); 76 if (!out_s) {
79 if (!out_s) { 77 fprintf(stderr, "Failed to allocate sparse file array\n");
80 fprintf(stderr, "Failed to allocate sparse file array\n"); 78 exit(-1);
81 exit(-1); 79 }
82 } 80
83 81 files = sparse_file_resparse(s, max_size, out_s, files);
84 files = sparse_file_resparse(s, max_size, out_s, files); 82 if (files < 0) {
85 if (files < 0) { 83 fprintf(stderr, "Failed to resparse\n");
86 fprintf(stderr, "Failed to resparse\n"); 84 exit(-1);
87 exit(-1); 85 }
88 } 86
89 87 for (i = 0; i < files; i++) {
90 for (i = 0; i < files; i++) { 88 ret = snprintf(filename, sizeof(filename), "%s.%d", argv[2], i);
91 ret = snprintf(filename, sizeof(filename), "%s.%d", argv[2], i); 89 if (ret >= (int)sizeof(filename)) {
92 if (ret >= (int)sizeof(filename)) { 90 fprintf(stderr, "Filename too long\n");
93 fprintf(stderr, "Filename too long\n"); 91 exit(-1);
94 exit(-1); 92 }
95 } 93
96 94 out = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0664);
97 out = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0664); 95 if (out < 0) {
98 if (out < 0) { 96 fprintf(stderr, "Cannot open output file %s\n", argv[2]);
99 fprintf(stderr, "Cannot open output file %s\n", argv[2]); 97 exit(-1);
100 exit(-1); 98 }
101 } 99
102 100 ret = sparse_file_write(out_s[i], out, false, true, false);
103 ret = sparse_file_write(out_s[i], out, false, true, false); 101 if (ret) {
104 if (ret) { 102 fprintf(stderr, "Failed to write sparse file\n");
105 fprintf(stderr, "Failed to write sparse file\n"); 103 exit(-1);
106 exit(-1); 104 }
107 } 105 close(out);
108 close(out); 106 }
109 } 107
110 108 close(in);
111 close(in); 109
112 110 exit(0);
113 exit(0);
114} 111}
diff --git a/libsparse/sparse.cpp b/libsparse/sparse.cpp
index 992945f44..6ff97b6ab 100644
--- a/libsparse/sparse.cpp
+++ b/libsparse/sparse.cpp
@@ -22,374 +22,327 @@
22#include "defs.h" 22#include "defs.h"
23#include "sparse_file.h" 23#include "sparse_file.h"
24 24
25#include "output_file.h"
26#include "backed_block.h" 25#include "backed_block.h"
26#include "output_file.h"
27#include "sparse_defs.h" 27#include "sparse_defs.h"
28#include "sparse_format.h" 28#include "sparse_format.h"
29 29
30struct sparse_file *sparse_file_new(unsigned int block_size, int64_t len) 30struct sparse_file* sparse_file_new(unsigned int block_size, int64_t len) {
31{ 31 struct sparse_file* s = reinterpret_cast<sparse_file*>(calloc(sizeof(struct sparse_file), 1));
32 struct sparse_file *s = reinterpret_cast<sparse_file*>(calloc(sizeof(struct sparse_file), 1)); 32 if (!s) {
33 if (!s) { 33 return NULL;
34 return NULL; 34 }
35 }
36 35
37 s->backed_block_list = backed_block_list_new(block_size); 36 s->backed_block_list = backed_block_list_new(block_size);
38 if (!s->backed_block_list) { 37 if (!s->backed_block_list) {
39 free(s); 38 free(s);
40 return NULL; 39 return NULL;
41 } 40 }
42 41
43 s->block_size = block_size; 42 s->block_size = block_size;
44 s->len = len; 43 s->len = len;
45 44
46 return s; 45 return s;
47} 46}
48 47
49void sparse_file_destroy(struct sparse_file *s) 48void sparse_file_destroy(struct sparse_file* s) {
50{ 49 backed_block_list_destroy(s->backed_block_list);
51 backed_block_list_destroy(s->backed_block_list); 50 free(s);
52 free(s);
53} 51}
54 52
55int sparse_file_add_data(struct sparse_file *s, 53int sparse_file_add_data(struct sparse_file* s, void* data, unsigned int len, unsigned int block) {
56 void *data, unsigned int len, unsigned int block) 54 return backed_block_add_data(s->backed_block_list, data, len, block);
57{
58 return backed_block_add_data(s->backed_block_list, data, len, block);
59} 55}
60 56
61int sparse_file_add_fill(struct sparse_file *s, 57int sparse_file_add_fill(struct sparse_file* s, uint32_t fill_val, unsigned int len,
62 uint32_t fill_val, unsigned int len, unsigned int block) 58 unsigned int block) {
63{ 59 return backed_block_add_fill(s->backed_block_list, fill_val, len, block);
64 return backed_block_add_fill(s->backed_block_list, fill_val, len, block);
65} 60}
66 61
67int sparse_file_add_file(struct sparse_file *s, 62int sparse_file_add_file(struct sparse_file* s, const char* filename, int64_t file_offset,
68 const char *filename, int64_t file_offset, unsigned int len, 63 unsigned int len, unsigned int block) {
69 unsigned int block) 64 return backed_block_add_file(s->backed_block_list, filename, file_offset, len, block);
70{
71 return backed_block_add_file(s->backed_block_list, filename, file_offset,
72 len, block);
73} 65}
74 66
75int sparse_file_add_fd(struct sparse_file *s, 67int sparse_file_add_fd(struct sparse_file* s, int fd, int64_t file_offset, unsigned int len,
76 int fd, int64_t file_offset, unsigned int len, unsigned int block) 68 unsigned int block) {
77{ 69 return backed_block_add_fd(s->backed_block_list, fd, file_offset, len, block);
78 return backed_block_add_fd(s->backed_block_list, fd, file_offset,
79 len, block);
80} 70}
81unsigned int sparse_count_chunks(struct sparse_file *s) 71unsigned int sparse_count_chunks(struct sparse_file* s) {
82{ 72 struct backed_block* bb;
83 struct backed_block *bb; 73 unsigned int last_block = 0;
84 unsigned int last_block = 0; 74 unsigned int chunks = 0;
85 unsigned int chunks = 0; 75
86 76 for (bb = backed_block_iter_new(s->backed_block_list); bb; bb = backed_block_iter_next(bb)) {
87 for (bb = backed_block_iter_new(s->backed_block_list); bb; 77 if (backed_block_block(bb) > last_block) {
88 bb = backed_block_iter_next(bb)) { 78 /* If there is a gap between chunks, add a skip chunk */
89 if (backed_block_block(bb) > last_block) { 79 chunks++;
90 /* If there is a gap between chunks, add a skip chunk */ 80 }
91 chunks++; 81 chunks++;
92 } 82 last_block = backed_block_block(bb) + DIV_ROUND_UP(backed_block_len(bb), s->block_size);
93 chunks++; 83 }
94 last_block = backed_block_block(bb) + 84 if (last_block < DIV_ROUND_UP(s->len, s->block_size)) {
95 DIV_ROUND_UP(backed_block_len(bb), s->block_size); 85 chunks++;
96 } 86 }
97 if (last_block < DIV_ROUND_UP(s->len, s->block_size)) { 87
98 chunks++; 88 return chunks;
99 }
100
101 return chunks;
102} 89}
103 90
104static int sparse_file_write_block(struct output_file *out, 91static int sparse_file_write_block(struct output_file* out, struct backed_block* bb) {
105 struct backed_block *bb) 92 int ret = -EINVAL;
106{ 93
107 int ret = -EINVAL; 94 switch (backed_block_type(bb)) {
108 95 case BACKED_BLOCK_DATA:
109 switch (backed_block_type(bb)) { 96 ret = write_data_chunk(out, backed_block_len(bb), backed_block_data(bb));
110 case BACKED_BLOCK_DATA: 97 break;
111 ret = write_data_chunk(out, backed_block_len(bb), backed_block_data(bb)); 98 case BACKED_BLOCK_FILE:
112 break; 99 ret = write_file_chunk(out, backed_block_len(bb), backed_block_filename(bb),
113 case BACKED_BLOCK_FILE: 100 backed_block_file_offset(bb));
114 ret = write_file_chunk(out, backed_block_len(bb), 101 break;
115 backed_block_filename(bb), 102 case BACKED_BLOCK_FD:
116 backed_block_file_offset(bb)); 103 ret = write_fd_chunk(out, backed_block_len(bb), backed_block_fd(bb),
117 break; 104 backed_block_file_offset(bb));
118 case BACKED_BLOCK_FD: 105 break;
119 ret = write_fd_chunk(out, backed_block_len(bb), 106 case BACKED_BLOCK_FILL:
120 backed_block_fd(bb), 107 ret = write_fill_chunk(out, backed_block_len(bb), backed_block_fill_val(bb));
121 backed_block_file_offset(bb)); 108 break;
122 break; 109 }
123 case BACKED_BLOCK_FILL: 110
124 ret = write_fill_chunk(out, backed_block_len(bb), 111 return ret;
125 backed_block_fill_val(bb));
126 break;
127 }
128
129 return ret;
130} 112}
131 113
132static int write_all_blocks(struct sparse_file *s, struct output_file *out) 114static int write_all_blocks(struct sparse_file* s, struct output_file* out) {
133{ 115 struct backed_block* bb;
134 struct backed_block *bb; 116 unsigned int last_block = 0;
135 unsigned int last_block = 0; 117 int64_t pad;
136 int64_t pad; 118 int ret = 0;
137 int ret = 0; 119
138 120 for (bb = backed_block_iter_new(s->backed_block_list); bb; bb = backed_block_iter_next(bb)) {
139 for (bb = backed_block_iter_new(s->backed_block_list); bb; 121 if (backed_block_block(bb) > last_block) {
140 bb = backed_block_iter_next(bb)) { 122 unsigned int blocks = backed_block_block(bb) - last_block;
141 if (backed_block_block(bb) > last_block) { 123 write_skip_chunk(out, (int64_t)blocks * s->block_size);
142 unsigned int blocks = backed_block_block(bb) - last_block; 124 }
143 write_skip_chunk(out, (int64_t)blocks * s->block_size); 125 ret = sparse_file_write_block(out, bb);
144 } 126 if (ret) return ret;
145 ret = sparse_file_write_block(out, bb); 127 last_block = backed_block_block(bb) + DIV_ROUND_UP(backed_block_len(bb), s->block_size);
146 if (ret) 128 }
147 return ret; 129
148 last_block = backed_block_block(bb) + 130 pad = s->len - (int64_t)last_block * s->block_size;
149 DIV_ROUND_UP(backed_block_len(bb), s->block_size); 131 assert(pad >= 0);
150 } 132 if (pad > 0) {
151 133 write_skip_chunk(out, pad);
152 pad = s->len - (int64_t)last_block * s->block_size; 134 }
153 assert(pad >= 0); 135
154 if (pad > 0) { 136 return 0;
155 write_skip_chunk(out, pad);
156 }
157
158 return 0;
159} 137}
160 138
161int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse, 139int sparse_file_write(struct sparse_file* s, int fd, bool gz, bool sparse, bool crc) {
162 bool crc) 140 int ret;
163{ 141 int chunks;
164 int ret; 142 struct output_file* out;
165 int chunks;
166 struct output_file *out;
167 143
168 chunks = sparse_count_chunks(s); 144 chunks = sparse_count_chunks(s);
169 out = output_file_open_fd(fd, s->block_size, s->len, gz, sparse, chunks, crc); 145 out = output_file_open_fd(fd, s->block_size, s->len, gz, sparse, chunks, crc);
170 146
171 if (!out) 147 if (!out) return -ENOMEM;
172 return -ENOMEM;
173 148
174 ret = write_all_blocks(s, out); 149 ret = write_all_blocks(s, out);
175 150
176 output_file_close(out); 151 output_file_close(out);
177 152
178 return ret; 153 return ret;
179} 154}
180 155
181int sparse_file_callback(struct sparse_file *s, bool sparse, bool crc, 156int sparse_file_callback(struct sparse_file* s, bool sparse, bool crc,
182 int (*write)(void *priv, const void *data, size_t len), void *priv) 157 int (*write)(void* priv, const void* data, size_t len), void* priv) {
183{ 158 int ret;
184 int ret; 159 int chunks;
185 int chunks; 160 struct output_file* out;
186 struct output_file *out;
187 161
188 chunks = sparse_count_chunks(s); 162 chunks = sparse_count_chunks(s);
189 out = output_file_open_callback(write, priv, s->block_size, s->len, false, 163 out = output_file_open_callback(write, priv, s->block_size, s->len, false, sparse, chunks, crc);
190 sparse, chunks, crc);
191 164
192 if (!out) 165 if (!out) return -ENOMEM;
193 return -ENOMEM;
194 166
195 ret = write_all_blocks(s, out); 167 ret = write_all_blocks(s, out);
196 168
197 output_file_close(out); 169 output_file_close(out);
198 170
199 return ret; 171 return ret;
200} 172}
201 173
202struct chunk_data { 174struct chunk_data {
203 void *priv; 175 void* priv;
204 unsigned int block; 176 unsigned int block;
205 unsigned int nr_blocks; 177 unsigned int nr_blocks;
206 int (*write)(void *priv, const void *data, size_t len, 178 int (*write)(void* priv, const void* data, size_t len, unsigned int block, unsigned int nr_blocks);
207 unsigned int block, unsigned int nr_blocks);
208}; 179};
209 180
210static int foreach_chunk_write(void *priv, const void *data, size_t len) 181static int foreach_chunk_write(void* priv, const void* data, size_t len) {
211{ 182 struct chunk_data* chk = reinterpret_cast<chunk_data*>(priv);
212 struct chunk_data *chk = reinterpret_cast<chunk_data*>(priv);
213 183
214 return chk->write(chk->priv, data, len, chk->block, chk->nr_blocks); 184 return chk->write(chk->priv, data, len, chk->block, chk->nr_blocks);
215} 185}
216 186
217int sparse_file_foreach_chunk(struct sparse_file *s, bool sparse, bool crc, 187int sparse_file_foreach_chunk(struct sparse_file* s, bool sparse, bool crc,
218 int (*write)(void *priv, const void *data, size_t len, unsigned int block, 188 int (*write)(void* priv, const void* data, size_t len,
219 unsigned int nr_blocks), 189 unsigned int block, unsigned int nr_blocks),
220 void *priv) 190 void* priv) {
221{ 191 int ret;
222 int ret; 192 int chunks;
223 int chunks; 193 struct chunk_data chk;
224 struct chunk_data chk; 194 struct output_file* out;
225 struct output_file *out; 195 struct backed_block* bb;
226 struct backed_block *bb; 196
227 197 chk.priv = priv;
228 chk.priv = priv; 198 chk.write = write;
229 chk.write = write; 199 chk.block = chk.nr_blocks = 0;
230 chk.block = chk.nr_blocks = 0; 200 chunks = sparse_count_chunks(s);
231 chunks = sparse_count_chunks(s); 201 out = output_file_open_callback(foreach_chunk_write, &chk, s->block_size, s->len, false, sparse,
232 out = output_file_open_callback(foreach_chunk_write, &chk, 202 chunks, crc);
233 s->block_size, s->len, false, sparse, 203
234 chunks, crc); 204 if (!out) return -ENOMEM;
235 205
236 if (!out) 206 for (bb = backed_block_iter_new(s->backed_block_list); bb; bb = backed_block_iter_next(bb)) {
237 return -ENOMEM; 207 chk.block = backed_block_block(bb);
238 208 chk.nr_blocks = (backed_block_len(bb) - 1) / s->block_size + 1;
239 for (bb = backed_block_iter_new(s->backed_block_list); bb; 209 ret = sparse_file_write_block(out, bb);
240 bb = backed_block_iter_next(bb)) { 210 if (ret) return ret;
241 chk.block = backed_block_block(bb); 211 }
242 chk.nr_blocks = (backed_block_len(bb) - 1) / s->block_size + 1; 212
243 ret = sparse_file_write_block(out, bb); 213 output_file_close(out);
244 if (ret) 214
245 return ret; 215 return ret;
246 }
247
248 output_file_close(out);
249
250 return ret;
251} 216}
252 217
253static int out_counter_write(void *priv, const void *data __unused, size_t len) 218static int out_counter_write(void* priv, const void* data __unused, size_t len) {
254{ 219 int64_t* count = reinterpret_cast<int64_t*>(priv);
255 int64_t *count = reinterpret_cast<int64_t*>(priv); 220 *count += len;
256 *count += len; 221 return 0;
257 return 0;
258} 222}
259 223
260int64_t sparse_file_len(struct sparse_file *s, bool sparse, bool crc) 224int64_t sparse_file_len(struct sparse_file* s, bool sparse, bool crc) {
261{ 225 int ret;
262 int ret; 226 int chunks = sparse_count_chunks(s);
263 int chunks = sparse_count_chunks(s); 227 int64_t count = 0;
264 int64_t count = 0; 228 struct output_file* out;
265 struct output_file *out;
266 229
267 out = output_file_open_callback(out_counter_write, &count, 230 out = output_file_open_callback(out_counter_write, &count, s->block_size, s->len, false, sparse,
268 s->block_size, s->len, false, sparse, chunks, crc); 231 chunks, crc);
269 if (!out) { 232 if (!out) {
270 return -1; 233 return -1;
271 } 234 }
272 235
273 ret = write_all_blocks(s, out); 236 ret = write_all_blocks(s, out);
274 237
275 output_file_close(out); 238 output_file_close(out);
276 239
277 if (ret < 0) { 240 if (ret < 0) {
278 return -1; 241 return -1;
279 } 242 }
280 243
281 return count; 244 return count;
282} 245}
283 246
284unsigned int sparse_file_block_size(struct sparse_file *s) 247unsigned int sparse_file_block_size(struct sparse_file* s) {
285{ 248 return s->block_size;
286 return s->block_size;
287} 249}
288 250
289static struct backed_block *move_chunks_up_to_len(struct sparse_file *from, 251static struct backed_block* move_chunks_up_to_len(struct sparse_file* from, struct sparse_file* to,
290 struct sparse_file *to, unsigned int len) 252 unsigned int len) {
291{ 253 int64_t count = 0;
292 int64_t count = 0; 254 struct output_file* out_counter;
293 struct output_file *out_counter; 255 struct backed_block* last_bb = NULL;
294 struct backed_block *last_bb = NULL; 256 struct backed_block* bb;
295 struct backed_block *bb; 257 struct backed_block* start;
296 struct backed_block *start; 258 unsigned int last_block = 0;
297 unsigned int last_block = 0; 259 int64_t file_len = 0;
298 int64_t file_len = 0; 260 int ret;
299 int ret; 261
300 262 /*
301 /* 263 * overhead is sparse file header, the potential end skip
302 * overhead is sparse file header, the potential end skip 264 * chunk and crc chunk.
303 * chunk and crc chunk. 265 */
304 */ 266 int overhead = sizeof(sparse_header_t) + 2 * sizeof(chunk_header_t) + sizeof(uint32_t);
305 int overhead = sizeof(sparse_header_t) + 2 * sizeof(chunk_header_t) + 267 len -= overhead;
306 sizeof(uint32_t); 268
307 len -= overhead; 269 start = backed_block_iter_new(from->backed_block_list);
308 270 out_counter = output_file_open_callback(out_counter_write, &count, to->block_size, to->len, false,
309 start = backed_block_iter_new(from->backed_block_list); 271 true, 0, false);
310 out_counter = output_file_open_callback(out_counter_write, &count, 272 if (!out_counter) {
311 to->block_size, to->len, false, true, 0, false); 273 return NULL;
312 if (!out_counter) { 274 }
313 return NULL; 275
314 } 276 for (bb = start; bb; bb = backed_block_iter_next(bb)) {
315 277 count = 0;
316 for (bb = start; bb; bb = backed_block_iter_next(bb)) { 278 if (backed_block_block(bb) > last_block) count += sizeof(chunk_header_t);
317 count = 0; 279 last_block = backed_block_block(bb) + DIV_ROUND_UP(backed_block_len(bb), to->block_size);
318 if (backed_block_block(bb) > last_block) 280
319 count += sizeof(chunk_header_t); 281 /* will call out_counter_write to update count */
320 last_block = backed_block_block(bb) + 282 ret = sparse_file_write_block(out_counter, bb);
321 DIV_ROUND_UP(backed_block_len(bb), to->block_size); 283 if (ret) {
322 284 bb = NULL;
323 /* will call out_counter_write to update count */ 285 goto out;
324 ret = sparse_file_write_block(out_counter, bb); 286 }
325 if (ret) { 287 if (file_len + count > len) {
326 bb = NULL; 288 /*
327 goto out; 289 * If the remaining available size is more than 1/8th of the
328 } 290 * requested size, split the chunk. Results in sparse files that
329 if (file_len + count > len) { 291 * are at least 7/8ths of the requested size
330 /* 292 */
331 * If the remaining available size is more than 1/8th of the 293 file_len += sizeof(chunk_header_t);
332 * requested size, split the chunk. Results in sparse files that 294 if (!last_bb || (len - file_len > (len / 8))) {
333 * are at least 7/8ths of the requested size 295 backed_block_split(from->backed_block_list, bb, len - file_len);
334 */ 296 last_bb = bb;
335 file_len += sizeof(chunk_header_t); 297 }
336 if (!last_bb || (len - file_len > (len / 8))) { 298 goto move;
337 backed_block_split(from->backed_block_list, bb, len - file_len); 299 }
338 last_bb = bb; 300 file_len += count;
339 } 301 last_bb = bb;
340 goto move; 302 }
341 }
342 file_len += count;
343 last_bb = bb;
344 }
345 303
346move: 304move:
347 backed_block_list_move(from->backed_block_list, 305 backed_block_list_move(from->backed_block_list, to->backed_block_list, start, last_bb);
348 to->backed_block_list, start, last_bb);
349 306
350out: 307out:
351 output_file_close(out_counter); 308 output_file_close(out_counter);
352 309
353 return bb; 310 return bb;
354} 311}
355 312
356int sparse_file_resparse(struct sparse_file *in_s, unsigned int max_len, 313int sparse_file_resparse(struct sparse_file* in_s, unsigned int max_len, struct sparse_file** out_s,
357 struct sparse_file **out_s, int out_s_count) 314 int out_s_count) {
358{ 315 struct backed_block* bb;
359 struct backed_block *bb; 316 struct sparse_file* s;
360 struct sparse_file *s; 317 struct sparse_file* tmp;
361 struct sparse_file *tmp; 318 int c = 0;
362 int c = 0;
363 319
364 tmp = sparse_file_new(in_s->block_size, in_s->len); 320 tmp = sparse_file_new(in_s->block_size, in_s->len);
365 if (!tmp) { 321 if (!tmp) {
366 return -ENOMEM; 322 return -ENOMEM;
367 } 323 }
368 324
369 do { 325 do {
370 s = sparse_file_new(in_s->block_size, in_s->len); 326 s = sparse_file_new(in_s->block_size, in_s->len);
371 327
372 bb = move_chunks_up_to_len(in_s, s, max_len); 328 bb = move_chunks_up_to_len(in_s, s, max_len);
373 329
374 if (c < out_s_count) { 330 if (c < out_s_count) {
375 out_s[c] = s; 331 out_s[c] = s;
376 } else { 332 } else {
377 backed_block_list_move(s->backed_block_list, tmp->backed_block_list, 333 backed_block_list_move(s->backed_block_list, tmp->backed_block_list, NULL, NULL);
378 NULL, NULL); 334 sparse_file_destroy(s);
379 sparse_file_destroy(s); 335 }
380 } 336 c++;
381 c++; 337 } while (bb);
382 } while (bb);
383 338
384 backed_block_list_move(tmp->backed_block_list, in_s->backed_block_list, 339 backed_block_list_move(tmp->backed_block_list, in_s->backed_block_list, NULL, NULL);
385 NULL, NULL);
386 340
387 sparse_file_destroy(tmp); 341 sparse_file_destroy(tmp);
388 342
389 return c; 343 return c;
390} 344}
391 345
392void sparse_file_verbose(struct sparse_file *s) 346void sparse_file_verbose(struct sparse_file* s) {
393{ 347 s->verbose = true;
394 s->verbose = true;
395} 348}
diff --git a/libsparse/sparse_crc32.cpp b/libsparse/sparse_crc32.cpp
index 97c5a1001..267322c06 100644
--- a/libsparse/sparse_crc32.cpp
+++ b/libsparse/sparse_crc32.cpp
@@ -47,50 +47,38 @@
47#include <stdio.h> 47#include <stdio.h>
48 48
49static uint32_t crc32_tab[] = { 49static uint32_t crc32_tab[] = {
50 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 50 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
51 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 51 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
52 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 52 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
53 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 53 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
54 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 54 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
55 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 55 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
56 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 56 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
57 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 57 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
58 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 58 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
59 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 59 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
60 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 60 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
61 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 61 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
62 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 62 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
63 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 63 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
64 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 64 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
65 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 65 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
66 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 66 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
67 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 67 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
68 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 68 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
69 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 69 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
70 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 70 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
71 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 71 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
72 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 72 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
73 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 73 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
74 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 74 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
75 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 75 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
76 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 76 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
77 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 77 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
78 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 78 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
79 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 79 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
80 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 80 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
81 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 81 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
82 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
83 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
84 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
85 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
86 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
87 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
88 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
89 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
90 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
91 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
92 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
93};
94 82
95/* 83/*
96 * A function that calculates the CRC-32 based on the table above is 84 * A function that calculates the CRC-32 based on the table above is
@@ -99,14 +87,11 @@ static uint32_t crc32_tab[] = {
99 * in sys/libkern.h, where it can be inlined. 87 * in sys/libkern.h, where it can be inlined.
100 */ 88 */
101 89
102uint32_t sparse_crc32(uint32_t crc_in, const void *buf, size_t size) 90uint32_t sparse_crc32(uint32_t crc_in, const void* buf, size_t size) {
103{ 91 const uint8_t* p = reinterpret_cast<const uint8_t*>(buf);
104 const uint8_t *p = reinterpret_cast<const uint8_t*>(buf); 92 uint32_t crc;
105 uint32_t crc;
106 93
107 crc = crc_in ^ ~0U; 94 crc = crc_in ^ ~0U;
108 while (size--) 95 while (size--) crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
109 crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); 96 return crc ^ ~0U;
110 return crc ^ ~0U;
111} 97}
112
diff --git a/libsparse/sparse_crc32.h b/libsparse/sparse_crc32.h
index e42c1eb98..2702c4faa 100644
--- a/libsparse/sparse_crc32.h
+++ b/libsparse/sparse_crc32.h
@@ -19,6 +19,6 @@
19 19
20#include <stdint.h> 20#include <stdint.h>
21 21
22uint32_t sparse_crc32(uint32_t crc, const void *buf, size_t size); 22uint32_t sparse_crc32(uint32_t crc, const void* buf, size_t size);
23 23
24#endif 24#endif
diff --git a/libsparse/sparse_defs.h b/libsparse/sparse_defs.h
index b99cfd584..9137805f7 100644
--- a/libsparse/sparse_defs.h
+++ b/libsparse/sparse_defs.h
@@ -39,11 +39,14 @@ typedef unsigned int u32;
39typedef unsigned short int u16; 39typedef unsigned short int u16;
40typedef unsigned char u8; 40typedef unsigned char u8;
41 41
42#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y)) 42#define DIV_ROUND_UP(x, y) (((x) + (y)-1) / (y))
43#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y))) 43#define ALIGN(x, y) ((y)*DIV_ROUND_UP((x), (y)))
44#define ALIGN_DOWN(x, y) ((y) * ((x) / (y))) 44#define ALIGN_DOWN(x, y) ((y) * ((x) / (y)))
45 45
46#define error(fmt, args...) do { fprintf(stderr, "error: %s: " fmt "\n", __func__, ## args); } while (0) 46#define error(fmt, args...) \
47 do { \
48 fprintf(stderr, "error: %s: " fmt "\n", __func__, ##args); \
49 } while (0)
47#define error_errno(s, args...) error(s ": %s", ##args, strerror(errno)) 50#define error_errno(s, args...) error(s ": %s", ##args, strerror(errno))
48 51
49#endif 52#endif
diff --git a/libsparse/sparse_err.cpp b/libsparse/sparse_err.cpp
index 0f392ad60..6886d31d7 100644
--- a/libsparse/sparse_err.cpp
+++ b/libsparse/sparse_err.cpp
@@ -20,14 +20,13 @@
20#include <stdio.h> 20#include <stdio.h>
21#include <unistd.h> 21#include <unistd.h>
22 22
23void sparse_default_print(const char *fmt, ...) 23void sparse_default_print(const char* fmt, ...) {
24{ 24 va_list argp;
25 va_list argp;
26 25
27 va_start(argp, fmt); 26 va_start(argp, fmt);
28 vfprintf(stderr, fmt, argp); 27 vfprintf(stderr, fmt, argp);
29 va_end(argp); 28 va_end(argp);
30} 29}
31 30
32void (*sparse_print_error)(const char *fmt, ...) = sparse_default_print; 31void (*sparse_print_error)(const char* fmt, ...) = sparse_default_print;
33void (*sparse_print_verbose)(const char *fmt, ...) = sparse_default_print; 32void (*sparse_print_verbose)(const char* fmt, ...) = sparse_default_print;
diff --git a/libsparse/sparse_file.h b/libsparse/sparse_file.h
index 763f43f67..e565f63c2 100644
--- a/libsparse/sparse_file.h
+++ b/libsparse/sparse_file.h
@@ -24,12 +24,12 @@ extern "C" {
24#include <sparse/sparse.h> 24#include <sparse/sparse.h>
25 25
26struct sparse_file { 26struct sparse_file {
27 unsigned int block_size; 27 unsigned int block_size;
28 int64_t len; 28 int64_t len;
29 bool verbose; 29 bool verbose;
30 30
31 struct backed_block_list *backed_block_list; 31 struct backed_block_list* backed_block_list;
32 struct output_file *out; 32 struct output_file* out;
33}; 33};
34 34
35#ifdef __cplusplus 35#ifdef __cplusplus
diff --git a/libsparse/sparse_format.h b/libsparse/sparse_format.h
index 779e0385d..a8a721e6e 100644
--- a/libsparse/sparse_format.h
+++ b/libsparse/sparse_format.h
@@ -23,31 +23,31 @@ extern "C" {
23#endif 23#endif
24 24
25typedef struct sparse_header { 25typedef struct sparse_header {
26 __le32 magic; /* 0xed26ff3a */ 26 __le32 magic; /* 0xed26ff3a */
27 __le16 major_version; /* (0x1) - reject images with higher major versions */ 27 __le16 major_version; /* (0x1) - reject images with higher major versions */
28 __le16 minor_version; /* (0x0) - allow images with higer minor versions */ 28 __le16 minor_version; /* (0x0) - allow images with higer minor versions */
29 __le16 file_hdr_sz; /* 28 bytes for first revision of the file format */ 29 __le16 file_hdr_sz; /* 28 bytes for first revision of the file format */
30 __le16 chunk_hdr_sz; /* 12 bytes for first revision of the file format */ 30 __le16 chunk_hdr_sz; /* 12 bytes for first revision of the file format */
31 __le32 blk_sz; /* block size in bytes, must be a multiple of 4 (4096) */ 31 __le32 blk_sz; /* block size in bytes, must be a multiple of 4 (4096) */
32 __le32 total_blks; /* total blocks in the non-sparse output image */ 32 __le32 total_blks; /* total blocks in the non-sparse output image */
33 __le32 total_chunks; /* total chunks in the sparse input image */ 33 __le32 total_chunks; /* total chunks in the sparse input image */
34 __le32 image_checksum; /* CRC32 checksum of the original data, counting "don't care" */ 34 __le32 image_checksum; /* CRC32 checksum of the original data, counting "don't care" */
35 /* as 0. Standard 802.3 polynomial, use a Public Domain */ 35 /* as 0. Standard 802.3 polynomial, use a Public Domain */
36 /* table implementation */ 36 /* table implementation */
37} sparse_header_t; 37} sparse_header_t;
38 38
39#define SPARSE_HEADER_MAGIC 0xed26ff3a 39#define SPARSE_HEADER_MAGIC 0xed26ff3a
40 40
41#define CHUNK_TYPE_RAW 0xCAC1 41#define CHUNK_TYPE_RAW 0xCAC1
42#define CHUNK_TYPE_FILL 0xCAC2 42#define CHUNK_TYPE_FILL 0xCAC2
43#define CHUNK_TYPE_DONT_CARE 0xCAC3 43#define CHUNK_TYPE_DONT_CARE 0xCAC3
44#define CHUNK_TYPE_CRC32 0xCAC4 44#define CHUNK_TYPE_CRC32 0xCAC4
45 45
46typedef struct chunk_header { 46typedef struct chunk_header {
47 __le16 chunk_type; /* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */ 47 __le16 chunk_type; /* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
48 __le16 reserved1; 48 __le16 reserved1;
49 __le32 chunk_sz; /* in blocks in output image */ 49 __le32 chunk_sz; /* in blocks in output image */
50 __le32 total_sz; /* in bytes of chunk input file including chunk header and data */ 50 __le32 total_sz; /* in bytes of chunk input file including chunk header and data */
51} chunk_header_t; 51} chunk_header_t;
52 52
53/* Following a Raw or Fill or CRC32 chunk is data. 53/* Following a Raw or Fill or CRC32 chunk is data.
diff --git a/libsparse/sparse_read.cpp b/libsparse/sparse_read.cpp
index d6a68b3c7..56e2c9a0b 100644
--- a/libsparse/sparse_read.cpp
+++ b/libsparse/sparse_read.cpp
@@ -17,16 +17,16 @@
17#define _FILE_OFFSET_BITS 64 17#define _FILE_OFFSET_BITS 64
18#define _LARGEFILE64_SOURCE 1 18#define _LARGEFILE64_SOURCE 1
19 19
20#include <algorithm>
21#include <inttypes.h>
22#include <fcntl.h> 20#include <fcntl.h>
21#include <inttypes.h>
23#include <stdarg.h> 22#include <stdarg.h>
24#include <stdint.h> 23#include <stdint.h>
25#include <stdio.h> 24#include <stdio.h>
26#include <stdlib.h> 25#include <stdlib.h>
27#include <string.h> 26#include <string.h>
28#include <string>
29#include <unistd.h> 27#include <unistd.h>
28#include <algorithm>
29#include <string>
30 30
31#include <sparse/sparse.h> 31#include <sparse/sparse.h>
32 32
@@ -37,563 +37,541 @@
37#include "sparse_file.h" 37#include "sparse_file.h"
38#include "sparse_format.h" 38#include "sparse_format.h"
39 39
40
41#if defined(__APPLE__) && defined(__MACH__) 40#if defined(__APPLE__) && defined(__MACH__)
42#define lseek64 lseek 41#define lseek64 lseek
43#define off64_t off_t 42#define off64_t off_t
44#endif 43#endif
45 44
46#define SPARSE_HEADER_MAJOR_VER 1 45#define SPARSE_HEADER_MAJOR_VER 1
47#define SPARSE_HEADER_LEN (sizeof(sparse_header_t)) 46#define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
48#define CHUNK_HEADER_LEN (sizeof(chunk_header_t)) 47#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
49 48
50static constexpr int64_t COPY_BUF_SIZE = 1024 * 1024; 49static constexpr int64_t COPY_BUF_SIZE = 1024 * 1024;
51static char *copybuf; 50static char* copybuf;
52 51
53static std::string ErrorString(int err) 52static std::string ErrorString(int err) {
54{ 53 if (err == -EOVERFLOW) return "EOF while reading file";
55 if (err == -EOVERFLOW) return "EOF while reading file"; 54 if (err == -EINVAL) return "Invalid sparse file format";
56 if (err == -EINVAL) return "Invalid sparse file format"; 55 if (err == -ENOMEM) return "Failed allocation while reading file";
57 if (err == -ENOMEM) return "Failed allocation while reading file"; 56 return android::base::StringPrintf("Unknown error %d", err);
58 return android::base::StringPrintf("Unknown error %d", err);
59} 57}
60 58
61class SparseFileSource { 59class SparseFileSource {
62public: 60 public:
63 /* Seeks the source ahead by the given offset. */ 61 /* Seeks the source ahead by the given offset. */
64 virtual void Seek(int64_t offset) = 0; 62 virtual void Seek(int64_t offset) = 0;
65 63
66 /* Return the current offset. */ 64 /* Return the current offset. */
67 virtual int64_t GetOffset() = 0; 65 virtual int64_t GetOffset() = 0;
68 66
69 /* Set the current offset. Return 0 if successful. */ 67 /* Set the current offset. Return 0 if successful. */
70 virtual int SetOffset(int64_t offset) = 0; 68 virtual int SetOffset(int64_t offset) = 0;
71 69
72 /* Adds the given length from the current offset of the source to the file at the given 70 /* Adds the given length from the current offset of the source to the file at the given block.
73 * block. Return 0 if successful. */ 71 * Return 0 if successful. */
74 virtual int AddToSparseFile(struct sparse_file *s, int64_t len, unsigned int block) = 0; 72 virtual int AddToSparseFile(struct sparse_file* s, int64_t len, unsigned int block) = 0;
75 73
76 /* Get data of fixed size from the current offset and seek len bytes. 74 /* Get data of fixed size from the current offset and seek len bytes. Return 0 if successful. */
77 * Return 0 if successful. */ 75 virtual int ReadValue(void* ptr, int len) = 0;
78 virtual int ReadValue(void *ptr, int len) = 0;
79 76
80 /* Find the crc32 of the next len bytes and seek ahead len bytes. Return 0 if successful. */ 77 /* Find the crc32 of the next len bytes and seek ahead len bytes. Return 0 if successful. */
81 virtual int GetCrc32(uint32_t *crc32, int64_t len) = 0; 78 virtual int GetCrc32(uint32_t* crc32, int64_t len) = 0;
82 79
83 virtual ~SparseFileSource() {}; 80 virtual ~SparseFileSource(){};
84}; 81};
85 82
86class SparseFileFdSource : public SparseFileSource { 83class SparseFileFdSource : public SparseFileSource {
87private: 84 private:
88 int fd; 85 int fd;
89public: 86
90 SparseFileFdSource(int fd) : fd(fd) {} 87 public:
91 ~SparseFileFdSource() override {} 88 SparseFileFdSource(int fd) : fd(fd) {}
92 89 ~SparseFileFdSource() override {}
93 void Seek(int64_t off) override { 90
94 lseek64(fd, off, SEEK_CUR); 91 void Seek(int64_t off) override { lseek64(fd, off, SEEK_CUR); }
95 } 92
96 93 int64_t GetOffset() override { return lseek64(fd, 0, SEEK_CUR); }
97 int64_t GetOffset() override { 94
98 return lseek64(fd, 0, SEEK_CUR); 95 int SetOffset(int64_t offset) override {
99 } 96 return lseek64(fd, offset, SEEK_SET) == offset ? 0 : -errno;
100 97 }
101 int SetOffset(int64_t offset) override { 98
102 return lseek64(fd, offset, SEEK_SET) == offset ? 0 : -errno; 99 int AddToSparseFile(struct sparse_file* s, int64_t len, unsigned int block) override {
103 } 100 return sparse_file_add_fd(s, fd, GetOffset(), len, block);
104 101 }
105 int AddToSparseFile(struct sparse_file *s, int64_t len, unsigned int block) override { 102
106 return sparse_file_add_fd(s, fd, GetOffset(), len, block); 103 int ReadValue(void* ptr, int len) override { return read_all(fd, ptr, len); }
107 } 104
108 105 int GetCrc32(uint32_t* crc32, int64_t len) override {
109 int ReadValue(void *ptr, int len) override { 106 int chunk;
110 return read_all(fd, ptr, len); 107 int ret;
111 } 108 while (len) {
112 109 chunk = std::min(len, COPY_BUF_SIZE);
113 int GetCrc32(uint32_t *crc32, int64_t len) override { 110 ret = read_all(fd, copybuf, chunk);
114 int chunk; 111 if (ret < 0) {
115 int ret; 112 return ret;
116 while (len) { 113 }
117 chunk = std::min(len, COPY_BUF_SIZE); 114 *crc32 = sparse_crc32(*crc32, copybuf, chunk);
118 ret = read_all(fd, copybuf, chunk); 115 len -= chunk;
119 if (ret < 0) { 116 }
120 return ret; 117 return 0;
121 } 118 }
122 *crc32 = sparse_crc32(*crc32, copybuf, chunk);
123 len -= chunk;
124 }
125 return 0;
126 }
127}; 119};
128 120
129class SparseFileBufSource : public SparseFileSource { 121class SparseFileBufSource : public SparseFileSource {
130private: 122 private:
131 char *buf; 123 char* buf;
132 int64_t offset; 124 int64_t offset;
133public: 125
134 SparseFileBufSource(char *buf) : buf(buf), offset(0) {} 126 public:
135 ~SparseFileBufSource() override {} 127 SparseFileBufSource(char* buf) : buf(buf), offset(0) {}
136 128 ~SparseFileBufSource() override {}
137 void Seek(int64_t off) override { 129
138 buf += off; 130 void Seek(int64_t off) override {
139 offset += off; 131 buf += off;
140 } 132 offset += off;
141 133 }
142 int64_t GetOffset() override { 134
143 return offset; 135 int64_t GetOffset() override { return offset; }
144 } 136
145 137 int SetOffset(int64_t off) override {
146 int SetOffset(int64_t off) override { 138 buf += off - offset;
147 buf += off - offset; 139 offset = off;
148 offset = off; 140 return 0;
149 return 0; 141 }
150 } 142
151 143 int AddToSparseFile(struct sparse_file* s, int64_t len, unsigned int block) override {
152 int AddToSparseFile(struct sparse_file *s, int64_t len, unsigned int block) override { 144 return sparse_file_add_data(s, buf, len, block);
153 return sparse_file_add_data(s, buf, len, block); 145 }
154 } 146
155 147 int ReadValue(void* ptr, int len) override {
156 int ReadValue(void *ptr, int len) override { 148 memcpy(ptr, buf, len);
157 memcpy(ptr, buf, len); 149 Seek(len);
158 Seek(len); 150 return 0;
159 return 0; 151 }
160 } 152
161 153 int GetCrc32(uint32_t* crc32, int64_t len) override {
162 int GetCrc32(uint32_t *crc32, int64_t len) override { 154 *crc32 = sparse_crc32(*crc32, buf, len);
163 *crc32 = sparse_crc32(*crc32, buf, len); 155 Seek(len);
164 Seek(len); 156 return 0;
165 return 0; 157 }
166 }
167}; 158};
168 159
169static void verbose_error(bool verbose, int err, const char *fmt, ...) 160static void verbose_error(bool verbose, int err, const char* fmt, ...) {
170{ 161 if (!verbose) return;
171 if (!verbose) return; 162
172 163 std::string msg = ErrorString(err);
173 std::string msg = ErrorString(err); 164 if (fmt) {
174 if (fmt) { 165 msg += " at ";
175 msg += " at "; 166 va_list argp;
176 va_list argp; 167 va_start(argp, fmt);
177 va_start(argp, fmt); 168 android::base::StringAppendV(&msg, fmt, argp);
178 android::base::StringAppendV(&msg, fmt, argp); 169 va_end(argp);
179 va_end(argp); 170 }
180 } 171 sparse_print_verbose("%s\n", msg.c_str());
181 sparse_print_verbose("%s\n", msg.c_str());
182} 172}
183 173
184static int process_raw_chunk(struct sparse_file *s, unsigned int chunk_size, 174static int process_raw_chunk(struct sparse_file* s, unsigned int chunk_size,
185 SparseFileSource *source, unsigned int blocks, unsigned int block, 175 SparseFileSource* source, unsigned int blocks, unsigned int block,
186 uint32_t *crc32) 176 uint32_t* crc32) {
187{ 177 int ret;
188 int ret; 178 int64_t len = blocks * s->block_size;
189 int64_t len = blocks * s->block_size; 179
190 180 if (chunk_size % s->block_size != 0) {
191 if (chunk_size % s->block_size != 0) { 181 return -EINVAL;
192 return -EINVAL; 182 }
193 } 183
194 184 if (chunk_size / s->block_size != blocks) {
195 if (chunk_size / s->block_size != blocks) { 185 return -EINVAL;
196 return -EINVAL; 186 }
197 } 187
198 188 ret = source->AddToSparseFile(s, len, block);
199 ret = source->AddToSparseFile(s, len, block); 189 if (ret < 0) {
200 if (ret < 0) { 190 return ret;
201 return ret; 191 }
202 } 192
203 193 if (crc32) {
204 if (crc32) { 194 ret = source->GetCrc32(crc32, len);
205 ret = source->GetCrc32(crc32, len); 195 if (ret < 0) {
206 if (ret < 0) { 196 return ret;
207 return ret; 197 }
208 } 198 } else {
209 } else { 199 source->Seek(len);
210 source->Seek(len); 200 }
211 } 201
212 202 return 0;
213 return 0;
214} 203}
215 204
216static int process_fill_chunk(struct sparse_file *s, unsigned int chunk_size, 205static int process_fill_chunk(struct sparse_file* s, unsigned int chunk_size,
217 SparseFileSource *source, unsigned int blocks, unsigned int block, uint32_t *crc32) 206 SparseFileSource* source, unsigned int blocks, unsigned int block,
218{ 207 uint32_t* crc32) {
219 int ret; 208 int ret;
220 int chunk; 209 int chunk;
221 int64_t len = (int64_t)blocks * s->block_size; 210 int64_t len = (int64_t)blocks * s->block_size;
222 uint32_t fill_val; 211 uint32_t fill_val;
223 uint32_t *fillbuf; 212 uint32_t* fillbuf;
224 unsigned int i; 213 unsigned int i;
225 214
226 if (chunk_size != sizeof(fill_val)) { 215 if (chunk_size != sizeof(fill_val)) {
227 return -EINVAL; 216 return -EINVAL;
228 } 217 }
229 218
230 ret = source->ReadValue(&fill_val, sizeof(fill_val)); 219 ret = source->ReadValue(&fill_val, sizeof(fill_val));
231 if (ret < 0) { 220 if (ret < 0) {
232 return ret; 221 return ret;
233 } 222 }
234 223
235 ret = sparse_file_add_fill(s, fill_val, len, block); 224 ret = sparse_file_add_fill(s, fill_val, len, block);
236 if (ret < 0) { 225 if (ret < 0) {
237 return ret; 226 return ret;
238 } 227 }
239 228
240 if (crc32) { 229 if (crc32) {
241 /* Fill copy_buf with the fill value */ 230 /* Fill copy_buf with the fill value */
242 fillbuf = (uint32_t *)copybuf; 231 fillbuf = (uint32_t*)copybuf;
243 for (i = 0; i < (COPY_BUF_SIZE / sizeof(fill_val)); i++) { 232 for (i = 0; i < (COPY_BUF_SIZE / sizeof(fill_val)); i++) {
244 fillbuf[i] = fill_val; 233 fillbuf[i] = fill_val;
245 } 234 }
246 235
247 while (len) { 236 while (len) {
248 chunk = std::min(len, COPY_BUF_SIZE); 237 chunk = std::min(len, COPY_BUF_SIZE);
249 *crc32 = sparse_crc32(*crc32, copybuf, chunk); 238 *crc32 = sparse_crc32(*crc32, copybuf, chunk);
250 len -= chunk; 239 len -= chunk;
251 } 240 }
252 } 241 }
253 242
254 return 0; 243 return 0;
255} 244}
256 245
257static int process_skip_chunk(struct sparse_file *s, unsigned int chunk_size, 246static int process_skip_chunk(struct sparse_file* s, unsigned int chunk_size,
258 SparseFileSource *source __unused, unsigned int blocks, 247 SparseFileSource* source __unused, unsigned int blocks,
259 unsigned int block __unused, uint32_t *crc32) 248 unsigned int block __unused, uint32_t* crc32) {
260{ 249 if (chunk_size != 0) {
261 if (chunk_size != 0) { 250 return -EINVAL;
262 return -EINVAL; 251 }
263 } 252
264 253 if (crc32) {
265 if (crc32) { 254 int64_t len = (int64_t)blocks * s->block_size;
266 int64_t len = (int64_t)blocks * s->block_size; 255 memset(copybuf, 0, COPY_BUF_SIZE);
267 memset(copybuf, 0, COPY_BUF_SIZE); 256
268 257 while (len) {
269 while (len) { 258 int chunk = std::min(len, COPY_BUF_SIZE);
270 int chunk = std::min(len, COPY_BUF_SIZE); 259 *crc32 = sparse_crc32(*crc32, copybuf, chunk);
271 *crc32 = sparse_crc32(*crc32, copybuf, chunk); 260 len -= chunk;
272 len -= chunk; 261 }
273 } 262 }
274 } 263
275 264 return 0;
276 return 0;
277} 265}
278 266
279static int process_crc32_chunk(SparseFileSource *source, unsigned int chunk_size, uint32_t *crc32) 267static int process_crc32_chunk(SparseFileSource* source, unsigned int chunk_size, uint32_t* crc32) {
280{ 268 uint32_t file_crc32;
281 uint32_t file_crc32;
282 269
283 if (chunk_size != sizeof(file_crc32)) { 270 if (chunk_size != sizeof(file_crc32)) {
284 return -EINVAL; 271 return -EINVAL;
285 } 272 }
286 273
287 int ret = source->ReadValue(&file_crc32, sizeof(file_crc32)); 274 int ret = source->ReadValue(&file_crc32, sizeof(file_crc32));
288 if (ret < 0) { 275 if (ret < 0) {
289 return ret; 276 return ret;
290 } 277 }
291 278
292 if (crc32 != NULL && file_crc32 != *crc32) { 279 if (crc32 != NULL && file_crc32 != *crc32) {
293 return -EINVAL; 280 return -EINVAL;
294 } 281 }
295 282
296 return 0; 283 return 0;
297} 284}
298 285
299static int process_chunk(struct sparse_file *s, SparseFileSource *source, 286static int process_chunk(struct sparse_file* s, SparseFileSource* source, unsigned int chunk_hdr_sz,
300 unsigned int chunk_hdr_sz, chunk_header_t *chunk_header, 287 chunk_header_t* chunk_header, unsigned int cur_block, uint32_t* crc_ptr) {
301 unsigned int cur_block, uint32_t *crc_ptr) 288 int ret;
302{ 289 unsigned int chunk_data_size;
303 int ret; 290 int64_t offset = source->GetOffset();
304 unsigned int chunk_data_size; 291
305 int64_t offset = source->GetOffset(); 292 chunk_data_size = chunk_header->total_sz - chunk_hdr_sz;
306 293
307 chunk_data_size = chunk_header->total_sz - chunk_hdr_sz; 294 switch (chunk_header->chunk_type) {
308 295 case CHUNK_TYPE_RAW:
309 switch (chunk_header->chunk_type) { 296 ret =
310 case CHUNK_TYPE_RAW: 297 process_raw_chunk(s, chunk_data_size, source, chunk_header->chunk_sz, cur_block, crc_ptr);
311 ret = process_raw_chunk(s, chunk_data_size, source, 298 if (ret < 0) {
312 chunk_header->chunk_sz, cur_block, crc_ptr); 299 verbose_error(s->verbose, ret, "data block at %" PRId64, offset);
313 if (ret < 0) { 300 return ret;
314 verbose_error(s->verbose, ret, "data block at %" PRId64, offset); 301 }
315 return ret; 302 return chunk_header->chunk_sz;
316 } 303 case CHUNK_TYPE_FILL:
317 return chunk_header->chunk_sz; 304 ret = process_fill_chunk(s, chunk_data_size, source, chunk_header->chunk_sz, cur_block,
318 case CHUNK_TYPE_FILL: 305 crc_ptr);
319 ret = process_fill_chunk(s, chunk_data_size, source, 306 if (ret < 0) {
320 chunk_header->chunk_sz, cur_block, crc_ptr); 307 verbose_error(s->verbose, ret, "fill block at %" PRId64, offset);
321 if (ret < 0) { 308 return ret;
322 verbose_error(s->verbose, ret, "fill block at %" PRId64, offset); 309 }
323 return ret; 310 return chunk_header->chunk_sz;
324 } 311 case CHUNK_TYPE_DONT_CARE:
325 return chunk_header->chunk_sz; 312 ret = process_skip_chunk(s, chunk_data_size, source, chunk_header->chunk_sz, cur_block,
326 case CHUNK_TYPE_DONT_CARE: 313 crc_ptr);
327 ret = process_skip_chunk(s, chunk_data_size, source, 314 if (chunk_data_size != 0) {
328 chunk_header->chunk_sz, cur_block, crc_ptr); 315 if (ret < 0) {
329 if (chunk_data_size != 0) { 316 verbose_error(s->verbose, ret, "skip block at %" PRId64, offset);
330 if (ret < 0) { 317 return ret;
331 verbose_error(s->verbose, ret, "skip block at %" PRId64, offset); 318 }
332 return ret; 319 }
333 } 320 return chunk_header->chunk_sz;
334 } 321 case CHUNK_TYPE_CRC32:
335 return chunk_header->chunk_sz; 322 ret = process_crc32_chunk(source, chunk_data_size, crc_ptr);
336 case CHUNK_TYPE_CRC32: 323 if (ret < 0) {
337 ret = process_crc32_chunk(source, chunk_data_size, crc_ptr); 324 verbose_error(s->verbose, -EINVAL, "crc block at %" PRId64, offset);
338 if (ret < 0) { 325 return ret;
339 verbose_error(s->verbose, -EINVAL, "crc block at %" PRId64, 326 }
340 offset); 327 return 0;
341 return ret; 328 default:
342 } 329 verbose_error(s->verbose, -EINVAL, "unknown block %04X at %" PRId64, chunk_header->chunk_type,
343 return 0; 330 offset);
344 default: 331 }
345 verbose_error(s->verbose, -EINVAL, "unknown block %04X at %" PRId64, 332
346 chunk_header->chunk_type, offset); 333 return 0;
347 }
348
349 return 0;
350} 334}
351 335
352static int sparse_file_read_sparse(struct sparse_file *s, SparseFileSource *source, bool crc) 336static int sparse_file_read_sparse(struct sparse_file* s, SparseFileSource* source, bool crc) {
353{ 337 int ret;
354 int ret; 338 unsigned int i;
355 unsigned int i; 339 sparse_header_t sparse_header;
356 sparse_header_t sparse_header; 340 chunk_header_t chunk_header;
357 chunk_header_t chunk_header; 341 uint32_t crc32 = 0;
358 uint32_t crc32 = 0; 342 uint32_t* crc_ptr = 0;
359 uint32_t *crc_ptr = 0; 343 unsigned int cur_block = 0;
360 unsigned int cur_block = 0; 344
361 345 if (!copybuf) {
362 if (!copybuf) { 346 copybuf = (char*)malloc(COPY_BUF_SIZE);
363 copybuf = (char *)malloc(COPY_BUF_SIZE); 347 }
364 } 348
365 349 if (!copybuf) {
366 if (!copybuf) { 350 return -ENOMEM;
367 return -ENOMEM; 351 }
368 } 352
369 353 if (crc) {
370 if (crc) { 354 crc_ptr = &crc32;
371 crc_ptr = &crc32; 355 }
372 } 356
373 357 ret = source->ReadValue(&sparse_header, sizeof(sparse_header));
374 ret = source->ReadValue(&sparse_header, sizeof(sparse_header)); 358 if (ret < 0) {
375 if (ret < 0) { 359 return ret;
376 return ret; 360 }
377 } 361
378 362 if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
379 if (sparse_header.magic != SPARSE_HEADER_MAGIC) { 363 return -EINVAL;
380 return -EINVAL; 364 }
381 } 365
382 366 if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
383 if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) { 367 return -EINVAL;
384 return -EINVAL; 368 }
385 } 369
386 370 if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
387 if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) { 371 return -EINVAL;
388 return -EINVAL; 372 }
389 } 373
390 374 if (sparse_header.chunk_hdr_sz < sizeof(chunk_header)) {
391 if (sparse_header.chunk_hdr_sz < sizeof(chunk_header)) { 375 return -EINVAL;
392 return -EINVAL; 376 }
393 } 377
394 378 if (sparse_header.file_hdr_sz > SPARSE_HEADER_LEN) {
395 if (sparse_header.file_hdr_sz > SPARSE_HEADER_LEN) { 379 /* Skip the remaining bytes in a header that is longer than
396 /* Skip the remaining bytes in a header that is longer than 380 * we expected.
397 * we expected. 381 */
398 */ 382 source->Seek(sparse_header.file_hdr_sz - SPARSE_HEADER_LEN);
399 source->Seek(sparse_header.file_hdr_sz - SPARSE_HEADER_LEN); 383 }
400 } 384
401 385 for (i = 0; i < sparse_header.total_chunks; i++) {
402 for (i = 0; i < sparse_header.total_chunks; i++) { 386 ret = source->ReadValue(&chunk_header, sizeof(chunk_header));
403 ret = source->ReadValue(&chunk_header, sizeof(chunk_header)); 387 if (ret < 0) {
404 if (ret < 0) { 388 return ret;
405 return ret; 389 }
406 } 390
407