1f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o/*
2f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * emptydir.c --- clear empty directory blocks
3efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o *
4f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * Copyright (C) 1998 Theodore Ts'o
5f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o *
6f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * %Begin-Header%
7f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * This file may be redistributed under the terms of the GNU Public
8f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * License.
9f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * %End-Header%
10f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o *
11f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * This file has the necessary routines to search for empty directory
12f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * blocks and get rid of them.
13f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o */
14f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
15f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o#include "e2fsck.h"
16f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o#include "problem.h"
17f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
18f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o/*
19f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * For e2fsck.h
20f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o */
21f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'ostruct empty_dir_info_struct {
22f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	ext2_dblist empty_dblist;
23f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	ext2fs_block_bitmap empty_dir_blocks;
24f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	ext2fs_inode_bitmap dir_map;
25f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	char *block_buf;
2686c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o	ext2_ino_t ino;
27f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	struct ext2_inode inode;
28e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t	logblk;
29e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t	freed_blocks;
30f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o};
31f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
32f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'otypedef struct empty_dir_info_struct *empty_dir_info;
33f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
34f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'oextern empty_dir_info init_empty_dir(e2fsck_t ctx);
35f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'oextern void free_empty_dirblock(empty_dir_info edi);
36f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'oextern void add_empty_dirblock(empty_dir_info edi,
37e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			       struct ext2_db_entry2 *db);
38f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'oextern void process_empty_dirblock(e2fsck_t ctx, empty_dir_info edi);
39f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
40f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
41f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'oempty_dir_info init_empty_dir(e2fsck_t ctx)
42f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o{
43f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	empty_dir_info	edi;
44f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	errcode_t	retval;
45f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
46f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	edi = malloc(sizeof(struct empty_dir_info_struct));
47f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (!edi)
48f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		return NULL;
49f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
50f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	memset(edi, 0, sizeof(struct empty_dir_info_struct));
51f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
52f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	retval = ext2fs_init_dblist(ctx->fs, &edi->empty_dblist);
53f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (retval)
54f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		goto errout;
55efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
560c4a07264e55b42c6e30230e66b1dea7d4b94ea9Theodore Ts'o	retval = ext2fs_allocate_block_bitmap(ctx->fs, _("empty dirblocks"),
57f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o					      &edi->empty_dir_blocks);
58f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (retval)
59f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		goto errout;
60f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
610c4a07264e55b42c6e30230e66b1dea7d4b94ea9Theodore Ts'o	retval = ext2fs_allocate_inode_bitmap(ctx->fs, _("empty dir map"),
62f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o					      &edi->dir_map);
63f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (retval)
64f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		goto errout;
65f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
66f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	return (edi);
67f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
68f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'oerrout:
69f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	free_empty_dirblock(edi);
70f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	return NULL;
71f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o}
72f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
73f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'ovoid free_empty_dirblock(empty_dir_info edi)
74f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o{
75f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (!edi)
76f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		return;
77f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (edi->empty_dblist)
78f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		ext2fs_free_dblist(edi->empty_dblist);
79f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (edi->empty_dir_blocks)
80f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		ext2fs_free_block_bitmap(edi->empty_dir_blocks);
81f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (edi->dir_map)
82f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		ext2fs_free_inode_bitmap(edi->dir_map);
83f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
84f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	memset(edi, 0, sizeof(struct empty_dir_info_struct));
85f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	free(edi);
86f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o}
87f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
88f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'ovoid add_empty_dirblock(empty_dir_info edi,
89e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			struct ext2_db_entry2 *db)
90f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o{
91f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (!edi || !db)
92f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		return;
93f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
94f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (db->ino == 11)
95f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		return;		/* Inode number 11 is usually lost+found */
96f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
97d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen	printf(_("Empty directory block %u (#%d) in inode %u\n"),
98f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	       db->blk, db->blockcnt, db->ino);
99f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
100e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_mark_block_bitmap2(edi->empty_dir_blocks, db->blk);
101f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (ext2fs_test_inode_bitmap(edi->dir_map, db->ino))
102f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		return;
103f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	ext2fs_mark_inode_bitmap(edi->dir_map, db->ino);
104f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
105e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_add_dir_block2(edi->empty_dblist, db->ino,
106e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			      db->blk, db->blockcnt);
107f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o}
108f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
109f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o/*
110f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * Helper function used by fix_directory.
111f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o *
112f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * XXX need to finish this.  General approach is to use bmap to
113f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * iterate over all of the logical blocks using the bmap function, and
114f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * copy the block reference as necessary.  Big question --- what do
115f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * about error recovery?
116f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o *
117f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * Also question --- how to free the indirect blocks.
118f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o */
119e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallint empty_pass1(ext2_filsys fs, blk64_t *block_nr, e2_blkcnt_t blockcnt,
120e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		blk64_t ref_block, int ref_offset, void *priv_data)
121f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o{
122f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	empty_dir_info edi = (empty_dir_info) priv_data;
123e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t	block, new_block;
124f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	errcode_t	retval;
125efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
126f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (blockcnt < 0)
127f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		return 0;
128f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	block = *block_nr;
129f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	do {
130e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = ext2fs_bmap2(fs, edi->ino, &edi->inode,
131e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				      edi->block_buf, 0, edi->logblk, 0,
132e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				      &new_block);
133f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		if (retval)
134f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o			return DIRENT_ABORT;   /* XXX what to do? */
135f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		if (new_block == 0)
136f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o			break;
137f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		edi->logblk++;
138e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	} while (ext2fs_test_block_bitmap2(edi->empty_dir_blocks, new_block));
139f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
140f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (new_block == block)
141f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		return 0;
142f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (new_block == 0)
143f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		edi->freed_blocks++;
144f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	*block_nr = new_block;
145f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	return BLOCK_CHANGED;
146f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o}
147f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
148f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'ostatic int fix_directory(ext2_filsys fs,
149e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			 struct ext2_db_entry2 *db,
150f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o			 void *priv_data)
151f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o{
152f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	errcode_t	retval;
153efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
154f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	empty_dir_info edi = (empty_dir_info) priv_data;
155f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
156f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	edi->logblk = 0;
157f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	edi->freed_blocks = 0;
158f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	edi->ino = db->ino;
159f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
160f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	retval = ext2fs_read_inode(fs, db->ino, &edi->inode);
161f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (retval)
162f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		return 0;
163f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
164e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	retval = ext2fs_block_iterate3(fs, db->ino, 0, edi->block_buf,
165f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o				       empty_pass1, edi);
166f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (retval)
167f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		return 0;
168f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
169f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (edi->freed_blocks) {
170f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		edi->inode.i_size -= edi->freed_blocks * fs->blocksize;
1711ca1059fd0126fd2c065f272a566c18f14bab16dTheodore Ts'o		ext2fs_iblk_add_blocks(fs, &edi->inode, edi->freed_blocks);
172d2b2a488f996871e6e40789a7890afc2f59730dbBrian Behlendorf		retval = ext2fs_write_inode(fs, db->ino, &edi->inode);
173d2b2a488f996871e6e40789a7890afc2f59730dbBrian Behlendorf		if (retval)
174d2b2a488f996871e6e40789a7890afc2f59730dbBrian Behlendorf			return 0;
175f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	}
176f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	return 0;
177f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o}
178f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
179f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'ovoid process_empty_dirblock(e2fsck_t ctx, empty_dir_info edi)
180f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o{
181f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (!edi)
182f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		return;
183f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
184f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	edi->block_buf = malloc(ctx->fs->blocksize * 3);
185f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
186f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	if (edi->block_buf) {
187e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		(void) ext2fs_dblist_iterate2(edi->empty_dblist,
188e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					      fix_directory, &edi);
189f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	}
190f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	free(edi->block_buf);
191f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o	free_empty_dirblock(edi);
192f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o}
193f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o
194