Make e2fsck uninit block group aware.

This patch has all the necesary pieces to open and fix filesystems created
with the uninit block group feature.

Signed-off-by: Jose R. Santos <[EMAIL PROTECTED]>
Signed-Off-By: Andreas Dilger <[EMAIL PROTECTED]>
--

 e2fsck/e2fsck.h  |    2 +
 e2fsck/journal.c |    2 +
 e2fsck/pass2.c   |   77 ++++++++++++++++++++++++++++++++++++++++++++++++------
 e2fsck/pass5.c   |   61 +++++++++++++++++++++++++++++++------------
 e2fsck/problem.c |   42 +++++++++++++++++++++++++++++
 e2fsck/problem.h |   26 ++++++++++++++++++
 e2fsck/super.c   |   40 ++++++++++++++++++++++++++++
 e2fsck/unix.c    |   11 ++++++--
 e2fsck/util.c    |   61 +++++++++++++++++++++++++++++++++++++++++++
 9 files changed, 292 insertions(+), 30 deletions(-)

diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index 9ccffd8..a67322d 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -468,6 +468,8 @@ extern void e2fsck_read_bitmaps(e2fsck_t ctx);
 extern void e2fsck_write_bitmaps(e2fsck_t ctx);
 extern void preenhalt(e2fsck_t ctx);
 extern char *string_copy(e2fsck_t ctx, const char *str, int len);
+extern errcode_t e2fsck_zero_blocks(ext2_filsys fs, blk_t blk, int num,
+                                   blk_t *ret_blk, int *ret_count);
 #ifdef RESOURCE_TRACK
 extern void print_resource_track(const char *desc,
                                 struct resource_track *track,
diff --git a/e2fsck/journal.c b/e2fsck/journal.c
index f5f4647..ceade93 100644
--- a/e2fsck/journal.c
+++ b/e2fsck/journal.c
@@ -988,6 +988,8 @@ void e2fsck_move_ext3_journal(e2fsck_t ctx)
        ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
        ext2fs_mark_ib_dirty(fs);
        fs->group_desc[group].bg_free_inodes_count++;
+       fs->group_desc[group].bg_checksum =
+               ext2fs_group_desc_csum(fs->super, group,&fs->group_desc[group]);
        fs->super->s_free_inodes_count++;
        return;
 
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 27f7136..047b5ca 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -151,7 +151,7 @@ void e2fsck_pass2(e2fsck_t ctx)
        
        cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
                                                &cd);
