The Uniqueness of IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
The documentation on IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
is a bit confusing... exactly what kind of ID should be returned in the MOUNTDEV_UNIQUE_ID
structure?
The documentation for
typedef struct _MOUNTDEV_UNIQUE_ID {
USHORT UniqueIdLength;
UCHAR UniqueId[1];
} MOUNTDEV_UNIQUE_ID, *PMOUNTDEV_UNIQUE_ID;
says:
UniqueIdLength
- Contains the length of unique volume ID.
UniqueId
- Contains the unique 开发者_StackOverflowvolume ID. The format for unique volume names is
"\??\Volume{GUID}\"
, where GUID is a globally unique identifier that identifies the volume.
However, there's something weird here: What should be the exact format of UniqueId
? If it's meant to be in the \??\Volume{GUID}\
format, then what's the point of the UniqueIdLength
field -- aren't they all the same size? Otherwise, what format does the device ID need to be in?
Furthermore, is this a device ID or a volume ID? In other words, is this supposed to be unique per medium (e.g. CD) or per device (CD drive)?
This kind of struct is pretty common in MS APIs - the UniqueID[1]
variable is just a placeholder, in reality it's used as a UniqueId[UniqueIdLength]
variable.
The ID is unique both per medium and per device - it depends on whether you're talking to a volume driver or a device class driver. The ID is intended to identify "something that can be mounted" - so e.g. a CD-ROM device, a fixed disk partition or an unpartitioned removable disk. The mount manager uses the ID a.o. to lookup where this particular volume was mounted before, and remount it at the same point.
From MSDN
Maybe there is misunderstanding about this structure.
I called DeviceIoControl(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID)
and got a string as the similar format to Device Interface Path, but it is just different of the prefix 4 characters, and then it saved in registry \HKLM\SYSTEM\MountedDevices
.
MOUNTDEV_UNIQUE_ID
is acquired upon a volume arrival notification where mountmgr!MountMgrMountedDeviceArrival
invokes mountmgr!QueryDeviceInformation
, which sends a IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
IRP to the volume PDO stack, which volmgr picks up, and I'm not sure what routine it is but in XP's ftdisk it was ftdisk!FtpQueryUniqueIdBuffer
that determined whether to set the UniqueID member to a GPT partition GUID, a MBR signature + offset, or the symbolic link like STORAGE#RemovableMedia...
. The symbolic link is based on the name of devnode that the volume PDO is part of, and the symbolic link was generated by IoRegisterDeviceInterface
, which was then stored in the volume extension before alerting mountmgr of the volume arrival in the first place (alerting is done by IoSetDeviceInterfaceState Enable
). On Windows 7 the volume PDO devnode name is STORAGE\Volume\_??_USBSTOR#Disk&Ven_SanDisk&Prod_Cruzer_B lade&Rev_1.27#4C530399920812105355&0#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}
, the symbolic link is STORAGE#Volume#_??_USBSTOR#Disk&Ven_SanDisk&Prod_Cruzer_Blade&Rev_1.27#4C530399920812105355&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}
but the MountedDevices data is _??_USBSTOR#Disk&Ven_SanDisk&Prod_Cruzer_Blade&Rev_1.27#4C530399920812105355&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}
. The symbolic link that is created is always to the volume PDO name, because the volume PDO is supplied to the call, which is \Device\HarddiskVolumeX
.
FtpQueryUniqueIdBuffer
uses the MBR signature and partition offset if it's an MBR disk, and uses the GPT partition GUID if it's a GPT disk, and uses the symbolic link if it's neither, which tends to be a regular USB drive mass storage volume that doesn't have a boot sector, and ftdisk considers a disk without a boot sector to be a 'superfloppy', so it looks for that flag on the volume extension. So that's how unique it is, MBR signature and GPT GUID uniqueness speak for themselves, but the symlink doesn't so I'll elaborate: it contains the DIID of the USBSTOR device, which includes the USB serial number, or if it doesn't have one, a system wide unique number determine according to the following scheme.
Mountmgr creates further symbolic links between the drive letter and volume device name, and the volume GUID and the volume device name, and then puts them in the MountedDevices database but uses the unique ID instead of the volume device name. The volume GUID \??\Volume{GUID}\
it generates using ExUuidCreate
. IOCTL_MOUNTMGR_QUERY_POINTS
shows each symbolic link for a mounted device, so it will show \DosDevices\C: -> \Device\HarddiskVolumeX
and \??\Volume{GUID}\ -> \Device\HarddiskVolumeX
and the unique ID of the mounted device and the name of the mounted device. It does not however show the symbolic link to \Device\HarddiskVolumeX
created by IoRegisterDeviceInterface
because the symbolic link wasn't created by mount manager, so it doesn't know about it.
精彩评论