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