-       if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+       if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
                return;
        if (cd.pctx.errcode) {
                fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
@@ -736,7 +736,7 @@ static int check_dir_block(ext2_filsys fs,
        buf = cd->buf;
        ctx = cd->ctx;
 
-       if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+       if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
                return DIRENT_ABORT;
        
        if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
@@ -833,6 +833,9 @@ static int check_dir_block(ext2_filsys fs,
        dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
        prev = 0;
        do {
+               int group;
+               ext2_ino_t first_unused_inode;
+
                problem = 0;
                dirent = (struct ext2_dir_entry *) (buf + offset);
                cd->pctx.dirent = dirent;
@@ -882,12 +885,6 @@ static int check_dir_block(ext2_filsys fs,
                     (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
                    (dirent->inode > fs->super->s_inodes_count)) {
                        problem = PR_2_BAD_INO;
-               } else if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
-                                              dirent->inode))) {
-                       /*
-                        * If the inode is unused, offer to clear it.
-                        */
-                       problem = PR_2_UNUSED_INODE;
                } else if (ctx->inode_bb_map &&
                           (ext2fs_test_inode_bitmap(ctx->inode_bb_map,
                                                     dirent->inode))) {
@@ -964,6 +961,67 @@ static int check_dir_block(ext2_filsys fs,
                                return DIRENT_ABORT;
                }
 
+               group = ext2fs_group_of_ino(fs, dirent->inode);
+               first_unused_inode = group * fs->super->s_inodes_per_group +
+                                       1 + fs->super->s_inodes_per_group -
+                                       fs->group_desc[group].bg_itable_unused;
+               cd->pctx.group = group;
+
+               /*
+                * Check if the inode was missed out because _INODE_UNINIT
+                * flag was set or bg_itable_unused was incorrect.
+                * If that is the case restart e2fsck.
+                * XXX Optimisations TODO:
+                * 1. only restart e2fsck once
+                * 2. only exposed inodes are checked again.
+                */
+               if (fs->group_desc[group].bg_flags & EXT2_BG_INODE_UNINIT) {
+                       if (fix_problem(ctx, PR_2_INOREF_BG_INO_UNINIT,
+                                       &cd->pctx)){
+                               fs->group_desc[group].bg_flags &=
+                                       ~EXT2_BG_INODE_UNINIT;
+                               ctx->flags |= E2F_FLAG_RESTART |
+                                       E2F_FLAG_SIGNAL_MASK;
+                       } else {
+                               ext2fs_unmark_valid(fs);
+                               if (problem == PR_2_BAD_INO)
+                                       goto next;
+                       }
+               } else if (dirent->inode >= first_unused_inode) {
+                       if (fix_problem(ctx, PR_2_INOREF_IN_UNUSED, &cd->pctx)){
+                               fs->group_desc[group].bg_itable_unused = 0;
+                               fs->group_desc[group].bg_flags &=
+                                       ~EXT2_BG_INODE_UNINIT;
+                               ext2fs_mark_super_dirty(fs);
+                               ctx->flags |= E2F_FLAG_RESTART;
+                               goto restart_fsck;
+                       } else {
+                               ext2fs_unmark_valid(fs);
+                               if (problem == PR_2_BAD_INO)
+                                       goto next;
+                       }
+               }
+
+               if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map,
+                                              dirent->inode))) {
+                       /*
+                        * If the inode is unused, offer to clear it.
+                        */
+                       problem = PR_2_UNUSED_INODE;
+               }
+
+               if (problem) {
+                       if (fix_problem(ctx, problem, &cd->pctx)) {
+                               dirent->inode = 0;
+                               dir_modified++;
+                               goto next;
+                       } else {
+                               ext2fs_unmark_valid(fs);
+                               if (problem == PR_2_BAD_INO)
+                                       goto next;
+                       }
+               }
+
                if (check_name(ctx, dirent, ino, &cd->pctx))
                        dir_modified++;
 
@@ -1073,8 +1131,9 @@ static int check_dir_block(ext2_filsys fs,
        dict_free_nodes(&de_dict);
        return 0;
 abort_free_dict:
-       dict_free_nodes(&de_dict);
        ctx->flags |= E2F_FLAG_ABORT;
+restart_fsck:
+       dict_free_nodes(&de_dict);
        return DIRENT_ABORT;
 }
 
diff --git a/e2fsck/pass5.c b/e2fsck/pass5.c
index 53248b0..1f1536b 100644
--- a/e2fsck/pass5.c
+++ b/e2fsck/pass5.c
@@ -121,7 +121,7 @@ static void check_block_bitmaps(e2fsck_t ctx)
        struct problem_context  pctx;
        int     problem, save_problem, fixit, had_problem;
        errcode_t       retval;
-       int             lazy_bg = 0;
+       int             lazy_flag, csum_flag;
        int             skip_group = 0;
 
        clear_problem_context(&pctx);
@@ -158,15 +158,16 @@ static void check_block_bitmaps(e2fsck_t ctx)
                goto errout;
        }
 
-       if (EXT2_HAS_COMPAT_FEATURE(fs->super, EXT2_FEATURE_COMPAT_LAZY_BG))
-               lazy_bg++;
-
+       lazy_flag = EXT2_HAS_COMPAT_FEATURE(fs->super,
+                                           EXT2_FEATURE_COMPAT_LAZY_BG);
+       csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                              EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
 redo_counts:
        had_problem = 0;
        save_problem = 0;
        pctx.blk = pctx.blk2 = NO_BLK;
