📄 unix_misc.c
字号:
/* * The Sleuth Kit * * Brian Carrier [carrier <at> sleuthkit [dot] org] * Copyright (c) 2008 Brian Carrier. All Rights reserved * * This software is distributed under the Common Public License 1.0 *//** * \file unix_misc.c * Contains code that is common to both UFS1/2 and Ext2/3 file systems. */#include "tsk_fs_i.h"#include "tsk_ffs.h"#include "tsk_ext2fs.h"/*********** MAKE DATA RUNS ***************//** \internal * Process an array of addresses and turn them into runs * * @param fs File system to analyze * @param fs_attr Data attribute to add runs to * @param addrs Buffer of addresses to process and turn into runs * @param addr_len Number of addresses in buffer * @param length Length of file remaining * * @returns the number of bytes processed and -1 if an error occurred */static TSK_OFF_Tunix_make_data_run_direct(TSK_FS_INFO * fs, TSK_FS_ATTR * fs_attr, TSK_DADDR_T * addrs, size_t addr_len, TSK_OFF_T length){ TSK_DADDR_T run_start = 0; TSK_DADDR_T run_len = 0; TSK_DADDR_T blks_processed = 0; size_t i; size_t fs_blen; // how big is each "block" (in fragments) if (addr_len == 0) { return 0; } // block_size is a fragment size in UFS, so we need to maintain length in fragments if (TSK_FS_TYPE_ISFFS(fs->ftype)) { FFS_INFO *ffs = (FFS_INFO *) fs; fs_blen = ffs->ffsbsize_f; } else { fs_blen = 1; } run_start = addrs[0]; run_len = fs_blen; /* Note that we are lazy about length. We stop only when a run is past length, * we do not end exactly at length -- although that should happen anyway. */ for (i = 0; i < addr_len; i++) { /* Make a new run if: * - This is the last addresss in the buffer * - The next address is not part of the current run * -- special case for sparse since they use 0 as an address */ if ((i + 1 == addr_len) || ((run_start + run_len != addrs[i + 1]) && (run_start != 0)) || ((run_start == 0) && (addrs[i + 1] != 0))) { TSK_FS_ATTR_RUN *data_run; // make a non-resident run data_run = tsk_fs_attr_run_alloc(); if (data_run == NULL) return -1; data_run->addr = run_start; data_run->len = run_len; if (run_start == 0) data_run->flags = TSK_FS_ATTR_RUN_FLAG_SPARSE; // save the run tsk_fs_attr_append_run(fs, fs_attr, data_run); // get ready for the next run if (i + 1 != addr_len) run_start = addrs[i + 1]; run_len = 0; // stop if we are past the length requested if (blks_processed * fs->block_size > (TSK_DADDR_T) length) break; } run_len += fs_blen; blks_processed += fs_blen; } return blks_processed * fs->block_size;}/** \internal * Read an indirect block and process the contents to make a runlist from the pointers. * * @param fs File system to analyze * @param fs_attr Structure to save run data into * @param buf Buffers to read block data into (0 is block sized, 1+ are DADDR_T arrays based on FS type) * @param level Indirection level that this will process at (1+) * @param addr Address of block to read * @param length Length of file remaining * * @returns the number of bytes processed during call and -1 if an error occurred */static TSK_OFF_Tunix_make_data_run_indirect(TSK_FS_INFO * fs, TSK_FS_ATTR * fs_attr, char *buf[], int level, TSK_DADDR_T addr, TSK_OFF_T length){ char *myname = "unix_make_data_run_indirect"; size_t addr_cnt = 0; TSK_DADDR_T *myaddrs = (TSK_DADDR_T *) buf[level]; TSK_OFF_T length_remain = length; TSK_OFF_T retval; size_t fs_bufsize; if (tsk_verbose) tsk_fprintf(stderr, "%s: level %d block %" PRIuDADDR "\n", myname, level, addr); if (TSK_FS_TYPE_ISFFS(fs->ftype)) { FFS_INFO *ffs = (FFS_INFO *) fs; fs_bufsize = ffs->ffsbsize_b; } else { fs_bufsize = fs->block_size; } if (addr > fs->last_block) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "unix: Indirect block address too large: %" PRIuDADDR "", addr); return -1; } /* * Read a block of disk addresses. */ // sparse if (addr == 0) { memset(buf[0], 0, fs_bufsize); } else { ssize_t cnt; // read the data into the scratch buffer cnt = tsk_fs_read_block(fs, addr, buf[0], fs_bufsize); if (cnt != fs_bufsize) { if (cnt >= 0) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_READ; } snprintf(tsk_errstr2, TSK_ERRSTR_L, "unix_make_data_run_indir: Block %" PRIuDADDR, addr); return -1; } // @@@ what do we do about META.... } // convert the raw addresses to the correct endian ordering if ((fs->ftype == TSK_FS_TYPE_FFS1) || (fs->ftype == TSK_FS_TYPE_FFS1B) || (TSK_FS_TYPE_ISEXT(fs->ftype))) { size_t n; uint32_t *iaddr = (uint32_t *) buf[0]; addr_cnt = fs_bufsize / sizeof(*iaddr); for (n = 0; n < addr_cnt; n++) { myaddrs[n] = tsk_getu32(fs->endian, (uint8_t *) & iaddr[n]); } } else if (fs->ftype == TSK_FS_TYPE_FFS2) { size_t n; uint64_t *iaddr = (uint64_t *) buf[0]; addr_cnt = fs_bufsize / sizeof(*iaddr); for (n = 0; n < addr_cnt; n++) { myaddrs[n] = tsk_getu64(fs->endian, (uint8_t *) & iaddr[n]); } } // pass the addresses to the next level if (level == 1) { retval = unix_make_data_run_direct(fs, fs_attr, myaddrs, addr_cnt, length_remain); if (retval != -1) { length_remain -= retval; } } else { size_t i; retval = 0; for (i = 0; i < addr_cnt && retval != -1; i++) { retval = unix_make_data_run_indirect(fs, fs_attr, buf, level - 1, myaddrs[i], length_remain); if (retval == -1) { break; } else { length_remain -= retval; } } } if (retval == -1) return -1; else return length - length_remain;}/** \internal * * @returns 1 on error and 0 on success */uint8_ttsk_fs_unix_make_data_run(TSK_FS_FILE * fs_file){ TSK_OFF_T length = 0; TSK_OFF_T read_b = 0; TSK_FS_ATTR *fs_attr; TSK_FS_META *fs_meta = fs_file->meta; TSK_FS_INFO *fs = fs_file->fs_info; // clean up any error messages that are lying around tsk_error_reset(); if (tsk_verbose) tsk_fprintf(stderr, "unix_make_data_run: Processing file %" PRIuINUM "\n", fs_meta->addr); // see if we have already loaded the runs if ((fs_meta->attr != NULL) && (fs_meta->attr_state == TSK_FS_META_ATTR_STUDIED)) { return 0; } else if (fs_meta->attr_state == TSK_FS_META_ATTR_ERROR) { return 1; } // not sure why this would ever happen, but... else if (fs_meta->attr != NULL) { tsk_fs_attrlist_markunused(fs_meta->attr); } else if (fs_meta->attr == NULL) { fs_meta->attr = tsk_fs_attrlist_alloc(); } if ((TSK_FS_TYPE_ISFFS(fs->ftype) == 0) && (TSK_FS_TYPE_ISEXT(fs->ftype) == 0)) { tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "unix_make_run: Called with non-Unix file system: %x", fs->ftype); return 1; } length = roundup(fs_meta->size, fs->block_size); if ((fs_attr = tsk_fs_attrlist_getnew(fs_meta->attr, TSK_FS_ATTR_NONRES)) == NULL) { return 1; } // initialize the data run if (tsk_fs_attr_set_run(fs_file, fs_attr, NULL, NULL, TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT, fs_meta->size, roundup(fs_meta->size, fs->block_size), 0, 0)) { return 1; } read_b = unix_make_data_run_direct(fs, fs_attr, (TSK_DADDR_T *) fs_meta->content_ptr, 12, length); if (read_b == -1) { fs_meta->attr_state = TSK_FS_META_ATTR_ERROR; if (fs_meta->flags & TSK_FS_META_FLAG_UNALLOC) tsk_errno = TSK_ERR_FS_RECOVER; return 1; } length -= read_b; /* if there is still data left, read the indirect */ if (length > 0) { int level; char **buf; size_t fs_bufsize0; size_t fs_bufsize1; /* With FFS/UFS a full block contains the addresses, but block_size is * only a fragment. Figure out the scratch buffer size and the buffers to * store the cleaned addresses (endian converted) */ if (TSK_FS_TYPE_ISFFS(fs->ftype)) { FFS_INFO *ffs = (FFS_INFO *) fs; fs_bufsize0 = ffs->ffsbsize_b; if ((fs->ftype == TSK_FS_TYPE_FFS1) || (fs->ftype == TSK_FS_TYPE_FFS1B)) fs_bufsize1 = sizeof(TSK_DADDR_T) * ffs->ffsbsize_b / 4; else fs_bufsize1 = sizeof(TSK_DADDR_T) * ffs->ffsbsize_b / 8; } else { fs_bufsize0 = fs->block_size; fs_bufsize1 = sizeof(TSK_DADDR_T) * fs->block_size / 4; } /* * Initialize a buffer for the 3 levels of indirection that are supported by * this inode. Each level of indirection will have a buffer to store * addresses in. buf[0] is a special scratch buffer that is used to store * raw data from the image (before endian conversions are applied). It is * equal to one block size. The others will store TSK_DADDR_T structures * and will have a size depending on the FS type. */ if ((buf = (char **) tsk_malloc(sizeof(char *) * 4)) == NULL) return 1; if ((buf[0] = (char *) tsk_malloc(fs_bufsize0)) == NULL) { free(buf); return 1; } for (level = 1; length > 0 && level < 4; level++) { TSK_DADDR_T *addr_ptr = (TSK_DADDR_T *) fs_meta->content_ptr; if ((buf[level] = (char *) tsk_malloc(fs_bufsize1)) == NULL) { int f; for (f = 0; f < level; f++) free(buf[f]); free(buf); return 1; } /* the indirect addresses are stored in addr_ptr after the 12 * direct addresses */ read_b = unix_make_data_run_indirect(fs, fs_attr, buf, level, addr_ptr[12 + level - 1], length); if (read_b == -1) break; length -= read_b; } /* * Cleanup. */ for (level = 0; level < 4; level++) { if (buf[level]) free(buf[level]); } } if (read_b == -1) { fs_meta->attr_state = TSK_FS_META_ATTR_ERROR; if (fs_meta->flags & TSK_FS_META_FLAG_UNALLOC) tsk_errno = TSK_ERR_FS_RECOVER; return 1; } fs_meta->attr_state = TSK_FS_META_ATTR_STUDIED; return 0;}TSK_FS_ATTR_TYPE_ENUMtsk_fs_unix_get_default_attr_type(const TSK_FS_FILE * a_file){ return TSK_FS_ATTR_TYPE_DEFAULT;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -