1f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o/* 2f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * emptydir.c --- clear empty directory blocks 3efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * 4f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * Copyright (C) 1998 Theodore Ts'o 5f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * 6f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * %Begin-Header% 7f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * This file may be redistributed under the terms of the GNU Public 8f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * License. 9f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * %End-Header% 10f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * 11f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * This file has the necessary routines to search for empty directory 12f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * blocks and get rid of them. 13f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o */ 14f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 15f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o#include "e2fsck.h" 16f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o#include "problem.h" 17f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 18f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o/* 19f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * For e2fsck.h 20f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o */ 21f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'ostruct empty_dir_info_struct { 22f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o ext2_dblist empty_dblist; 23f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o ext2fs_block_bitmap empty_dir_blocks; 24f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o ext2fs_inode_bitmap dir_map; 25f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o char *block_buf; 2686c627ec1136446409a0170d439e60c148e6eb48Theodore Ts'o ext2_ino_t ino; 27f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o struct ext2_inode inode; 28e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall blk64_t logblk; 29e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall blk64_t freed_blocks; 30f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o}; 31f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 32f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'otypedef struct empty_dir_info_struct *empty_dir_info; 33f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 34f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'oextern empty_dir_info init_empty_dir(e2fsck_t ctx); 35f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'oextern void free_empty_dirblock(empty_dir_info edi); 36f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'oextern void add_empty_dirblock(empty_dir_info edi, 37e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall struct ext2_db_entry2 *db); 38f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'oextern void process_empty_dirblock(e2fsck_t ctx, empty_dir_info edi); 39f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 40f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 41f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'oempty_dir_info init_empty_dir(e2fsck_t ctx) 42f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o{ 43f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o empty_dir_info edi; 44f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o errcode_t retval; 45f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 46f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o edi = malloc(sizeof(struct empty_dir_info_struct)); 47f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (!edi) 48f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o return NULL; 49f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 50f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o memset(edi, 0, sizeof(struct empty_dir_info_struct)); 51f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 52f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o retval = ext2fs_init_dblist(ctx->fs, &edi->empty_dblist); 53f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (retval) 54f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o goto errout; 55efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 560c4a07264e55b42c6e30230e66b1dea7d4b94ea9Theodore Ts'o retval = ext2fs_allocate_block_bitmap(ctx->fs, _("empty dirblocks"), 57f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o &edi->empty_dir_blocks); 58f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (retval) 59f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o goto errout; 60f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 610c4a07264e55b42c6e30230e66b1dea7d4b94ea9Theodore Ts'o retval = ext2fs_allocate_inode_bitmap(ctx->fs, _("empty dir map"), 62f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o &edi->dir_map); 63f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (retval) 64f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o goto errout; 65f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 66f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o return (edi); 67f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 68f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'oerrout: 69f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o free_empty_dirblock(edi); 70f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o return NULL; 71f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o} 72f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 73f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'ovoid free_empty_dirblock(empty_dir_info edi) 74f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o{ 75f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (!edi) 76f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o return; 77f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (edi->empty_dblist) 78f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o ext2fs_free_dblist(edi->empty_dblist); 79f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (edi->empty_dir_blocks) 80f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o ext2fs_free_block_bitmap(edi->empty_dir_blocks); 81f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (edi->dir_map) 82f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o ext2fs_free_inode_bitmap(edi->dir_map); 83f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 84f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o memset(edi, 0, sizeof(struct empty_dir_info_struct)); 85f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o free(edi); 86f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o} 87f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 88f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'ovoid add_empty_dirblock(empty_dir_info edi, 89e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall struct ext2_db_entry2 *db) 90f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o{ 91f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (!edi || !db) 92f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o return; 93f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 94f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (db->ino == 11) 95f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o return; /* Inode number 11 is usually lost+found */ 96f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 97d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen printf(_("Empty directory block %u (#%d) in inode %u\n"), 98f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o db->blk, db->blockcnt, db->ino); 99f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 100e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall ext2fs_mark_block_bitmap2(edi->empty_dir_blocks, db->blk); 101f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (ext2fs_test_inode_bitmap(edi->dir_map, db->ino)) 102f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o return; 103f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o ext2fs_mark_inode_bitmap(edi->dir_map, db->ino); 104f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 105e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall ext2fs_add_dir_block2(edi->empty_dblist, db->ino, 106e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall db->blk, db->blockcnt); 107f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o} 108f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 109f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o/* 110f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * Helper function used by fix_directory. 111f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * 112f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * XXX need to finish this. General approach is to use bmap to 113f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * iterate over all of the logical blocks using the bmap function, and 114f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * copy the block reference as necessary. Big question --- what do 115f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * about error recovery? 116f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * 117f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o * Also question --- how to free the indirect blocks. 118f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o */ 119e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallint empty_pass1(ext2_filsys fs, blk64_t *block_nr, e2_blkcnt_t blockcnt, 120e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall blk64_t ref_block, int ref_offset, void *priv_data) 121f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o{ 122f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o empty_dir_info edi = (empty_dir_info) priv_data; 123e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall blk64_t block, new_block; 124f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o errcode_t retval; 125efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 126f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (blockcnt < 0) 127f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o return 0; 128f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o block = *block_nr; 129f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o do { 130e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall retval = ext2fs_bmap2(fs, edi->ino, &edi->inode, 131e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall edi->block_buf, 0, edi->logblk, 0, 132e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall &new_block); 133f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (retval) 134f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o return DIRENT_ABORT; /* XXX what to do? */ 135f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (new_block == 0) 136f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o break; 137f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o edi->logblk++; 138e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall } while (ext2fs_test_block_bitmap2(edi->empty_dir_blocks, new_block)); 139f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 140f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (new_block == block) 141f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o return 0; 142f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (new_block == 0) 143f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o edi->freed_blocks++; 144f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o *block_nr = new_block; 145f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o return BLOCK_CHANGED; 146f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o} 147f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 148f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'ostatic int fix_directory(ext2_filsys fs, 149e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall struct ext2_db_entry2 *db, 150f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o void *priv_data) 151f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o{ 152f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o errcode_t retval; 153efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 154f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o empty_dir_info edi = (empty_dir_info) priv_data; 155f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 156f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o edi->logblk = 0; 157f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o edi->freed_blocks = 0; 158f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o edi->ino = db->ino; 159f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 160f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o retval = ext2fs_read_inode(fs, db->ino, &edi->inode); 161f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (retval) 162f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o return 0; 163f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 164e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall retval = ext2fs_block_iterate3(fs, db->ino, 0, edi->block_buf, 165f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o empty_pass1, edi); 166f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (retval) 167f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o return 0; 168f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 169f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (edi->freed_blocks) { 170f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o edi->inode.i_size -= edi->freed_blocks * fs->blocksize; 1711ca1059fd0126fd2c065f272a566c18f14bab16dTheodore Ts'o ext2fs_iblk_add_blocks(fs, &edi->inode, edi->freed_blocks); 172d2b2a488f996871e6e40789a7890afc2f59730dbBrian Behlendorf retval = ext2fs_write_inode(fs, db->ino, &edi->inode); 173d2b2a488f996871e6e40789a7890afc2f59730dbBrian Behlendorf if (retval) 174d2b2a488f996871e6e40789a7890afc2f59730dbBrian Behlendorf return 0; 175f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o } 176f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o return 0; 177f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o} 178f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 179f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'ovoid process_empty_dirblock(e2fsck_t ctx, empty_dir_info edi) 180f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o{ 181f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (!edi) 182f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o return; 183f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 184f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o edi->block_buf = malloc(ctx->fs->blocksize * 3); 185f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 186f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o if (edi->block_buf) { 187e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall (void) ext2fs_dblist_iterate2(edi->empty_dblist, 188e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall fix_directory, &edi); 189f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o } 190f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o free(edi->block_buf); 191f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o free_empty_dirblock(edi); 192f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o} 193f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o 194