On 2/9/21, Doug Campbell <wdouglascampb...@hotmail.com> wrote: > > win32file.DeviceIoControl(hDevice, > winioctlcon.IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, > None, extents, None) > pywintypes.error: (1, 'DeviceIoControl', 'Incorrect function.') > > I have tried with all three of the disks on my system: \\.\PhysicalDrive0, > \\.\PhysicalDrive1, and \\.\PhyscialDrive2 but the results are always the > same.
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS requests the disk extents of a volume device. Disk devices do not implement this request. A volume device such as "\\.\C:" can span multiple extents across one or more physical disks such as "\\.\PhysicalDrive0" and "\\.\PhysicalDrive1". If the request fails with winerror.ERROR_MORE_DATA, you need to be prepared to resize the structure according to NumberOfDiskExtents. ctypes doesn't make this all that easy or convenient at a high level. What I do is to make the array field private and implement a property that takes the dynamic length into account. For example: ANYSIZE_ARRAY = 1 class VOLUME_DISK_EXTENTS(ctypes.Structure): _fields_ = (('NumberOfDiskExtents', ctypes.c_ulong), ('_Extents', DISK_EXTENT * ANYSIZE_ARRAY)) @property def Extents(self): offset = type(self)._Extents.offset array_t = DISK_EXTENT * self.NumberOfDiskExtents return array_t.from_buffer(self, offset) def resize(self): if self.NumberOfDiskExtents < 1: self.NumberOfDiskExtents = 1 offset = type(self)._Extents.offset array_size = ctypes.sizeof(DISK_EXTENT) * self.NumberOfDiskExtents ctypes.resize(self, offset + array_size) If you passed `vde = VOLUME_DISK_EXTENTS()`, and the request fails with winerror.ERROR_MORE_DATA, the call should have set NumberOfDiskExtents to the required length. Call vde.resize(), and try again. It's a bit clumsy, but it works. > hDevice = win32file.CreateFile( > disk, win32con.GENERIC_READ, > win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE, > None, win32con.OPEN_EXISTING, win32con.FILE_ATTRIBUTE_NORMAL, > None) IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS is defined to require FILE_ANY_ACCESS. This means the desired access and access sharing can both be 0, and should be since there's no reason to request access that you don't need that could cause the call to fail with a permission error (e.g. access denied, or a sharing violation if read access isn't shared). For example: volume = r'\\.\C:' hDevice = win32file.CreateFile(volume, 0, 0, None, win32file.OPEN_EXISTING, 0, None) --- Volume Device Names The base name of a volume device is typically something like "\Device\HarddiskVolume<N>" or "\Device\CdRom<N>", but these are automatic names that can vary in the device number N each time a volume comes online. The mountpoint manager usually will also assign persistent names to a volume device, which are stored in the registry if necessary (HKLM\System\MountedDevices) and are set globally in the "\GLOBAL??" device-alias directory when the volume comes online. Usually it assigns a GUID name of the form "Volume{12345678-0000-0000-0000-123456789ABC}". A GUID name is used when mounting a volume on an existing directory (e.g. mounting a volume as "C:\Mount\BackupDrive"). It usually also assigns a DOS drive-letter name such as "C:", which provides the classic DOS volume mountpoint, such as "C:\". The "\GLOBAL??" object directory is rarely accessed directly, even in native NT API programs that have full access to the NT object namespace. Instead, native NT programs use "\??", a virtual directory that allows accessing global device symlinks in addition to, and shadowed by, device symlinks in the caller's logon session device directory. The SYSTEM logon uses "\GLOBAL??" for its logon session devices, so it always creates and accesses global device aliases. In the Windows API, the NT API "\??\" prefix maps to "\\.\" or "\\?\" UNC-style paths. The former is more common if just the device is accessed, and the latter is more common for a filesystem path. Thus to access the "C:" volume device directly, programs typically use "\\.\C:". Note that just "C:" by itself is a DOS drive-relative path that expands to the working directory in the mounted filesystem, which defaults to the root directory. So passing "C:" as the path to open is actually a reference to a filesystem directory, not to the volume device, which obviously won't work. _______________________________________________ python-win32 mailing list python-win32@python.org https://mail.python.org/mailman/listinfo/python-win32