mirror of
https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git
synced 2024-12-29 03:40:06 +08:00
f75c28de47
pass2.c (e2fsck_pass2): Fix the progress accounting so that we get to 100%. pass3.c (e2fsck_pass3): Change progress accounting to be consistent with the other e2fsck passes. e2fsck.c (e2fsck_run): At the end of each pass, call the progress function with the pass number set to zero. unix.c (e2fsck_update_progress): If the pass number is zero, ignore the call, since that indicates that we just want to deallocate any progress structures. emptydir.c: Commit partially done file. ChangeLog, badblocks.c: badblocks.c (ext2fs_badblocks_list_add): Use a bigger increment than 10 blocks when we need to expand the size of the badblocks list.
193 lines
4.3 KiB
C
193 lines
4.3 KiB
C
/*
|
|
* emptydir.c --- clear empty directory blocks
|
|
*
|
|
* Copyright (C) 1998 Theodore Ts'o
|
|
*
|
|
* %Begin-Header%
|
|
* This file may be redistributed under the terms of the GNU Public
|
|
* License.
|
|
* %End-Header%
|
|
*
|
|
* This file has the necessary routines to search for empty directory
|
|
* blocks and get rid of them.
|
|
*/
|
|
|
|
#include "e2fsck.h"
|
|
#include "problem.h"
|
|
|
|
/*
|
|
* For e2fsck.h
|
|
*/
|
|
struct empty_dir_info_struct {
|
|
ext2_dblist empty_dblist;
|
|
ext2fs_block_bitmap empty_dir_blocks;
|
|
ext2fs_inode_bitmap dir_map;
|
|
char *block_buf;
|
|
ino_t ino;
|
|
struct ext2_inode inode;
|
|
blk_t logblk;
|
|
blk_t freed_blocks;
|
|
};
|
|
|
|
typedef struct empty_dir_info_struct *empty_dir_info;
|
|
|
|
extern empty_dir_info init_empty_dir(e2fsck_t ctx);
|
|
extern void free_empty_dirblock(empty_dir_info edi);
|
|
extern void add_empty_dirblock(empty_dir_info edi,
|
|
struct ext2_db_entry *db);
|
|
extern void process_empty_dirblock(e2fsck_t ctx, empty_dir_info edi);
|
|
|
|
|
|
empty_dir_info init_empty_dir(e2fsck_t ctx)
|
|
{
|
|
empty_dir_info edi;
|
|
errcode_t retval;
|
|
|
|
edi = malloc(sizeof(struct empty_dir_info_struct));
|
|
if (!edi)
|
|
return NULL;
|
|
|
|
memset(edi, 0, sizeof(struct empty_dir_info_struct));
|
|
|
|
retval = ext2fs_init_dblist(ctx->fs, &edi->empty_dblist);
|
|
if (retval)
|
|
goto errout;
|
|
|
|
retval = ext2fs_allocate_block_bitmap(ctx->fs, "empty dirblocks",
|
|
&edi->empty_dir_blocks);
|
|
if (retval)
|
|
goto errout;
|
|
|
|
retval = ext2fs_allocate_inode_bitmap(ctx->fs, "empty dir map",
|
|
&edi->dir_map);
|
|
if (retval)
|
|
goto errout;
|
|
|
|
return (edi);
|
|
|
|
errout:
|
|
free_empty_dirblock(edi);
|
|
return NULL;
|
|
}
|
|
|
|
void free_empty_dirblock(empty_dir_info edi)
|
|
{
|
|
if (!edi)
|
|
return;
|
|
if (edi->empty_dblist)
|
|
ext2fs_free_dblist(edi->empty_dblist);
|
|
if (edi->empty_dir_blocks)
|
|
ext2fs_free_block_bitmap(edi->empty_dir_blocks);
|
|
if (edi->dir_map)
|
|
ext2fs_free_inode_bitmap(edi->dir_map);
|
|
|
|
memset(edi, 0, sizeof(struct empty_dir_info_struct));
|
|
free(edi);
|
|
}
|
|
|
|
void add_empty_dirblock(empty_dir_info edi,
|
|
struct ext2_db_entry *db)
|
|
{
|
|
if (!edi || !db)
|
|
return;
|
|
|
|
if (db->ino == 11)
|
|
return; /* Inode number 11 is usually lost+found */
|
|
|
|
printf("Empty directory block %d (#%d) in inode %d\n",
|
|
db->blk, db->blockcnt, db->ino);
|
|
|
|
ext2fs_mark_block_bitmap(edi->empty_dir_blocks, db->blk);
|
|
if (ext2fs_test_inode_bitmap(edi->dir_map, db->ino))
|
|
return;
|
|
ext2fs_mark_inode_bitmap(edi->dir_map, db->ino);
|
|
|
|
ext2fs_add_dir_block(edi->empty_dblist, db->ino,
|
|
db->blk, db->blockcnt);
|
|
}
|
|
|
|
/*
|
|
* Helper function used by fix_directory.
|
|
*
|
|
* XXX need to finish this. General approach is to use bmap to
|
|
* iterate over all of the logical blocks using the bmap function, and
|
|
* copy the block reference as necessary. Big question --- what do
|
|
* about error recovery?
|
|
*
|
|
* Also question --- how to free the indirect blocks.
|
|
*/
|
|
int empty_pass1(ext2_filsys fs, blk_t *block_nr, e2_blkcnt_t blockcnt,
|
|
blk_t ref_block, int ref_offset, void *priv_data)
|
|
{
|
|
empty_dir_info edi = (empty_dir_info) priv_data;
|
|
blk_t block, new_block;
|
|
errcode_t retval;
|
|
|
|
if (blockcnt < 0)
|
|
return 0;
|
|
block = *block_nr;
|
|
do {
|
|
retval = ext2fs_bmap(fs, edi->ino, &edi->inode,
|
|
edi->block_buf, 0, edi->logblk,
|
|
&new_block);
|
|
if (retval)
|
|
return DIRENT_ABORT; /* XXX what to do? */
|
|
if (new_block == 0)
|
|
break;
|
|
edi->logblk++;
|
|
} while (ext2fs_test_block_bitmap(edi->empty_dir_blocks, new_block));
|
|
|
|
if (new_block == block)
|
|
return 0;
|
|
if (new_block == 0)
|
|
edi->freed_blocks++;
|
|
*block_nr = new_block;
|
|
return BLOCK_CHANGED;
|
|
}
|
|
|
|
static int fix_directory(ext2_filsys fs,
|
|
struct ext2_db_entry *db,
|
|
void *priv_data)
|
|
{
|
|
errcode_t retval;
|
|
|
|
empty_dir_info edi = (empty_dir_info) priv_data;
|
|
|
|
edi->logblk = 0;
|
|
edi->freed_blocks = 0;
|
|
edi->ino = db->ino;
|
|
|
|
retval = ext2fs_read_inode(fs, db->ino, &edi->inode);
|
|
if (retval)
|
|
return 0;
|
|
|
|
retval = ext2fs_block_iterate2(fs, db->ino, 0, edi->block_buf,
|
|
empty_pass1, edi);
|
|
if (retval)
|
|
return 0;
|
|
|
|
if (edi->freed_blocks) {
|
|
edi->inode.i_size -= edi->freed_blocks * fs->blocksize;
|
|
edi->inode.i_blocks -= edi->freed_blocks *
|
|
(fs->blocksize / 512);
|
|
(void) ext2fs_write_inode(fs, db->ino, &edi->inode);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void process_empty_dirblock(e2fsck_t ctx, empty_dir_info edi)
|
|
{
|
|
if (!edi)
|
|
return;
|
|
|
|
edi->block_buf = malloc(ctx->fs->blocksize * 3);
|
|
|
|
if (edi->block_buf) {
|
|
(void) ext2fs_dblist_iterate(edi->empty_dblist,
|
|
fix_directory, &edi);
|
|
}
|
|
free(edi->block_buf);
|
|
free_empty_dirblock(edi);
|
|
}
|
|
|