📄 ffs.c
字号:
/*** The Sleuth Kit **** Brian Carrier [carrier <at> sleuthkit [dot] org]** Copyright (c) 2006-2008 Brian Carrier, Basis Technology. All Rights reserved** Copyright (c) 2003-2005 Brian Carrier. All rights reserved **** TASK** Copyright (c) 2002-2003 Brian Carrier, @stake Inc. All rights reserved** ** Copyright (c) 1997,1998,1999, International Business Machines ** Corporation and others. All Rights Reserved.*//* TCT * LICENSE * This software is distributed under the IBM Public License. * AUTHOR(S) * Wietse Venema * IBM T.J. Watson Research * P.O. Box 704 * Yorktown Heights, NY 10598, USA --*//** * \file ffs.c * Contains the internal TSK UFS / FFS file system functions */#include "tsk_fs_i.h"#include "tsk_ffs.h"/* ffs_group_load - load cylinder group descriptor info into cache * * return 1 on error and 0 on success * */static uint8_tffs_group_load(FFS_INFO * ffs, FFS_GRPNUM_T grp_num){ TSK_DADDR_T addr; TSK_FS_INFO *fs = (TSK_FS_INFO *) & ffs->fs_info; /* * Sanity check */ if (grp_num < 0 || grp_num >= ffs->groups_count) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "ffs_group_load: invalid cylinder group number: %" PRI_FFSGRP "", grp_num); return 1; } /* * Allocate/read cylinder group info on the fly. Trust that a cylinder * group always fits within a logical disk block (as promised in the * 4.4BSD <ufs/ffs/fs.h> include file). */ if (ffs->grp_buf == NULL) { if ((ffs->grp_buf = tsk_malloc(ffs->ffsbsize_b)) == NULL) return 1; } addr = cgtod_lcl(fs, ffs->fs.sb1, grp_num); if (ffs->grp_addr != addr) { ffs_cgd *cg; ssize_t cnt; cnt = tsk_fs_read_block(fs, addr, ffs->grp_buf, ffs->ffsbsize_b); if (cnt != ffs->ffsbsize_b) { if (cnt >= 0) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_READ; } snprintf(tsk_errstr2, TSK_ERRSTR_L, "ffs_group_load: Group %" PRI_FFSGRP " at %" PRIuDADDR, grp_num, addr); return 1; } ffs->grp_addr = addr; /* Perform a sanity check on the data to make sure offsets are in range */ cg = (ffs_cgd *) ffs->grp_buf; if ((tsk_gets32(fs->endian, cg->cg_iusedoff) > ffs->ffsbsize_b) || (tsk_gets32(fs->endian, cg->cg_freeoff) > ffs->ffsbsize_b)) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_CORRUPT; snprintf(tsk_errstr2, TSK_ERRSTR_L, "ffs_group_load: Group %" PRI_FFSGRP " descriptor offsets too large at %" PRIuDADDR, grp_num, addr); return 1; } } ffs->grp_num = grp_num; return 0;}/* * ffs_dinode_load - read disk inode and load into local cache (ffs->dino_buf) * * Return 0 on success and 1 on error */static uint8_tffs_dinode_load(FFS_INFO * ffs, TSK_INUM_T inum){ TSK_DADDR_T addr; TSK_OFF_T offs; TSK_FS_INFO *fs = (TSK_FS_INFO *) & ffs->fs_info; /* * Sanity check. * Use last_num-1 to account for virtual Orphan directory in last_inum. */ if (inum < fs->first_inum || inum > fs->last_inum - 1) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_NUM; snprintf(tsk_errstr, TSK_ERRSTR_L, "ffs_dinode_load: address: %" PRIuINUM, inum); return 1; } /* * Allocate/read the inode table buffer on the fly. */ if (ffs->itbl_buf == NULL) { if ((ffs->itbl_buf = tsk_malloc(ffs->ffsbsize_b)) == NULL) return 1; } /* UFS2 is different because it does not initialize all inodes * when the file system is created. Therefore we need to check * the group descriptor to find out if this is in the valid * range */ if (fs->ftype == TSK_FS_TYPE_FFS2) { ffs_cgd2 *cg2; FFS_GRPNUM_T grp_num; if (ffs->dino_buf == NULL) { ffs->dino_buf = (char *) tsk_malloc(sizeof(ffs_inode2)); if (ffs->dino_buf == NULL) return 1; } else if (ffs->dino_inum == inum) { return 0; } /* Lookup the cylinder group descriptor if it isn't * cached */ grp_num = (FFS_GRPNUM_T) 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; } } cg2 = (ffs_cgd2 *) ffs->grp_buf; /* If the inode is not init, then do not worry about it */ if ((inum - grp_num * tsk_getu32(fs->endian, ffs->fs.sb2->cg_inode_num)) >= tsk_getu32(fs->endian, cg2->cg_initediblk)) { memset((char *) ffs->dino_buf, 0, sizeof(ffs_inode2)); } else { ssize_t cnt; /* Get the base and offset addr for the inode in the tbl */ addr = itod_lcl(fs, ffs->fs.sb1, inum); if (ffs->itbl_addr != addr) { cnt = tsk_fs_read_block (fs, addr, ffs->itbl_buf, ffs->ffsbsize_b); if (cnt != ffs->ffsbsize_b) { if (cnt >= 0) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_READ; } snprintf(tsk_errstr2, TSK_ERRSTR_L, "ffs_dinode_load: FFS2 inode table at %" PRIuDADDR, addr); return 1; } ffs->itbl_addr = addr; } offs = itoo_lcl(fs, ffs->fs.sb2, inum) * sizeof(ffs_inode2); memcpy((char *) ffs->dino_buf, ffs->itbl_buf + offs, sizeof(ffs_inode2)); } } else { if (ffs->dino_buf == NULL) { ffs->dino_buf = (char *) tsk_malloc(sizeof(ffs_inode1)); if (ffs->dino_buf == NULL) return 1; } else if (ffs->dino_inum == inum) { return 0; } addr = itod_lcl(fs, ffs->fs.sb1, inum); if (ffs->itbl_addr != addr) { ssize_t cnt; cnt = tsk_fs_read_block(fs, addr, ffs->itbl_buf, ffs->ffsbsize_b); if (cnt != ffs->ffsbsize_b) { if (cnt >= 0) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_READ; } snprintf(tsk_errstr2, TSK_ERRSTR_L, "ffs_dinode_load: FFS1 inode table at %" PRIuDADDR, addr); return 1; } ffs->itbl_addr = addr; } offs = itoo_lcl(fs, ffs->fs.sb1, inum) * sizeof(ffs_inode1); memcpy((char *) ffs->dino_buf, ffs->itbl_buf + offs, sizeof(ffs_inode1)); } ffs->dino_inum = inum; return 0;}static TSK_FS_META_TYPE_ENUMffsmode2tsktype(uint16_t a_mode){ switch (a_mode & FFS_IN_FMT) { case FFS_IN_REG: return TSK_FS_META_TYPE_REG; case FFS_IN_DIR: return TSK_FS_META_TYPE_DIR; case FFS_IN_SOCK: return TSK_FS_META_TYPE_SOCK; case FFS_IN_LNK: return TSK_FS_META_TYPE_LNK; case FFS_IN_BLK: return TSK_FS_META_TYPE_BLK; case FFS_IN_CHR: return TSK_FS_META_TYPE_CHR; case FFS_IN_FIFO: return TSK_FS_META_TYPE_FIFO; case FFS_IN_SHAD: return TSK_FS_META_TYPE_SHAD; case FFS_IN_WHT: return TSK_FS_META_TYPE_WHT; default: return TSK_FS_META_TYPE_UNDEF; }}static uint16_tffsmode2tskmode(uint16_t a_mode){ uint16_t mode = 0; if (a_mode & FFS_IN_ISUID) mode |= TSK_FS_META_MODE_ISUID; if (a_mode & FFS_IN_ISGID) mode |= TSK_FS_META_MODE_ISGID; if (a_mode & FFS_IN_ISVTX) mode |= TSK_FS_META_MODE_ISVTX; if (a_mode & FFS_IN_IRUSR) mode |= TSK_FS_META_MODE_IRUSR; if (a_mode & FFS_IN_IWUSR) mode |= TSK_FS_META_MODE_IWUSR; if (a_mode & FFS_IN_IXUSR) mode |= TSK_FS_META_MODE_IXUSR; if (a_mode & FFS_IN_IRGRP) mode |= TSK_FS_META_MODE_IRGRP; if (a_mode & FFS_IN_IWGRP) mode |= TSK_FS_META_MODE_IWGRP; if (a_mode & FFS_IN_IXGRP) mode |= TSK_FS_META_MODE_IXGRP; if (a_mode & FFS_IN_IROTH) mode |= TSK_FS_META_MODE_IROTH; if (a_mode & FFS_IN_IWOTH) mode |= TSK_FS_META_MODE_IWOTH; if (a_mode & FFS_IN_IXOTH) mode |= TSK_FS_META_MODE_IXOTH; return mode;}/* ffs_dinode_copy - copy cached disk inode to generic inode * * Return 1 on error and 0 on success */static uint8_tffs_dinode_copy(FFS_INFO * ffs, TSK_FS_META * fs_meta){ int i, j; unsigned int count; TSK_FS_INFO *fs = &(ffs->fs_info); FFS_GRPNUM_T grp_num; ffs_cgd *cg; unsigned char *inosused = NULL; TSK_INUM_T ibase; fs_meta->attr_state = TSK_FS_META_ATTR_EMPTY; if (fs_meta->attr) { tsk_fs_attrlist_markunused(fs_meta->attr); } fs_meta->flags = 0; fs_meta->seq = 0; /* If the symlink field is set from a previous run, then free it */ if (fs_meta->link) { free(fs_meta->link); fs_meta->link = NULL; } fs_meta->addr = ffs->dino_inum; /* OpenBSD and FreeBSD style */ if (fs->ftype == TSK_FS_TYPE_FFS1) { ffs_inode1 *in = (ffs_inode1 *) ffs->dino_buf; TSK_DADDR_T *addr_ptr; fs_meta->mode = ffsmode2tskmode(tsk_getu16(fs->endian, in->di_mode)); fs_meta->type = ffsmode2tsktype(tsk_getu16(fs->endian, in->di_mode)); fs_meta->nlink = tsk_gets16(fs->endian, in->di_nlink); fs_meta->size = tsk_getu64(fs->endian, in->di_size); fs_meta->uid = tsk_getu32(fs->endian, in->di_uid); fs_meta->gid = tsk_getu32(fs->endian, in->di_gid); fs_meta->mtime = tsk_gets32(fs->endian, in->di_mtime); fs_meta->atime = tsk_gets32(fs->endian, in->di_atime); fs_meta->ctime = tsk_gets32(fs->endian, in->di_ctime); fs_meta->crtime = 0; if (fs_meta->content_len < FFS_FILE_CONTENT_LEN) { if ((fs_meta = tsk_fs_meta_realloc(fs_meta, FFS_FILE_CONTENT_LEN)) == NULL) { return 1; } } addr_ptr = (TSK_DADDR_T *) fs_meta->content_ptr; for (i = 0; i < FFS_NDADDR; i++) addr_ptr[i] = tsk_gets32(fs->endian, in->di_db[i]); for (i = 0; i < FFS_NIADDR; i++) addr_ptr[FFS_NDADDR + i] = tsk_gets32(fs->endian, in->di_ib[i]); /* set the link string (if the file is a link) * The size check is a sanity check so that we don't try and allocate * a huge amount of memory for a bad inode value */ if ((fs_meta->type == TSK_FS_META_TYPE_LNK) && (fs_meta->size < FFS_MAXPATHLEN) && (fs_meta->size >= 0)) { int i; fs_meta->link = tsk_malloc((size_t) fs_meta->size + 1); if (fs_meta->link == NULL) { return 1; } count = 0; /* index into the link array */ /* it is located directly in the pointers */ if (fs_meta->size < 4 * (FFS_NDADDR + FFS_NIADDR)) { char *ptr; /* Direct block pointer locations */ for (i = 0; i < FFS_NDADDR && count < fs_meta->size; i++) { ptr = (char *) &in->di_db[i]; for (j = 0; j < 4 && count < fs_meta->size; j++) fs_meta->link[count++] = ptr[j]; } /* indirect block pointers */ for (i = 0; i < FFS_NIADDR && count < fs_meta->size; i++) { ptr = (char *) &in->di_ib[i];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -