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