-       if (lazy_bg && (fs->group_desc[group].bg_flags &
-                       EXT2_BG_BLOCK_UNINIT))
+       if ((lazy_flag || csum_flag) &&
+           (fs->group_desc[group].bg_flags & EXT2_BG_BLOCK_UNINIT))
                skip_group++;
        super = fs->super->s_first_data_block;
        for (i = fs->super->s_first_data_block;
@@ -206,6 +207,17 @@ redo_counts:
                         * Block used, but not marked in use in the bitmap.
                         */
                        problem = PR_5_BLOCK_USED;
+
+                       if (skip_group) {
+                               struct problem_context pctx2;
+                               pctx2.blk = i;
+                               pctx2.group = group;
+                               if (fix_problem(ctx, PR_5_BLOCK_UNINIT,&pctx2)){
+                                       fs->group_desc[group].bg_flags &=
+                                               ~EXT2_BG_BLOCK_UNINIT;
+                                       skip_group = 0;
+                               }
+                       }
                }
                if (pctx.blk == NO_BLK) {
                        pctx.blk = pctx.blk2 = i;
@@ -224,7 +236,7 @@ redo_counts:
                had_problem++;
 
        do_counts:
-               if (!bitmap && !skip_group) {
+               if (!bitmap && (!skip_group || csum_flag)) {
                        group_free++;
                        free_blocks++;
                }
@@ -241,7 +253,7 @@ redo_counts:
                                if ((ctx->progress)(ctx, 5, group,
                                                    fs->group_desc_count*2))
                                        goto errout;
-                       if (lazy_bg &&
+                       if ((lazy_flag || csum_flag) &&
                            (i != fs->super->s_blocks_count-1) &&
                            (fs->group_desc[group].bg_flags &
                             EXT2_BG_BLOCK_UNINIT))
@@ -321,7 +333,7 @@ static void check_inode_bitmaps(e2fsck_t ctx)
        errcode_t       retval;
        struct problem_context  pctx;
        int             problem, save_problem, fixit, had_problem;
-       int             lazy_bg = 0;
+       int             lazy_flag, csum_flag;
        int             skip_group = 0;
 
        clear_problem_context(&pctx);
@@ -358,16 +370,16 @@ static void check_inode_bitmaps(e2fsck_t ctx)
                goto errout;
        }
 
-       if (EXT2_HAS_COMPAT_FEATURE(fs->super,
-                                   EXT2_FEATURE_COMPAT_LAZY_BG))
-               lazy_bg++;
-
+       lazy_flag = EXT2_HAS_COMPAT_FEATURE(fs->super,
+                                           EXT2_FEATURE_COMPAT_LAZY_BG);
+       csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                              EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
 redo_counts:
        had_problem = 0;
        save_problem = 0;
        pctx.ino = pctx.ino2 = 0;
-       if (lazy_bg && (fs->group_desc[group].bg_flags &
-                       EXT2_BG_INODE_UNINIT))
+       if ((lazy_flag || csum_flag) &&
+           (fs->group_desc[group].bg_flags & EXT2_BG_INODE_UNINIT))
                skip_group++;
 
        /* Protect loop from wrap-around if inodes_count is maxed */
@@ -390,6 +402,21 @@ redo_counts:
                         * Inode used, but not in bitmap
                         */
                        problem = PR_5_INODE_USED;
+
+                       /* We should never hit this, because it means that
+                        * inodes were marked in use that weren't noticed
+                        * in pass1 or pass 2. It is easier to fix the problem
+                        * than to kill e2fsck and leave the user stuck. */
+                       if (skip_group) {
+                               struct problem_context pctx2;
+                               pctx2.blk = i;
+                               pctx2.group = group;
+                               if (fix_problem(ctx, PR_5_INODE_UNINIT,&pctx2)){
+                                       fs->group_desc[group].bg_flags &=
+                                               ~EXT2_BG_INODE_UNINIT;
+                                       skip_group = 0;
+                               }
+                       }
                }
                if (pctx.ino == 0) {
                        pctx.ino = pctx.ino2 = i;
@@ -411,7 +438,7 @@ do_counts:
                if (bitmap) {
                        if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
                                dirs_count++;
-               } else if (!skip_group) {
+               } else if (!skip_group || csum_flag) {
                        group_free++;
                        free_inodes++;
                }
@@ -430,7 +457,7 @@ do_counts:
                                            group + fs->group_desc_count,
                                            fs->group_desc_count*2))
                                        goto errout;
