]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - e2fsck/emptydir.c
debugfs.c: the max length of debugfs argument is too short
[thirdparty/e2fsprogs.git] / e2fsck / emptydir.c
CommitLineData
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 */
22struct 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
33typedef struct empty_dir_info_struct *empty_dir_info;
34
35extern empty_dir_info init_empty_dir(e2fsck_t ctx);
36extern void free_empty_dirblock(empty_dir_info edi);
37extern void add_empty_dirblock(empty_dir_info edi,
6dc64392 38 struct ext2_db_entry2 *db);
f75c28de
TT
39extern void process_empty_dirblock(e2fsck_t ctx, empty_dir_info edi);
40
41
42empty_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
69errout:
70 free_empty_dirblock(edi);
71 return NULL;
72}
73
74void 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
89void 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
120int 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
149static 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
180void 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