/* returns 0 on success and 1 on error */ static uint8_t ext2fs_dent_walk_lcl(TSK_FS_INFO * fs, EXT2FS_DINFO * dinfo, TSK_LIST ** list_seen, INUM_T inode, TSK_FS_DENT_FLAG_ENUM flags, TSK_FS_DENT_TYPE_WALK_CB action, void *ptr) { TSK_FS_INODE *fs_inode; EXT2FS_INFO *ext2fs = (EXT2FS_INFO *) fs; char *dirbuf, *dirptr; OFF_T size; TSK_FS_LOAD_FILE load_file; int retval = 0; if (inode < fs->first_inum || inode > fs->last_inum) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_WALK_RNG; snprintf(tsk_errstr, TSK_ERRSTR_L, "ext2fs_dent_walk_lcl: inode value: %" PRIuINUM "\n", inode); return 1; } if (tsk_verbose) tsk_fprintf(stderr, "ext2fs_dent_walk_lcl: Processing directory %" PRIuINUM "\n", inode); if ((fs_inode = fs->inode_lookup(fs, inode)) == NULL) { strncat(tsk_errstr2, " - ext2fs_dent_walk_lcl", TSK_ERRSTR_L - strlen(tsk_errstr2)); return 1; } size = roundup(fs_inode->size, fs->block_size); if ((dirbuf = tsk_malloc((size_t) size)) == NULL) { tsk_fs_inode_free(fs_inode); return 1; } /* make a copy of the directory contents that we can process */ load_file.left = load_file.total = (size_t) size; load_file.base = load_file.cur = dirbuf; if (fs->file_walk(fs, fs_inode, 0, 0, TSK_FS_FILE_FLAG_SLACK | TSK_FS_FILE_FLAG_NOID, tsk_fs_load_file_action, (void *) &load_file)) { free(dirbuf); tsk_fs_inode_free(fs_inode); strncat(tsk_errstr2, " - extX_dent_walk_lcl", TSK_ERRSTR_L - strlen(tsk_errstr2)); return 1; } /* Not all of the directory was copied, so we exit */ if (load_file.left > 0) { free(dirbuf); tsk_fs_inode_free(fs_inode); tsk_error_reset(); tsk_errno = TSK_ERR_FS_FWALK; snprintf(tsk_errstr, TSK_ERRSTR_L, "ext2fs_dent_walk: Error reading directory contents: %" PRIuINUM "\n", inode); return 1; } dirptr = dirbuf; while ((int64_t) size > 0) { int len = (fs->block_size < size) ? fs->block_size : (int) size; retval = ext2fs_dent_parse_block(ext2fs, dinfo, list_seen, dirptr, len, flags, action, ptr); /* if 1, then the action wants to stop, -1 is error */ if ((retval == 1) || (retval == -1)) break; size -= len; dirptr = (char *) ((uintptr_t) dirptr + len); } tsk_fs_inode_free(fs_inode); free(dirbuf); if (retval == -1) return 1; else return 0; }
TSK_RETVAL_ENUM ext2fs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir, TSK_INUM_T a_addr) { EXT2FS_INFO *ext2fs = (EXT2FS_INFO *) a_fs; char *dirbuf, *dirptr; TSK_OFF_T size; TSK_FS_LOAD_FILE load_file; TSK_FS_DIR *fs_dir; TSK_LIST *list_seen = NULL; /* If we get corruption in one of the blocks, then continue processing. * retval_final will change when corruption is detected. Errors are * returned immediately. */ TSK_RETVAL_ENUM retval_tmp; TSK_RETVAL_ENUM retval_final = TSK_OK; if (a_addr < a_fs->first_inum || a_addr > a_fs->last_inum) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_WALK_RNG); tsk_error_set_errstr("ext2fs_dir_open_meta: inode value: %" PRIuINUM "\n", a_addr); return TSK_ERR; } else if (a_fs_dir == NULL) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr ("ext2fs_dir_open_meta: NULL fs_attr argument given"); return TSK_ERR; } if (tsk_verbose) { tsk_fprintf(stderr, "ext2fs_dir_open_meta: Processing directory %" PRIuINUM "\n", a_addr); #ifdef Ext4_DBG tsk_fprintf(stderr, "ext2fs_dir_open_meta: $OrphanFiles Inum %" PRIuINUM " == %" PRIuINUM ": %d\n", TSK_FS_ORPHANDIR_INUM(a_fs), a_addr, a_addr == TSK_FS_ORPHANDIR_INUM(a_fs)); #endif } fs_dir = *a_fs_dir; if (fs_dir) { tsk_fs_dir_reset(fs_dir); fs_dir->addr = a_addr; } else { if ((*a_fs_dir = fs_dir = tsk_fs_dir_alloc(a_fs, a_addr, 128)) == NULL) { return TSK_ERR; } } // handle the orphan directory if its contents were requested if (a_addr == TSK_FS_ORPHANDIR_INUM(a_fs)) { #ifdef Ext4_DBG tsk_fprintf(stderr, "DEBUG: Getting ready to process ORPHANS\n"); #endif return tsk_fs_dir_find_orphans(a_fs, fs_dir); } else { #ifdef Ext4_DBG tsk_fprintf(stderr, "DEBUG: not orphan %" PRIuINUM "!=%" PRIuINUM "\n", a_addr, TSK_FS_ORPHANDIR_INUM(a_fs)); #endif } if ((fs_dir->fs_file = tsk_fs_file_open_meta(a_fs, NULL, a_addr)) == NULL) { tsk_error_reset(); tsk_error_errstr2_concat("- ext2fs_dir_open_meta"); return TSK_COR; } size = roundup(fs_dir->fs_file->meta->size, a_fs->block_size); if ((dirbuf = tsk_malloc((size_t) size)) == NULL) { return TSK_ERR; } /* make a copy of the directory contents that we can process */ load_file.left = load_file.total = (size_t) size; load_file.base = load_file.cur = dirbuf; if (tsk_fs_file_walk(fs_dir->fs_file, TSK_FS_FILE_WALK_FLAG_SLACK, tsk_fs_load_file_action, (void *) &load_file)) { tsk_error_reset(); tsk_error_errstr2_concat("- ext2fs_dir_open_meta"); free(dirbuf); return TSK_COR; } /* Not all of the directory was copied, so we exit */ if (load_file.left > 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_FWALK); tsk_error_set_errstr ("ext2fs_dir_open_meta: Error reading directory contents: %" PRIuINUM "\n", a_addr); free(dirbuf); return TSK_COR; } dirptr = dirbuf; while ((int64_t) size > 0) { int len = (a_fs->block_size < size) ? a_fs->block_size : (int) size; retval_tmp = ext2fs_dent_parse_block(ext2fs, fs_dir, (fs_dir->fs_file->meta-> flags & TSK_FS_META_FLAG_UNALLOC) ? 1 : 0, &list_seen, dirptr, len); if (retval_tmp == TSK_ERR) { retval_final = TSK_ERR; break; } else if (retval_tmp == TSK_COR) { retval_final = TSK_COR; } size -= len; dirptr = (char *) ((uintptr_t) dirptr + len); } free(dirbuf); // if we are listing the root directory, add the Orphan directory entry if (a_addr == a_fs->root_inum) { TSK_FS_NAME *fs_name = tsk_fs_name_alloc(256, 0); if (fs_name == NULL) return TSK_ERR; if (tsk_fs_dir_make_orphan_dir_name(a_fs, fs_name)) { tsk_fs_name_free(fs_name); return TSK_ERR; } if (tsk_fs_dir_add(fs_dir, fs_name)) { tsk_fs_name_free(fs_name); return TSK_ERR; } tsk_fs_name_free(fs_name); } return retval_final; }