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