/* * Class: edu_uw_apl_commons_tsk4j_filesys_FileSystem * Method: fileOpenMeta * Signature: (JJ)Ledu/uw/apl/commons/tsk4j/filesys/File; */ JNIEXPORT jobject JNICALL Java_edu_uw_apl_commons_tsk4j_filesys_FileSystem_fileOpenMeta (JNIEnv * env, jobject thiz, jlong nativePtr, jlong metadataAddr ) { TSK_FS_INFO* info = (TSK_FS_INFO*)nativePtr; TSK_FS_FILE* fsFile = tsk_fs_file_open_meta( info, NULL, (TSK_INUM_T)metadataAddr ); if( !fsFile ) return (jobject)NULL; jobject fileMeta = createFileMeta( env, fsFile->meta ); if( !fileMeta ) { tsk_fs_file_close( fsFile ); return (jobject)NULL; } jobject result = createFile( env, fsFile, thiz, fileMeta, NULL ); if( !result ) { tsk_fs_file_close( fsFile ); // LOOK: free fileMeta ?? return (jobject)NULL; } return result; }
/* * Close the given file * @param env pointer to java environment this was called from * @param obj the java object this was called from * @param a_file_info the pointer to the file object */ JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_closeFileNat(JNIEnv * env, jclass obj, jlong a_file_info) { TSK_FS_FILE *file_info = castFsFile(env, a_file_info); tsk_fs_file_close(file_info); }
/* Verify that a specific attribute can be read from the file * @param a_addr The metadata address of the file to analyze * @param a_type Type that is known to be in file * @returns 1 if a test failed */ static int test_get_type(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr, TSK_FS_ATTR_TYPE_ENUM a_type) { TSK_FS_FILE *fs_file; // open the file fs_file = tsk_fs_file_open_meta(a_fs, NULL, a_addr); if (!fs_file) { fprintf(stderr, "Error opening file %" PRIuINUM " via meta\n", a_addr); tsk_error_print(stderr); return 1; } // verify the specified type can be opened const TSK_FS_ATTR *fs_attr = tsk_fs_file_attr_get_type(fs_file, a_type, 0, 0); if (!fs_attr) { fprintf(stderr, "Error getting specified attribute %d-X (no id) from %" PRIuINUM "\n", a_type, a_addr); tsk_error_print(stderr); return 1; } tsk_fs_file_close(fs_file); return 0; }
/** \ingroup fslib * Close the directory that was opened with tsk_fs_dir_open() * @param a_fs_dir Directory to close */ void tsk_fs_dir_close(TSK_FS_DIR * a_fs_dir) { size_t i; if ((a_fs_dir == NULL) || (a_fs_dir->tag != TSK_FS_DIR_TAG)) { return; } for (i = 0; i < a_fs_dir->names_used; i++) { if (a_fs_dir->names[i].name) { free(a_fs_dir->names[i].name); a_fs_dir->names[i].name = NULL; a_fs_dir->names[i].name_size = 0; } if (a_fs_dir->names[i].shrt_name) { free(a_fs_dir->names[i].shrt_name); a_fs_dir->names[i].shrt_name = NULL; a_fs_dir->names[i].shrt_name_size = 0; } } free(a_fs_dir->names); if (a_fs_dir->fs_file) { tsk_fs_file_close(a_fs_dir->fs_file); a_fs_dir->fs_file = NULL; } a_fs_dir->tag = 0; free(a_fs_dir); }
/** * Walk through the Update Sequence Number journal file * opened with ntfs_usnjopen. * * For each USN record, calls the callback action passing the USN record header, * the USN record and the pointer ptr. * * @param ntfs File system where the journal is stored * @param action action to be called per each USN entry * @param ptr pointer to data passed to the action callback * @returns 0 on success, 1 otherwise */ uint8_t tsk_ntfs_usnjentry_walk(TSK_FS_INFO *fs, TSK_FS_USNJENTRY_WALK_CB action, void *ptr) { uint8_t ret = 0; unsigned char *buf = NULL; NTFS_INFO *ntfs = (NTFS_INFO*)fs; tsk_error_reset(); if (ntfs == NULL || ntfs->fs_info.ftype != TSK_FS_TYPE_NTFS) { tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr("Invalid FS type in ntfs_usnjentry_walk"); return 1; } if (ntfs->usnjinfo == NULL) { tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr("Must call tsk_ntfs_usnjopen first"); return 1; } buf = tsk_malloc(ntfs->usnjinfo->bsize); if (buf == NULL) return 1; ret = parse_file(ntfs, buf, action, ptr); tsk_fs_file_close(ntfs->usnjinfo->fs_file); free(ntfs->usnjinfo); free(buf); return ret; }
/* Return 1 on error and 0 on success */ uint8_t tsk_fs_icat(TSK_FS_INFO * fs, TSK_INUM_T inum, TSK_FS_ATTR_TYPE_ENUM type, uint8_t type_used, uint16_t id, uint8_t id_used, TSK_FS_FILE_WALK_FLAG_ENUM flags) { TSK_FS_FILE *fs_file; #ifdef TSK_WIN32 if (-1 == _setmode(_fileno(stdout), _O_BINARY)) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_WRITE; snprintf(tsk_errstr, TSK_ERRSTR_L, "icat_lib: error setting stdout to binary: %s", strerror(errno)); return 1; } #endif fs_file = tsk_fs_file_open_meta(fs, NULL, inum); if (!fs_file) { return 1; } if (type_used) { if (id_used == 0) { flags |= TSK_FS_FILE_WALK_FLAG_NOID; } if (tsk_fs_file_walk_type(fs_file, type, id, flags, icat_action, NULL)) { tsk_fs_file_close(fs_file); return 1; } } else { if (tsk_fs_file_walk(fs_file, flags, icat_action, NULL)) { tsk_fs_file_close(fs_file); return 1; } } tsk_fs_file_close(fs_file); return 0; }
/* * Class: edu_uw_apl_commons_tsk4j_filesys_File * Method: close * Signature: (J)V */ JNIEXPORT void JNICALL Java_edu_uw_apl_commons_tsk4j_filesys_File_close (JNIEnv *env, jobject thiz, jlong id) { TSK_FS_FILE* info = (TSK_FS_FILE*)id; tsk_fs_file_close( info ); #ifdef DEBUGTSK fprintf( stderr, "File.Close %p\n", info ); #endif }
/** \internal * Reset the structures in a FS_DIR so that it can be reused. * @param a_fs_dir FS_DIR structure to re-use */ void tsk_fs_dir_reset(TSK_FS_DIR * a_fs_dir) { if ((a_fs_dir == NULL) || (a_fs_dir->tag != TSK_FS_DIR_TAG)) return; if (a_fs_dir->fs_file) { tsk_fs_file_close(a_fs_dir->fs_file); a_fs_dir->fs_file = NULL; } a_fs_dir->names_used = 0; a_fs_dir->addr = 0; }
/** * \internal * Prints file system category data for an exFAT file system to a file * handle. * * @param [in] a_fs Generic file system info structure for the file system. * @param [in] a_hFile The file handle. * @return 0 on success, 1 otherwise, per TSK convention. */ static uint8_t exfatfs_fsstat_fs_info(TSK_FS_INFO *a_fs, FILE *a_hFile) { FATFS_INFO *fatfs = NULL; EXFATFS_MASTER_BOOT_REC *exfatbs = NULL; TSK_FS_FILE *fs_file = NULL; assert(a_fs != NULL); assert(a_hFile != NULL); fatfs = (FATFS_INFO*)a_fs; exfatbs = (EXFATFS_MASTER_BOOT_REC*)&(fatfs->boot_sector_buffer); if ((fs_file = tsk_fs_file_alloc(a_fs)) == NULL) { return FATFS_FAIL; } if ((fs_file->meta = tsk_fs_meta_alloc(FATFS_FILE_CONTENT_LEN)) == NULL) { return FATFS_FAIL; } tsk_fprintf(a_hFile, "FILE SYSTEM INFORMATION\n"); tsk_fprintf(a_hFile, "--------------------------------------------\n"); tsk_fprintf(a_hFile, "File System Type: exFAT\n"); tsk_fprintf(a_hFile, "\nVolume Serial Number: %x%x-%x%x\n", exfatbs->vol_serial_no[3], exfatbs->vol_serial_no[2], exfatbs->vol_serial_no[1], exfatbs->vol_serial_no[0]); if (exfatfs_find_volume_label_dentry(fatfs, fs_file) == 0) { tsk_fprintf(a_hFile, "Volume Label (from root directory): %s\n", fs_file->meta->name2->name); } else { tsk_fprintf(a_hFile, "Volume Label:\n"); } tsk_fprintf(a_hFile, "File System Name (from MBR): %s\n", exfatbs->fs_name); tsk_fprintf(a_hFile, "File System Revision: %x.%x\n", exfatbs->fs_revision[1], exfatbs->fs_revision[0]); tsk_fprintf(a_hFile, "Partition Offset: %" PRIuDADDR "\n", tsk_getu64(a_fs->endian, exfatbs->partition_offset)); tsk_fprintf(a_hFile, "Number of FATs: %d\n", fatfs->numfat); tsk_fs_file_close(fs_file); return FATFS_OK; }
/* * Class: edu_uw_apl_commons_tsk4j_filesys_FileSystem * Method: fileOpen * Signature: (JLjava/lang/String;)Ledu/uw/apl/commons/tsk4j/filesys/File; */ JNIEXPORT jobject JNICALL Java_edu_uw_apl_commons_tsk4j_filesys_FileSystem_fileOpen (JNIEnv *env, jobject thiz, jlong nativePtr, jstring path ) { const char* pathC = (*env)->GetStringUTFChars( env, path, NULL ); TSK_FS_INFO* info = (TSK_FS_INFO*)nativePtr; TSK_FS_FILE* fsFile = tsk_fs_file_open( info, NULL, pathC ); if( !fsFile ) { (*env)->ReleaseStringUTFChars( env, path, pathC ); return (jobject)NULL; } jobject fileMeta = NULL; if( fsFile->meta ) { fileMeta = createFileMeta( env, fsFile->meta ); if( !fileMeta ) { (*env)->ReleaseStringUTFChars( env, path, pathC ); tsk_fs_file_close( fsFile ); return (jobject)NULL; } } jobject fileName = NULL; if( fsFile->name ) { fileName = createFileName( env, fsFile->name ); if( !fileName ) { (*env)->ReleaseStringUTFChars( env, path, pathC ); tsk_fs_file_close( fsFile ); return (jobject)NULL; } } jobject result = createFile( env, fsFile, thiz, fileMeta, fileName ); (*env)->ReleaseStringUTFChars( env, path, pathC ); return result; }
int testfile(TSK_FS_INFO * a_fs, TSK_INUM_T a_inum) { TSK_FS_FILE *file1 = NULL; if ((s_buf = (char *) malloc(a_fs->block_size)) == NULL) { fprintf(stderr, "Error allocating memory\n"); return 1; } file1 = tsk_fs_file_open_meta(a_fs, NULL, a_inum); if (file1 == NULL) { fprintf(stderr, "Error opening inode %" PRIuINUM "\n", a_inum); return 1; } s_file2 = tsk_fs_file_open_meta(a_fs, NULL, a_inum); if (s_file2 == NULL) { fprintf(stderr, "Error opening inode %" PRIuINUM "\n", a_inum); return 1; } s_off = 0; if (tsk_fs_file_walk(file1, (TSK_FS_FILE_WALK_FLAG_ENUM) 0, fw_action1, NULL)) { fprintf(stderr, "Error walking file inode: %" PRIuINUM "\n", a_inum); tsk_error_print(stderr); tsk_error_reset(); return 1; } free(s_buf); tsk_fs_file_close(file1); tsk_fs_file_close(s_file2); return 0; }
/* Place journal data in *fs * * Return 0 on success and 1 on error * */ uint8_t ext2fs_jopen(TSK_FS_INFO * fs, TSK_INUM_T inum) { EXT2FS_INFO *ext2fs = (EXT2FS_INFO *) fs; EXT2FS_JINFO *jinfo; // clean up any error messages that are lying around tsk_error_reset(); if (!fs) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "ext2fs_jopen: fs is null"); return 1; } ext2fs->jinfo = jinfo = (EXT2FS_JINFO *) tsk_malloc(sizeof(EXT2FS_JINFO)); if (jinfo == NULL) { return 1; } jinfo->j_inum = inum; jinfo->fs_file = tsk_fs_file_open_meta(fs, NULL, inum); if (!jinfo->fs_file) { free(jinfo); return 1; // error("error finding journal inode %" PRIu32, inum); } if (tsk_fs_file_walk(jinfo->fs_file, 0, load_sb_action, NULL)) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_FWALK; snprintf(tsk_errstr, TSK_ERRSTR_L, "Error loading ext3 journal"); tsk_fs_file_close(jinfo->fs_file); free(jinfo); return 1; } if (tsk_verbose) tsk_fprintf(stderr, "journal opened at inode %" PRIuINUM " bsize: %" PRIu32 " First JBlk: %" PRIuDADDR " Last JBlk: %" PRIuDADDR "\n", inum, jinfo->bsize, jinfo->first_block, jinfo->last_block); return 0; }
static TSK_WALK_RET_ENUM find_file_in_partiton( TSK_VS_INFO * vs, const TSK_VS_PART_INFO * part, void *ptr){ find_file_data *data = (find_file_data*)ptr; const char *file_path = data->full_path; TSK_FS_INFO *filesystem; TSK_FS_FILE *file; filesystem = tsk_fs_open_vol(part, TSK_FS_TYPE_DETECT); if (OPEN_FAIL(filesystem)) return TSK_WALK_CONT; file = tsk_fs_file_open(filesystem, NULL, file_path); if (OPEN_FAIL(file)) return TSK_WALK_CONT; data->file_found_in_partiton = 0; utarray_new(data->offsets_in_filesystem, &ut_tsk_daddr_tuple_icd); log_file_offsets_in_filesystem(data, file); if (data->file_found_in_partiton) { TSK_DADDR_T *p; for (p=(TSK_DADDR_T*)utarray_front(data->offsets_in_filesystem); p != NULL; p=(TSK_DADDR_T*)utarray_next(data->offsets_in_filesystem, p)) { TSK_DADDR_T offset_start_and_last[2] = { p[0] + part->start*vs->img_info->sector_size, p[1] + part->start*vs->img_info->sector_size }; utarray_push_back(data->offsets_in_disk, &offset_start_and_last); } data->file_found = 1; } utarray_free(data->offsets_in_filesystem); tsk_fs_file_close(file); tsk_fs_close(filesystem); return TSK_WALK_CONT; }
/** * \ingroup fslib * * Open a file given its metadata address. This function loads the metadata * and returns a handle that can be used to read and process the file. Note * that the returned TSK_FS_FILE structure will not have the file name set because * it was not used to load the file and this function does not search the * directory structure to find the name that points to the address. In general, * if you know the metadata address of a file, this function is more efficient * then tsk_fs_file_open, which first maps a file name to the metadata address * and then opens the file using this function. * * @param a_fs File system to analyze * @param a_fs_file Structure to store file data in or NULL to have one allocated. * @param a_addr Metadata address of file to lookup * @returns NULL on error */ TSK_FS_FILE * tsk_fs_file_open_meta(TSK_FS_INFO * a_fs, TSK_FS_FILE * a_fs_file, TSK_INUM_T a_addr) { TSK_FS_FILE *fs_file; if ((a_fs == NULL) || (a_fs->tag != TSK_FS_INFO_TAG)) { tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr ("tsk_fs_file_open_meta: called with NULL or unallocated structures"); return NULL; } fs_file = a_fs_file; if (fs_file == NULL) { if ((fs_file = tsk_fs_file_alloc(a_fs)) == NULL) return NULL; } else { /* if the structure passed has a name structure, free it * because we won't use it. */ if (fs_file->name) { tsk_fs_name_free(fs_file->name); fs_file->name = NULL; } // reset the rest of it tsk_fs_file_reset(fs_file); } if (a_fs->file_add_meta(a_fs, fs_file, a_addr)) { if (a_fs_file == NULL) tsk_fs_file_close(fs_file); return NULL; } return fs_file; }
int TskImageFileTsk::closeFile(const int handle) { // get the handle from m_openFiles TskImageFileTsk::OPEN_FILE * openFile = m_openFiles[handle]; if (openFile == NULL || openFile->fsFile == NULL) { std::wstringstream errorMsg; errorMsg << L"TskImageFileTsk::closeFile - Either OPEN_FILE ot TSK_FS_FILE is null." << std::endl; LOGERROR(errorMsg.str()); return -1; } // close the file tsk_fs_file_close(openFile->fsFile); // remove the entry from m_openFiles m_openFiles.erase(m_openFiles.begin() + handle); // delete the struct delete openFile; return 0; }
/* Compare the differences between dir_open_meta and dir_open * @param a_path Path of directory to open * @param a_addr The metadata address of the same directory as the path * @returns 1 if a test failed */ static int test_dir_open_apis(TSK_FS_INFO * a_fs, const char *a_path, TSK_INUM_T a_addr) { TSK_FS_DIR *fs_dir_m; TSK_FS_DIR *fs_dir_p; TSK_FS_DIR *fs_dir_tmp; TSK_FS_FILE *fs_file_m; TSK_FS_FILE *fs_file_p; int retval = 0; size_t entry = 0; // open via inode addr fs_dir_m = tsk_fs_dir_open_meta(a_fs, a_addr); if (!fs_dir_m) { fprintf(stderr, "Error opening dir %" PRIuINUM " via meta\n", a_addr); tsk_error_print(stderr); return 1; } /* open the root directory to throw some more state into the system * in case data is cached from first call */ fs_dir_tmp = tsk_fs_dir_open_meta(a_fs, a_fs->root_inum); if (!fs_dir_tmp) { fprintf(stderr, "Error opening root directory via meta\n"); tsk_error_print(stderr); return 1; } // open via path fs_dir_p = tsk_fs_dir_open(a_fs, a_path); if (!fs_dir_p) { fprintf(stderr, "Error opening directory %s\n", a_path); tsk_error_print(stderr); return 1; } // test that path has the name structure set (correctly) if ((fs_dir_p->fs_file == NULL) || (fs_dir_p->fs_file->name == NULL)) { fprintf(stderr, "dir opened via path has null name (%s)\n", a_path); retval = 1; goto open_cleanup; } if (fs_dir_p->fs_file->name->meta_addr != fs_dir_p->fs_file->meta->addr) { fprintf(stderr, "dir opened via path has different meta addresses in name and meta (%s) (%" PRIuINUM " vs %" PRIuINUM "\n", a_path, fs_dir_p->fs_file->name->meta_addr, fs_dir_p->fs_file->meta->addr); retval = 1; goto open_cleanup; } // verify both methods have same dir addr if (fs_dir_p->fs_file->meta->addr != fs_dir_m->fs_file->meta->addr) { fprintf(stderr, "parent dir addrs from fs_dir_open_meta and via path are different: %" PRIuINUM " vs %" PRIuINUM " (%s - %" PRIuINUM "\n", fs_dir_p->fs_file->meta->addr, fs_dir_m->fs_file->meta->addr, a_path, a_addr); retval = 1; goto open_cleanup; } // verify path method has same dir addr as open via meta if (fs_dir_p->fs_file->meta->addr != a_addr) { fprintf(stderr, "parent dir addrs from fs_dir_open is diff from meta address %" PRIuINUM " (%s - %" PRIuINUM "\n", fs_dir_p->fs_file->meta->addr, a_path, a_addr); retval = 1; goto open_cleanup; } // verify both have same size if (tsk_fs_dir_getsize(fs_dir_p) != tsk_fs_dir_getsize(fs_dir_m)) { fprintf(stderr, "sizes from fs_dir_open_meta and via path are different: %" PRIuSIZE " vs %" PRIuSIZE " (%s - %" PRIuINUM "\n", tsk_fs_dir_getsize(fs_dir_p), tsk_fs_dir_getsize(fs_dir_m), a_path, a_addr); retval = 1; goto open_cleanup; } // compare the first entry in both. if (tsk_fs_dir_getsize(fs_dir_p) == 0) { fprintf(stderr, "directory sizes are 0\n"); retval = 1; goto open_cleanup; } fs_file_m = tsk_fs_dir_get(fs_dir_m, 0); if (fs_file_m == NULL) { fprintf(stderr, "Error opening entry 0 from meta open: %" PRIuINUM "\n", a_addr); tsk_error_print(stderr); retval = 1; goto open_cleanup; } fs_file_p = tsk_fs_dir_get(fs_dir_p, 0); if (fs_file_p == NULL) { fprintf(stderr, "Error opening entry 0 from path open: %" PRIuINUM "\n", a_addr); tsk_error_print(stderr); retval = 1; goto open_cleanup; } if (compare_names(fs_file_p->name, fs_file_m->name, 1)) { fprintf(stderr, "results from entry 0 are different\n"); retval = 1; goto open_cleanup; } tsk_fs_file_close(fs_file_m); tsk_fs_file_close(fs_file_p); // compare the last entry in both entry = tsk_fs_dir_getsize(fs_dir_m) - 1; fs_file_m = tsk_fs_dir_get(fs_dir_m, entry); if (fs_file_m == NULL) { fprintf(stderr, "Error opening entry %" PRIuSIZE " from meta open: %" PRIuINUM "\n", entry, a_addr); tsk_error_print(stderr); retval = 1; goto open_cleanup; } fs_file_p = tsk_fs_dir_get(fs_dir_p, entry); if (fs_file_p == NULL) { fprintf(stderr, "Error opening entry %" PRIuSIZE " from path open: %" PRIuINUM "\n", entry, a_addr); tsk_error_print(stderr); retval = 1; goto open_cleanup; } if (compare_names(fs_file_p->name, fs_file_m->name, 1)) { fprintf(stderr, "results from entry %" PRIuSIZE " are different\n", entry); retval = 1; goto open_cleanup; } tsk_fs_file_close(fs_file_m); tsk_fs_file_close(fs_file_p); open_cleanup: tsk_fs_dir_close(fs_dir_p); tsk_fs_dir_close(fs_dir_tmp); tsk_fs_dir_close(fs_dir_m); return retval; }
/* dir_walk local function that is used for recursive calls. Callers * should initially call the non-local version. */ static TSK_WALK_RET_ENUM tsk_fs_dir_walk_lcl(TSK_FS_INFO * a_fs, DENT_DINFO * a_dinfo, TSK_INUM_T a_addr, TSK_FS_DIR_WALK_FLAG_ENUM a_flags, TSK_FS_DIR_WALK_CB a_action, void *a_ptr) { TSK_FS_DIR *fs_dir; TSK_FS_FILE *fs_file; size_t i; // get the list of entries in the directory if ((fs_dir = tsk_fs_dir_open_meta(a_fs, a_addr)) == NULL) { return TSK_WALK_ERROR; } /* Allocate a file structure for the callbacks. We * will allocate fs_meta structures as needed and * point into the fs_dir structure for the names. */ if ((fs_file = tsk_fs_file_alloc(a_fs)) == NULL) { tsk_fs_dir_close(fs_dir); return TSK_WALK_ERROR; } for (i = 0; i < fs_dir->names_used; i++) { TSK_WALK_RET_ENUM retval; /* Point name to the buffer of names. We need to be * careful about resetting this before we free fs_file */ fs_file->name = (TSK_FS_NAME *) & fs_dir->names[i]; /* load the fs_meta structure if possible. * Must have non-zero inode addr or have allocated name (if inode is 0) */ if (((fs_file->name->meta_addr) || (fs_file->name->flags & TSK_FS_NAME_FLAG_ALLOC))) { if (a_fs->file_add_meta(a_fs, fs_file, fs_file->name->meta_addr)) { if (tsk_verbose) tsk_error_print(stderr); tsk_error_reset(); } } // call the action if we have the right flags. if ((fs_file->name->flags & a_flags) == fs_file->name->flags) { retval = a_action(fs_file, a_dinfo->dirs, a_ptr); if (retval == TSK_WALK_STOP) { tsk_fs_dir_close(fs_dir); fs_file->name = NULL; tsk_fs_file_close(fs_file); /* free the list -- fs_dir_walk has no way * of knowing that we stopped early w/out error. */ if (a_dinfo->save_inum_named) { tsk_list_free(a_dinfo->list_inum_named); a_dinfo->list_inum_named = NULL; a_dinfo->save_inum_named = 0; } return TSK_WALK_STOP; } else if (retval == TSK_WALK_ERROR) { tsk_fs_dir_close(fs_dir); fs_file->name = NULL; tsk_fs_file_close(fs_file); return TSK_WALK_ERROR; } } // save the inode info for orphan finding - if requested if ((a_dinfo->save_inum_named) && (fs_file->meta) && (fs_file->meta->flags & TSK_FS_META_FLAG_UNALLOC)) { if (tsk_list_add(&a_dinfo->list_inum_named, fs_file->meta->addr)) { // if there is an error, then clear the list tsk_list_free(a_dinfo->list_inum_named); a_dinfo->list_inum_named = NULL; a_dinfo->save_inum_named = 0; } } /* Recurse into a directory if: * - Both dir entry and inode have DIR type (or name is undefined) * - Recurse flag is set * - dir entry is allocated OR both are unallocated * - not one of the '.' or '..' entries * - A Non-Orphan Dir or the Orphan Dir with the NOORPHAN flag not set. */ if (((fs_file->name->type == TSK_FS_NAME_TYPE_DIR) || (fs_file->name->type == TSK_FS_NAME_TYPE_UNDEF)) && (fs_file->meta) && (fs_file->meta->type == TSK_FS_META_TYPE_DIR) && (a_flags & TSK_FS_DIR_WALK_FLAG_RECURSE) && ((fs_file->name->flags & TSK_FS_NAME_FLAG_ALLOC) || ((fs_file->name->flags & TSK_FS_NAME_FLAG_UNALLOC) && (fs_file->meta->flags & TSK_FS_META_FLAG_UNALLOC)) ) && (!TSK_FS_ISDOT(fs_file->name->name)) && ((fs_file->name->meta_addr != TSK_FS_ORPHANDIR_INUM(a_fs)) || ((a_flags & TSK_FS_DIR_WALK_FLAG_NOORPHAN) == 0)) ) { /* Make sure we do not get into an infinite loop */ if (0 == tsk_stack_find(a_dinfo->stack_seen, fs_file->name->meta_addr)) { int depth_added = 0; uint8_t save_bak = 0; if (tsk_stack_push(a_dinfo->stack_seen, fs_file->name->meta_addr)) { tsk_fs_dir_close(fs_dir); fs_file->name = NULL; tsk_fs_file_close(fs_file); return TSK_WALK_ERROR; } if ((a_dinfo->depth < MAX_DEPTH) && (DIR_STRSZ > strlen(a_dinfo->dirs) + strlen(fs_file->name->name))) { a_dinfo->didx[a_dinfo->depth] = &a_dinfo->dirs[strlen(a_dinfo->dirs)]; strncpy(a_dinfo->didx[a_dinfo->depth], fs_file->name->name, DIR_STRSZ - strlen(a_dinfo->dirs)); strncat(a_dinfo->dirs, "/", DIR_STRSZ); depth_added = 1; } a_dinfo->depth++; /* We do not want to save info about named unalloc files * when we go into the Orphan directory (because then we have * no orphans). So, disable it for this recursion. */ if (fs_file->name->meta_addr == TSK_FS_ORPHANDIR_INUM(a_fs)) { save_bak = a_dinfo->save_inum_named; a_dinfo->save_inum_named = 0; } retval = tsk_fs_dir_walk_lcl(a_fs, a_dinfo, fs_file->name->meta_addr, a_flags, a_action, a_ptr); if (retval == TSK_WALK_ERROR) { /* If this fails because the directory could not be * loaded, then we still continue */ if (tsk_verbose) { tsk_fprintf(stderr, "tsk_fs_dir_walk_lcl: error reading directory: %" PRIuINUM "\n", fs_file->name->meta_addr); tsk_error_print(stderr); } tsk_error_reset(); } else if (retval == TSK_WALK_STOP) { tsk_fs_dir_close(fs_dir); fs_file->name = NULL; tsk_fs_file_close(fs_file); return TSK_WALK_STOP; } // reset the save status if (fs_file->name->meta_addr == TSK_FS_ORPHANDIR_INUM(a_fs)) { a_dinfo->save_inum_named = save_bak; } tsk_stack_pop(a_dinfo->stack_seen); a_dinfo->depth--; if (depth_added) *a_dinfo->didx[a_dinfo->depth] = '\0'; } else { if (tsk_verbose) fprintf(stderr, "tsk_fs_dir_walk_lcl: Loop detected with address %" PRIuINUM, fs_file->name->meta_addr); } } // remove the pointer to name buffer fs_file->name = NULL; // free the metadata if we allocated it if (fs_file->meta) { tsk_fs_meta_close(fs_file->meta); fs_file->meta = NULL; } } tsk_fs_dir_close(fs_dir); fs_file->name = NULL; tsk_fs_file_close(fs_file); return TSK_WALK_CONT; }
void tsk_get_file(const char* imgname,uint64_t haddr_img_offset, const char* file_path, const char* destination, uint64_t start_offset, int read_file_len ) { TSK_IMG_INFO *img; TSK_VS_INFO *vs; TSK_FS_INFO *fs; uint8_t id_used = 0, type_used = 0; TSK_DADDR_T partition_offset = 0; TSK_DADDR_T block_img_offset = 0; TSK_DADDR_T part_byte_offset = 0; TSK_DADDR_T part_block_offset = 0; MBA_IFIND_DATA_DATA* ifind_data; TSK_IMG_TYPE_ENUM imgtype; MBA_FFIND_DATA* ffind_data; TSK_FS_FILE *file; FILE* writeHive; char *temp; //open image imgtype = tsk_img_type_toid(QCOW_IMG_TYPE); img = tsk_img_open_sing(imgname, imgtype, 0); if(img == NULL) { printf("Image Open Failed!!\n"); return; } if(haddr_img_offset >= img->size) { printf("Request haddr is larger than image size\n"); return; } //open volume vs = tsk_vs_open(img, 0 , TSK_VS_TYPE_DETECT); if(vs==NULL) { printf("Volume Open Failed!!\n"); return; } //calculate block address block_img_offset = haddr_img_offset/img->sector_size; //search the partition contain the target block partition_offset = search_partition(vs, block_img_offset); if(partition_offset == 0) { printf("Cannot found partition contains the target haddr\n"); return; } //open the partition's file system fs = tsk_fs_open_img(img, partition_offset * img->sector_size, TSK_FS_TYPE_DETECT); if(fs==NULL) { printf("Cannot open file system\n"); return; } //calculate offset to the current partition part_byte_offset = haddr_img_offset - (partition_offset * img->sector_size); part_block_offset = part_byte_offset/fs->block_size; file = tsk_fs_file_open( fs, NULL, file_path); if ( OPEN_FAIL(file) ) printf("open file fail\n\n"); temp = calloc( read_file_len, sizeof(char)); int size = tsk_fs_file_read( file, start_offset, temp, read_file_len, TSK_FS_FILE_READ_FLAG_NONE ); tsk_fs_file_close(file); writeHive = fopen( destination, "w" ); if ( writeHive == NULL ) printf("Open fail"); else { fwrite( temp, size, sizeof(char), writeHive ); fclose(writeHive); } // else free(temp); //find the inode of this block ifind_data = fs_ifind_data(fs, (TSK_FS_IFIND_FLAG_ENUM) 0, part_block_offset); if(ifind_data == NULL) { return; } if(ifind_data->found!=1) { printf("Inode not found\n"); return; } //Find the inode's filename //Note: Do Not Know what to fill in variable type_used and id_used ffind_data = fs_ffind(fs, 0, ifind_data->curinode, ifind_data->curtype , type_used, ifind_data->curid , id_used, (TSK_FS_DIR_WALK_FLAG_RECURSE | TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC)); if(ffind_data==NULL){ printf("Cannot found fdata associate with inode\n"); return; } free(ifind_data); return; }
/** * Populates the buffer with the contents of the specified filename. * * \param id_number The id number of the file (in our case the inode) * \param filename The real filename for this file. * \param buf The buffer to write data into * \param size The size of the buffer * \param offset The offset into the file the data should be taken from. * \returns The amount of bytes read, or -1 on error. */ int do_read(unsigned int id_number, const char *filename, char *buf, size_t size, off_t offset) { //FILE* outfile = fopen("/tmp/sleuth.txt", "a"); //fprintf(outfile, "do_read(%u, %s, %p, %zu, %zu);\n", id_number, filename, buf, size, offset); //fflush(outfile); //fprintf(outfile, "inode_buffer=%p, inode_buffered=%lld, inode_buf_pos=%llu, end=%llu\n", inode_buffer, inode_buffered, inode_buffer_pos, inode_buffer_pos + inode_buffer_size); //fflush(outfile); // If the data is already cached in our buffer then read from that instead if ((inode_buffer != NULL) && (id_number == inode_buffered) && (offset >= inode_buffer_pos) && (offset < inode_buffer_pos + inode_buffer_size)) { if ((offset + size) <= (inode_buffer_pos + inode_buffer_size)) { offset = offset % BUFFER_AMOUNT; memcpy(buf, inode_buffer + offset, size); //fprintf(outfile, "Fully cached!\n"); //fclose(outfile); return size; } // If we're here then we've cached part of the data needed, but not all of it // (ie, the data requested spans a block boundary) offset = offset % BUFFER_AMOUNT; memcpy(buf, inode_buffer + offset, inode_buffer_size - offset); int ret_size = inode_buffer_size - offset; ret_size += do_read(id_number, filename, buf + ret_size, size - ret_size, inode_buffer_pos + inode_buffer_size); //fprintf(outfile, "Partially cached: Size = %d\n", ret_size); //fclose(outfile); return ret_size; } TSK_FS_FILE *fs_file = tsk_fs_file_open_meta(fs_info, NULL, id_number); if (fs_file == NULL) { //fprintf(outfile, "FS file not found?\n"); //fclose(outfile); return -1; } // If the file is larger than FILE_SIZE_THRESHOLD, and the offset is larger // than FILE_OFFSET_THRESHOLD, buffer up BUFFER_AMOUNT and return from that if (fs_file->meta != NULL) { //fprintf(outfile, "File size is %" PRIdDADDR" bytes\n", fs_file->meta->size); //fflush(outfile); if (offset >= fs_file->meta->size) { //fprintf(outfile, "Reading beyond end of file\n"); //fclose(outfile); return 0; } if ((fs_file->meta->size >= FILE_SIZE_THRESHOLD) && (offset >= FILE_OFFSET_THRESHOLD)) { if (inode_buffer == NULL) { inode_buffer = (unsigned char *) g_malloc(BUFFER_AMOUNT); } inode_buffered = id_number; inode_buffer_pos = (offset / BUFFER_AMOUNT) * BUFFER_AMOUNT; struct read_struct r; r.buf = inode_buffer; r.offset = inode_buffer_pos; r.size = BUFFER_AMOUNT; r.read = 0; //fprintf(outfile, "Caching data...offset = %zu, size =%zu\n", r.offset, r.size); //fflush(outfile); tsk_fs_file_walk(fs_file, TSK_FS_FILE_WALK_FLAG_NONE, read_file_content_callback, &r); inode_buffer_size = r.read; //fprintf(outfile, "Recursing to read data\n"); //fclose(outfile); return do_read(id_number, filename, buf, size, offset); } } struct read_struct r; r.buf = (unsigned char *) buf; r.offset = offset; r.size = size; r.read = 0; tsk_fs_file_walk(fs_file, TSK_FS_FILE_WALK_FLAG_NONE, read_file_content_callback, &r); tsk_fs_file_close(fs_file); //fprintf(outfile, "Simple read %zu\n", r.read); //fclose(outfile); return r.read; }
/** * Open a directory and cycle through its contents. Read each file and recurse * into each directory. * * @param fs_info File system to process * @param stack Stack to prevent infinite recursion loops * @param dir_inum Metadata address of directory to open * @param path Path of directory being opened * @returns 1 on error */ static uint8_t proc_dir(TSK_FS_INFO * fs_info, TSK_STACK * stack, TSK_INUM_T dir_inum, const char *path) { TSK_FS_DIR *fs_dir; size_t i; char *path2 = NULL; char *buf = NULL; // open the directory if ((fs_dir = tsk_fs_dir_open_meta(fs_info, dir_inum)) == NULL) { fprintf(stderr, "Error opening directory: %" PRIuINUM "\n", dir_inum); tsk_error_print(stderr); return 1; } /* These should be dynamic lengths, but this is just a sample program. * Allocate heap space instead of stack to prevent overflow for deep * directories. */ if ((path2 = (char *) malloc(4096)) == NULL) { return 1; } if ((buf = (char *) malloc(2048)) == NULL) { free(path2); return 1; } // cycle through each entry for (i = 0; i < tsk_fs_dir_getsize(fs_dir); i++) { TSK_FS_FILE *fs_file; TSK_OFF_T off = 0; size_t len = 0; // get the entry if ((fs_file = tsk_fs_dir_get(fs_dir, i)) == NULL) { fprintf(stderr, "Error getting directory entry %" PRIuSIZE " in directory %" PRIuINUM "\n", i, dir_inum); tsk_error_print(stderr); free(path2); free(buf); return 1; } /* Ignore NTFS System files */ if ((TSK_FS_TYPE_ISNTFS(fs_file->fs_info->ftype)) && (fs_file->name->name[0] == '$')) { tsk_fs_file_close(fs_file); continue; } //printf("Processing %s/%s\n", path, fs_file->name->name); // make sure it's got metadata and not only a name if (fs_file->meta) { ssize_t cnt; /* Note that we could also cycle through all of the attributes in the * file by using one of the tsk_fs_attr_get() functions and reading it * with tsk_fs_attr_read(). See the File Systems section of the Library * User's Guide for more details: * http://www.sleuthkit.org/sleuthkit/docs/api-docs/ */ // read file contents if (fs_file->meta->type == TSK_FS_META_TYPE_REG) { int myflags = 0; for (off = 0; off < fs_file->meta->size; off += len) { if (fs_file->meta->size - off < 2048) len = (size_t) (fs_file->meta->size - off); else len = 2048; cnt = tsk_fs_file_read(fs_file, off, buf, len, (TSK_FS_FILE_READ_FLAG_ENUM) myflags); if (cnt == -1) { // could check tsk_errno here for a recovery error (TSK_ERR_FS_RECOVER) fprintf(stderr, "Error reading %s file: %s\n", ((fs_file->name-> flags & TSK_FS_NAME_FLAG_UNALLOC) || (fs_file->meta-> flags & TSK_FS_META_FLAG_UNALLOC)) ? "unallocated" : "allocated", fs_file->name->name); tsk_error_print(stderr); break; } else if (cnt != (ssize_t) len) { fprintf(stderr, "Warning: %" PRIuSIZE " of %" PRIuSIZE " bytes read from %s file %s\n", cnt, len, ((fs_file->name-> flags & TSK_FS_NAME_FLAG_UNALLOC) || (fs_file->meta-> flags & TSK_FS_META_FLAG_UNALLOC)) ? "unallocated" : "allocated", fs_file->name->name); } // do something with the data... } } // recurse into another directory (unless it is a '.' or '..') else if (fs_file->meta->type == TSK_FS_META_TYPE_DIR) { if (TSK_FS_ISDOT(fs_file->name->name) == 0) { // only go in if it is not on our stack if (tsk_stack_find(stack, fs_file->meta->addr) == 0) { // add the address to the top of the stack tsk_stack_push(stack, fs_file->meta->addr); snprintf(path2, 4096, "%s/%s", path, fs_file->name->name); if (proc_dir(fs_info, stack, fs_file->meta->addr, path2)) { tsk_fs_file_close(fs_file); tsk_fs_dir_close(fs_dir); free(path2); free(buf); return 1; } // pop the address tsk_stack_pop(stack); } } } } tsk_fs_file_close(fs_file); } tsk_fs_dir_close(fs_dir); free(path2); free(buf); return 0; }
uint8_t ntfs_find_file(TSK_FS_INFO * fs, TSK_INUM_T inode_toid, uint32_t type_toid, uint8_t type_used, uint16_t id_toid, uint8_t id_used, TSK_FS_DIR_WALK_FLAG_ENUM dir_walk_flags, TSK_FS_DIR_WALK_CB action, void *ptr) { TSK_FS_META_NAME_LIST *fs_name_list; NTFS_INFO *ntfs = (NTFS_INFO *) fs; char *attr = NULL; NTFS_DINFO dinfo; TSK_FS_FILE *fs_file; /* sanity check */ if (inode_toid < fs->first_inum || inode_toid > fs->last_inum) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "ntfs_find_file: invalid inode value: %" PRIuINUM "\n", inode_toid); return 1; } // open the file to ID fs_file = tsk_fs_file_open_meta(fs, NULL, inode_toid); if (fs_file == NULL) { strncat(tsk_errstr2, " - ntfs_find_file", TSK_ERRSTR_L - strlen(tsk_errstr2)); tsk_fs_file_close(fs_file); return 1; } // see if its allocation status meets the callback needs if ((fs_file->meta->flags & TSK_FS_META_FLAG_ALLOC) && ((dir_walk_flags & TSK_FS_DIR_WALK_FLAG_ALLOC) == 0)) { tsk_fs_file_close(fs_file); return 1; } else if ((fs_file->meta->flags & TSK_FS_META_FLAG_UNALLOC) && ((dir_walk_flags & TSK_FS_DIR_WALK_FLAG_UNALLOC) == 0)) { tsk_fs_file_close(fs_file); return 1; } /* Allocate a name and fill in some details */ if ((fs_file->name = tsk_fs_name_alloc(NTFS_MAXNAMLEN_UTF8, 0)) == NULL) { return 1; } fs_file->name->meta_addr = inode_toid; fs_file->name->meta_seq = 0; fs_file->name->flags = ((tsk_getu16(fs->endian, ntfs-> mft->flags) & NTFS_MFT_INUSE) ? TSK_FS_NAME_FLAG_ALLOC : TSK_FS_NAME_FLAG_UNALLOC); memset(&dinfo, 0, sizeof(NTFS_DINFO)); /* in this function, we use the dinfo->dirs array in the opposite order. * we set the end of it to NULL and then prepend the * directories to it * * dinfo->didx[dinfo->depth] will point to where the current level started their * dir name */ dinfo.dirs[DIR_STRSZ - 2] = '/'; dinfo.dirs[DIR_STRSZ - 1] = '\0'; dinfo.didx[0] = &dinfo.dirs[DIR_STRSZ - 2]; dinfo.depth = 1; /* Get the name for the attribute - if specified */ if (type_used) { const TSK_FS_ATTR *fs_attr; if (id_used) fs_attr = tsk_fs_attrlist_get_id(fs_file->meta->attr, type_toid, id_toid); else fs_attr = tsk_fs_attrlist_get(fs_file->meta->attr, type_toid); if (!fs_attr) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "find_file: Type %" PRIu32 " Id %" PRIu16 " not found in MFT %" PRIuINUM "", type_toid, id_toid, inode_toid); tsk_fs_file_close(fs_file); return 1; } /* only add the attribute name if it is the non-default data stream */ if (strcmp(fs_attr->name, "$Data") != 0) attr = fs_attr->name; } /* loop through all the names it may have */ for (fs_name_list = fs_file->meta->name2; fs_name_list != NULL; fs_name_list = fs_name_list->next) { int retval; /* Append on the attribute name, if it exists */ if (attr != NULL) { snprintf(fs_file->name->name, fs_file->name->name_size, "%s:%s", fs_name_list->name, attr); } else { strncpy(fs_file->name->name, fs_name_list->name, fs_file->name->name_size); } /* if this is in the root directory, then call back */ if (fs_name_list->par_inode == NTFS_ROOTINO) { retval = action(fs_file, dinfo.didx[0], 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; } } /* call the recursive function on the parent to get the full path */ else { if (ntfs_find_file_rec(fs, &dinfo, fs_file, fs_name_list, action, ptr)) { tsk_fs_file_close(fs_file); return 1; } } } /* end of name loop */ tsk_fs_file_close(fs_file); return 0; }
/* * Looks up the parent inode described in fs_name. * * fs_name was filled in by ntfs_find_file and will get the final path * added to it before action is called * * return 1 on error and 0 on success */ static uint8_t ntfs_find_file_rec(TSK_FS_INFO * fs, NTFS_DINFO * dinfo, TSK_FS_FILE * fs_file, TSK_FS_META_NAME_LIST * fs_name_list, TSK_FS_DIR_WALK_CB action, void *ptr) { TSK_FS_FILE *fs_file_par; TSK_FS_META_NAME_LIST *fs_name_list_par; uint8_t decrem = 0; size_t len = 0, i; char *begin = NULL; int retval; if (fs_name_list->par_inode < fs->first_inum || fs_name_list->par_inode > fs->last_inum) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "invalid inode value: %" PRIuINUM "\n", fs_name_list->par_inode); return 1; } fs_file_par = tsk_fs_file_open_meta(fs, NULL, fs_name_list->par_inode); if (fs_file_par == NULL) { strncat(tsk_errstr2, " - ntfs_find_file_rec", TSK_ERRSTR_L - strlen(tsk_errstr2)); return 1; } /* * Orphan File * This occurs when the file is deleted and either: * - The parent is no longer a directory * - The sequence number of the parent is no longer correct */ if ((fs_file_par->meta->type != TSK_FS_META_TYPE_DIR) || (fs_file_par->meta->seq != fs_name_list->par_seq)) { char *str = TSK_FS_ORPHAN_STR; len = strlen(str); /* @@@ There should be a sanity check here to verify that the * previous name was unallocated ... but how do I get it again? */ if ((((uintptr_t) dinfo->didx[dinfo->depth - 1] - len) >= (uintptr_t) & dinfo->dirs[0]) && (dinfo->depth < MAX_DEPTH)) { begin = dinfo->didx[dinfo->depth] = (char *) ((uintptr_t) dinfo->didx[dinfo->depth - 1] - len); dinfo->depth++; decrem = 1; for (i = 0; i < len; i++) begin[i] = str[i]; } retval = action(fs_file, begin, ptr); if (decrem) dinfo->depth--; tsk_fs_file_close(fs_file_par); return (retval == TSK_WALK_ERROR) ? 1 : 0; } for (fs_name_list_par = fs_file_par->meta->name2; fs_name_list_par != NULL; fs_name_list_par = fs_name_list_par->next) { len = strlen(fs_name_list_par->name); /* do some length checks on the dir structure * if we can't fit it then forget about it */ if ((((uintptr_t) dinfo->didx[dinfo->depth - 1] - len - 1) >= (uintptr_t) & dinfo->dirs[0]) && (dinfo->depth < MAX_DEPTH)) { begin = dinfo->didx[dinfo->depth] = (char *) ((uintptr_t) dinfo->didx[dinfo->depth - 1] - len - 1); dinfo->depth++; decrem = 1; *begin = '/'; for (i = 0; i < len; i++) begin[i + 1] = fs_name_list_par->name[i]; } else { begin = dinfo->didx[dinfo->depth]; decrem = 0; } /* if we are at the root, then fill out the rest of fs_name with * the full path and call the action */ if (fs_name_list_par->par_inode == NTFS_ROOTINO) { /* increase the path by one so that we do not pass the '/' * if we do then the printed result will have '//' at * the beginning */ if (TSK_WALK_ERROR == action(fs_file, (const char *) ((uintptr_t) begin + 1), ptr)) { tsk_fs_file_close(fs_file_par); return 1; } } /* otherwise, recurse some more */ else { if (ntfs_find_file_rec(fs, dinfo, fs_file, fs_name_list_par, action, ptr)) { tsk_fs_file_close(fs_file_par); return 1; } } /* if we incremented before, then decrement the depth now */ if (decrem) dinfo->depth--; } tsk_fs_file_close(fs_file_par); return 0; }
/* Verify that all attributes can be accessed from both get_idx and get_type... * @param a_addr The metadata address of the file to analyze * @param a_len Expected number of attributes in file. * @returns 1 if a test failed */ static int test_get_apis(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr, int a_len) { TSK_FS_FILE *fs_file; int retval = 0; // open the file fs_file = tsk_fs_file_open_meta(a_fs, NULL, a_addr); if (!fs_file) { fprintf(stderr, "Error opening file %" PRIuINUM " via meta\n", a_addr); tsk_error_print(stderr); return 1; } int len = tsk_fs_file_attr_getsize(fs_file); if (len != a_len) { fprintf(stderr, "%" PRIuINUM " attribute count diff from expected (%d vs %d)\n", a_addr, a_len, len); tsk_error_print(stderr); return 1; } for (int i = 0; i < len; i++) { // get the attribute by index const TSK_FS_ATTR *fs_attr = tsk_fs_file_attr_get_idx(fs_file, i); if (!fs_attr) { fprintf(stderr, "Error getting attribute %d from %" PRIuINUM "\n", i, a_addr); tsk_error_print(stderr); return 1; } // verify we can also get it via type / id const TSK_FS_ATTR *fs_attr2 = tsk_fs_file_attr_get_type(fs_file, fs_attr->type, fs_attr->id, 1); if (!fs_attr2) { fprintf(stderr, "Error getting attribute %d-%d from %" PRIuINUM "\n", fs_attr->type, fs_attr->id, a_addr); tsk_error_print(stderr); return 1; } if ((fs_attr->type != fs_attr2->type) || (fs_attr->id != fs_attr2->id)) { fprintf(stderr, "Attribute from get_type not expected %d-%d vs %d-%d from %" PRIuINUM "\n", fs_attr->type, fs_attr->id, fs_attr2->type, fs_attr2->id, a_addr); tsk_error_print(stderr); return 1; } if (fs_attr != fs_attr2) { fprintf(stderr, "Attribute from get_type not same addr as original %lu vs %lu from %" PRIuINUM "\n", (long) fs_attr, (long) fs_attr2, a_addr); tsk_error_print(stderr); return 1; } // verify we also get something via only type fs_attr2 = tsk_fs_file_attr_get_type(fs_file, fs_attr->type, 0, 0); if (!fs_attr2) { fprintf(stderr, "Error getting attribute %d (no id) from %" PRIuINUM "\n", fs_attr->type, a_addr); tsk_error_print(stderr); return 1; } if (fs_attr->type != fs_attr2->type) { fprintf(stderr, "Attribute from get_type (no id) not expected %d vs %d from %" PRIuINUM "\n", fs_attr->type, fs_attr2->type, a_addr); tsk_error_print(stderr); return 1; } // Try with a "random" ID: Note this atribute could actually exist... fs_attr2 = tsk_fs_file_attr_get_type(fs_file, fs_attr->type, 0xfd, 1); if (fs_attr2) { fprintf(stderr, "Got unexpected attribute %d-0xfd (random ID) from %" PRIuINUM "\n", fs_attr->type, a_addr); tsk_error_print(stderr); return 1; } else if (tsk_error_get_errno() != TSK_ERR_FS_ATTR_NOTFOUND) { fprintf(stderr, "Unexpected error code %x from getting %d-0xfd (random ID) from %" PRIuINUM "\n", (int)tsk_error_get_errno(), fs_attr->type, a_addr); tsk_error_print(stderr); return 1; } tsk_error_reset(); // Try with a "random" type Note this atribute could actually exist... fs_attr2 = tsk_fs_file_attr_get_type(fs_file, (TSK_FS_ATTR_TYPE_ENUM) (fs_attr->type + 37), 0, 0); if (fs_attr2) { fprintf(stderr, "Got unexpected attribute %d-X (random type, no id) from %" PRIuINUM "\n", fs_attr->type + 37, a_addr); tsk_error_print(stderr); return 1; } else if (tsk_error_get_errno() != TSK_ERR_FS_ATTR_NOTFOUND) { fprintf(stderr, "Unexpected error code %x from getting %d-X (random type, no id) from %" PRIuINUM "\n", (int)tsk_error_get_errno(), fs_attr->type, a_addr); tsk_error_print(stderr); return 1; } tsk_error_reset(); } tsk_fs_file_close(fs_file); return retval; }
/** * \ingroup fslib * * Find the meta data address for a given file name (UTF-8). * The basic idea of the function is to break the given name into its * subdirectories and start looking for each (starting in the root * directory). * * @param a_fs FS to analyze * @param a_path UTF-8 path of file to search for * @param [out] a_result Meta data address of file * @param [out] a_fs_name Copy of name details (or NULL if details not wanted) * @returns -1 on (system) error, 0 if found, and 1 if not found */ int8_t tsk_fs_path2inum(TSK_FS_INFO * a_fs, const char *a_path, TSK_INUM_T * a_result, TSK_FS_NAME * a_fs_name) { char *cpath; size_t clen; char *cur_dir; // The "current" directory or file we are looking for char *cur_attr; // The "current" attribute of the dir we are looking for TSK_INUM_T next_meta; uint8_t is_done; char *strtok_last; *a_result = 0; // copy path to a buffer that we can modify clen = strlen(a_path) + 1; if ((cpath = (char *) tsk_malloc(clen)) == NULL) { return -1; } strncpy(cpath, a_path, clen); // Get the first part of the directory path. cur_dir = (char *) strtok_r(cpath, "/", &strtok_last); cur_attr = NULL; /* If there is no token, then only a '/' was given */ if (cur_dir == NULL) { free(cpath); *a_result = a_fs->root_inum; // create the dummy entry if needed if (a_fs_name) { a_fs_name->meta_addr = a_fs->root_inum; // Note that we are not filling in meta_seq -- we could, we just aren't a_fs_name->type = TSK_FS_NAME_TYPE_DIR; a_fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; if (a_fs_name->name) a_fs_name->name[0] = '\0'; if (a_fs_name->shrt_name) a_fs_name->shrt_name[0] = '\0'; } return 0; } /* If this is NTFS, separate out the attribute of the current directory */ if (TSK_FS_TYPE_ISNTFS(a_fs->ftype) && ((cur_attr = strchr(cur_dir, ':')) != NULL)) { *(cur_attr) = '\0'; cur_attr++; } if (tsk_verbose) tsk_fprintf(stderr, "Looking for %s\n", cur_dir); // initialize the first place to look, the root dir next_meta = a_fs->root_inum; // we loop until we know the outcome and then exit. // everything should return from inside the loop. is_done = 0; while (is_done == 0) { size_t i; TSK_FS_FILE *fs_file_alloc = NULL; // set to the allocated file that is our target TSK_FS_FILE *fs_file_del = NULL; // set to an unallocated file that matches our criteria TSK_FS_DIR *fs_dir = NULL; // open the next directory in the recursion if ((fs_dir = tsk_fs_dir_open_meta(a_fs, next_meta)) == NULL) { free(cpath); return -1; } /* Verify this is indeed a directory. We had one reported * problem where a file was a disk image and opening it as * a directory found the directory entries inside of the file * and this caused problems... */ if ( !TSK_FS_IS_DIR_META(fs_dir->fs_file->meta->type)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_GENFS); tsk_error_set_errstr("Address %" PRIuINUM " is not for a directory\n", next_meta); free(cpath); return -1; } // cycle through each entry for (i = 0; i < tsk_fs_dir_getsize(fs_dir); i++) { TSK_FS_FILE *fs_file; uint8_t found_name = 0; if ((fs_file = tsk_fs_dir_get(fs_dir, i)) == NULL) { tsk_fs_dir_close(fs_dir); free(cpath); return -1; } /* * Check if this is the name that we are currently looking for, * as identified in 'cur_dir' */ if ((fs_file->name->name) && (a_fs->name_cmp(a_fs, fs_file->name->name, cur_dir) == 0)) { found_name = 1; } else if ((fs_file->name->shrt_name) && (a_fs->name_cmp(a_fs, fs_file->name->shrt_name, cur_dir) == 0)) { found_name = 1; } /* For NTFS, we have to check the attribute name. */ if ((found_name == 1) && (TSK_FS_TYPE_ISNTFS(a_fs->ftype))) { /* ensure we have the right attribute name */ if (cur_attr != NULL) { found_name = 0; if (fs_file->meta) { int cnt, i; // cycle through the attributes cnt = tsk_fs_file_attr_getsize(fs_file); for (i = 0; i < cnt; i++) { const TSK_FS_ATTR *fs_attr = tsk_fs_file_attr_get_idx(fs_file, i); if (!fs_attr) continue; if ((fs_attr->name) && (a_fs->name_cmp(a_fs, fs_attr->name, cur_attr) == 0)) { found_name = 1; break; } } } } } if (found_name) { /* If we found our file and it is allocated, then stop. If * it is unallocated, keep on going to see if we can get * an allocated hit */ if (fs_file->name->flags & TSK_FS_NAME_FLAG_ALLOC) { fs_file_alloc = fs_file; break; } else { // if we already have an unalloc and its addr is 0, then use the new one if ((fs_file_del) && (fs_file_del->name->meta_addr == 0)) { tsk_fs_file_close(fs_file_del); } fs_file_del = fs_file; } } // close the file if we did not save it for future analysis. else { tsk_fs_file_close(fs_file); fs_file = NULL; } } // we found a directory, go into it if ((fs_file_alloc) || (fs_file_del)) { const char *pname; TSK_FS_FILE *fs_file_tmp; // choose the alloc one first (if they both exist) if (fs_file_alloc) fs_file_tmp = fs_file_alloc; else fs_file_tmp = fs_file_del; pname = cur_dir; // save a copy of the current name pointer // advance to the next name cur_dir = (char *) strtok_r(NULL, "/", &(strtok_last)); cur_attr = NULL; if (tsk_verbose) tsk_fprintf(stderr, "Found it (%s), now looking for %s\n", pname, cur_dir); /* That was the last name in the path -- we found the file! */ if (cur_dir == NULL) { *a_result = fs_file_tmp->name->meta_addr; // make a copy if one was requested if (a_fs_name) { tsk_fs_name_copy(a_fs_name, fs_file_tmp->name); } if (fs_file_alloc) tsk_fs_file_close(fs_file_alloc); if (fs_file_del) tsk_fs_file_close(fs_file_del); tsk_fs_dir_close(fs_dir); free(cpath); return 0; } // update the attribute field, if needed if (TSK_FS_TYPE_ISNTFS(a_fs->ftype) && ((cur_attr = strchr(cur_dir, ':')) != NULL)) { *(cur_attr) = '\0'; cur_attr++; } // update the value for the next directory to open next_meta = fs_file_tmp->name->meta_addr; if (fs_file_alloc) { tsk_fs_file_close(fs_file_alloc); fs_file_alloc = NULL; } if (fs_file_del) { tsk_fs_file_close(fs_file_del); fs_file_del = NULL; } } // no hit in directory else { is_done = 1; } tsk_fs_dir_close(fs_dir); fs_dir = NULL; } free(cpath); return 1; }
// XXX([email protected]): had better fix the comment // find file of the given inode // // \param fs filesystem info structure defined in sleuthkit // \param lclflags traverse options defined in sleuthkit // \param a_inode the inode of the file // \param type filesystem type number // \param type_used don't know what it is, just give a 0(XXX) // \param id the id of file attribute that the inode refers // \param id_used don't know what it is, just give a 0(XXX) // \param flags traverse options difned in sleuthkit // // Return 0 if error, otherwise a pointer static MBA_FFIND_DATA* fs_ffind(TSK_FS_INFO * fs, TSK_FS_FFIND_FLAG_ENUM lclflags, TSK_INUM_T a_inode, TSK_FS_ATTR_TYPE_ENUM type, uint8_t type_used, uint16_t id, uint8_t id_used, TSK_FS_DIR_WALK_FLAG_ENUM flags) { MBA_FFIND_DATA* data=(MBA_FFIND_DATA*)malloc(sizeof(MBA_FFIND_DATA)); char* orphan =NULL; int size = 0; if(data == NULL) { printf("Cannot allocate memory\n"); return NULL; } data->found = 0; data->flags = lclflags; data->inode = a_inode; utarray_new(data->filenames, &ut_str_icd); /* Since we start the walk on the root inode, then this will not show ** up in the above functions, so do it now */ if (data->inode == fs->root_inum) { if (flags & TSK_FS_DIR_WALK_FLAG_ALLOC) { //tsk_printf("/\n"); data->found = 1; if (!(lclflags & TSK_FS_FFIND_ALL)) return data; } } if (TSK_FS_TYPE_ISNTFS(fs->ftype)) { if (ntfs_find_file(fs, data->inode, type, type_used, id, id_used, flags, find_file_act, data)) return NULL; } else { if (tsk_fs_dir_walk(fs, fs->root_inum, flags, find_file_act, data)) return NULL; } if (data->found == 0) { /* With FAT, we can at least give the name of the file and call * it orphan */ if (TSK_FS_TYPE_ISFAT(fs->ftype)) { TSK_FS_FILE *fs_file = tsk_fs_file_open_meta(fs, NULL, data->inode); if ((fs_file != NULL) && (fs_file->meta != NULL) && (fs_file->meta->name2 != NULL)) { //if (fs_file->meta->flags & TSK_FS_META_FLAG_UNALLOC) // tsk_printf("* "); //tsk_printf("%s/%s\n", TSK_FS_ORPHAN_STR, // fs_file->meta->name2->name); //Added Ophan file into file list size = strlen(TSK_FS_ORPHAN_STR) + strlen(fs_file->meta->name2->name)+2; orphan = (char*)malloc(size); if(orphan == NULL) { printf("Cannot allocate memory\n"); }else { snprintf(orphan, size, "%s/%s", TSK_FS_ORPHAN_STR,fs_file->meta->name2->name); utarray_push_back(data->filenames, orphan ); } } if (fs_file) tsk_fs_file_close(fs_file); } else { tsk_printf("File name not found for inode\n"); } } return data; }
/* This test checks the RECOVER flags */ int test_fat_recover() { TSK_FS_INFO *fs; TSK_IMG_INFO *img; const char *tname = "fe_test_1.img-FAT"; char fname[512]; TSK_FS_FILE *file1; TSK_FS_FILE *file2; char buf[512]; ssize_t retval; snprintf(fname, 512, "%s/fe_test_1.img", s_root); if ((img = tsk_img_open_sing(fname, (TSK_IMG_TYPE_ENUM) 0, 0)) == NULL) { fprintf(stderr, "Error opening %s image\n", tname); tsk_error_print(stderr); tsk_error_reset(); return 1; } if ((fs = tsk_fs_open_img(img, 41126400, (TSK_FS_TYPE_ENUM) 0)) == NULL) { fprintf(stderr, "Error opening %s image\n", tname); tsk_error_print(stderr); tsk_error_reset(); return 1; } // fragmented.html const char *fname2 = "fragmented.html"; file1 = tsk_fs_file_open_meta(fs, NULL, 1162); if (file1 == NULL) { fprintf(stderr, "Error opening %s (%s)\n", fname2, tname); tsk_error_print(stderr); tsk_error_reset(); return 1; } // verify expected size if (file1->meta->size != 5905) { fprintf(stderr, "Error: %s not expected size (%" PRIuOFF ") (%s)\n", fname2, file1->meta->size, tname); return 1; } // verify we can open it via name as well file2 = tsk_fs_file_open(fs, NULL, "/deleted/fragmented.html"); if (file2 == NULL) { fprintf(stderr, "Error opening /deleted/fragmented.html via path name (%s)\n", tname); tsk_error_print(stderr); tsk_error_reset(); return 1; } if (file2->name == NULL) { fprintf(stderr, "Opening /deleted/fragmented.html via path name did not have name set(%s)\n", tname); return 1; } if (strcmp(file2->name->name, fname2) != 0) { fprintf(stderr, "Opening /deleted/fragmented.html via path had incorrect name set (%s) (%s)\n", file2->name->name, tname); return 1; } if ((file2->name->meta_addr != file2->meta->addr) || (file2->meta->addr != file1->meta->addr)) { fprintf(stderr, "Opening /deleted/fragmented.html via path had incorrect meta addresses (%" PRIuINUM " %" PRIuINUM " %" PRIuINUM " (%s)\n", file2->name->meta_addr, file2->meta->addr, file1->meta->addr, tname); return 1; } tsk_fs_file_close(file2); file2 = NULL; // try to read past end of first 2048-byte cluster retval = tsk_fs_file_read(file1, 2048, buf, 512, (TSK_FS_FILE_READ_FLAG_ENUM) 0); if (retval == -1) { fprintf(stderr, "Error reading %s past end w/out Recover flag\n", fname2); tsk_error_print(stderr); tsk_error_reset(); return 1; } // current behavior is to return 0s in "unitialized" space //if (retval != 0) { if (retval != 512) { fprintf(stderr, "Unexpected return value from reading %s past end w/out Recover flag.\n", fname2); fprintf(stderr, "Expected: 0. Got: %zd\n", retval); return 1; } retval = tsk_fs_file_read(file1, 2048, buf, 512, (TSK_FS_FILE_READ_FLAG_ENUM) 0); if (retval == -1) { fprintf(stderr, "Error reading %s past end w/Recover flag\n", fname2); tsk_error_print(stderr); tsk_error_reset(); return 1; } if (retval != 512) { fprintf(stderr, "Unexpected return value from %s past end w/Recover flag.\n", fname2); fprintf(stderr, "Expected: 512. Got: %zd\n", retval); return 1; } // verify the term in the slack space if (memcmp("appear", buf, 6) != 0) { fprintf(stderr, "expected string not found in %s recovery: %c %c %c %c %c %c\n", fname2, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); return 1; } tsk_fs_file_close(file1); tsk_fs_close(fs); tsk_img_close(img); return 0; }
/* This test checks the SLACK flags and verifies * that we read data from the slack space */ int test_ntfs_slack_ads() { TSK_FS_INFO *fs; TSK_IMG_INFO *img; const char *tname = "ntfs-img-kw"; char fname[512]; TSK_FS_FILE *file1; char buf[512]; ssize_t retval; snprintf(fname, 512, "%s/ntfs-img-kw-1.dd", s_root); if ((img = tsk_img_open_sing(fname, (TSK_IMG_TYPE_ENUM) 0, 0)) == NULL) { fprintf(stderr, "Error opening %s image\n", tname); tsk_error_print(stderr); tsk_error_reset(); return 1; } if ((fs = tsk_fs_open_img(img, 0, (TSK_FS_TYPE_ENUM) 0)) == NULL) { fprintf(stderr, "Error opening %s image\n", tname); tsk_error_print(stderr); tsk_error_reset(); return 1; } // file-n-44.dat file1 = tsk_fs_file_open_meta(fs, NULL, 36); if (file1 == NULL) { fprintf(stderr, "Error opening file-n-4.dat (%s)\n", tname); return 1; } // verify expected size if (file1->meta->size != 2000) { fprintf(stderr, "Error: file-n-4.dat not expected size (%" PRIuOFF ") (%s)\n", file1->meta->size, tname); return 1; } // try to read all of last sector with/out Slack set retval = tsk_fs_file_read(file1, 1536, buf, 512, (TSK_FS_FILE_READ_FLAG_ENUM) 0); if (retval == -1) { fprintf(stderr, "Error reading file-n-4.dat to end w/out slack flag (%s)\n", tname); tsk_error_print(stderr); tsk_error_reset(); return 1; } if (retval != 464) { fprintf(stderr, "Unexpected return value from reading file-n-4.dat to end w/out slack flag (%s).\n", tname); fprintf(stderr, "Expected: 464. Got: %zd\n", retval); return 1; } retval = tsk_fs_file_read(file1, 1536, buf, 512, TSK_FS_FILE_READ_FLAG_SLACK); if (retval == -1) { fprintf(stderr, "Error reading file-n-4.dat to end w/slack flag (%s)\n", tname); tsk_error_print(stderr); tsk_error_reset(); return 1; } if (retval != 512) { fprintf(stderr, "Unexpected return value from reading file-n-4.dat w/slack flag. (%s)\n", tname); fprintf(stderr, "Expected: 512. Got: %zd\n", retval); return 1; } // verify the term in the slack space if (memcmp("n-slack", &buf[485], 7) != 0) { fprintf(stderr, "slack string not found in file-n-4.dat slack space: %c %c %c %c %c %c %c (%s)\n", buf[485], buf[486], buf[487], buf[488], buf[489], buf[490], buf[491], tname); return 1; } // try to read past end of file retval = tsk_fs_file_read(file1, 2001, buf, 32, (TSK_FS_FILE_READ_FLAG_ENUM) 0); if (retval != -1) { fprintf(stderr, "Unexpected return value from reading file-n-4.dat after end of file (%s).\n", tname); fprintf(stderr, "Expected: -1. Got: %zd\n", retval); return 1; } tsk_fs_file_close(file1); // file-n-5.dat file1 = tsk_fs_file_open_meta(fs, NULL, 37); if (file1 == NULL) { fprintf(stderr, "Error opening file-n-5.dat (%s)\n", tname); tsk_error_print(stderr); tsk_error_reset(); return 1; } // check the default size to make sure it is the default $Data if (file1->meta->size != 1300) { fprintf(stderr, "file-n-5.dat size is not 1300 (%" PRIuOFF ") (%s)", file1->meta->size, tname); return 1; } // test the getsize API for both attributes const TSK_FS_ATTR *fs_attr = tsk_fs_file_attr_get_type(file1, TSK_FS_ATTR_TYPE_NTFS_DATA, 3, 1); if (!fs_attr) { fprintf(stderr, "Error getting data attribute 3 in file-n-5.dat (%s)", tname); tsk_error_print(stderr); tsk_error_reset(); return 1; } if (fs_attr->size != 1300) { fprintf(stderr, "file-n-5.dat size (via getsize) is not 1300 (%" PRIuOFF ") (%s)", fs_attr->size, tname); return 1; } fs_attr = tsk_fs_file_attr_get_type(file1, TSK_FS_ATTR_TYPE_NTFS_DATA, 5, 1); if (!fs_attr) { fprintf(stderr, "Error getting size of attribute 5 in file-n-5.dat (%s)", tname); tsk_error_print(stderr); tsk_error_reset(); return 1; } if (fs_attr->size != 2000) { fprintf(stderr, "file-n-5.dat:here size (via getsize) is not 2000 (%" PRIuOFF ") (%s)", fs_attr->size, tname); return 1; } tsk_fs_file_close(file1); tsk_fs_close(fs); tsk_img_close(img); return 0; }
/* Test function that compares the dir_open/dir_get() APIs * with the dir_walk results * @param a_addr Address of directory to analyze * @returns 1 if a test failed. */ static int test_walk_apis(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr) { TSK_FS_DIR *fs_dir; int retval = 0; fs_dir = tsk_fs_dir_open_meta(a_fs, a_addr); if (!fs_dir) { fprintf(stderr, "Error opening dir %" PRIuINUM " via meta\n", a_addr); tsk_error_print(stderr); return 1; } // verify they have the same number of entries // walk the directory to get its count size_t walk_size = 0; if (tsk_fs_dir_walk(a_fs, a_addr, (TSK_FS_DIR_WALK_FLAG_ENUM) 0, dir_walk_count_cb, &walk_size)) { fprintf(stderr, "Error doing dent walk on dir %" PRIuINUM "\n", a_addr); retval = 1; goto walk_cleanup; } if (walk_size != tsk_fs_dir_getsize(fs_dir)) { fprintf(stderr, "Size returned by dir_walk different from dir_getsize: %" PRIuINUM ": %" PRIuSIZE " %" PRIuSIZE "\n", a_addr, walk_size, tsk_fs_dir_getsize(fs_dir)); retval = 1; goto walk_cleanup; } // verify each entry is the same for (size_t i = 0; i < tsk_fs_dir_getsize(fs_dir); i++) { TSK_FS_FILE *fs_file; fs_file = tsk_fs_dir_get(fs_dir, i); if (fs_file == NULL) { fprintf(stderr, "Error getting entry %" PRIuSIZE " from directory %" PRIuINUM "\n", i, a_addr); tsk_error_print(stderr); retval = 1; goto walk_cleanup; } if (fs_file->meta == NULL) { fprintf(stderr, "Error: %s (%" PRIuINUM ") does not have meta set in dir: \n", fs_file->name->name, fs_file->name->meta_addr); retval = 1; goto walk_cleanup; } s_found = 0; if (tsk_fs_dir_walk(a_fs, a_addr, (TSK_FS_DIR_WALK_FLAG_ENUM) 0, dir_walk_comp_cb, (void *) fs_file)) { fprintf(stderr, "Error doing dent walk on dir %" PRIuINUM "\n", a_addr); retval = 1; goto walk_cleanup; } if (s_found == 0) { fprintf(stderr, "entry %" PRIuSIZE " in dir not found via walk: %s\n", i, fs_file->name->name); retval = 1; goto walk_cleanup; } tsk_fs_file_close(fs_file); } walk_cleanup: tsk_fs_dir_close(fs_dir); return retval; }