/* * 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; }
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; }
uint8_t ntfs_find_file(TSK_FS_INFO * fs, INUM_T inode_toid, uint32_t type_toid, uint16_t id_toid, int flags, TSK_FS_DENT_TYPE_WALK_CB action, void *ptr) { TSK_FS_INODE_NAME_LIST *fs_name; TSK_FS_DENT *fs_dent; NTFS_INFO *ntfs = (NTFS_INFO *) fs; char *attr = NULL; NTFS_DINFO dinfo; /* 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; } if ((fs_dent = tsk_fs_dent_alloc(NTFS_MAXNAMLEN_UTF8, 0)) == NULL) { return 1; } 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; /* lookup the inode and get its allocation status */ fs_dent->inode = inode_toid; fs_dent->fsi = fs->inode_lookup(fs, inode_toid); if (fs_dent->fsi == NULL) { strncat(tsk_errstr2, " - ntfs_find_file", TSK_ERRSTR_L - strlen(tsk_errstr2)); tsk_fs_dent_free(fs_dent); return 1; } fs_dent->flags = ((tsk_getu16(fs->endian, ntfs->mft-> flags) & NTFS_MFT_INUSE) ? TSK_FS_DENT_FLAG_ALLOC : TSK_FS_DENT_FLAG_UNALLOC); /* Get the name for the attribute - if specified */ if (type_toid != 0) { TSK_FS_DATA *fs_data; if (flags & TSK_FS_FILE_FLAG_NOID) fs_data = tsk_fs_data_lookup_noid(fs_dent->fsi->attr, type_toid); else fs_data = tsk_fs_data_lookup(fs_dent->fsi->attr, type_toid, id_toid); if (!fs_data) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_INT; 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_dent_free(fs_dent); return 1; } /* only add the attribute name if it is the non-default data stream */ if (strcmp(fs_data->name, "$Data") != 0) attr = fs_data->name; } /* loop through all the names it may have */ for (fs_name = fs_dent->fsi->name; fs_name != NULL; fs_name = fs_name->next) { int retval; /* Append on the attribute name, if it exists */ if (attr != NULL) { snprintf(fs_dent->name, fs_dent->name_max, "%s:%s", fs_name->name, attr); } else { strncpy(fs_dent->name, fs_name->name, fs_dent->name_max); } /* if this is in the root directory, then call back */ if (fs_name->par_inode == NTFS_ROOTINO) { fs_dent->path = dinfo.didx[0]; fs_dent->pathdepth = dinfo.depth; retval = action(fs, fs_dent, ptr); if (retval == TSK_WALK_STOP) { tsk_fs_dent_free(fs_dent); return 0; } else if (retval == TSK_WALK_ERROR) { tsk_fs_dent_free(fs_dent); return 1; } } /* call the recursive function on the parent */ else { if (ntfs_find_file_rec(fs, &dinfo, fs_dent, fs_name, flags, action, ptr)) { tsk_fs_dent_free(fs_dent); return 1; } } } /* end of name loop */ tsk_fs_dent_free(fs_dent); return 0; }