/* * Class: edu_uw_apl_commons_tsk4j_filesys_File * Method: attribute * Signature: (JI)J */ JNIEXPORT jlong JNICALL Java_edu_uw_apl_commons_tsk4j_filesys_File_attribute (JNIEnv *env, jobject thiz, jlong nativePtr, jint indx ) { TSK_FS_FILE* info = (TSK_FS_FILE*)nativePtr; const TSK_FS_ATTR* attr = tsk_fs_file_attr_get_idx( info, indx ); return (jlong)attr; }
static TSK_WALK_RET_ENUM count_slack_inode_act(TSK_FS_FILE * fs_file, void *ptr) { BLKCALC_DATA *data = (BLKCALC_DATA *) ptr; if (tsk_verbose) tsk_fprintf(stderr, "count_slack_inode_act: Processing meta data: %" PRIuINUM "\n", fs_file->meta->addr); /* We will now do a file walk on the content */ if (TSK_FS_TYPE_ISNTFS(fs_file->fs_info->ftype) == 0) { data->flen = fs_file->meta->size; if (tsk_fs_file_walk(fs_file, TSK_FS_FILE_WALK_FLAG_SLACK, count_slack_file_act, ptr)) { /* ignore any errors */ if (tsk_verbose) tsk_fprintf(stderr, "Error walking file %" PRIuINUM, fs_file->meta->addr); tsk_error_reset(); } } /* For NTFS we go through each non-resident attribute */ else { int i, cnt; 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->flags & TSK_FS_ATTR_NONRES) { data->flen = fs_attr->size; if (tsk_fs_file_walk_type(fs_file, fs_attr->type, fs_attr->id, TSK_FS_FILE_WALK_FLAG_SLACK, count_slack_file_act, ptr)) { /* ignore any errors */ if (tsk_verbose) tsk_fprintf(stderr, "Error walking file %" PRIuINUM, fs_file->meta->addr); tsk_error_reset(); } } } } return TSK_WALK_CONT; }
/** * Method that can be used from within processFile() to look at each * attribute that a file may have. This will call the processAttribute() * method (which you must implement) on each of the attributes in the file. * @param fs_file file details * @param path full path of parent directory * @returns STOP if the file system processing should stop and not process more files or OK. */ TSK_RETVAL_ENUM TskAuto::processAttributes(TSK_FS_FILE * fs_file, const char *path) { int count = tsk_fs_file_attr_getsize(fs_file), i; for (i = 0; i < count; i++) { TSK_RETVAL_ENUM retval = processAttribute(fs_file, tsk_fs_file_attr_get_idx(fs_file, i), path); if ((retval == TSK_STOP) || (m_stopAllProcessing)) return TSK_STOP; } return TSK_OK; }
/* ** find_inode ** ** Callback action for inode_walk */ static TSK_WALK_RET_ENUM ifind_data_act(TSK_FS_FILE * fs_file, void *ptr) { IFIND_DATA_DATA *data = (IFIND_DATA_DATA *) ptr; int file_flags = (TSK_FS_FILE_WALK_FLAG_AONLY | TSK_FS_FILE_WALK_FLAG_SLACK); int i, cnt; data->curinode = fs_file->meta->addr; /* Search all 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; data->curtype = fs_attr->type; data->curid = fs_attr->id; if (fs_attr->flags & TSK_FS_ATTR_NONRES) { if (tsk_fs_attr_walk(fs_attr, file_flags, ifind_data_file_act, ptr)) { if (tsk_verbose) tsk_fprintf(stderr, "Error walking file %" PRIuINUM " Attribute: %i", fs_file->meta->addr, i); /* Ignore these errors */ tsk_error_reset(); } // stop if we only want one hit if ((data->found) && (!(data->flags & TSK_FS_IFIND_ALL))) break; } } if ((data->found) && (!(data->flags & TSK_FS_IFIND_ALL))) return TSK_WALK_STOP; else return TSK_WALK_CONT; }
/** \ingroup fslib * Return a specific attribute by its ID for the file. * @param a_fs_file File to get data from * @param a_id Id of attribute to load * @returns NULL on error */ const TSK_FS_ATTR * tsk_fs_file_attr_get_id(TSK_FS_FILE * a_fs_file, uint16_t a_id) { int i, size; if (tsk_fs_file_attr_check(a_fs_file, "tsk_fs_file_attr_get_type")) return NULL; size = tsk_fs_file_attr_getsize(a_fs_file); for (i = 0; i < size; i++) { const TSK_FS_ATTR *fs_attr = tsk_fs_file_attr_get_idx(a_fs_file, i); if (fs_attr == NULL) return NULL; if (fs_attr->id == a_id) return fs_attr; } tsk_error_set_errno(TSK_ERR_FS_ATTR_NOTFOUND); tsk_error_set_errstr ("tsk_fs_attr_get_id: Attribute ID %d not found", a_id); return NULL; }
// file contains attributes, one attribute is the content. static void log_file_offsets_in_filesystem(find_file_data *data, TSK_FS_FILE *file){ int i; int cnt = tsk_fs_file_attr_getsize(file); TSK_FS_FILE_WALK_FLAG_ENUM file_walk_flags = (TSK_FS_FILE_WALK_FLAG_ENUM)( TSK_FS_FILE_WALK_FLAG_AONLY // Provide callback with only addr | TSK_FS_FILE_WALK_FLAG_SLACK // Include file's slack space ); for (i = 0; i < cnt; i++) { const TSK_FS_ATTR *attr = tsk_fs_file_attr_get_idx(file, i); if (attr && is_attr_on_disk(attr)) { tsk_fs_attr_walk( attr, // file attribute to log offsets file_walk_flags, // walk options log_attr_offsets_in_filesystem, // action for each attr data // argument for action ); } } }
/* * call back action function for dent_walk */ static TSK_WALK_RET_ENUM print_dent_act(TSK_FS_FILE * fs_file, const char *a_path, void *ptr) { FLS_DATA *fls_data = (FLS_DATA *) ptr; /* only print dirs if TSK_FS_FLS_DIR is set and only print everything ** else if TSK_FS_FLS_FILE is set (or we aren't sure what it is) */ if (((fls_data->flags & TSK_FS_FLS_DIR) && ((fs_file->meta) && (fs_file->meta->type == TSK_FS_META_TYPE_DIR))) || ((fls_data->flags & TSK_FS_FLS_FILE) && (((fs_file->meta) && (fs_file->meta->type != TSK_FS_META_TYPE_DIR)) || (!fs_file->meta)))) { /* Make a special case for NTFS so we can identify all of the * alternate data streams! */ if ((TSK_FS_TYPE_ISNTFS(fs_file->fs_info->ftype)) && (fs_file->meta)) { uint8_t printed = 0; int i, cnt; // 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->type == TSK_FS_ATTR_TYPE_NTFS_DATA) { printed = 1; if (fs_file->meta->type == TSK_FS_META_TYPE_DIR) { /* we don't want to print the ..:blah stream if * the -a flag was not given */ if ((fs_file->name->name[0] == '.') && (fs_file->name->name[1]) && (fs_file->name->name[2] == '\0') && ((fls_data->flags & TSK_FS_FLS_DOT) == 0)) { continue; } } printit(fs_file, a_path, fs_attr, fls_data); } else if (fs_attr->type == TSK_FS_ATTR_TYPE_NTFS_IDXROOT) { printed = 1; /* If it is . or .. only print it if the flags say so, * we continue with other streams though in case the * directory has a data stream */ if (!((TSK_FS_ISDOT(fs_file->name->name)) && ((fls_data->flags & TSK_FS_FLS_DOT) == 0))) printit(fs_file, a_path, fs_attr, fls_data); } /* Print the FILE_NAME times if this is the same attribute * that we collected the times from. */ else if ((fs_attr->type == TSK_FS_ATTR_TYPE_NTFS_FNAME) && (fs_attr->id == fs_file->meta->time2.ntfs.fn_id) && (fls_data->flags & TSK_FS_FLS_MAC)) { /* If it is . or .. only print it if the flags say so, * we continue with other streams though in case the * directory has a data stream */ if (!((TSK_FS_ISDOT(fs_file->name->name)) && ((fls_data->flags & TSK_FS_FLS_DOT) == 0))) printit(fs_file, a_path, fs_attr, fls_data); } } /* A user reported that an allocated file had the standard * attributes, but no $Data. We should print something */ if (printed == 0) { printit(fs_file, a_path, NULL, fls_data); } } else { /* skip it if it is . or .. and we don't want them */ if (!((TSK_FS_ISDOT(fs_file->name->name)) && ((fls_data->flags & TSK_FS_FLS_DOT) == 0))) printit(fs_file, a_path, NULL, fls_data); } } return TSK_WALK_CONT; }
/* inode walk call back for tsk_fs_ifind_par to find unallocated files * based on parent directory */ static TSK_WALK_RET_ENUM ifind_par_act(TSK_FS_FILE * fs_file, void *ptr) { IFIND_PAR_DATA *data = (IFIND_PAR_DATA *) ptr; TSK_FS_META_NAME_LIST *fs_name_list; /* go through each file name attribute for this file */ fs_name_list = fs_file->meta->name2; while (fs_name_list) { /* we found a file that has the target parent directory. * Make a FS_NAME structure and print it. */ if (fs_name_list->par_inode == data->parinode) { int i, cnt; uint8_t printed; TSK_FS_NAME *fs_name; if ((fs_name = tsk_fs_name_alloc(256, 0)) == NULL) return TSK_WALK_ERROR; /* Fill in the basics of the fs_name entry * so we can print in the fls formats */ fs_name->meta_addr = fs_file->meta->addr; fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; strncpy(fs_name->name, fs_name_list->name, fs_name->name_size); // now look for the $Data and $IDXROOT attributes fs_file->name = fs_name; printed = 0; // 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->type == TSK_FS_ATTR_TYPE_NTFS_DATA) || (fs_attr->type == TSK_FS_ATTR_TYPE_NTFS_IDXROOT)) { if (data->flags & TSK_FS_IFIND_PAR_LONG) { tsk_fs_name_print_long(stdout, fs_file, NULL, fs_file->fs_info, fs_attr, 0, 0); tsk_printf("\n"); } else { tsk_fs_name_print(stdout, fs_file, NULL, fs_file->fs_info, fs_attr, 0); tsk_printf("\n"); } printed = 1; } } // if there were no attributes, print what we got if (printed == 0) { if (data->flags & TSK_FS_IFIND_PAR_LONG) { tsk_fs_name_print_long(stdout, fs_file, NULL, fs_file->fs_info, NULL, 0, 0); tsk_printf("\n"); } else { tsk_fs_name_print(stdout, fs_file, NULL, fs_file->fs_info, NULL, 0); tsk_printf("\n"); } } tsk_fs_name_free(fs_name); data->found = 1; } fs_name_list = fs_name_list->next; } return TSK_WALK_CONT; }
/** * \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; }
/* 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; }