📄 vdkread.c
字号:
/* vdkread.c Virtual Disk read function Copyright (C) 2003 Ken Kato*/#include "vdkbase.h"#include "vdkutil.h"#include "vdkaccess.h"#include "cowdisk.h"#include "vmdisk.h"//// Read requested sectors from virtual disk//VDKSTAT VdkReadSector( PVDK_DISK_INFO DiskInfo, ULONG Offset, ULONG Length, PUCHAR Buffer){ PVDK_FILE_INFO top_level_file; PVDK_FILE_INFO no_more_file; ULONG top_level_offset; VDKSTAT status; VDKTRACE(VDKREAD | VDKINFO, ("[VDK] VdkRead - Request Offset sec. %u, length %u\n", Offset, Length)); if (DiskInfo == NULL || DiskInfo->Files == NULL) { VDKTRACE(VDKREAD, ("[VDK] null DiskInfo\n")); return VDK_INTERNAL; } if (Offset + Length > DiskInfo->Capacity) { VDKTRACE(VDKREAD, ("[VDK] request out of range\n")); return VDK_INTERNAL; } if (Buffer == NULL) { VDKTRACE(VDKREAD, ("[VDK] null read buffer\n")); return VDK_INTERNAL; } top_level_file = DiskInfo->Files; no_more_file = &(DiskInfo->Files[DiskInfo->FilesTotal]); top_level_offset = Offset; // // Start reading data from file // while (Length) { PVDK_FILE_INFO file_info; ULONG sector_map_idx; ULONG read_offset; ULONG read_length; ULONG actual_length; // // look for a top level file containing the target sector // while (top_level_offset >= top_level_file->Capacity) { // // data is stored past this file // top_level_offset -= top_level_file->Capacity; top_level_file++; } VDKTRACE(VDKREAD | VDKINFO, ("[VDK] Checking file #%u.\n", top_level_file - DiskInfo->Files)); // // current file info pointer to work with // file_info = top_level_file; // // offset in a allocation block // The whole file is one block for plain files. // read_offset = top_level_offset; // // maximum data which could be read at once // read_length = file_info->Capacity; // // initial sector map index number // sector_map_idx = 0; // // Walk through the file generation chain to find a file // which actually contains target sector range // for (;;) { if (file_info->FileType == VDK_FILETYPE_FLAT) { // // This file contains the target sector // break; } else if (file_info->FileType == VDK_FILETYPE_COWD) { // // check for the smallest block size // if (read_length > file_info->prm.cowd->SecondaryGranularity) { read_length = file_info->prm.cowd->SecondaryGranularity; VDKTRACE(VDKREAD | VDKINFO, ("[VDK] Using Granularity %u\n", read_length)); } // // check secondary map allocation // sector_map_idx = read_offset / file_info->prm.cowd->PrimaryGranularity; if (sector_map_idx >= file_info->prm.cowd->PrimaryMapSize) { // // offset exceeds the primary map size // Probably COWD header is corrupt and inconsistent // VDKTRACE(VDKREAD | VDKWARN, ("[VDK] Primary Map overflow\n")); file_info = NULL; break; } if (file_info->prm.cowd->PrimaryMap[sector_map_idx]) { // // Secondary map is allocated in the file // if (file_info->prm.cowd->SecondaryMapIdx != sector_map_idx) { // // Need to read secondary map from the file // VDKTRACE(VDKREAD | VDKINFO, ("[VDK] Loading Secondary Map #%u\n", sector_map_idx)); if (file_info->prm.cowd->PrimaryMap[sector_map_idx] >= file_info->EndOfFile) { // // Secondary Map Offset is too large // VDKTRACE(VDKREAD | VDKWARN, ("[VDK] Invalid Secondary Map Offset 0x%x\n", file_info->prm.cowd->PrimaryMap[sector_map_idx])); VdkZeroMem( file_info->prm.cowd->SecondaryMap, file_info->prm.cowd->SecondaryMapSize * sizeof(ULONG)); } else { status = VdkReadFileAt( file_info->FileHandle, (INT64)file_info->prm.cowd->PrimaryMap[sector_map_idx] << VDK_BYTE_SHIFT_TO_SECTOR, file_info->prm.cowd->SecondaryMap, file_info->prm.cowd->SecondaryMapSize * sizeof(ULONG), NULL); if (!VDKSUCCESS(status)) { return status; } } file_info->prm.cowd->SecondaryMapIdx = sector_map_idx; } // // check the target sector allocation // sector_map_idx = (read_offset % file_info->prm.cowd->PrimaryGranularity) / file_info->prm.cowd->SecondaryGranularity; if (sector_map_idx >= file_info->prm.cowd->SecondaryMapSize) { // // offset exceeds the secondary map size // Probably COWD header is corrupt and inconsistent // Or I have to find out how to get non-fixed secondary map size. // VDKTRACE(VDKREAD | VDKWARN, ("[VDK] Secondary Map overflow\n")); file_info = NULL; break; } if (file_info->prm.cowd->SecondaryMap[sector_map_idx] && file_info->prm.cowd->SecondaryMap[sector_map_idx] < file_info->EndOfFile) { // // Start sector is allocated in this file // break; } else if (file_info->prm.cowd->SecondaryMap[sector_map_idx] >= file_info->EndOfFile) { // // sector block offset exceeds current end of file // VDKTRACE(VDKREAD | VDKWARN, ("[VDK] Sector block offset too large\n")); file_info = NULL; break; } // // sector block is not allocated // } } else if (file_info->FileType == VDK_FILETYPE_VMDK) { // // check for the smallest block size // if (read_length > file_info->prm.vmdk->SectorsPerGrain) { read_length = file_info->prm.vmdk->SectorsPerGrain; VDKTRACE(VDKREAD | VDKINFO, ("[VDK] Using Granularity %u\n", read_length)); } // // Get grain table index // sector_map_idx = read_offset / file_info->prm.vmdk->SectorsPerTable; if (sector_map_idx >= file_info->prm.vmdk->DirectorySize || !file_info->prm.vmdk->PrimaryDirectory[sector_map_idx] || file_info->prm.vmdk->PrimaryDirectory[sector_map_idx] >= file_info->EndOfFile) { // // Grain table is not present; // something's wrong with VMDK header // VDKTRACE(VDKREAD | VDKWARN, ("[VDK] Cannot locate Grain Table %lu\n", sector_map_idx)); file_info = NULL; break; } if (file_info->prm.vmdk->GrainTableIdx != sector_map_idx) { // // Need to read the grain table from the file // VDKTRACE(VDKREAD | VDKINFO, ("[VDK] Loading Grain Table #%u\n", sector_map_idx)); status = VdkReadFileAt( file_info->FileHandle, (INT64)file_info->prm.vmdk->PrimaryDirectory[sector_map_idx] << VDK_BYTE_SHIFT_TO_SECTOR, file_info->prm.vmdk->GrainTable, file_info->prm.vmdk->GrainTableSize * sizeof(ULONG), NULL); if (!VDKSUCCESS(status)) { return status; } file_info->prm.vmdk->GrainTableIdx = sector_map_idx; } // // Find grain offset // sector_map_idx = (read_offset % file_info->prm.vmdk->SectorsPerTable) / file_info->prm.vmdk->SectorsPerGrain; if (sector_map_idx >= file_info->prm.vmdk->GrainTableSize) { // // offset exceeds the grain table size // Probably VMDK header is corrupt and inconsistent // VDKTRACE(VDKREAD | VDKWARN, ("[VDK] Grain Table overflow\n")); file_info = NULL; break; } if (file_info->prm.vmdk->GrainTable[sector_map_idx] && file_info->prm.vmdk->GrainTable[sector_map_idx] < file_info->EndOfFile) { // // Target sector is allocated in this file // break; } else if (file_info->prm.vmdk->GrainTable[sector_map_idx] >= file_info->EndOfFile) { // // Grain offset exceeds current end of file // VDKTRACE(VDKREAD | VDKWARN, ("[VDK] Grain offset too large\n")); file_info = NULL; break; } // // Grain is not allocated // } // // Look for the first file of the next generation // while (++file_info < no_more_file) { if (file_info->StartSector == 0) { // // Found it // break; } } if (file_info == no_more_file) { // // No more generation // file_info = NULL; VDKTRACE(VDKREAD | VDKINFO, ("[VDK] No more parent.\n")); break; } // // look for a file containing the target sector // read_offset = Offset; while (read_offset >= file_info->Capacity) { // // data is stored past this file // read_offset -= file_info->Capacity; file_info++; } VDKTRACE(VDKREAD | VDKINFO, ("[VDK] Checking file #%u.\n", file_info - DiskInfo->Files)); } // for (;;) // // How many sectors can be read at once? // read_offset %= read_length; read_length -= read_offset; if (read_length > Length) { read_length = Length; } // // If the Target sector is not allocated on any file. // Pretend it to be filled with zero. // if (file_info == NULL || file_info->FileType == VDK_FILETYPE_NONE) { VDKTRACE(VDKREAD | VDKINFO, ("[VDK] Sector not present. %u sectors filled with Zero.\n", read_length)); VdkZeroMem(Buffer, read_length << VDK_BYTE_SHIFT_TO_SECTOR); goto next_block; } // // Get the actual sector offset in the file // if (file_info->FileType == VDK_FILETYPE_FLAT) { read_offset += file_info->prm.SolidBackOffset; } if (file_info->FileType == VDK_FILETYPE_COWD) { read_offset += file_info->prm.cowd->SecondaryMap[sector_map_idx]; } else if (file_info->FileType == VDK_FILETYPE_VMDK) { read_offset += file_info->prm.vmdk->GrainTable[sector_map_idx]; } // // Check if whole sector range is acturally presend in this file // actual_length = read_length; if (read_offset + read_length > file_info->EndOfFile) { if (read_offset > file_info->EndOfFile) { // // Offset is too large // actual_length = 0; VDKTRACE(VDKREAD | VDKWARN, ("[VDK] Invalid Offset 0x%lu\n", read_offset)); } else { // // Length is too large. Data is clipped. // actual_length = file_info->EndOfFile - read_offset; VDKTRACE(VDKREAD | VDKWARN, ("[VDK] Only %u sectors can be read\n", actual_length)); } VdkZeroMem( Buffer + (actual_length << VDK_BYTE_SHIFT_TO_SECTOR), (read_length - actual_length) << VDK_BYTE_SHIFT_TO_SECTOR); } if (!actual_length) { goto next_block; } // // Now read // VDKTRACE(VDKREAD | VDKINFO, ("[VDK] Reading %u sectors from file #%u, byte offset 0x%"INT64_PRINT_FORMAT"x\n", actual_length, file_info - DiskInfo->Files, (INT64)read_offset << VDK_BYTE_SHIFT_TO_SECTOR)); status = VdkReadFileAt( file_info->FileHandle, (INT64)read_offset << VDK_BYTE_SHIFT_TO_SECTOR, Buffer, actual_length << VDK_BYTE_SHIFT_TO_SECTOR, NULL); if (!VDKSUCCESS(status)) { return status; }next_block: // // Prepare for the following data // Buffer += (read_length << VDK_BYTE_SHIFT_TO_SECTOR); Offset += read_length; Length -= read_length; top_level_offset += read_length; } // // Reading successfull // return VDK_OK;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -