/* Returns 0 on success and 1 on error */ uint8_t tsk_fs_fls(TSK_FS_INFO * fs, TSK_FS_FLS_FLAG_ENUM lclflags, TSK_INUM_T inode, TSK_FS_DIR_WALK_FLAG_ENUM flags, TSK_TCHAR * tpre, int32_t skew) { FLS_DATA data; data.flags = lclflags; data.sec_skew = skew; #ifdef TSK_WIN32 { size_t clen; UTF8 *ptr8; UTF16 *ptr16; int retval; if ((tpre != NULL) && (TSTRLEN(tpre) > 0)) { clen = TSTRLEN(tpre) * 4; data.macpre = (char *) tsk_malloc(clen); if (data.macpre == NULL) { return 1; } ptr8 = (UTF8 *) data.macpre; ptr16 = (UTF16 *) tpre; retval = tsk_UTF16toUTF8_lclorder((const UTF16 **) &ptr16, (UTF16 *) & ptr16[TSTRLEN(tpre) + 1], &ptr8, (UTF8 *) ((uintptr_t) ptr8 + clen), TSKlenientConversion); if (retval != TSKconversionOK) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_UNICODE); tsk_error_set_errstr ("Error converting fls mactime pre-text to UTF-8 %d\n", retval); return 1; } } else { data.macpre = (char *) tsk_malloc(1); if (data.macpre == NULL) { return 1; } data.macpre[0] = '\0'; } retval = tsk_fs_dir_walk(fs, inode, flags, print_dent_act, &data); free(data.macpre); data.macpre = NULL; return retval; } #else data.macpre = tpre; return tsk_fs_dir_walk(fs, inode, flags, print_dent_act, &data); #endif }
int do_internal_find_inode (const mountable_t *mountable, int64_t inode) { int ret = -1; TSK_FS_INFO *fs = NULL; TSK_IMG_INFO *img = NULL; /* Used internally by tsk_fs_dir_walk */ const int flags = TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC | TSK_FS_DIR_WALK_FLAG_RECURSE | TSK_FS_DIR_WALK_FLAG_NOORPHAN; ret = open_filesystem (mountable->device, &img, &fs); if (ret < 0) return ret; reply (NULL, NULL); /* Reply message. */ ret = tsk_fs_dir_walk (fs, fs->root_inum, flags, findino_callback, (void *) &inode); if (ret == 0) ret = send_file_end (0); /* File transfer end. */ else send_file_end (1); /* Cancel file transfer. */ fs->close (fs); img->close (img); return ret; }
/** \internal * Internal method that the other findFilesInFs can call after they * have opened FS_INFO. * @returns OK, STOP, or ERR (error message will already have been registered) */ TSK_RETVAL_ENUM TskAuto::findFilesInFsInt(TSK_FS_INFO * a_fs_info, TSK_INUM_T a_inum) { // see if the super class wants us to proceed TSK_FILTER_ENUM retval = filterFs(a_fs_info); if ((retval == TSK_FILTER_STOP) || (m_stopAllProcessing)) return TSK_STOP; else if (retval == TSK_FILTER_SKIP) return TSK_OK; /* Walk the files, starting at the given inum */ if (tsk_fs_dir_walk(a_fs_info, a_inum, (TSK_FS_DIR_WALK_FLAG_ENUM) (TSK_FS_DIR_WALK_FLAG_RECURSE | m_fileFilterFlags), dirWalkCb, this)) { tsk_error_set_errstr2( "Error walking directory in file system at offset %" PRIuOFF, a_fs_info->offset); registerError(); return TSK_ERR; } if (m_stopAllProcessing) return TSK_STOP; /* We could do some analysis of unallocated blocks at this point... */ return TSK_OK; }
/** * Analyze the volume starting at byte offset 'start' * and walk each file that can be found. * * @param img Disk image to be analyzed. * @param start Byte offset of volume starting location. * * @return 1 on error and 0 on success */ static uint8_t proc_fs(TSK_IMG_INFO * img_info, TSK_OFF_T start) { TSK_FS_INFO *fs_info; /* Try it as a file system */ if ((fs_info = tsk_fs_open_img(img_info, start, TSK_FS_TYPE_DETECT)) == NULL) { tsk_error_print(stderr); /* We could do some carving on the volume data at this point */ return 1; } /* Walk the files, starting at the root directory */ if (tsk_fs_dir_walk(fs_info, fs_info->root_inum, (TSK_FS_DIR_WALK_FLAG_ENUM) (TSK_FS_DIR_WALK_FLAG_RECURSE), dir_act, NULL)) { tsk_error_print(stderr); tsk_fs_close(fs_info); return 1; } /* We could do some analysis of unallocated blocks at this point... */ tsk_fs_close(fs_info); return 0; }
/* Internal method that the other findFilesInFs can call after they * have opened FS_INFO. */ TSK_RETVAL_ENUM TskAuto::findFilesInFsInt(TSK_FS_INFO * a_fs_info, TSK_INUM_T a_inum) { TSK_FILTER_ENUM retval = filterFs(a_fs_info); if (retval == TSK_FILTER_STOP) return TSK_STOP; else if (retval == TSK_FILTER_SKIP) return TSK_OK; /* Walk the files, starting at the given inum */ if (tsk_fs_dir_walk(a_fs_info, a_inum, (TSK_FS_DIR_WALK_FLAG_ENUM) (TSK_FS_DIR_WALK_FLAG_RECURSE | m_fileFilterFlags), dirWalkCb, this)) { char msg[1024]; snprintf(msg, 1024, "Error walking directory in file system at offset %" PRIuOFF " (%s)", a_fs_info->offset, tsk_error_get()); if (tsk_verbose) fprintf(stderr, "%s\n", msg); handleNotification(msg); return TSK_ERR; } /* We could do some analysis of unallocated blocks at this point... */ return TSK_OK; }
/** \internal * Proces a file system and populate a list of the metadata structures * that are reachable by file names. This is used to find orphan files. * Each file system has code that does the populating. */ TSK_RETVAL_ENUM tsk_fs_dir_load_inum_named(TSK_FS_INFO * a_fs) { tsk_take_lock(&a_fs->list_inum_named_lock); if (a_fs->list_inum_named != NULL) { tsk_release_lock(&a_fs->list_inum_named_lock); if (tsk_verbose) fprintf(stderr, "tsk_fs_dir_load_inum_named: List already populated. Skipping walk.\n"); return TSK_OK; } tsk_release_lock(&a_fs->list_inum_named_lock); if (tsk_verbose) fprintf(stderr, "tsk_fs_dir_load_inum_named: Performing dir walk to find named files\n"); /* 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)) { tsk_error_errstr2_concat ("- tsk_fs_dir_load_inum_named: identifying inodes allocated by file names"); return TSK_ERR; } return TSK_OK; }
/* * Class: edu_uw_apl_commons_tsk4j_filesys_FileSystem * Method: dirWalk * Signature: (JJILedu/uw/apl/commons/tsk4j/filesys/DirectoryWalk/Callback;)I */ JNIEXPORT jint JNICALL Java_edu_uw_apl_commons_tsk4j_filesys_FileSystem_dirWalk (JNIEnv * env, jobject thiz, jlong nativePtr, jlong metadataAddr, jint flags, jobject callback ) { // We need three handles in the callback, so package them here. Gruesome! void* vs[3] = { env, thiz, callback }; TSK_FS_INFO* fsInfo = (TSK_FS_INFO*)nativePtr; uint8_t ret = tsk_fs_dir_walk( fsInfo, metadataAddr, flags, dirWalkCallback, (void*)vs ); /* fprintf( stderr, "%s: tsk_fs_dir_walk result %d\n", __FUNCTION__, ret ); */ if( ret ) { fprintf( stderr, "Error in callback %d\n", ret ); jthrowable t = (*env)->ExceptionOccurred( env ); if( t ) { (*env)->Throw( env, t ); } else { fprintf( stderr, "dirWalk ended ERROR but no Java Exception??\n" ); } } return (jint)ret; }
static void proc_fs(TSK_FS_INFO* fs, FILE* log) { // Walk starting at $OrphanFiles to provoke recursive call to tsk_fs_dir_load_inum_named. if (tsk_fs_dir_walk(fs, TSK_FS_ORPHANDIR_INUM(fs), TSK_FS_DIR_WALK_FLAG_RECURSE, proc_dir, log)) { fprintf(stderr, "dir walk from $OrphanFiles failed\n"); tsk_error_print(stderr); } // Walk starting at the root. Note that we walk the root tree // -after- the $OrphanFile because if we use the other order, // things are already cached. if (tsk_fs_dir_walk(fs, fs->root_inum, TSK_FS_DIR_WALK_FLAG_RECURSE, proc_dir, log)) { fprintf(stderr, "dir walk from root failed\n"); tsk_error_print(stderr); } }
void ie_file(TSK_FS_INFO *fs) { TSK_INUM_T inode; void * ptr= NULL; tsk_fs_path2inum(fs, "/Users", &inode, NULL); tsk_fs_dir_walk(fs, inode, TSK_FS_DIR_WALK_FLAG_NONE, callback2, ptr); }
void ntuser_hive(TSK_FS_INFO *fs) { TSK_INUM_T inode; void * ptr= NULL; // TSK_FS_DIR * dir = tsk_fs_dir_open (fs, "/user"); tsk_fs_path2inum(fs, "/Users", &inode, NULL); printf("%d\n", (int)inode); tsk_fs_dir_walk(fs, inode, TSK_FS_DIR_WALK_FLAG_NONE, callback, ptr); }
/** * /internal * Parse a buffer containing the contents of a directory and add TSK_FS_NAME * objects for each named file found to the TSK_FS_DIR representation of the * directory. * * @param fatfs File system information structure for file system that * contains the directory. * @param a_fs_dir Directory structure into to which parsed file metadata will * be added. * @param buf Buffer that contains the directory contents. * @param len Length of buffer in bytes (must be a multiple of sector * size). * @param addrs Array where each element is the original address of * the corresponding sector in a_buf (size of array is number of sectors in * the directory). * @return TSK_RETVAL_ENUM */ TSK_RETVAL_ENUM fatxxfs_dent_parse_buf(FATFS_INFO *fatfs, TSK_FS_DIR *a_fs_dir, char *buf, TSK_OFF_T len, TSK_DADDR_T *addrs) { char *func_name = "fatxxfs_dent_parse_buf"; unsigned int idx = 0; unsigned int sidx = 0; int a = 0; int b = 0; TSK_INUM_T ibase = 0; FATXXFS_DENTRY *dep = NULL; TSK_FS_INFO *fs = (TSK_FS_INFO*)&fatfs->fs_info; int sectalloc = 0; TSK_FS_NAME *fs_name = NULL; FATXXFS_LFN lfninfo; int entrySeenCount = 0; int entryInvalidCount = 0; uint8_t isCorruptDir = 0; tsk_error_reset(); if (fatfs_ptr_arg_is_null(fatfs, "fatfs", func_name) || fatfs_ptr_arg_is_null(a_fs_dir, "a_fs_dir", func_name) || fatfs_ptr_arg_is_null(buf, "buf", func_name) || fatfs_ptr_arg_is_null(addrs, "addrs", func_name)) { return TSK_ERR; } assert(len > 0); if (len < 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr("%s: invalid buffer length", func_name); return TSK_ERR; } dep = (FATXXFS_DENTRY*)buf; if ((fs_name = tsk_fs_name_alloc(FATFS_MAXNAMLEN_UTF8, 32)) == NULL) { return TSK_ERR; } memset(&lfninfo, 0, sizeof(FATXXFS_LFN)); lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; /* Loop through the sectors in the buffer. */ for (sidx = 0; sidx < (unsigned int) (len / fatfs->ssize); sidx++) { /* Get the base inode for the current sector */ ibase = FATFS_SECT_2_INODE(fatfs, addrs[sidx]); if (ibase > fs->last_inum) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr ("fatfs_parse: inode address is too large"); tsk_fs_name_free(fs_name); return TSK_COR; } if (tsk_verbose) tsk_fprintf(stderr, "fatfs_dent_parse_buf: Parsing sector %" PRIuDADDR " for dir %" PRIuINUM "\n", addrs[sidx], a_fs_dir->addr); /* Get the allocation status of the current sector. */ if ((sectalloc = fatfs_is_sectalloc(fatfs, addrs[sidx])) == -1) { if (tsk_verbose) { tsk_fprintf(stderr, "fatfs_dent_parse_buf: Error looking up sector allocation: %" PRIuDADDR "\n", addrs[sidx]); tsk_error_print(stderr); } tsk_error_reset(); continue; } /* Loop through the putative directory entries in the current sector. */ for (idx = 0; idx < fatfs->dentry_cnt_se; idx++, dep++) { FATXXFS_DENTRY *dir; TSK_INUM_T inode; entrySeenCount++; /* Is the current entry a valid entry? */ if (0 == fatxxfs_is_dentry(fatfs, (FATFS_DENTRY*)dep, (FATFS_DATA_UNIT_ALLOC_STATUS_ENUM)sectalloc, ((isCorruptDir == 0) && (sectalloc)) ? 1 : 0)) { if (tsk_verbose) tsk_fprintf(stderr, "fatfs_dent_parse_buf: Entry %u is invalid\n", idx); entryInvalidCount++; /* If we have seen four entries and all of them are corrupt, * then test every remaining entry in this folder -- * even if the sector is allocated. The scenario is one * where we are processing a cluster that is allocated * to a file and we happen to get some data that matches * every now and then. */ if ((entrySeenCount == 4) && (entryInvalidCount == 4)) { isCorruptDir = 1; } continue; } dir = dep; /* Compute the inode address corresponding to this directory entry. */ inode = ibase + idx; if ((dir->attrib & FATFS_ATTR_LFN) == FATFS_ATTR_LFN) { /* The current entry is a long file name entry. */ FATXXFS_DENTRY_LFN *dirl = (FATXXFS_DENTRY_LFN *) dir; /* Store the name in dinfo until we get the 8.3 name * Use the checksum to identify a new sequence. */ if (((dirl->seq & FATXXFS_LFN_SEQ_FIRST) && (dirl->seq != FATXXFS_SLOT_DELETED)) || (dirl->chksum != lfninfo.chk)) { // @@@ Do a partial output here /* This is the last long file name entry in a sequence. * Reset the sequence number, check sum, and next char * address. */ lfninfo.seq = dirl->seq & FATXXFS_LFN_SEQ_MASK; lfninfo.chk = dirl->chksum; lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; } else if (dirl->seq != lfninfo.seq - 1) { // @@@ Check the sequence number - the checksum is correct though... } /* Copy the UTF16 values starting at end of buffer */ for (a = 3; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part3[a]; } for (a = 11; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part2[a]; } for (a = 9; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part1[a]; } // Skip ahead until we get a new sequence num or the 8.3 name continue; } else if ((dir->attrib & FATFS_ATTR_VOLUME) == FATFS_ATTR_VOLUME) { /* Special case for volume label: name does not have an * extension and we add a note at the end that it is a label */ a = 0; for (b = 0; b < 8; b++) { if ((dir->name[b] >= 0x20) && (dir->name[b] != 0xff)) { fs_name->name[a++] = dir->name[b]; } else { fs_name->name[a++] = '^'; } } for (b = 0; b < 3; b++) { if ((dir->ext[b] >= 0x20) && (dir->ext[b] != 0xff)) { fs_name->name[a++] = dir->ext[b]; } else { fs_name->name[a++] = '^'; } } fs_name->name[a] = '\0'; /* Append a string to show it is a label */ if (a + 22 < FATFS_MAXNAMLEN_UTF8) { const char *volstr = " (Volume Label Entry)"; strncat(fs_name->name, volstr, FATFS_MAXNAMLEN_UTF8 - a); } } else { /* A short (8.3) entry */ char *name_ptr; // The dest location for the short name /* if we have a lfn, copy it into fs_name->name * and put the short name in fs_name->shrt_name */ if (lfninfo.start != FATFS_MAXNAMLEN_UTF8 - 1) { int retVal; /* @@@ Check the checksum */ /* Convert the UTF16 to UTF8 */ UTF16 *name16 = (UTF16 *) ((uintptr_t) & lfninfo. name[lfninfo.start + 1]); UTF8 *name8 = (UTF8 *) fs_name->name; retVal = tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16, (UTF16 *) & lfninfo.name[FATFS_MAXNAMLEN_UTF8], &name8, (UTF8 *) ((uintptr_t) name8 + FATFS_MAXNAMLEN_UTF8), TSKlenientConversion); if (retVal != TSKconversionOK) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_UNICODE); tsk_error_set_errstr ("fatfs_parse: Error converting FAT LFN to UTF8: %d", retVal); continue; } /* Make sure it is NULL Terminated */ if ((uintptr_t) name8 > (uintptr_t) fs_name->name + FATFS_MAXNAMLEN_UTF8) fs_name->name[FATFS_MAXNAMLEN_UTF8 - 1] = '\0'; else *name8 = '\0'; lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; name_ptr = fs_name->shrt_name; // put 8.3 into shrt_name } /* We don't have a LFN, so put the short name in * fs_name->name */ else { fs_name->shrt_name[0] = '\0'; name_ptr = fs_name->name; // put 8.3 into normal location } /* copy in the short name into the place specified above. * Skip spaces and put in the . */ a = 0; for (b = 0; b < 8; b++) { if ((dir->name[b] != 0) && (dir->name[b] != 0xff) && (dir->name[b] != 0x20)) { if ((b == 0) && (dir->name[0] == FATXXFS_SLOT_DELETED)) { name_ptr[a++] = '_'; } else if ((dir->lowercase & FATXXFS_CASE_LOWER_BASE) && (dir->name[b] >= 'A') && (dir->name[b] <= 'Z')) { name_ptr[a++] = dir->name[b] + 32; } else { name_ptr[a++] = dir->name[b]; } } } for (b = 0; b < 3; b++) { if ((dir->ext[b] != 0) && (dir->ext[b] != 0xff) && (dir->ext[b] != 0x20)) { if (b == 0) name_ptr[a++] = '.'; if ((dir->lowercase & FATXXFS_CASE_LOWER_EXT) && (dir->ext[b] >= 'A') && (dir->ext[b] <= 'Z')) name_ptr[a++] = dir->ext[b] + 32; else name_ptr[a++] = dir->ext[b]; } } name_ptr[a] = '\0'; // make sure that only ASCII is in the short name fatfs_cleanup_ascii(name_ptr); } /* file type: FAT only knows DIR and FILE */ if ((dir->attrib & FATFS_ATTR_DIRECTORY) == FATFS_ATTR_DIRECTORY) fs_name->type = TSK_FS_NAME_TYPE_DIR; else fs_name->type = TSK_FS_NAME_TYPE_REG; /* set the inode */ fs_name->meta_addr = inode; inode = 0; // so that we don't use it anymore -- use only fs_name->meta_addr /* Handle the . and .. entries specially * The current inode 'address' they have is for the current * slot in the cluster, but it needs to refer to the original * slot */ if (TSK_FS_ISDOT(fs_name->name) && (fs_name->type == TSK_FS_NAME_TYPE_DIR) && idx < 2) { if (fs_name->name[1] == '\0') { /* Current directory - "." */ fs_name->meta_addr = a_fs_dir->fs_file->meta->addr; } /* for the parent directory, look up in the list that * is maintained in fafs_info */ else if (fs_name->name[1] == '.') { /* Parent directory - ".." */ uint8_t dir_found = 0; if (fatfs_dir_buf_get(fatfs, a_fs_dir->fs_file->meta->addr, &(fs_name->meta_addr)) == 0) { dir_found = 1; } if ((dir_found == 0) && (addrs[0] == fatfs->firstdatasect)) { /* if we are currently in the root directory, we aren't going to find * a parent. This shouldn't happen, but could result in an infinite loop. */ fs_name->meta_addr = 0; dir_found = 1; } if (dir_found == 0) { if (tsk_verbose) fprintf(stderr, "fatfs_dent_parse_buf: Walking directory to find parent\n"); /* The parent directory is not in the list. We are going to walk * the directory until we hit this directory. This process will * populate the buffer table and we will then rescan it */ if (tsk_fs_dir_walk(fs, fs->root_inum, (TSK_FS_DIR_WALK_FLAG_ENUM)(TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC | TSK_FS_DIR_WALK_FLAG_RECURSE), fatfs_find_parent_act, (void *) &a_fs_dir->fs_file->meta->addr)) { return TSK_OK; } if (tsk_verbose) fprintf(stderr, "fatfs_dent_parse_buf: Finished walking directory to find parent\n"); if (fatfs_dir_buf_get(fatfs, a_fs_dir->fs_file->meta->addr, &(fs_name->meta_addr)) == 0) { dir_found = 1; } // if we did not find it, then it was probably // from the orphan directory... if (dir_found == 0) fs_name->meta_addr = TSK_FS_ORPHANDIR_INUM(fs); } } } else { /* Save the (non-. or ..) directory to parent directory info to local * structures so that we can later fill into the inode * info for '..' entries */ if (fs_name->type == TSK_FS_NAME_TYPE_DIR) { if (fatfs_dir_buf_add(fatfs, a_fs_dir->fs_file->meta->addr, fs_name->meta_addr)) return TSK_ERR; } } /* The allocation status of an entry is based on the allocation * status of the sector it is in and the flag. Deleted directories * do not always clear the flags of each entry */ if (sectalloc == 1) { if(FATXXFS_IS_DELETED(dep->name, fatfs)){ fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; } else{ fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; } } else { fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; } tsk_fs_dir_add(a_fs_dir, fs_name); } } tsk_fs_name_free(fs_name); return TSK_OK; }
/** * Parses the file and populates the structures used by this FUSE driver. * * \param filename The filename to parse * \param r The result structure to populate (or NULL if not needed) * \returns 0 if successful, -1 if not. */ static int process_file(const char *filename, result_t new_result) { img_info = tsk_img_open_sing(filename, TSK_IMG_TYPE_DETECT, 0); if (img_info == NULL) { info_log("Failed to open image: %s", filename); return -1; } fs_info = tsk_fs_open_img(img_info, 0, TSK_FS_TYPE_DETECT); if (fs_info == NULL) { info_log("Failed to open filesystem: %s", filename); return -1; } const char *fsname = tsk_fs_type_toname(fs_info->ftype); result_set_brief_data_description(new_result, fsname); mountpoint = g_strdup_printf("%s:mnt-%s", filename, fsname); char *description = g_strdup_printf("%" PRIdDADDR " bytes (%" PRIdDADDR " %ss of %u size)", fs_info->block_count * fs_info->block_size, fs_info->block_count, fs_info->duname, fs_info->block_size); result_set_data_description(new_result, description); g_free(description); result_set_confidence(new_result, 100); block_start(absolute_offset); TSK_FS_DIR_WALK_FLAG_ENUM name_flags = (TSK_FS_DIR_WALK_FLAG_ENUM) (TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC | TSK_FS_DIR_WALK_FLAG_RECURSE); if (tsk_fs_dir_walk(fs_info, fs_info->root_inum, name_flags, examine_dirent, new_result) != 0) { // Why does this occur? Is it because it's an invalid filesystem structure, or the // structure is damaged? I'm going to assume the structure is damaged, but partially available. warning_log("Warning, unable to fully walk fs! Probably truncated or not a real FS header."); } unsigned int size; block_range_t *ranges = block_end(&size); if (ranges != NULL) { result_set_block_ranges(new_result, ranges, size); for (int i = 0; i < size; i++) { block_range_close(ranges[i]); } g_free(ranges); } if (inode_lookup != NULL) { g_tree_destroy(inode_lookup); inode_lookup = NULL; } unsigned int num_contracts; result_get_new_contracts(new_result, &num_contracts); if (num_contracts > 0) { // Ready to mount! int ret = do_mount(mountpoint); if (ret != 0) { error_log("Failed to mount filesystem!"); } } remove_all_files(); return 0; }
/* * Process the contents of a directory and add them to FS_DIR. * * @param fatfs File system information structure * @param a_fs_dir Structure to store the files in. * @param list_seen List of directory inodes that have been seen thus far in * directory walking (can be a pointer to a NULL pointer on first call). * @param buf Buffer that contains the directory contents. * @param len Length of buffer in bytes (must be a multiple of sector size) * @param addrs Array where each element is the original address of the * corresponding block in buf (size of array is number of blocks in directory). * * @return -1 on error, 0 on success, and 1 to stop */ static TSK_RETVAL_ENUM fatfs_dent_parse_buf(FATFS_INFO * fatfs, TSK_FS_DIR * a_fs_dir, char *buf, TSK_OFF_T len, TSK_DADDR_T * addrs) { unsigned int idx, sidx; int a, b; TSK_INUM_T inode, ibase; fatfs_dentry *dep; TSK_FS_INFO *fs = (TSK_FS_INFO *) & fatfs->fs_info; int sectalloc; TSK_FS_NAME *fs_name; FATFS_LFN lfninfo; if (buf == NULL) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "fatfs_dent_parse_buf: buffer is NULL"); return TSK_ERR; } dep = (fatfs_dentry *) buf; if ((fs_name = tsk_fs_name_alloc(FATFS_MAXNAMLEN_UTF8, 32)) == NULL) { return TSK_ERR; } memset(&lfninfo, 0, sizeof(FATFS_LFN)); lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; for (sidx = 0; sidx < (unsigned int) (len / fatfs->ssize); sidx++) { /* Get the base inode for this sector */ ibase = FATFS_SECT_2_INODE(fatfs, addrs[sidx]); if (ibase > fs->last_inum) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "fatfs_parse: inode address is too large"); tsk_fs_name_free(fs_name); return TSK_COR; } if (tsk_verbose) tsk_fprintf(stderr, "fatfs_dent_parse_buf: Parsing sector %" PRIuDADDR "\n", addrs[sidx]); if ((sectalloc = fatfs_is_sectalloc(fatfs, addrs[sidx])) == -1) { if (tsk_verbose) { tsk_fprintf(stderr, "fatfs_dent_parse_buf: Error looking up sector allocation: %" PRIuDADDR "\n", addrs[sidx]); tsk_error_print(stderr); } tsk_error_reset(); continue; } /* cycle through the directory entries */ for (idx = 0; idx < fatfs->dentry_cnt_se; idx++, dep++) { fatfs_dentry *dir; int i; /* is it a valid dentry? */ if (0 == fatfs_isdentry(fatfs, dep)) { if (tsk_verbose) tsk_fprintf(stderr, "fatfs_dent_parse_buf: Entry %u is invalid\n", idx); continue; } /* Copy the directory entry into the TSK_FS_NAME structure */ dir = (fatfs_dentry *) dep; inode = ibase + idx; /* Take care of the name * Copy a long name to a buffer and take action if it * is a small name */ if ((dir->attrib & FATFS_ATTR_LFN) == FATFS_ATTR_LFN) { fatfs_dentry_lfn *dirl = (fatfs_dentry_lfn *) dir; /* Store the name in dinfo until we get the 8.3 name * Use the checksum to identify a new sequence * */ if (((dirl->seq & FATFS_LFN_SEQ_FIRST) && (dirl->seq != FATFS_SLOT_DELETED)) || (dirl->chksum != lfninfo.chk)) { // @@@ Do a partial output here /* Reset the values */ lfninfo.seq = dirl->seq & FATFS_LFN_SEQ_MASK; lfninfo.chk = dirl->chksum; lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; } else if (dirl->seq != lfninfo.seq - 1) { // @@@ Check the sequence number - the checksum is correct though... } /* Copy the UTF16 values starting at end of buffer */ for (a = 3; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part3[a]; } for (a = 11; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part2[a]; } for (a = 9; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part1[a]; } // Skip ahead until we get a new sequence num or the 8.3 name continue; } /* Special case for volume label: name does not have an * extension and we add a note at the end that it is a label */ else if ((dir->attrib & FATFS_ATTR_VOLUME) == FATFS_ATTR_VOLUME) { a = 0; for (b = 0; b < 8; b++) { if ((dir->name[b] >= 0x20) && (dir->name[b] != 0xff)) { fs_name->name[a++] = dir->name[b]; } else { fs_name->name[a++] = '^'; } } for (b = 0; b < 3; b++) { if ((dir->ext[b] >= 0x20) && (dir->ext[b] != 0xff)) { fs_name->name[a++] = dir->ext[b]; } else { fs_name->name[a++] = '^'; } } fs_name->name[a] = '\0'; /* Append a string to show it is a label */ if (a + 22 < FATFS_MAXNAMLEN_UTF8) { char *volstr = " (Volume Label Entry)"; strncat(fs_name->name, volstr, FATFS_MAXNAMLEN_UTF8 - a); } } /* A short (8.3) entry */ else { char *name_ptr; // The dest location for the short name /* if we have a lfn, copy it into fs_name->name * and put the short name in fs_name->shrt_name */ if (lfninfo.start != FATFS_MAXNAMLEN_UTF8 - 1) { int retVal; /* @@@ Check the checksum */ /* Convert the UTF16 to UTF8 */ UTF16 *name16 = (UTF16 *) ((uintptr_t) & lfninfo.name[lfninfo. start + 1]); UTF8 *name8 = (UTF8 *) fs_name->name; retVal = tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16, (UTF16 *) & lfninfo.name[FATFS_MAXNAMLEN_UTF8], &name8, (UTF8 *) ((uintptr_t) name8 + FATFS_MAXNAMLEN_UTF8), TSKlenientConversion); if (retVal != TSKconversionOK) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_UNICODE; snprintf(tsk_errstr, TSK_ERRSTR_L, "fatfs_parse: Error converting FAT LFN to UTF8: %d", retVal); continue; } /* Make sure it is NULL Terminated */ if ((uintptr_t) name8 > (uintptr_t) fs_name->name + FATFS_MAXNAMLEN_UTF8) fs_name->name[FATFS_MAXNAMLEN_UTF8 - 1] = '\0'; else *name8 = '\0'; /* Clean up name */ i = 0; while (fs_name->name[i] != '\0') { if (TSK_IS_CNTRL(fs_name->name[i])) fs_name->name[i] = '^'; i++; } lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; name_ptr = fs_name->shrt_name; // put 8.3 into shrt_name } /* We don't have a LFN, so put the short name in * fs_name->name */ else { fs_name->shrt_name[0] = '\0'; name_ptr = fs_name->name; // put 8.3 into normal location } /* copy in the short name into the place specified above. * Skip spaces and put in the . */ a = 0; for (b = 0; b < 8; b++) { if ((dir->name[b] != 0) && (dir->name[b] != 0xff) && (dir->name[b] != 0x20)) { if ((b == 0) && (dir->name[0] == FATFS_SLOT_DELETED)) { name_ptr[a++] = '_'; } else if ((dir->lowercase & FATFS_CASE_LOWER_BASE) && (dir->name[b] >= 'A') && (dir->name[b] <= 'Z')) { name_ptr[a++] = dir->name[b] + 32; } else { name_ptr[a++] = dir->name[b]; } } } for (b = 0; b < 3; b++) { if ((dir->ext[b] != 0) && (dir->ext[b] != 0xff) && (dir->ext[b] != 0x20)) { if (b == 0) name_ptr[a++] = '.'; if ((dir->lowercase & FATFS_CASE_LOWER_EXT) && (dir->ext[b] >= 'A') && (dir->ext[b] <= 'Z')) name_ptr[a++] = dir->ext[b] + 32; else name_ptr[a++] = dir->ext[b]; } } name_ptr[a] = '\0'; } /* Clean up name to remove control chars */ i = 0; while (fs_name->name[i] != '\0') { if (TSK_IS_CNTRL(fs_name->name[i])) fs_name->name[i] = '^'; i++; } /* file type: FAT only knows DIR and FILE */ if ((dir->attrib & FATFS_ATTR_DIRECTORY) == FATFS_ATTR_DIRECTORY) fs_name->type = TSK_FS_NAME_TYPE_DIR; else fs_name->type = TSK_FS_NAME_TYPE_REG; /* Get inode */ fs_name->meta_addr = inode; /* Handle the . and .. entries specially * The current inode 'address' they have is for the current * slot in the cluster, but it needs to refer to the original * slot */ if (TSK_FS_ISDOT(fs_name->name)) { if (fs_name->name[1] == '\0') { inode = fs_name->meta_addr = a_fs_dir->fs_file->meta->addr; } /* for the parent directory, look up in the list that * is maintained in fafs_info */ else if (fs_name->name[1] == '.') { size_t q; uint8_t dir_found = 0; for (q = 0; q < fatfs->dir_buf_next; q++) { if (fatfs->dir_buf[q] == a_fs_dir->fs_file->meta->addr) { inode = fs_name->meta_addr = fatfs->par_buf[q]; dir_found = 1; break; } } if ((dir_found == 0) && (fs->isOrphanHunting)) { /* if we are currently scanning the fs to determine the orphan files, * then we do not care about the value of '..' and this can only cause * infinite loop problems */ inode = fs_name->meta_addr = 0; dir_found = 1; } if ((dir_found == 0) && (addrs[0] == fatfs->firstdatasect)) { /* if we are currently in the root directory, we aren't going to find * a parent. This shouldn't happen, but could result in an infinite loop. */ inode = fs_name->meta_addr = 0; dir_found = 1; } if (dir_found == 0) { /* The parent directory is not in the list. We are going to walk * the directory until we hit this directory. This process will * populate the buffer table and we will then rescan it */ if (tsk_fs_dir_walk(fs, fs->root_inum, TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC | TSK_FS_DIR_WALK_FLAG_RECURSE, find_parent_act, (void *) &a_fs_dir->fs_file->meta->addr)) { return 0; } for (q = 0; q < fatfs->dir_buf_next; q++) { if (fatfs->dir_buf[q] == a_fs_dir->fs_file->meta->addr) { inode = fs_name->meta_addr = fatfs->par_buf[q]; dir_found = 1; break; } } // if we did not find it, then it was probably // from the orphan directory... if (dir_found == 0) inode = fs_name->meta_addr = TSK_FS_ORPHANDIR_INUM(fs); } } } else { /* Save the (non-. or ..) directory to parent directory info to local * structures so that we can later fill into the inode * info for '..' entries */ if (fs_name->type == TSK_FS_NAME_TYPE_DIR) { if (fatfs_dir_buf_add(fatfs, a_fs_dir->fs_file->meta->addr, inode)) return TSK_ERR; } } /* The allocation status of an entry is based on the allocation * status of the sector it is in and the flag. Deleted directories * do not always clear the flags of each entry */ if (sectalloc == 1) { fs_name->flags = (dep->name[0] == FATFS_SLOT_DELETED) ? TSK_FS_NAME_FLAG_UNALLOC : TSK_FS_NAME_FLAG_ALLOC; } else { fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; } tsk_fs_dir_add(a_fs_dir, fs_name); } } tsk_fs_name_free(fs_name); return TSK_OK; }
// 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; }
/* * Process the contents of a directory and add them to FS_DIR. * * @param xtaffs File system information structure * @param a_fs_dir Structure to store the files in. * @param list_seen List of directory inodes that have been seen thus far in * directory walking (can be a pointer to a NULL pointer on first call). * @param buf Buffer that contains the directory contents. * @param len Length of buffer in bytes (must be a multiple of sector size) * @param addrs Array where each element is the original address of the * corresponding block in buf (size of array is number of blocks in directory). * * @return -1 on error, 0 on success, and 1 to stop */ static TSK_RETVAL_ENUM xtaffs_dent_parse_buf(XTAFFS_INFO * xtaffs, TSK_FS_DIR * a_fs_dir, char *buf, TSK_OFF_T len, TSK_DADDR_T * addrs) { unsigned int idx, sidx; int a, b; TSK_INUM_T ibase; xtaffs_dentry *dep; TSK_FS_INFO *fs = (TSK_FS_INFO *) & xtaffs->fs_info; int sectalloc; TSK_FS_NAME *fs_name; XTAFFS_LFN lfninfo; int entrySeenCount = 0; int entryInvalidCount = 0; uint8_t isCorruptDir = 0; if (buf == NULL) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr("xtaffs_dent_parse_buf: buffer is NULL"); return TSK_ERR; } dep = (xtaffs_dentry *) buf; if ((fs_name = tsk_fs_name_alloc(XTAFFS_MAXNAMLEN_UTF8, 32)) == NULL) { return TSK_ERR; } memset(&lfninfo, 0, sizeof(XTAFFS_LFN)); lfninfo.start = XTAFFS_MAXNAMLEN_UTF8 - 1; for (sidx = 0; sidx < (unsigned int) (len / xtaffs->ssize); sidx++) { /* Get the base inode for this sector */ ibase = XTAFFS_SECT_2_INODE(xtaffs, addrs[sidx]); if (ibase > fs->last_inum) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr ("xtaffs_parse: inode address is too large"); tsk_fs_name_free(fs_name); return TSK_COR; } if (tsk_verbose) tsk_fprintf(stderr, "xtaffs_dent_parse_buf: Parsing sector %" PRIuDADDR " for dir %" PRIuINUM "\n", addrs[sidx], a_fs_dir->addr); if ((sectalloc = xtaffs_is_sectalloc(xtaffs, addrs[sidx])) == -1) { if (tsk_verbose) { tsk_fprintf(stderr, "xtaffs_dent_parse_buf: Error looking up sector allocation: %" PRIuDADDR "\n", addrs[sidx]); tsk_error_print(stderr); } tsk_error_reset(); continue; } /* cycle through the directory entries */ for (idx = 0; idx < xtaffs->dentry_cnt_se; idx++, dep++) { xtaffs_dentry *dir; TSK_INUM_T inode; entrySeenCount++; /* is it a valid dentry? */ if (0 == xtaffs_isdentry(xtaffs, dep, ((isCorruptDir == 0) && (sectalloc)) ? 1 : 0)) { if (tsk_verbose) tsk_fprintf(stderr, "xtaffs_dent_parse_buf: Entry %u is invalid\n", idx); entryInvalidCount++; /* If we have seen four entries and all of them are corrupt, * then test every remaining entry in this folder -- * even if the sector is allocated. The scenario is one * where we are processing a cluster that is allocated * to a file and we happen to get some data that matches * every now and then. */ if ((entrySeenCount == 4) && (entryInvalidCount == 4)) { isCorruptDir = 1; } continue; } /* Copy the directory entry into the TSK_FS_NAME structure */ dir = (xtaffs_dentry *) dep; inode = ibase + idx; /* Take care of the name * Copy a long name to a buffer and take action if it * is a small name if ((dir->attrib & XTAFFS_ATTR_LFN) == XTAFFS_ATTR_LFN) { xtaffs_dentry_lfn *dirl = (xtaffs_dentry_lfn *) dir; * Store the name in dinfo until we get the 8.3 name * Use the checksum to identify a new sequence * * if (((dirl->seq & XTAFFS_LFN_SEQ_FIRST) && (dirl->seq != XTAFFS_SLOT_DELETED)) || (dirl->chksum != lfninfo.chk)) { // @@@ Do a partial output here * Reset the values * lfninfo.seq = dirl->seq & XTAFFS_LFN_SEQ_MASK; lfninfo.chk = dirl->chksum; lfninfo.start = XTAFFS_MAXNAMLEN_UTF8 - 1; } else if (dirl->seq != lfninfo.seq - 1) { // @@@ Check the sequence number - the checksum is correct though... } * Copy the UTF16 values starting at end of buffer * for (a = 3; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part3[a]; } for (a = 11; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part2[a]; } for (a = 9; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part1[a]; } // Skip ahead until we get a new sequence num or the 8.3 name continue; } */ /* Special case for volume label: name does not have an * extension and we add a note at the end that it is a label */ if ((dir->attrib & XTAFFS_ATTR_VOLUME) == XTAFFS_ATTR_VOLUME) { a = 0; for (b = 0; b < 42; b++) { if(dir->name[b] < 32 || dir->name[b] > 126) break; if ((dir->name[b] >= 0x20) && (dir->name[b] != 0xff)) { fs_name->name[a++] = dir->name[b]; } else { fs_name->name[a++] = '^'; } } fs_name->name[a] = '\0'; /* Append a string to show it is a label */ if (a + 22 < XTAFFS_MAXNAMLEN_UTF8) { const char *volstr = " (Volume Label Entry)"; strncat(fs_name->name, volstr, XTAFFS_MAXNAMLEN_UTF8 - a); } } /* AJN TODO Scrap this 8.3 stuff, it isn't in XTAF.*/ /* A short (8.3) entry */ else { char *name_ptr; // The dest location for the short name fs_name->shrt_name[0] = '\0'; name_ptr = fs_name->name; // put 8.3 into normal location /* copy in the short name into the place specified above. */ a = 0; for (b = 0; b < 42; b++) { if(dir->name[b] < 32 || dir->name[b] > 126) break; if ((dir->name[b] != 0) && (dir->name[b] != 0xff)) { if ((b == 0) && (dir->name[0] == XTAFFS_SLOT_DELETED)) { name_ptr[a++] = '_'; } else { name_ptr[a++] = dir->name[b]; } } } name_ptr[a] = '\0'; // make sure that only ASCII is in the short name xtaffs_cleanup_ascii(name_ptr); } /* file type: FAT only knows DIR and FILE */ if ((dir->attrib & XTAFFS_ATTR_DIRECTORY) == XTAFFS_ATTR_DIRECTORY) fs_name->type = TSK_FS_NAME_TYPE_DIR; else fs_name->type = TSK_FS_NAME_TYPE_REG; /* set the inode */ fs_name->meta_addr = inode; inode = 0; // so that we don't use it anymore -- use only fs_name->meta_addr /* Handle the . and .. entries specially * The current inode 'address' they have is for the current * slot in the cluster, but it needs to refer to the original * slot */ if (TSK_FS_ISDOT(fs_name->name) && (fs_name->type == TSK_FS_NAME_TYPE_DIR) && idx < 2) { if (fs_name->name[1] == '\0') { fs_name->meta_addr = a_fs_dir->fs_file->meta->addr; } /* for the parent directory, look up in the list that * is maintained in fafs_info */ else if (fs_name->name[1] == '.') { uint8_t dir_found = 0; if (xtaffs_dir_buf_get(xtaffs, a_fs_dir->fs_file->meta->addr, &(fs_name->meta_addr)) == 0) { dir_found = 1; } if ((dir_found == 0) && (addrs[0] == xtaffs->firstdatasect)) { /* if we are currently in the root directory, we aren't going to find * a parent. This shouldn't happen, but could result in an infinite loop. */ fs_name->meta_addr = 0; dir_found = 1; } if (dir_found == 0) { if (tsk_verbose) fprintf(stderr, "xtaffs_dent_parse_buf: Walking directory to find parent\n"); /* The parent directory is not in the list. We are going to walk * the directory until we hit this directory. This process will * populate the buffer table and we will then rescan it */ if (tsk_fs_dir_walk(fs, fs->root_inum, (TSK_FS_DIR_WALK_FLAG_ENUM)(TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC | TSK_FS_DIR_WALK_FLAG_RECURSE), find_parent_act, (void *) &a_fs_dir->fs_file->meta->addr)) { return TSK_OK; } if (tsk_verbose) fprintf(stderr, "xtaffs_dent_parse_buf: Finished walking directory to find parent\n"); if (xtaffs_dir_buf_get(xtaffs, a_fs_dir->fs_file->meta->addr, &(fs_name->meta_addr)) == 0) { dir_found = 1; } // if we did not find it, then it was probably // from the orphan directory... if (dir_found == 0) fs_name->meta_addr = TSK_FS_ORPHANDIR_INUM(fs); } } } else { /* Save the (non-. or ..) directory to parent directory info to local * structures so that we can later fill into the inode * info for '..' entries */ if (fs_name->type == TSK_FS_NAME_TYPE_DIR) { if (xtaffs_dir_buf_add(xtaffs, a_fs_dir->fs_file->meta->addr, fs_name->meta_addr)) return TSK_ERR; } } /* The allocation status of an entry is based on the allocation * status of the sector it is in and the flag. Deleted directories * do not always clear the flags of each entry */ if (sectalloc == 1) { fs_name->flags = (dep->name[0] == XTAFFS_SLOT_DELETED) ? TSK_FS_NAME_FLAG_UNALLOC : TSK_FS_NAME_FLAG_ALLOC; } else { fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; } tsk_fs_dir_add(a_fs_dir, fs_name); } } tsk_fs_name_free(fs_name); return TSK_OK; }
/* used to identify the unnamed metadata structures */ static TSK_WALK_RET_ENUM find_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 */ tsk_take_lock(&fs->list_inum_named_lock); if ((fs->list_inum_named) && (tsk_list_find(fs->list_inum_named, a_fs_file->meta->addr))) { tsk_release_lock(&fs->list_inum_named_lock); return TSK_WALK_CONT; } tsk_release_lock(&fs->list_inum_named_lock); // 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; data->fs_name->type = TSK_FS_NAME_TYPE_UNDEF; if (tsk_fs_dir_add(data->fs_dir, data->fs_name)) return TSK_WALK_ERROR; /* FAT file systems spend a lot of time hunting for parent * directory addresses, so we put this code in here to save * the info when we have it. */ if (TSK_FS_TYPE_ISFAT(fs->ftype)) { if (fatfs_dir_buf_add((FATFS_INFO *) fs, TSK_FS_ORPHANDIR_INUM(fs), a_fs_file->meta->addr)) 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_verbose) fprintf(stderr, "find_orphan_meta_walk_cb: Going into directory %" PRIuINUM " to mark contents as seen\n", a_fs_file->meta->addr); 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)) { tsk_error_errstr2_concat (" - find_orphan_meta_walk_cb: identifying inodes allocated by file names"); return TSK_WALK_ERROR; } } return TSK_WALK_CONT; }
/* 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; }