Whamcloud - gitweb
ChangeLog, dir_iterate.c:
[tools/e2fsprogs.git] / e2fsck / pass1b.c
index b3bc833..df787e8 100644 (file)
  * (so that the file gets a fresh copy of the duplicated blocks) or
  * simply to delete the file.
  * 
- * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
- * redistributed under the terms of the GNU Public License.
+ * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
  * 
  */
 
@@ -31,6 +35,8 @@
 #include <et/com_err.h>
 #include "e2fsck.h"
 
+#include "problem.h"
+
 /*
  * This is structure is allocated for each time that a block is
  * claimed by more than one file.  So if a particular block is claimed
@@ -75,24 +81,20 @@ struct dup_block {
  * of multiply-claimed blocks.
  */
 struct dup_inode {
-       ino_t           ino;
-       time_t          mtime;
-       char            *pathname;
-       int             num_dupblocks;
-       int             flags;
+       ino_t                   ino, dir;
+       int                     num_dupblocks;
+       struct ext2_inode       inode;
        struct dup_inode        *next;
 };
 
-#define DUP_INODE_DONT_FREE_PATHNAME   0x1
-
 static int process_pass1b_block(ext2_filsys fs, blk_t  *blocknr,
-                               int     blockcnt, void  *private);
-static void delete_file(ext2_filsys fs, struct dup_inode *dp,
+                               int     blockcnt, void  *priv_data);
+static void delete_file(e2fsck_t ctx, struct dup_inode *dp,
                        char *block_buf);
-static int clone_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf);
-static void pass1b(ext2_filsys fs, char *block_buf);
-static void pass1c(ext2_filsys fs, char *block_buf);
-static void pass1d(ext2_filsys fs, char *block_buf);
+static int clone_file(e2fsck_t ctx, struct dup_inode *dp, char* block_buf);
+static void pass1b(e2fsck_t ctx, char *block_buf);
+static void pass1c(e2fsck_t ctx, char *block_buf);
+static void pass1d(e2fsck_t ctx, char *block_buf);
 
 static struct dup_block *dup_blk = 0;
 static struct dup_inode *dup_ino = 0;
@@ -103,42 +105,43 @@ static ext2fs_inode_bitmap inode_dup_map;
 /*
  * Main procedure for handling duplicate blocks
  */
