Eryk Sun added the comment:

Paths starting with "\\.\" (or  "//./") and "\\?\" are not UNC paths. I've 
provided some explanations and examples below, and I also encourage you to read 
"Naming Files, Paths, and Namespaces":

https://msdn.microsoft.com/en-us/library/aa365247

"\\.\" is the general way to access DOS devices, but with some path processing 
still enabled. For example:

    >>> files = os.listdir(r'//./C:/Windows/System32/..')
    >>> [x for x in files if x[:2] == 'py']
    ['py.exe', 'pyw.exe']

Notice that using slash and ".." is allowed. This form doesn't allow relative 
paths that depend on per-drive current directories. It's actually not 
recommended to use "\\.\" to access files on drive letters. Normally it's used 
with drive letters only when directly opening a volume. For example:

    >>> fd = os.open(r'\\.\C:', os.O_RDONLY | os.O_BINARY)
    >>> os.read(fd, 512)[:7]
    b'\xebR\x90NTFS'

The "\\?\" prefix allows the most access to the NT kernel namespace from within 
the Windows API (e.g. file paths can be up to 32K characters instead of the DOS 
limit of 260 characters). It does so by disabling all path processing, which 
means the onus is on the programmer to provide a fully-qualified, Unicode path 
that only uses backslash as the path separator.

So why does "\\.\" exist? Some DOS devices are made implicitly available in the 
Windows API, such as DOS drive letters and "CON". However, the Windows API 
greatly extends the number of 'DOS' devices (e.g. the "PhysicalDrive0" device 
for low-level access to the first disk). Accessing these devices unambiguously 
requires the "\\.\" prefix. A common example is using "\\.\pipe\[pipe name]" to 
open a NamedPipe. You can even list the NamedPipe filesystem in Python. For 
example:

    >>> p1, p2 = multiprocessing.Pipe()
    >>> [x for x in os.listdir(r'\\.\pipe') if x[:2] == 'py']
    ['pyc-719-1-hoirbkzb']

Global DOS device names are defined in the kernel's "\Global??" directory. Some 
DOS devices, such as mapped network drives, are usually defined local to a 
logon session in the kernel's "\Sessions\0\DosDevices\[Logon Session ID]" 
directory. In the examples I gave, you may have noticed that each native kernel 
path starts with "\??\". This is a virtual directory in the kernel (and only 
the kernel). It instructs the object manager to first search the local session 
DOS devices and then the global DOS devices.

A DOS device is almost always implemented as an object symbolic link to the 
real NT device name in the kernel's "\Device" directory. For example, 
"\Global??\PIPE" links to "\Device\NamedPipe" and the "C:" drive may be a link 
to "\Device\HarddiskVolume2". This device is what the kernel actually opened in 
the previous example that read from "\\.\C:". Note that this accesses the 
volume itself, not the root directory of the filesystem that resides on the 
volume. The latter is "\\.C:\". The trailing backslash makes all the 
difference. (Opening a directory such as the latter requires backup semantics, 
as described in the CreateFile docs.)

If a DOS drive letter is assigned to a volume, the assignment is stored in the 
registry by the volume's ID. (Dynamic volumes that span multiple disks also 
contain a drive letter hint.) For volume devices, the kernel also creates a 
GUID name that's always available and allows mounting a volume in a directory 
using an NTFS reparse point (e.g. see the output of mountvol.exe). You can also 
use GUID volume names in the Windows API. For example:

    >>> path = r'\\?\Volume{1693b540-0000-0000-0000-612e00000000}\Windows'
    >>> files = os.listdir(path)
    >>> [x for x in files if x[:2] == 'py']
    ['py.exe', 'pyw.exe']

But normally you'd just mount the volume, which can even be recursively mounted 
within itself. For example:

    >>> os.mkdir('C:\\SystemVolume')
    >>> subprocess.call(r'mountvol C:\SystemVolume 
\\?\Volume{1693b540-0000-0000-0000-612e00000000}')
    0
    >>> files = os.listdir(r'C:\SystemVolume\Windows')
    >>> [x for x in files if x[:2] == 'py']
    ['py.exe', 'pyw.exe']

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue27403>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to