mirror of
https://github.com/bobranten/Ext4Fsd.git
synced 2025-10-30 13:28:31 -05:00
5513 lines
139 KiB
C++
5513 lines
139 KiB
C++
|
|
#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);
|
|
}
|