📄 ffs.c
字号:
* * INODE WALKING * **************************************************************************//* ffs_inode_walk - inode iterator * * flags used: TSK_FS_META_FLAG_USED, TSK_FS_META_FLAG_UNUSED, * TSK_FS_META_FLAG_ALLOC, TSK_FS_META_FLAG_UNALLOC, TSK_FS_META_FLAG_ORPHAN * * return 1 on error and 0 on success */uint8_tffs_inode_walk(TSK_FS_INFO * fs, TSK_INUM_T start_inum, TSK_INUM_T end_inum, TSK_FS_META_FLAG_ENUM a_flags, TSK_FS_META_WALK_CB action, void *ptr){ char *myname = "ffs_inode_walk"; FFS_INFO *ffs = (FFS_INFO *) fs; FFS_GRPNUM_T grp_num; ffs_cgd *cg = NULL; TSK_INUM_T inum; unsigned char *inosused = NULL; TSK_FS_FILE *fs_file; int myflags; TSK_INUM_T ibase = 0; TSK_INUM_T end_inum_tmp; // clean up any error messages that are lying around tsk_error_reset(); /* * Sanity checks. */ if (start_inum < fs->first_inum || start_inum > fs->last_inum) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_WALK_RNG; snprintf(tsk_errstr, TSK_ERRSTR_L, "%s: Start inode: %" PRIuINUM "", myname, start_inum); return 1; } else if (end_inum < fs->first_inum || end_inum > fs->last_inum || end_inum < start_inum) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_WALK_RNG; snprintf(tsk_errstr, TSK_ERRSTR_L, "%s: End inode: %" PRIuINUM "", myname, end_inum); return 1; } /* If ORPHAN is wanted, then make sure that the flags are correct */ if (a_flags & TSK_FS_META_FLAG_ORPHAN) { a_flags |= TSK_FS_META_FLAG_UNALLOC; a_flags &= ~TSK_FS_META_FLAG_ALLOC; a_flags |= TSK_FS_META_FLAG_USED; a_flags &= ~TSK_FS_META_FLAG_UNUSED; } else { if (((a_flags & TSK_FS_META_FLAG_ALLOC) == 0) && ((a_flags & TSK_FS_META_FLAG_UNALLOC) == 0)) { a_flags |= (TSK_FS_META_FLAG_ALLOC | TSK_FS_META_FLAG_UNALLOC); } /* If neither of the USED or UNUSED flags are set, then set them * both */ if (((a_flags & TSK_FS_META_FLAG_USED) == 0) && ((a_flags & TSK_FS_META_FLAG_UNUSED) == 0)) { a_flags |= (TSK_FS_META_FLAG_USED | TSK_FS_META_FLAG_UNUSED); } } /* If we are looking for orphan files and have not yet filled * in the list of unalloc inodes that are pointed to, then fill * in the list * */ if ((a_flags & TSK_FS_META_FLAG_ORPHAN) && (fs->list_inum_named == NULL)) { if (tsk_fs_dir_load_inum_named(fs) != TSK_OK) { strncat(tsk_errstr2, " - ffs_inode_walk: identifying inodes allocated by file names", TSK_ERRSTR_L); return 1; } } if ((fs_file = tsk_fs_file_alloc(fs)) == NULL) return 1; if ((fs_file->meta = tsk_fs_meta_alloc(FFS_FILE_CONTENT_LEN)) == NULL) return 1; // we need to handle fs->last_inum specially because it is for the // virtual ORPHANS directory. Handle it outside of the loop. if (end_inum == TSK_FS_ORPHANDIR_INUM(fs)) end_inum_tmp = end_inum - 1; else end_inum_tmp = end_inum; /* * Iterate. This is easy because inode numbers are contiguous, unlike * data blocks which are interleaved with cylinder group blocks. */ for (inum = start_inum; inum <= end_inum_tmp; inum++) { int retval; /* * Be sure to use the proper cylinder group data. */ grp_num = itog_lcl(fs, ffs->fs.sb1, inum); if ((ffs->grp_buf == NULL) || (grp_num != ffs->grp_num)) { if (ffs_group_load(ffs, grp_num)) return 1; cg = NULL; } /* Load up the cached one if the needed one was already loaded or if a new was just loaded */ if (cg == NULL) { cg = (ffs_cgd *) ffs->grp_buf; inosused = (unsigned char *) cg_inosused_lcl(fs, cg); ibase = grp_num * tsk_gets32(fs->endian, ffs->fs.sb1->cg_inode_num); } /* * Apply the allocated/unallocated restriction. */ myflags = (isset(inosused, inum - ibase) ? TSK_FS_META_FLAG_ALLOC : TSK_FS_META_FLAG_UNALLOC); if ((a_flags & myflags) != myflags) continue; if (ffs_dinode_load(ffs, inum)) { tsk_fs_file_close(fs_file); return 1; } if ((fs->ftype == TSK_FS_TYPE_FFS1) || (fs->ftype == TSK_FS_TYPE_FFS1B)) { /* both inode forms are the same for the required fields */ ffs_inode1 *in1 = (ffs_inode1 *) ffs->dino_buf; /* * Apply the used/unused restriction. */ myflags |= (tsk_gets32(fs->endian, in1->di_ctime) ? TSK_FS_META_FLAG_USED : TSK_FS_META_FLAG_UNUSED); if ((a_flags & myflags) != myflags) continue; } else { ffs_inode2 *in2 = (ffs_inode2 *) ffs->dino_buf; /* * Apply the used/unused restriction. */ myflags |= (tsk_gets64(fs->endian, in2->di_ctime) ? TSK_FS_META_FLAG_USED : TSK_FS_META_FLAG_UNUSED); if ((a_flags & myflags) != myflags) continue; } /* If we want only orphans, then check if this * inode is in the seen list */ if ((myflags & TSK_FS_META_FLAG_UNALLOC) && (a_flags & TSK_FS_META_FLAG_ORPHAN) && (tsk_list_find(fs->list_inum_named, inum))) { continue; } /* * Fill in a file system-independent inode structure and pass control * to the application. */ if (ffs_dinode_copy(ffs, fs_file->meta)) { tsk_fs_file_close(fs_file); return 1; } retval = action(fs_file, ptr); if (retval == TSK_WALK_STOP) { tsk_fs_file_close(fs_file); return 0; } else if (retval == TSK_WALK_ERROR) { tsk_fs_file_close(fs_file); return 1; } } // handle the virtual orphans folder if they asked for it if ((end_inum == TSK_FS_ORPHANDIR_INUM(fs)) && (a_flags & TSK_FS_META_FLAG_ALLOC) && (a_flags & TSK_FS_META_FLAG_USED)) { int retval; if (tsk_fs_dir_make_orphan_dir_meta(fs, fs_file->meta)) { tsk_fs_file_close(fs_file); return 1; } /* call action */ retval = action(fs_file, ptr); if (retval == TSK_WALK_STOP) { tsk_fs_file_close(fs_file); return 0; } else if (retval == TSK_WALK_ERROR) { tsk_fs_file_close(fs_file); return 1; } } /* * Cleanup. */ tsk_fs_file_close(fs_file); return 0;}TSK_FS_BLOCK_FLAG_ENUMffs_block_getflags(TSK_FS_INFO * a_fs, TSK_DADDR_T a_addr){ FFS_INFO *ffs = (FFS_INFO *) a_fs; FFS_GRPNUM_T grp_num; ffs_cgd *cg = 0; TSK_DADDR_T frag_base = 0; TSK_DADDR_T dblock_addr = 0; /* first data block in group */ TSK_DADDR_T sblock_addr = 0; /* super block in group */ unsigned char *freeblocks = NULL; int flags; grp_num = dtog_lcl(a_fs, ffs->fs.sb1, a_addr); if (ffs_group_load(ffs, grp_num)) { return 0; } cg = (ffs_cgd *) ffs->grp_buf; freeblocks = (unsigned char *) cg_blksfree_lcl(a_fs, cg); // get the base fragment for the group frag_base = cgbase_lcl(a_fs, ffs->fs.sb1, grp_num); // address of first data block in group dblock_addr = cgdmin_lcl(a_fs, ffs->fs.sb1, grp_num); // address of super block in group sblock_addr = cgsblock_lcl(a_fs, ffs->fs.sb1, grp_num); /* get the flags for this fragment * * Beware: FFS stores file data in the blocks between the start of a * cylinder group and the start of its super block. */ flags = (isset(freeblocks, a_addr - frag_base) ? TSK_FS_BLOCK_FLAG_UNALLOC : TSK_FS_BLOCK_FLAG_ALLOC); if (a_addr >= sblock_addr && a_addr < dblock_addr) flags |= TSK_FS_BLOCK_FLAG_META; else flags |= TSK_FS_BLOCK_FLAG_CONT; return flags;}/************************************************************************** * * BLOCK WALKING * **************************************************************************//* ffs_block_walk - block iterator * * flags: TSK_FS_BLOCK_FLAG_ALLOC, TSK_FS_BLOCK_FLAG_UNALLOC, TSK_FS_BLOCK_FLAG_CONT, * TSK_FS_BLOCK_FLAG_META * * return 1 on error and 0 on success */uint8_tffs_block_walk(TSK_FS_INFO * fs, TSK_DADDR_T a_start_blk, TSK_DADDR_T a_end_blk, TSK_FS_BLOCK_WALK_FLAG_ENUM a_flags, TSK_FS_BLOCK_WALK_CB action, void *ptr){ char *myname = "ffs_block_walk"; FFS_INFO *ffs = (FFS_INFO *) fs; TSK_FS_BLOCK *fs_block; TSK_DADDR_T addr; char *cache_blk_buf; // buffer used for local read cache TSK_DADDR_T cache_addr; // base address in local cache int cache_len_f; // amount of data read into cache (in fragments) // clean up any error messages that are lying around tsk_error_reset(); /* * Sanity checks on input bounds */ if (a_start_blk < fs->first_block || a_start_blk > fs->last_block) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_WALK_RNG; snprintf(tsk_errstr, TSK_ERRSTR_L, "%s: Start block: %" PRIuDADDR "", myname, a_start_blk); return 1; } if (a_end_blk < fs->first_block || a_end_blk > fs->last_block || a_end_blk < a_start_blk) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_WALK_RNG; snprintf(tsk_errstr, TSK_ERRSTR_L, "%s: End block: %" PRIuDADDR "", myname, a_end_blk); return 1; } /* Sanity check on flags -- make sure at least one ALLOC is set */ if (((a_flags & TSK_FS_BLOCK_WALK_FLAG_ALLOC) == 0) && ((a_flags & TSK_FS_BLOCK_WALK_FLAG_UNALLOC) == 0)) { a_flags |= (TSK_FS_BLOCK_WALK_FLAG_ALLOC | TSK_FS_BLOCK_WALK_FLAG_UNALLOC); } if (((a_flags & TSK_FS_BLOCK_WALK_FLAG_META) == 0) && ((a_flags & TSK_FS_BLOCK_WALK_FLAG_CONT) == 0)) { a_flags |= (TSK_FS_BLOCK_WALK_FLAG_CONT | TSK_FS_BLOCK_WALK_FLAG_META); } /* Other initialization */ if ((fs_block = tsk_fs_block_alloc(fs)) == NULL) { return 1; } if ((cache_blk_buf = tsk_malloc(ffs->ffsbsize_b)) == NULL) { return 1; } cache_len_f = 0; cache_addr = 0; /* Cycle through the fragment range requested */ for (addr = a_start_blk; addr <= a_end_blk; addr++) { int retval; int myflags = ffs_block_getflags(fs, addr); if ((tsk_verbose) && (myflags & TSK_FS_BLOCK_FLAG_META) && (myflags & TSK_FS_BLOCK_FLAG_UNALLOC)) tsk_fprintf(stderr, "impossible: unallocated meta block %" PRIuDADDR, addr); // test if we should call the callback with this one if ((myflags & TSK_FS_BLOCK_FLAG_META) && (!(a_flags & TSK_FS_BLOCK_WALK_FLAG_META))) continue; else if ((myflags & TSK_FS_BLOCK_FLAG_CONT) && (!(a_flags & TSK_FS_BLOCK_WALK_FLAG_CONT))) continue; else if ((myflags & TSK_FS_BLOCK_FLAG_ALLOC) && (!(a_flags & TSK_FS_BLOCK_WALK_FLAG_ALLOC))) continue; else if ((myflags & TSK_FS_BLOCK_FLAG_UNALLOC) && (!(a_flags & TSK_FS_BLOCK_WALK_FLAG_UNALLOC))) continue; /* we read in block-sized chunks and cache the result for later * calls. See if this fragment is in our cache */ if ((cache_len_f == 0) || (addr >= cache_addr + cache_len_f)) { ssize_t cnt; int frags; /* Ideally, we want to read in block sized chunks, verify we can do that */ frags = (a_end_blk > addr + ffs->ffsbsize_f - 1 ? ffs->ffsbsize_f : (int) (a_end_blk + 1 - addr)); cnt = tsk_fs_read_block(fs, addr, cache_blk_buf, fs->block_size * frags); if (cnt != fs->block_size * frags) { if (cnt >= 0) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_READ; } snprintf(tsk_errstr2, TSK_ERRSTR_L, "ffs_block_walk: Block %" PRIuDADDR, addr); tsk_fs_block_free(fs_block); free(cache_blk_buf); return 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -