diff options
Diffstat (limited to 'meta/recipes-devtools/genext2fs/genext2fs-1.4.1/0010-Convert-over-to-keeping-the-filesystem-on-disk.patch')
-rw-r--r-- | meta/recipes-devtools/genext2fs/genext2fs-1.4.1/0010-Convert-over-to-keeping-the-filesystem-on-disk.patch | 839 |
1 files changed, 839 insertions, 0 deletions
diff --git a/meta/recipes-devtools/genext2fs/genext2fs-1.4.1/0010-Convert-over-to-keeping-the-filesystem-on-disk.patch b/meta/recipes-devtools/genext2fs/genext2fs-1.4.1/0010-Convert-over-to-keeping-the-filesystem-on-disk.patch new file mode 100644 index 0000000000..79e82c8c73 --- /dev/null +++ b/meta/recipes-devtools/genext2fs/genext2fs-1.4.1/0010-Convert-over-to-keeping-the-filesystem-on-disk.patch | |||
@@ -0,0 +1,839 @@ | |||
1 | Upstream-Status: inappropriate | ||
2 | |||
3 | From 29a36b0b91ee009ee4219934c7a70278b1361834 Mon Sep 17 00:00:00 2001 | ||
4 | From: Corey Minyard <cminyard@mvista.com> | ||
5 | Date: Sun, 5 Jun 2011 15:24:57 -0500 | ||
6 | Subject: [PATCH 10/19] Convert over to keeping the filesystem on disk | ||
7 | |||
8 | This makes the actual filesystem be on disk and not in memory. It | ||
9 | adds caching of the filesystem data to help keep oft-accessed blocks | ||
10 | in memory and byteswapped. | ||
11 | --- | ||
12 | cache.h | 128 ++++++++++++++++++++ | ||
13 | genext2fs.c | 377 +++++++++++++++++++++++++++++++++++++++++++++++++---------- | ||
14 | list.h | 78 ++++++++++++ | ||
15 | 3 files changed, 521 insertions(+), 62 deletions(-) | ||
16 | create mode 100644 cache.h | ||
17 | create mode 100644 list.h | ||
18 | |||
19 | diff --git a/cache.h b/cache.h | ||
20 | new file mode 100644 | ||
21 | index 0000000..5275be6 | ||
22 | --- /dev/null | ||
23 | +++ b/cache.h | ||
24 | @@ -0,0 +1,128 @@ | ||
25 | +#ifndef __CACHE_H__ | ||
26 | +#define __CACHE_H__ | ||
27 | + | ||
28 | +#include "list.h" | ||
29 | + | ||
30 | +#define CACHE_LISTS 256 | ||
31 | + | ||
32 | +typedef struct | ||
33 | +{ | ||
34 | + list_elem link; | ||
35 | + list_elem lru_link; | ||
36 | +} cache_link; | ||
37 | + | ||
38 | +typedef struct | ||
39 | +{ | ||
40 | + /* LRU list holds unused items */ | ||
41 | + unsigned int lru_entries; | ||
42 | + list_elem lru_list; | ||
43 | + unsigned int max_free_entries; | ||
44 | + | ||
45 | + unsigned int entries; | ||
46 | + list_elem lists[CACHE_LISTS]; | ||
47 | + unsigned int (*elem_val)(cache_link *elem); | ||
48 | + void (*freed)(cache_link *elem); | ||
49 | +} listcache; | ||
50 | + | ||
51 | +static inline void | ||
52 | +cache_add(listcache *c, cache_link *elem) | ||
53 | +{ | ||
54 | + unsigned int hash = c->elem_val(elem) % CACHE_LISTS; | ||
55 | + int delcount = c->lru_entries - c->max_free_entries; | ||
56 | + | ||
57 | + if (delcount > 0) { | ||
58 | + /* Delete some unused items. */ | ||
59 | + list_elem *lru, *next; | ||
60 | + cache_link *l; | ||
61 | + list_for_each_elem_safe(&c->lru_list, lru, next) { | ||
62 | + l = container_of(lru, cache_link, lru_link); | ||
63 | + list_del(lru); | ||
64 | + list_del(&l->link); | ||
65 | + c->entries--; | ||
66 | + c->lru_entries--; | ||
67 | + c->freed(l); | ||
68 | + delcount--; | ||
69 | + if (delcount <= 0) | ||
70 | + break; | ||
71 | + } | ||
72 | + } | ||
73 | + | ||
74 | + c->entries++; | ||
75 | + list_item_init(&elem->lru_link); /* Mark it not in the LRU list */ | ||
76 | + list_add_after(&c->lists[hash], &elem->link); | ||
77 | +} | ||
78 | + | ||
79 | +static inline void | ||
80 | +cache_item_set_unused(listcache *c, cache_link *elem) | ||
81 | +{ | ||
82 | + list_add_before(&c->lru_list, &elem->lru_link); | ||
83 | + c->lru_entries++; | ||
84 | +} | ||
85 | + | ||
86 | +static inline cache_link * | ||
87 | +cache_find(listcache *c, unsigned int val) | ||
88 | +{ | ||
89 | + unsigned int hash = val % CACHE_LISTS; | ||
90 | + list_elem *elem; | ||
91 | + | ||
92 | + list_for_each_elem(&c->lists[hash], elem) { | ||
93 | + cache_link *l = container_of(elem, cache_link, link); | ||
94 | + if (c->elem_val(l) == val) { | ||
95 | + if (!list_empty(&l->lru_link)) { | ||
96 | + /* It's in the unused list, remove it. */ | ||
97 | + list_del(&l->lru_link); | ||
98 | + list_item_init(&l->lru_link); | ||
99 | + c->lru_entries--; | ||
100 | + } | ||
101 | + return l; | ||
102 | + } | ||
103 | + } | ||
104 | + return NULL; | ||
105 | +} | ||
106 | + | ||
107 | +static inline int | ||
108 | +cache_flush(listcache *c) | ||
109 | +{ | ||
110 | + list_elem *elem, *next; | ||
111 | + cache_link *l; | ||
112 | + int i; | ||
113 | + | ||
114 | + list_for_each_elem_safe(&c->lru_list, elem, next) { | ||
115 | + l = container_of(elem, cache_link, lru_link); | ||
116 | + list_del(elem); | ||
117 | + list_del(&l->link); | ||
118 | + c->entries--; | ||
119 | + c->lru_entries--; | ||
120 | + c->freed(l); | ||
121 | + } | ||
122 | + | ||
123 | + for (i = 0; i < CACHE_LISTS; i++) { | ||
124 | + list_for_each_elem_safe(&c->lists[i], elem, next) { | ||
125 | + l = container_of(elem, cache_link, link); | ||
126 | + list_del(&l->link); | ||
127 | + c->entries--; | ||
128 | + c->freed(l); | ||
129 | + } | ||
130 | + } | ||
131 | + | ||
132 | + return c->entries || c->lru_entries; | ||
133 | +} | ||
134 | + | ||
135 | +static inline void | ||
136 | +cache_init(listcache *c, unsigned int max_free_entries, | ||
137 | + unsigned int (*elem_val)(cache_link *elem), | ||
138 | + void (*freed)(cache_link *elem)) | ||
139 | +{ | ||
140 | + int i; | ||
141 | + | ||
142 | + c->entries = 0; | ||
143 | + c->lru_entries = 0; | ||
144 | + c->max_free_entries = max_free_entries; | ||
145 | + list_init(&c->lru_list); | ||
146 | + for (i = 0; i < CACHE_LISTS; i++) | ||
147 | + list_init(&c->lists[i]); | ||
148 | + c->elem_val = elem_val; | ||
149 | + c->freed = freed; | ||
150 | +} | ||
151 | + | ||
152 | +#endif /* __CACHE_H__ */ | ||
153 | diff --git a/genext2fs.c b/genext2fs.c | ||
154 | index 51403a2..f79438d 100644 | ||
155 | --- a/genext2fs.c | ||
156 | +++ b/genext2fs.c | ||
157 | @@ -142,6 +142,8 @@ | ||
158 | # include <limits.h> | ||
159 | #endif | ||
160 | |||
161 | +#include "cache.h" | ||
162 | + | ||
163 | struct stats { | ||
164 | unsigned long nblocks; | ||
165 | unsigned long ninodes; | ||
166 | @@ -600,6 +602,7 @@ struct hdlinks_s | ||
167 | #if BLOCKSIZE == 1024 | ||
168 | typedef struct | ||
169 | { | ||
170 | + FILE *f; | ||
171 | uint8 *data; | ||
172 | superblock *sb; | ||
173 | groupdescriptor *gd; | ||
174 | @@ -607,6 +610,10 @@ typedef struct | ||
175 | int swapit; | ||
176 | int32 hdlink_cnt; | ||
177 | struct hdlinks_s hdlinks; | ||
178 | + | ||
179 | + listcache blks; | ||
180 | + listcache inodes; | ||
181 | + listcache blkmaps; | ||
182 | } filesystem; | ||
183 | #else | ||
184 | #error UNHANDLED BLOCKSIZE | ||
185 | @@ -848,45 +855,150 @@ allocated(block b, uint32 item) | ||
186 | // by the user. | ||
187 | typedef struct | ||
188 | { | ||
189 | - int dummy; | ||
190 | + cache_link link; | ||
191 | + | ||
192 | + filesystem *fs; | ||
193 | + uint32 blk; | ||
194 | + uint8 *b; | ||
195 | + uint32 usecount; | ||
196 | } blk_info; | ||
197 | |||
198 | +#define MAX_FREE_CACHE_BLOCKS 100 | ||
199 | + | ||
200 | +static uint32 | ||
201 | +blk_elem_val(cache_link *elem) | ||
202 | +{ | ||
203 | + blk_info *bi = container_of(elem, blk_info, link); | ||
204 | + return bi->blk; | ||
205 | +} | ||
206 | + | ||
207 | +static void | ||
208 | +blk_freed(cache_link *elem) | ||
209 | +{ | ||
210 | + blk_info *bi = container_of(elem, blk_info, link); | ||
211 | + | ||
212 | + if (fseeko(bi->fs->f, ((off_t) bi->blk) * BLOCKSIZE, SEEK_SET)) | ||
213 | + perror_msg_and_die("fseek"); | ||
214 | + if (fwrite(bi->b, BLOCKSIZE, 1, bi->fs->f) != 1) | ||
215 | + perror_msg_and_die("get_blk: write"); | ||
216 | + free(bi->b); | ||
217 | + free(bi); | ||
218 | +} | ||
219 | + | ||
220 | // Return a given block from a filesystem. Make sure to call | ||
221 | // put_blk when you are done with it. | ||
222 | static inline uint8 * | ||
223 | get_blk(filesystem *fs, uint32 blk, blk_info **rbi) | ||
224 | { | ||
225 | - return fs->data + blk*BLOCKSIZE; | ||
226 | + cache_link *curr; | ||
227 | + blk_info *bi; | ||
228 | + | ||
229 | + if (blk < fs->nheadblocks) | ||
230 | + error_msg_and_die("Internal error, request for head block"); | ||
231 | + if (blk >= fs->sb->s_blocks_count) | ||
232 | + error_msg_and_die("Internal error, block out of range"); | ||
233 | + | ||
234 | + curr = cache_find(&fs->blks, blk); | ||
235 | + if (curr) { | ||
236 | + bi = container_of(curr, blk_info, link); | ||
237 | + bi->usecount++; | ||
238 | + goto out; | ||
239 | + } | ||
240 | + | ||
241 | + bi = malloc(sizeof(*bi)); | ||
242 | + if (!bi) | ||
243 | + error_msg_and_die("get_blk: out of memory"); | ||
244 | + bi->fs = fs; | ||
245 | + bi->blk = blk; | ||
246 | + bi->usecount = 1; | ||
247 | + bi->b = malloc(BLOCKSIZE); | ||
248 | + if (!bi->b) | ||
249 | + error_msg_and_die("get_blk: out of memory"); | ||
250 | + cache_add(&fs->blks, &bi->link); | ||
251 | + if (fseeko(fs->f, ((off_t) blk) * BLOCKSIZE, SEEK_SET)) | ||
252 | + perror_msg_and_die("fseek"); | ||
253 | + if (fread(bi->b, BLOCKSIZE, 1, fs->f) != 1) { | ||
254 | + if (ferror(fs->f)) | ||
255 | + perror_msg_and_die("fread"); | ||
256 | + memset(bi->b, 0, BLOCKSIZE); | ||
257 | + } | ||
258 | + | ||
259 | +out: | ||
260 | + *rbi = bi; | ||
261 | + return bi->b; | ||
262 | } | ||
263 | |||
264 | static inline void | ||
265 | put_blk(blk_info *bi) | ||
266 | { | ||
267 | + if (bi->usecount == 0) | ||
268 | + error_msg_and_die("Internal error: put_blk usecount zero"); | ||
269 | + bi->usecount--; | ||
270 | + if (bi->usecount == 0) | ||
271 | + /* Free happens in the cache code */ | ||
272 | + cache_item_set_unused(&bi->fs->blks, &bi->link); | ||
273 | } | ||
274 | |||
275 | // Used by get_blkmap/put_blkmap to hold information about an block map | ||
276 | // owned by the user. | ||
277 | typedef struct | ||
278 | { | ||
279 | + cache_link link; | ||
280 | + | ||
281 | filesystem *fs; | ||
282 | + uint32 blk; | ||
283 | uint8 *b; | ||
284 | blk_info *bi; | ||
285 | + uint32 usecount; | ||
286 | } blkmap_info; | ||
287 | |||
288 | +#define MAX_FREE_CACHE_BLOCKMAPS 100 | ||
289 | + | ||
290 | +static uint32 | ||
291 | +blkmap_elem_val(cache_link *elem) | ||
292 | +{ | ||
293 | + blkmap_info *bmi = container_of(elem, blkmap_info, link); | ||
294 | + return bmi->blk; | ||
295 | +} | ||
296 | + | ||
297 | +static void | ||
298 | +blkmap_freed(cache_link *elem) | ||
299 | +{ | ||
300 | + blkmap_info *bmi = container_of(elem, blkmap_info, link); | ||
301 | + | ||
302 | + if (bmi->fs->swapit) | ||
303 | + swap_block(bmi->b); | ||
304 | + put_blk(bmi->bi); | ||
305 | + free(bmi); | ||
306 | +} | ||
307 | + | ||
308 | // Return a given block map from a filesystem. Make sure to call | ||
309 | // put_blkmap when you are done with it. | ||
310 | static inline uint32 * | ||
311 | get_blkmap(filesystem *fs, uint32 blk, blkmap_info **rbmi) | ||
312 | { | ||
313 | blkmap_info *bmi; | ||
314 | + cache_link *curr; | ||
315 | + | ||
316 | + curr = cache_find(&fs->blkmaps, blk); | ||
317 | + if (curr) { | ||
318 | + bmi = container_of(curr, blkmap_info, link); | ||
319 | + bmi->usecount++; | ||
320 | + goto out; | ||
321 | + } | ||
322 | |||
323 | bmi = malloc(sizeof(*bmi)); | ||
324 | if (!bmi) | ||
325 | error_msg_and_die("get_blkmap: out of memory"); | ||
326 | bmi->fs = fs; | ||
327 | + bmi->blk = blk; | ||
328 | bmi->b = get_blk(fs, blk, &bmi->bi); | ||
329 | - if (bmi->fs->swapit) | ||
330 | + bmi->usecount = 1; | ||
331 | + cache_add(&fs->blkmaps, &bmi->link); | ||
332 | + | ||
333 | + if (fs->swapit) | ||
334 | swap_block(bmi->b); | ||
335 | +out: | ||
336 | *rbmi = bmi; | ||
337 | return (uint32 *) bmi->b; | ||
338 | } | ||
339 | @@ -894,42 +1006,83 @@ get_blkmap(filesystem *fs, uint32 blk, blkmap_info **rbmi) | ||
340 | static inline void | ||
341 | put_blkmap(blkmap_info *bmi) | ||
342 | { | ||
343 | - if (bmi->fs->swapit) | ||
344 | - swap_block(bmi->b); | ||
345 | - put_blk(bmi->bi); | ||
346 | - free(bmi); | ||
347 | + if (bmi->usecount == 0) | ||
348 | + error_msg_and_die("Internal error: put_blkmap usecount zero"); | ||
349 | + | ||
350 | + bmi->usecount--; | ||
351 | + if (bmi->usecount == 0) | ||
352 | + /* Free happens in the cache code */ | ||
353 | + cache_item_set_unused(&bmi->fs->blkmaps, &bmi->link); | ||
354 | } | ||
355 | |||
356 | // Used by get_nod/put_nod to hold information about an inode owned | ||
357 | // by the user. | ||
358 | typedef struct | ||
359 | { | ||
360 | + cache_link link; | ||
361 | + | ||
362 | filesystem *fs; | ||
363 | + uint32 nod; | ||
364 | + uint8 *b; | ||
365 | blk_info *bi; | ||
366 | inode *itab; | ||
367 | + uint32 usecount; | ||
368 | } nod_info; | ||
369 | |||
370 | +#define MAX_FREE_CACHE_INODES 100 | ||
371 | + | ||
372 | +static uint32 | ||
373 | +inode_elem_val(cache_link *elem) | ||
374 | +{ | ||
375 | + nod_info *ni = container_of(elem, nod_info, link); | ||
376 | + return ni->nod; | ||
377 | +} | ||
378 | + | ||
379 | +static void | ||
380 | +inode_freed(cache_link *elem) | ||
381 | +{ | ||
382 | + nod_info *ni = container_of(elem, nod_info, link); | ||
383 | + | ||
384 | + if (ni->fs->swapit) | ||
385 | + swap_nod(ni->itab); | ||
386 | + put_blk(ni->bi); | ||
387 | + free(ni); | ||
388 | +} | ||
389 | + | ||
390 | // Return a given inode from a filesystem. Make sure to call put_nod() | ||
391 | // when you are done with the inode. | ||
392 | static inline inode * | ||
393 | get_nod(filesystem *fs, uint32 nod, nod_info **rni) | ||
394 | { | ||
395 | int grp, offset, boffset; | ||
396 | + cache_link *curr; | ||
397 | nod_info *ni; | ||
398 | - uint8 *b; | ||
399 | |||
400 | - offset = GRP_IBM_OFFSET(fs,nod) - 1; | ||
401 | - boffset = offset / (BLOCKSIZE / sizeof(inode)); | ||
402 | - offset %= BLOCKSIZE / sizeof(inode); | ||
403 | - grp = GRP_GROUP_OF_INODE(fs,nod); | ||
404 | + curr = cache_find(&fs->inodes, nod); | ||
405 | + if (curr) { | ||
406 | + ni = container_of(curr, nod_info, link); | ||
407 | + ni->usecount++; | ||
408 | + goto out; | ||
409 | + } | ||
410 | + | ||
411 | ni = malloc(sizeof(*ni)); | ||
412 | if (!ni) | ||
413 | error_msg_and_die("get_nod: out of memory"); | ||
414 | ni->fs = fs; | ||
415 | - b = get_blk(fs, fs->gd[grp].bg_inode_table + boffset, &ni->bi); | ||
416 | - ni->itab = ((inode *) b) + offset; | ||
417 | + ni->nod = nod; | ||
418 | + ni->usecount = 1; | ||
419 | + cache_add(&fs->inodes, &ni->link); | ||
420 | + | ||
421 | + offset = GRP_IBM_OFFSET(fs, nod) - 1; | ||
422 | + boffset = offset / (BLOCKSIZE / sizeof(inode)); | ||
423 | + offset %= BLOCKSIZE / sizeof(inode); | ||
424 | + grp = GRP_GROUP_OF_INODE(fs,nod); | ||
425 | + ni->b = get_blk(fs, fs->gd[grp].bg_inode_table + boffset, &ni->bi); | ||
426 | + ni->itab = ((inode *) ni->b) + offset; | ||
427 | if (fs->swapit) | ||
428 | swap_nod(ni->itab); | ||
429 | + | ||
430 | +out: | ||
431 | *rni = ni; | ||
432 | return ni->itab; | ||
433 | } | ||
434 | @@ -937,10 +1090,13 @@ get_nod(filesystem *fs, uint32 nod, nod_info **rni) | ||
435 | static inline void | ||
436 | put_nod(nod_info *ni) | ||
437 | { | ||
438 | - if (ni->fs->swapit) | ||
439 | - swap_nod(ni->itab); | ||
440 | - put_blk(ni->bi); | ||
441 | - free(ni); | ||
442 | + if (ni->usecount == 0) | ||
443 | + error_msg_and_die("Internal error: put_nod usecount zero"); | ||
444 | + | ||
445 | + ni->usecount--; | ||
446 | + if (ni->usecount == 0) | ||
447 | + /* Free happens in the cache code */ | ||
448 | + cache_item_set_unused(&ni->fs->inodes, &ni->link); | ||
449 | } | ||
450 | |||
451 | // Used to hold state information while walking a directory inode. | ||
452 | @@ -2090,40 +2246,61 @@ add2fs_from_dir(filesystem *fs, uint32 this_nod, int squash_uids, int squash_per | ||
453 | closedir(dh); | ||
454 | } | ||
455 | |||
456 | -// endianness swap of the whole filesystem | ||
457 | static void | ||
458 | -swap_goodfs(filesystem *fs) | ||
459 | +swap_gds(filesystem *fs) | ||
460 | { | ||
461 | uint32 i; | ||
462 | - | ||
463 | for(i=0;i<GRP_NBGROUPS(fs);i++) | ||
464 | swap_gd(&(fs->gd[i])); | ||
465 | - swap_sb(fs->sb); | ||
466 | } | ||
467 | |||
468 | +// Copy size blocks from src to dst, putting holes in the output | ||
469 | +// file (if possible) if the input block is all zeros. | ||
470 | static void | ||
471 | -swap_badfs(filesystem *fs) | ||
472 | +copy_file(filesystem *fs, FILE *dst, FILE *src, size_t size) | ||
473 | { | ||
474 | - uint32 i; | ||
475 | - swap_sb(fs->sb); | ||
476 | - for(i=0;i<GRP_NBGROUPS(fs);i++) | ||
477 | - swap_gd(&(fs->gd[i])); | ||
478 | + uint8 *b; | ||
479 | + | ||
480 | + b = malloc(BLOCKSIZE); | ||
481 | + if (!b) | ||
482 | + error_msg_and_die("copy_file: out of memory"); | ||
483 | + if (fseek(src, 0, SEEK_SET)) | ||
484 | + perror_msg_and_die("fseek"); | ||
485 | + if (ftruncate(fileno(dst), 0)) | ||
486 | + perror_msg_and_die("copy_file: ftruncate"); | ||
487 | + while (size > 0) { | ||
488 | + if (fread(b, BLOCKSIZE, 1, src) != 1) | ||
489 | + perror_msg_and_die("copy failed on read"); | ||
490 | + if ((dst != stdout) && is_blk_empty(b)) { | ||
491 | + /* Empty block, just skip it */ | ||
492 | + if (fseek(dst, BLOCKSIZE, SEEK_CUR)) | ||
493 | + perror_msg_and_die("fseek"); | ||
494 | + } else { | ||
495 | + if (fwrite(b, BLOCKSIZE, 1, dst) != 1) | ||
496 | + perror_msg_and_die("copy failed on write"); | ||
497 | + } | ||
498 | + size --; | ||
499 | + } | ||
500 | } | ||
501 | |||
502 | // Allocate a new filesystem structure, allocate internal memory, | ||
503 | // and initialize the contents. | ||
504 | static filesystem * | ||
505 | -alloc_fs(uint32 nbblocks, int swapit) | ||
506 | +alloc_fs(int swapit, char *fname, uint32 nbblocks, FILE *srcfile) | ||
507 | { | ||
508 | filesystem *fs; | ||
509 | + struct stat srcstat, dststat; | ||
510 | |||
511 | fs = malloc(sizeof(*fs)); | ||
512 | if (!fs) | ||
513 | error_msg_and_die("not enough memory for filesystem"); | ||
514 | memset(fs, 0, sizeof(*fs)); | ||
515 | fs->swapit = swapit; | ||
516 | - if(!(fs->data = calloc(nbblocks, BLOCKSIZE))) | ||
517 | - error_msg_and_die("not enough memory for filesystem"); | ||
518 | + cache_init(&fs->blks, MAX_FREE_CACHE_BLOCKS, blk_elem_val, blk_freed); | ||
519 | + cache_init(&fs->blkmaps, MAX_FREE_CACHE_BLOCKMAPS, | ||
520 | + blkmap_elem_val, blkmap_freed); | ||
521 | + cache_init(&fs->inodes, MAX_FREE_CACHE_INODES, | ||
522 | + inode_elem_val, inode_freed); | ||
523 | fs->hdlink_cnt = HDLINK_CNT; | ||
524 | fs->hdlinks.hdl = calloc(sizeof(struct hdlink_s), fs->hdlink_cnt); | ||
525 | if (!fs->hdlinks.hdl) | ||
526 | @@ -2131,12 +2308,44 @@ alloc_fs(uint32 nbblocks, int swapit) | ||
527 | fs->hdlinks.count = 0 ; | ||
528 | fs->sb = (superblock *) (fs->data + BLOCKSIZE); | ||
529 | fs->gd = (groupdescriptor *) (fs->sb + 1); | ||
530 | + | ||
531 | + if (strcmp(fname, "-") == 0) | ||
532 | + fs->f = tmpfile(); | ||
533 | + else if (srcfile) { | ||
534 | + if (fstat(fileno(srcfile), &srcstat)) | ||
535 | + perror_msg_and_die("fstat srcfile"); | ||
536 | + if (stat(fname, &dststat)) | ||
537 | + perror_msg_and_die("stat-ing %s", fname); | ||
538 | + if (srcstat.st_ino == dststat.st_ino) { | ||
539 | + // source and destination are the same file, don't | ||
540 | + // truncate or copy, just use the file. | ||
541 | + fs->f = fopen(fname, "r+b"); | ||
542 | + } else { | ||
543 | + fs->f = fopen(fname, "w+b"); | ||
544 | + if (fs->f) | ||
545 | + copy_file(fs, fs->f, srcfile, | ||
546 | + nbblocks * BLOCKSIZE); | ||
547 | + } | ||
548 | + } else | ||
549 | + fs->f = fopen(fname, "w+b"); | ||
550 | + if (!fs->f) | ||
551 | + perror_msg_and_die("opening %s", fname); | ||
552 | return fs; | ||
553 | } | ||
554 | |||
555 | +/* Make sure the output file is the right size */ | ||
556 | +static void | ||
557 | +set_file_size(filesystem *fs) | ||
558 | +{ | ||
559 | + if (ftruncate(fileno(fs->f), | ||
560 | + ((off_t) fs->sb->s_blocks_count) * BLOCKSIZE)) | ||
561 | + perror_msg_and_die("set_file_size: ftruncate"); | ||
562 | +} | ||
563 | + | ||
564 | // initialize an empty filesystem | ||
565 | static filesystem * | ||
566 | -init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp, int swapit) | ||
567 | +init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, | ||
568 | + uint32 fs_timestamp, int swapit, char *fname) | ||
569 | { | ||
570 | uint32 i; | ||
571 | filesystem *fs; | ||
572 | @@ -2184,10 +2393,16 @@ init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp | ||
573 | free_blocks = nbblocks - overhead_per_group*nbgroups - 1 /*boot block*/; | ||
574 | free_blocks_per_group = nbblocks_per_group - overhead_per_group; | ||
575 | |||
576 | - fs = alloc_fs(nbblocks, swapit); | ||
577 | + fs = alloc_fs(swapit, fname, nbblocks, NULL); | ||
578 | fs->nheadblocks = (((nbgroups * sizeof(groupdescriptor)) | ||
579 | + sizeof(superblock) + (BLOCKSIZE - 1)) | ||
580 | / BLOCKSIZE); | ||
581 | + fs->sb = (superblock *) malloc(BLOCKSIZE); | ||
582 | + if (!fs->sb) | ||
583 | + error_msg_and_die("error allocating header memory"); | ||
584 | + fs->gd = (groupdescriptor *) calloc(fs->nheadblocks - 1, BLOCKSIZE); | ||
585 | + if (!fs->gd) | ||
586 | + error_msg_and_die("error allocating header memory"); | ||
587 | |||
588 | // create the superblock for an empty filesystem | ||
589 | fs->sb->s_inodes_count = nbinodes_per_group * nbgroups; | ||
590 | @@ -2205,6 +2420,10 @@ init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp | ||
591 | fs->sb->s_magic = EXT2_MAGIC_NUMBER; | ||
592 | fs->sb->s_lastcheck = fs_timestamp; | ||
593 | |||
594 | + fs->sb->s_reserved[200] = 0; | ||
595 | + | ||
596 | + set_file_size(fs); | ||
597 | + | ||
598 | // set up groupdescriptors | ||
599 | for(i=0, bbmpos=gdsz+2, ibmpos=bbmpos+1, itblpos=ibmpos+1; | ||
600 | i<nbgroups; | ||
601 | @@ -2315,27 +2534,49 @@ init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp | ||
602 | |||
603 | // loads a filesystem from disk | ||
604 | static filesystem * | ||
605 | -load_fs(FILE * fh, int swapit) | ||
606 | +load_fs(FILE * fh, int swapit, char *fname) | ||
607 | { | ||
608 | - size_t fssize; | ||
609 | + off_t fssize; | ||
610 | filesystem *fs; | ||
611 | - if((fseek(fh, 0, SEEK_END) < 0) || ((ssize_t)(fssize = ftell(fh)) == -1)) | ||
612 | + | ||
613 | + if((fseek(fh, 0, SEEK_END) < 0) || ((fssize = ftello(fh)) == -1)) | ||
614 | perror_msg_and_die("input filesystem image"); | ||
615 | rewind(fh); | ||
616 | - fssize = (fssize + BLOCKSIZE - 1) / BLOCKSIZE; | ||
617 | + if ((fssize % BLOCKSIZE) != 0) | ||
618 | + error_msg_and_die("Input file not a multiple of block size"); | ||
619 | + fssize /= BLOCKSIZE; | ||
620 | if(fssize < 16) // totally arbitrary | ||
621 | error_msg_and_die("too small filesystem"); | ||
622 | - fs = alloc_fs(fssize, swapit); | ||
623 | - if(fread(fs->data, BLOCKSIZE, fssize, fh) != fssize) | ||
624 | - perror_msg_and_die("input filesystem image"); | ||
625 | - | ||
626 | + fs = alloc_fs(swapit, fname, fssize, fh); | ||
627 | + | ||
628 | + /* Read and check the superblock, then read the superblock | ||
629 | + * and all the group descriptors */ | ||
630 | + fs->sb = malloc(BLOCKSIZE); | ||
631 | + if (!fs->sb) | ||
632 | + error_msg_and_die("error allocating header memory"); | ||
633 | + if (fseek(fs->f, BLOCKSIZE, SEEK_SET)) | ||
634 | + perror_msg_and_die("fseek"); | ||
635 | + if (fread(fs->sb, BLOCKSIZE, 1, fs->f) != 1) | ||
636 | + perror_msg_and_die("fread filesystem image superblock"); | ||
637 | if(swapit) | ||
638 | - swap_badfs(fs); | ||
639 | + swap_sb(fs->sb); | ||
640 | if(fs->sb->s_rev_level || (fs->sb->s_magic != EXT2_MAGIC_NUMBER)) | ||
641 | error_msg_and_die("not a suitable ext2 filesystem"); | ||
642 | fs->nheadblocks = (((GRP_NBGROUPS(fs) * sizeof(groupdescriptor)) | ||
643 | + sizeof(superblock) + (BLOCKSIZE - 1)) | ||
644 | / BLOCKSIZE); | ||
645 | + | ||
646 | + fs->gd = calloc(fs->nheadblocks - 1, BLOCKSIZE); | ||
647 | + if (!fs->gd) | ||
648 | + error_msg_and_die("error allocating header memory"); | ||
649 | + if (fread(fs->gd, BLOCKSIZE, fs->nheadblocks - 1, fs->f) | ||
650 | + != (fs->nheadblocks - 1)) | ||
651 | + perror_msg_and_die("fread filesystem image group descriptors"); | ||
652 | + | ||
653 | + if(swapit) | ||
654 | + swap_gds(fs); | ||
655 | + | ||
656 | + set_file_size(fs); | ||
657 | return fs; | ||
658 | } | ||
659 | |||
660 | @@ -2343,7 +2584,9 @@ static void | ||
661 | free_fs(filesystem *fs) | ||
662 | { | ||
663 | free(fs->hdlinks.hdl); | ||
664 | - free(fs->data); | ||
665 | + fclose(fs->f); | ||
666 | + free(fs->sb); | ||
667 | + free(fs->gd); | ||
668 | free(fs); | ||
669 | } | ||
670 | |||
671 | @@ -2631,16 +2874,30 @@ print_fs(filesystem *fs) | ||
672 | } | ||
673 | |||
674 | static void | ||
675 | -dump_fs(filesystem *fs, FILE * fh, int swapit) | ||
676 | -{ | ||
677 | - uint32 nbblocks = fs->sb->s_blocks_count; | ||
678 | +finish_fs(filesystem *fs) | ||
679 | +{ | ||
680 | + if (cache_flush(&fs->inodes)) | ||
681 | + error_msg_and_die("entry mismatch on inode cache flush"); | ||
682 | + if (cache_flush(&fs->blkmaps)) | ||
683 | + error_msg_and_die("entry mismatch on blockmap cache flush"); | ||
684 | + if (cache_flush(&fs->blks)) | ||
685 | + error_msg_and_die("entry mismatch on block cache flush"); | ||
686 | fs->sb->s_reserved[200] = 0; | ||
687 | - if(swapit) | ||
688 | - swap_goodfs(fs); | ||
689 | - if(fwrite(fs->data, BLOCKSIZE, nbblocks, fh) < nbblocks) | ||
690 | - perror_msg_and_die("output filesystem image"); | ||
691 | - if(swapit) | ||
692 | - swap_badfs(fs); | ||
693 | + if(fs->swapit) { | ||
694 | + swap_sb(fs->sb); | ||
695 | + swap_gds(fs); | ||
696 | + } | ||
697 | + if (fseek(fs->f, BLOCKSIZE, SEEK_SET)) | ||
698 | + perror_msg_and_die("fseek"); | ||
699 | + if(fwrite(fs->sb, BLOCKSIZE, 1, fs->f) != 1) | ||
700 | + perror_msg_and_die("output filesystem superblock"); | ||
701 | + if(fwrite(fs->gd, BLOCKSIZE, fs->nheadblocks - 1, fs->f) | ||
702 | + != (fs->nheadblocks - 1)) | ||
703 | + perror_msg_and_die("output filesystem group descriptors"); | ||
704 | + if(fs->swapit) { | ||
705 | + swap_sb(fs->sb); | ||
706 | + swap_gds(fs); | ||
707 | + } | ||
708 | } | ||
709 | |||
710 | static void | ||
711 | @@ -2851,11 +3108,11 @@ main(int argc, char **argv) | ||
712 | if(strcmp(fsin, "-")) | ||
713 | { | ||
714 | FILE * fh = xfopen(fsin, "rb"); | ||
715 | - fs = load_fs(fh, bigendian); | ||
716 | + fs = load_fs(fh, bigendian, fsout); | ||
717 | fclose(fh); | ||
718 | } | ||
719 | else | ||
720 | - fs = load_fs(stdin, bigendian); | ||
721 | + fs = load_fs(stdin, bigendian, fsout); | ||
722 | } | ||
723 | else | ||
724 | { | ||
725 | @@ -2886,7 +3143,7 @@ main(int argc, char **argv) | ||
726 | if(fs_timestamp == -1) | ||
727 | fs_timestamp = time(NULL); | ||
728 | fs = init_fs(nbblocks, nbinodes, nbresrvd, holes, fs_timestamp, | ||
729 | - bigendian); | ||
730 | + bigendian, fsout); | ||
731 | } | ||
732 | |||
733 | populate_fs(fs, dopt, didx, squash_uids, squash_perms, fs_timestamp, NULL); | ||
734 | @@ -2925,14 +3182,10 @@ main(int argc, char **argv) | ||
735 | flist_blocks(fs, nod, fh); | ||
736 | fclose(fh); | ||
737 | } | ||
738 | - if(strcmp(fsout, "-")) | ||
739 | - { | ||
740 | - FILE * fh = xfopen(fsout, "wb"); | ||
741 | - dump_fs(fs, fh, bigendian); | ||
742 | - fclose(fh); | ||
743 | - } | ||
744 | - else | ||
745 | - dump_fs(fs, stdout, bigendian); | ||
746 | + finish_fs(fs); | ||
747 | + if(strcmp(fsout, "-") == 0) | ||
748 | + copy_file(fs, stdout, fs->f, fs->sb->s_blocks_count); | ||
749 | + | ||
750 | free_fs(fs); | ||
751 | return 0; | ||
752 | } | ||
753 | diff --git a/list.h b/list.h | ||
754 | new file mode 100644 | ||
755 | index 0000000..52bb181 | ||
756 | --- /dev/null | ||
757 | +++ b/list.h | ||
758 | @@ -0,0 +1,78 @@ | ||
759 | +#ifndef __LIST_H__ | ||
760 | +#define __LIST_H__ | ||
761 | + | ||
762 | +#if STDC_HEADERS | ||
763 | +# include <stdlib.h> | ||
764 | +# include <stddef.h> | ||
765 | +#else | ||
766 | +# if HAVE_STDLIB_H | ||
767 | +# include <stdlib.h> | ||
768 | +# endif | ||
769 | +# if HAVE_STDDEF_H | ||
770 | +# include <stddef.h> | ||
771 | +# endif | ||
772 | +#endif | ||
773 | + | ||
774 | +#ifndef offsetof | ||
775 | +#define offsetof(st, m) \ | ||
776 | + ((size_t) ( (char *)&((st *)(0))->m - (char *)0 )) | ||
777 | +#endif | ||
778 | + | ||
779 | +#define container_of(ptr, type, member) ({ \ | ||
780 | + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ | ||
781 | + (type *)( (char *)__mptr - offsetof(type,member) );}) | ||
782 | + | ||
783 | +typedef struct list_elem | ||
784 | +{ | ||
785 | + struct list_elem *next; | ||
786 | + struct list_elem *prev; | ||
787 | +} list_elem; | ||
788 | + | ||
789 | +static inline void list_init(list_elem *list) | ||
790 | +{ | ||
791 | + list->next = list; | ||
792 | + list->prev = list; | ||
793 | +} | ||
794 | + | ||
795 | +static inline void list_add_after(list_elem *pos, list_elem *elem) | ||
796 | +{ | ||
797 | + elem->next = pos->next; | ||
798 | + elem->prev = pos; | ||
799 | + pos->next->prev = elem; | ||
800 | + pos->next = elem; | ||
801 | +} | ||
802 | + | ||
803 | +static inline void list_add_before(list_elem *pos, list_elem *elem) | ||
804 | +{ | ||
805 | + elem->prev = pos->prev; | ||
806 | + elem->next = pos; | ||
807 | + pos->prev->next = elem; | ||
808 | + pos->prev = elem; | ||
809 | +} | ||
810 | + | ||
811 | +static inline void list_del(list_elem *elem) | ||
812 | +{ | ||
813 | + elem->next->prev = elem->prev; | ||
814 | + elem->prev->next = elem->next; | ||
815 | +} | ||
816 | + | ||
817 | +static inline void list_item_init(list_elem *elem) | ||
818 | +{ | ||
819 | + elem->next = elem; | ||
820 | + elem->prev = elem; | ||
821 | +} | ||
822 | + | ||
823 | +static inline int list_empty(list_elem *elem) | ||
824 | +{ | ||
825 | + return elem->next == elem; | ||
826 | +} | ||
827 | + | ||
828 | +#define list_for_each_elem(list, curr) \ | ||
829 | + for ((curr) = (list)->next; (curr) != (list); (curr) = (curr)->next) | ||
830 | + | ||
831 | +#define list_for_each_elem_safe(list, curr, next) \ | ||
832 | + for ((curr) = (list)->next, (next) = (curr)->next; \ | ||
833 | + (curr) != (list); \ | ||
834 | + (curr) = (next), (next) = (curr)->next) | ||
835 | + | ||
836 | +#endif /* __LIST_H__ */ | ||
837 | -- | ||
838 | 1.7.4.1 | ||
839 | |||