]>
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 | ||
47 | edi = malloc(sizeof(struct empty_dir_info_struct)); | |
48 | if (!edi) | |
49 | return NULL; | |
50 | ||
51 | memset(edi, 0, sizeof(struct empty_dir_info_struct)); | |
52 | ||
53 | retval = ext2fs_init_dblist(ctx->fs, &edi->empty_dblist); | |
54 | if (retval) | |
55 | goto errout; | |
efc6f628 | 56 | |
0c4a0726 | 57 | retval = ext2fs_allocate_block_bitmap(ctx->fs, _("empty dirblocks"), |
f75c28de TT |
58 | &edi->empty_dir_blocks); |
59 | if (retval) | |
60 | goto errout; | |
61 | ||
0c4a0726 | 62 | retval = ext2fs_allocate_inode_bitmap(ctx->fs, _("empty dir map"), |
f75c28de TT |
63 | &edi->dir_map); |
64 | if (retval) | |
65 | goto errout; | |
66 | ||
67 | return (edi); | |
68 | ||
69 | errout: | |
70 | free_empty_dirblock(edi); | |
71 | return NULL; | |
72 | } | |
73 | ||
74 | void free_empty_dirblock(empty_dir_info edi) | |
75 | { | |
76 | if (!edi) | |
77 | return; | |
78 | if (edi->empty_dblist) | |
79 | ext2fs_free_dblist(edi->empty_dblist); | |
80 | if (edi->empty_dir_blocks) | |
81 | ext2fs_free_block_bitmap(edi->empty_dir_blocks); | |
82 | if (edi->dir_map) | |
83 | ext2fs_free_inode_bitmap(edi->dir_map); | |
84 | ||
85 | memset(edi, 0, sizeof(struct empty_dir_info_struct)); | |
86 | free(edi); | |
87 | } | |
88 | ||
89 | void add_empty_dirblock(empty_dir_info edi, | |
6dc64392 | 90 | struct ext2_db_entry2 *db) |
f75c28de TT |
91 | { |
92 | if (!edi || !db) | |
93 | return; | |
94 | ||
95 | if (db->ino == 11) | |
96 | return; /* Inode number 11 is usually lost+found */ | |
97 | ||
d0ff90d5 | 98 | printf(_("Empty directory block %u (#%d) in inode %u\n"), |
f75c28de TT |
99 | db->blk, db->blockcnt, db->ino); |
100 | ||
c5d2f50d | 101 | ext2fs_mark_block_bitmap2(edi->empty_dir_blocks, db->blk); |
f75c28de TT |
102 | if (ext2fs_test_inode_bitmap(edi->dir_map, db->ino)) |
103 | return; | |
104 | ext2fs_mark_inode_bitmap(edi->dir_map, db->ino); | |
105 | ||
6dc64392 VAH |
106 | ext2fs_add_dir_block2(edi->empty_dblist, db->ino, |
107 | db->blk, db->blockcnt); | |
f75c28de TT |
108 | } |
109 | ||
110 | /* | |
111 | * Helper function used by fix_directory. | |
112 | * | |
113 | * XXX need to finish this. General approach is to use bmap to | |
114 | * iterate over all of the logical blocks using the bmap function, and | |
115 | * copy the block reference as necessary. Big question --- what do | |
116 | * about error recovery? | |
117 | * | |
118 | * Also question --- how to free the indirect blocks. | |
119 | */ | |
6dc64392 VAH |
120 | int empty_pass1(ext2_filsys fs, blk64_t *block_nr, e2_blkcnt_t blockcnt, |
121 | blk64_t ref_block, int ref_offset, void *priv_data) | |
f75c28de TT |
122 | { |
123 | empty_dir_info edi = (empty_dir_info) priv_data; | |
6dc64392 | 124 | blk64_t block, new_block; |
f75c28de | 125 | errcode_t retval; |
efc6f628 | 126 | |
f75c28de TT |
127 | if (blockcnt < 0) |
128 | return 0; | |
129 | block = *block_nr; | |
130 | do { | |
6dc64392 VAH |
131 | retval = ext2fs_bmap2(fs, edi->ino, &edi->inode, |
132 | edi->block_buf, 0, edi->logblk, 0, | |
133 | &new_block); | |
f75c28de TT |
134 | if (retval) |
135 | return DIRENT_ABORT; /* XXX what to do? */ | |
136 | if (new_block == 0) | |
137 | break; | |
138 | edi->logblk++; | |
c5d2f50d | 139 | } while (ext2fs_test_block_bitmap2(edi->empty_dir_blocks, new_block)); |
f75c28de TT |
140 | |
141 | if (new_block == block) | |
142 | return 0; | |
143 | if (new_block == 0) | |
144 | edi->freed_blocks++; | |
145 | *block_nr = new_block; | |
146 | return BLOCK_CHANGED; | |
147 | } | |
148 | ||
149 | static int fix_directory(ext2_filsys fs, | |
6dc64392 | 150 | struct ext2_db_entry2 *db, |
f75c28de TT |
151 | void *priv_data) |
152 | { | |
153 | errcode_t retval; | |
efc6f628 | 154 | |
f75c28de TT |
155 | empty_dir_info edi = (empty_dir_info) priv_data; |
156 | ||
157 | edi->logblk = 0; | |
158 | edi->freed_blocks = 0; | |
159 | edi->ino = db->ino; | |
160 | ||
161 | retval = ext2fs_read_inode(fs, db->ino, &edi->inode); | |
162 | if (retval) | |
163 | return 0; | |
164 | ||
6dc64392 | 165 | retval = ext2fs_block_iterate3(fs, db->ino, 0, edi->block_buf, |
f75c28de TT |
166 | empty_pass1, edi); |
167 | if (retval) | |
168 | return 0; | |
169 | ||
170 | if (edi->freed_blocks) { | |
171 | edi->inode.i_size -= edi->freed_blocks * fs->blocksize; | |
1ca1059f | 172 | ext2fs_iblk_add_blocks(fs, &edi->inode, edi->freed_blocks); |
d2b2a488 BB |
173 | retval = ext2fs_write_inode(fs, db->ino, &edi->inode); |
174 | if (retval) | |
175 | return 0; | |
f75c28de TT |
176 | } |
177 | return 0; | |
178 | } | |
179 | ||
180 | void process_empty_dirblock(e2fsck_t ctx, empty_dir_info edi) | |
181 | { | |
182 | if (!edi) | |
183 | return; | |
184 | ||
185 | edi->block_buf = malloc(ctx->fs->blocksize * 3); | |
186 | ||
187 | if (edi->block_buf) { | |
6dc64392 VAH |
188 | (void) ext2fs_dblist_iterate2(edi->empty_dblist, |
189 | fix_directory, &edi); | |
f75c28de TT |
190 | } |
191 | free(edi->block_buf); | |
192 | free_empty_dirblock(edi); | |
193 | } | |
194 |