diff options
author | robi <robi> | 2010-05-20 00:15:01 +0000 |
---|---|---|
committer | robi <robi> | 2010-05-20 00:15:01 +0000 |
commit | 4efdf36026aa2c76ea8a0b8667598e49bde7b678 (patch) | |
tree | de14b911cf2fb2e77a8913b9fdce3c3348320ceb /src/inode.c |
Initial revision
Diffstat (limited to 'src/inode.c')
-rw-r--r-- | src/inode.c | 805 |
1 files changed, 805 insertions, 0 deletions
diff --git a/src/inode.c b/src/inode.c new file mode 100644 index 0000000..d617775 --- /dev/null +++ b/src/inode.c @@ -0,0 +1,805 @@ +/*************************************************************************** + * Copyright (C) 2010 by Roberto Maar * + * robi@users.berlios.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> + +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif + +#include "inode.h" +#include "ring_buf.h" + +extern ext2_filsys current_fs; + + + +// read real fs inode 128++ +int intern_read_inode_full(ext2_ino_t ino, struct ext2_inode * inode, int bufsize) +{ + int retval; + + retval = ext2fs_read_inode_full(current_fs, ino, inode, bufsize); + if (retval) { + fprintf(stderr,"Error %d while reading inode %u\n",retval, ino); + return 1; + } + return 0; +} + + +// read real fs inode 128 +int intern_read_inode(ext2_ino_t ino, struct ext2_inode * inode) +{ + int retval; + + retval = ext2fs_read_inode(current_fs, ino, inode); + if (retval) { + fprintf(stderr,"Error %d while reading inode %u\n",retval, ino); + return 1; + } + return 0; +} + + +//#ifdef WORDS_BIGENDIAN +// On my current version of libext2 the extra time fields ar not bigendian corrected +// We want this solved temporarily here with this function + static void le_to_cpu_swap_extra_time(struct ext2_inode_large *inode, char *inode_buf){ + //inode->i_pad1 = ext2fs_le16_to_cpu(((struct ext2_inode_large *))inode_buf->i_pad1); + inode->i_ctime_extra = ext2fs_le32_to_cpu(((struct ext2_inode_large *)inode_buf)->i_ctime_extra); + inode->i_mtime_extra = ext2fs_le32_to_cpu(((struct ext2_inode_large *)inode_buf)->i_mtime_extra ); + inode->i_atime_extra = ext2fs_le32_to_cpu(((struct ext2_inode_large *)inode_buf)->i_atime_extra ); + inode->i_crtime = ext2fs_le32_to_cpu(((struct ext2_inode_large *)inode_buf)->i_crtime ); + inode->i_crtime_extra = ext2fs_le32_to_cpu(((struct ext2_inode_large *)inode_buf)->i_crtime_extra ); + //inode->i_version_hi = ext2fs_le32_to_cpu(((struct ext2_inode_large *)inode_buf)->i_version_hi ); +} +//#endif + +//subfunction for dump_inode_extra +static void dump_xattr_string(FILE *out, const char *str, int len) +{ + int printable = 0; + int i; + + // check: is string "printable enough?" + for (i = 0; i < len; i++) + if (isprint(str[i])) + printable++; + + if (printable <= len*7/8) + printable = 0; + + for (i = 0; i < len; i++) + if (printable) + fprintf(out, isprint(str[i]) ? "%c" : "\\%03o", + (unsigned char)str[i]); + else + fprintf(out, "%02x ", (unsigned char)str[i]); +} + + +//print Blocks of inode (ext4) +static void local_dump_extents(FILE *f, const char *prefix, struct ext2_inode * inode, + int flags, int logical_width, int physical_width) +{ + ext2_extent_handle_t handle; + struct ext2fs_extent extent; + struct ext2_extent_info info; + int op = EXT2_EXTENT_ROOT; + unsigned int printed = 0; + errcode_t errcode; + + errcode = local_ext2fs_extent_open(current_fs, *inode, &handle); + if (errcode) + return; + + if (flags & DUMP_EXTENT_TABLE) + fprintf(f, "Level Entries %*s %*s Length Flags\n", + (logical_width*2)+3, "Logical", + (physical_width*2)+3, "Physical"); + else + fprintf(f, "%sEXTENTS:\n%s", prefix, prefix); + + while (1) { + errcode = ext2fs_extent_get(handle, op, &extent); + + if (errcode) + break; + + op = EXT2_EXTENT_NEXT; + + if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) + continue; + + if (extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) { + if ((flags & DUMP_LEAF_EXTENTS) == 0) + continue; + } else { + if ((flags & DUMP_NODE_EXTENTS) == 0) + continue; + } + + + errcode = ext2fs_extent_get_info(handle, &info); + if (errcode) + continue; + + if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) { + if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) + continue; + + if (flags & DUMP_EXTENT_TABLE) { + fprintf(f, "%2d/%2d %3d/%3d %*llu - %*llu " + "%*llu%*s %6u\n", + info.curr_level, info.max_depth, + info.curr_entry, info.num_entries, + logical_width, + extent.e_lblk, + logical_width, + extent.e_lblk + (extent.e_len - 1), + physical_width, + extent.e_pblk, + physical_width+3, "", extent.e_len); + continue; + } + + fprintf(f, "%s(NODE #%d, %lld-%lld, blk %lld)", + printed ? ", " : "", + info.curr_entry, + extent.e_lblk, + extent.e_lblk + (extent.e_len - 1), + extent.e_pblk); + printed = 1; + continue; + } + + if (flags & DUMP_EXTENT_TABLE) { + fprintf(f, "%2d/%2d %3d/%3d %*llu - %*llu " + "%*llu - %*llu %6u %s\n", + info.curr_level, info.max_depth, + info.curr_entry, info.num_entries, + logical_width, + extent.e_lblk, + logical_width, + extent.e_lblk + (extent.e_len - 1), + physical_width, + extent.e_pblk, + physical_width, + extent.e_pblk + (extent.e_len - 1), + extent.e_len, + extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT ? + "Uninit" : ""); + continue; + } + + if (extent.e_len == 0) + continue; + else if (extent.e_len == 1) + fprintf(f, + "%s(%lld%s): %lld", + printed ? ", " : "", + extent.e_lblk, + extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT ? + " [uninit]" : "", + extent.e_pblk); + else + fprintf(f, + "%s(%lld-%lld%s): %lld-%lld", + printed ? ", " : "", + extent.e_lblk, + extent.e_lblk + (extent.e_len - 1), + extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT ? + " [uninit]" : "", + extent.e_pblk, + extent.e_pblk + (extent.e_len - 1)); + printed = 1; + } + if (printed) + fprintf(f, "\n\n"); + local_ext2fs_extent_free(handle); + + +} + + +//print extended attribute of Inode +static void dump_inode_extra(FILE *out, + const char *prefix EXT2FS_ATTR((unused)), + ext2_ino_t inode_num EXT2FS_ATTR((unused)), + struct ext2_inode_large *inode) +{ + struct ext2_ext_attr_entry *entry; + __u32 *magic; + char *start, *end; + unsigned int storage_size; + + fprintf(out, "Size of extra inode fields: %u\n", inode->i_extra_isize); + if (inode->i_extra_isize > EXT2_INODE_SIZE(current_fs->super) - + EXT2_GOOD_OLD_INODE_SIZE) { + fprintf(stderr, "invalid inode->i_extra_isize (%u)\n", + inode->i_extra_isize); + return; + } + storage_size = EXT2_INODE_SIZE(current_fs->super) - + EXT2_GOOD_OLD_INODE_SIZE - + inode->i_extra_isize; + magic = (__u32 *)((char *)inode + EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize); + if (*magic == EXT2_EXT_ATTR_MAGIC) { + fprintf(out, "Extended attributes stored in inode body: \n"); + end = (char *) inode + EXT2_INODE_SIZE(current_fs->super); + start = (char *) magic + sizeof(__u32); + entry = (struct ext2_ext_attr_entry *) start; + while (!EXT2_EXT_IS_LAST_ENTRY(entry)) { + struct ext2_ext_attr_entry *next = + EXT2_EXT_ATTR_NEXT(entry); + if (entry->e_value_size > storage_size || + (char *) next >= end) { + fprintf(out, "invalid EA entry in inode\n"); + return; + } + fprintf(out, " "); + dump_xattr_string(out, EXT2_EXT_ATTR_NAME(entry), + entry->e_name_len); + fprintf(out, " = \""); + dump_xattr_string(out, start + entry->e_value_offs, + entry->e_value_size); + fprintf(out, "\" (%u)\n", entry->e_value_size); + entry = next; + } + } +} + + +//subfunction for dump_blocks +static void finish_range(struct list_blocks_struct *lb) +{ + if (lb->first_block == 0) + return; + if (lb->first) + lb->first = 0; + else + fprintf(lb->f, ", "); + if (lb->first_block == lb->last_block) + fprintf(lb->f, "(%lld):%u", + (long long)lb->first_bcnt, lb->first_block); + else + fprintf(lb->f, "(%lld-%lld):%u-%u", + (long long)lb->first_bcnt, (long long)lb->last_bcnt, + lb->first_block, lb->last_block); + lb->first_block = 0; +} + + +//subfunction for dump_blocks +static int list_blocks_proc(ext2_filsys fs EXT2FS_ATTR((unused)), + blk_t *blocknr, e2_blkcnt_t blockcnt, + blk_t ref_block EXT2FS_ATTR((unused)), + int ref_offset EXT2FS_ATTR((unused)), + void *private) +{ + struct list_blocks_struct *lb = (struct list_blocks_struct *) private; + + lb->total++; + if (blockcnt >= 0) { +//* See if we can add on to the existing range (if it exists) + if (lb->first_block && + (lb->last_block+1 == *blocknr) && + (lb->last_bcnt+1 == blockcnt)) { + lb->last_block = *blocknr; + lb->last_bcnt = blockcnt; + return 0; + } +//* Start a new range. + finish_range(lb); + lb->first_block = lb->last_block = *blocknr; + lb->first_bcnt = lb->last_bcnt = blockcnt; + return 0; + } +//* Not a normal block. Always force a new range. + finish_range(lb); + if (lb->first) + lb->first = 0; + else + fprintf(lb->f, ", "); + if (blockcnt == -1) + fprintf(lb->f, "(IND):%u", *blocknr); + else if (blockcnt == -2) + fprintf(lb->f, "(DIND):%u", *blocknr); + else if (blockcnt == -3) + fprintf(lb->f, "(TIND):%u", *blocknr); + return 0; +} + + +// print the Datablocks from Inode (ext3) +static void dump_blocks(FILE *f, const char *prefix, struct ext2_inode *inode) +{ + struct list_blocks_struct lb; + + fprintf(f, "%sBLOCKS:\n%s", prefix, prefix); + lb.total = 0; + lb.first_block = 0; + lb.f = f; + lb.first = 1; + // ext2fs_block_iterate2(current_fs, inode, BLOCK_FLAG_READ_ONLY, NULL, + local_block_iterate3(current_fs, *inode, BLOCK_FLAG_READ_ONLY, NULL, + list_blocks_proc, (void *)&lb); + finish_range(&lb); + if (lb.total) + fprintf(f, "\n%sTOTAL: %lld\n", prefix, (long long)lb.total); + fprintf(f,"\n"); +} + + +//print the contents of inode +void dump_inode(FILE *out, const char *prefix, + ext2_ino_t inode_num, struct ext2_inode *inode, + int do_dump_blocks) +{ + const char *i_type; + char frag, fsize; + int os = current_fs->super->s_creator_os; + struct ext2_inode_large *large_inode; + int is_large_inode = 0; + + if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE) + is_large_inode = 1; + large_inode = (struct ext2_inode_large *) inode; +// blockhex(stdout,large_inode,0,256); + + if (LINUX_S_ISDIR(inode->i_mode)) i_type = "directory"; + else if (LINUX_S_ISREG(inode->i_mode)) i_type = "regular"; + else if (LINUX_S_ISLNK(inode->i_mode)) i_type = "symlink"; + else if (LINUX_S_ISBLK(inode->i_mode)) i_type = "block special"; + else if (LINUX_S_ISCHR(inode->i_mode)) i_type = "character special"; + else if (LINUX_S_ISFIFO(inode->i_mode)) i_type = "FIFO"; + else if (LINUX_S_ISSOCK(inode->i_mode)) i_type = "socket"; + else i_type = "bad type"; + fprintf(out, "%sInode: %u Type: %s ", prefix, inode_num, i_type); + fprintf(out, "%sMode: %04o Flags: 0x%x\n", + prefix, inode->i_mode & 0777, inode->i_flags); + if (is_large_inode && large_inode->i_extra_isize >= 24) { + fprintf(out, "%sGeneration: %u Version: 0x%08x:%08x\n", + prefix, inode->i_generation, large_inode->i_version_hi, + inode->osd1.linux1.l_i_version); + } else { + fprintf(out, "%sGeneration: %u Version: 0x%08x\n", prefix, + inode->i_generation, inode->osd1.linux1.l_i_version); + } + fprintf(out, "%sUser: %5d Group: %5d Size: ", + prefix, inode_uid(*inode), inode_gid(*inode)); + if (LINUX_S_ISREG(inode->i_mode)) { + unsigned long long i_size = (inode->i_size | + ((unsigned long long)inode->i_size_high << 32)); + + fprintf(out, "%llu\n", i_size); + } else + fprintf(out, "%d\n", inode->i_size); + if (os == EXT2_OS_HURD) + fprintf(out, + "%sFile ACL: %d Directory ACL: %d Translator: %d\n", + prefix, + inode->i_file_acl, LINUX_S_ISDIR(inode->i_mode) ? inode->i_dir_acl : 0, + inode->osd1.hurd1.h_i_translator); + else + fprintf(out, "%sFile ACL: %llu Directory ACL: %d\n", + prefix, + inode->i_file_acl | ((long long) + (inode->osd2.linux2.l_i_file_acl_high) << 32), + LINUX_S_ISDIR(inode->i_mode) ? inode->i_dir_acl : 0); + if (os == EXT2_OS_LINUX) + fprintf(out, "%sLinks: %d Blockcount: %llu\n", + prefix, inode->i_links_count, + (((unsigned long long) + inode->osd2.linux2.l_i_blocks_hi << 32)) + + inode->i_blocks); + else + fprintf(out, "%sLinks: %d Blockcount: %u\n", + prefix, inode->i_links_count, inode->i_blocks); + switch (os) { + case EXT2_OS_HURD: + frag = inode->osd2.hurd2.h_i_frag; + fsize = inode->osd2.hurd2.h_i_fsize; + break; + default: + frag = fsize = 0; + } + fprintf(out, "%sFragment: Address: %d Number: %d Size: %d\n", + prefix, inode->i_faddr, frag, fsize); + if (is_large_inode && large_inode->i_extra_isize >= 24) { + fprintf(out, "%s ctime: %10lu:%010lu -- %s", prefix, + inode->i_ctime, large_inode->i_ctime_extra, + time_to_string(inode->i_ctime)); + fprintf(out, "%s atime: %10lu:%010lu -- %s", prefix, + inode->i_atime, large_inode->i_atime_extra, + time_to_string(inode->i_atime)); + fprintf(out, "%s mtime: %10lu:%010lu -- %s", prefix, + inode->i_mtime, large_inode->i_mtime_extra, + time_to_string(inode->i_mtime)); + fprintf(out, "%scrtime: %10lu:%010lu -- %s", prefix, + large_inode->i_crtime, large_inode->i_crtime_extra, + time_to_string(large_inode->i_crtime)); + } else { + fprintf(out, "%sctime: %10lu -- %s", prefix, inode->i_ctime, + time_to_string(inode->i_ctime)); + fprintf(out, "%satime: %10lu -- %s", prefix, inode->i_atime, + time_to_string(inode->i_atime)); + fprintf(out, "%smtime: %10lu -- %s", prefix, inode->i_mtime, + time_to_string(inode->i_mtime)); + } + if (inode->i_dtime) + fprintf(out, "%sdtime: %10lu -- %s", prefix, inode->i_dtime, + time_to_string(inode->i_dtime)); + if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE) + dump_inode_extra(out, prefix, inode_num, + (struct ext2_inode_large *) inode); + if (LINUX_S_ISLNK(inode->i_mode) && ext2fs_inode_data_blocks(current_fs,inode) == 0) + fprintf(out, "%sFast_link_dest: %.*s\n\n", prefix, + (int) inode->i_size, (char *)inode->i_block); + else if (LINUX_S_ISBLK(inode->i_mode) || LINUX_S_ISCHR(inode->i_mode)) { + int major, minor; + const char *devnote; + + if (inode->i_block[0]) { + major = (inode->i_block[0] >> 8) & 255; + minor = inode->i_block[0] & 255; + devnote = ""; + } else { + major = (inode->i_block[1] & 0xfff00) >> 8; + minor = ((inode->i_block[1] & 0xff) | + ((inode->i_block[1] >> 12) & 0xfff00)); + devnote = "(New-style) "; + } + fprintf(out, "%sDevice major/minor number: %02d:%02d (hex %02x:%02x)\n\n", + devnote, major, minor, major, minor); + } else if (do_dump_blocks) { + if (inode->i_flags & EXT4_EXTENTS_FL) + local_dump_extents(out, prefix, inode, + DUMP_LEAF_EXTENTS, 0, 0); + else + dump_blocks(out, prefix, inode); + } +} + + +//calculate the position of inode in FS +blk_t get_inode_pos(struct ext2_super_block *es ,struct inode_pos_struct *pos, ext2_ino_t inode_nr,int flag){ + + __u32 inode_group, group_offset, inodes_per_block, inode_offset; + blk_t inode_block; + + pos->size = EXT2_INODE_SIZE(current_fs->super); + inode_group = ((inode_nr - 1) / es->s_inodes_per_group); + group_offset = ((inode_nr - 1) % es->s_inodes_per_group); + inodes_per_block = (current_fs->blocksize / pos->size ); + + inode_block = current_fs->group_desc[inode_group].bg_inode_table + (group_offset / inodes_per_block); + inode_offset = ((group_offset % inodes_per_block) * pos->size ); + if (flag) + printf("Inode %u is at group %u, block %u, offset %u\n", inode_nr, inode_group, inode_block, inode_offset); + + pos->block = inode_block; + pos->offset = inode_offset; + + return inode_block; +}; + + +// get journalinode from transactionnumber +int get_transaction_inode(ext2_ino_t inode_nr, int transaction_nr, struct ext2_inode_large *inode){ + struct inode_pos_struct pos; + __u32 journal_block; + blk_t block_nr; + struct ext2_inode_large *inode_buf; + char *buf = NULL; + int got,retval = 0; + int blocksize = current_fs->blocksize; + + block_nr = get_inode_pos(current_fs->super, &pos , inode_nr, 0); + journal_block = get_journal_blocknr(block_nr, transaction_nr); + if (! journal_block){ + fprintf(stdout,"No journalblock found for inode %u by transaction %u\n",inode_nr,transaction_nr); + retval = -1; + } + else { + buf =(char*) malloc(blocksize); + if(buf){ + //inode = (struct ext2_inode_large *)(buf + blocksize); + retval = read_journal_block(journal_block * blocksize ,buf,blocksize,&got); + if ((! retval) && (got == blocksize)){ + inode_buf = (struct ext2_inode_large *)(buf + pos.offset); +#ifdef WORDS_BIGENDIAN + memset(inode, 0, pos.size); + ext2fs_swap_inode_full(current_fs, inode, inode_buf, 0, pos.size); + + if ((pos.size > EXT2_GOOD_OLD_INODE_SIZE) && (inode->i_extra_isize >= 24) + && (ext2fs_le32_to_cpu(inode_buf->i_crtime ) != inode->i_crtime)){ +//FIXME: On my current version of libext2 the extra time fields ar not bigendian corrected + // We solved this temporarily here with this function + le_to_cpu_swap_extra_time(inode,(char*)inode_buf); + } +#else + memcpy(inode, inode_buf, pos.size); +#endif + } + free(buf); + } + } +return retval; +} + + +//function for dump_inode_list +void print_j_inode(struct ext2_inode_large *inode , ext2_ino_t inode_nr , __u32 transaction , int flag){ + fprintf(stdout,"\nDump Inode %d from journal transaction %d\n",inode_nr,transaction); + dump_inode(stdout, "",inode_nr, (struct ext2_inode *)inode, flag); +return ; +} + + + +//print the contents of all copy of inode in the journal +void dump_inode_list(struct ring_buf* buf, int flag){ + r_item* item; + int i, count; + + if (!buf ) return; + item = r_first(buf); + + count = r_get_count(buf); + for (i = 0; i < count ; i++){ + print_j_inode(item->inode , buf->nr , item->transaction.start, flag); + if ( LINUX_S_ISDIR(item->inode->i_mode)) + list_dir3(buf->nr, (struct ext2_inode*)item->inode, &(item->transaction)); + item = r_next(item); + } +return; +} + + +// return the last undeleted inode in journal +r_item* get_last_undel_inode(struct ring_buf* buf){ + r_item* item; + int i, count; +// __u32 generation; + + if (!buf ) return NULL; + item = r_last(buf); + + count = r_get_count(buf); + for (i = 0; i< count; i++){ +// if ( !i ) generation = item->inode->i_generation; + if (item->inode->i_dtime) { +// buf->del_flag = 1; + item = r_prev(item); + } + else { +// if (item->inode->i_generation != generation) +// buf->reuse_flag = 1; + return item; + } + } + return NULL; +} + + +// return the last undelete inode in journal after -> <-before + r_item* get_undel_inode(struct ring_buf* buf, __u32 after, __u32 before){ + r_item* item; + int i, count; + __u32 generation; + + if (!buf) return NULL; + item = r_last(buf); + + count = r_get_count(buf); + for (i = 0; i< count; i++){ +// if ( !i ) generation = item->inode->i_generation; + if ((item->inode->i_dtime) && (item->inode->i_dtime < after) ) + return NULL; + if ((item->inode->i_ctime >= before ) || (item->inode->i_dtime)) { +// if (item->inode->i_dtime) +// buf->del_flag = 1 ; + item = r_prev(item); + continue; + } +// if (item->inode->i_generation != generation) +// buf->reuse_flag = 1; + return item; + } + return NULL; +} + + +//fill all inode found in the Journal in the inode-ringbuffer +struct ring_buf* get_j_inode_list(struct ext2_super_block *es, ext2_ino_t inode_nr){ + struct inode_pos_struct pos; + blk_t block; + char * inode_buf = NULL ; + struct ext2_inode *inode_pointer; + struct ring_buf* buf = NULL; + r_item *item = NULL; +// struct ext2_inode_large *inode = NULL; + int count, got, retval = 0; + off_t offset; + char *journal_tag_buf = NULL; + journal_descriptor_tag_t *block_list; + __u32 ctime = 1; + __u32 same_size = 1; + __u16 same_link_count = 0; + + if ((inode_nr > es->s_inodes_count) || (inode_nr == 0)) + { + printf(" unknown ERROR: bad inode number found %d \n", inode_nr ); + return NULL; + } + + block = get_inode_pos(es , &pos , inode_nr, 0); + inode_buf = malloc(pos.size); + if (!inode_buf) { + fprintf(stderr,"Error: can not allocate memory for buffer\n"); + goto errout; + } + count = get_block_list_count(block) ; + + if(! count) { +// no inode block found +// then we will load the oginal inode from the filesystem +// we will hope, the file has not change for a long time + buf = ring_new(pos.size,inode_nr); + if (buf) + item = r_item_add(buf); + if ( ! item) + { + fprintf(stderr,"Error: can not allocate memory for inode\n"); + goto errout; + } + if ( ext2fs_read_inode_full(current_fs, inode_nr, (struct ext2_inode*) item->inode, pos.size)) + goto errout; + item->transaction.start = item->transaction.end = 0; + } + else { + +// read and fill the journal inode + journal_tag_buf = (void *)malloc((sizeof(journal_descriptor_tag_t) * count)); + if (!journal_tag_buf) { + fprintf(stderr,"Error: while allocate Memory for blocklist\n"); + goto errout; + } + block_list = (journal_descriptor_tag_t *) journal_tag_buf; + + count = get_block_list(block_list, block, count); + buf = ring_new(pos.size,inode_nr); + if ((! buf) || (! count)) goto errout; + + for (;count > 0;count-- , block_list++ ){ + offset = (block_list->j_blocknr * current_fs->blocksize) + pos.offset ; + retval = read_journal_block( offset , inode_buf , pos.size , &got); + if (retval) { + fprintf(stderr,"Error: while read Inode %d from journal transaction %d\n", inode_nr, block_list->transaction); + goto errout; + } + + inode_pointer = (struct ext2_inode*) inode_buf ; +//FIXME: check more bad Inode + if (get_inode_mode_type(ext2fs_le16_to_cpu(inode_pointer->i_mode)) == ' '){ +#ifdef DEBUG + fprintf(stdout,"Transaction %d has a bad Inode, skip\n",block_list->transaction); +#endif + continue; + } +//inode with the same ctime and the same size an links, skipped + if (ext2fs_le32_to_cpu(inode_pointer->i_ctime) == ctime){ + if (item) { + if ((ext2fs_le32_to_cpu(inode_pointer->i_size) == same_size) && + (ext2fs_le16_to_cpu(inode_pointer->i_links_count == same_link_count))){ + item->transaction.end = block_list->transaction; + continue; + } + } + } + + item = r_item_add(buf); + if ( ! item) + { + fprintf(stderr,"Error: can not allocate memory for inode\n"); + goto errout; + } + +#ifdef WORDS_BIGENDIAN + memset(item->inode, 0, pos.size); + + ext2fs_swap_inode_full(current_fs, + (struct ext2_inode_large *) item->inode, + (struct ext2_inode_large *) inode_buf, + 0, pos.size); + + if ((pos.size > EXT2_GOOD_OLD_INODE_SIZE) && (item->inode->i_extra_isize >= 24) + && (ext2fs_le32_to_cpu(((struct ext2_inode_large *)inode_buf)->i_crtime) != item->inode->i_crtime)){ +//FIXME: On my current version of libext2 the extra time fields ar not bigendian corrected + // We solved this temporarily here with this function + le_to_cpu_swap_extra_time(item->inode,(char*)inode_buf); + } +#else + memcpy(item->inode, inode_buf, pos.size); +#endif + item->transaction.start = block_list->transaction; + item->transaction.end = block_list->transaction; + ctime = item->inode->i_ctime; + same_size = item->inode->i_size; + same_link_count = item->inode->i_links_count; + } + } // else-tree ? count==0 + + if (buf->count == 0) + goto errout; + + if ( inode_buf ) { + free(inode_buf); + inode_buf = NULL; + } + if ( journal_tag_buf ) { + free(journal_tag_buf); + journal_tag_buf = NULL; + } + r_begin(buf); + return buf; + +errout: + if ( inode_buf ) { + free(inode_buf); + inode_buf = NULL; + } + if ( journal_tag_buf ) { + free(journal_tag_buf); + journal_tag_buf = NULL; + } + + if ( buf ) { + ring_del(buf); + buf = NULL; + } + return NULL; +} + + + +// get the first Journal Inode by transaction +int read_journal_inode( ext2_ino_t inode_nr, struct ext2_inode* inode_buf, __u32 transaction){ + struct ring_buf* i_ring; + r_item* item; + int retval = 1; + + i_ring = get_j_inode_list(current_fs->super, inode_nr); + if (i_ring) { + item = r_first(i_ring); + while ((item->transaction.start < transaction) && ( item != r_last(i_ring))) + item = r_next(item); + memcpy(inode_buf,item->inode,EXT2_GOOD_OLD_INODE_SIZE); + ring_del(i_ring); + retval= 0; + } +return retval; +} |