1 #include "config.h"
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <stdint.h>
7 #include "ext2_fs.h"
8 #include "ext2fs.h"
9 
10 #ifndef O_BINARY
11 #define O_BINARY 0
12 #endif
13 
14 #if !defined(ENABLE_LIBSPARSE)
sparse_open(const char * name EXT2FS_ATTR ((unused)),int flags EXT2FS_ATTR ((unused)),io_channel * channel EXT2FS_ATTR ((unused)))15 static errcode_t sparse_open(const char *name EXT2FS_ATTR((unused)),
16 			     int flags EXT2FS_ATTR((unused)),
17 			     io_channel *channel EXT2FS_ATTR((unused)))
18 {
19 	return EXT2_ET_UNIMPLEMENTED;
20 }
sparse_close(io_channel channel EXT2FS_ATTR ((unused)))21 static errcode_t sparse_close(io_channel channel EXT2FS_ATTR((unused)))
22 {
23 	return EXT2_ET_UNIMPLEMENTED;
24 }
25 static struct struct_io_manager struct_sparse_manager = {
26 	.magic			= EXT2_ET_MAGIC_IO_MANAGER,
27 	.name			= "Android sparse I/O Manager",
28 	.open			= sparse_open,
29 	.close			= sparse_close,
30 };
31 static struct struct_io_manager struct_sparsefd_manager = {
32 	.magic			= EXT2_ET_MAGIC_IO_MANAGER,
33 	.name			= "Android sparse fd I/O Manager",
34 	.open			= sparse_open,
35 	.close			= sparse_close,
36 };
37 #else
38 #include <sparse/sparse.h>
39 
40 struct sparse_map {
41 	int			fd;
42 	char			**blocks;
43 	int			block_size;
44 	uint64_t		blocks_count;
45 	char			*file;
46 	struct sparse_file	*sparse_file;
47 	io_channel		channel;
48 };
49 
50 struct sparse_io_params {
51 	int			fd;
52 	char			*file;
53 	uint64_t		blocks_count;
54 	unsigned int		block_size;
55 };
56 
57 static errcode_t sparse_write_blk(io_channel channel, unsigned long block,
58 				  int count, const void *buf);
59 
free_sparse_blocks(struct sparse_map * sm)60 static void free_sparse_blocks(struct sparse_map *sm)
61 {
62 	uint64_t i;
63 
64 	for (i = 0; i < sm->blocks_count; ++i)
65 		free(sm->blocks[i]);
66 	free(sm->blocks);
67 	sm->blocks = NULL;
68 }
69 
sparse_import_segment(void * priv,const void * data,int len,unsigned int block,unsigned int nr_blocks)70 static int sparse_import_segment(void *priv, const void *data, int len,
71 				 unsigned int block, unsigned int nr_blocks)
72 {
73 	struct sparse_map *sm = priv;
74 
75 	/* Ignore chunk headers, only write the data */
76 	if (!nr_blocks || len % sm->block_size)
77 		return 0;
78 
79 	return sparse_write_blk(sm->channel, block, nr_blocks, data);
80 }
81 
io_manager_import_sparse(struct sparse_io_params * params,struct sparse_map * sm,io_channel io)82 static errcode_t io_manager_import_sparse(struct sparse_io_params *params,
83 					  struct sparse_map *sm, io_channel io)
84 {
85 	int fd;
86 	errcode_t retval;
87 	struct sparse_file *sparse_file;
88 
89 	if (params->fd < 0) {
90 		fd = open(params->file, O_RDONLY);
91 		if (fd < 0) {
92 			retval = -1;
93 			goto err_open;
94 		}
95 	} else
96 		fd = params->fd;
97 	sparse_file = sparse_file_import(fd, false, false);
98 	if (!sparse_file) {
99 		retval = -1;
100 		goto err_sparse;
101 	}
102 
103 	sm->block_size = sparse_file_block_size(sparse_file);
104 	sm->blocks_count = (sparse_file_len(sparse_file, 0, 0) - 1)
105 				/ sm->block_size + 1;
106 	sm->blocks = calloc(sm->blocks_count, sizeof(char*));
107 	if (!sm->blocks) {
108 		retval = -1;
109 		goto err_alloc;
110 	}
111 	io->block_size = sm->block_size;
112 
113 	retval = sparse_file_foreach_chunk(sparse_file, true, false,
114 					   sparse_import_segment, sm);
115 
116 	if (retval)
117 		free_sparse_blocks(sm);
118 err_alloc:
119 	sparse_file_destroy(sparse_file);
120 err_sparse:
121 	close(fd);
122 err_open:
123 	return retval;
124 }
125 
io_manager_configure(struct sparse_io_params * params,int flags,io_channel io)126 static errcode_t io_manager_configure(struct sparse_io_params *params,
127 				      int flags, io_channel io)
128 {
129 	errcode_t retval;
130 	uint64_t img_size;
131 	struct sparse_map *sm = calloc(1, sizeof(*sm));
132 	if (!sm)
133 		return EXT2_ET_NO_MEMORY;
134 
135 	sm->file = params->file;
136 	sm->channel = io;
137 	io->private_data = sm;
138 	retval = io_manager_import_sparse(params, sm, io);
139 	if (retval) {
140 		if (!params->block_size || !params->blocks_count) {
141 			retval = -EINVAL;
142 			goto err_params;
143 		}
144 		sm->block_size = params->block_size;
145 		sm->blocks_count = params->blocks_count;
146 		sm->blocks = calloc(params->blocks_count, sizeof(void*));
147 		if (!sm->blocks) {
148 			retval = EXT2_ET_NO_MEMORY;
149 			goto err_alloc;
150 		}
151 	}
152 	io->block_size = sm->block_size;
153 	img_size = (uint64_t)sm->block_size * sm->blocks_count;
154 
155 	if (flags & IO_FLAG_RW) {
156 		sm->sparse_file = sparse_file_new(sm->block_size, img_size);
157 		if (!sm->sparse_file) {
158 			retval = EXT2_ET_NO_MEMORY;
159 			goto err_alloc;
160 		}
161 		if (params->fd < 0) {
162 			sm->fd = open(params->file, O_CREAT | O_RDWR | O_TRUNC | O_BINARY,
163 				      0644);
164 			if (sm->fd < 0) {
165 				retval = errno;
166 				goto err_open;
167 			}
168 		} else
169 			sm->fd = params->fd;
170 	} else {
171 		sm->fd = -1;
172 		sm->sparse_file = NULL;
173 	}
174 	return 0;
175 
176 err_open:
177 	sparse_file_destroy(sm->sparse_file);
178 err_alloc:
179 	free_sparse_blocks(sm);
180 err_params:
181 	free(sm);
182 	return retval;
183 }
184 
sparse_open_channel(struct sparse_io_params * sparse_params,int flags,io_channel * channel)185 static errcode_t sparse_open_channel(struct sparse_io_params *sparse_params,
186 				     int flags, io_channel *channel)
187 {
188 	io_channel io;
189 
190 	io = calloc(1, sizeof(struct struct_io_channel));
191 	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
192 	io->block_size = 0;
193 	io->refcount = 1;
194 	*channel = io;
195 	return io_manager_configure(sparse_params, flags, io);
196 }
197 
read_sparse_argv(const char * name,bool is_fd,struct sparse_io_params * sparse_params)198 static errcode_t read_sparse_argv(const char *name, bool is_fd,
199 				  struct sparse_io_params *sparse_params)
200 {
201 	int ret;
202 	sparse_params->fd = -1;
203 	sparse_params->block_size = 0;
204 	sparse_params->blocks_count = 0;
205 
206 	sparse_params->file = malloc(strlen(name) + 1);
207 	if (!sparse_params->file) {
208 		fprintf(stderr, "failed to alloc %zu\n", strlen(name) + 1);
209 		return EXT2_ET_NO_MEMORY;
210 	}
211 
212 	if (is_fd) {
213 		ret = sscanf(name, "(%d):%llu:%u", &sparse_params->fd,
214 			     (unsigned long long *)&sparse_params->blocks_count,
215 			     &sparse_params->block_size);
216 	} else {
217 		ret = sscanf(name, "(%[^)])%*[:]%llu%*[:]%u", sparse_params->file,
218 			     (unsigned long long *)&sparse_params->blocks_count,
219 			     &sparse_params->block_size);
220 	}
221 
222 	if (ret < 1) {
223 		free(sparse_params->file);
224 		return -EINVAL;
225 	}
226 	return 0;
227 }
228 
sparse_open(const char * name,int flags,io_channel * channel)229 static errcode_t sparse_open(const char *name, int flags, io_channel *channel)
230 {
231 	errcode_t retval;
232 	struct sparse_io_params sparse_params;
233 
234 	retval = read_sparse_argv(name, false, &sparse_params);
235 	if (retval)
236 		return EXT2_ET_BAD_DEVICE_NAME;
237 
238 	retval = sparse_open_channel(&sparse_params, flags, channel);
239 	if (retval)
240 		return retval;
241 	(*channel)->manager = sparse_io_manager;
242 
243 	return retval;
244 }
245 
sparsefd_open(const char * name,int flags,io_channel * channel)246 static errcode_t sparsefd_open(const char *name, int flags, io_channel *channel)
247 {
248 	errcode_t retval;
249 	struct sparse_io_params sparse_params;
250 
251 	retval = read_sparse_argv(name, true, &sparse_params);
252 	if (retval)
253 		return EXT2_ET_BAD_DEVICE_NAME;
254 
255 	retval = sparse_open_channel(&sparse_params, flags, channel);
256 	if (retval)
257 		return retval;
258 	(*channel)->manager = sparsefd_io_manager;
259 
260 	return retval;
261 }
262 
sparse_merge_blocks(struct sparse_map * sm,uint64_t start,uint64_t num)263 static errcode_t sparse_merge_blocks(struct sparse_map *sm, uint64_t start,
264 					uint64_t num)
265 {
266 	char *buf;
267 	uint64_t i;
268 	unsigned int block_size = sm->block_size;
269 	errcode_t retval = 0;
270 
271 	buf = calloc(num, block_size);
272 	if (!buf) {
273 		fprintf(stderr, "failed to alloc %llu\n",
274 			(unsigned long long)num * block_size);
275 		return EXT2_ET_NO_MEMORY;
276 	}
277 
278 	for (i = 0; i < num; i++) {
279 		memcpy(buf + i * block_size, sm->blocks[start + i] , block_size);
280 		free(sm->blocks[start + i]);
281 		sm->blocks[start + i] = NULL;
282 	}
283 
284 	/* free_sparse_blocks will release this buf. */
285 	sm->blocks[start] = buf;
286 
287 	retval = sparse_file_add_data(sm->sparse_file, sm->blocks[start],
288 					block_size * num, start);
289 
290 	return retval;
291 }
292 
sparse_close_channel(io_channel channel)293 static errcode_t sparse_close_channel(io_channel channel)
294 {
295 	uint64_t i;
296 	errcode_t retval = 0;
297 	struct sparse_map *sm = channel->private_data;
298 
299 	if (sm->sparse_file) {
300 		int64_t chunk_start = (sm->blocks[0] == NULL) ? -1 : 0;
301 		for (i = 0; i < sm->blocks_count; ++i) {
302 			if (!sm->blocks[i] && chunk_start != -1) {
303 				retval = sparse_merge_blocks(sm, chunk_start, i - chunk_start);
304 				chunk_start = -1;
305 			} else if (sm->blocks[i] && chunk_start == -1) {
306 				chunk_start = i;
307 			}
308 			if (retval)
309 				goto ret;
310 		}
311 		if (chunk_start != -1) {
312 			retval = sparse_merge_blocks(sm, chunk_start,
313 							sm->blocks_count - chunk_start);
314 			if (retval)
315 				goto ret;
316 		}
317 		retval = sparse_file_write(sm->sparse_file, sm->fd,
318 					   /*gzip*/0, /*sparse*/1, /*crc*/0);
319 	}
320 
321 ret:
322 	if (sm->sparse_file)
323 		sparse_file_destroy(sm->sparse_file);
324 	free_sparse_blocks(sm);
325 	free(sm->file);
326 	free(sm);
327 	free(channel);
328 	return retval;
329 }
330 
sparse_close(io_channel channel)331 static errcode_t sparse_close(io_channel channel)
332 {
333 	errcode_t retval;
334 	struct sparse_map *sm = channel->private_data;
335 	int fd = sm->fd;
336 
337 	retval = sparse_close_channel(channel);
338 	if (fd >= 0)
339 		close(fd);
340 
341 	return retval;
342 }
343 
sparse_set_blksize(io_channel channel,int blksize)344 static errcode_t sparse_set_blksize(io_channel channel, int blksize)
345 {
346 	channel->block_size = blksize;
347 	return 0;
348 }
349 
block_to_sparse_block(blk64_t block,blk64_t * offset,io_channel channel,struct sparse_map * sm)350 static blk64_t block_to_sparse_block(blk64_t block, blk64_t *offset,
351 			       io_channel channel, struct sparse_map *sm)
352 {
353 	int ratio;
354 	blk64_t ret = block;
355 
356 	ratio = sm->block_size / channel->block_size;
357 	ret /= ratio;
358 	*offset = (block % ratio) * channel->block_size;
359 
360 	return ret;
361 }
362 
check_block_size(io_channel channel,struct sparse_map * sm)363 static errcode_t check_block_size(io_channel channel, struct sparse_map *sm)
364 {
365 	if (sm->block_size >= channel->block_size)
366 		return 0;
367 	return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
368 }
369 
sparse_read_blk64(io_channel channel,blk64_t block,int count,void * buf)370 static errcode_t sparse_read_blk64(io_channel channel, blk64_t block,
371 				   int count, void *buf)
372 {
373 	int i;
374 	char *out = buf;
375 	blk64_t offset = 0, cur_block;
376 	struct sparse_map *sm = channel->private_data;
377 
378 	if (check_block_size(channel, sm))
379 		return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
380 
381 	if (count < 0) { //partial read
382 		count = -count;
383 		cur_block = block_to_sparse_block(block, &offset, channel, sm);
384 		if (sm->blocks[cur_block])
385 			memcpy(out, (sm->blocks[cur_block]) + offset, count);
386 		else
387 			memset(out, 0, count);
388 	} else {
389 		for (i = 0; i < count; ++i) {
390 			cur_block = block_to_sparse_block(block + i, &offset,
391 						    channel, sm);
392 			if (sm->blocks[cur_block])
393 				memcpy(out + (i * channel->block_size),
394 				       sm->blocks[cur_block] + offset,
395 				       channel->block_size);
396 			else if (sm->blocks)
397 				memset(out + (i * channel->block_size), 0,
398 				       channel->block_size);
399 		}
400 	}
401 	return 0;
402 }
403 
sparse_read_blk(io_channel channel,unsigned long block,int count,void * buf)404 static errcode_t sparse_read_blk(io_channel channel, unsigned long block,
405 				 int count, void *buf)
406 {
407 	return sparse_read_blk64(channel, block, count, buf);
408 }
409 
sparse_write_blk64(io_channel channel,blk64_t block,int count,const void * buf)410 static errcode_t sparse_write_blk64(io_channel channel, blk64_t block,
411 				    int count, const void *buf)
412 {
413 	int i;
414 	blk64_t offset = 0, cur_block;
415 	const char *in = buf;
416 	struct sparse_map *sm = channel->private_data;
417 
418 	if (check_block_size(channel, sm))
419 		return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
420 
421 	if (count < 0) { //partial write
422 		count = -count;
423 		cur_block = block_to_sparse_block(block, &offset, channel,
424 						  sm);
425 		if (!sm->blocks[cur_block]) {
426 			sm->blocks[cur_block] = calloc(1, sm->block_size);
427 			if (!sm->blocks[cur_block])
428 				return EXT2_ET_NO_MEMORY;
429 		}
430 		memcpy(sm->blocks[cur_block] + offset, in, count);
431 	} else {
432 		for (i = 0; i < count; ++i) {
433 			if (block + i >= sm->blocks_count)
434 				return 0;
435 			cur_block = block_to_sparse_block(block + i, &offset,
436 						    channel, sm);
437 			if (!sm->blocks[cur_block]) {
438 				sm->blocks[cur_block] =
439 					calloc(1, sm->block_size);
440 				if (!sm->blocks[cur_block])
441 					return EXT2_ET_NO_MEMORY;
442 			}
443 			memcpy(sm->blocks[cur_block] + offset,
444 			       in + (i * channel->block_size),
445 			       channel->block_size);
446 		}
447 	}
448 	return 0;
449 }
450 
sparse_write_blk(io_channel channel,unsigned long block,int count,const void * buf)451 static errcode_t sparse_write_blk(io_channel channel, unsigned long block,
452 				  int count, const void *buf)
453 {
454 	return sparse_write_blk64(channel, block, count, buf);
455 }
456 
sparse_discard(io_channel channel,blk64_t blk,unsigned long long count)457 static errcode_t sparse_discard(io_channel channel __attribute__((unused)),
458 				blk64_t blk, unsigned long long count)
459 {
460 	blk64_t cur_block, offset;
461 	struct sparse_map *sm = channel->private_data;
462 
463 	if (check_block_size(channel, sm))
464 		return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
465 
466 	for (unsigned long long i = 0; i < count; ++i) {
467 		if (blk + i >= sm->blocks_count)
468 			return 0;
469 		cur_block = block_to_sparse_block(blk + i, &offset, channel,
470 						  sm);
471 		if (!sm->blocks[cur_block])
472 			continue;
473 		free(sm->blocks[cur_block]);
474 		sm->blocks[cur_block] = NULL;
475 	}
476 	return 0;
477 }
478 
sparse_zeroout(io_channel channel,blk64_t blk,unsigned long long count)479 static errcode_t sparse_zeroout(io_channel channel, blk64_t blk,
480 				unsigned long long count)
481 {
482 	return sparse_discard(channel, blk, count);
483 }
484 
sparse_flush(io_channel channel)485 static errcode_t sparse_flush(io_channel channel __attribute__((unused)))
486 {
487 	return 0;
488 }
489 
sparse_set_option(io_channel channel,const char * option,const char * arg)490 static errcode_t sparse_set_option(io_channel channel __attribute__((unused)),
491                                    const char *option __attribute__((unused)),
492                                    const char *arg __attribute__((unused)))
493 {
494 	return 0;
495 }
496 
sparse_cache_readahead(io_channel channel,blk64_t blk,unsigned long long count)497 static errcode_t sparse_cache_readahead(
498 			io_channel channel __attribute__((unused)),
499 			blk64_t blk __attribute__((unused)),
500 			unsigned long long count __attribute__((unused)))
501 {
502 	return 0;
503 }
504 
505 static struct struct_io_manager struct_sparse_manager = {
506 	.magic			= EXT2_ET_MAGIC_IO_MANAGER,
507 	.name			= "Android sparse I/O Manager",
508 	.open			= sparse_open,
509 	.close			= sparse_close,
510 	.set_blksize		= sparse_set_blksize,
511 	.read_blk		= sparse_read_blk,
512 	.write_blk		= sparse_write_blk,
513 	.flush			= sparse_flush,
514 	.write_byte		= NULL,
515 	.set_option		= sparse_set_option,
516 	.get_stats		= NULL,
517 	.read_blk64		= sparse_read_blk64,
518 	.write_blk64		= sparse_write_blk64,
519 	.discard		= sparse_discard,
520 	.cache_readahead	= sparse_cache_readahead,
521 	.zeroout		= sparse_zeroout,
522 };
523 
524 static struct struct_io_manager struct_sparsefd_manager = {
525 	.magic			= EXT2_ET_MAGIC_IO_MANAGER,
526 	.name			= "Android sparse fd I/O Manager",
527 	.open			= sparsefd_open,
528 	.close			= sparse_close,
529 	.set_blksize		= sparse_set_blksize,
530 	.read_blk		= sparse_read_blk,
531 	.write_blk		= sparse_write_blk,
532 	.flush			= sparse_flush,
533 	.write_byte		= NULL,
534 	.set_option		= sparse_set_option,
535 	.get_stats		= NULL,
536 	.read_blk64		= sparse_read_blk64,
537 	.write_blk64		= sparse_write_blk64,
538 	.discard		= sparse_discard,
539 	.cache_readahead	= sparse_cache_readahead,
540 	.zeroout		= sparse_zeroout,
541 };
542 
543 #endif
544 
545 io_manager sparse_io_manager = &struct_sparse_manager;
546 io_manager sparsefd_io_manager = &struct_sparsefd_manager;
547