]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blob - e2fsck/emptydir.c
e2fsck: consistently use ext2fs_get_mem()
[thirdparty/e2fsprogs.git] / e2fsck / emptydir.c
1 /*
2 * emptydir.c --- clear empty directory blocks
3 *
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
15 #include "config.h"
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;
27 ext2_ino_t ino;
28 struct ext2_inode inode;
29 blk64_t logblk;
30 blk64_t freed_blocks;
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,
38 struct ext2_db_entry2 *db);
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 = e2fsck_allocate_memzero(ctx, sizeof(struct empty_dir_info_struct),
48 "empty dir info");
49 if (retval)
50 return NULL;
51
52 retval = ext2fs_init_dblist(ctx->fs, &edi->empty_dblist);
53 if (retval)
54 goto errout;
55
56 retval = ext2fs_allocate_block_bitmap(ctx->fs, _("empty dirblocks"),
57 &edi->empty_dir_blocks);
58 if (retval)
59 goto errout;
60
61 retval = ext2fs_allocate_inode_bitmap(ctx->fs, _("empty dir map"),
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));
85 ext2fs_free_mem(&edi);
86 }
87
88 void add_empty_dirblock(empty_dir_info edi,
89 struct ext2_db_entry2 *db)
90 {
91 if (!edi || !db)
92 return;
93
94 if (db->ino == 11)
95 return; /* Inode number 11 is usually lost+found */
96
97 printf(_("Empty directory block %u (#%d) in inode %u\n"),
98 db->blk, db->blockcnt, db->ino);
99
100 ext2fs_mark_block_bitmap2(edi->empty_dir_blocks, db->blk);
101 if (ext2fs_test_inode_bitmap(edi->dir_map, db->ino))
102 return;
103 ext2fs_mark_inode_bitmap(edi->dir_map, db->ino);
104
105 ext2fs_add_dir_block2(edi->empty_dblist, db->ino,
106 db->blk, db->blockcnt);
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 */
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)
121 {
122 empty_dir_info edi = (empty_dir_info) priv_data;
123 blk64_t block, new_block;
124 errcode_t retval;
125
126 if (blockcnt < 0)
127 return 0;
128 block = *block_nr;
129 do {
130 retval = ext2fs_bmap2(fs, edi->ino, &edi->inode,
131 edi->block_buf, 0, edi->logblk, 0,
132 &new_block);
133 if (retval)
134 return DIRENT_ABORT; /* XXX what to do? */
135 if (new_block == 0)
136 break;
137 edi->logblk++;
138 } while (ext2fs_test_block_bitmap2(edi->empty_dir_blocks, new_block));
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,
149 struct ext2_db_entry2 *db,
150 void *priv_data)
151 {
152 errcode_t retval;
153
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
164 retval = ext2fs_block_iterate3(fs, db->ino, 0, edi->block_buf,
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;
171 ext2fs_iblk_add_blocks(fs, &edi->inode, edi->freed_blocks);
172 retval = ext2fs_write_inode(fs, db->ino, &edi->inode);
173 if (retval)
174 return 0;
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
184 retval = ext2f_get_mem(ctx, ctx->fs->blocksize * 3,
185 &edi->block_buf);
186
187 if (edi->block_buf) {
188 (void) ext2fs_dblist_iterate2(edi->empty_dblist,
189 fix_directory, &edi);
190 }
191 ext2fs_free_mem(&edi->block_buf);
192 free_empty_dirblock(edi);
193 }
194