ce que vous affichez \Device\0000010f
c'est AOP (Physical Device Object) créé par un chauffeur de bus (il a drapeau DO_BUS_ENUMERATED_DEVICE
)
à elle peut être joint quelques FDO (Objet de périphérique fonctionnel). si cela est de la pile de stockage (basé sur CompatibleIDs chaînes renvoyées par le dispositif de bus pour ce AOP) typique nom FDO ont une forme \Device\Harddisk%d\DR%d
et bien connu lien symbolique vers elle \Device\Harddisk%d\Partition0
pilote de disque FDO Énumérer partitions sur le volume et pour chaque partition créer AOP objet périphérique (avec bien connu lien symbolique \Device\Harddisk%d\Partition%d
où le numéro de partition toujours> 0, Partition0 est reportez-vous à disque entier FDO)
partition habituelle est le même que le volume, mais pas toujours (Partitions and Volumes) noter également IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
- il revenir ensemble de structures DISK_EXTENT
- regardez ici pour DiskNumber -The number of the disk that contains this extent.
si le volume peut placé sur plusieurs disques. mais dans 99% + IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
vous de retour seulement unDISK_EXTENT
donc ce que vous pouvez faire si vous avez chemin de PDO dans la pile de stockage?
- ouvrir l'appareil - si l'utilisation
ZwOpenFile
(bien sûr cela a fonctionné en mode utilisateur), nous pouvons utiliser \Device\0000010f
comme il est. si nous voulons utiliser win32 api nous avons besoin d'utiliser le préfixe \\?\GLOBALROOT
pour tous les noms. vraiment que nous ouvrons par ce bus AOP mais parce que le disque FDO est attaché à AOP toutes nos demandes seront envoyés via FDO et traitée ici. accès souhaité?SYNCHRONIZE
est suffisant (en cas CreateFile
si nous fixons pas FILE_FLAG_OVERLAPPED
api ce drapeau ajouter implicitement à DESIRED_ACCESS
)
- envoyer
IOCTL_STORAGE_GET_DEVICE_NUMBER
à l'appareil. vérifier que DeviceType == FILE_DEVICE_DISK && sdn.PartitionNumber == 0
- envoyer
IOCTL_DISK_GET_DRIVE_LAYOUT_EX
pour obtenir un tableau de taille variable de PARTITION_INFORMATION_EX
structures
- sur la base
DeviceNumber
(que nous obtenons à l'étape 2) et PartitionNumber
(que nous obtenons à l'étape 3) Format lien symbolique vers partition AOP-\\?\GLOBALROOT\Device\Harddisk%d\Partition%d
- partition ouverte AOP avec accès
SYNCHRONIZE
(assez parce que tous IOCTL que nous utilisons ont FILE_ANY_ACCESS
de type
- envoyer
IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
partitionner
- maintenant, nous devons gérer au dispositif MountManager (
\\.\MountPointManager
) pour lui envoyer IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH
cette IOCTL défini dans mountmgr.h
en entrée, il nécessite MOUNTDEV_NAME
que nous obtenons à l'étape 6. sur la production que nous recevons MOUNTMGR_VOLUME_PATHS
structure (également définie dans mountmgr.h
) Sinon, nous pouvons utiliser IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS
- si tout ok nous avons obtenu la liste des lettres de lecteur comme C:
, D:
, etc ..
- pour les lecteurs de disque énumèrent dans le système, nous pouvons utiliser
CM_Get_Device_ID_ListW
avec {4d36e967-e325-11ce-bfc1-08002be10318}
filtre, ouvert tous les appareils exemple par CM_Locate_DevNodeW
et enfin interroger pour DEVPKEY_Device_PDOName
par appel CM_Get_DevNode_Property
ok, ici l'exemple de code correct qui fait tout ceci:
#include <mountmgr.h>
// guz == 0 always, volatile for prevent CL "optimization" - it can drop alloca(0) call
static volatile UCHAR guz;
ULONG QueryPartitionW32(HANDLE hPartition, HANDLE hMountManager)
{
MOUNTDEV_STABLE_GUID guid;
ULONG dwBytesRet;
if (DeviceIoControl(hPartition, IOCTL_MOUNTDEV_QUERY_STABLE_GUID, 0, 0, &guid, sizeof(guid), &dwBytesRet, NULL))
{
DbgPrint("StableGuid = \\\\?\\Volume{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
guid.StableGuid.Data1, guid.StableGuid.Data2, guid.StableGuid.Data3,
guid.StableGuid.Data4[0],
guid.StableGuid.Data4[1],
guid.StableGuid.Data4[2],
guid.StableGuid.Data4[3],
guid.StableGuid.Data4[4],
guid.StableGuid.Data4[5],
guid.StableGuid.Data4[6],
guid.StableGuid.Data4[7]
);
}
// assume NumberOfDiskExtents == 1
VOLUME_DISK_EXTENTS vde;
if (DeviceIoControl(hPartition, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, 0, 0, &vde, sizeof(vde), &dwBytesRet, 0))
{
if (vde.NumberOfDiskExtents)
{
DbgPrint("ofs=%I64u, len=%I64u\n", vde.Extents->StartingOffset.QuadPart, vde.Extents->ExtentLength.QuadPart);
}
}
PVOID stack = alloca(guz);
union {
PVOID buf;
PMOUNTDEV_NAME pmdn;
};
ULONG err;
ULONG cb = 0, rcb = sizeof(MOUNTDEV_NAME) + 0x10, InputBufferLength;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (DeviceIoControl(hPartition, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, 0, 0, buf, cb, &dwBytesRet, NULL))
{
DbgPrint("%.*S\n", pmdn->NameLength >> 1, pmdn->Name);
union {
PVOID pv;
PMOUNTMGR_VOLUME_PATHS pmvp;
};
cb = 0, rcb = sizeof(MOUNTMGR_VOLUME_PATHS) + 0x10, InputBufferLength = sizeof(MOUNTDEV_NAME) + pmdn->NameLength;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(pv = alloca(rcb - cb), pmdn);
}
if (DeviceIoControl(hMountManager, IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH,
pmdn, InputBufferLength, pv, cb, &dwBytesRet, NULL))
{
PWSTR sz = pmvp->MultiSz;
while(*sz)
{
DbgPrint("%S\n", sz);
sz += 1 + wcslen(sz);
}
return NOERROR;
}
rcb = sizeof(MOUNTMGR_VOLUME_PATHS) + pmvp->MultiSzLength;
} while ((err = GetLastError()) == ERROR_MORE_DATA);
break;
}
rcb = sizeof(MOUNTDEV_NAME) + pmdn->NameLength;
} while ((err = GetLastError()) == ERROR_MORE_DATA);
return err;
}
ULONG EnumDiskPartitionsW32(HANDLE hDisk, HANDLE hMountManager)
{
STORAGE_DEVICE_NUMBER sdn;
ULONG dwBytesRet;
if (!DeviceIoControl(hDisk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesRet, NULL))
{
return GetLastError();
}
if (sdn.DeviceType != FILE_DEVICE_DISK || sdn.PartitionNumber != 0)
{
return ERROR_GEN_FAILURE;
}
WCHAR sz[128], *c = sz + swprintf(sz, L"\\\\?\\GLOBALROOT\\Device\\Harddisk%d\\Partition", sdn.DeviceNumber);
PVOID stack = alloca(guz);
union {
PVOID buf;
PDRIVE_LAYOUT_INFORMATION_EX pdli;
};
ULONG cb = 0, rcb, PartitionCount = 4;
for (;;)
{
if (cb < (rcb = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[PartitionCount])))
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, buf, cb, &dwBytesRet, NULL))
{
if (PartitionCount = pdli->PartitionCount)
{
PPARTITION_INFORMATION_EX PartitionEntry = pdli->PartitionEntry;
do
{
if (!PartitionEntry->PartitionNumber)
{
continue;
}
_itow(PartitionEntry->PartitionNumber, c, 10);
DbgPrint("%S\n", sz);
HANDLE hPartition = CreateFile(sz, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hPartition != INVALID_HANDLE_VALUE)
{
QueryPartitionW32(hPartition, hMountManager);
CloseHandle(hPartition);
}
} while (PartitionEntry++, --PartitionCount);
}
return NOERROR;
}
switch (ULONG err = GetLastError())
{
case ERROR_MORE_DATA:
PartitionCount = pdli->PartitionCount;
continue;
case ERROR_BAD_LENGTH:
case ERROR_INSUFFICIENT_BUFFER:
PartitionCount <<= 1;
continue;
default:
return err;
}
}
}
void DiskEnumW32(HANDLE hMountManager)
{
static const WCHAR DEVCLASS_DISK[] = L"{4d36e967-e325-11ce-bfc1-08002be10318}";
enum { flags = CM_GETIDLIST_FILTER_CLASS|CM_GETIDLIST_FILTER_PRESENT };
ULONG len;
if (!CM_Get_Device_ID_List_SizeW(&len, DEVCLASS_DISK, flags))
{
PWSTR buf = (PWSTR)alloca(len * sizeof(WCHAR));
if (!CM_Get_Device_ID_ListW(DEVCLASS_DISK, buf, len, flags))
{
PVOID stack = buf;
static const WCHAR prefix[] = L"\\\\?\\GLOBALROOT";
ULONG cb = 0, rcb = sizeof(prefix) + 0x20;
while (*buf)
{
DbgPrint("%S\n", buf);
DEVINST dnDevInst;
if (!CM_Locate_DevNodeW(&dnDevInst, buf, CM_LOCATE_DEVNODE_NORMAL))
{
DEVPROPTYPE PropertyType;
int err;
union {
PVOID pv;
PWSTR sz;
PBYTE pb;
};
do
{
if (cb < rcb)
{
rcb = cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack);
}
rcb -= sizeof(prefix) - sizeof(WCHAR);
if (!(err = CM_Get_DevNode_PropertyW(dnDevInst, &DEVPKEY_Device_PDOName, &PropertyType,
pb + sizeof(prefix) - sizeof(WCHAR), &rcb, 0)))
{
if (PropertyType == DEVPROP_TYPE_STRING)
{
memcpy(pv, prefix, sizeof(prefix) - sizeof(WCHAR));
DbgPrint("%S\n", sz);
HANDLE hDisk = CreateFile(sz, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hDisk != INVALID_HANDLE_VALUE)
{
EnumDiskPartitionsW32(hDisk, hMountManager);
CloseHandle(hDisk);
}
}
else
{
err = ERROR_GEN_FAILURE;
}
break;
}
rcb += sizeof(prefix) - sizeof(WCHAR);
} while (err == CR_BUFFER_SMALL);
}
buf += 1 + wcslen(buf);
}
}
}
}
void DiskEnumW32()
{
HANDLE hMountManager = CreateFile(MOUNTMGR_DOS_DEVICE_NAME, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hMountManager != INVALID_HANDLE_VALUE)
{
DiskEnumW32(hMountManager);
CloseHandle(hMountManager);
}
}
Il n'y a pas de correspondance 1: 1 pour cela, vous pouvez avoir plusieurs lettres de lecteur montées sur le périphérique physique. Mieux vaut parcourir les lettres de lecteur un par un et trouver leurs dispositifs physiques. –
@JonathanPotter, bien sûr, mais il y a un mappage 1: N, et dans ce cas, j'ai besoin de toutes les partitions montées sur ce périphérique (ou vice versa - périphérique de partition, n'a pas d'importance). Ok - "Mieux vaut parcourir les lettres de lecteur un par un et trouver leurs dispositifs physiques" - comment? – Tar
@Tar: Il n'y a pas de correspondance 1: N non plus. Un volume n'a pas besoin d'avoir une lettre de lecteur assignée. Les lettres de lecteur sont des restes des jours où MS DOS était nouveau. – IInspectable