/** * \ingroup fslib * Get the contents and flags of a specific file system block. Note that if the block contains * compressed data, then this function will return the compressed data with the RAW flag set. * The uncompressed data can be obtained only from the file-level functions. * * @param a_fs The file system to read the block from. * @param a_fs_block The structure to write the block data into or NULL to have one created. * @param a_addr The file system address to read. * @param a_flags Flag to assign to the returned TSK_FS_BLOCK (use if you already have it as part of a block_walk-type scenario) * @return The TSK_FS_BLOCK with the data or NULL on error. (If a_fs_block was not NULL, this will * be the same structure). */ TSK_FS_BLOCK * tsk_fs_block_get_flag(TSK_FS_INFO * a_fs, TSK_FS_BLOCK * a_fs_block, TSK_DADDR_T a_addr, TSK_FS_BLOCK_FLAG_ENUM a_flags) { TSK_OFF_T offs; size_t len; if (a_fs == NULL) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_READ); tsk_error_set_errstr("tsk_fs_block_get: fs unallocated"); return NULL; } if (a_fs_block == NULL) { a_fs_block = tsk_fs_block_alloc(a_fs); } else if ((a_fs_block->tag != TSK_FS_BLOCK_TAG) || (a_fs_block->buf == NULL)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_READ); tsk_error_set_errstr("tsk_fs_block_get: fs_block unallocated"); return NULL; } len = a_fs->block_size; if (a_addr > a_fs->last_block_act) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_READ); if (a_addr <= a_fs->last_block) tsk_error_set_errstr ("tsk_fs_block_get: Address missing in partial image: %" PRIuDADDR ")", a_addr); else tsk_error_set_errstr ("tsk_fs_block_get: Address is too large for image: %" PRIuDADDR ")", a_addr); return NULL; } a_fs_block->fs_info = a_fs; a_fs_block->addr = a_addr; a_fs_block->flags = a_flags; a_fs_block->flags |= TSK_FS_BLOCK_FLAG_RAW; offs = (TSK_OFF_T) a_addr *a_fs->block_size; if ((a_fs_block->flags & TSK_FS_BLOCK_FLAG_AONLY) == 0) { ssize_t cnt; cnt = tsk_img_read(a_fs->img_info, a_fs->offset + offs, a_fs_block->buf, len); if (cnt != (ssize_t)len) { return NULL; } } return a_fs_block; }
/** \internal * * return 1 on error and 0 on success */ uint8_t tsk_fs_nofs_block_walk(TSK_FS_INFO * fs, TSK_DADDR_T a_start_blk, TSK_DADDR_T a_end_blk, TSK_FS_BLOCK_WALK_FLAG_ENUM a_flags, TSK_FS_BLOCK_WALK_CB a_action, void *a_ptr) { TSK_FS_BLOCK *fs_block; TSK_DADDR_T addr; // clean up any error messages that are lying around tsk_error_reset(); /* * Sanity checks. */ if (a_start_blk < fs->first_block || a_start_blk > fs->last_block) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_WALK_RNG); tsk_error_set_errstr("nofs_block_walk: Start block number: %" PRIuDADDR, a_start_blk); return 1; } if (a_end_blk < fs->first_block || a_end_blk > fs->last_block || a_end_blk < a_start_blk) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_WALK_RNG); tsk_error_set_errstr("nofs_block_walk: Last block number: %" PRIuDADDR, a_end_blk); return 1; } /* Sanity check on a_flags -- make sure at least one ALLOC is set */ if (((a_flags & TSK_FS_BLOCK_WALK_FLAG_ALLOC) == 0) && ((a_flags & TSK_FS_BLOCK_WALK_FLAG_UNALLOC) == 0)) { a_flags |= (TSK_FS_BLOCK_WALK_FLAG_ALLOC | TSK_FS_BLOCK_WALK_FLAG_UNALLOC); } /* All swap has is allocated blocks... exit if not wanted */ if (!(a_flags & TSK_FS_BLOCK_FLAG_ALLOC)) { return 0; } if ((fs_block = tsk_fs_block_alloc(fs)) == NULL) { return 1; } for (addr = a_start_blk; addr <= a_end_blk; addr++) { int retval; if (tsk_fs_block_get(fs, fs_block, addr) == NULL) { tsk_error_set_errstr2("nofs_block_walk: Block %" PRIuDADDR, addr); tsk_fs_block_free(fs_block); return 1; } retval = a_action(fs_block, a_ptr); if (retval == TSK_WALK_STOP) { break; } else if (retval == TSK_WALK_ERROR) { tsk_fs_block_free(fs_block); return 1; } } /* * Cleanup. */ tsk_fs_block_free(fs_block); return 0; }