Whamcloud - gitweb
Fixes necessary for e2fsprogs to work using the diet libc.
[tools/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 "e2fsck.h"
16 #include "problem.h"
17
18 /*
19  * For e2fsck.h
20  */
21 struct empty_dir_info_struct {
22         ext2_dblist empty_dblist;
23         ext2fs_block_bitmap empty_dir_blocks;
24         ext2fs_inode_bitmap dir_map;
25         char *block_buf;
26         ext2_ino_t ino;
27         struct ext2_inode inode;
28         blk_t   logblk;
29         blk_t   freed_blocks;
30 };
31
32 typedef struct empty_dir_info_struct *empty_dir_info;
33
34 extern empty_dir_info init_empty_dir(e2fsck_t ctx);
35 extern void free_empty_dirblock(empty_dir_info edi);
36 extern void add_empty_dirblock(empty_dir_info edi,
37                                struct ext2_db_entry *db);
38 extern void process_empty_dirblock(e2fsck_t ctx, empty_dir_info edi);
39
40
41 empty_dir_info init_empty_dir(e2fsck_t ctx)
42 {
43         empty_dir_info  edi;
44         errcode_t       retval;
45
46         edi = malloc(sizeof(struct empty_dir_info_struct));
47         if (!edi)
48                 return NULL;
49
50         memset(edi, 0, sizeof(struct empty_dir_info_struct));
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         free(edi);
86 }
87
88 void add_empty_dirblock(empty_dir_info edi,
89                         struct ext2_db_entry *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 %d (#%d) in inode %d\n"),
98                db->blk, db->blockcnt, db->ino);
99
100         ext2fs_mark_block_bitmap(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_block(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, blk_t *block_nr, e2_blkcnt_t blockcnt,
120                 blk_t ref_block, int ref_offset, void *priv_data)
121 {
122         empty_dir_info edi = (empty_dir_info) priv_data;
123         blk_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_bmap(fs, edi->ino, &edi->inode,
131                                      edi->block_buf, 0, edi->logblk,
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_bitmap(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_entry *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_iterate2(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                 edi->inode.i_blocks -= edi->freed_blocks *
172                         (fs->blocksize / 512);
173                 (void) ext2fs_write_inode(fs, db->ino, &edi->inode);
174         }
175         return 0;
176 }
177
178 void process_empty_dirblock(e2fsck_t ctx, empty_dir_info edi)
179 {
180         if (!edi)
181                 return;
182
183         edi->block_buf = malloc(ctx->fs->blocksize * 3);
184
185         if (edi->block_buf) {
186                 (void) ext2fs_dblist_iterate(edi->empty_dblist,
187                                              fix_directory, &edi);
188         }
189         free(edi->block_buf);
190         free_empty_dirblock(edi);
191 }
192