Home | History | Annotate | Download | only in e2fsck
      1 /*
      2  * pass1b.c --- Pass #1b of e2fsck
      3  *
      4  * This file contains pass1B, pass1C, and pass1D of e2fsck.  They are
      5  * only invoked if pass 1 discovered blocks which are in use by more
      6  * than one inode.
      7  *
      8  * Pass1B scans the data blocks of all the inodes again, generating a
      9  * complete list of duplicate blocks and which inodes have claimed
     10  * them.
     11  *
     12  * Pass1C does a tree-traversal of the filesystem, to determine the
     13  * parent directories of these inodes.  This step is necessary so that
     14  * e2fsck can print out the pathnames of affected inodes.
     15  *
     16  * Pass1D is a reconciliation pass.  For each inode with duplicate
     17  * blocks, the user is prompted if s/he would like to clone the file
     18  * (so that the file gets a fresh copy of the duplicated blocks) or
     19  * simply to delete the file.
     20  *
     21  * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
     22  *
     23  * %Begin-Header%
     24  * This file may be redistributed under the terms of the GNU Public
     25  * License.
     26  * %End-Header%
     27  *
     28  */
     29 
     30 #include <time.h>
     31 #ifdef HAVE_ERRNO_H
     32 #include <errno.h>
     33 #endif
     34 
     35 #ifdef HAVE_INTTYPES_H
     36 #include <inttypes.h>
     37 #endif
     38 
     39 #ifndef HAVE_INTPTR_T
     40 typedef long intptr_t;
     41 #endif
     42 
     43 /* Needed for architectures where sizeof(int) != sizeof(void *) */
     44 #define INT_TO_VOIDPTR(val)  ((void *)(intptr_t)(val))
     45 #define VOIDPTR_TO_INT(ptr)  ((int)(intptr_t)(ptr))
     46 
     47 #include <et/com_err.h>
     48 #include "e2fsck.h"
     49 
     50 #include "problem.h"
     51 #include "dict.h"
     52 
     53 /* Define an extension to the ext2 library's block count information */
     54 #define BLOCK_COUNT_EXTATTR	(-5)
     55 
     56 struct block_el {
     57 	blk_t	block;
     58 	struct block_el *next;
     59 };
     60 
     61 struct inode_el {
     62 	ext2_ino_t	inode;
     63 	struct inode_el *next;
     64 };
     65 
     66 struct dup_block {
     67 	int		num_bad;
     68 	struct inode_el *inode_list;
     69 };
     70 
     71 /*
     72  * This structure stores information about a particular inode which
     73  * is sharing blocks with other inodes.  This information is collected
     74  * to display to the user, so that the user knows what files he or she
     75  * is dealing with, when trying to decide how to resolve the conflict
     76  * of multiply-claimed blocks.
     77  */
     78 struct dup_inode {
     79 	ext2_ino_t		dir;
     80 	int			num_dupblocks;
     81 	struct ext2_inode	inode;
     82 	struct block_el		*block_list;
     83 };
     84 
     85 static int process_pass1b_block(ext2_filsys fs, blk_t	*blocknr,
     86 				e2_blkcnt_t blockcnt, blk_t ref_blk,
     87 				int ref_offset, void *priv_data);
     88 static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
     89 			struct dup_inode *dp, char *block_buf);
     90 static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
     91 		      struct dup_inode *dp, char* block_buf);
     92 static int check_if_fs_block(e2fsck_t ctx, blk_t test_blk);
     93 
     94 static void pass1b(e2fsck_t ctx, char *block_buf);
     95 static void pass1c(e2fsck_t ctx, char *block_buf);
     96 static void pass1d(e2fsck_t ctx, char *block_buf);
     97 
     98 static int dup_inode_count = 0;
     99 static int dup_inode_founddir = 0;
    100 
    101 static dict_t blk_dict, ino_dict;
    102 
    103 static ext2fs_inode_bitmap inode_dup_map;
    104 
    105 static int dict_int_cmp(const void *a, const void *b)
    106 {
    107 	intptr_t	ia, ib;
    108 
    109 	ia = (intptr_t)a;
    110 	ib = (intptr_t)b;
    111 
    112 	return (ia-ib);
    113 }
    114 
    115 /*
    116  * Add a duplicate block record
    117  */
    118 static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk_t blk,
    119 		     struct ext2_inode *inode)
    120 {
    121 	dnode_t	*n;
    122 	struct dup_block	*db;
    123 	struct dup_inode	*di;
    124 	struct block_el		*blk_el;
    125 	struct inode_el 	*ino_el;
    126 
    127 	n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
    128 	if (n)
    129 		db = (struct dup_block *) dnode_get(n);
    130 	else {
    131 		db = (struct dup_block *) e2fsck_allocate_memory(ctx,
    132 			 sizeof(struct dup_block), "duplicate block header");
    133 		db->num_bad = 0;
    134 		db->inode_list = 0;
    135 		dict_alloc_insert(&blk_dict, INT_TO_VOIDPTR(blk), db);
    136 	}
    137 	ino_el = (struct inode_el *) e2fsck_allocate_memory(ctx,
    138 			 sizeof(struct inode_el), "inode element");
    139 	ino_el->inode = ino;
    140 	ino_el->next = db->inode_list;
    141 	db->inode_list = ino_el;
    142 	db->num_bad++;
    143 
    144 	n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino));
    145 	if (n)
    146 		di = (struct dup_inode *) dnode_get(n);
    147 	else {
    148 		di = (struct dup_inode *) e2fsck_allocate_memory(ctx,
    149 			 sizeof(struct dup_inode), "duplicate inode header");
    150 		if (ino == EXT2_ROOT_INO) {
    151 			di->dir = EXT2_ROOT_INO;
    152 			dup_inode_founddir++;
    153 		} else
    154 			di->dir = 0;
    155 
    156 		di->num_dupblocks = 0;
    157 		di->block_list = 0;
    158 		di->inode = *inode;
    159 		dict_alloc_insert(&ino_dict, INT_TO_VOIDPTR(ino), di);
    160 	}
    161 	blk_el = (struct block_el *) e2fsck_allocate_memory(ctx,
    162 			 sizeof(struct block_el), "block element");
    163 	blk_el->block = blk;
    164 	blk_el->next = di->block_list;
    165 	di->block_list = blk_el;
    166 	di->num_dupblocks++;
    167 }
    168 
    169 /*
    170  * Free a duplicate inode record
    171  */
    172 static void inode_dnode_free(dnode_t *node,
    173 			     void *context EXT2FS_ATTR((unused)))
    174 {
    175 	struct dup_inode	*di;
    176 	struct block_el		*p, *next;
    177 
    178 	di = (struct dup_inode *) dnode_get(node);
    179 	for (p = di->block_list; p; p = next) {
    180 		next = p->next;
    181 		free(p);
    182 	}
    183 	free(node);
    184 }
    185 
    186 /*
    187  * Free a duplicate block record
    188  */
    189 static void block_dnode_free(dnode_t *node,
    190 			     void *context EXT2FS_ATTR((unused)))
    191 {
    192 	struct dup_block	*db;
    193 	struct inode_el		*p, *next;
    194 
    195 	db = (struct dup_block *) dnode_get(node);
    196 	for (p = db->inode_list; p; p = next) {
    197 		next = p->next;
    198 		free(p);
    199 	}
    200 	free(node);
    201 }
    202 
    203 
    204 /*
    205  * Main procedure for handling duplicate blocks
    206  */
    207 void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf)
    208 {
    209 	ext2_filsys 		fs = ctx->fs;
    210 	struct problem_context	pctx;
    211 
    212 	clear_problem_context(&pctx);
    213 
    214 	pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
    215 		      _("multiply claimed inode map"), &inode_dup_map);
    216 	if (pctx.errcode) {
    217 		fix_problem(ctx, PR_1B_ALLOCATE_IBITMAP_ERROR, &pctx);
    218 		ctx->flags |= E2F_FLAG_ABORT;
    219 		return;
    220 	}
    221 
    222 	dict_init(&ino_dict, DICTCOUNT_T_MAX, dict_int_cmp);
    223 	dict_init(&blk_dict, DICTCOUNT_T_MAX, dict_int_cmp);
    224 	dict_set_allocator(&ino_dict, NULL, inode_dnode_free, NULL);
    225 	dict_set_allocator(&blk_dict, NULL, block_dnode_free, NULL);
    226 
    227 	pass1b(ctx, block_buf);
    228 	pass1c(ctx, block_buf);
    229 	pass1d(ctx, block_buf);
    230 
    231 	/*
    232 	 * Time to free all of the accumulated data structures that we
    233 	 * don't need anymore.
    234 	 */
    235 	dict_free_nodes(&ino_dict);
    236 	dict_free_nodes(&blk_dict);
    237 }
    238 
    239 /*
    240  * Scan the inodes looking for inodes that contain duplicate blocks.
    241  */
    242 struct process_block_struct {
    243 	e2fsck_t	ctx;
    244 	ext2_ino_t	ino;
    245 	int		dup_blocks;
    246 	struct ext2_inode *inode;
    247 	struct problem_context *pctx;
    248 };
    249 
    250 static void pass1b(e2fsck_t ctx, char *block_buf)
    251 {
    252 	ext2_filsys fs = ctx->fs;
    253 	ext2_ino_t ino;
    254 	struct ext2_inode inode;
    255 	ext2_inode_scan	scan;
    256 	struct process_block_struct pb;
    257 	struct problem_context pctx;
    258 
    259 	clear_problem_context(&pctx);
    260 
    261 	if (!(ctx->options & E2F_OPT_PREEN))
    262 		fix_problem(ctx, PR_1B_PASS_HEADER, &pctx);
    263 	pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
    264 					      &scan);
    265 	if (pctx.errcode) {
    266 		fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
    267 		ctx->flags |= E2F_FLAG_ABORT;
    268 		return;
    269 	}
    270 	ctx->stashed_inode = &inode;
    271 	pb.ctx = ctx;
    272 	pb.pctx = &pctx;
    273 	pctx.str = "pass1b";
    274 	while (1) {
    275 		pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
    276 		if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
    277 			continue;
    278 		if (pctx.errcode) {
    279 			fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx);
    280 			ctx->flags |= E2F_FLAG_ABORT;
    281 			return;
    282 		}
    283 		if (!ino)
    284 			break;
    285 		pctx.ino = ctx->stashed_ino = ino;
    286 		if ((ino != EXT2_BAD_INO) &&
    287 		    !ext2fs_test_inode_bitmap(ctx->inode_used_map, ino))
    288 			continue;
    289 
    290 		pb.ino = ino;
    291 		pb.dup_blocks = 0;
    292 		pb.inode = &inode;
    293 
    294 		if (ext2fs_inode_has_valid_blocks(&inode) ||
    295 		    (ino == EXT2_BAD_INO))
    296 			pctx.errcode = ext2fs_block_iterate2(fs, ino,
    297 				     0, block_buf, process_pass1b_block, &pb);
    298 		if (inode.i_file_acl)
    299 			process_pass1b_block(fs, &inode.i_file_acl,
    300 					     BLOCK_COUNT_EXTATTR, 0, 0, &pb);
    301 		if (pb.dup_blocks) {
    302 			end_problem_latch(ctx, PR_LATCH_DBLOCK);
    303 			if (ino >= EXT2_FIRST_INODE(fs->super) ||
    304 			    ino == EXT2_ROOT_INO)
    305 				dup_inode_count++;
    306 		}
    307 		if (pctx.errcode)
    308 			fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
    309 	}
    310 	ext2fs_close_inode_scan(scan);
    311 	e2fsck_use_inode_shortcuts(ctx, 0);
    312 }
    313 
    314 static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)),
    315 				blk_t	*block_nr,
    316 				e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
    317 				blk_t ref_blk EXT2FS_ATTR((unused)),
    318 				int ref_offset EXT2FS_ATTR((unused)),
    319 				void *priv_data)
    320 {
    321 	struct process_block_struct *p;
    322 	e2fsck_t ctx;
    323 
    324 	if (HOLE_BLKADDR(*block_nr))
    325 		return 0;
    326 	p = (struct process_block_struct *) priv_data;
    327 	ctx = p->ctx;
    328 
    329 	if (!ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr))
    330 		return 0;
    331 
    332 	/* OK, this is a duplicate block */
    333 	if (p->ino != EXT2_BAD_INO) {
    334 		p->pctx->blk = *block_nr;
    335 		fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx);
    336 	}
    337 	p->dup_blocks++;
    338 	ext2fs_mark_inode_bitmap(inode_dup_map, p->ino);
    339 
    340 	add_dupe(ctx, p->ino, *block_nr, p->inode);
    341 
    342 	return 0;
    343 }
    344 
    345 /*
    346  * Pass 1c: Scan directories for inodes with duplicate blocks.  This
    347  * is used so that we can print pathnames when prompting the user for
    348  * what to do.
    349  */
    350 struct search_dir_struct {
    351 	int		count;
    352 	ext2_ino_t	first_inode;
    353 	ext2_ino_t	max_inode;
    354 };
    355 
    356 static int search_dirent_proc(ext2_ino_t dir, int entry,
    357 			      struct ext2_dir_entry *dirent,
    358 			      int offset EXT2FS_ATTR((unused)),
    359 			      int blocksize EXT2FS_ATTR((unused)),
    360 			      char *buf EXT2FS_ATTR((unused)),
    361 			      void *priv_data)
    362 {
    363 	struct search_dir_struct *sd;
    364 	struct dup_inode	*p;
    365 	dnode_t			*n;
    366 
    367 	sd = (struct search_dir_struct *) priv_data;
    368 
    369 	if (dirent->inode > sd->max_inode)
    370 		/* Should abort this inode, but not everything */
    371 		return 0;
    372 
    373 	if ((dirent->inode < sd->first_inode) || (entry < DIRENT_OTHER_FILE) ||
    374 	    !ext2fs_test_inode_bitmap(inode_dup_map, dirent->inode))
    375 		return 0;
    376 
    377 	n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(dirent->inode));
    378 	if (!n)
    379 		return 0;
    380 	p = (struct dup_inode *) dnode_get(n);
    381 	if (!p->dir) {
    382 		p->dir = dir;
    383 		sd->count--;
    384 	}
    385 
    386 	return(sd->count ? 0 : DIRENT_ABORT);
    387 }
    388 
    389 
    390 static void pass1c(e2fsck_t ctx, char *block_buf)
    391 {
    392 	ext2_filsys fs = ctx->fs;
    393 	struct search_dir_struct sd;
    394 	struct problem_context pctx;
    395 
    396 	clear_problem_context(&pctx);
    397 
    398 	if (!(ctx->options & E2F_OPT_PREEN))
    399 		fix_problem(ctx, PR_1C_PASS_HEADER, &pctx);
    400 
    401 	/*
    402 	 * Search through all directories to translate inodes to names
    403 	 * (by searching for the containing directory for that inode.)
    404 	 */
    405 	sd.count = dup_inode_count - dup_inode_founddir;
    406 	sd.first_inode = EXT2_FIRST_INODE(fs->super);
    407 	sd.max_inode = fs->super->s_inodes_count;
    408 	ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf,
    409 				  search_dirent_proc, &sd);
    410 }
    411 
    412 static void pass1d(e2fsck_t ctx, char *block_buf)
    413 {
    414 	ext2_filsys fs = ctx->fs;
    415 	struct dup_inode	*p, *t;
    416 	struct dup_block	*q;
    417 	ext2_ino_t		*shared, ino;
    418 	int	shared_len;
    419 	int	i;
    420 	int	file_ok;
    421 	int	meta_data = 0;
    422 	struct problem_context pctx;
    423 	dnode_t	*n, *m;
    424 	struct block_el	*s;
    425 	struct inode_el *r;
    426 
    427 	clear_problem_context(&pctx);
    428 
    429 	if (!(ctx->options & E2F_OPT_PREEN))
    430 		fix_problem(ctx, PR_1D_PASS_HEADER, &pctx);
    431 	e2fsck_read_bitmaps(ctx);
    432 
    433 	pctx.num = dup_inode_count; /* dict_count(&ino_dict); */
    434 	fix_problem(ctx, PR_1D_NUM_DUP_INODES, &pctx);
    435 	shared = (ext2_ino_t *) e2fsck_allocate_memory(ctx,
    436 				sizeof(ext2_ino_t) * dict_count(&ino_dict),
    437 				"Shared inode list");
    438 	for (n = dict_first(&ino_dict); n; n = dict_next(&ino_dict, n)) {
    439 		p = (struct dup_inode *) dnode_get(n);
    440 		shared_len = 0;
    441 		file_ok = 1;
    442 		ino = (ext2_ino_t)VOIDPTR_TO_INT(dnode_getkey(n));
    443 		if (ino == EXT2_BAD_INO || ino == EXT2_RESIZE_INO)
    444 			continue;
    445 
    446 		/*
    447 		 * Find all of the inodes which share blocks with this
    448 		 * one.  First we find all of the duplicate blocks
    449 		 * belonging to this inode, and then search each block
    450 		 * get the list of inodes, and merge them together.
    451 		 */
    452 		for (s = p->block_list; s; s = s->next) {
    453 			m = dict_lookup(&blk_dict, INT_TO_VOIDPTR(s->block));
    454 			if (!m)
    455 				continue; /* Should never happen... */
    456 			q = (struct dup_block *) dnode_get(m);
    457 			if (q->num_bad > 1)
    458 				file_ok = 0;
    459 			if (check_if_fs_block(ctx, s->block)) {
    460 				file_ok = 0;
    461 				meta_data = 1;
    462 			}
    463 
    464 			/*
    465 			 * Add all inodes used by this block to the
    466 			 * shared[] --- which is a unique list, so
    467 			 * if an inode is already in shared[], don't
    468 			 * add it again.
    469 			 */
    470 			for (r = q->inode_list; r; r = r->next) {
    471 				if (r->inode == ino)
    472 					continue;
    473 				for (i = 0; i < shared_len; i++)
    474 					if (shared[i] == r->inode)
    475 						break;
    476 				if (i == shared_len) {
    477 					shared[shared_len++] = r->inode;
    478 				}
    479 			}
    480 		}
    481 
    482 		/*
    483 		 * Report the inode that we are working on
    484 		 */
    485 		pctx.inode = &p->inode;
    486 		pctx.ino = ino;
    487 		pctx.dir = p->dir;
    488 		pctx.blkcount = p->num_dupblocks;
    489 		pctx.num = meta_data ? shared_len+1 : shared_len;
    490 		fix_problem(ctx, PR_1D_DUP_FILE, &pctx);
    491 		pctx.blkcount = 0;
    492 		pctx.num = 0;
    493 
    494 		if (meta_data)
    495 			fix_problem(ctx, PR_1D_SHARE_METADATA, &pctx);
    496 
    497 		for (i = 0; i < shared_len; i++) {
    498 			m = dict_lookup(&ino_dict, INT_TO_VOIDPTR(shared[i]));
    499 			if (!m)
    500 				continue; /* should never happen */
    501 			t = (struct dup_inode *) dnode_get(m);
    502 			/*
    503 			 * Report the inode that we are sharing with
    504 			 */
    505 			pctx.inode = &t->inode;
    506 			pctx.ino = shared[i];
    507 			pctx.dir = t->dir;
    508 			fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
    509 		}
    510 		if (file_ok) {
    511 			fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
    512 			continue;
    513 		}
    514 		if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
    515 			pctx.errcode = clone_file(ctx, ino, p, block_buf);
    516 			if (pctx.errcode)
    517 				fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx);
    518 			else
    519 				continue;
    520 		}
    521 		if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
    522 			delete_file(ctx, ino, p, block_buf);
    523 		else
    524 			ext2fs_unmark_valid(fs);
    525 	}
    526 	ext2fs_free_mem(&shared);
    527 }
    528 
    529 /*
    530  * Drop the refcount on the dup_block structure, and clear the entry
    531  * in the block_dup_map if appropriate.
    532  */
    533 static void decrement_badcount(e2fsck_t ctx, blk_t block, struct dup_block *p)
    534 {
    535 	p->num_bad--;
    536 	if (p->num_bad <= 0 ||
    537 	    (p->num_bad == 1 && !check_if_fs_block(ctx, block)))
    538 		ext2fs_unmark_block_bitmap(ctx->block_dup_map, block);
    539 }
    540 
    541 static int delete_file_block(ext2_filsys fs,
    542 			     blk_t	*block_nr,
    543 			     e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
    544 			     blk_t ref_block EXT2FS_ATTR((unused)),
    545 			     int ref_offset EXT2FS_ATTR((unused)),
    546 			     void *priv_data)
    547 {
    548 	struct process_block_struct *pb;
    549 	struct dup_block *p;
    550 	dnode_t	*n;
    551 	e2fsck_t ctx;
    552 
    553 	pb = (struct process_block_struct *) priv_data;
    554 	ctx = pb->ctx;
    555 
    556 	if (HOLE_BLKADDR(*block_nr))
    557 		return 0;
    558 
    559 	if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
    560 		n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
    561 		if (n) {
    562 			p = (struct dup_block *) dnode_get(n);
    563 			decrement_badcount(ctx, *block_nr, p);
    564 		} else
    565 			com_err("delete_file_block", 0,
    566 			    _("internal error: can't find dup_blk for %u\n"),
    567 				*block_nr);
    568 	} else {
    569 		ext2fs_unmark_block_bitmap(ctx->block_found_map, *block_nr);
    570 		ext2fs_block_alloc_stats(fs, *block_nr, -1);
    571 	}
    572 
    573 	return 0;
    574 }
    575 
    576 static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
    577 			struct dup_inode *dp, char* block_buf)
    578 {
    579 	ext2_filsys fs = ctx->fs;
    580 	struct process_block_struct pb;
    581 	struct ext2_inode	inode;
    582 	struct problem_context	pctx;
    583 	unsigned int		count;
    584 
    585 	clear_problem_context(&pctx);
    586 	pctx.ino = pb.ino = ino;
    587 	pb.dup_blocks = dp->num_dupblocks;
    588 	pb.ctx = ctx;
    589 	pctx.str = "delete_file";
    590 
    591 	e2fsck_read_inode(ctx, ino, &inode, "delete_file");
    592 	if (ext2fs_inode_has_valid_blocks(&inode))
    593 		pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
    594 						     delete_file_block, &pb);
    595 	if (pctx.errcode)
    596 		fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
    597 	ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
    598 	ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
    599 	if (ctx->inode_bad_map)
    600 		ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
    601 	ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
    602 
    603 	/* Inode may have changed by block_iterate, so reread it */
    604 	e2fsck_read_inode(ctx, ino, &inode, "delete_file");
    605 	inode.i_links_count = 0;
    606 	inode.i_dtime = ctx->now;
    607 	if (inode.i_file_acl &&
    608 	    (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
    609 		count = 1;
    610 		pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl,
    611 						   block_buf, -1, &count);
    612 		if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
    613 			pctx.errcode = 0;
    614 			count = 1;
    615 		}
    616 		if (pctx.errcode) {
    617 			pctx.blk = inode.i_file_acl;
    618 			fix_problem(ctx, PR_1B_ADJ_EA_REFCOUNT, &pctx);
    619 		}
    620 		/*
    621 		 * If the count is zero, then arrange to have the
    622 		 * block deleted.  If the block is in the block_dup_map,
    623 		 * also call delete_file_block since it will take care
    624 		 * of keeping the accounting straight.
    625 		 */
    626 		if ((count == 0) ||
    627 		    ext2fs_test_block_bitmap(ctx->block_dup_map,
    628 					     inode.i_file_acl))
    629 			delete_file_block(fs, &inode.i_file_acl,
    630 					  BLOCK_COUNT_EXTATTR, 0, 0, &pb);
    631 	}
    632 	e2fsck_write_inode(ctx, ino, &inode, "delete_file");
    633 }
    634 
    635 struct clone_struct {
    636 	errcode_t	errcode;
    637 	ext2_ino_t	dir;
    638 	char	*buf;
    639 	e2fsck_t ctx;
    640 };
    641 
    642 static int clone_file_block(ext2_filsys fs,
    643 			    blk_t	*block_nr,
    644 			    e2_blkcnt_t blockcnt,
    645 			    blk_t ref_block EXT2FS_ATTR((unused)),
    646 			    int ref_offset EXT2FS_ATTR((unused)),
    647 			    void *priv_data)
    648 {
    649 	struct dup_block *p;
    650 	blk_t	new_block;
    651 	errcode_t	retval;
    652 	struct clone_struct *cs = (struct clone_struct *) priv_data;
    653 	dnode_t *n;
    654 	e2fsck_t ctx;
    655 
    656 	ctx = cs->ctx;
    657 
    658 	if (HOLE_BLKADDR(*block_nr))
    659 		return 0;
    660 
    661 	if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
    662 		n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(*block_nr));
    663 		if (n) {
    664 			p = (struct dup_block *) dnode_get(n);
    665 			retval = ext2fs_new_block(fs, 0, ctx->block_found_map,
    666 						  &new_block);
    667 			if (retval) {
    668 				cs->errcode = retval;
    669 				return BLOCK_ABORT;
    670 			}
    671 			if (cs->dir && (blockcnt >= 0)) {
    672 				retval = ext2fs_set_dir_block(fs->dblist,
    673 				      cs->dir, new_block, blockcnt);
    674 				if (retval) {
    675 					cs->errcode = retval;
    676 					return BLOCK_ABORT;
    677 				}
    678 			}
    679 #if 0
    680 			printf("Cloning block %u to %u\n", *block_nr,
    681 			       new_block);
    682 #endif
    683 			retval = io_channel_read_blk(fs->io, *block_nr, 1,
    684 						     cs->buf);
    685 			if (retval) {
    686 				cs->errcode = retval;
    687 				return BLOCK_ABORT;
    688 			}
    689 			retval = io_channel_write_blk(fs->io, new_block, 1,
    690 						      cs->buf);
    691 			if (retval) {
    692 				cs->errcode = retval;
    693 				return BLOCK_ABORT;
    694 			}
    695 			decrement_badcount(ctx, *block_nr, p);
    696 			*block_nr = new_block;
    697 			ext2fs_mark_block_bitmap(ctx->block_found_map,
    698 						 new_block);
    699 			ext2fs_mark_block_bitmap(fs->block_map, new_block);
    700 			return BLOCK_CHANGED;
    701 		} else
    702 			com_err("clone_file_block", 0,
    703 			    _("internal error: can't find dup_blk for %u\n"),
    704 				*block_nr);
    705 	}
    706 	return 0;
    707 }
    708 
    709 static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
    710 		      struct dup_inode *dp, char* block_buf)
    711 {
    712 	ext2_filsys fs = ctx->fs;
    713 	errcode_t	retval;
    714 	struct clone_struct cs;
    715 	struct problem_context	pctx;
    716 	blk_t		blk;
    717 	dnode_t		*n;
    718 	struct inode_el	*ino_el;
    719 	struct dup_block	*db;
    720 	struct dup_inode	*di;
    721 
    722 	clear_problem_context(&pctx);
    723 	cs.errcode = 0;
    724 	cs.dir = 0;
    725 	cs.ctx = ctx;
    726 	retval = ext2fs_get_mem(fs->blocksize, &cs.buf);
    727 	if (retval)
    728 		return retval;
    729 
    730 	if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino))
    731 		cs.dir = ino;
    732 
    733 	pctx.ino = ino;
    734 	pctx.str = "clone_file";
    735 	if (ext2fs_inode_has_valid_blocks(&dp->inode))
    736 		pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
    737 						     clone_file_block, &cs);
    738 	ext2fs_mark_bb_dirty(fs);
    739 	if (pctx.errcode) {
    740 		fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
    741 		retval = pctx.errcode;
    742 		goto errout;
    743 	}
    744 	if (cs.errcode) {
    745 		com_err("clone_file", cs.errcode,
    746 			_("returned from clone_file_block"));
    747 		retval = cs.errcode;
    748 		goto errout;
    749 	}
    750 	/* The inode may have changed on disk, so we have to re-read it */
    751 	e2fsck_read_inode(ctx, ino, &dp->inode, "clone file EA");
    752 	blk = dp->inode.i_file_acl;
    753 	if (blk && (clone_file_block(fs, &dp->inode.i_file_acl,
    754 				     BLOCK_COUNT_EXTATTR, 0, 0, &cs) ==
    755 		    BLOCK_CHANGED)) {
    756 		e2fsck_write_inode(ctx, ino, &dp->inode, "clone file EA");
    757 		/*
    758 		 * If we cloned the EA block, find all other inodes
    759 		 * which refered to that EA block, and modify
    760 		 * them to point to the new EA block.
    761 		 */
    762 		n = dict_lookup(&blk_dict, INT_TO_VOIDPTR(blk));
    763 		if (!n) {
    764 			com_err("clone_file", 0,
    765 				_("internal error: couldn't lookup EA "
    766 				  "block record for %u"), blk);
    767 			retval = 0; /* OK to stumble on... */
    768 			goto errout;
    769 		}
    770 		db = (struct dup_block *) dnode_get(n);
    771 		for (ino_el = db->inode_list; ino_el; ino_el = ino_el->next) {
    772 			if (ino_el->inode == ino)
    773 				continue;
    774 			n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino_el->inode));
    775 			if (!n) {
    776 				com_err("clone_file", 0,
    777 					_("internal error: couldn't lookup EA "
    778 					  "inode record for %u"),
    779 					ino_el->inode);
    780 				retval = 0; /* OK to stumble on... */
    781 				goto errout;
    782 			}
    783 			di = (struct dup_inode *) dnode_get(n);
    784 			if (di->inode.i_file_acl == blk) {
    785 				di->inode.i_file_acl = dp->inode.i_file_acl;
    786 				e2fsck_write_inode(ctx, ino_el->inode,
    787 					   &di->inode, "clone file EA");
    788 				decrement_badcount(ctx, blk, db);
    789 			}
    790 		}
    791 	}
    792 	retval = 0;
    793 errout:
    794 	ext2fs_free_mem(&cs.buf);
    795 	return retval;
    796 }
    797 
    798 /*
    799  * This routine returns 1 if a block overlaps with one of the superblocks,
    800  * group descriptors, inode bitmaps, or block bitmaps.
    801  */
    802 static int check_if_fs_block(e2fsck_t ctx, blk_t test_block)
    803 {
    804 	ext2_filsys fs = ctx->fs;
    805 	blk_t	first_block;
    806 	dgrp_t	i;
    807 
    808 	first_block = fs->super->s_first_data_block;
    809 	for (i = 0; i < fs->group_desc_count; i++) {
    810 
    811 		/* Check superblocks/block group descriptors */
    812 		if (ext2fs_bg_has_super(fs, i)) {
    813 			if (test_block >= first_block &&
    814 			    (test_block <= first_block + fs->desc_blocks))
    815 				return 1;
    816 		}
    817 
    818 		/* Check the inode table */
    819 		if ((fs->group_desc[i].bg_inode_table) &&
    820 		    (test_block >= fs->group_desc[i].bg_inode_table) &&
    821 		    (test_block < (fs->group_desc[i].bg_inode_table +
    822 				   fs->inode_blocks_per_group)))
    823 			return 1;
    824 
    825 		/* Check the bitmap blocks */
    826 		if ((test_block == fs->group_desc[i].bg_block_bitmap) ||
    827 		    (test_block == fs->group_desc[i].bg_inode_bitmap))
    828 			return 1;
    829 
    830 		first_block += fs->super->s_blocks_per_group;
    831 	}
    832 	return 0;
    833 }
    834