summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Cross2012-04-25 23:02:16 -0500
committerColin Cross2012-07-10 00:09:37 -0500
commitbe8ddcb35a459481c0bcf5bfe645c1fefe963f5c (patch)
treef3ab4517291fd1a8fc6c75d8670ba3cd3015be11 /libsparse
parenta21930b6b0dbb04a52948566d58fb48c6db58bab (diff)
downloadplatform-system-core-be8ddcb35a459481c0bcf5bfe645c1fefe963f5c.tar.gz
platform-system-core-be8ddcb35a459481c0bcf5bfe645c1fefe963f5c.tar.xz
platform-system-core-be8ddcb35a459481c0bcf5bfe645c1fefe963f5c.zip
libsparse: merge adjacent blocks of the same type
When a block is added that is adjacent to another block and of the same type, merge it. This will be useful for converting regular images to sparse images, allowing the reader to add a single block at a time and letting libsparse optimize into larger blocks as it goes. Does not support merge two blocks that are backed by a data pointer, only blocks that are backed by a file for now. Change-Id: I95aa231714cbe01ac194e868c21385806c0bdb97
Diffstat (limited to 'libsparse')
-rw-r--r--libsparse/backed_block.c81
-rw-r--r--libsparse/backed_block.h2
-rw-r--r--libsparse/sparse.c2
3 files changed, 76 insertions, 9 deletions
diff --git a/libsparse/backed_block.c b/libsparse/backed_block.c
index 8c3fab04a..629fc284f 100644
--- a/libsparse/backed_block.c
+++ b/libsparse/backed_block.c
@@ -21,6 +21,7 @@
21#include <string.h> 21#include <string.h>
22 22
23#include "backed_block.h" 23#include "backed_block.h"
24#include "sparse_defs.h"
24 25
25struct backed_block { 26struct backed_block {
26 unsigned int block; 27 unsigned int block;
@@ -48,6 +49,7 @@ struct backed_block {
48struct backed_block_list { 49struct backed_block_list {
49 struct backed_block *data_blocks; 50 struct backed_block *data_blocks;
50 struct backed_block *last_used; 51 struct backed_block *last_used;
52 unsigned int block_size;
51}; 53};
52 54
53struct backed_block *backed_block_iter_new(struct backed_block_list *bbl) 55struct backed_block *backed_block_iter_new(struct backed_block_list *bbl)
@@ -109,10 +111,19 @@ enum backed_block_type backed_block_type(struct backed_block *bb)
109 return bb->type; 111 return bb->type;
110} 112}
111 113
112struct backed_block_list *backed_block_list_new(void) 114void backed_block_destroy(struct backed_block *bb)
113{ 115{
114 struct backed_block_list *b = calloc(sizeof(struct backed_block_list), 1); 116 if (bb->type == BACKED_BLOCK_FILE) {
117 free(bb->file.filename);
118 }
115 119
120 free(bb);
121}
122
123struct backed_block_list *backed_block_list_new(unsigned int block_size)
124{
125 struct backed_block_list *b = calloc(sizeof(struct backed_block_list), 1);
126 b->block_size = block_size;
116 return b; 127 return b;
117} 128}
118 129
@@ -122,11 +133,7 @@ void backed_block_list_destroy(struct backed_block_list *bbl)
122 struct backed_block *bb = bbl->data_blocks; 133 struct backed_block *bb = bbl->data_blocks;
123 while (bb) { 134 while (bb) {
124 struct backed_block *next = bb->next; 135 struct backed_block *next = bb->next;
125 if (bb->type == BACKED_BLOCK_FILE) { 136 backed_block_destroy(bb);
126 free(bb->file.filename);
127 }
128
129 free(bb);
130 bb = next; 137 bb = next;
131 } 138 }
132 } 139 }
@@ -134,6 +141,63 @@ void backed_block_list_destroy(struct backed_block_list *bbl)
134 free(bbl); 141 free(bbl);
135} 142}
136 143
144/* may free b */
145static int merge_bb(struct backed_block_list *bbl,
146 struct backed_block *a, struct backed_block *b)
147{
148 unsigned int block_len;
149
150 /* Block doesn't exist (possible if one block is the last block) */
151 if (!a || !b) {
152 return -EINVAL;
153 }
154
155 assert(a->block < b->block);
156
157 /* Blocks are of different types */
158 if (a->type != b->type) {
159 return -EINVAL;
160 }
161
162 /* Blocks are not adjacent */
163 block_len = a->len / bbl->block_size; /* rounds down */
164 if (a->block + block_len != b->block) {
165 return -EINVAL;
166 }
167
168 switch (a->type) {
169 case BACKED_BLOCK_DATA:
170 /* Don't support merging data for now */
171 return -EINVAL;
172 case BACKED_BLOCK_FILL:
173 if (a->fill.val != b->fill.val) {
174 return -EINVAL;
175 }
176 break;
177 case BACKED_BLOCK_FILE:
178 if (a->file.filename != b->file.filename ||
179 a->file.offset + a->len != b->file.offset) {
180 return -EINVAL;
181 }
182 break;
183 case BACKED_BLOCK_FD:
184 if (a->fd.fd != b->fd.fd ||
185 a->fd.offset + a->len != b->fd.offset) {
186 return -EINVAL;
187 }
188 break;
189 }
190
191 /* Blocks are compatible and adjacent, with a before b. Merge b into a,
192 * and free b */
193 a->len += b->len;
194 a->next = b->next;
195
196 backed_block_destroy(b);
197
198 return 0;
199}
200
137static int queue_bb(struct backed_block_list *bbl, struct backed_block *new_bb) 201static int queue_bb(struct backed_block_list *bbl, struct backed_block *new_bb)
138{ 202{
139 struct backed_block *bb; 203 struct backed_block *bb;
@@ -168,6 +232,9 @@ static int queue_bb(struct backed_block_list *bbl, struct backed_block *new_bb)
168 bb->next = new_bb; 232 bb->next = new_bb;
169 } 233 }
170 234
235 merge_bb(bbl, new_bb, new_bb->next);
236 merge_bb(bbl, bb, new_bb);
237
171 return 0; 238 return 0;
172} 239}
173 240
diff --git a/libsparse/backed_block.h b/libsparse/backed_block.h
index ca2ad1d9b..692691712 100644
--- a/libsparse/backed_block.h
+++ b/libsparse/backed_block.h
@@ -52,7 +52,7 @@ enum backed_block_type backed_block_type(struct backed_block *bb);
52struct backed_block *backed_block_iter_new(struct backed_block_list *bbl); 52struct backed_block *backed_block_iter_new(struct backed_block_list *bbl);
53struct backed_block *backed_block_iter_next(struct backed_block *bb); 53struct backed_block *backed_block_iter_next(struct backed_block *bb);
54 54
55struct backed_block_list *backed_block_list_new(void); 55struct backed_block_list *backed_block_list_new(unsigned int block_size);
56void backed_block_list_destroy(struct backed_block_list *bbl); 56void backed_block_list_destroy(struct backed_block_list *bbl);
57 57
58#endif 58#endif
diff --git a/libsparse/sparse.c b/libsparse/sparse.c
index 3403604d4..d778e1dc6 100644
--- a/libsparse/sparse.c
+++ b/libsparse/sparse.c
@@ -32,7 +32,7 @@ struct sparse_file *sparse_file_new(unsigned int block_size, int64_t len)
32 return NULL; 32 return NULL;
33 } 33 }
34 34
35 s->backed_block_list = backed_block_list_new(); 35 s->backed_block_list = backed_block_list_new(block_size);
36 if (!s->backed_block_list) { 36 if (!s->backed_block_list) {
37 free(s); 37 free(s);
38 return NULL; 38 return NULL;