www.pudn.com > vdksrc.zip > vdkpart.c
/*
vdkpart.c
Read partition table from virtual disk
Copyright (C) 2003 Ken Kato
*/
#include "vdkbase.h"
#include "vdkutil.h"
#include "vdkaccess.h"
#include "vdkpart.h"
//
// Decide file system type from sector data
//
UCHAR VdkIdentifyFAT(
PFAT16_PBR Pbr,
PPARTITION_ITEM PartItem)
{
if (Pbr->signature == SIGNATURE_WORD &&
(Pbr->bpb.BytesPerSector == 512 ||
Pbr->bpb.BytesPerSector == 1024 ||
Pbr->bpb.BytesPerSector == 2048 ||
Pbr->bpb.BytesPerSector == 4096) &&
(Pbr->bpb.SectorsPerCluster == 1 ||
Pbr->bpb.SectorsPerCluster == 2 ||
Pbr->bpb.SectorsPerCluster == 4 ||
Pbr->bpb.SectorsPerCluster == 8 ||
Pbr->bpb.SectorsPerCluster == 16 ||
Pbr->bpb.SectorsPerCluster == 32 ||
Pbr->bpb.SectorsPerCluster == 64 ||
Pbr->bpb.SectorsPerCluster == 128) &&
Pbr->bpb.MediaDescriptor) {
if (Pbr->bpb.NumberOfFATs == 0 &&
Pbr->bpb.RootEntries == 0 &&
Pbr->bpb.SmallSectors == 0 &&
Pbr->bpb.SectorsPerFAT == 0 &&
Pbr->bpb.LargeSectors == 0) {
//
// could be NTFS
//
if (VdkCmpNoCaseN(Pbr->oemid, "OS2", 3) == 0) {
//
// OS/2 filesystem
//
if (VdkCmpNoCaseN(Pbr->exbpb.FileSystemType, "HPFS", 4) == 0) {
strncpy(PartItem->fsname, "OS2 HPFS", MAX_FSNAME_LEN);
}
else {
strncpy(PartItem->fsname, "OS2 IFS", MAX_FSNAME_LEN);
}
}
else if (VdkCmpNoCaseN(Pbr->oemid, "NTFS", 4) == 0) {
//
// NTFS
//
strncpy(PartItem->fsname, "NTFS", MAX_FSNAME_LEN);
}
return PART_NTFS_HPFS;
}
else if (Pbr->bpb.NumberOfFATs == 2) {
//
// FAT12/16/32
//
if (Pbr->bpb.RootEntries == 0 &&
Pbr->bpb.SmallSectors == 0 &&
Pbr->bpb.SectorsPerFAT == 0 &&
Pbr->bpb.LargeSectors) {
//
// FAT32
//
strcpy(PartItem->fsname, "FAT32");
strncpy(
PartItem->label,
((PFAT32_PBR)Pbr)->exbpb.VolumeLabel,
sizeof(((PFAT32_PBR)Pbr)->exbpb.VolumeLabel));
return PART_DOS_FAT32;
}
else if (Pbr->bpb.RootEntries &&
Pbr->bpb.SectorsPerFAT &&
((Pbr->bpb.SmallSectors == 0 && Pbr->bpb.LargeSectors) ||
(Pbr->bpb.SmallSectors && Pbr->bpb.LargeSectors == 0))) {
//
// FAT12 or FAT16
//
if (!strncmp(Pbr->exbpb.FileSystemType, "FAT", 3)) {
strncpy(
PartItem->fsname,
Pbr->exbpb.FileSystemType,
sizeof(Pbr->exbpb.FileSystemType));
}
else {
strcpy(PartItem->fsname, "FAT16");
}
strncpy(
PartItem->label,
Pbr->exbpb.VolumeLabel,
sizeof(Pbr->exbpb.VolumeLabel));
if (Pbr->bpb.LargeSectors) {
return PART_DOS_HUGE;
}
else if (Pbr->bpb.SmallSectors >= MIN_FAT16_VOLUME) {
return PART_DOS_FAT16;
}
else {
return PART_DOS_FAT12;
}
}
}
}
return PART_NONE;
}
UCHAR VdkIdentifyXFS(
PXFS_SB Xfsb,
PPARTITION_ITEM PartItem)
{
if (!strncmp(Xfsb->s_magic, XFS_SUPER_MAGIC, sizeof(Xfsb->s_magic))) {
strncpy(PartItem->fsname, "xfs", MAX_FSNAME_LEN);
strncpy(
PartItem->label,
Xfsb->s_fname,
sizeof(Xfsb->s_fname));
return PART_LINUX;
}
return PART_NONE;
}
UCHAR VdkIdentifyEXT2(
PEXT2_SB e2fsb,
PPARTITION_ITEM PartItem)
{
if (e2fsb->s_magic == EXT2_SUPER_MAGIC) {
if (e2fsb->s_feature & EXT3_HAS_JOURNAL) {
strncpy(PartItem->fsname, "ext3fs", MAX_FSNAME_LEN);
}
else {
strncpy(PartItem->fsname, "ext2fs", MAX_FSNAME_LEN);
}
strncpy(
PartItem->label,
e2fsb->s_volume_name,
sizeof(e2fsb->s_volume_name));
return PART_LINUX;
}
return PART_NONE;
}
UCHAR VdkIdentifyRFS(
PREISER_SB rfsb,
PPARTITION_ITEM PartItem)
{
if (!strncmp(rfsb->s_magic, REISERFS_SUPER_MAGIC, strlen(REISERFS_SUPER_MAGIC)) ||
!strncmp(rfsb->s_magic, REISER2FS_SUPER_MAGIC, strlen(REISER2FS_SUPER_MAGIC))) {
strncpy(PartItem->fsname, "reiserfs", MAX_FSNAME_LEN);
return PART_LINUX;
}
return PART_NONE;
}
UCHAR VdkIdentifyFS(
PVDK_DISK_INFO DiskInfo,
HANDLE hFile,
PPARTITION_ITEM PartItem)
{
UCHAR buf[1024];
UCHAR type;
VDKSTAT ret;
//
// Read partition boot record
//
if (DiskInfo) {
ret = VdkReadSector(
DiskInfo,
PartItem->offset,
1,
buf);
}
else {
ret = VdkReadFileAt(
hFile,
(INT64)PartItem->offset << VDK_BYTE_SHIFT_TO_SECTOR,
buf,
VDK_BYTES_PER_SECTOR,
NULL);
}
if (ret != VDK_OK) {
return PART_NONE;
}
type = VdkIdentifyFAT((PFAT16_PBR)buf, PartItem);
if (type != PART_NONE) {
return type;
}
type = VdkIdentifyXFS((PXFS_SB)buf, PartItem);
if (type != PART_NONE) {
return type;
}
if (DiskInfo) {
ret = VdkReadSector(
DiskInfo,
PartItem->offset + 2,
1,
buf);
}
else {
ret = VdkReadFileAt(
hFile,
(INT64)(PartItem->offset + 2) << VDK_BYTE_SHIFT_TO_SECTOR,
buf,
VDK_BYTES_PER_SECTOR,
NULL);
}
if (ret != VDK_OK) {
return PART_NONE;
}
type = VdkIdentifyEXT2((PEXT2_SB)buf, PartItem);
if (type != PART_NONE) {
return type;
}
if (DiskInfo) {
ret = VdkReadSector(
DiskInfo,
PartItem->offset + REISERFS_SUPER_OFFSET,
1,
buf);
}
else {
ret = VdkReadFileAt(
hFile,
(INT64)(PartItem->offset + REISERFS_SUPER_OFFSET) << VDK_BYTE_SHIFT_TO_SECTOR,
buf,
VDK_BYTES_PER_SECTOR,
NULL);
}
if (ret != VDK_OK) {
return PART_NONE;
}
type = VdkIdentifyRFS((PREISER_SB)buf, PartItem);
return type;
}
//
// Read partition table and build partition list
//
VDKSTAT VdkListPartitions(
PVDK_DISK_INFO DiskInfo,
HANDLE hFile,
ULONG Capacity,
PLIST_CALLBACK CallBack,
PVOID Param)
{
PARTITION_TABLE ptable;
PPARTITION_ENTRY pentry;
PARTITION_ITEM pitem;
ULONG ext_offset;
int logical_num;
int logical_offset;
VDKSTAT ret;
int idx;
//
// Read master boot record
//
if (DiskInfo) {
Capacity = DiskInfo->Capacity;
ret = VdkReadSector(
DiskInfo,
0,
1,
(PUCHAR)&ptable);
}
else {
ret = VdkReadFileAt(
hFile,
0,
&ptable,
VDK_BYTES_PER_SECTOR,
NULL);
}
if (ret != VDK_OK) {
return ret;
}
//
// Check if the MBR contains a valid partition table
//
idx = 0;
if (ptable.p.signature == SIGNATURE_WORD) {
do {
pentry = &(ptable.p.partition[idx]);
if (pentry->type) {
ULONG start, end;
start = pentry->start_head * (pentry->start_sec & 0x3f) *
(((pentry->start_sec & 0xc0) << 8) + pentry->start_cyl);
end = pentry->end_head * (pentry->end_sec & 0x3f) *
(((pentry->end_sec & 0xc0) << 8) + pentry->end_cyl);
if (end <= start ||
pentry->lba_start >= Capacity ||
pentry->lba_length > Capacity ||
pentry->lba_start + pentry->lba_length > Capacity) {
break;
}
}
}
while (++idx < 4);
}
VdkZeroMem(&pitem, sizeof(pitem));
pitem.length = Capacity;
strcpy(pitem.fsname, "");
if (idx < 4) {
pitem.type = VdkIdentifyFS(DiskInfo, hFile, &pitem);
(*CallBack)(&pitem, Param);
return VDK_OK;
}
//
// callback for disk itself
//
(*CallBack)(&pitem, Param);
//
// Process primary partitions
//
ext_offset = 0;
for (idx = 0; idx < 4; idx++) {
pentry = &(ptable.p.partition[idx]);
if (pentry->type) {
if (IS_EXTENDED(pentry->type)) {
ext_offset = pentry->lba_start;
}
else {
pitem.idx++;
pitem.num = idx + 1;
pitem.type = pentry->type;
pitem.offset = pentry->lba_start;
pitem.length = pentry->lba_length;
pitem.fsname[0] = '\0';
pitem.label[0] = '\0';
VdkIdentifyFS(DiskInfo, hFile, &pitem);
(*CallBack)(&pitem, Param);
}
}
}
if (!ext_offset) {
return VDK_OK;
}
//
// Process extended partitions
//
logical_offset = 0;
logical_num = 5;
for (;;) {
//
// Read extended partition PBR
//
if (DiskInfo) {
ret = VdkReadSector(
DiskInfo,
ext_offset + logical_offset,
1,
(PUCHAR)&ptable);
}
else {
ret = VdkReadFileAt(
hFile,
(INT64)(ext_offset + logical_offset) << VDK_BYTE_SHIFT_TO_SECTOR,
&ptable,
VDK_BYTES_PER_SECTOR,
NULL);
}
if (ret != VDK_OK) {
return ret;
}
if (ptable.p.signature != SIGNATURE_WORD) {
return VDK_DATA;
}
//
// Process logical partition
//
for (idx = 0; idx < 4; idx++) {
pentry = &(ptable.p.partition[idx]);
if (pentry->type && !IS_EXTENDED(pentry->type)) {
pitem.idx++;
pitem.num = logical_num++;
pitem.type = pentry->type;
pitem.offset = pentry->lba_start + ext_offset + logical_offset;
pitem.length = pentry->lba_length;
pitem.fsname[0] = '\0';
pitem.label[0] = '\0';
VdkIdentifyFS(DiskInfo, hFile, &pitem);
(*CallBack)(&pitem, Param);
break;
}
}
//
// Search next extended partition
//
for (idx = 0; idx < 4; idx++) {
if (IS_EXTENDED(ptable.p.partition[idx].type)) {
logical_offset = ptable.p.partition[idx].lba_start;
break;
}
}
if (idx >= 4) {
// No more extended partition
break;
}
}
return VDK_OK;
}
static const struct _PARTITION_NAME {
ULONG type;
PCHAR name;
}
p_names[] = {
{ 0x00, "(none)" },
{ 0x01, "FAT12" },
{ 0x02, "XENIX root" },
{ 0x03, "XENIX /usr" },
{ 0x04, "FAT16" },
{ 0x05, "Extended" },
{ 0x06, "FAT16 HUGE" },
{ 0x07, "HPFS/NTFS" },
{ 0x08, "AIX boot" },
{ 0x09, "AIX data" },
{ 0x0a, "OS/2 Boot Manager" },
{ 0x0b, "FAT32" },
{ 0x0c, "FAT32 LBA" },
{ 0x0e, "FAT16 LBA" },
{ 0x0f, "Extended LBA" },
{ 0x10, "OPUS" },
{ 0x11, "FAT12 hidden" },
{ 0x12, "Compaq Diag" },
{ 0x13, "B-right/V" },
{ 0x14, "FAT16 hidden" },
{ 0x16, "FAT16 HUGE hidden" },
{ 0x17, "HPFS/NTFS hidden" },
{ 0x18, "AST SmartSleep" },
{ 0x19, "Willowtech" },
{ 0x1b, "FAT32 hidden" },
{ 0x1c, "FAT32 LBA hidden" },
{ 0x1e, "FAT16 LBA hidden" },
{ 0x20, "Willowsoft OFS1" },
{ 0x21, "FSo2" },
{ 0x24, "NEC DOS 3.x" },
{ 0x38, "Theos" },
{ 0x39, "Plan 9" },
{ 0x3c, "PartitionMagic" },
{ 0x40, "Venix 80286" },
{ 0x41, "PPC PReP boot" },
{ 0x42, "Dynamic Disk" },
{ 0x45, "EUMEL/Elan" },
{ 0x46, "EUMEL/Elan" },
{ 0x47, "EUMEL/Elan" },
{ 0x48, "EUMEL/Elan" },
{ 0x4d, "QNX4.x" },
{ 0x4e, "QNX4.x 2nd" },
{ 0x4f, "QNX4.x 3rd" },
{ 0x50, "OnTrack DM" },
{ 0x51, "OnTrack DM" },
{ 0x52, "CP/M" },
{ 0x53, "OnTrack DM" },
{ 0x54, "OnTrack DM" },
{ 0x55, "EZ-Drive" },
{ 0x56, "GoldenBow" },
{ 0x5c, "Priam Edisk" },
{ 0x61, "SpeedStor" },
{ 0x63, "GNU HURD" },
{ 0x64, "Netware 286" },
{ 0x65, "Netware 386" },
{ 0x70, "DiskSecure" },
{ 0x75, "PC/IX" },
{ 0x7e, "F.I.X." },
{ 0x80, "Old Minix" },
{ 0x81, "Minix/Old Linux" },
{ 0x82, "Linux swap" },
{ 0x83, "Linux" },
{ 0x84, "NTFT FAT16" },
{ 0x85, "Linux Extended" },
{ 0x86, "NTFT FAT16 HUGE" },
{ 0x87, "NTFT NTFS" },
{ 0x8b, "NTFT FAT32" },
{ 0x8c, "NTFT FAT32X" },
{ 0x8e, "NTFT FAT16X" },
{ 0x93, "Amoeba" },
{ 0x94, "Amoeba BBT" },
{ 0x99, "Mylex EISA SCSI" },
{ 0x9f, "BSD/OS" },
{ 0xa0, "Suspend" },
{ 0xa5, "FreeBSD" },
{ 0xa6, "OpenBSD" },
{ 0xa7, "NeXTSTEP" },
{ 0xa9, "NetBSD" },
{ 0xb7, "BSDI fs" },
{ 0xb8, "BSDI swap" },
{ 0xbb, "Boot Wizard (hid)" },
{ 0xbe, "Solaris boot" },
{ 0xc0, "Novell DOS/sec" },
{ 0xc1, "DRDOS FAT12" },
{ 0xc4, "DRDOS FAT16" },
{ 0xc6, "DRDOS FAT16 HUGE" },
{ 0xc7, "Syrinx" },
{ 0xcb, "DRDOS FAT32" },
{ 0xcc, "DRDOS FAT32X" },
{ 0xce, "DRDOS FAT16X" },
{ 0xd0, "MDOS FAT12" },
{ 0xd1, "MDOS FAT12" },
{ 0xd4, "MDOS FAT16" },
{ 0xd5, "MDOS Extended" },
{ 0xd6, "MDOS FAT16 HUGE" },
{ 0xd8, "CP/M" },
{ 0xda, "Non-FS data" },
{ 0xdb, "CP/M" },
{ 0xde, "Dell Utility" },
{ 0xdf, "BootIt" },
{ 0xe1, "DOS access" },
{ 0xe2, "DOS R/O" },
{ 0xe3, "DOS R/O" },
{ 0xe4, "SpeedStor" },
{ 0xeb, "BeOS BFS" },
{ 0xee, "EFI GPT" },
{ 0xef, "EFI FAT" },
{ 0xf0, "PA-RISC boot" },
{ 0xf1, "SpeedStor" },
{ 0xf2, "DOS secondary" },
{ 0xf4, "SpeedStor" },
{ 0xf5, "Prologue" },
{ 0xfd, "Linux RAID" },
{ 0xfe, "LANstep" },
{ 0xff, "Xenix BBT" },
{ 0, 0 }
};
const PCHAR GetPartitionTypeName(ULONG type)
{
const struct _PARTITION_NAME *p = p_names;
while (p->name && p->type != type) {
p++;
}
return p->name;
}
#ifdef _WIN32
//
// Decide if a partition is mountable or not
// NTFT partitions are not mountable because
// VDK driver does not communicate with the
// Windows Mount Manager
//
BOOL IsPartitionMountable(ULONG type, BOOL read_only)
{
switch (type) {
case 0x01: // DOS FAT12
case 0x04: // DOS FAT16
case 0x06: // DOS FAT16 HUGE
case 0x0e: // DOS FAT16X
return TRUE;
case 0x07: // HPFS, NTFS
if (read_only) {
OSVERSIONINFO os = { sizeof(os) };
if (GetVersionEx(&os)) {
if (os.dwPlatformId == VER_PLATFORM_WIN32_NT &&
os.dwMajorVersion >= 5 &&
os.dwMinorVersion >= 1) {
// XP and later can mount NTFS read-only.
return TRUE;
}
}
return FALSE;
}
else {
return TRUE;
}
case 0x0b: // DOS FAT32
case 0x0c: // DOS FAT32X
// Windows NT 4.0 usually cannot mount FAT32 partition
return ((GetVersion() & 0xFF) >= 5);
default:
return FALSE;
}
}
#endif // _WIN32