diff options
Diffstat (limited to 'resize/banalysis.c')
-rw-r--r-- | resize/banalysis.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/resize/banalysis.c b/resize/banalysis.c new file mode 100644 index 00000000..233158b6 --- /dev/null +++ b/resize/banalysis.c @@ -0,0 +1,141 @@ +/* + * banalysis.c --- Analyze a filesystem for a block struct + * + * Copyright (C) 1997 Theodore Ts'o. This file may be redistributed + * under the terms of the GNU Public License. + */ + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/time.h> + +#ifdef HAVE_LINUX_FS_H +#include <linux/fs.h> +#endif +#include <linux/ext2_fs.h> + +#include "ext2fs/ext2fs.h" + +#include "ext2fs/brel.h" +#include "banalysis.h" + +struct process_block_struct { + struct ext2_block_analyzer_funcs *funcs; + struct ext2_inode_context *ctx; + void *private; +}; + +/* + * This function returns 1 if the inode's block entries actually + * contain block entries. + */ +static int inode_has_valid_blocks(struct ext2_inode *inode) +{ + /* + * Only directories, regular files, and some symbolic links + * have valid block entries. + */ + if (!LINUX_S_ISDIR(inode->i_mode) && !LINUX_S_ISREG(inode->i_mode) && + !LINUX_S_ISLNK(inode->i_mode)) + return 0; + + /* + * If the symbolic link is a "fast symlink", then the symlink + * target is stored in the block entries. + */ + if (LINUX_S_ISLNK (inode->i_mode) && inode->i_blocks == 0 && + inode->i_size < EXT2_N_BLOCKS * sizeof (unsigned long)) + return 0; + + return 1; +} + +static int process_block(ext2_filsys fs, blk_t *block_nr, + int blockcnt, blk_t ref_block, + int ref_offset, void *private) +{ + struct process_block_struct *pb = private; + blk_t new_block; + struct ext2_block_relocate_entry ent; + + if (ref_block == 0) + ref_offset = blockcnt; + + new_block = pb->funcs->block_analyze(fs, *block_nr, ref_block, + ref_offset, pb->ctx, pb->private); + if (new_block) { + ent.new = new_block; + ent.offset = ref_offset; + if (ref_block) { + ent.owner.block_ref = ref_block; + ent.flags = 0; + } else { + ent.owner.inode_ref = pb->ctx->ino; + ent.flags = RELOCATE_INODE_REF; + } + ext2fs_brel_put(pb->ctx->brel, *block_nr, &ent); + } + return 0; +} + +errcode_t ext2_block_analyze(ext2_filsys fs, + struct ext2_block_analyzer_funcs *funcs, + ext2_brel block_relocation_table, + void *private) +{ + ino_t ino; + struct ext2_inode inode; + errcode_t retval; + struct process_block_struct pb; + struct ext2_inode_context ctx; + ext2_inode_scan scan; + char *block_buf; + + retval = ext2fs_open_inode_scan(fs, 0, &scan); + if (retval) + return retval; + + pb.funcs = funcs; + pb.private = private; + pb.ctx = &ctx; + + block_buf = malloc(fs->blocksize * 3); + if (!block_buf) + return ENOMEM; + + retval = ext2fs_get_next_inode(scan, &ino, &inode); + if (retval) + return retval; + ctx.ctx = private; + ctx.brel = block_relocation_table; + while (ino) { + if ((inode.i_links_count == 0) || + !inode_has_valid_blocks(&inode)) + goto next; + + ctx.ino = ino; + ctx.inode = &inode; + ctx.error = 0; + + if (funcs->pre_analyze && + !(*funcs->pre_analyze)(fs, &ctx, private)) + goto next; + + retval = ext2fs_block_iterate2(fs, ino, 0, block_buf, + process_block, &pb); + if (retval) + return retval; + + if (funcs->post_analyze) + (funcs->post_analyze)(fs, &ctx, private); + + next: + retval = ext2fs_get_next_inode(scan, &ino, &inode); + if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) + goto next; + } + return 0; +} |