static void pass1d(e2fsck_t ctx, char *block_buf)
{
	ext2_filsys fs = ctx->fs;
	struct dup_inode	*p, *t;
	struct dup_cluster	*q;
	ext2_ino_t		*shared, ino;
	int	shared_len;
	int	i;
	int	file_ok;
	int	meta_data = 0;
	struct problem_context pctx;
	dnode_t	*n, *m;
	struct cluster_el	*s;
	struct inode_el *r;

	clear_problem_context(&pctx);

	if (!(ctx->options & E2F_OPT_PREEN))
		fix_problem(ctx, PR_1D_PASS_HEADER, &pctx);
	e2fsck_read_bitmaps(ctx);

	pctx.num = dup_inode_count; /* dict_count(&ino_dict); */
	fix_problem(ctx, PR_1D_NUM_DUP_INODES, &pctx);
	shared = (ext2_ino_t *) e2fsck_allocate_memory(ctx,
				sizeof(ext2_ino_t) * dict_count(&ino_dict),
				"Shared inode list");
	for (n = dict_first(&ino_dict); n; n = dict_next(&ino_dict, n)) {
		p = (struct dup_inode *) dnode_get(n);
		shared_len = 0;
		file_ok = 1;
		ino = (ext2_ino_t)VOIDPTR_TO_INT(dnode_getkey(n));
		if (ino == EXT2_BAD_INO || ino == EXT2_RESIZE_INO)
			continue;

		/*
		 * Find all of the inodes which share blocks with this
		 * one.  First we find all of the duplicate blocks
		 * belonging to this inode, and then search each block
		 * get the list of inodes, and merge them together.
		 */
		for (s = p->cluster_list; s; s = s->next) {
			m = dict_lookup(&clstr_dict,
					INT_TO_VOIDPTR(s->cluster));
			if (!m)
				continue; /* Should never happen... */
			q = (struct dup_cluster *) dnode_get(m);
			if (q->num_bad > 1)
				file_ok = 0;
			if (check_if_fs_cluster(ctx, s->cluster)) {
				file_ok = 0;
				meta_data = 1;
			}

			/*
			 * Add all inodes used by this block to the
			 * shared[] --- which is a unique list, so
			 * if an inode is already in shared[], don't
			 * add it again.
			 */
			for (r = q->inode_list; r; r = r->next) {
				if (r->inode == ino)
					continue;
				for (i = 0; i < shared_len; i++)
					if (shared[i] == r->inode)
						break;
				if (i == shared_len) {
					shared[shared_len++] = r->inode;
				}
			}
		}

		/*
		 * Report the inode that we are working on
		 */
		pctx.inode = EXT2_INODE(&p->inode);
		pctx.ino = 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++) {
			m = dict_lookup(&ino_dict, INT_TO_VOIDPTR(shared[i]));
			if (!m)
				continue; /* should never happen */
			t = (struct dup_inode *) dnode_get(m);
			/*
			 * Report the inode that we are sharing with
			 */
			pctx.inode = EXT2_INODE(&t->inode);
			pctx.ino = shared[i];
			pctx.dir = t->dir;
			fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
		}
		/*
		 * Even if the file shares blocks with itself, we still need to
		 * clone the blocks.
		 */
		if (file_ok && (meta_data ? shared_len+1 : shared_len) != 0) {
			fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
			continue;
		}
		if ((ctx->options & E2F_OPT_UNSHARE_BLOCKS) ||
                    fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
			pctx.errcode = clone_file(ctx, ino, p, block_buf);
			if (pctx.errcode)
				fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx);
			else
				continue;
		}
		/*
		 * Note: When unsharing blocks, we don't prompt to delete
		 * files. If the clone operation fails than the unshare
		 * operation should fail too.
		 */
		if (!(ctx->options & E2F_OPT_UNSHARE_BLOCKS) &&
                    fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
			delete_file(ctx, ino, p, block_buf);
		else
			ext2fs_unmark_valid(fs);
	}
	ext2fs_free_mem(&shared);
}