-                       if (lazy_bg &&
+                       if ((lazy_flag || csum_flag) &&
                            (i != fs->super->s_inodes_count) &&
                            (fs->group_desc[group].bg_flags &
                             EXT2_BG_INODE_UNINIT))
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index 7c3ebea..6fc811c 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -351,8 +351,28 @@ static struct e2fsck_problem problem_table[] = {
          N_("Adding dirhash hint to @f.\n\n"),
          PROMPT_NONE, 0 },
 
+       /* group descriptor N checksum is invalid. */
+       { PR_0_GDT_CSUM,
+         N_("@g descriptor %g checksum is invalid.  "),
+            PROMPT_FIX, PR_PREEN_OK },
+
+       /* group descriptor N marked uninitialized without feature set. */
+       { PR_0_GDT_UNINIT,
+         N_("@g descriptor %g marked uninitialized without feature set.\n"),
+            PROMPT_FIX, PR_PREEN_OK },
+
+       /* group N block bitmap uninitialized but inode bitmap in use. */
+       { PR_0_BB_UNINIT_IB_INIT,
+         N_("@g %g @b @B uninitialized but @i @B in use.\n"),
+            PROMPT_FIX, PR_PREEN_OK },
+
+       /* Group descriptor N has invalid unused inodes count. */
+       { PR_0_GDT_ITABLE_UNUSED,
+         N_("@g descriptor %g has invalid unused inodes count %b.  "),
+            PROMPT_FIX, PR_PREEN_OK },
+
        /* Pass 1 errors */
-       
+
        /* Pass 1: Checking inodes, blocks, and sizes */
        { PR_1_PASS_HEADER,
          N_("Pass 1: Checking @is, @bs, and sizes\n"),
@@ -1188,6 +1208,16 @@ static struct e2fsck_problem problem_table[] = {
          N_("i_blocks_hi @F %N, @s zero.\n"),
          PROMPT_CLEAR, 0 },
 
+       /* Inode found in group where _INODE_UNINIT is set */
+       { PR_2_INOREF_BG_INO_UNINIT,
+         N_("@i %i found in @g %g where _INODE_UNINIT is set.  "),
+         PROMPT_FIX, PR_PREEN_OK },
+
+       /* Inode found in group unused inodes area */
+       { PR_2_INOREF_IN_UNUSED,
+         N_("@i %i found in @g %g unused inodes area.  "),
+         PROMPT_FIX, PR_PREEN_OK },
+
        /* Pass 3 errors */
 
        /* Pass 3: Checking directory connectivity */
@@ -1499,6 +1529,16 @@ static struct e2fsck_problem problem_table[] = {
          N_("Recreate journal to make the filesystem ext3 again?\n"),
          PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
 
+       /* Group N block(s) in use but group is marked BLOCK_UNINIT */
+       { PR_5_BLOCK_UNINIT,
+         N_("@g %g @b(s) in use but @g is marked BLOCK_UNINIT\n"),
+         PROMPT_FIX, PR_PREEN_OK },
+
+       /* Group N inode(s) in use but group is marked INODE_UNINIT */
+       { PR_5_INODE_UNINIT,
+         N_("@g %g @i(s) in use but @g is marked INODE_UNINIT\n"),
+         PROMPT_FIX, PR_PREEN_OK },
+
        { 0 }
 };
 
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index f5f7212..8ec9ee5 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -196,6 +196,18 @@ struct problem_context {
 /* Superblock hint for external journal incorrect */
 #define PR_0_DIRHASH_HINT                      0x000034
 
+/* Group descriptor N checksum is invalid */
+#define PR_0_GDT_CSUM                          0x000035
+
+/* Group descriptor N marked uninitialized without feature set. */
+#define PR_0_GDT_UNINIT                                0x000036
+
+/* Block bitmap is not initialised and Inode bitmap is */
+#define PR_0_BB_UNINIT_IB_INIT                 0x000037
+
+/* Group descriptor N has invalid unused inodes count. */
+#define PR_0_GDT_ITABLE_UNUSED                 0x000038
+
 /*
  * Pass 1 errors
  */
@@ -708,6 +720,12 @@ struct problem_context {
 /* i_blocks_hi should be zero */
 #define PR_2_BLOCKS_HI_ZERO    0x020044
 
+/* Inode found in group where _INODE_UNINIT is set */
+#define PR_2_INOREF_BG_INO_UNINIT      0x020045
+
+/* Inode found in group unused inodes area */
+#define PR_2_INOREF_IN_UNUSED          0x020046
+
 /*
  * Pass 3 errors
  */
@@ -896,10 +914,16 @@ struct problem_context {
 
 /* Inode range not used, but marked in bitmap */
 #define PR_5_INODE_RANGE_UNUSED                0x050016
-         
+
 /* Inode rangeused, but not marked used in bitmap */
 #define PR_5_INODE_RANGE_USED          0x050017
 
+/* Block in use but group is marked BLOCK_UNINIT */
+#define PR_5_BLOCK_UNINIT              0x050018
+
+/* Inode in use but group is marked INODE_UNINIT */
+#define PR_5_INODE_UNINIT              0x050019
+
 /*
  * Post-Pass 5 errors
  */
diff --git a/e2fsck/super.c b/e2fsck/super.c
index a4835f7..6b39a65 100644
--- a/e2fsck/super.c
+++ b/e2fsck/super.c
@@ -468,6 +468,7 @@ void check_super_block(e2fsck_t ctx)
        blk_t   should_be;
        struct problem_context  pctx;
        __u32   free_blocks = 0, free_inodes = 0;
+       int     lazy_flag, csum_flag;
 
        inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super);
        ipg_max = inodes_per_block * (blocks_per_group - 4);
@@ -576,6 +577,10 @@ void check_super_block(e2fsck_t ctx)
         */
        first_block =  sb->s_first_data_block;
 
+       lazy_flag = EXT2_HAS_COMPAT_FEATURE(fs->super,
+                                           EXT2_FEATURE_COMPAT_LAZY_BG);
+       csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                              EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
        for (i = 0, gd=fs->group_desc; i < fs->group_desc_count; i++, gd++) {
                pctx.group = i;
 
@@ -621,6 +626,41 @@ void check_super_block(e2fsck_t ctx)
                    (gd->bg_used_dirs_count > sb->s_inodes_per_group))
                        ext2fs_unmark_valid(fs);
 
+               if (!ext2fs_group_desc_csum_verify(sb, i, gd)) {
+                       if (fix_problem(ctx, PR_0_GDT_CSUM, &pctx)) {
+                               gd->bg_flags &= ~(EXT2_BG_BLOCK_UNINIT |
+                                                 EXT2_BG_INODE_UNINIT);
+                               gd->bg_itable_unused = 0;
+                       }
+                       ext2fs_unmark_valid(fs);
+               }
+
+               if (!lazy_flag && !csum_flag &&
+                   (gd->bg_flags &(EXT2_BG_BLOCK_UNINIT|EXT2_BG_INODE_UNINIT)||
+                    gd->bg_itable_unused != 0)){
+                       if (fix_problem(ctx, PR_0_GDT_UNINIT, &pctx)) {
+                               gd->bg_flags &= ~(EXT2_BG_BLOCK_UNINIT |
+                                                 EXT2_BG_INODE_UNINIT);
+                               gd->bg_itable_unused = 0;
+                       }
+                       ext2fs_unmark_valid(fs);
+               }
+               if (gd->bg_flags & EXT2_BG_BLOCK_UNINIT &&
+                   !(gd->bg_flags & EXT2_BG_INODE_UNINIT)) {
+                       if (fix_problem(ctx, PR_0_BB_UNINIT_IB_INIT, &pctx))
+                               gd->bg_flags &= ~EXT2_BG_BLOCK_UNINIT;
+                       ext2fs_unmark_valid(fs);
+               }
+               if (csum_flag &&
+                   (gd->bg_itable_unused > gd->bg_free_inodes_count ||
+                    gd->bg_itable_unused > sb->s_inodes_per_group)) {
+                       pctx.blk = gd->bg_itable_unused;
+                       if (fix_problem(ctx, PR_0_GDT_ITABLE_UNUSED, &pctx))
+                               gd->bg_itable_unused = 0;
+                       ext2fs_unmark_valid(fs);
+               }
+
+               gd->bg_checksum = ext2fs_group_desc_csum(fs->super, i, gd);
        }
 
        /*
diff --git a/e2fsck/unix.c b/e2fsck/unix.c
index 291ff85..596c650 100644
--- a/e2fsck/unix.c
+++ b/e2fsck/unix.c
@@ -558,7 +558,9 @@ static void parse_extended_opts(e2fsck_t ctx, const char 
*opts)
                       "and may take an argument which\n"
                       "is set off by an equals ('=') sign.  "
                        "Valid extended options are:\n"
-                      "\tea_ver=<ea_version (1 or 2)>\n\n"), stderr);
+                       "\tea_ver=<ea_version (1 or 2)>\n"
+                       "\tuninit_groups\n"
+                       "\tinit_groups\n\n"), stderr);
                exit(1);
        }
 }
@@ -745,6 +747,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t 
*ret_ctx)
        if ((ctx->options & E2F_OPT_NO) && !bad_blocks_file &&
            !cflag && !(ctx->options & E2F_OPT_COMPRESS_DIRS))
                ctx->options |= E2F_OPT_READONLY;
+
        ctx->io_options = strchr(argv[optind], '?');
        if (ctx->io_options) 
                *ctx->io_options++ = 0;
@@ -842,7 +845,7 @@ sscanf_err:
 
 static const char *my_ver_string = E2FSPROGS_VERSION;
 static const char *my_ver_date = E2FSPROGS_DATE;
-                                       
+
 int main (int argc, char *argv[])
 {
        errcode_t       retval = 0, orig_retval = 0;
@@ -1306,6 +1309,10 @@ no_journal:
                }
        }
 
+       if (sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM &&
+           !(ctx->options & E2F_OPT_READONLY))
+               ext2fs_set_gdt_csum(ctx->fs);
+
        e2fsck_write_bitmaps(ctx);
 #ifdef RESOURCE_TRACK
        io_channel_flush(ctx->fs->io);
diff --git a/e2fsck/util.c b/e2fsck/util.c
index ba7ef4a..751ad78 100644
--- a/e2fsck/util.c
+++ b/e2fsck/util.c
@@ -29,6 +29,10 @@
 #include <malloc.h>
 #endif
 
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
 #include "e2fsck.h"
 
 extern e2fsck_t e2fsck_global_ctx;   /* Try your very best not to use this! */
@@ -532,3 +536,60 @@ int ext2_file_type(unsigned int mode)
        
        return 0;
 }
+
+#define STRIDE_LENGTH 8
+/*
+ * Helper function which zeros out _num_ blocks starting at _blk_.  In
+ * case of an error, the details of the error is returned via _ret_blk_
+ * and _ret_count_ if they are non-NULL pointers.  Returns 0 on
+ * success, and an error code on an error.
+ *
+ * As a special case, if the first argument is NULL, then it will
+ * attempt to free the static zeroizing buffer.  (This is to keep
+ * programs that check for memory leaks happy.)
+ */
+errcode_t e2fsck_zero_blocks(ext2_filsys fs, blk_t blk, int num,
+                            blk_t *ret_blk, int *ret_count)
+{
+       int             j, count, next_update, next_update_incr;
+       static char     *buf;
+       errcode_t       retval;
+
+       /* If fs is null, clean up the static buffer and return */
+       if (!fs) {
+               if (buf) {
+                       free(buf);
+                       buf = 0;
+               }
+               return 0;
+       }
+       /* Allocate the zeroizing buffer if necessary */
+       if (!buf) {
+               buf = malloc(fs->blocksize * STRIDE_LENGTH);
+               if (!buf) {
+                       com_err("malloc", ENOMEM,
+                               _("while allocating zeroizing buffer"));
+                       exit(1);
+               }
+               memset(buf, 0, fs->blocksize * STRIDE_LENGTH);
+       }
+       /* OK, do the write loop */
+       next_update = 0;
+       next_update_incr = num / 100;
+       if (next_update_incr < 1)
+               next_update_incr = 1;
+       for (j = 0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) {
+               count = num - j;
+               if (count > STRIDE_LENGTH)
+                       count = STRIDE_LENGTH;
+               retval = io_channel_write_blk(fs->io, blk, count, buf);
+               if (retval) {
+                       if (ret_count)
+                               *ret_count = count;
+                       if (ret_blk)
+                               *ret_blk = blk;
+                       return retval;
+               }
+       }
+       return 0;
+}
-
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to