diff options
-rw-r--r-- | libsparse/backed_block.c | 81 | ||||
-rw-r--r-- | libsparse/backed_block.h | 2 | ||||
-rw-r--r-- | libsparse/sparse.c | 2 |
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 | ||
25 | struct backed_block { | 26 | struct backed_block { |
26 | unsigned int block; | 27 | unsigned int block; |
@@ -48,6 +49,7 @@ struct backed_block { | |||
48 | struct backed_block_list { | 49 | struct 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 | ||
53 | struct backed_block *backed_block_iter_new(struct backed_block_list *bbl) | 55 | struct 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 | ||
112 | struct backed_block_list *backed_block_list_new(void) | 114 | void 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 | |||
123 | struct 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 */ | ||
145 | static 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 | |||
137 | static int queue_bb(struct backed_block_list *bbl, struct backed_block *new_bb) | 201 | static 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); | |||
52 | struct backed_block *backed_block_iter_new(struct backed_block_list *bbl); | 52 | struct backed_block *backed_block_iter_new(struct backed_block_list *bbl); |
53 | struct backed_block *backed_block_iter_next(struct backed_block *bb); | 53 | struct backed_block *backed_block_iter_next(struct backed_block *bb); |
54 | 54 | ||
55 | struct backed_block_list *backed_block_list_new(void); | 55 | struct backed_block_list *backed_block_list_new(unsigned int block_size); |
56 | void backed_block_list_destroy(struct backed_block_list *bbl); | 56 | void 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; |