-void pass1_dupblocks(ext2_filsys fs, char *block_buf)
+void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf)
 {
-       errcode_t               retval;
+       ext2_filsys             fs = ctx->fs;
        struct dup_block        *p, *q, *next_p, *next_q;
        struct dup_inode        *r, *next_r;
+       struct problem_context  pctx;
+
+       clear_problem_context(&pctx);
        
-       retval = ext2fs_allocate_inode_bitmap(fs,
+       pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
                      "multiply claimed inode map", &inode_dup_map);
-       if (retval) {
-               com_err("ext2fs_allocate_inode_bitmap", retval,
-                       "while allocating inode_dup_map");
-               fatal_error(0);
+       if (pctx.errcode) {
+               fix_problem(ctx, PR_1B_ALLOCATE_IBITMAP_ERROR, &pctx);
+               ctx->flags |= E2F_FLAG_ABORT;
+               return;
        }
        
-       pass1b(fs, block_buf);
-       pass1c(fs, block_buf);
-       pass1d(fs, block_buf);
+       pass1b(ctx, block_buf);
+       pass1c(ctx, block_buf);
+       pass1d(ctx, block_buf);
 
        /*
         * Time to free all of the accumulated data structures that we
         * don't need anymore.
         */
-       ext2fs_free_inode_bitmap(inode_dup_map);        inode_dup_map = 0;
-       ext2fs_free_block_bitmap(block_dup_map);    block_dup_map = 0;
+       ext2fs_free_inode_bitmap(inode_dup_map); inode_dup_map = 0;
+       ext2fs_free_block_bitmap(ctx->block_dup_map); ctx->block_dup_map = 0;
        for (p = dup_blk; p; p = next_p) {
                next_p = p->next_block;
                for (q = p; q; q = next_q) {
                        next_q = q->next_inode;
-                       free(q);
+                       ext2fs_free_mem((void **) &q);
                }
        }
        for (r = dup_ino; r; r = next_r) {
                next_r = r->next;
-               if (r->pathname && !(r->flags & DUP_INODE_DONT_FREE_PATHNAME))
-                       free(r->pathname);
-               free(r);
+               ext2fs_free_mem((void **) &r);
        }
 }
 
@@ -148,35 +151,45 @@ void pass1_dupblocks(ext2_filsys fs, char *block_buf)
 struct process_block_struct {
        ino_t   ino;
        int     dup_blocks;
+       e2fsck_t ctx;
+       struct problem_context *pctx;
 };
 
-void pass1b(ext2_filsys fs, char *block_buf)
+static void pass1b(e2fsck_t ctx, char *block_buf)
 {
+       ext2_filsys fs = ctx->fs;
        ino_t   ino;
        struct ext2_inode inode;
        ext2_inode_scan scan;
        errcode_t       retval;
        struct process_block_struct pb;
        struct dup_inode *dp;
+       struct problem_context pctx;
+
+       clear_problem_context(&pctx);
        
-       printf("Duplicate blocks found... invoking duplicate block passes.\n");
-       printf("Pass 1B: Rescan for duplicate/bad blocks\n");
-       retval = ext2fs_open_inode_scan(fs, inode_buffer_blocks, &scan);
-       if (retval) {
-               com_err(program_name, retval, "while opening inode scan");
-               fatal_error(0);
+       fix_problem(ctx, PR_1B_PASS_HEADER, &pctx);
+       pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
+                                             &scan);
+       if (pctx.errcode) {
+               fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
+               ctx->flags |= E2F_FLAG_ABORT;
+               return;
        }
-       retval = ext2fs_get_next_inode(scan, &ino, &inode);
-       if (retval) {
-               com_err(program_name, retval, "while starting inode scan");
-               fatal_error(0);
+       pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
+       if (pctx.errcode) {
+               fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
+               ctx->flags |= E2F_FLAG_ABORT;
+               return;
        }
-       stashed_inode = &inode;
+       ctx->stashed_inode = &inode;
+       pb.ctx = ctx;
+       pb.pctx = &pctx;
        while (ino) {
-               stashed_ino = ino;
+               pctx.ino = ctx->stashed_ino = ino;
                if ((ino != EXT2_BAD_INO) &&
-                   (!ext2fs_test_inode_bitmap(inode_used_map, ino) ||
-                    !inode_has_valid_blocks(&inode)))
+                   (!ext2fs_test_inode_bitmap(ctx->inode_used_map, ino) ||
+                    !ext2fs_inode_has_valid_blocks(&inode)))
                        goto next;
 
                pb.ino = ino;
@@ -184,30 +197,31 @@ void pass1b(ext2_filsys fs, char *block_buf)
                retval = ext2fs_block_iterate(fs, ino, 0, block_buf,
                                              process_pass1b_block, &pb);
                if (pb.dup_blocks) {
-                       if (ino != EXT2_BAD_INO)
-                               printf("\n");
-                       dp = allocate_memory(sizeof(struct dup_inode),
-                                            "duplicate inode record");
+                       end_problem_latch(ctx, PR_LATCH_DBLOCK);
+                       dp = (struct dup_inode *) e2fsck_allocate_memory(ctx,
+                                   sizeof(struct dup_inode),
+                                   "duplicate inode record");
                        dp->ino = ino;
-                       dp->mtime = inode.i_mtime;
+                       dp->dir = 0;
+                       dp->inode = inode;
                        dp->num_dupblocks = pb.dup_blocks;
-                       dp->pathname = 0;
-                       dp->flags = 0;
                        dp->next = dup_ino;
                        dup_ino = dp;
                        if (ino != EXT2_BAD_INO)
                                dup_inode_count++;
                }
                if (retval)
-                       com_err(program_name, retval,
+                       com_err(ctx->program_name, retval,
                                "while calling ext2fs_block_iterate in pass1b");
                
        next:
-               retval = ext2fs_get_next_inode(scan, &ino, &inode);
-               if (retval) {
-                       com_err(program_name, retval,
-                               "while doing inode scan");
-                       fatal_error(0);
+               pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
+               if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
+                       goto next;
+               if (pctx.errcode) {
+                       fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
+                       ctx->flags |= E2F_FLAG_ABORT;
+                       return;
                }
        }
        ext2fs_close_inode_scan(scan);
@@ -218,29 +232,30 @@ void pass1b(ext2_filsys fs, char *block_buf)
 int process_pass1b_block(ext2_filsys fs,
                         blk_t  *block_nr,
                         int blockcnt,
-                        void *private)
+                        void *priv_data)
 {
        struct process_block_struct *p;
        struct dup_block *dp, *q, *r;
        int i;
+       e2fsck_t ctx;
 
        if (!*block_nr)
                return 0;
-       p = (struct process_block_struct *) private;
+       p = (struct process_block_struct *) priv_data;
+       ctx = p->ctx;
        
-       if (ext2fs_test_block_bitmap(block_dup_map, *block_nr)) {
+       if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
                /* OK, this is a duplicate block */
                if (p->ino != EXT2_BAD_INO) {
-                       if (!p->dup_blocks)
-                               printf("Duplicate/bad block(s) in inode %lu:",
-                                      p->ino);
-                       printf(" %u", *block_nr);
+                       p->pctx->blk = *block_nr;
+                       fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx);
                }
                p->dup_blocks++;
-               ext2fs_mark_block_bitmap(block_dup_map, *block_nr);
+               ext2fs_mark_block_bitmap(ctx->block_dup_map, *block_nr);
                ext2fs_mark_inode_bitmap(inode_dup_map, p->ino);
-               dp = allocate_memory(sizeof(struct dup_block),
-                                     "duplicate block record");
+               dp = (struct dup_block *) e2fsck_allocate_memory(ctx,
+                                           sizeof(struct dup_block),
+                                           "duplicate block record");
                dp->block = *block_nr;
                dp->ino = p->ino;
                dp->num_bad = 0;
@@ -271,132 +286,106 @@ int process_pass1b_block(ext2_filsys fs,
 }
 
 /*
- * Used by pass1c to name the "special" inodes.  They are declared as
- * writeable strings to prevent const problems.
- */
-#define num_special_inodes     7
-char special_inode_name[num_special_inodes][40] =
-{
-       "<The NULL inode>",                     /* 0 */
-       "<The bad blocks inode>",               /* 1 */
-       "/",                                    /* 2 */
-       "<The ACL index inode>",                /* 3 */
-       "<The ACL data inode>",                 /* 4 */
-       "<The boot loader inode>",              /* 5 */
-       "<The undelete directory inode>"        /* 6 */
-};
-
-/*
  * Pass 1c: Scan directories for inodes with duplicate blocks.  This
  * is used so that we can print pathnames when prompting the user for
  * what to do.
  */
-struct process_dir_struct {
-       ext2_filsys     fs;
-       ino_t           dir_ino;
+struct search_dir_struct {
        int             count;
+       ino_t           first_inode;
+       ino_t           max_inode;
 };
 
-void pass1c(ext2_filsys fs, char *block_buf)
+static int search_dirent_proc(ino_t dir, int entry,
+                             struct ext2_dir_entry *dirent,
+                             int offset, int blocksize,
+                             char *buf, void *priv_data)
 {
-       int     i;
+       struct search_dir_struct *sd;
+       struct dup_inode        *p;
+
+       sd = (struct search_dir_struct *) priv_data;
+
+       if (dirent->inode > sd->max_inode)
+               /* Should abort this inode, but not everything */
+               return 0;       
+
+       if (!dirent->inode || (entry < DIRENT_OTHER_FILE) ||
+           !ext2fs_test_inode_bitmap(inode_dup_map, dirent->inode))
+               return 0;
+
+       for (p = dup_ino; p; p = p->next) {
+               if ((p->ino >= sd->first_inode) && 
+                   (p->ino == dirent->inode))
+                       break;
+       }
+
+       if (!p || p->dir)
+               return 0;
+
+       p->dir = dir;
+       sd->count--;
+
+       return(sd->count ? 0 : DIRENT_ABORT);
+}
+
+
+static void pass1c(e2fsck_t ctx, char *block_buf)
+{
+       ext2_filsys fs = ctx->fs;
        struct dup_inode        *p;
-       errcode_t       retval;
-       char    buf[80];
        int     inodes_left = dup_inode_count;
-       int     offset, entry;
-       struct ext2_dir_entry *dirent;
+       struct search_dir_struct sd;
+       struct problem_context pctx;
 
-       printf("Pass 1C: Scan directories for inodes with dup blocks.\n");
+       clear_problem_context(&pctx);
+
+       fix_problem(ctx, PR_1C_PASS_HEADER, &pctx);
 
        /*
         * First check to see if any of the inodes with dup blocks is
-        * the bad block inode or the root inode; handle them as
-        * special cases.
+        * a special inode.  (Note that the bad block inode isn't
+        * counted.)
         */
        for (p = dup_ino; p; p = p->next) {
-               if (p->ino < num_special_inodes) {
-                       p->pathname = special_inode_name[p->ino];
-                       p->flags |= DUP_INODE_DONT_FREE_PATHNAME;
+               if ((p->ino < EXT2_FIRST_INODE(fs->super)) &&
+                   (p->ino != EXT2_BAD_INO))
                        inodes_left--;
-               }
        }
 
        /*
         * Search through all directories to translate inodes to names
         * (by searching for the containing directory for that inode.)
         */
-       for (i=0; inodes_left && i < dir_block_count; i++) {
-               retval = ext2fs_read_dir_block(fs, dir_blocks[i].blk,
-                                              block_buf);
-               entry = offset = 0;
-               while (offset < fs->blocksize) {
-                       entry++;
-                       dirent = (struct ext2_dir_entry *)
-                               (block_buf + offset);
-                       if (!dirent->inode ||
-                           ((dir_blocks[i].blockcnt == 0) && (entry <= 2)))
-                               goto next;
-
-                       if (!ext2fs_test_inode_bitmap(inode_dup_map,
-                                                     dirent->inode))
-                               goto next;
-
-                       for (p = dup_ino; p; p = p->next) {
-                               if (p->ino == dirent->inode)
-                                       break;
-                       }
-
-                       if (!p || p->pathname)
-                               goto next;
-                       
-                       (void) ext2fs_get_pathname(fs, dir_blocks[i].ino,
-                                                  p->ino, &p->pathname);
-                       inodes_left--;
-                       
-               next:
-                       if (dirent->rec_len < 8)
-                               break;
-                       offset += dirent->rec_len;
-               }
-       }
-
-
-       /*
-        * If we can't get a name, then put in a generic one.
-        */
-       for (p = dup_ino; p; p = p->next) {
-               if (!p->pathname) {
-                       sprintf(buf, "<Unknown inode #%lu>", p->ino);
-                       p->pathname = malloc(strlen(buf)+1);
-                       if (!p->pathname) {
-                               fprintf(stderr, "pass1c: couldn't malloc "
-                                       "generic pathname\n");
-                               fatal_error(0);
-                       }
-                       strcpy(p->pathname, buf);
-               }
-       }
+       sd.count = inodes_left;
+       sd.first_inode = EXT2_FIRST_INODE(fs->super);
+       sd.max_inode = fs->super->s_inodes_count;
+       ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf,
+                                 search_dirent_proc, &sd);
 }      
 
-static void pass1d(ext2_filsys fs, char *block_buf)
+static void pass1d(e2fsck_t ctx, char *block_buf)
 {
+       ext2_filsys fs = ctx->fs;
        struct dup_inode        *p, *s;
        struct dup_block        *q, *r;
        ino_t   *shared;
        int     shared_len;
        int     i;
-       errcode_t       retval;
-       char    *time_str;
        int     file_ok;
-       
-       printf("Pass 1D: Reconciling duplicate blocks\n");
-       read_bitmaps(fs);
+       int     meta_data = 0;
+       struct problem_context pctx;
 
-       printf("(There are %d inodes containing duplicate/bad blocks.)\n\n",
-              dup_inode_count);
-       shared = allocate_memory(sizeof(ino_t) * dup_inode_count,
-                                "Shared inode list");
+       clear_problem_context(&pctx);
+       
+       fix_problem(ctx, PR_1D_PASS_HEADER, &pctx);
+       e2fsck_read_bitmaps(ctx);
+
+       pctx.num = dup_inode_count;
+       fix_problem(ctx, PR_1D_NUM_DUP_INODES, &pctx);
+       shared = (ino_t *) e2fsck_allocate_memory(ctx,
+                               sizeof(ino_t) * dup_inode_count,
+                               "Shared inode list");
        for (p = dup_ino; p; p = p->next) {
                shared_len = 0;
                file_ok = 1;
@@ -419,6 +408,12 @@ static void pass1d(ext2_filsys fs, char *block_buf)
                                continue;
                        if (q->num_bad > 1)
                                file_ok = 0;
+                       if (ext2fs_test_block_bitmap(ctx->block_illegal_map,
+                                                    q->block)) {
+                               file_ok = 0;
+                               meta_data = 1;
+                       }
+                       
                        /*
                         * Add all inodes used by this block to the
                         * shared[] --- which is a unique list, so
@@ -436,87 +431,101 @@ static void pass1d(ext2_filsys fs, char *block_buf)
                                }
                        }
                }
-               time_str = ctime(&p->mtime);
-               time_str[24] = 0;
-               printf("File %s (inode #%lu, mod time %s) \n",
-                      p->pathname, p->ino, time_str);
-               printf("  has %d duplicate blocks, shared with %d file%s:\n",
-                      p->num_dupblocks, shared_len,
-                      (shared_len>1) ? "s" : "");
+
+               /*
+                * Report the inode that we are working on
+                */
+               pctx.inode = &p->inode;
+               pctx.ino = p->ino;
+               pctx.dir = p->dir;
+               pctx.blkcount = p->num_dupblocks;
+               pctx.num = meta_data ? shared_len+1 : shared_len;
+               fix_problem(ctx, PR_1D_DUP_FILE, &pctx);
+               pctx.blkcount = 0;
+               pctx.num = 0;
+               
+               if (meta_data)
+                       fix_problem(ctx, PR_1D_SHARE_METADATA, &pctx);
+               
                for (i = 0; i < shared_len; i++) {
                        for (s = dup_ino; s; s = s->next)
                                if (s->ino == shared[i])
                                        break;
                        if (!s)
                                continue;
-                       time_str = ctime(&s->mtime);
-                       time_str[24] = 0;
-                       printf("\t%s (inode #%lu, mod time %s)\n",
-                              s->pathname, s->ino, time_str);
+                       /*
+                        * Report the inode that we are sharing with
+                        */
+                       pctx.inode = &s->inode;
+                       pctx.ino = s->ino;
+                       pctx.dir = s->dir;
+                       fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
                }
                if (file_ok) {
-                       printf("Duplicated blocks already reassigned or cloned.\n\n");
+                       fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
                        continue;
                }
-                       
-               if (ask("Clone duplicate/bad blocks", 1)) {
-                       retval = clone_file(fs, p, block_buf);
-                       if (retval)
-                               printf("Couldn't clone file: %s\n",
-                                      error_message(retval));
-                       else {
-                               printf("\n");
+               if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
+                       pctx.errcode = clone_file(ctx, p, block_buf);
+                       if (pctx.errcode)
+                               fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx);
+                       else
                                continue;
-                       }
                }
-               if (ask("Delete file", 1))
-                       delete_file(fs, p, block_buf);
+               if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
+                       delete_file(ctx, p, block_buf);
                else
                        ext2fs_unmark_valid(fs);
-               printf("\n");
        }
-       free(shared);
+       ext2fs_free_mem((void **) &shared);
 }
 
 static int delete_file_block(ext2_filsys fs,
                             blk_t      *block_nr,
                             int blockcnt,
-                            void *private)
+                            void *priv_data)
 {
+       struct process_block_struct *pb;
        struct dup_block *p;
+       e2fsck_t ctx;
+
+       pb = (struct process_block_struct *) priv_data;
+       ctx = pb->ctx;
 
        if (!*block_nr)
                return 0;
 
-       if (ext2fs_test_block_bitmap(block_dup_map, *block_nr)) {
+       if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
                for (p = dup_blk; p; p = p->next_block)
                        if (p->block == *block_nr)
                                break;
                if (p) {
                        p->num_bad--;
                        if (p->num_bad == 1)
-                               ext2fs_unmark_block_bitmap(block_dup_map,
+                               ext2fs_unmark_block_bitmap(ctx->block_dup_map,
                                                           *block_nr);
                } else
                        com_err("delete_file_block", 0,
                                "internal error; can't find dup_blk for %d\n",
                                *block_nr);
        } else {
-               ext2fs_unmark_block_bitmap(block_found_map, *block_nr);
+               ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
                ext2fs_unmark_block_bitmap(fs->block_map, *block_nr);
        }
                
        return 0;
 }
                
-static void delete_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf)
+static void delete_file(e2fsck_t ctx, struct dup_inode *dp, char* block_buf)
 {
+       ext2_filsys fs = ctx->fs;
        errcode_t       retval;
        struct process_block_struct pb;
        struct ext2_inode       inode;
 
        pb.ino = dp->ino;
        pb.dup_blocks = dp->num_dupblocks;
+       pb.ctx = ctx;
        
        retval = ext2fs_block_iterate(fs, dp->ino, 0, block_buf,
                                      delete_file_block, &pb);
@@ -524,48 +533,61 @@ static void delete_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf)
                com_err("delete_file", retval,
                        "while calling ext2fs_block_iterate for inode %d",
                        dp->ino);
-       ext2fs_unmark_inode_bitmap(inode_used_map, dp->ino);
-       ext2fs_unmark_inode_bitmap(inode_dir_map, dp->ino);
-       if (inode_bad_map)
-               ext2fs_unmark_inode_bitmap(inode_bad_map, dp->ino);
+       ext2fs_unmark_inode_bitmap(ctx->inode_used_map, dp->ino);
+       ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, dp->ino);
+       if (ctx->inode_bad_map)
+               ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, dp->ino);
        ext2fs_unmark_inode_bitmap(fs->inode_map, dp->ino);
        ext2fs_mark_ib_dirty(fs);
        ext2fs_mark_bb_dirty(fs);
