summaryrefslogtreecommitdiff
path: root/src/inode.c
diff options
context:
space:
mode:
authorrobi <robi>2010-05-20 00:15:01 +0000
committerrobi <robi>2010-05-20 00:15:01 +0000
commit4efdf36026aa2c76ea8a0b8667598e49bde7b678 (patch)
treede14b911cf2fb2e77a8913b9fdce3c3348320ceb /src/inode.c
Initial revision
Diffstat (limited to 'src/inode.c')
-rw-r--r--src/inode.c805
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;
+}