#include "stdafx.h" #include "mountmgr.h" /* global management information */ BOOL g_bAutoMount = 0; ULONG g_nFlps = 0; ULONG g_nDisks = 0; ULONG g_nCdroms = 0; ULONG g_nVols = 0; EXT2_LETTER drvLetters[26]; EXT2_LETTER drvDigits[10]; ULONGLONG Ext2DrvLetters[2] = {-1, -1}; PEXT2_DISK gDisks = NULL; PEXT2_CDROM gCdroms = NULL; PEXT2_VOLUME gVols = NULL; /* information string array */ typedef struct { int PartitionType; char *type; } PARTITION_LIST; typedef struct { UINT DriveType; char *type; } DRIVE_LIST; typedef struct { DEVICE_TYPE DeviceType; char *type; } DEVICE_LIST; typedef struct { STORAGE_BUS_TYPE BusType; char *type; } BUSTYPE_LIST; CHAR * IrpMjStrings[] = { "IRP_MJ_CREATE", "IRP_MJ_CREATE_NAMED_PIPE", "IRP_MJ_CLOSE", "IRP_MJ_READ", "IRP_MJ_WRITE", "IRP_MJ_QUERY_INFORMATION", "IRP_MJ_SET_INFORMATION", "IRP_MJ_QUERY_EA", "IRP_MJ_SET_EA", "IRP_MJ_FLUSH_BUFFERS", "IRP_MJ_QUERY_VOLUME_INFORMATION", "IRP_MJ_SET_VOLUME_INFORMATION", "IRP_MJ_DIRECTORY_CONTROL", "IRP_MJ_FILE_SYSTEM_CONTROL", "IRP_MJ_DEVICE_CONTROL", "IRP_MJ_INTERNAL_DEVICE_CONTROL", "IRP_MJ_SHUTDOWN", "IRP_MJ_LOCK_CONTROL", "IRP_MJ_CLEANUP", "IRP_MJ_CREATE_MAILSLOT", "IRP_MJ_QUERY_SECURITY", "IRP_MJ_SET_SECURITY", "IRP_MJ_POWER", "IRP_MJ_SYSTEM_CONTROL", "IRP_MJ_DEVICE_CHANGE", "IRP_MJ_QUERY_QUOTA", "IRP_MJ_SET_QUOTA", "IRP_MJ_PNP" }; CHAR * PerfStatStrings[] = { "IRP_CONTEXT", "VCB", "FCB", "CCB", "MCB", "EXTENT", "RW_CONTEXT", "VPB", "FCB_NAME", "MCB_NAME", "FILE_NAME", "DIR_ENTRY", "DIR_PATTERN", "DISK_EVENT", "DISK_BUFFER", "BLOCK_DATA", "inode", "dentry", "buffer head", NULL }; PARTITION_LIST PartitionList[] = { {PARTITION_ENTRY_UNUSED , "Empty"}, {PARTITION_FAT_12 , "FAT12"}, /* 01 */ {PARTITION_XENIX_1 , "Xenix-1"}, /* 02 */ {PARTITION_XENIX_2 , "Xenix-2"}, {PARTITION_FAT_16 , "FAT16"}, /* 04 */ {PARTITION_EXTENDED , "Extended"}, {PARTITION_HUGE , "FAT16 HUGE"}, /* 06*/ {PARTITION_IFS , "HPFS/NTFS"}, /* 07 */ {PARTITION_OS2BOOTMGR, "OS/2"}, /* 0A */ {PARTITION_FAT32 , "FAT32"}, /* 0B */ {PARTITION_FAT32_XINT13 , "FAT32X"}, /* 0C*/ {PARTITION_XINT13 , "XINT13"}, /* 0E */ {PARTITION_XINT13_EXTENDED ,"EXINT13"}, /* 0F */ {0x11 , "Hidden FAT12"}, {0x14 , "Hidden FAT16"}, {0x16 , "Hidden FAT16"}, {0x17 , "Hidden HPFS/NTFS"}, {0x1B , "Hidden FAT32"}, {0x1C , "Hidden FAT32X"}, {PARTITION_PREP , "OS/2"}, /* 41 */ {PARTITION_LDM , "LDM"}, /* 42 */ {0x52 , "CP/M"}, {PARTITION_UNIX , "UNIX"}, /* 63 */ {PARTITION_NTFT , "NTFT"}, /* 80 */ {0x81, "Minix"}, {0x82, "Linux swap"}, {0x83, "Linux"}, {0x85, "Linux extend"}, {0x8e, "Linux LVM"}, {0xa5, "FreeBSD"}, {0xa6, "OpenBSD"}, {0xa8, "Darwin UFS"}, {0xa9, "NetBSD"}, {0xbe, "Solaris Boot"}, {0xbf, "Solaris"}, {VALID_NTFT , "VNTFT"}, /* C0 */ {-1 ,"UNKNOWN"} }; DRIVE_LIST DriveList[] = { {DRIVE_UNKNOWN, "Unkown"}, {DRIVE_NO_ROOT_DIR, "NoRoot"}, {DRIVE_REMOVABLE, "Removable"}, {DRIVE_FIXED, "Fixed"}, {DRIVE_REMOTE, "Remote"}, {DRIVE_CDROM, "CDROM"}, {DRIVE_RAMDISK, "RAMdisk"}, {(UINT)-1, "Invalid"} }; BUSTYPE_LIST BusTypeList[] = { {BusTypeUnknown, "Unkown"}, {BusTypeScsi, "SCSI"}, {BusTypeAtapi, "ATAPI"}, {BusTypeAta, "ATA"}, {BusType1394, "1394"}, {BusTypeSsa, "Ssa"}, {BusTypeFibre, "Fibre"}, {BusTypeUsb, "USB"}, {BusTypeRAID, "RAID"}, {(STORAGE_BUS_TYPE)-1, "Invalid"} }; DEVICE_LIST DeviceList[] = { {FILE_DEVICE_8042_PORT ,"8042_PORT"}, {FILE_DEVICE_ACPI ,"ACPI"}, {FILE_DEVICE_BATTERY ,"BATTERY"}, {FILE_DEVICE_BEEP ,"BEEP"}, {FILE_DEVICE_BUS_EXTENDER ,"BUS_EXTENDER"}, {FILE_DEVICE_CD_ROM ,"CD_ROM"}, {FILE_DEVICE_CD_ROM_FILE_SYSTEM ,"CD_ROM_FILE_SYSTEM"}, {FILE_DEVICE_CHANGER ,"CHANGER"}, {FILE_DEVICE_CONTROLLER ,"CONTROLLER"}, {FILE_DEVICE_DATALINK ,"DATALINK"}, {FILE_DEVICE_DFS ,"DFS"}, {FILE_DEVICE_DFS_FILE_SYSTEM ,"DFS_FILE_SYSTEM"}, {FILE_DEVICE_DFS_VOLUME ,"DFS_VOLUME"}, {FILE_DEVICE_DISK ,"DISK"}, {FILE_DEVICE_DISK_FILE_SYSTEM ,"DISK_FILE_SYSTEM"}, {FILE_DEVICE_DVD ,"DVD"}, {FILE_DEVICE_FILE_SYSTEM ,"FILE_SYSTEM"}, {0x0000003a /*FILE_DEVICE_FIPS*/ ,"FIPS"}, {FILE_DEVICE_FULLSCREEN_VIDEO ,"FULLSCREEN_VIDEO"}, {FILE_DEVICE_INPORT_PORT ,"INPORT_PORT"}, {FILE_DEVICE_KEYBOARD ,"KEYBOARD"}, {FILE_DEVICE_KS ,"KS"}, {FILE_DEVICE_KSEC ,"KSEC"}, {FILE_DEVICE_MAILSLOT ,"MAILSLOT"}, {FILE_DEVICE_MASS_STORAGE ,"MASS_STORAGE"}, {FILE_DEVICE_MIDI_IN ,"MIDI_IN"}, {FILE_DEVICE_MIDI_OUT ,"MIDI_OUT"}, {FILE_DEVICE_MODEM ,"MODEM"}, {FILE_DEVICE_MOUSE ,"MOUSE"}, {FILE_DEVICE_MULTI_UNC_PROVIDER ,"MULTI_UNC_PROVIDER"}, {FILE_DEVICE_NAMED_PIPE ,"NAMED_PIPE"}, {FILE_DEVICE_NETWORK ,"NETWORK"}, {FILE_DEVICE_NETWORK_BROWSER ,"NETWORK_BROWSER"}, {FILE_DEVICE_NETWORK_FILE_SYSTEM,"NETWORK_FILE_SYSTEM"}, {FILE_DEVICE_NETWORK_REDIRECTOR ,"NETWORK_REDIRECTOR"}, {FILE_DEVICE_NULL ,"NULL"}, {FILE_DEVICE_PARALLEL_PORT ,"PARALLEL_PORT"}, {FILE_DEVICE_PHYSICAL_NETCARD ,"PHYSICAL_NETCARD"}, {FILE_DEVICE_PRINTER ,"PRINTER"}, {FILE_DEVICE_SCANNER ,"SCANNER"}, {FILE_DEVICE_SCREEN ,"SCREEN"}, {FILE_DEVICE_SERENUM ,"SERENUM"}, {FILE_DEVICE_SERIAL_MOUSE_PORT ,"SERIAL_MOUSE_PORT"}, {FILE_DEVICE_SERIAL_PORT ,"SERIAL_PORT"}, {FILE_DEVICE_SMARTCARD ,"SMARTCARD"}, {FILE_DEVICE_SMB ,"SMB"}, {FILE_DEVICE_SOUND ,"SOUND"}, {FILE_DEVICE_STREAMS ,"STREAMS"}, {FILE_DEVICE_TAPE ,"TAPE"}, {FILE_DEVICE_TAPE_FILE_SYSTEM ,"TAPE_FILE_SYSTEM"}, {FILE_DEVICE_TERMSRV ,"TERMSRV"}, {FILE_DEVICE_TRANSPORT ,"TRANSPORT"}, {FILE_DEVICE_UNKNOWN ,"UNKNOWN"}, {FILE_DEVICE_VDM ,"VDM"}, {FILE_DEVICE_VIDEO ,"VIDEO"}, {FILE_DEVICE_VIRTUAL_DISK ,"VIRTUAL_DISK"}, {FILE_DEVICE_WAVE_IN ,"WAVE_IN"}, {FILE_DEVICE_WAVE_OUT ,"WAVE_OUT"}, {(DEVICE_TYPE)-1 ,"UNKNOWN"} }; char *PartitionString(int type) { PARTITION_LIST *p = PartitionList; while ( p->PartitionType != -1 ) { if ( type == p->PartitionType ) { return p->type; } p++; } return p->type; } char *DriveTypeString(UINT media) { DRIVE_LIST *p = DriveList; while ( p->DriveType != (UINT)-1 ) { if ( media == p->DriveType ) { return p->type; } p++; } return p->type; } char *DeviceTypeString(DEVICE_TYPE media) { DEVICE_LIST *p = DeviceList; while ( p->DeviceType != (DEVICE_TYPE)-1 ) { if ( media == p->DeviceType ) { return p->type; } p++; } return p->type; } char *BusTypeString(STORAGE_BUS_TYPE BusType) { BUSTYPE_LIST *p = BusTypeList; while ( p->BusType != (STORAGE_BUS_TYPE)-1 ) { if ( BusType == p->BusType ) { return p->type; } p++; } return p->type; } /* Ext2Fsd supported codepages */ CHAR * gCodepages[] = { "default", "cp936", "gb2312", "utf8", "cp1251", "cp1255", "cp437", "cp737", "cp775", "cp850", "cp852", "cp855", "cp857", "cp860", "cp861", "cp862", "cp863", "cp864", "cp865", "cp866", "cp869", "cp874", "tis-620", "cp932", "euc-jp", "sjis", "cp949", "euc-kr", "cp950", "big5", "iso8859-1", "iso8859-13", "iso8859-14", "iso8859-15", "iso8859-2", "iso8859-3", "iso8859-4", "iso8859-5", "iso8859-6", "iso8859-7", "iso8859-8", "iso8859-9", "koi8-r", "koi8-u", "koi8-ru", "cp1250", "acsii", NULL }; /* routines */ BOOL g_isWow64 = FALSE; BOOL g_isX64 = FALSE; #define PROCESSOR_ARCHITECTURE_AMD64 9 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); LPFN_ISWOW64PROCESS fnIsWow64Process = NULL; typedef void (WINAPI *LPFN_GETNATIVESYSINFO)( LPSYSTEM_INFO lpSystemInfo); LPFN_GETNATIVESYSINFO fnGetNativeSystemInfo = NULL; BOOL Ext2IsWow64() { if (NULL != fnIsWow64Process) { if (!fnIsWow64Process(GetCurrentProcess(), &g_isWow64)) { } } return g_isWow64; } BOOL Ext2IsX64System() { SYSTEM_INFO sysInfo; fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress( GetModuleHandle("kernel32"), "IsWow64Process"); fnGetNativeSystemInfo = (LPFN_GETNATIVESYSINFO)GetProcAddress( GetModuleHandle("kernel32"), "GetNativeSystemInfo"); if (fnGetNativeSystemInfo) { fnGetNativeSystemInfo(&sysInfo); if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 && Ext2IsWow64()) { g_isWow64 = TRUE; return TRUE; } } return FALSE; } BOOL IsVistaOrAbove() { OSVERSIONINFO OsVerInfo; OsVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (GetVersionEx(&OsVerInfo)) { if (OsVerInfo.dwMajorVersion == 6 && OsVerInfo.dwBuildNumber > 3790) return TRUE; if (OsVerInfo.dwMajorVersion > 6) return TRUE; } return FALSE; } BOOL CanDoLocalMount() { return !IsWindowsVistaOrGreater(); } BOOL IsWindows2000() { OSVERSIONINFO OsVer; memset(&OsVer, 0, sizeof(OsVer)); OsVer.dwOSVersionInfoSize = sizeof(OsVer); if (GetVersionEx(&OsVer)) { if (OsVer.dwPlatformId == VER_PLATFORM_WIN32_NT && OsVer.dwMajorVersion <= 5 && OsVer.dwMinorVersion == 0) { return TRUE; } } else { return TRUE; } return FALSE; } BOOL Ext2DismountVolume(CHAR *voldev) { HANDLE device; ULONG bytes; BOOL rc = FALSE; device = CreateFile(voldev, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (device == INVALID_HANDLE_VALUE) { goto errorout; } if (!DeviceIoControl(device, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bytes, NULL)) { } rc = DeviceIoControl(device, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &bytes, NULL); CloseHandle(device); errorout: return rc; } /* * Ext2LockVolume * Lock the volume ... * * ARGUMENTS: * VolumeHandle: Volume handle. * * RETURNS: * Success or Fail * * NOTES: * N/A */ NT::NTSTATUS Ext2LockVolume(HANDLE Handle) { NT::NTSTATUS status; NT::IO_STATUS_BLOCK ioSb; status = NT::ZwFsControlFile( Handle, NULL, NULL, NULL, &ioSb, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0); return status; } NT::NTSTATUS Ext2UnLockVolume(HANDLE Handle) { NT::NTSTATUS status; NT::IO_STATUS_BLOCK ioSb; status = NT::ZwFsControlFile( Handle, NULL, NULL, NULL, &ioSb, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0); return status; } NT::NTSTATUS Ext2DisMountVolume(HANDLE Handle) { NT::NTSTATUS status; NT::IO_STATUS_BLOCK ioSb; status = NT::ZwFsControlFile( Handle, NULL, NULL, NULL, &ioSb, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0); return status; } PDRIVE_LAYOUT_INFORMATION_EXT Ext2QueryDriveLayout( HANDLE Handle, PUCHAR NumOfParts ) { NT::IO_STATUS_BLOCK ioSb; NT::NTSTATUS status; PDRIVE_LAYOUT_INFORMATION_EXT driveLayout = NULL; ULONG dataSize = 512; ULONG retSize = 0; QueryDrive: status = STATUS_SUCCESS; driveLayout = (PDRIVE_LAYOUT_INFORMATION_EXT) malloc(dataSize); if(!driveLayout) { goto errorout; } memset(driveLayout, 0, dataSize); if (IsWindows2000()) { PDRIVE_LAYOUT_INFORMATION oldLayout = (PDRIVE_LAYOUT_INFORMATION ) malloc(dataSize); if (!oldLayout) { goto errorout; } status = NT::ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &ioSb, IOCTL_DISK_GET_DRIVE_LAYOUT, NULL, 0, (PVOID)oldLayout, dataSize ); if (NT_SUCCESS(status)) { ULONG newLayoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry); newLayoutSize += sizeof(PARTITION_INFORMATION_EX) * oldLayout->PartitionCount; if (dataSize >= newLayoutSize) { driveLayout->PartitionStyle = PARTITION_STYLE_MBR; driveLayout->PartitionCount = oldLayout->PartitionCount; driveLayout->Mbr.Signature = oldLayout->Signature; for (DWORD i=0; i < oldLayout->PartitionCount; i++) { driveLayout->PartitionEntry[i].PartitionStyle = PARTITION_STYLE_MBR; driveLayout->PartitionEntry[i].StartingOffset = oldLayout->PartitionEntry[i].StartingOffset; driveLayout->PartitionEntry[i].PartitionLength = oldLayout->PartitionEntry[i].PartitionLength; driveLayout->PartitionEntry[i].PartitionNumber = oldLayout->PartitionEntry[i].PartitionNumber; driveLayout->PartitionEntry[i].RewritePartition = oldLayout->PartitionEntry[i].RewritePartition; driveLayout->PartitionEntry[i].Mbr.PartitionType = oldLayout->PartitionEntry[i].PartitionType; driveLayout->PartitionEntry[i].Mbr.BootIndicator = oldLayout->PartitionEntry[i].BootIndicator; driveLayout->PartitionEntry[i].Mbr.RecognizedPartition = oldLayout->PartitionEntry[i].RecognizedPartition; driveLayout->PartitionEntry[i].Mbr.HiddenSectors = oldLayout->PartitionEntry[i].HiddenSectors; } } else { dataSize = newLayoutSize; status = STATUS_BUFFER_TOO_SMALL; } } free(oldLayout); } else { status = NT::ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &ioSb, IOCTL_DISK_GET_DRIVE_LAYOUT_EXT, NULL, 0, (PVOID)driveLayout, dataSize ); } if (status == STATUS_BUFFER_TOO_SMALL) { free(driveLayout); driveLayout = NULL; dataSize *= 2; goto QueryDrive; } if (!NT_SUCCESS(status)) { free(driveLayout); driveLayout = NULL; goto errorout; } retSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EXT, PartitionEntry); retSize += sizeof(PARTITION_INFORMATION) * driveLayout->PartitionCount; if (driveLayout->PartitionStyle == PARTITION_STYLE_MBR) { PPARTITION_INFORMATION_EXT Part; UCHAR i = 0, cnt = 0; /* Now walk the Drive_Layout to count the partitions */ while (i < (UCHAR)driveLayout->PartitionCount) { Part = &driveLayout->PartitionEntry[i++]; if (Part->Mbr.PartitionType != PARTITION_ENTRY_UNUSED && Part->Mbr.PartitionType != PARTITION_EXTENDED && Part->Mbr.PartitionType != PARTITION_XINT13_EXTENDED) { cnt++; } } *NumOfParts = cnt; } else if (driveLayout->PartitionStyle == PARTITION_STYLE_GPT) { *NumOfParts = (UCHAR)driveLayout->PartitionCount; } else { *NumOfParts = 0; free(driveLayout); driveLayout = NULL; } if (*NumOfParts == 0) { free(driveLayout); driveLayout = NULL; } errorout: return driveLayout; } NT::NTSTATUS Ext2SetDriveLayout( HANDLE Handle, PDRIVE_LAYOUT_INFORMATION_EXT Layout ) { NT::IO_STATUS_BLOCK ioSb; NT::NTSTATUS status = STATUS_SUCCESS; ULONG dataSize; dataSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EXT, PartitionEntry); dataSize += sizeof(PARTITION_INFORMATION_EXT) * Layout->PartitionCount; if (IsWindows2000()) { if (Layout->PartitionStyle != PARTITION_STYLE_MBR) { return STATUS_UNSUCCESSFUL; } ULONG newLayoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry); newLayoutSize += sizeof(PARTITION_INFORMATION) * Layout->PartitionCount; PDRIVE_LAYOUT_INFORMATION oldLayout = (PDRIVE_LAYOUT_INFORMATION ) malloc(newLayoutSize); if (!oldLayout) { goto errorout; } oldLayout->PartitionCount = Layout->PartitionCount; oldLayout->Signature = Layout->Mbr.Signature; for (DWORD i=0; i < oldLayout->PartitionCount; i++) { oldLayout->PartitionEntry[i].StartingOffset = Layout->PartitionEntry[i].StartingOffset; oldLayout->PartitionEntry[i].PartitionLength = Layout->PartitionEntry[i].PartitionLength; oldLayout->PartitionEntry[i].PartitionNumber = Layout->PartitionEntry[i].PartitionNumber; oldLayout->PartitionEntry[i].RewritePartition = Layout->PartitionEntry[i].RewritePartition; oldLayout->PartitionEntry[i].PartitionType = Layout->PartitionEntry[i].Mbr.PartitionType; oldLayout->PartitionEntry[i].BootIndicator = Layout->PartitionEntry[i].Mbr.BootIndicator; oldLayout->PartitionEntry[i].RecognizedPartition = Layout->PartitionEntry[i].Mbr.RecognizedPartition; oldLayout->PartitionEntry[i].HiddenSectors = Layout->PartitionEntry[i].Mbr.HiddenSectors; } status = NT::ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &ioSb, IOCTL_DISK_SET_DRIVE_LAYOUT, (PVOID)oldLayout, newLayoutSize, NULL, 0 ); free(oldLayout); } else { status = NT::ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &ioSb, IOCTL_DISK_SET_DRIVE_LAYOUT_EXT, (PVOID)Layout, dataSize,NULL, 0 ); } return status; errorout: return STATUS_UNSUCCESSFUL; } BOOL Ext2IsDeviceValid(CHAR *Device) { HANDLE handle = NULL; NT::NTSTATUS status; status = Ext2Open(Device, &handle, EXT2_DESIRED_ACCESS); if (!NT_SUCCESS(status)) { goto errorout; } errorout: if (handle) { Ext2Close(&handle); } return NT_SUCCESS(status); } BOOL Ext2SetPartitionType( PEXT2_PARTITION Part, BYTE Type ) { BOOL rc = FALSE; HANDLE Handle = NULL; NT::NTSTATUS status; UCHAR NumParts = 0; PDRIVE_LAYOUT_INFORMATION_EXT Layout = NULL; DWORD i; status = Ext2Open(Part->Disk->Name, &Handle, EXT2_DESIRED_ACCESS | GENERIC_WRITE); if (!NT_SUCCESS(status)) { goto errorout; } Layout = Part->Disk->Layout; if (!Layout) { goto errorout; } if (Layout->PartitionStyle != PARTITION_STYLE_MBR) { goto errorout; } for (i=0; i < Layout->PartitionCount; i++) { if ((Layout->PartitionEntry[i].StartingOffset.QuadPart == Part->Entry->StartingOffset.QuadPart) && (Layout->PartitionEntry[i].PartitionLength.QuadPart == Part->Entry->PartitionLength.QuadPart) && (Layout->PartitionEntry[i].PartitionNumber == Part->Entry->PartitionNumber) ) { Layout->PartitionEntry[i].Mbr.PartitionType = Type; Layout->PartitionEntry[i].RewritePartition = TRUE; rc = TRUE; break; } } if (!rc) { goto errorout; } status = Ext2SetDriveLayout(Handle, Layout); rc = NT_SUCCESS(status); errorout: Ext2Close(&Handle); return rc; } BOOL Ext2FlushVolume(CHAR *Device) { HANDLE handle = NULL; NT::NTSTATUS status; NT::IO_STATUS_BLOCK iosb; status = Ext2Open(Device, &handle, EXT2_DESIRED_ACCESS | GENERIC_WRITE); if (!NT_SUCCESS(status)) { goto errorout; } status = NT::ZwFlushBuffersFile(handle, &iosb); errorout: if (handle) { Ext2Close(&handle); } return NT_SUCCESS(status); } PEXT2_PARTITION Ext2QueryVolumePartition( PEXT2_VOLUME Volume ) { PEXT2_PARTITION Part = NULL; DWORD i, j; for (i=0; i < g_nDisks; i++) { for (j=0; j < (int)gDisks[i].NumParts; j++) { if (gDisks[i].DataParts[j].Volume == Volume) { Part = &gDisks[i].DataParts[j]; break; } } } return Part; } NT::NTSTATUS Ext2QueryProperty( HANDLE Handle, STORAGE_PROPERTY_ID Id, PVOID DescBuf, ULONG DescSize ) { STORAGE_PROPERTY_QUERY SPQ; NT::NTSTATUS status; NT::IO_STATUS_BLOCK ioSb; SPQ.PropertyId = Id; SPQ.QueryType = PropertyStandardQuery; memset(DescBuf, 0, DescSize); status = NT::ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &ioSb, IOCTL_STORAGE_QUERY_PROPERTY, &SPQ, sizeof(STORAGE_PROPERTY_QUERY), DescBuf, DescSize ); return status; } /* * Ext2QueryDisk * Get volume gemmetry information ... * * ARGUMENTS: * VolumeHandle: Volume handle. * * RETURNS: * Success or Fail * * NOTES: * N/A */ NT::NTSTATUS Ext2QueryDisk( HANDLE Handle, PDISK_GEOMETRY DiskGeometry ) { NT::NTSTATUS status; NT::IO_STATUS_BLOCK ioSb; status = NT::ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &ioSb, IOCTL_DISK_GET_DRIVE_GEOMETRY, DiskGeometry, sizeof(DISK_GEOMETRY), DiskGeometry, sizeof(DISK_GEOMETRY)); if (!NT_SUCCESS(status)) { goto errorout; } errorout: return status; } PVOLUME_DISK_EXTENTS Ext2QueryVolumeExtents(HANDLE hVolume) { ULONG dataSize = 1024; PVOLUME_DISK_EXTENTS dskExtents = NULL; NT::NTSTATUS status; NT::IO_STATUS_BLOCK ioSb; QueryExtent: dskExtents = (PVOLUME_DISK_EXTENTS)malloc(dataSize); if (NULL == dskExtents) { goto errorout; } status = NT::ZwDeviceIoControlFile( hVolume, NULL, NULL, NULL, &ioSb, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, dskExtents, dataSize ); if (status == STATUS_BUFFER_TOO_SMALL) { free(dskExtents); dskExtents = NULL; dataSize += 1024; goto QueryExtent; } if (!NT_SUCCESS(status)) { free(dskExtents); dskExtents = NULL; goto errorout; } errorout: return dskExtents; } PSTORAGE_DEVICE_NUMBER Ext2QueryDeviceNumber(HANDLE hVolume) { ULONG dataSize; PSTORAGE_DEVICE_NUMBER SDN = NULL; NT::NTSTATUS status; NT::IO_STATUS_BLOCK ioSb; dataSize = sizeof(STORAGE_DEVICE_NUMBER); QuerySDN: SDN = (PSTORAGE_DEVICE_NUMBER)malloc(dataSize); if (NULL == SDN) { goto errorout; } memset(SDN, 0, dataSize); status = NT::ZwDeviceIoControlFile( hVolume, NULL, NULL, NULL, &ioSb, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, SDN, dataSize ); if (status == STATUS_BUFFER_TOO_SMALL) { free(SDN); SDN = NULL; dataSize += sizeof(STORAGE_DEVICE_NUMBER); goto QuerySDN; } if (!NT_SUCCESS(status)) { free(SDN); SDN = NULL; goto errorout; } errorout: return SDN; } BOOL Ext2QueryDrvLetter( PEXT2_LETTER drvLetter ) { HANDLE hVolume; NT::NTSTATUS status = STATUS_SUCCESS; DWORD rc = 0; drvLetter->DrvType = Ext2QueryDrive(drvLetter->Letter, drvLetter->SymLink); if (drvLetter->DrvType == DRIVE_NO_ROOT_DIR) { drvLetter->bUsed = FALSE; goto errorout; } else { drvLetter->bUsed = TRUE; } if (drvLetter->Letter == 'A' || drvLetter->Letter == 'B' ) { drvLetter->bUsed = TRUE; goto errorout; } if (drvLetter->DrvType == DRIVE_REMOVABLE || drvLetter->DrvType == DRIVE_FIXED) { status = Ext2Open(drvLetter->SymLink, &hVolume, EXT2_DESIRED_ACCESS); if (!NT_SUCCESS(status) && status != STATUS_ACCESS_DENIED) { drvLetter->bInvalid = TRUE; goto errorout; } drvLetter->Extent = Ext2QueryVolumeExtents(hVolume); if (drvLetter->DrvType == DRIVE_REMOVABLE) { drvLetter->SDN = Ext2QueryDeviceNumber(hVolume); } Ext2Close(&hVolume); } errorout: return NT_SUCCESS(status); } PEXT2_LETTER Ext2GetFirstUnusedDrvLetter() { PEXT2_LETTER drvLetter = NULL; CHAR devPath[] = "C:"; int i; for (i = 5; i < 24; i++) { drvLetter = &drvLetters[i]; if (drvLetter->DrvType == DRIVE_NO_ROOT_DIR) { drvLetter->DrvType = Ext2QueryDrive(drvLetter->Letter, drvLetter->SymLink); if (drvLetter->DrvType == DRIVE_NO_ROOT_DIR) { /* we got it */ break; } else { /* we need do a new refresh */ } } drvLetter = NULL; } return drvLetter; } CHAR Ext2MountVolume(CHAR *voldev) { PEXT2_LETTER drvLetter; CHAR rc = 0; /* query drive letter to check whether it's mounted */ drvLetter = Ext2GetFirstUnusedDrvLetter(); if (!drvLetter) { goto errorout; } if (Ext2AssignDrvLetter(drvLetter, voldev, FALSE)) { rc = drvLetter->Letter; } errorout: return rc; } CHAR Ext2MountVolumeAs(CHAR *voldev, CHAR DrvLetter) { PEXT2_LETTER drvLetter; CHAR rc = 0; if (DrvLetter >= '0' && DrvLetter <= '9') { drvLetter = &drvDigits[DrvLetter - '0']; } else if (DrvLetter >= 'A' && DrvLetter <= 'Z') { drvLetter = &drvLetters[DrvLetter - 'A']; } else if (DrvLetter >= 'a' && DrvLetter <= 'z') { drvLetter = &drvLetters[DrvLetter - 'a']; } if (!drvLetter || drvLetter->bUsed) { goto errorout; } if (Ext2AssignDrvLetter(drvLetter, voldev, FALSE)) { rc = drvLetter->Letter; } errorout: return rc; } NT::NTSTATUS Ext2QueryMediaType( HANDLE Handle, PDWORD MediaType ) { NT::NTSTATUS status; NT::IO_STATUS_BLOCK ioSb; PGET_MEDIA_TYPES mediaTypes; UCHAR buffer[1024]; status = NT::ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &ioSb, IOCTL_STORAGE_GET_MEDIA_TYPES_EX, NULL, 0, buffer, 1024 ); if (!NT_SUCCESS(status)) { goto errorout; } mediaTypes = (PGET_MEDIA_TYPES) buffer; *MediaType = mediaTypes->DeviceType; errorout: return status; } /* * Ext2Read * Read data from disk or file ... * * ARGUMENTS: * VolumeHandle: Volume Handle * Offset : Disk Offset * Length : Data Length to be read * Buffer : ... * * RETURNS: * Success: STATUS_SUCCESS * Fail: ... * * NOTES: * Both Length and Offset should be SECTOR_SIZE aligned. */ NT::NTSTATUS Ext2Read( IN HANDLE Handle, IN BOOL IsFile, IN ULONG SectorSize, IN ULONGLONG Offset, IN ULONG Length, IN PVOID Buffer ) { NT::NTSTATUS status; NT::IO_STATUS_BLOCK ioSb; LARGE_INTEGER address; ULONG aLength = 0; PVOID aBuffer = NULL; if (SectorSize == 0 || SectorSize == 1) IsFile = TRUE; ASSERT(Buffer != NULL); if (IsFile) { address.QuadPart = Offset; status = NT::ZwReadFile( Handle, 0, NULL, NULL, &ioSb, Buffer, Length, &address, NULL ); } else { address.QuadPart = Offset & (~((ULONGLONG)SectorSize - 1)); aLength = (Length + SectorSize - 1)&(~(SectorSize - 1)); aLength += ((ULONG)(Offset - address.QuadPart) + SectorSize - 1) & (~(SectorSize - 1)); aBuffer = malloc(aLength); if (!aBuffer) { status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } status = NT::ZwReadFile( Handle, 0, NULL, NULL, &ioSb, aBuffer, aLength, &address, NULL ); if (!NT_SUCCESS(status)) { goto errorout; } memmove( Buffer, (PUCHAR)aBuffer + (ULONG)(Offset - address.QuadPart), Length); } errorout: if (aBuffer) free(aBuffer); return status; } /* * Ext2Write * Write data to disk or file ... * * ARGUMENTS: * VolumeHandle: Volume Handle * Offset : Disk Offset * Length : Data Length to be written * Buffer : Data to be written ... * * RETURNS: * Success: STATUS_SUCCESS * Fail: ... * * NOTES: * Both Length and Offset should be SECTOR_SIZE aligned. */ NT::NTSTATUS Ext2WriteDisk( HANDLE Handle, BOOL IsFile, ULONG SectorSize, ULONGLONG Offset, ULONG Length, PVOID Buffer ) { LARGE_INTEGER address; NT::NTSTATUS status; NT::IO_STATUS_BLOCK ioSb; ULONG aLength = 0; PVOID aBuffer = NULL; if (SectorSize == 0 || SectorSize == 1) IsFile = TRUE; ASSERT(Buffer != NULL); if (IsFile) { address.QuadPart = Offset; status = NT::ZwWriteFile( Handle, 0, NULL, NULL, &ioSb, Buffer, Length, &address, NULL ); } else { address.QuadPart = Offset & (~((ULONGLONG)SectorSize - 1)); aLength = (Length + SectorSize - 1)&(~(SectorSize - 1)); aLength += ((ULONG)(Offset - address.QuadPart) + SectorSize - 1) & (~(SectorSize - 1)); aBuffer = malloc(aLength); if (!aBuffer) { status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } if ( (aLength != Length) || (address.QuadPart != (LONGLONG)Offset)) { status = NT::ZwReadFile( Handle, 0, NULL, NULL, &ioSb, aBuffer, aLength, &address, NULL ); if (!NT_SUCCESS(status)) { goto errorout; } } memmove((PUCHAR)aBuffer + (ULONG)(Offset - address.QuadPart), Buffer, Length); status = NT::ZwWriteFile( Handle, 0, NULL, NULL, &ioSb, aBuffer, aLength, &address, NULL ); } errorout: if (aBuffer) free(aBuffer); return status; } NT::NTSTATUS Ext2Open( PCHAR FileName, PHANDLE Handle, ULONG DesiredAccess ) { NT::IO_STATUS_BLOCK iosb; NT::NTSTATUS status; NT::ANSI_STRING AnsiFilespec; NT::UNICODE_STRING UnicodeFilespec; NT::OBJECT_ATTRIBUTES ObjectAttributes; SHORT UnicodeName[MAX_PATH]; CHAR AnsiName[MAX_PATH]; USHORT NameLength = 0; memset(UnicodeName, 0, sizeof(SHORT) * MAX_PATH); memset(AnsiName, 0, sizeof(UCHAR) * MAX_PATH); NameLength = strlen(FileName); ASSERT(NameLength < MAX_PATH); if (FileName[0] == '\\') { memmove(AnsiName, FileName, NameLength); } else { memmove(&AnsiName[0], "\\DosDevices\\", 12); memmove(&AnsiName[12], FileName, NameLength); NameLength += 12; } AnsiFilespec.MaximumLength = AnsiFilespec.Length = NameLength; AnsiFilespec.Buffer = AnsiName; UnicodeFilespec.MaximumLength = MAX_PATH * 2; UnicodeFilespec.Length = 0; UnicodeFilespec.Buffer = (PWSTR)UnicodeName; NT::RtlAnsiStringToUnicodeString(&UnicodeFilespec, &AnsiFilespec, FALSE); // // Setup the name in an object attributes structure. // Note that we create a name that is case INsensitive // ObjectAttributes.Length = sizeof(NT::OBJECT_ATTRIBUTES); ObjectAttributes.RootDirectory = NULL; ObjectAttributes.Attributes = 0; /*OBJ_CASE_INSENSITIVE;*/ ObjectAttributes.ObjectName = &UnicodeFilespec; ObjectAttributes.SecurityDescriptor = NULL; ObjectAttributes.SecurityQualityOfService = NULL; // // Do the create. In this particular case, we'll have the I/O Manager // make our write requests syncrhonous for our convenience. // status = NT::ZwCreateFile( Handle, // returned file handle (DesiredAccess | SYNCHRONIZE), // desired access &ObjectAttributes, // ptr to object attributes &iosb, // ptr to I/O status block 0, // allocation size FILE_ATTRIBUTE_NORMAL, // file attributes FILE_SHARE_WRITE | FILE_SHARE_READ, // share access FILE_OPEN /*FILE_SUPERSEDE*/, // create disposition FILE_SYNCHRONOUS_IO_NONALERT | // create options ((DesiredAccess & GENERIC_WRITE) ? FILE_NO_INTERMEDIATE_BUFFERING : 0), NULL, // ptr to extended attributes 0); // length of ea buffer // // Check the system service status // if (!NT_SUCCESS(status)) { return status; } // // Check the returned status too... // if (!NT_SUCCESS(iosb.Status)) { return iosb.Status; } return status; } VOID Ext2Close(HANDLE * Handle) { NT::NTSTATUS status = 0; if (Handle != NULL && *Handle != 0 && *Handle != INVALID_HANDLE_VALUE) { status = NT::ZwClose(*Handle); if (NT_SUCCESS(status)) { *Handle = 0; } else { ::MessageBox(NULL, "Failed to close handle", "Ext2Close", MB_OK); } } } BOOL Ext2QuerySysConfig() { NT::NTSTATUS status; NT::_SYSTEM_CONFIGURATION_INFORMATION ConfigInfo; status = NT::ZwQuerySystemInformation( NT::SystemConfigurationInformation, &ConfigInfo, sizeof(ConfigInfo), 0); if (NT_SUCCESS(status)) { g_nDisks = ConfigInfo.DiskCount; g_nFlps = ConfigInfo.FloppyCount; g_nCdroms = ConfigInfo.CdRomCount; return TRUE; } return FALSE; } BOOL Ext2LoadDisks() { ULONG i = 0, j = 0; NT::NTSTATUS status; CHAR drvName[MAX_PATH]; if (g_nDisks == 0) { return FALSE; } gDisks = (PEXT2_DISK) malloc(sizeof(EXT2_DISK) * g_nDisks); if (gDisks == NULL) { return FALSE; } memset(gDisks, 0, sizeof(EXT2_DISK) * g_nDisks); while (i < g_nDisks && j < 256) { HANDLE Handle = NULL; gDisks[i].Magic = EXT2_DISK_MAGIC; gDisks[i].Null = EXT2_DISK_NULL_MAGIC; gDisks[i].OrderNo = (UCHAR) j; gDisks[i].bLoaded = FALSE; sprintf(drvName, "PhysicalDrive%d\0", j); if (QueryDosDevice(drvName, gDisks[i].Name, MAX_PATH) == 0) { sprintf(gDisks[i].Name, "\\DosDevices\\PhysicalDrive%d\0", j); } j++; status = Ext2Open(gDisks[i].Name, &Handle, EXT2_DESIRED_ACCESS); if (!NT_SUCCESS(status)) { continue; } status = Ext2QueryDisk(Handle, &gDisks[i].DiskGeometry); if (NT_SUCCESS(status)) { gDisks[i].bEjected = FALSE; } else { if (STATUS_NO_MEDIA_IN_DEVICE == status) { gDisks[i].bEjected = TRUE; } else { goto Next; } } status = Ext2QueryProperty( Handle, StorageDeviceProperty, (PVOID)&gDisks[i].SDD, sizeof(STORAGE_DEVICE_DESCRIPTOR) ); if (!NT_SUCCESS(status)) { goto Next; } status = Ext2QueryProperty( Handle, StorageAdapterProperty, (PVOID)&gDisks[i].SAD, sizeof(STORAGE_ADAPTER_DESCRIPTOR) ); if (!NT_SUCCESS(status)) { goto Next; } if (!gDisks[i].bEjected) { gDisks[i].Layout = Ext2QueryDriveLayout( Handle, &gDisks[i].NumParts); } gDisks[i].bLoaded = TRUE; Next: Ext2Close(&Handle); i++; } g_nDisks = i; return TRUE; } CString Ext2PartInformation(PEXT2_PARTITION part) { CString s, ret=""; s.Format("\r\n Partition No: %d\r\n\r\n", part->Number); if (!part->Entry) { return ret; } s = " Partition Type: "; if (part->Entry->PartitionStyle == PARTITION_STYLE_MBR) { s += PartitionString(part->Entry->Mbr.PartitionType); } else if (part->Entry->PartitionStyle == PARTITION_STYLE_GPT){ s += "GPT"; if (part->Entry->Gpt.Name && wcslen(part->Entry->Gpt.Name)) { s += ":"; for (size_t i = 0; i < wcslen(part->Entry->Gpt.Name); i++) s += (CHAR)part->Entry->Gpt.Name[i]; } } else { s += "GPT"; } ret += s; ret += "\r\n"; s.Format(" StartingOffset: %I64u\r\n", part->Entry->StartingOffset.QuadPart); ret += s; s.Format(" PartitionLength: %I64u\r\n", part->Entry->PartitionLength.QuadPart); ret += s; /* mount points */ ret += " MountPoints: "; ret += Ext2QueryVolumeLetterStrings(part->DrvLetters, NULL); ret += "\r\n"; if (!part->Volume) { return ret; } if (part->Volume->bRecognized) { ULONGLONG totalSize, freeSize; s.Format(" Filesystem: %s\r\n", part->Volume->FileSystem); ret += s; if ((part->Volume->EVP.bExt2 || part->Volume->EVP.bExt3)) { s = " codepage:"; s += part->Volume->EVP.Codepage; if (part->Volume->EVP.bReadonly) { s += ",Readonly"; } } ret += s; ret += "\r\n"; totalSize = part->Volume->FssInfo.TotalAllocationUnits.QuadPart; freeSize = part->Volume->FssInfo.AvailableAllocationUnits.QuadPart; totalSize = totalSize * part->Volume->FssInfo.BytesPerSector * part->Volume->FssInfo.SectorsPerAllocationUnit; freeSize = freeSize * part->Volume->FssInfo.BytesPerSector * part->Volume->FssInfo.SectorsPerAllocationUnit; s.Format(" Size: %I64u\r\n", totalSize); ret += s; s.Format(" Free: %I64u\r\n", freeSize); ret += s; } return ret; } CString Ext2DiskInformation(PEXT2_DISK disk) { CString s, ret=""; s.Format("\r\nDisk %d: %s\r\n\r\n", disk->OrderNo, disk->Name); ret += s; if (disk->SDD.VendorIdOffset) { ret += "\r\n VendorId: "; ret += (PCHAR)&disk->SDD + disk->SDD.VendorIdOffset; ret += "\r\n"; } if (disk->SDD.ProductIdOffset) { ret += " ProductId: "; ret += (PCHAR)&disk->SDD + disk->SDD.ProductIdOffset; ret += "\r\n"; } if (disk->SDD.SerialNumberOffset) { ret += " SerialNumber: "; ret += (PCHAR)&disk->SDD + disk->SDD.SerialNumberOffset; ret += "\r\n"; } ret += " BusType: "; ret += BusTypeString(disk->SDD.BusType); ret += "\r\n"; ret += " Media Type: "; if (disk->SDD.RemovableMedia) { ret += " Removable\r\n"; } else { s = "RAW"; if (disk->Layout) { if (disk->Layout->PartitionStyle == PARTITION_STYLE_MBR) { if (disk->Layout->PartitionEntry->Mbr.PartitionType == PARTITION_LDM) { s.LoadString(IDS_DISK_TYPE_DYN); } else { s.LoadString(IDS_DISK_TYPE_BASIC); } } else if (disk->Layout->PartitionStyle == PARTITION_STYLE_GPT) { s = "GPT"; } } s += "\r\n"; ret += s; } if (disk->bEjected) { ret += " No media\r\n"; } else { /* geometry information */ ret += " DiskGeometry Layout:\r\n"; s.Format(" BytesPerSector = %u\r\n", disk->DiskGeometry.BytesPerSector); ret += s; s.Format(" SectorsPerTrack = %u\r\n", disk->DiskGeometry.SectorsPerTrack); ret += s; s.Format(" TracksPerCylinder = %u\r\n", disk->DiskGeometry.TracksPerCylinder); ret += s; s.Format(" Cylinderst = %I64u\r\n", disk->DiskGeometry.Cylinders.QuadPart); ret += s; switch (disk->DiskGeometry.MediaType) { case FixedMedia: s="Fixed"; break; case RemovableMedia: s="Removable"; break; case CD_ROM: s="CDROM"; break; case CD_R: s="CDR"; break; case CD_RW: s="CDRW"; break; case DVD_ROM: s="DVD"; break; case DVD_R: s="DVDR"; break; case DVD_RW: s="DVDRW"; break; default: s="Unkown"; } ret += " MediaType: "; ret += s; ret += "\r\n"; } ret += "\r\n"; if (disk->Layout) { s.Format(" Partition Numbers: %d\r\n", disk->NumParts); ret += s; for (UCHAR i=0; i < disk->NumParts; i++) { ret += Ext2PartInformation(&disk->DataParts[i]); ret += "\r\n"; } } return ret; } CString Ext2CdromInformation(PEXT2_CDROM cdrom) { CString s, ret=""; s.Format("\r\nCdrom %d: %s\r\n\r\n", cdrom->OrderNo, cdrom->Name); ret += s; if (cdrom->SDD.VendorIdOffset) { ret += " VendorId: "; ret += (PCHAR)&cdrom->SDD + cdrom->SDD.VendorIdOffset; ret += "\r\n"; } if (cdrom->SDD.ProductIdOffset) { ret += " ProductId: "; ret += (PCHAR)&cdrom->SDD + cdrom->SDD.ProductIdOffset; ret += "\r\n"; } if (cdrom->SDD.SerialNumberOffset) { ret += " SerialNumber: "; ret += (PCHAR)&cdrom->SDD + cdrom->SDD.SerialNumberOffset; ret += "\r\n"; } ret += " BusType: "; ret += BusTypeString(cdrom->SDD.BusType); ret += "\r\n"; if (cdrom->bLoaded) { ret += " Media Type: "; if (cdrom->bIsDVD) { s = "DVD\r\n"; } else { s = "CDROM\r\n"; } ret += s; ret += " DiskGeometry Layout:\r\n"; s.Format(" BytesPerSector = %u\r\n", cdrom->DiskGeometry.BytesPerSector); ret += s; s.Format(" SectorsPerTrack = %u\r\n", cdrom->DiskGeometry.SectorsPerTrack); ret += s; s.Format(" TracksPerCylinder = %u\r\n", cdrom->DiskGeometry.TracksPerCylinder); ret += s; s.Format(" Cylinderst = %I64u\r\n", cdrom->DiskGeometry.Cylinders.QuadPart); ret += s; } else { s = " No media\r\n"; ret += s; } if (cdrom->bLoaded) { if (cdrom->bEjected) { ret += " Media ejected\r\n"; } else { ret += " File system: "; if (cdrom->EVP.bExt2) { s = "EXT"; s += (CHAR)('2' + cdrom->EVP.bExt3); } else { s = "CDFS"; } ret += s; ret += "\r\n"; s = " Online,"; switch (cdrom->DiskGeometry.MediaType) { case FixedMedia: s +="Fixed"; break; case RemovableMedia: s += "Media Removable"; break; case CD_ROM: s +=" CDROM"; break; case CD_R: s += "CDR"; break; case CD_RW: s += "CDRW"; break; case DVD_ROM: s += "DVD"; break; case DVD_R: s += "DVDR"; break; case DVD_RW: s += "DVDRW"; break; default: s += "Unkown"; } ret += s; ret += "\r\n"; } } else { ret += " Device stopped\r\n"; } ret += " Mountpoints: "; ret += Ext2QueryVolumeLetterStrings(cdrom->DrvLetters, NULL); ret += "\r\n"; return ret; } CString Ext2VolumeInformation(PEXT2_VOLUME vol) { CString s, ret = ""; s.Format("\r\nVolume: %s:\r\n\r\n", vol->Name); ret += s; ret += " Filesystem: "; ret += vol->FileSystem; ret += "\r\n"; /* mount points */ ret += " Mountpoints: "; ret += Ext2QueryVolumeLetterStrings(vol->DrvLetters, NULL); ret += "\r\n"; /* set volume status */ s = " Volume status: Online"; if (vol->bRecognized && (vol->EVP.bExt2 || vol->EVP.bExt3)) { s += ",codepage:"; s += vol->EVP.Codepage; if (vol->EVP.bReadonly) { s += ",Readonly"; } } ret += s; ret += "\r\n"; { ULONGLONG totalSize, freeSize; totalSize = vol->FssInfo.TotalAllocationUnits.QuadPart; freeSize = vol->FssInfo.AvailableAllocationUnits.QuadPart; totalSize = totalSize * vol->FssInfo.BytesPerSector * vol->FssInfo.SectorsPerAllocationUnit; freeSize = freeSize * vol->FssInfo.BytesPerSector * vol->FssInfo.SectorsPerAllocationUnit; s.Format(" size: %I64u\r\n", totalSize); ret += s; s.Format(" free space: %I64u\r\n", freeSize); ret += s; } if (vol->Extent) { for (DWORD i=0; i < vol->Extent->NumberOfDiskExtents; i++) { s.Format(" Extent: %d\r\n", i); ret += s; s.Format(" DiskNumber: %d\r\n", vol->Extent->Extents[i].DiskNumber); ret += s; s.Format(" StartingOffset: %I64u\r\n", vol->Extent->Extents[i].StartingOffset.QuadPart); ret += s; s.Format(" ExtentLength: %I64u\r\n", vol->Extent->Extents[i].ExtentLength.QuadPart); ret += s; } } return ret; } CString Ext2SysInformation() { ULONG i = 0; CString s; PEXT2_VOLUME chain = gVols; s = "\r\nDisk devices:\r\n"; for (i=0; i < g_nDisks; i++) { s += Ext2DiskInformation(&gDisks[i]); } s += "\r\nCdrom/DVD devices:\r\n"; for (i=0; i < g_nCdroms; i++) { s += Ext2CdromInformation(&gCdroms[i]); } while (chain) { s += Ext2VolumeInformation(chain); chain = chain->Next; } return s; } VOID Ext2CleanupDisks() { ULONG i = 0; for (i=0; i < g_nDisks; i++) { if (gDisks[i].bLoaded) { if (gDisks[i].Layout) { free(gDisks[i].Layout); gDisks[i].Layout = NULL; } gDisks[i].bLoaded = FALSE; if (gDisks[i].DataParts) { free(gDisks[i].DataParts); } } } g_nDisks = 0; if (gDisks) { free(gDisks); gDisks = NULL; } } BOOL Ext2LoadCdroms() { ULONG i = 0, j = 0; NT::NTSTATUS status; DWORD mediaType; if (g_nCdroms == 0) { return TRUE; } gCdroms = (PEXT2_CDROM) malloc(sizeof(EXT2_CDROM) * g_nCdroms); if (gCdroms == NULL) { return FALSE; } memset(gCdroms, 0, sizeof(EXT2_CDROM) * g_nCdroms); while (i < g_nCdroms && j < 256) { HANDLE Handle = NULL; gCdroms[i].Magic[0] = EXT2_CDROM_DEVICE_MAGIC; gCdroms[i].Magic[1] = EXT2_CDROM_VOLUME_MAGIC; gCdroms[i].OrderNo = (UCHAR) j; gCdroms[i].bLoaded = FALSE; sprintf(gCdroms[i].Name, "\\Device\\Cdrom%d\0", j); j++; status = Ext2Open(gCdroms[i].Name, &Handle, EXT2_DESIRED_ACCESS); if (!NT_SUCCESS(status)) { continue; } status = Ext2QueryProperty( Handle, StorageDeviceProperty, (PVOID)&gCdroms[i].SDD, sizeof(STORAGE_DEVICE_DESCRIPTOR) ); if (!NT_SUCCESS(status)) { goto Next; } status = Ext2QueryProperty( Handle, StorageAdapterProperty, (PVOID)&gCdroms[i].SAD, sizeof(STORAGE_ADAPTER_DESCRIPTOR) ); if (!NT_SUCCESS(status)) { goto Next; } status = Ext2QueryDisk(Handle, &gCdroms[i].DiskGeometry); if (NT_SUCCESS(status)) { gCdroms[i].bEjected = FALSE; } else { // (status == STATUS_NO_MEDIA_IN_DEVICE) { gCdroms[i].bEjected = TRUE; } status = Ext2QueryMediaType(Handle, &mediaType); if (NT_SUCCESS(status) && mediaType == FILE_DEVICE_DVD) { gCdroms[i].bIsDVD = TRUE; } else { gCdroms[i].bIsDVD = FALSE; } if (!gCdroms[i].bEjected) { Ext2QueryExt2Property(Handle, &gCdroms[i].EVP); } gCdroms[i].bLoaded = TRUE; Next: Ext2Close(&Handle); i++; } g_nCdroms = i; return TRUE; } VOID Ext2LoadCdromDrvLetters() { for (ULONG i = 0; i < g_nCdroms; i++) { gCdroms[i].DrvLetters = Ext2QueryCdromDrvLetters(&gCdroms[i]); } } VOID Ext2CleanupCdroms() { ULONG i = 0; for (i=0; i < g_nCdroms; i++) { if (gCdroms[i].bLoaded) { gCdroms[i].bLoaded = FALSE; } } g_nCdroms = 0; if (gCdroms) { free(gCdroms); gCdroms = NULL; } } BOOL Ext2CompareExtents( PVOLUME_DISK_EXTENTS ext1, PVOLUME_DISK_EXTENTS ext2 ) { DWORD nExt; if (ext1->NumberOfDiskExtents != ext2->NumberOfDiskExtents) { return FALSE; } for (nExt = 0; nExt < ext1->NumberOfDiskExtents; nExt++) { if ((ext1->Extents[nExt].DiskNumber != ext2->Extents[nExt].DiskNumber) || (ext1->Extents[nExt].StartingOffset.QuadPart != ext2->Extents[nExt].StartingOffset.QuadPart) || (ext1->Extents[nExt].ExtentLength.QuadPart != ext2->Extents[nExt].ExtentLength.QuadPart) ) { return FALSE; } } return TRUE; } ULONGLONG Ext2EjectedDiskLetters( PEXT2_DISK Disk ) { ULONGLONG letters = 0; int i; /* checking the digits ltters */ for (i=0; i < 10; i++) { if (drvDigits[i].bUsed && drvDigits[i].SDN) { if (drvDigits[i].SDN->DeviceNumber == Disk->OrderNo) { letters |= (((ULONGLONG) 1) << (32 + i)); } } } for (i=0; i <26; i++) { if (drvLetters[i].bUsed && drvLetters[i].SDN) { if (drvLetters[i].SDN->DeviceNumber == Disk->OrderNo) { letters |= (((ULONGLONG) 1) << i); } } } return letters; } ULONGLONG Ext2QueryVolumeDrvLetters(PEXT2_VOLUME Volume) { ULONGLONG letters = 0; int i; UCHAR drvChar = Ext2QueryMountPoint(Volume->Name); if (drvChar) { letters |= (((ULONGLONG) 1) << (drvChar - 'A')); } if (!Volume->Extent) { goto errorout; } /* checking the digits ltters */ for (i=0; i < 10; i++) { if (drvDigits[i].bUsed && drvDigits[i].Extent) { if (Ext2CompareExtents(drvDigits[i].Extent, Volume->Extent)) { letters |= (((ULONGLONG) 1) << (32 + i)); if (drvChar != drvDigits[i].Letter) { drvDigits[i].bTemporary = TRUE; } } } } for (i=0; i <26; i++) { if (drvLetters[i].bUsed && drvLetters[i].Extent) { if (Ext2CompareExtents(drvLetters[i].Extent, Volume->Extent)) { letters |= (((ULONGLONG) 1) << i); if (drvChar != drvLetters[i].Letter) { drvLetters[i].bTemporary = TRUE; } } } } errorout: return letters; } ULONGLONG Ext2QueryCdromDrvLetters(PEXT2_CDROM Cdrom) { ULONGLONG letters = 0; UCHAR drvChar; int i; if (!Cdrom) { goto errorout; } drvChar = Ext2QueryMountPoint(Cdrom->Name); if (drvChar) { letters |= (((ULONGLONG) 1) << (drvChar - 'A')); } /* checking the digits ltters */ for (i=0; i < 10; i++) { if (drvDigits[i].bUsed && drvDigits[i].DrvType == DRIVE_CDROM) { if (!_stricmp(drvDigits[i].SymLink, Cdrom->Name)) { letters |= (((ULONGLONG) 1) << (i + 32)); } } } for (i=0; i <26; i++) { if (drvLetters[i].bUsed && drvLetters[i].DrvType == DRIVE_CDROM) { if (!_stricmp(drvLetters[i].SymLink, Cdrom->Name)) { letters |= (((ULONGLONG) 1) << i); } } } errorout: return letters; } BOOL Ext2QueryVolumeFS( HANDLE Handle, PEXT2_VOLUME volume ) { struct ext2_super_block *sb = NULL; union swap_header* swap = NULL; PUCHAR buffer = NULL; NT::NTSTATUS status; buffer = (PUCHAR)malloc(PAGE_SIZE); if (!buffer) { return FALSE; } swap = (union swap_header*)&buffer[SWAP_HEADER_OFFSET]; sb = (struct ext2_super_block *)&buffer[SUPER_BLOCK_OFFSET]; status = Ext2Read( Handle, FALSE, volume->FssInfo.BytesPerSector, (ULONGLONG)0,PAGE_SIZE, (PUCHAR) buffer); if (!NT_SUCCESS(status)) { free(buffer); return FALSE; } if (sb->s_magic == EXT2_SUPER_MAGIC) { volume->FsaInfo.FileSystemNameLength = 8; volume->FsaInfo.FileSystemName[0] = (WCHAR)'E'; volume->FsaInfo.FileSystemName[1] = (WCHAR)'X'; volume->FsaInfo.FileSystemName[2] = (WCHAR)'T'; volume->FsaInfo.FileSystemName[4] = 0; if ((sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) || (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) || (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) ) { volume->FsaInfo.FileSystemName[3] = (WCHAR)'3'; volume->EVP.bExt3 = TRUE; } else { volume->FsaInfo.FileSystemName[3] = (WCHAR)'2'; volume->EVP.bExt2 = TRUE; } memcpy(&volume->EVP.UUID[0], &sb->s_uuid[0], 16); goto errorout; } if ((memcmp(swap->magic.magic, SWAP_HEADER_MAGIC_V1, 10) == 0) || (memcmp(swap->magic.magic, SWAP_HEADER_MAGIC_V2, 10) == 0)) { volume->FsaInfo.FileSystemNameLength = 8; volume->FsaInfo.FileSystemName[0] = (WCHAR)'S'; volume->FsaInfo.FileSystemName[1] = (WCHAR)'W'; volume->FsaInfo.FileSystemName[2] = (WCHAR)'A'; volume->FsaInfo.FileSystemName[3] = (WCHAR)'P'; volume->FsaInfo.FileSystemName[4] = 0; } errorout: free(buffer); return (volume->EVP.bExt2 || volume->EVP.bExt3); } BOOL Ext2QueryExt2Property ( HANDLE Handle, PEXT2_VOLUME_PROPERTY3 EVP ) { NT::NTSTATUS status; NT::IO_STATUS_BLOCK iosb; BOOLEAN bExt2, bExt3; CHAR UUID[16]; if (!Ext2IsServiceStarted()) { return FALSE; } bExt2 = EVP->bExt2; bExt3 = EVP->bExt3; memcpy(&UUID[0], &EVP->UUID[0], 16); memset(EVP, 0, sizeof(EXT2_VOLUME_PROPERTY2)); memcpy(&EVP->UUID[0], &UUID[0], 16); EVP->bExt2 = bExt2; EVP->bExt3 = bExt3; EVP->Magic = EXT2_VOLUME_PROPERTY_MAGIC; EVP->Command = APP_CMD_QUERY_PROPERTY3; status = NT::ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &iosb, IOCTL_APP_VOLUME_PROPERTY, EVP, sizeof(EXT2_VOLUME_PROPERTY3), EVP, sizeof(EXT2_VOLUME_PROPERTY3) ); return NT_SUCCESS(status); } BOOL Ext2QueryPerfStat ( HANDLE Handle, PEXT2_QUERY_PERFSTAT Stat, PEXT2_PERF_STATISTICS_V1 *PerfV1, PEXT2_PERF_STATISTICS_V2 *PerfV2 ) { NT::NTSTATUS status; NT::IO_STATUS_BLOCK iosb; memset(Stat, 0, sizeof(EXT2_QUERY_PERFSTAT)); Stat->Magic = EXT2_VOLUME_PROPERTY_MAGIC; Stat->Command = IOCTL_APP_QUERY_PERFSTAT; *PerfV1 = NULL; *PerfV2 = NULL; status = NT::ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &iosb, IOCTL_APP_QUERY_PERFSTAT, Stat, sizeof(EXT2_QUERY_PERFSTAT), Stat, sizeof(EXT2_QUERY_PERFSTAT) ); if (!NT_SUCCESS(!status)) return FALSE; if (iosb.Information == EXT2_QUERY_PERFSTAT_SZV2 && (Stat->Flags & EXT2_QUERY_PERFSTAT_VER2) != 0) { if (Stat->PerfStatV2.Magic == EXT2_PERF_STAT_MAGIC && Stat->PerfStatV2.Length == sizeof(EXT2_PERF_STATISTICS_V2) && Stat->PerfStatV2.Version == EXT2_PERF_STAT_VER2) { *PerfV2 = &Stat->PerfStatV2; } } else if (iosb.Information >= EXT2_QUERY_PERFSTAT_SZV1) { *PerfV1 = &Stat->PerfStatV1; } if (PerfV1 || PerfV2) return TRUE; return FALSE; } VOID Ext2StorePropertyinRegistry(PEXT2_VOLUME_PROPERTY3 EVP) { CHAR UUID[50], ID[16]; HKEY hKey; CHAR keyPath[MAX_PATH]; LONG status; CString data = ""; int i; int len = 0; memset(UUID, 0, 50); for (i=0; i < 16; i++) { if (i == 0) { sprintf(&UUID[len], "{%2.2X", EVP->UUID[i]); len += 3; } else if (i == 15) { sprintf(&UUID[len], "-%2.2X}", EVP->UUID[i]); len +=4; } else { sprintf(&UUID[len], "-%2.2X", EVP->UUID[i]); len += 3; } } /* Create or open ext2fsd volumes key */ strcpy (keyPath, "SYSTEM\\CurrentControlSet\\Services\\Ext2Fsd\\Volumes") ; status = ::RegCreateKeyEx (HKEY_LOCAL_MACHINE, keyPath, 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL); if (status != ERROR_SUCCESS) { return; } #define READING_ONLY "Readonly" #define WRITING_SUPPORT "WritingSupport" #define EXT3_FORCEWRITING "Ext3ForceWriting" #define CODEPAGE_NAME "CodePage" #define HIDING_PREFIX "HidingPrefix" #define HIDING_SUFFIX "HidingSuffix" #define MOUNT_POINT "MountPoint" #define UID "uid" #define GID "gid" #define EUID "euid" #define EGID "egid" if (EVP->bReadonly) { data += READING_ONLY";"; } else if (EVP->bExt3 && EVP->bExt3Writable) { data += EXT3_FORCEWRITING";"; } if (EVP->DrvLetter) { if ((EVP->DrvLetter & 0x7F) == 0 || EVP->DrvLetter == 0xFF) { data += MOUNT_POINT";"; } else { data += MOUNT_POINT"="; data += (CHAR)(EVP->DrvLetter & 0x7F); data += ":;"; } } if (strlen((CHAR*)EVP->Codepage) > 0) { data += CODEPAGE_NAME"="; data += &EVP->Codepage[0]; data += ";"; } if (EVP->bHidingPrefix) { data += HIDING_PREFIX"="; data += EVP->sHidingPrefix; data += ";"; } if (EVP->bHidingSuffix) { data += HIDING_SUFFIX"="; data += EVP->sHidingSuffix; data += ";"; } if (EVP->Flags2 & EXT2_VPROP3_USERIDS) { sprintf(ID, "%u", EVP->uid); data += UID"="; data += ID; data += ";"; sprintf(ID, "%u", EVP->gid); data += GID"="; data += ID; data += ";"; if (EVP->EIDS) { sprintf(ID, "%u", EVP->euid); data += EUID"="; data += ID; data += ";"; } } /* set volume parameters */ status = RegSetValueEx( hKey, UUID, 0, REG_SZ, (BYTE *) data.GetBuffer(data.GetLength()), data.GetLength()); RegCloseKey(hKey); } BOOL Ext2IsNullUuid (__u8 * uuid) { int i; for (i = 0; i < 16; i++) { if (uuid[i]) { break; } } return (i >= 16); } BOOL Ext2CheckVolumeRegistryProperty(PEXT2_VOLUME_PROPERTY3 EVP) { CHAR UUID[50]; HKEY hKey; CHAR keyPath[MAX_PATH]; CHAR content[MAX_PATH]; LONG status, type = 0; int i; int len = 0; BOOL rc = TRUE; if (Ext2IsNullUuid(&EVP->UUID[0])) { return TRUE; } memset(UUID, 0, 50); for (i=0; i < 16; i++) { if (i == 0) { sprintf(&UUID[len], "{%2.2X", EVP->UUID[i]); len += 3; } else if (i == 15) { sprintf(&UUID[len], "-%2.2X}", EVP->UUID[i]); len +=4; } else { sprintf(&UUID[len], "-%2.2X", EVP->UUID[i]); len += 3; } } /* Create or open ext2fsd volumes key */ strcpy (keyPath, "SYSTEM\\CurrentControlSet\\Services\\Ext2Fsd\\Volumes") ; status = ::RegOpenKeyEx (HKEY_LOCAL_MACHINE, keyPath, 0, KEY_ALL_ACCESS, &hKey) ; if (status != ERROR_SUCCESS) { rc = FALSE; goto errorout; } /* Query volume parameters */ len = MAX_PATH; status = RegQueryValueEx(hKey, &UUID[0], 0, (LPDWORD)&type, (BYTE *)&content[0], (LPDWORD)&len); if (status != ERROR_SUCCESS) { rc = FALSE; } RegCloseKey(hKey); errorout: return rc; } VOID Ext2SetDefaultVolumeRegistryProperty(PEXT2_VOLUME_PROPERTY3 EVP) { ULONG StartMode; BOOL AutoMount = 0; if (Ext2IsNullUuid(&EVP->UUID[0])) { return; } /* query global parameters */ Ext2QueryGlobalProperty( &StartMode, (BOOL *)&EVP->bReadonly, (BOOL *)&EVP->bExt3Writable, (CHAR *)EVP->Codepage, (CHAR *)NULL, (CHAR *)NULL, (BOOL *)&AutoMount ); if (EVP->bExt3 && !EVP->bExt3Writable) EVP->bReadonly = TRUE; EVP->DrvLetter = 0x80; EVP->Flags2 |= EXT2_VPROP3_AUTOMOUNT; Ext2StorePropertyinRegistry(EVP); } BOOL Ext2SetExt2Property ( HANDLE Handle, PEXT2_VOLUME_PROPERTY3 EVP ) { NT::NTSTATUS status; NT::IO_STATUS_BLOCK iosb; ASSERT(EVP->Magic == EXT2_VOLUME_PROPERTY_MAGIC); EVP->Command = APP_CMD_SET_PROPERTY3; status = NT::ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &iosb, IOCTL_APP_VOLUME_PROPERTY, EVP, sizeof(EXT2_VOLUME_PROPERTY3), EVP, sizeof(EXT2_VOLUME_PROPERTY3) ); if (NT_SUCCESS(status)) { return TRUE; } else { CString s; s.Format("Status = %xh\n", status); AfxMessageBox(s); } return FALSE; } BOOL Ext2QueryGlobalProperty( ULONG * ulStartup, BOOL * bReadonly, BOOL * bExt3Writable, CHAR * Codepage, CHAR * sPrefix, CHAR * sSuffix, BOOL * bAutoMount ) { int rc = TRUE; HKEY hKey; CHAR keyPath[MAX_PATH]; DWORD data = 0; LONG status, type, len; /* Open ext2fsd sevice key */ strcpy (keyPath, "SYSTEM\\CurrentControlSet\\Services\\Ext2Fsd") ; status = ::RegOpenKeyEx (HKEY_LOCAL_MACHINE, keyPath, 0, KEY_ALL_ACCESS, &hKey) ; if (status != ERROR_SUCCESS) { rc = FALSE; goto errorout; } /* Query Start type */ len = sizeof(DWORD); status = RegQueryValueEx( hKey, "Start", 0, (LPDWORD)&type, (BYTE *)&data, (LPDWORD)&len); if (status == ERROR_SUCCESS) { *ulStartup = data; } RegCloseKey(hKey); /* Open ext2fsd parameters key */ strcpy (keyPath, "SYSTEM\\CurrentControlSet\\Services\\Ext2Fsd\\Parameters") ; status = ::RegOpenKeyEx (HKEY_LOCAL_MACHINE, keyPath, 0, KEY_ALL_ACCESS, &hKey) ; if (status != ERROR_SUCCESS) { rc = FALSE; goto errorout; } /* Query WritingSupport */ len = sizeof(DWORD); status = RegQueryValueEx( hKey, "WritingSupport", 0, (LPDWORD)&type, (BYTE *)&data, (LPDWORD)&len); if (status == ERROR_SUCCESS) { *bReadonly = (data == 0); } /* query Ext3ForceWriting */ len = sizeof(DWORD); status = RegQueryValueEx( hKey, "Ext3ForceWriting", 0, (LPDWORD)&type, (BYTE *)&data, (LPDWORD)&len); if (status == ERROR_SUCCESS) { *bExt3Writable = (data != 0); } /* query AutoMount */ len = sizeof(DWORD); status = RegQueryValueEx( hKey, "AutoMount", 0, (LPDWORD)&type, (BYTE *)&data, (LPDWORD)&len); if (status == ERROR_SUCCESS) { *bAutoMount = (data != 0); } if (Codepage) { /* query codepage */ len = CODEPAGE_MAXLEN; status = RegQueryValueEx( hKey, "CodePage", 0, (LPDWORD)&type, (BYTE *)Codepage, (LPDWORD)&len); } if (sPrefix) { /* querying hidding filter patterns */ len = CODEPAGE_MAXLEN; status = RegQueryValueEx( hKey, "HidingPrefix", 0, (LPDWORD)&type, (BYTE *)sPrefix, (LPDWORD)&len); } if (sSuffix) { len = CODEPAGE_MAXLEN; status = RegQueryValueEx( hKey, "HidingSuffix", 0, (LPDWORD)&type, (BYTE *)sSuffix, (LPDWORD)&len); } RegCloseKey(hKey); errorout: return rc; } INT Ext2QueryDrvVersion( CHAR * Version, CHAR * Date, CHAR * Time ) { EXT2_VOLUME_PROPERTY_VERSION EVPV; NT::NTSTATUS status; HANDLE handle = NULL; NT::IO_STATUS_BLOCK iosb; INT rc = 0; memset(&EVPV, 0, sizeof(EXT2_VOLUME_PROPERTY_VERSION)); EVPV.Magic = EXT2_VOLUME_PROPERTY_MAGIC; EVPV.Command = APP_CMD_QUERY_VERSION; EVPV.Flags |= EXT2_FLAG_VP_SET_GLOBAL; status = Ext2Open("\\DosDevices\\Ext2Fsd", &handle, EXT2_DESIRED_ACCESS); if (!NT_SUCCESS(status)) { rc = -1; goto errorout; } status = NT::ZwDeviceIoControlFile( handle, NULL, NULL, NULL, &iosb, IOCTL_APP_VOLUME_PROPERTY, &EVPV, sizeof(EXT2_VOLUME_PROPERTY_VERSION), &EVPV, sizeof(EXT2_VOLUME_PROPERTY_VERSION) ); if (NT_SUCCESS(status)) { strncpy(Version, EVPV.Version, 0x1B); strncpy(Date, EVPV.Date, 0x1F); strncpy(Time, EVPV.Time, 0x1F); } rc = NT_SUCCESS(status); errorout: Ext2Close(&handle); return rc; } BOOL Ext2SetGlobalProperty ( ULONG ulStartup, BOOLEAN bReadonly, BOOLEAN bExt3Writable, CHAR * Codepage, CHAR * sPrefix, CHAR * sSuffix, BOOL bAutoMount ) { EXT2_VOLUME_PROPERTY3 EVP; NT::NTSTATUS status; HANDLE Handle = NULL; int rc = TRUE; HKEY hKey; CHAR keyPath[MAX_PATH] ; ULONG data = 0; memset(&EVP, 0, sizeof(EXT2_VOLUME_PROPERTY3)); EVP.Magic = EXT2_VOLUME_PROPERTY_MAGIC; EVP.Command = APP_CMD_SET_PROPERTY3; EVP.Flags |= EXT2_FLAG_VP_SET_GLOBAL; EVP.bReadonly = bReadonly; EVP.bExt3Writable = bExt3Writable; strcpy((CHAR *)EVP.Codepage, Codepage); if (strlen(sPrefix)) { strcpy(EVP.sHidingPrefix, sPrefix); EVP.bHidingPrefix = TRUE; } if (strlen(sSuffix)) { strcpy(EVP.sHidingSuffix, sSuffix); EVP.bHidingSuffix = TRUE; } strcpy (keyPath, "SYSTEM\\CurrentControlSet\\Services\\Ext2Fsd") ; status = ::RegOpenKeyEx (HKEY_LOCAL_MACHINE, keyPath, 0, KEY_ALL_ACCESS, &hKey) ; if (status != ERROR_SUCCESS) { rc = FALSE; goto errorout; } /* set Start type */ status = RegSetValueEx( hKey, "Start", 0, REG_DWORD, (BYTE *)&ulStartup, sizeof(DWORD)); RegCloseKey(hKey); strcpy (keyPath, "SYSTEM\\CurrentControlSet\\Services\\Ext2Fsd\\Parameters") ; status = ::RegOpenKeyEx (HKEY_LOCAL_MACHINE, keyPath, 0, KEY_ALL_ACCESS, &hKey) ; if (status != ERROR_SUCCESS) { rc = FALSE; goto errorout; } /* set WritingSupport */ data = !bReadonly; status = RegSetValueEx( hKey, "WritingSupport", 0, REG_DWORD, (BYTE *)&data, sizeof(ULONG)); /* set Ext3ForceWriting */ data = bExt3Writable; status = RegSetValueEx( hKey, "Ext3ForceWriting", 0, REG_DWORD, (BYTE *)&data, sizeof(ULONG)); /* set AutoMount */ data = bAutoMount; status = RegSetValueEx( hKey, "AutoMount", 0, REG_DWORD, (BYTE *)&data, sizeof(ULONG)); /* set codepage */ status = RegSetValueEx( hKey, "CodePage", 0, REG_SZ, (BYTE *)Codepage, strlen(Codepage)); /* set hiding filter patterns */ status = RegSetValueEx( hKey, "HidingPrefix", 0, REG_SZ, (BYTE *)sPrefix, strlen(sPrefix)); status = RegSetValueEx( hKey, "HidingSuffix", 0, REG_SZ, (BYTE *)sSuffix, strlen(sSuffix)); RegCloseKey(hKey); status = Ext2Open("\\DosDevices\\Ext2Fsd", &Handle, EXT2_DESIRED_ACCESS); if (!NT_SUCCESS(status)) { goto errorout; } EVP.Flags2 = EXT2_VPROP3_AUTOMOUNT; EVP.AutoMount = g_bAutoMount; rc = Ext2SetExt2Property(Handle, &EVP); if (!rc) { } errorout: Ext2Close(&Handle); return rc; } BOOL Ext2SetService(PCHAR Target, PCHAR Name, PCHAR Desc, BOOL bInstall) { SC_HANDLE hService; SC_HANDLE hManager; // open Service Control Manager hManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (hManager == NULL) { // AfxMessageBox("Ext2Mgr: cannot open Service Control Manager", // MB_ICONEXCLAMATION | MB_OK); return FALSE; } if (bInstall) { // now create service entry hService = CreateService( hManager, // SCManager database Name, // name of service Desc, // name to display SERVICE_ALL_ACCESS, // desired access SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, // service type SERVICE_AUTO_START, // start type SERVICE_ERROR_NORMAL, // error control type Target, // service's binary NULL, // no load ordering group NULL, // no tag identifier NULL, // dependencies NULL, // LocalSystem account NULL); // no password if (hService == NULL) { DWORD error = GetLastError(); if (error == ERROR_SERVICE_EXISTS) { // AfxMessageBox("Service is already registered.", // MB_ICONEXCLAMATION | MB_OK); } else { // AfxMessageBox("Service couldn't be registered.", // MB_ICONEXCLAMATION | MB_OK); } } else { CloseServiceHandle(hService); } } else { /* open the service */ hService = OpenService( hManager, Name, SERVICE_ALL_ACCESS ); if (hService != NULL) { // remove the service from the SCM if (DeleteService(hService)) { } else { DWORD error = GetLastError(); if (error == ERROR_SERVICE_MARKED_FOR_DELETE) { // AfxMessageBox("Service is already unregistered", // MB_ICONEXCLAMATION | MB_OK); } else { // AfxMessageBox("Service could not be unregistered", // MB_ICONEXCLAMATION | MB_OK); } } CloseServiceHandle(hService); } } CloseServiceHandle(hManager); return TRUE; } BOOL ExtSaveResourceToFile(UINT id, CHAR *target) { HANDLE handle; ULONG bytes = 0; BOOL rc = FALSE; HRSRC hr = FindResource(NULL, MAKEINTRESOURCE(id), RT_RCDATA); ULONG size = SizeofResource(NULL, hr); HGLOBAL hg = LoadResource(NULL, hr); PVOID data = LockResource(hg); if (!data) goto errorout; handle = CreateFile(target, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (handle == INVALID_HANDLE_VALUE) { goto errorout; } rc = WriteFile(handle, data, size, &bytes, NULL); if (rc) rc = (bytes == size); CloseHandle(handle); errorout: return rc; } TCHAR *Ext2StrLastA(TCHAR *t, TCHAR *s); BOOL Ext2InstallExt2Srv() { TCHAR cmd[512] = {0}, *p; BOOL rc = FALSE; if (GetWindowsDirectory(cmd, 512)) { if (g_isWow64) strcat(cmd, "\\SysWOW64\\Ext2Srv.EXE"); else strcat(cmd, "\\System32\\Ext2Srv.EXE"); rc = ExtSaveResourceToFile(IDR_RCDAT_SRV, cmd); } if (!rc) { GetModuleFileName(NULL, cmd, 510); p = Ext2StrLastA(cmd, ".EXE"); if (p && p > &cmd[3]) { p[-3] = 'S'; p[-2] = 'r'; p[-1] = 'v'; } else { strcat(cmd, "-Srv.EXE"); } rc = ExtSaveResourceToFile(IDR_RCDAT_SRV, cmd); } if (!rc) { GetTempPath(50, cmd); strcat(cmd, "\\Ext2Srv.EXE"); rc = ExtSaveResourceToFile(IDR_RCDAT_SRV, cmd); } if (!rc) { return rc; } rc = Ext2SetService(cmd, "Ext2Srv", "Ext2Fsd Service Manager", TRUE); if (!rc) { return rc; } return Ext2StartService("Ext2Srv"); } BOOL Ext2StartService(CHAR *service) { BOOL rc = FALSE; SC_HANDLE scmHandle = NULL; SC_HANDLE drvHandle = NULL; scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (!scmHandle) { goto errorout; } drvHandle = OpenService(scmHandle, service, SERVICE_ALL_ACCESS); if (!drvHandle) { goto errorout; } rc = (0 != StartService(drvHandle, 0, NULL)); errorout: if (drvHandle) CloseServiceHandle(drvHandle); if (scmHandle) { CloseServiceHandle(scmHandle); } return rc; } BOOL Ext2StartExt2Srv() { BOOL rc = Ext2StartService("Ext2Srv"); if (!rc) rc = Ext2InstallExt2Srv(); return rc; } BOOL Ext2StartExt2Fsd() { if (Ext2IsServiceStarted()) { return TRUE; } return Ext2StartService("ext2fsd"); } BOOL Ext2IsServiceStarted() { NT::NTSTATUS status; HANDLE Handle = NULL; status = Ext2Open("\\DosDevices\\Ext2Fsd", &Handle, EXT2_DESIRED_ACCESS); Ext2Close(&Handle); if (NT_SUCCESS(status)) { return TRUE; } return FALSE; } BOOL Ext2IsRemovable(PEXT2_VOLUME volume) { STORAGE_BUS_TYPE busType = BusTypeAta; BOOL bRemovableMedia = FALSE; if (volume && volume->Part) { busType = volume->Part->Disk->SDD.BusType; bRemovableMedia = volume->Part->Disk->SDD.RemovableMedia; } if (busType == BusType1394 || busType == BusTypeUsb || bRemovableMedia ) { return TRUE; } return FALSE; } BOOL Ext2RemoveDriveLetter(CHAR DrvLetter) { PEXT2_LETTER drvLetter = NULL; BOOL rc = FALSE; if (DrvLetter >= '0' && DrvLetter <= '9') { drvLetter = &drvDigits[DrvLetter - '0']; } else if (DrvLetter >= 'A' && DrvLetter <= 'Z') { drvLetter = &drvLetters[DrvLetter - 'A']; } else if (DrvLetter >= 'a' && DrvLetter <= 'z') { drvLetter = &drvLetters[DrvLetter - 'a']; } if (drvLetter && drvLetter->bUsed) { rc = Ext2RemoveDrvLetter(drvLetter); } return rc; } BOOL Ext2InitializeVolume( PCHAR NameString, PEXT2_VOLUME * Volume ) { BOOL rc = FALSE; HANDLE hVolume = NULL; NT::NTSTATUS status; NT::IO_STATUS_BLOCK ioSb; PEXT2_VOLUME volume = NULL; volume = (PEXT2_VOLUME) malloc(sizeof(EXT2_VOLUME)); if (!volume) { goto errorout; } status = Ext2Open(NameString, &hVolume, EXT2_DESIRED_ACCESS); if (!NT_SUCCESS(status)) { free(volume); volume = NULL; goto errorout; } memset(volume, 0, sizeof(EXT2_VOLUME)); volume->Magic = EXT2_VOLUME_MAGIC; strcpy(volume->Name, NameString); status = NT::ZwQueryVolumeInformationFile( hVolume, &ioSb, &volume->FsaInfo, MAX_PATH, NT::FileFsAttributeInformation ); if (NT_SUCCESS(status)) { NT::UNICODE_STRING uniString; NT::ANSI_STRING aniString; NT::ZwQueryVolumeInformationFile( hVolume, &ioSb, &volume->FsdInfo, sizeof(NT::FILE_FS_DEVICE_INFORMATION), NT::FileFsDeviceInformation ); NT::ZwQueryVolumeInformationFile( hVolume, &ioSb, &volume->FssInfo, sizeof(NT::FILE_FS_SIZE_INFORMATION), NT::FileFsSizeInformation ); if (volume->FsaInfo.FileSystemNameLength == 6 && (volume->FsaInfo.FileSystemName[0] == (WCHAR)'R' || volume->FsaInfo.FileSystemName[0] == (WCHAR)'r') && (volume->FsaInfo.FileSystemName[1] == (WCHAR)'A' || volume->FsaInfo.FileSystemName[1] == (WCHAR)'a') && (volume->FsaInfo.FileSystemName[2] == (WCHAR)'W' || volume->FsaInfo.FileSystemName[2] == (WCHAR)'w')) { if (!Ext2QueryVolumeFS(hVolume, volume)) { /* memcpy(volume->Codepage, "N/A", 3); */ } } else { if (Ext2QueryExt2Property(hVolume, &volume->EVP)) { volume->bRecognized = TRUE; } } /* convert the unicode file system name to mbs */ uniString.MaximumLength = uniString.Length = (USHORT)volume->FsaInfo.FileSystemNameLength; uniString.Buffer = volume->FsaInfo.FileSystemName; aniString.Buffer = volume->FileSystem; aniString.Length = 0; aniString.MaximumLength = 64; memset(volume->FileSystem, 0, 64); NT::RtlUnicodeStringToAnsiString(&aniString, &uniString, FALSE); } volume->Extent = Ext2QueryVolumeExtents(hVolume); if (!volume->Extent) { free(volume); volume = NULL; goto errorout; } *Volume = volume; rc = TRUE; errorout: Ext2Close(&hVolume); return rc; } CHAR Ext2ProcessExt2Property(PEXT2_VOLUME volume) { HANDLE hVolume = NULL; NT::NTSTATUS status; CHAR rc = 0; status = Ext2Open(volume->Name, &hVolume, EXT2_DESIRED_ACCESS); if (!NT_SUCCESS(status)) { goto errorout; } if (Ext2QueryExt2Property(hVolume, &volume->EVP)) { if (volume->DrvLetters == 0 && volume->EVP.DrvLetter) { CHAR DrvLetter = volume->EVP.DrvLetter & 0x7F; if (DrvLetter && Ext2IsDrvLetterAvailable(DrvLetter)) { rc = Ext2MountVolumeAs(volume->Name, DrvLetter); } else { rc = volume->EVP.DrvLetter = Ext2MountVolume(volume->Name); volume->EVP.DrvLetter |= 0x80; } } } errorout: Ext2Close(&hVolume); return rc; } BOOL Ext2ProcessExt2Volumes() { PEXT2_VOLUME volume = gVols; BOOL rc = FALSE; while (volume) { if (Ext2ProcessExt2Property(volume)) { rc = TRUE; } volume = volume->Next; } return rc; } BOOL Ext2IsPartitionExtent( ULONG disk, PPARTITION_INFORMATION_EXT part, PVOLUME_DISK_EXTENTS extent ) { DWORD nExt = 0; for (nExt = 0; nExt < extent->NumberOfDiskExtents; nExt++) { if ((extent->Extents[nExt].DiskNumber == disk) && (extent->Extents[nExt].StartingOffset.QuadPart == part->StartingOffset.QuadPart ) && (extent->Extents[nExt].ExtentLength.QuadPart == part->PartitionLength.QuadPart)) { return TRUE; } } return FALSE; } /* should be called after volumes' initiaization */ BOOL Ext2LoadDiskPartitions(PEXT2_DISK Disk) { UCHAR i = 0, cnt = 0; ULONG j = 0; BOOL bDynamic = FALSE; if (Disk->NumParts == 0) { Disk->NumParts = 1; } Disk->DataParts = (PEXT2_PARTITION) malloc( sizeof(EXT2_PARTITION) * Disk->NumParts); if (!Disk->DataParts) { return FALSE; } memset(Disk->DataParts, 0, sizeof(EXT2_PARTITION) * Disk->NumParts); if (Disk->Layout) { if (Disk->Layout->PartitionStyle == PARTITION_STYLE_MBR && Disk->Layout->PartitionEntry->Mbr.PartitionType == PARTITION_LDM) { bDynamic = TRUE; } /* Now walk through driveLayout and pack partitions */ for (i = 0; (Disk->Layout != NULL) && (i < (UCHAR)Disk->Layout->PartitionCount); i++) { PPARTITION_INFORMATION_EXT Part; Part = &Disk->Layout->PartitionEntry[i]; if (Disk->Layout->PartitionStyle == PARTITION_STYLE_MBR) { if (Part->Mbr.PartitionType == PARTITION_ENTRY_UNUSED || Part->Mbr.PartitionType == PARTITION_EXTENDED || Part->Mbr.PartitionType == PARTITION_XINT13_EXTENDED) { continue; } } sprintf(&Disk->DataParts[cnt].Name[0], "\\Device\\Harddisk%u\\Partition%u", Disk->OrderNo, cnt + 1); Disk->DataParts[cnt].Magic = EXT2_PART_MAGIC; Disk->DataParts[cnt].PartType = Disk->Layout->PartitionStyle; Disk->DataParts[cnt].Disk = Disk; Disk->DataParts[cnt].Number = cnt + 1; Disk->DataParts[cnt++].Entry = Part; } /* Search the volumes of the partition */ for (i=0; i < cnt; i++) { PEXT2_VOLUME volume = gVols; for (j=0; (ULONG)j < g_nVols; j++) { if (Ext2IsPartitionExtent(Disk->OrderNo, Disk->DataParts[i].Entry, volume->Extent )) { volume->bDynamic = bDynamic; if (volume->Extent->NumberOfDiskExtents == 1) { volume->Part = &Disk->DataParts[i]; } Disk->DataParts[i].Volume = volume; Disk->DataParts[i].DrvLetters = volume->DrvLetters; break; } volume = volume->Next; } } } else { Disk->DataParts[cnt].Magic = EXT2_PART_MAGIC; Disk->DataParts[cnt].Disk = Disk; Disk->DataParts[cnt].Number = cnt + 1; Disk->DataParts[cnt].DrvLetters = Ext2EjectedDiskLetters(Disk); } return TRUE; } VOID Ext2LoadAllDiskPartitions() { for (ULONG i=0; i < g_nDisks; i++) { Ext2LoadDiskPartitions(&gDisks[i]); } } VOID Ext2MountingVolumes() { PEXT2_VOLUME volume = gVols; int j; if (!Ext2IsServiceStarted()) { return; } for (j=0; (ULONG)j < g_nVols; j++) { if ((volume->EVP.bExt2 || volume->EVP.bExt3) && !volume->bRecognized) { if (Ext2IsRemovable(volume) || (volume->DrvLetters != 0) || g_bAutoMount) { if (!Ext2CheckVolumeRegistryProperty(&volume->EVP)) { Ext2SetDefaultVolumeRegistryProperty(&volume->EVP); } Ext2NotifyVolumePoint(volume, 0); } } volume = volume->Next; } } /* * Must initialize driver letter before loading volumes */ BOOL Ext2LoadVolumes() { ULONG rc = TRUE; TCHAR *nameString = NULL; ULONG nameLen = REGSTR_VAL_MAX_HCID_LEN; HMACHINE hMachine = NULL; DEVNODE dnRoot, dnFirst; DEVINSTID devIds[] = { "ROOT\\FTDISK\\0000", "ROOT\\DMIO\\0000", NULL, "ROOT\\VOLMGR\\0000", NULL }; int i = 0; if (IsVistaOrAbove()) { i = 3; } nameString = new TCHAR [nameLen]; if (nameString == NULL) { goto errorout; } while (devIds[i] != NULL) { rc = CM_Locate_DevNode_Ex(&dnRoot, devIds[i], CM_LOCATE_DEVNODE_NORMAL , hMachine); if (rc != CR_SUCCESS) { break; } rc = CM_Get_Child_Ex(&dnFirst, dnRoot, 0, hMachine); if (rc != CR_SUCCESS) { goto errorout; } while (TRUE) { PEXT2_VOLUME volume = NULL; nameLen = REGSTR_VAL_MAX_HCID_LEN; memset(nameString, 0, nameLen); rc = CM_Get_DevNode_Registry_Property_Ex( dnFirst, CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME, NULL, nameString, &nameLen, 0, hMachine); if (rc != CR_SUCCESS) { break; } if (Ext2InitializeVolume(nameString, &volume)) { volume->bDynamic = 0; /* attach the volume to global list */ if (gVols) { PEXT2_VOLUME chain = gVols; while (chain->Next) { chain = chain->Next; } chain->Next = volume; } else { gVols = volume; } g_nVols++; } rc = CM_Get_Sibling_Ex(&dnFirst, dnFirst, 0, hMachine); if (rc != CR_SUCCESS) { break; } } i++; } errorout: if (nameString) { delete []nameString; } return TRUE; } BOOL Ext2LoadRemovableVolumes() { BOOL rc = FALSE; HDEVINFO devInfo = INVALID_HANDLE_VALUE; PSP_DEVICE_INTERFACE_DETAIL_DATA ifDetail = NULL; SP_DEVICE_INTERFACE_DATA ifData; PCHAR nameString; int nInterface = 0; if (IsVistaOrAbove()) { return TRUE; } nameString = (PCHAR)malloc(REGSTR_VAL_MAX_HCID_LEN); if (nameString == NULL) { goto errorout; } ifDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(PAGE_SIZE); if (ifDetail == NULL) { goto errorout; } devInfo = SetupDiGetClassDevs( &VolumeClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE ); if (devInfo == INVALID_HANDLE_VALUE) { goto errorout; } while (TRUE) { BOOL bFound = FALSE; ifData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); bFound = SetupDiEnumDeviceInterfaces( devInfo, NULL, &VolumeClassGuid, (ULONG)nInterface++, &ifData); if (!bFound) { break; } memset(ifDetail, 0, PAGE_SIZE); ifDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); if (SetupDiGetInterfaceDeviceDetail( devInfo, &ifData, ifDetail, PAGE_SIZE, NULL, NULL)) { PEXT2_VOLUME volume = NULL; memset(nameString, 0, REGSTR_VAL_MAX_HCID_LEN); QueryDosDevice(&ifDetail->DevicePath[4], nameString, REGSTR_VAL_MAX_HCID_LEN); if (Ext2InitializeVolume(nameString, &volume)) { if (volume->FsdInfo.Characteristics & FILE_REMOVABLE_MEDIA) { /* attach the volume to global list */ if (gVols) { PEXT2_VOLUME chain = gVols; while (chain->Next) { chain = chain->Next; } chain->Next = volume; } else { gVols = volume; } g_nVols++; } else { if (volume->Extent) { free(volume->Extent); } free(volume); } } } } rc = TRUE; errorout: if (nameString) { free(nameString); } if (ifDetail) { free(ifDetail); } if (devInfo != INVALID_HANDLE_VALUE) { SetupDiDestroyDeviceInfoList(devInfo); } return rc; } VOID Ext2LoadAllVolumeDrvLetters() { PEXT2_VOLUME volume = gVols; BOOL started = Ext2IsServiceStarted(); // Ext2DrvLetters[0] = Ext2DrvLetters[1]; // Ext2DrvLetters[1] = 0; while (volume) { volume->DrvLetters = Ext2QueryVolumeDrvLetters(volume); if ( started && volume->bRecognized && (volume->EVP.bExt2 || volume->EVP.bExt3)) { Ext2DrvLetters[1] |= volume->DrvLetters; } volume = volume->Next; } } CString Ext2QueryVolumeLetterStrings( ULONGLONG letters, PEXT2_LETTER * first ) { CHAR drvName[] = "C:\0"; CString str; int i = 0; BOOL bInserted = FALSE; ULONGLONG drive = 0; str.Empty(); for (i=0; i < 10; i++) { drive = ((ULONGLONG) 1) << (i + 32); if (letters & drive) { if (bInserted) { str += ","; } else { str = "("; if (first) { *first = &drvDigits[i]; } } drvName[0] = '0' + i; str += drvName; bInserted = TRUE; } } for (i=0; i < 26; i++) { drive = ((ULONGLONG) 1) << (i); if (letters & drive) { if (bInserted) { str += ","; } else { str = "("; if (first) { *first = &drvLetters[i]; } } drvName[0] = 'A' + i; str += drvName; bInserted = TRUE; } } if (bInserted) { str += ")"; } return str; } VOID Ext2RefreshVLVI( CListCtrl *List, PEXT2_VOLUME chain, int nItem ) { ULONGLONG totalSize, usedSize; CString sSize, sUnit, s; PEXT2_LETTER first = NULL; CString Letters = Ext2QueryVolumeLetterStrings( chain->DrvLetters, &first); List->SetItem( nItem, 1, LVIF_TEXT, (LPCSTR)Letters, 0, 0, 0,0); if (chain->bDynamic) { s.LoadString(IDS_DISK_TYPE_DYN); } else { s.LoadString(IDS_DISK_TYPE_BASIC); } List->SetItem(nItem, 2, LVIF_TEXT, (LPCSTR)s, 0, 0, 0,0); List->SetItem(nItem, 3, LVIF_TEXT, (LPCSTR)chain->FileSystem, 0, 0, 0,0); totalSize = chain->FssInfo.TotalAllocationUnits.QuadPart; usedSize = totalSize - chain->FssInfo.AvailableAllocationUnits.QuadPart; totalSize = totalSize * chain->FssInfo.BytesPerSector * chain->FssInfo.SectorsPerAllocationUnit; usedSize = usedSize * chain->FssInfo.BytesPerSector * chain->FssInfo.SectorsPerAllocationUnit; if (totalSize > (ULONGLONG) 10 * 1024 * 1024 * 1024) { totalSize = totalSize / ((ULONG)1024 * 1024 * 1024); usedSize = usedSize / ((ULONG)1024 * 1024 * 1024); sUnit = " GB"; } else if (totalSize > 10 * 1024 * 1024){ totalSize = totalSize / (1024 * 1024); usedSize = usedSize / (1024 * 1024); sUnit = " MB"; } else if (totalSize > 10 * 1024){ totalSize = totalSize / (1024); usedSize = usedSize / (1024); sUnit = " KB"; } else { sUnit = " B"; } sSize.Format("%I64u", totalSize); sSize += sUnit; List->SetItem(nItem, 4, LVIF_TEXT, (LPCSTR)sSize, 0, 0, 0,0); if (chain->bRecognized) { sSize.Format("%I64u", usedSize); sSize += sUnit; } List->SetItem(nItem, 5, LVIF_TEXT, (LPCSTR)sSize, 0, 0, 0,0); List->SetItem(nItem, 6, LVIF_TEXT, (LPCSTR)chain->EVP.Codepage, 0, 0, 0,0); List->SetItem(nItem, 7, LVIF_TEXT, (LPCSTR)chain->Name, 0, 0, 0,0); /* List->SetItemState( nItem, LVIS_SELECTED | LVIS_FOCUSED , LVIS_SELECTED | LVIS_FOCUSED); */ } VOID Ext2InsertVolume( CListCtrl *List, PEXT2_VOLUME chain ) { int nItem = 0, nImage = 0; nItem = List->GetItemCount(); nImage = 0; if (chain->FsdInfo.Characteristics & FILE_VIRTUAL_VOLUME) { nImage = IDI_DYNAMIC - IDI_FLOPPY; } else if (chain->FsdInfo.Characteristics & FILE_REMOVABLE_MEDIA) { nImage = IDI_FLOPPY - IDI_FLOPPY; } else { nImage = IDI_DISK - IDI_FLOPPY; } nItem = List->InsertItem( LVIF_PARAM|LVIF_IMAGE, nItem, NULL, 0, 0, nImage, (LPARAM)chain); Ext2RefreshVLVI(List, chain, nItem); } VOID Ext2RefreshVLCD( CListCtrl *List, PEXT2_CDROM Cdrom, int nItem ) { ULONGLONG totalSize; CString sSize, sUnit, s; PEXT2_LETTER first = NULL; CString Letters = Ext2QueryVolumeLetterStrings( Cdrom->DrvLetters, &first); List->SetItem( nItem, 1, LVIF_TEXT, (LPCSTR)Letters, 0, 0, 0,0); s.LoadString(IDS_DISK_TYPE_BASIC); List->SetItem(nItem, 2, LVIF_TEXT, (LPCSTR)s, 0, 0, 0,0); List->SetItem(nItem, 3, LVIF_TEXT, (LPCSTR)"CDFS", 0, 0, 0,0); totalSize = (ULONGLONG)Cdrom->DiskGeometry.Cylinders.QuadPart; totalSize = totalSize * Cdrom->DiskGeometry.TracksPerCylinder * Cdrom->DiskGeometry.SectorsPerTrack * Cdrom->DiskGeometry.BytesPerSector; if (totalSize > 1024 * 1024 * 1024) { totalSize = totalSize / (1024 * 1024 * 1024); sUnit = " GB"; } else if (totalSize > 1024 * 1024){ totalSize = totalSize / (1024 * 1024); sUnit = " MB"; } else if (totalSize > 1024){ totalSize = totalSize / (1024); sUnit = " KB"; } else { sUnit = " B"; } sSize.Format("%I64u", totalSize); sSize += sUnit; List->SetItem(nItem, 4, LVIF_TEXT, (LPCSTR)sSize, 0, 0, 0,0); sSize.Format("%I64u", totalSize); sSize += sUnit; List->SetItem(nItem, 5, LVIF_TEXT, (LPCSTR)sSize, 0, 0, 0,0); List->SetItem(nItem, 8, LVIF_TEXT, (LPCSTR)Cdrom->Name, 0, 0, 0,0); } VOID Ext2InsertCdromAsVolume( CListCtrl *List, PEXT2_CDROM Cdrom ) { int nItem = 0, nImage = 0; nItem = List->GetItemCount(); nImage = 0; if (Cdrom->bIsDVD) { nImage = IDI_DVD - IDI_FLOPPY; } else { nImage = IDI_CDROM - IDI_FLOPPY; } nItem = List->InsertItem( LVIF_PARAM|LVIF_IMAGE, nItem, NULL, 0, 0, nImage, (LPARAM)Cdrom); Ext2RefreshVLCD(List, Cdrom, nItem); } VOID Ext2RefreshVolumeList(CListCtrl *List) { List->DeleteAllItems(); PEXT2_VOLUME chain = gVols; /* adding disk volumes */ while (chain) { Ext2InsertVolume(List, chain); chain = chain->Next; } /* adding cdroms */ ULONG i = 0; for (i=0; i < g_nCdroms; i++) { if (!gCdroms[i].bLoaded || gCdroms[i].bEjected) { continue; } Ext2InsertCdromAsVolume(List, &gCdroms[i]); } } VOID Ext2RefreshDVPT( CListCtrl* List, PEXT2_PARTITION Part, int nItem ) { ULONGLONG totalSize, usedSize; CString sSize, sUnit, s; PEXT2_LETTER first = NULL; PEXT2_VOLUME chain = NULL; CString Letters = Ext2QueryVolumeLetterStrings( Part->DrvLetters, &first); List->SetItem( nItem, 0, LVIF_TEXT, (LPCSTR)Letters, 0, 0, 0,0); if (Part->Entry) { CString PartType; if (Part->Entry->PartitionStyle == PARTITION_STYLE_MBR) { PartType = PartitionString(Part->Entry->Mbr.PartitionType); } else if (Part->Entry->PartitionStyle == PARTITION_STYLE_GPT) { PartType = ""; if (Part->Entry->Gpt.Name && wcslen(Part->Entry->Gpt.Name)) { for (size_t i = 0; i < wcslen(Part->Entry->Gpt.Name); i++) PartType += (CHAR)Part->Entry->Gpt.Name[i]; } else { PartType = "GPT"; } } else { PartType = "RAW"; } List->SetItem(nItem, 6, LVIF_TEXT, (LPCSTR) PartType, 0, 0, 0,0); } /* query the volume information of the partition */ chain = Part->Volume; if (!chain) { PEXT2_DISK disk = Part->Disk; CString s; if (disk->SDD.RemovableMedia) { s.LoadString(IDS_DISK_TYPE_BASIC); } else if (disk->bLoaded){ if (disk->Layout) { if (disk->Layout->PartitionStyle == PARTITION_STYLE_MBR) { if (disk->Layout->PartitionEntry->Mbr.PartitionType == PARTITION_LDM) { s.LoadString(IDS_DISK_TYPE_DYN); } else { s.LoadString(IDS_DISK_TYPE_BASIC); } } else if (disk->Layout->PartitionStyle == PARTITION_STYLE_GPT) { s = "GPT"; } } else { s = "RAW"; } } else { s = "Stopped"; } List->SetItem(nItem, 1, LVIF_TEXT, (LPCSTR)s, 0, 0, 0,0); return; } if (chain->bDynamic) { s.LoadString(IDS_DISK_TYPE_DYN); } else { s.LoadString(IDS_DISK_TYPE_BASIC); } List->SetItem(nItem, 1, LVIF_TEXT, (LPCSTR)s, 0, 0, 0,0); List->SetItem(nItem, 2, LVIF_TEXT, (LPCSTR)chain->FileSystem, 0, 0, 0,0); totalSize = chain->FssInfo.TotalAllocationUnits.QuadPart; usedSize = totalSize - chain->FssInfo.AvailableAllocationUnits.QuadPart; totalSize = totalSize * chain->FssInfo.BytesPerSector * chain->FssInfo.SectorsPerAllocationUnit; usedSize = usedSize * chain->FssInfo.BytesPerSector * chain->FssInfo.SectorsPerAllocationUnit; if (totalSize > (ULONGLONG) 10 * 1024 * 1024 * 1024) { totalSize = totalSize / ((ULONG)1024 * 1024 * 1024); usedSize = usedSize / ((ULONG)1024 * 1024 * 1024); sUnit = " GB"; } else if (totalSize > 10 * 1024 * 1024){ totalSize = totalSize / (1024 * 1024); usedSize = usedSize / (1024 * 1024); sUnit = " MB"; } else if (totalSize > 10 * 1024){ totalSize = totalSize / (1024); usedSize = usedSize / (1024); sUnit = " KB"; } else { sUnit = " B"; } sSize.Format("%I64u", totalSize); sSize += sUnit; List->SetItem(nItem, 3, LVIF_TEXT, (LPCSTR)sSize, 0, 0, 0,0); if (chain->bRecognized) { sSize.Format("%I64u", usedSize); sSize += sUnit; } List->SetItem(nItem, 4, LVIF_TEXT, (LPCSTR)sSize, 0, 0, 0,0); List->SetItem(nItem, 5, LVIF_TEXT, (LPCSTR)chain->EVP.Codepage, 0, 0, 0,0); } VOID Ext2InsertPartition( CListCtrl* List, PEXT2_DISK Disk, PEXT2_PARTITION Part ) { int nItem = 0, nImage = 0; nItem = List->GetItemCount(); nImage = 0; if (!Disk) { nItem = List->InsertItem( LVIF_PARAM|LVIF_IMAGE, nItem, NULL, 0, 0, nImage, (LPARAM)NULL); return; } if (!Part) { nItem = List->InsertItem( LVIF_PARAM|LVIF_IMAGE, nItem, NULL, 0, 0, nImage, (LPARAM)&Disk->Null); List->SetItem( nItem, 1, LVIF_TEXT, (LPCSTR)"RAW", 0, 0, 0,0); return; } nItem = List->InsertItem( LVIF_PARAM| LVIF_IMAGE, nItem, NULL, 0, 0, nImage, (LPARAM)Part); Ext2RefreshDVPT(List, Part, nItem); } VOID Ext2InsertDisk( CListCtrl *List, PEXT2_DISK Disk ) { UCHAR i; CHAR devName[64]; int nItem = 0, nImage = 0; sprintf(devName, "DISK %d", Disk->OrderNo); nItem = List->GetItemCount(); nItem = List->InsertItem( LVIF_PARAM|LVIF_IMAGE, nItem, NULL, 0, 0, nImage, (LPARAM)Disk); List->SetItem( nItem, 0, LVIF_TEXT, (LPCSTR)devName, 0, 0, 0,0); if (Disk->NumParts > 0) { for (i=0; i < Disk->NumParts; i++) { Ext2InsertPartition(List, Disk, &Disk->DataParts[i]); } } else { Ext2InsertPartition(List, Disk, NULL); } } VOID Ext2RefreshDVCM( CListCtrl *List, PEXT2_CDROM Cdrom, int nItem ) { ULONGLONG totalSize; CString sSize, sUnit, s; PEXT2_LETTER first = NULL; CString Letters = Ext2QueryVolumeLetterStrings( Cdrom->DrvLetters, &first); if (!Cdrom->bLoaded) { List->SetItem( nItem, 1, LVIF_TEXT, (LPCSTR)"Stopped", 0, 0, 0,0); return; } List->SetItem( nItem, 0, LVIF_TEXT, (LPCSTR)Letters, 0, 0, 0,0); if (Cdrom->bEjected) { return; } s.LoadString(IDS_DISK_TYPE_BASIC); List->SetItem(nItem, 1, LVIF_TEXT, (LPCSTR)s, 0, 0, 0,0); List->SetItem(nItem, 2, LVIF_TEXT, (LPCSTR)"CDFS", 0, 0, 0,0); totalSize = (ULONGLONG)Cdrom->DiskGeometry.Cylinders.QuadPart; totalSize = totalSize * Cdrom->DiskGeometry.TracksPerCylinder * Cdrom->DiskGeometry.SectorsPerTrack * Cdrom->DiskGeometry.BytesPerSector; if (totalSize > 1024 * 1024 * 1024) { totalSize = totalSize / (1024 * 1024 * 1024); sUnit = " GB"; } else if (totalSize > 1024 * 1024){ totalSize = totalSize / (1024 * 1024); sUnit = " MB"; } else if (totalSize > 1024){ totalSize = totalSize / (1024); sUnit = " KB"; } else { sUnit = " B"; } sSize.Format("%I64u", totalSize); sSize += sUnit; List->SetItem(nItem, 3, LVIF_TEXT, (LPCSTR)sSize, 0, 0, 0,0); sSize.Format("%I64u", totalSize); sSize += sUnit; List->SetItem(nItem, 4, LVIF_TEXT, (LPCSTR)sSize, 0, 0, 0,0); List->SetItem(nItem, 5, LVIF_TEXT, (LPCSTR)"", 0, 0, 0,0); List->SetItem(nItem, 6, LVIF_TEXT, (LPCSTR)"", 0, 0, 0,0); } VOID Ext2InsertCdromAsDisk( CListCtrl *List, PEXT2_CDROM Cdrom ) { CHAR devName[64]; int nItem = 0, nImage = 0; sprintf(devName, "CDROM %d", Cdrom->OrderNo); nItem = List->GetItemCount(); nItem = List->InsertItem( LVIF_PARAM|LVIF_IMAGE, nItem, NULL, 0, 0, nImage, (LPARAM)Cdrom); List->SetItem( nItem, 0, LVIF_TEXT, (LPCSTR)devName, 0, 0, 0,0); nItem = List->GetItemCount(); nImage = 0; if (Cdrom->bIsDVD) { nImage = IDI_DVD - IDI_FLOPPY; } else { nImage = IDI_CDROM - IDI_FLOPPY; } nItem = List->InsertItem( LVIF_PARAM|LVIF_IMAGE, nItem, NULL, 0, 0, nImage, (LPARAM)(&Cdrom->Magic[1])); Ext2RefreshDVCM(List, Cdrom, nItem); } VOID Ext2RefreshDiskList(CListCtrl *List) { List->DeleteAllItems(); ULONG i = 0; /* adding disks */ for (i=0; i < g_nDisks; i++) { Ext2InsertDisk(List, &gDisks[i]); Ext2InsertPartition(List, NULL, NULL); } /* adding cdroms */ for (i=0; i < g_nCdroms; i++) { Ext2InsertCdromAsDisk(List, &gCdroms[i]); Ext2InsertPartition(List, NULL, NULL); } } VOID Ext2CleanupVolumes() { PEXT2_VOLUME chain = gVols, next = NULL; while (chain) { next = chain->Next; if (chain->Extent) { free(chain->Extent); } free(chain); g_nVols--; chain = next; } ASSERT(g_nVols == 0); g_nVols = 0; gVols = NULL; } VOID Ext2LoadDrvLetter(PEXT2_LETTER drvLetter, CHAR cLetter) { if (drvLetter->bUsed) { return; } if (cLetter >= 'a' && cLetter <= 'z') { cLetter -= 0x20; } memset(drvLetter, 0, sizeof(EXT2_LETTER)); drvLetter->Letter = cLetter; Ext2QueryDrvLetter(drvLetter); } VOID Ext2LoadDrvLetters() { int i; for (i=0; i < 36; i++) { PEXT2_LETTER drvLetter = NULL; CHAR cLetter = 0; if (i < 10) { drvLetter = &drvDigits[i]; cLetter = '0' + i; } else { drvLetter = &drvLetters[i-10]; cLetter = 'A' + (i - 10); } Ext2LoadDrvLetter(drvLetter, cLetter); } } VOID Ext2CleanDrvLetter(PEXT2_LETTER drvLetter) { if (drvLetter->Extent) { free(drvLetter->Extent); drvLetter->Extent = NULL; } if (drvLetter->SDN) { free(drvLetter->SDN); drvLetter->SDN = NULL; } drvLetter->bUsed = FALSE; drvLetter->bTemporary = FALSE; drvLetter->DrvType = DRIVE_NO_ROOT_DIR; memset(drvLetter->SymLink, 0, MAX_PATH); } VOID Ext2CleanupDrvLetters() { int i = 0; for (i=0; i < 10; i++) { Ext2CleanDrvLetter(&drvDigits[i]); } for (i=0; i < 26; i++) { Ext2CleanDrvLetter(&drvLetters[i]); } } VOID Ext2DrvNotify(UCHAR drive, int mount) { DEV_BROADCAST_VOLUME dbv; DWORD target = BSM_APPLICATIONS; unsigned long drv = 0; if (drive >= 'A' && drive <= 'Z') drv = drive - 'A'; else if(drive >= 'a' && drive <= 'z') drv = drive - 'a'; else return; dbv.dbcv_size = sizeof( dbv ); dbv.dbcv_devicetype = DBT_DEVTYP_VOLUME; dbv.dbcv_reserved = 0; dbv.dbcv_unitmask = (1 << drv); dbv.dbcv_flags = DBTF_NET; BroadcastSystemMessage(BSF_IGNORECURRENTTASK | BSF_FORCEIFHUNG | BSF_NOHANG | BSF_NOTIMEOUTIFNOTHUNG, &target, WM_DEVICECHANGE, mount ? DBT_DEVICEARRIVAL : DBT_DEVICEREMOVECOMPLETE, (LPARAM)(DEV_BROADCAST_HDR *)&dbv ); } BOOL Ext2RemoveDrvLetter( PEXT2_LETTER drvLetter ) { CHAR drvPath[] = "A:\\\0"; CHAR dosPath[] = "A:\0"; BOOL rc = FALSE; if (!drvLetter->bUsed) { return TRUE; } dosPath[0] = drvPath[0] = drvLetter->Letter; rc = Ext2DefineDosDevice ( DDD_RAW_TARGET_PATH| DDD_REMOVE_DEFINITION| DDD_EXACT_MATCH_ON_REMOVE, dosPath, drvLetter->SymLink); DeleteVolumeMountPoint(drvPath); if (!rc) { return FALSE; } return TRUE; } CHAR Ext2QueryRegistryMountPoint ( CHAR * devName ) { DWORD i = 0; LONG status; HKEY hKey; DWORD drvSize; DWORD dosSize; DWORD valType; CHAR keyPath[MAX_PATH]; CHAR drvPath[MAX_PATH]; CHAR dosPath[64]; /* set dos deivce path */ strcpy (keyPath, "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\DOS Devices"); /* open session manager\dos devices */ status = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyPath, 0, KEY_ALL_ACCESS, &hKey) ; if (status != ERROR_SUCCESS) { return FALSE; } /* enum all values and compare devName ... */ while (status != ERROR_NO_MORE_ITEMS && i < 1024) { valType = REG_SZ; dosSize = 64; drvSize = MAX_PATH; status = RegEnumValue(hKey, i++, &dosPath[0], &dosSize, NULL, &valType, (LPBYTE)&drvPath[0], &drvSize); if (status == ERROR_SUCCESS) { if (_stricmp(devName, drvPath) == 0) { RegCloseKey(hKey); return dosPath[0]; } } } RegCloseKey(hKey); return 0; } BOOL Ext2SetRegistryMountPoint ( CHAR * dosPath, CHAR * devName, BOOL bSet ) { LONG status; HKEY hKey; CHAR keyPath[MAX_PATH]; CHAR drvPath[MAX_PATH]; /* set dos driver name */ sprintf(drvPath, "%c:", dosPath[0]); /* set dos deivce path */ strcpy (keyPath, "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\DOS Devices"); /* open session manager\dos devices */ status = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyPath, 0, KEY_ALL_ACCESS, &hKey) ; if (status != ERROR_SUCCESS) { return FALSE; } if (bSet) { /* set value */ status = RegSetValueEx( hKey, drvPath, 0, REG_SZ, (BYTE *)devName, strlen(devName) ); } else { /* delete key */ status = RegDeleteValue( hKey, drvPath ); } RegCloseKey(hKey); if (status != ERROR_SUCCESS) { return FALSE; } return TRUE; } VOID Ext2UpdateDrvLetter( PEXT2_LETTER drvLetter, PCHAR devPath ) { CHAR dosPath[] = "A:\0"; BOOL rc = 0; if (drvLetter->bUsed) { return; } dosPath[0] = drvLetter->Letter; rc = Ext2DefineDosDevice(DDD_RAW_TARGET_PATH, dosPath, devPath); if (rc) { Ext2DefineDosDevice ( DDD_RAW_TARGET_PATH| DDD_REMOVE_DEFINITION| DDD_EXACT_MATCH_ON_REMOVE, dosPath, devPath); } } BOOL Ext2AssignDrvLetter( PEXT2_LETTER drvLetter, PCHAR devPath, BOOL bMountMgr ) { CHAR dosPath[] = "A:\0"; CHAR drvPath[] = "A:\\\0"; CHAR volumeName[MAX_PATH]; BOOL rc = 0; if (drvLetter->bUsed) { return FALSE; } memset(volumeName, 0, MAX_PATH); dosPath[0] = drvPath[0] = drvLetter->Letter; rc = Ext2DefineDosDevice(DDD_RAW_TARGET_PATH, dosPath, devPath); if (rc) { /* Now it's done, since user only needs a temporary mount point */ if (!bMountMgr) { goto DrvMounted; } rc = GetVolumeNameForVolumeMountPoint ( drvPath, volumeName, MAX_PATH); Ext2DefineDosDevice ( DDD_RAW_TARGET_PATH| DDD_REMOVE_DEFINITION| DDD_EXACT_MATCH_ON_REMOVE, dosPath, devPath); if (rc) { rc = SetVolumeMountPoint(drvPath, volumeName); } } if (!rc) { return FALSE; } DrvMounted: drvLetter->bTemporary = !bMountMgr; Ext2QueryDrvLetter(drvLetter); return TRUE; } /* * Mount Manager Support Routines */ VOID Ext2AnsiToUnicode( CHAR * AnsiName, WCHAR* UniName, USHORT UniLength ) { USHORT NameLength = 0; NT::ANSI_STRING AnsiFilespec; NT::UNICODE_STRING UnicodeFilespec; memset(UniName, 0, sizeof(WCHAR) * UniLength); NameLength = strlen(AnsiName); ASSERT(NameLength < UniLength); AnsiFilespec.MaximumLength = AnsiFilespec.Length = NameLength; AnsiFilespec.Buffer = AnsiName; UnicodeFilespec.MaximumLength = UniLength * 2; UnicodeFilespec.Length = 0; UnicodeFilespec.Buffer = (PWSTR)UniName; NT::RtlAnsiStringToUnicodeString(&UnicodeFilespec, &AnsiFilespec, FALSE); } BOOL Ext2VolumeArrivalNotify(PCHAR VolumePath) { HANDLE hMountMgr = NULL; NT::IO_STATUS_BLOCK iosb; NT::NTSTATUS status; DWORD rc = 0; WCHAR volPath[MAX_PATH + 2]; PMOUNTMGR_TARGET_NAME target; target = (PMOUNTMGR_TARGET_NAME) volPath; Ext2AnsiToUnicode(VolumePath, &target->DeviceName[0], MAX_PATH); target->DeviceNameLength = (USHORT)wcslen(target->DeviceName) * 2; status = Ext2Open("\\Device\\MountPointManager", &hMountMgr, EXT2_DESIRED_ACCESS); if (!NT_SUCCESS(status)) { goto errorout; } status = NT::ZwDeviceIoControlFile( hMountMgr, NULL, NULL, NULL, &iosb, IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION, (PVOID)target, sizeof(USHORT) + target->DeviceNameLength, NULL, 0 ); if (!NT_SUCCESS(status)) { goto errorout; } errorout: Ext2Close(&hMountMgr); return NT_SUCCESS(status); } BOOL Ext2SymLinkRemoval(CHAR drvLetter) { HANDLE hMountMgr = NULL; NT::IO_STATUS_BLOCK iosb; NT::NTSTATUS status; DWORD rc = 0; WCHAR buffer[MAX_PATH], *dosName; PMOUNTMGR_MOUNT_POINT pmp = NULL; PMOUNTMGR_MOUNT_POINTS pms = NULL; memset(buffer, 0, sizeof(WCHAR) * MAX_PATH); pmp = (PMOUNTMGR_MOUNT_POINT) buffer; pmp->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT); pmp->SymbolicLinkNameLength = 14 * sizeof(WCHAR); dosName = (WCHAR *) (pmp + 1); swprintf_s(dosName, MAX_PATH - sizeof(MOUNTMGR_MOUNT_POINT), L"\\DosDevices\\%c:\0", drvLetter); status = Ext2Open("\\Device\\MountPointManager", &hMountMgr, EXT2_DESIRED_ACCESS); if (!NT_SUCCESS(status)) { goto errorout; } status = NT::ZwDeviceIoControlFile( hMountMgr, NULL, NULL, NULL, &iosb, IOCTL_MOUNTMGR_DELETE_POINTS, (PVOID)pmp, sizeof(WCHAR) * MAX_PATH, (PVOID)pmp, sizeof(WCHAR) * MAX_PATH ); if (!NT_SUCCESS(status)) { goto errorout; } errorout: Ext2Close(&hMountMgr); return NT_SUCCESS(status); } BOOL Ext2SetVolumeMountPoint ( CHAR * dosPath, CHAR * devName ) { HANDLE hMountMgr; NT::IO_STATUS_BLOCK iosb; NT::NTSTATUS status; DWORD rc = 0; CHAR dosDevice[MAX_PATH]; WCHAR volPath[MAX_PATH]; WCHAR devPath[MAX_PATH]; PMOUNTMGR_CREATE_POINT_INPUT mcpi = NULL; USHORT lmcpi = 0, lvolp = 0, ldevp = 0; memset(dosDevice, 0, MAX_PATH); memset(volPath, 0, MAX_PATH * sizeof(WCHAR)); memset(devPath, 0, MAX_PATH * sizeof(WCHAR)); /* covert names to unicode */ sprintf(dosDevice, "\\DosDevices\\%c:", toupper(dosPath[0])); Ext2AnsiToUnicode(dosDevice, volPath, MAX_PATH); Ext2AnsiToUnicode(devName, devPath, MAX_PATH); ldevp = (USHORT)wcslen(devPath) * 2; lvolp = (USHORT)wcslen(volPath) * 2; lmcpi = sizeof(MOUNTMGR_CREATE_POINT_INPUT) + lvolp + ldevp; /* initialize MMGR_CREATE_MOUNT_POINT_INPUT */ mcpi = (PMOUNTMGR_CREATE_POINT_INPUT) malloc(lmcpi); if (mcpi == NULL) { status = STATUS_UNSUCCESSFUL; goto errorout; } mcpi->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT); mcpi->SymbolicLinkNameLength = lvolp; mcpi->DeviceNameOffset = mcpi->SymbolicLinkNameOffset + lvolp; mcpi->DeviceNameLength = ldevp; memcpy((PCHAR)mcpi + mcpi->SymbolicLinkNameOffset, volPath, lvolp); memcpy((PCHAR)mcpi + mcpi->DeviceNameOffset, devPath, ldevp); /* open MountMgr */ status = Ext2Open("\\Device\\MountPointManager", &hMountMgr, EXT2_DESIRED_ACCESS); if (!NT_SUCCESS(status)) { goto errorout; } /* ioctl .... */ status = NT::ZwDeviceIoControlFile( hMountMgr, NULL, NULL, NULL, &iosb, IOCTL_MOUNTMGR_CREATE_POINT, (PVOID)mcpi, lmcpi, NULL, 0 ); if (!NT_SUCCESS(status)) { goto errorout; } Ext2Close(&hMountMgr); errorout: if (mcpi) { free(mcpi); } return NT_SUCCESS(status); } UCHAR Ext2QueryMountPoint( CHAR * volume ) { NT::IO_STATUS_BLOCK iosb; NT::NTSTATUS status; ULONG lp, lps; ULONG i; HANDLE hMountMgr = 0; NT::UNICODE_STRING volPoint; NT::UNICODE_STRING VolumeName; WCHAR VolumeBuffer[MAX_PATH]; PMOUNTMGR_MOUNT_POINT point = NULL; PMOUNTMGR_MOUNT_POINTS points = NULL; UCHAR drvLetter = 0; memset(VolumeBuffer, 0, MAX_PATH * sizeof(WCHAR)); Ext2AnsiToUnicode(volume, VolumeBuffer, MAX_PATH); VolumeName.MaximumLength = MAX_PATH; VolumeName.Length = (USHORT)wcslen(VolumeBuffer) * 2; VolumeName.Buffer = VolumeBuffer; status = Ext2Open("\\Device\\MountPointManager", &hMountMgr, EXT2_DESIRED_ACCESS); if (!NT_SUCCESS(status)) { goto errorout; } lp = VolumeName.Length + sizeof(MOUNTMGR_MOUNT_POINT) + 2; point = (PMOUNTMGR_MOUNT_POINT)malloc(lp); if (point == NULL) { goto errorout; } /* initialize MountMgr ioctl input structure */ memset(point, 0, lp); point->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT); point->DeviceNameLength = VolumeName.Length; RtlMoveMemory((PCHAR) point + point->DeviceNameOffset, VolumeBuffer, VolumeName.Length); lps = 1024; Again: /* allocate ioctl output structure */ points = (PMOUNTMGR_MOUNT_POINTS)malloc(lps); if (!points) { goto errorout; } RtlZeroMemory(points, lps); /* could MoungMgr to create volume points for us ? */ status = NT::ZwDeviceIoControlFile( hMountMgr, NULL, NULL, NULL, &iosb, IOCTL_MOUNTMGR_QUERY_POINTS, point, lp, points, lps ); if (status == STATUS_BUFFER_OVERFLOW) { lps = (ULONG)iosb.Information + 2; free(points); points = NULL; goto Again; } for (i = 0; i < points->NumberOfMountPoints; i++) { volPoint.Length = volPoint.MaximumLength = points->MountPoints[i].SymbolicLinkNameLength; volPoint.Buffer = (PWSTR) ((PCHAR) points + points->MountPoints[i].SymbolicLinkNameOffset); #if 0 if (MOUNTMGR_IS_VOLUME_NAME(&volPoint)) { if (length) { if (*length >= volPoint.Length + 2) { *length = volPoint.Length + 2; memcpy(vp, volPoint.Buffer, volPoint.Length); vp[1] = (WCHAR)'\\'; vp[volPoint.Length / 2] = (WCHAR)'\\'; vp[*length / 2] = 0; } else { *length = 0; } } } #endif if (MOUNTMGR_IS_DRIVE_LETTER(&volPoint)) { drvLetter = (UCHAR)(volPoint.Buffer[12]); break; } } errorout: if (points) { free(points); } if (point) { free(point); } if (hMountMgr) { Ext2Close(&hMountMgr); } return drvLetter; } PEXT2_LETTER Ext2GetDrvLetterPoint(CHAR drvChar) { PEXT2_LETTER drvLetter = NULL; if (drvChar >= '0' && drvChar <= '9') { drvLetter = &drvDigits[drvChar - '0']; } else if (drvChar >= 'A' && drvChar <= 'Z') { drvLetter = &drvLetters[drvChar - 'A']; } else { drvLetter = NULL; } return drvLetter; } BOOL Ext2InsertMountPoint( CHAR * volume, UCHAR drvChar, BOOL bGlobal ) { CHAR volumeName[MAX_PATH]; CHAR dosPath[] = "A:\0"; CHAR drvPath[] = "A:\\\0"; BOOL rc = FALSE; dosPath[0] = drvPath[0] = drvChar & 0x7F; rc = Ext2DefineDosDevice(DDD_RAW_TARGET_PATH, dosPath, volume); if (rc && bGlobal) { rc = GetVolumeNameForVolumeMountPoint ( drvPath, volumeName, MAX_PATH); Ext2DefineDosDevice ( DDD_RAW_TARGET_PATH| DDD_REMOVE_DEFINITION, dosPath, volume); if (rc) { rc = SetVolumeMountPoint(drvPath, volumeName); } } return rc; } VOID Ext2RemoveMountPoint( PEXT2_LETTER drvLetter, BOOL bPermanent ) { CHAR drvPath[] = "A:\\\0"; CHAR dosPath[] = "A:\0"; dosPath[0] = drvPath[0] = drvLetter->Letter; Ext2DefineDosDevice ( DDD_RAW_TARGET_PATH| DDD_REMOVE_DEFINITION| DDD_EXACT_MATCH_ON_REMOVE, dosPath, drvLetter->SymLink); if (bPermanent) { DeleteVolumeMountPoint(drvPath); } Ext2CleanDrvLetter(drvLetter); Ext2QueryDrvLetter(drvLetter); } BOOL Ext2RefreshVolumePoint( CHAR * volume, UCHAR drvChar ) { PEXT2_LETTER drvLetter = NULL; BOOL rc = TRUE; CHAR cLetter = 0; cLetter = Ext2QueryMountPoint(volume); if (cLetter) { goto errorout; } else { rc = FALSE; } if (drvChar & 0x7F) { if (Ext2InsertMountPoint(volume, drvChar & 0x7F, TRUE)) { return TRUE; } } if (!rc) { Ext2VolumeArrivalNotify(volume); } cLetter = Ext2QueryMountPoint(volume); if (!cLetter && (cLetter != (drvChar & 0x7F))) { Ext2InsertMountPoint(volume, drvChar & 0x7F, TRUE); } cLetter = Ext2QueryMountPoint(volume); if (cLetter) { Ext2InsertMountPoint(volume, cLetter, FALSE); } rc = (cLetter > 0) ? TRUE: FALSE; errorout: return rc; } BOOL Ext2IsDrvLetterAvailable(CHAR drive) { CHAR symLink[MAX_PATH] = {0}; UINT drvType; drvType = Ext2QueryDrive(drive, symLink); if (drvType == DRIVE_NO_ROOT_DIR) { return TRUE; } return FALSE; } CHAR Ext2GetFirstAvailableDrvLetter() { int i; for (i = 2; i < 24; i++) { if (Ext2IsDrvLetterAvailable('A' + i)) return ('A' + i); } return 0; } BOOL Ext2NotifyVolumePoint( PEXT2_VOLUME volume, UCHAR drvChar ) { PEXT2_LETTER letter; UCHAR mounted = 0; BOOL rc = FALSE; PCHAR Name = NULL; drvChar = (UCHAR)toupper(drvChar); letter = &drvLetters[drvChar - 'A']; if (volume->Part) { Name = &volume->Part->Name[0]; } else { Name = &volume->Name[0]; } /* do drive update */ if (Ext2IsDrvLetterAvailable(drvChar)) Ext2UpdateDrvLetter(letter, Name); rc = Ext2VolumeArrivalNotify(Name); Sleep(500); mounted = Ext2QueryMountPoint(Name); if (mounted) { rc = TRUE; goto errorout; } if (!Ext2IsDrvLetterAvailable(drvChar)) { drvChar = Ext2GetFirstAvailableDrvLetter(); if ((drvChar|0x20) >= 'a' && (drvChar | 0x20) <= 'z') { letter = &drvLetters[drvChar - 'A']; } else { letter = NULL; } } if (letter) { rc = Ext2AssignDrvLetter(letter, Name, FALSE); } errorout: return rc; } #define EXT2_MANAGER_NAME "Ext2 Volume Manager" BOOL Ext2RunMgrForCurrentUserXP() { HKEY key ; CHAR keyPath[MAX_PATH] ; LONG status ; DWORD type, len = MAX_PATH; BOOL rc = FALSE; CHAR appPath[MAX_PATH] ; GetModuleFileName(NULL, appPath, MAX_PATH - 6); strcat(appPath, " -quiet"); strcpy (keyPath, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run") ; status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, keyPath, 0, KEY_ALL_ACCESS, &key) ; if (status != ERROR_SUCCESS) { return FALSE; } status = RegQueryValueEx( key, EXT2_MANAGER_NAME, 0, &type, (BYTE *)appPath, &len); if (status != ERROR_SUCCESS) { goto errorout; } rc = TRUE; errorout: RegCloseKey (key) ; return rc; } BOOL Ext2SetAppAutorunXP(BOOL bInstall) { BOOL rc = FALSE; HKEY key ; CHAR keyPath[MAX_PATH] ; LONG status ; CHAR appPath[MAX_PATH] ; GetModuleFileName(NULL, appPath, MAX_PATH - 6); strcat(appPath, " -quiet"); strcpy (keyPath, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run") ; status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, keyPath, 0, KEY_ALL_ACCESS, &key) ; if (status != ERROR_SUCCESS) { return FALSE; } if (!bInstall) { status = RegDeleteValue (key, EXT2_MANAGER_NAME) ; if (status != ERROR_SUCCESS) { goto errorout; } } else { status = RegSetValueEx( key, EXT2_MANAGER_NAME, 0, REG_SZ, (BYTE *)appPath, strlen(appPath)); if (status != ERROR_SUCCESS) { goto errorout; } } rc = TRUE; errorout: RegCloseKey (key) ; return rc; } CHAR *Ext2QueryAutoUserList() { int rc = TRUE; HKEY hKey; CHAR keyPath[MAX_PATH]; CHAR *userList = NULL; LONG status, type, len; /* Open ext2fsd sevice key */ strcpy (keyPath, "SYSTEM\\CurrentControlSet\\Services\\Ext2Fsd\\Parameters") ; status = ::RegOpenKeyEx (HKEY_LOCAL_MACHINE, keyPath, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &hKey) ; if (status != ERROR_SUCCESS) { rc = FALSE; goto errorout; } /* query autorun user list */ len = PAGE_SIZE - 1; userList = new CHAR[len + 1]; if (!userList) goto errorout; memset(userList, 0, len + 1); status = RegQueryValueEx( hKey, "AutorunUsers", 0, (LPDWORD)&type, (BYTE *)userList, (LPDWORD)&len); errorout: RegCloseKey(hKey); return userList; } BOOL Ext2SetAutoRunUserList(CHAR *userList) { HKEY key; CHAR keyPath[MAX_PATH] ; LONG status; strcpy (keyPath, "SYSTEM\\CurrentControlSet\\Services\\Ext2Fsd\\Parameters") ; status = ::RegOpenKeyEx (HKEY_LOCAL_MACHINE, keyPath, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &key) ; if (status != ERROR_SUCCESS) { goto errorout; } status = RegSetValueEx( key, "AutorunUsers", 0, REG_SZ, (BYTE *)userList, strlen(userList)); if (status != ERROR_SUCCESS) { goto errorout; } errorout: RegCloseKey(key) ; return (status == ERROR_SUCCESS); } TCHAR * Ext2StrStr(TCHAR *s, TCHAR *t) { int ls = _tcslen(s), lt = _tcslen(t), i; for (i = 0; i + lt <= ls; i++) { if (0 == _tcsnicmp(&s[i], t, lt)) return &s[i]; } return NULL; } BOOL Ext2RunMgrForCurrentUserVista() { CHAR *userList = NULL, *user, e; CHAR userName[256] = {0}; DWORD userLen = 255; BOOL rc = FALSE; if (!GetUserName(userName, &userLen)) return FALSE; userList = Ext2QueryAutoUserList(); if (!userList) return FALSE; user = userList; while (user = Ext2StrStr(user, userName)) { if (user > userList) { e = user[-1]; if (e != ',' && e != ';') { user = user + strlen(userName); continue; } } e = user[strlen(userName)]; if (!e || e == ',' || e == ';') { rc = TRUE; goto errorout; } user = user + strlen(userName); } errorout: if (userList) delete [] userList; return rc; } BOOL Ext2SetAppAutorunVista(BOOL bAutorun) { CHAR *userList = NULL, *user, *e; CHAR userName[256] = {0}; DWORD userLen = 255; BOOL changed = FALSE; if (!GetUserName(userName, &userLen)) return FALSE; userList = Ext2QueryAutoUserList(); if (!userList) return FALSE; if (bAutorun) { user = userList; while (user = Ext2StrStr(user, userName)) { if (user > userList) { e = user-1; if (*e != ',' && *e != ';') { user = user + strlen(userName); continue; } } e = &user[strlen(userName)]; if (!*e || *e == ',' || *e == ';') { goto errorout; } user = user + strlen(userName); } e = &userList[strlen(userList) - 1]; if (e > userList && *e != ',' && *e != ';') { strcat_s(userList, PAGE_SIZE - 1, ";"); } strcat_s(userList, PAGE_SIZE - 1, userName); strcat_s(userList, PAGE_SIZE - 1, ";"); changed = TRUE; } else { user = userList; while (user = Ext2StrStr(user, userName)) { if (user > userList) { e = user - 1; if (*e != ',' && *e != ';') { user = user + strlen(userName); continue; } } e = &user[strlen(userName)]; if (!*e) { memset(user, 0, strlen(userName) + 1); changed = TRUE; } else if (*e == ',' || *e == ';') { memmove(user, e + 1, strlen(e)); changed = TRUE; } else { user = user + strlen(userName); } } } if (changed) changed = Ext2SetAutoRunUserList(userList); else changed = TRUE; errorout: if (userList) delete []userList; return TRUE; } BOOL Ext2SetAppAutorun(BOOL bAutorun) { if (IsWindowsVistaOrGreater()) return Ext2SetAppAutorunVista(bAutorun); return Ext2SetAppAutorunXP(bAutorun); } BOOL Ext2RunMgrForCurrentUser() { if (IsWindowsVistaOrGreater()) return Ext2RunMgrForCurrentUserVista(); return Ext2RunMgrForCurrentUserXP(); } #define SERVICE_CMD_LENGTH (MAX_PATH * 2) int Ext2SetManagerAsService(BOOL bInstall) { SC_HANDLE hService; SC_HANDLE hManager; CHAR Target[SERVICE_CMD_LENGTH]; // get the filename of this executable if (GetModuleFileName(NULL, Target, SERVICE_CMD_LENGTH - 20) == 0) { AfxMessageBox("Unable to install Ext2Mgr as service", MB_ICONEXCLAMATION | MB_OK); return FALSE; } // append parameters to the end of the path: strcat(Target, " -service -hide"); // open Service Control Manager hManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (hManager == NULL) { AfxMessageBox("Ext2Mgr: cannot open Service Control Manager", MB_ICONEXCLAMATION | MB_OK); return FALSE; } if (bInstall) { // now create service entry for Ext2Mgr hService = CreateService( hManager, // SCManager database "Ext2Mgr", // name of service "Ext2 Volume Manger", // name to display SERVICE_ALL_ACCESS, // desired access SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, // service type SERVICE_AUTO_START, // start type SERVICE_ERROR_NORMAL, // error control type Target, // service's binary NULL, // no load ordering group NULL, // no tag identifier NULL, // dependencies NULL, // LocalSystem account NULL); // no password if (hService == NULL) { DWORD error = GetLastError(); if (error == ERROR_SERVICE_EXISTS) { AfxMessageBox("Ext2Mgr service is already registered.", MB_ICONEXCLAMATION | MB_OK); } else { AfxMessageBox("Ext2Mgr service couldn't be registered.", MB_ICONEXCLAMATION | MB_OK); } } else { CloseServiceHandle(hService); // got Ext2Mgr installed as a service AfxMessageBox( "Ext2Mgr service was successfully registered. \n\n" "You can modify the default settings and start/stop it from Control Panel.\n" "The service will automatically run the next time when system is restarted.\n", MB_ICONINFORMATION | MB_OK); } Ext2SetAppAutorun(FALSE); } else { /* open the service of Ext2Mgr */ hService = OpenService( hManager, "Ext2Mgr", SERVICE_ALL_ACCESS ); if (hService != NULL) { #if 0 SERVICE_STATUS status; // stop the service if (ControlService(hService, SERVICE_CONTROL_STOP, &status)) { while(QueryServiceStatus(hService, &status)) { if (status.dwCurrentState == SERVICE_STOP_PENDING) { Sleep(1000); } else { break; } } if (status.dwCurrentState != SERVICE_STOPPED) { AfxMessageBox("Could not stop Ext2Mgr service !", MB_ICONEXCLAMATION | MB_OK); } } #endif // remove the service from the SCM if (DeleteService(hService)) { AfxMessageBox("The Ext2Mgr service has been unregistered.", MB_ICONINFORMATION | MB_OK); } else { DWORD error = GetLastError(); if (error == ERROR_SERVICE_MARKED_FOR_DELETE) { AfxMessageBox("Ext2Mgr service is already unregistered", MB_ICONEXCLAMATION | MB_OK); } else { AfxMessageBox("Ext2Mgr service could not be unregistered", MB_ICONEXCLAMATION | MB_OK); } } CloseServiceHandle(hService); } } CloseServiceHandle(hManager); return TRUE; } BOOL g_bAutoRemoveDeadLetters = TRUE; VOID Ext2AddLetterMask(ULONGLONG LetterMask) { Ext2DrvLetters[1] |= LetterMask; } VOID Ext2AutoRemoveDeadLetters() { ULONGLONG LetterMask = Ext2DrvLetters[0]; DWORD i, j; PEXT2_DISK disk; PEXT2_PARTITION part; PEXT2_CDROM cdrom; if (LetterMask != -1) { AfxMessageBox("Different Mask"); } for (i = 0; i < g_nDisks; i++) { disk = &gDisks[i]; if (disk->DataParts == NULL) { continue; } for (j=0; j < disk->NumParts; j++) { part = &disk->DataParts[j]; if (part) { LetterMask &= ~(part->DrvLetters); } } } for (i = 0; i < g_nCdroms; i++) { cdrom = &gCdroms[i]; LetterMask &= ~(cdrom->DrvLetters); } for (i=0; i < 10; i++) { if (drvDigits[i].bUsed && (drvDigits[i].Extent == NULL) && (LetterMask & (((ULONGLONG) 1) << (i + 32)) ) ) { if (drvDigits[i].bInvalid && drvDigits[i].DrvType == DRIVE_FIXED) { LetterMask &= (~(((ULONGLONG) 1) << (i + 32))); Ext2RemoveMountPoint(&drvDigits[i], FALSE); Ext2RemoveDosSymLink(drvDigits[i].Letter); } } } for (i=2; i <26; i++) { if (drvLetters[i].bUsed && (drvLetters[i].Extent == NULL) && (LetterMask & (((ULONGLONG) 1) << i)) ) { if (drvLetters[i].bInvalid && drvLetters[i].DrvType == DRIVE_FIXED) { LetterMask &= (~(((ULONGLONG) 1) << i)); Ext2RemoveMountPoint(&drvLetters[i], FALSE); Ext2RemoveDosSymLink(drvLetters[i].Letter); } } } // Ext2DrvLetters[0] = LetterMask; } BOOL Ext2RemoveDosSymLink(CHAR drvChar) { EXT2_MOUNT_POINT E2MP; NT::NTSTATUS status; HANDLE handle = NULL; NT::IO_STATUS_BLOCK iosb; Ext2SymLinkRemoval(drvChar); memset(&E2MP, 0, sizeof(EXT2_MOUNT_POINT)); E2MP.Magic = EXT2_APP_MOUNTPOINT_MAGIC; E2MP.Command = APP_CMD_DEL_DOS_SYMLINK; E2MP.Link[0] = (USHORT) drvChar; status = Ext2Open("\\DosDevices\\Ext2Fsd", &handle, EXT2_DESIRED_ACCESS); if (!NT_SUCCESS(status)) { goto errorout; } status = NT::ZwDeviceIoControlFile( handle, NULL, NULL, NULL, &iosb, IOCTL_APP_MOUNT_POINT, &E2MP, sizeof(EXT2_MOUNT_POINT), &E2MP, sizeof(EXT2_MOUNT_POINT) ); errorout: Ext2Close(&handle); return NT_SUCCESS(status); }