-       e2fsck_read_inode(fs, dp->ino, &inode, "delete_file");
+       e2fsck_read_inode(ctx, dp->ino, &inode, "delete_file");
        inode.i_links_count = 0;
        inode.i_dtime = time(0);
-       e2fsck_write_inode(fs, dp->ino, &inode, "delete_file");
+       e2fsck_write_inode(ctx, dp->ino, &inode, "delete_file");
 }
 
 struct clone_struct {
        errcode_t       errcode;
+       ino_t           dir;
        char    *buf;
+       e2fsck_t ctx;
 };
 
 static int clone_file_block(ext2_filsys fs,
                            blk_t       *block_nr,
                            int blockcnt,
-                           void *private)
+                           void *priv_data)
 {
        struct dup_block *p;
        blk_t   new_block;
        errcode_t       retval;
-       struct clone_struct *cs = (struct clone_struct *) private;
+       struct clone_struct *cs = (struct clone_struct *) priv_data;
+       e2fsck_t ctx;
 
+       ctx = cs->ctx;
+       
        if (!*block_nr)
                return 0;
 
-       if (ext2fs_test_block_bitmap(block_dup_map, *block_nr)) {
+       if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
                for (p = dup_blk; p; p = p->next_block)
                        if (p->block == *block_nr)
                                break;
                if (p) {
-                       retval = ext2fs_new_block(fs, 0, block_found_map,
+                       retval = ext2fs_new_block(fs, 0, ctx->block_found_map,
                                                  &new_block);
                        if (retval) {
                                cs->errcode = retval;
                                return BLOCK_ABORT;
                        }
+                       if (cs->dir) {
+                               retval = ext2fs_set_dir_block(fs->dblist,
+                                     cs->dir, new_block, blockcnt);
+                               if (retval) {
+                                       cs->errcode = retval;
+                                       return BLOCK_ABORT;
+                               }
+                       }
                        retval = io_channel_read_blk(fs->io, *block_nr, 1,
                                                     cs->buf);
                        if (retval) {
@@ -580,10 +602,10 @@ static int clone_file_block(ext2_filsys fs,
                        }
                        p->num_bad--;
                        if (p->num_bad == 1)
-                               ext2fs_unmark_block_bitmap(block_dup_map,
+                               ext2fs_unmark_block_bitmap(ctx->block_dup_map,
                                                           *block_nr);
                        *block_nr = new_block;
-                       ext2fs_mark_block_bitmap(block_found_map,
+                       ext2fs_mark_block_bitmap(ctx->block_found_map,
                                                 new_block);
                        ext2fs_mark_block_bitmap(fs->block_map, new_block);
                        return BLOCK_CHANGED;
@@ -595,20 +617,26 @@ static int clone_file_block(ext2_filsys fs,
        return 0;
 }
                
-static int clone_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf)
+static int clone_file(e2fsck_t ctx, struct dup_inode *dp, char* block_buf)
 {
+       ext2_filsys fs = ctx->fs;
        errcode_t       retval;
        struct clone_struct cs;
 
        cs.errcode = 0;
-       cs.buf = malloc(fs->blocksize);
-       if (!cs.buf)
-               return ENOMEM;
+       cs.dir = 0;
+       cs.ctx = ctx;
+       retval = ext2fs_get_mem(fs->blocksize, (void **) &cs.buf);
+       if (retval)
+               return retval;
+
+       if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dp->ino))
+               cs.dir = dp->ino;
        
        retval = ext2fs_block_iterate(fs, dp->ino, 0, block_buf,
                                      clone_file_block, &cs);
        ext2fs_mark_bb_dirty(fs);
-       free(cs.buf);
+       ext2fs_free_mem((void **) &cs.buf);
        if (retval) {
                com_err("clone_file", retval,
                        "while calling ext2fs_block_iterate for inode %d",
@@ -616,14 +644,9 @@ static int clone_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf)
                return retval;
        }
        if (cs.errcode) {
-               com_err("clone_file", retval,
+               com_err("clone_file", cs.errcode,
                        "returned from clone_file_block");
                return retval;
        }
        return 0;
 }
-
-
-       
-
-