1

How would I check if a raw(Windows) drive exists in python? i.e. "\\.\PhysicalDriveN" where N in the disk number

Right now I can check if a raw drive exists(as admin) by opening and immediately closing it. If there is an exception, then the raw device may not exist, otherwise it does. I know that's not very pythonic. Is there a better way?

os.access(drive_name, os.F_OK) always returns False. Same with with os.path.exists(drive_name). I'd prefer just to use the python standard library. os.stat(drive_name) cannot find the device either.

Example of my working code:

drive_name = r"\\.\PhysicalDrive1"
try:
    open(drive_name).close()
except FileNotFoundError:
    print("The device does not exist")
else:
    print("The device exists")
Bryce Guinta
  • 3,456
  • 1
  • 35
  • 36
  • 1
    You can use ctypes to call [`QueryDosDeviceW`](https://msdn.microsoft.com/en-us/library/aa365461). If the DOS device symbolic link exists, this gets the target in the NT object namespace, e.g. `\\?\PhysicalDrive0` => `\Device\Harddisk0\DR0`. – Eryk Sun Jun 16 '15 at 00:59
  • For example: `target = (ctypes.c_wchar * 32768)();` `target_len = ctypes.windll.kernel32.QueryDosDeviceW(u'PhysicalDrive0', target, len(target))`. – Eryk Sun Jun 16 '15 at 01:05
  • @eryksun If I understand correctly, You're saying `\\.\PhysicalDrive0` is a symbolic link? Would it be easier to check some `\Device\Harddisk0`? This function does seem to work though – Bryce Guinta Jun 16 '15 at 15:25
  • 1
    `PhysicalDrive0` could be mapped to a raw drive for any disk in the system, not just `\Device\Harddisk0\DR0`. Plus you can't directly access native object paths using the Windows API. Well, if you're an administrator you can jump out via the `\\?\GlobalRoot` link, but you can't list object directories such as `\Device` without using native NT APIs. The Windows API abstracts access to NT directories such as `\Global??`, `\BaseNamedObjects`, `\Sessions` (Windows and logon sessions), and private namespaces (i.e. `CreatePrivateNamespace`). You can view the object namespace using WinObj. – Eryk Sun Jun 16 '15 at 16:30

2 Answers2

3

As eryksun pointed out in the comments, ctypes.windll.kernel32.QueryDosDeviceW can be used to test for whether the device symbolic link exists(PhysicalDrive1 is a symbolic link to the actual device location). The ctypes module allows one to access this API function, through a Dynamically-linked library.

QueryDosDeviceW requires the drive name as a string, a character array, and the character array's length. The character array stores the raw device that the drive name maps to. The function returns the amount of characters stored in the character array, which would be zero if the drive doesn't exist.

import ctypes
drive_name = "PhysicalDrive1"
target = (ctypes.c_wchar * 32768)(); # Creates an instance of a character array
target_len = ctypes.windll.kernel32.QueryDosDeviceW(drive_name, target, len(target))
if not target_len:
     print("The device does not exist")
else:
     print("The device exists")

The target character array object might have the value "\Device\Harddisk2\DR10" stored in it

Note In python 3 strings are unicode by default, which is why QueryDosDeviceW(above) works. For Python 2, ctypes.windll.kernel32.QueryDosDeviceA would work in place of QueryDocDeviceW for byte strings.

Community
  • 1
  • 1
Bryce Guinta
  • 3,456
  • 1
  • 35
  • 36
0

Without importing ctypes etc.

os.path.exists("C:")

works correctly. Driver argument should have a trailing ":" character.

>>> os.path.exists("C:")
True
>>> os.path.exists("D:")
True
>>> os.path.exists("A:")
False
>>> os.path.exists("X:")
True  # i have mounted a local directory here
>>> os.path.exists("C")
False  # without trailing ":"
alercelik
  • 615
  • 7
  • 11