/** \internal * Create a dummy META entry for the Orphan file virtual directory. * @param a_fs File system directory is for * @param a_fs_meta META structure to populate with data * @returns 1 on error */ uint8_t tsk_fs_dir_make_orphan_dir_meta(TSK_FS_INFO * a_fs, TSK_FS_META * a_fs_meta) { a_fs_meta->type = TSK_FS_META_TYPE_DIR; a_fs_meta->mode = 0; a_fs_meta->nlink = 1; a_fs_meta->flags = (TSK_FS_META_FLAG_USED | TSK_FS_META_FLAG_ALLOC); a_fs_meta->uid = a_fs_meta->gid = 0; a_fs_meta->mtime = a_fs_meta->atime = a_fs_meta->ctime = a_fs_meta->crtime = 0; a_fs_meta->mtime_nano = a_fs_meta->atime_nano = a_fs_meta->ctime_nano = a_fs_meta->crtime_nano = 0; if (a_fs_meta->name2 == NULL) { if ((a_fs_meta->name2 = (TSK_FS_META_NAME_LIST *) tsk_malloc(sizeof(TSK_FS_META_NAME_LIST))) == NULL) return 1; a_fs_meta->name2->next = NULL; } a_fs_meta->attr_state = TSK_FS_META_ATTR_EMPTY; if (a_fs_meta->attr) { tsk_fs_attrlist_markunused(a_fs_meta->attr); } a_fs_meta->addr = TSK_FS_ORPHANDIR_INUM(a_fs); strncpy(a_fs_meta->name2->name, "$OrphanFiles", TSK_FS_META_NAME_LIST_NSIZE); if (a_fs_meta->content_len) { TSK_DADDR_T *addr_ptr = (TSK_DADDR_T *) a_fs_meta->content_ptr; addr_ptr[0] = 0; } a_fs_meta->size = 0; return 0; }
/** \internal * * @returns 1 on error and 0 on success */ uint8_t tsk_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_ATTR *fs_attr_indir; 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_error_set_errno(TSK_ERR_FS_INODE_COR); tsk_error_set_errstr ("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, 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_error_set_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[4] = {NULL}; size_t fs_bufsize0; size_t fs_bufsize1; size_t ptrsperblock; int numBlocks = 0; int numSingIndirect = 0; int numDblIndirect = 0; int numTripIndirect = 0; /* 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)) { ptrsperblock = fs_bufsize0 / 4; } else { ptrsperblock = fs_bufsize0 / 8; } } else { fs_bufsize0 = fs->block_size; ptrsperblock = fs_bufsize0 / 4; } fs_bufsize1 = sizeof(TSK_DADDR_T) * ptrsperblock; /* * 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 ((fs_attr_indir = tsk_fs_attrlist_getnew(fs_meta->attr, TSK_FS_ATTR_NONRES)) == NULL) { return 1; } // determine number of indirect lbocks needed for file size... numBlocks = (int) (((fs_meta->size + fs_bufsize0 - 1) / fs_bufsize0) - 12); numSingIndirect = (int) ((numBlocks + ptrsperblock - 1) / ptrsperblock); numDblIndirect = 0; numTripIndirect = 0; // double block pointer? if (numSingIndirect > 1) { numDblIndirect = (int) ((numSingIndirect - 1 + ptrsperblock - 1) / ptrsperblock); if (numDblIndirect > 1) { numTripIndirect = (int) ((numDblIndirect - 1 + ptrsperblock - 1) / ptrsperblock); } } // initialize the data run if (tsk_fs_attr_set_run(fs_file, fs_attr_indir, NULL, NULL, TSK_FS_ATTR_TYPE_UNIX_INDIR, TSK_FS_ATTR_ID_DEFAULT, fs_bufsize0 * (numSingIndirect + numDblIndirect + numTripIndirect), fs_bufsize0 * (numSingIndirect + numDblIndirect + numTripIndirect), fs_bufsize0 * (numSingIndirect + numDblIndirect + numTripIndirect), 0, 0)) { return 1; } if ((buf[0] = (char *) tsk_malloc(fs_bufsize0)) == NULL) { 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]); } 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, fs_attr_indir, 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_error_set_errno(TSK_ERR_FS_RECOVER); return 1; } fs_meta->attr_state = TSK_FS_META_ATTR_STUDIED; return 0; }