summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/genext2fs/genext2fs-1.4.1/0010-Convert-over-to-keeping-the-filesystem-on-disk.patch
diff options
context:
space:
mode:
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.patch839
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 @@
1Upstream-Status: inappropriate
2
3From 29a36b0b91ee009ee4219934c7a70278b1361834 Mon Sep 17 00:00:00 2001
4From: Corey Minyard <cminyard@mvista.com>
5Date: Sun, 5 Jun 2011 15:24:57 -0500
6Subject: [PATCH 10/19] Convert over to keeping the filesystem on disk
7
8This makes the actual filesystem be on disk and not in memory. It
9adds caching of the filesystem data to help keep oft-accessed blocks
10in 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
19diff --git a/cache.h b/cache.h
20new file mode 100644
21index 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__ */
153diff --git a/genext2fs.c b/genext2fs.c
154index 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 }
753diff --git a/list.h b/list.h
754new file mode 100644
755index 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--
8381.7.4.1
839