📄 fs_dir.c
字号:
a_fs->list_inum_named = NULL; a_dinfo->save_inum_named = 0; } return 0; } else if (retval == TSK_WALK_ERROR) { tsk_fs_dir_close(fs_dir); return 1; } } // 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_fs->list_inum_named, fs_file->meta->addr)) { // if there is an error, then clear the list tsk_list_free(a_fs->list_inum_named); a_fs->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); return 1; } 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; } if (tsk_fs_dir_walk_lcl(a_fs, a_dinfo, fs_file->name->meta_addr, a_flags, a_action, a_ptr)) { /* 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(); } // 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'; } } // 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); tsk_fs_file_close(fs_file); return 0;}/** \ingroup fslib* Walk the file names in a directory and obtain the details of the files via a callback. ** @param a_fs File system to analyze* @param a_addr Metadata address of the directory to analyze* @param a_flags Flags used during analysis* @param a_action Callback function that is called for each file name* @param a_ptr Pointer to data that is passed to the callback function each time* @returns 1 on error and 0 on success*/uint8_ttsk_fs_dir_walk(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr, TSK_FS_DIR_WALK_FLAG_ENUM a_flags, TSK_FS_DIR_WALK_CB a_action, void *a_ptr){ DENT_DINFO dinfo; TSK_RETVAL_ENUM retval; if ((a_fs == NULL) || (a_fs->tag != TSK_FS_INFO_TAG)) { tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "tsk_fs_dir_walk: called with NULL or unallocated structures"); return 1; } memset(&dinfo, 0, sizeof(DENT_DINFO)); if ((dinfo.stack_seen = tsk_stack_create()) == NULL) return 1; /* Sanity check on flags -- make sure at least one ALLOC is set */ if (((a_flags & TSK_FS_DIR_WALK_FLAG_ALLOC) == 0) && ((a_flags & TSK_FS_DIR_WALK_FLAG_UNALLOC) == 0)) { a_flags |= (TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC); } /* if the flags are right, we can collect info that may be needed * for an orphan walk. If the walk fails or stops, the code that * calls the action will clear this stuff. */ if ((a_fs->list_inum_named == NULL) && (a_addr == a_fs->root_inum) && (a_flags & TSK_FS_DIR_WALK_FLAG_RECURSE)) { dinfo.save_inum_named = 1; } retval = tsk_fs_dir_walk_lcl(a_fs, &dinfo, a_addr, a_flags, a_action, a_ptr); /* If there was an error, then we stopped early and we should get * rid of the partial list we were making. */ if ((retval != TSK_OK) && (dinfo.save_inum_named == 1)) { tsk_list_free(a_fs->list_inum_named); a_fs->list_inum_named = NULL; } tsk_stack_free(dinfo.stack_seen); return retval;}/** \internal* Create a dummy NAME entry for the Orphan file virtual directory.* @param a_fs File system directory is for* @param a_fs_name NAME structure to populate with data* @returns 1 on error*/uint8_ttsk_fs_dir_make_orphan_dir_name(TSK_FS_INFO * a_fs, TSK_FS_NAME * a_fs_name){ snprintf(a_fs_name->name, a_fs_name->name_size, "$OrphanFiles"); if (a_fs_name->shrt_name_size > 0) a_fs_name->shrt_name[0] = '\0'; a_fs_name->meta_addr = TSK_FS_ORPHANDIR_INUM(a_fs); a_fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; a_fs_name->type = TSK_FS_NAME_TYPE_DIR; return 0;}/** \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_ttsk_fs_dir_make_orphan_dir_meta(TSK_FS_INFO * a_fs, TSK_FS_META * a_fs_meta){ TSK_DADDR_T *addr_ptr; 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; 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->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) { addr_ptr = (TSK_DADDR_T *) a_fs_meta->content_ptr; addr_ptr[0] = 0; } a_fs_meta->size = 0; return 0;}static TSK_WALK_RET_ENUMload_named_dir_walk_cb(TSK_FS_FILE * a_fs_file, const char *a_path, void *a_ptr){ return TSK_WALK_CONT;}TSK_RETVAL_ENUMtsk_fs_dir_load_inum_named(TSK_FS_INFO * a_fs){ if (a_fs->list_inum_named != NULL) return TSK_OK; /* Do a dir_walk. There is internal caching code that will populate * the structure. The callback is really a dummy call. This could * be made more effecient in the future (not do callbacks...). We * specify UNALLOC only as a flag on the assumption that there will * be fewer callbacks for UNALLOC than ALLOC. */ if (tsk_fs_dir_walk(a_fs, a_fs->root_inum, TSK_FS_NAME_FLAG_UNALLOC | TSK_FS_DIR_WALK_FLAG_RECURSE | TSK_FS_DIR_WALK_FLAG_NOORPHAN, load_named_dir_walk_cb, NULL)) { strncat(tsk_errstr2, " - tsk_fs_dir_load_inum_named: identifying inodes allocated by file names", TSK_ERRSTR_L); return TSK_ERR; } return TSK_OK;}typedef struct { TSK_FS_NAME *fs_name; TSK_FS_DIR *fs_dir; TSK_LIST *orphan_subdir_list; // keep track of files that can already be accessed via orphan directory} FIND_ORPHAN_DATA;static TSK_WALK_RET_ENUMload_orphan_dir_walk_cb(TSK_FS_FILE * a_fs_file, const char *a_path, void *a_ptr){ FIND_ORPHAN_DATA *data = (FIND_ORPHAN_DATA *) a_ptr; // add this entry to the orphan list if (a_fs_file->meta) tsk_list_add(&data->orphan_subdir_list, a_fs_file->meta->addr); return TSK_WALK_CONT;}static TSK_WALK_RET_ENUMfind_orphan_meta_walk_cb(TSK_FS_FILE * a_fs_file, void *a_ptr){ FIND_ORPHAN_DATA *data = (FIND_ORPHAN_DATA *) a_ptr; TSK_FS_INFO *fs = a_fs_file->fs_info; /* We want only orphans, then check if this * inode is in the seen list */ if (tsk_list_find(fs->list_inum_named, a_fs_file->meta->addr)) { return TSK_WALK_CONT; } // check if we have already added it as an orphan (in a subdirectory) if (tsk_list_find(data->orphan_subdir_list, a_fs_file->meta->addr)) { return TSK_WALK_CONT; } // use their name if they have one if (a_fs_file->meta->name2) { strncpy(data->fs_name->name, a_fs_file->meta->name2->name, data->fs_name->name_size); } else { snprintf(data->fs_name->name, data->fs_name->name_size, "OrphanFile-%" PRIuINUM, a_fs_file->meta->addr); } data->fs_name->meta_addr = a_fs_file->meta->addr; data->fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; if (a_fs_file->meta->type == TSK_FS_META_TYPE_DIR) data->fs_name->type = TSK_FS_NAME_TYPE_DIR; else data->fs_name->type = TSK_FS_NAME_TYPE_REG; if (tsk_fs_dir_add(data->fs_dir, data->fs_name)) return TSK_WALK_ERROR; /* Go into directories to mark their contents as "seen" */ if (a_fs_file->meta->type == TSK_FS_META_TYPE_DIR) { if (tsk_fs_dir_walk(fs, a_fs_file->meta->addr, TSK_FS_DIR_WALK_FLAG_UNALLOC | TSK_FS_DIR_WALK_FLAG_RECURSE | TSK_FS_DIR_WALK_FLAG_NOORPHAN, load_orphan_dir_walk_cb, data)) { strncat(tsk_errstr2, " - tsk_fs_dir_load_inum_named: identifying inodes allocated by file names", TSK_ERRSTR_L); return TSK_ERR; } } return TSK_WALK_CONT;}TSK_RETVAL_ENUMtsk_fs_dir_find_orphans(TSK_FS_INFO * a_fs, TSK_FS_DIR * a_fs_dir){ FIND_ORPHAN_DATA data; size_t i; if (a_fs->isOrphanHunting) { return TSK_OK; } a_fs->isOrphanHunting = 1; memset(&data, 0, sizeof(FIND_ORPHAN_DATA)); /* We first need to determine which of the unallocated meta structures * have a name pointing to them. We cache this data, so see if it is * already known. */ if (a_fs->list_inum_named == NULL) { a_fs->isOrphanHunting = 0; if (tsk_fs_dir_load_inum_named(a_fs) != TSK_OK) { return TSK_ERR; } if (a_fs->list_inum_named == NULL) { tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "tsk_fs_dir_find_orphans: list_inum_named still NULL after dir_walk"); return TSK_ERR; } } /* Now we walk the unallocated metadata structures and find ones that are * not named. The callback will add the names to the FS_DIR structure. */ data.fs_dir = a_fs_dir; // allocate a name once so that we will reuse for each name we add to FS_DIR if ((data.fs_name = tsk_fs_name_alloc(256, 0)) == NULL) { a_fs->isOrphanHunting = 0; return TSK_ERR; } if (tsk_fs_meta_walk(a_fs, a_fs->first_inum, a_fs->last_inum, TSK_FS_META_FLAG_UNALLOC | TSK_FS_META_FLAG_USED, find_orphan_meta_walk_cb, &data)) { a_fs->isOrphanHunting = 0; tsk_fs_name_free(data.fs_name); return TSK_ERR; } tsk_fs_name_free(data.fs_name); /* do some cleanup on the final list. This cleanup will compare the * entries in the root orphan directory with files that can be accessed * from subdirectories of the orphan directory. These entries will exist if * they were added before their parent directory was added to the orphan directory. */ for (i = 0; i < a_fs_dir->names_used; i++) { if (tsk_list_find(data.orphan_subdir_list, a_fs_dir->names[i].meta_addr)) { if (a_fs_dir->names_used > 1) { tsk_fs_name_copy(&a_fs_dir->names[i], &a_fs_dir->names[a_fs_dir->names_used - 1]); } a_fs_dir->names_used--; } } // populate the fake FS_FILE structure for the "Orphan Directory" /* Get the inode and verify it has attributes */ if ((a_fs_dir->fs_file = tsk_fs_file_alloc(a_fs)) == NULL) { a_fs->isOrphanHunting = 0; return TSK_ERR; } if ((a_fs_dir->fs_file->meta = tsk_fs_meta_alloc(sizeof(TSK_DADDR_T))) == NULL) { a_fs->isOrphanHunting = 0; return TSK_ERR; } if (tsk_fs_dir_make_orphan_dir_meta(a_fs, a_fs_dir->fs_file->meta)) { a_fs->isOrphanHunting = 0; return TSK_ERR; } if (data.orphan_subdir_list) tsk_list_free(data.orphan_subdir_list); a_fs->isOrphanHunting = 0; return TSK_OK;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -