~ubuntu-branches/ubuntu/edgy/e2fsprogs/edgy

« back to all changes in this revision

Viewing changes to e2fsck/emptydir.c

  • Committer: Bazaar Package Importer
  • Author(s): Yann Dirson
  • Date: 2002-03-21 23:58:48 UTC
  • Revision ID: james.westby@ubuntu.com-20020321235848-cmmy98hy0nihp922
Tags: upstream-1.27
ImportĀ upstreamĀ versionĀ 1.27

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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