Doubled backslashes in Windows paths

eryk sun eryksun at gmail.com
Fri Oct 7 09:00:38 EDT 2016


On Fri, Oct 7, 2016 at 9:27 AM, Peter Otten <__peter__ at web.de> wrote:
> To fix the problem either use forward slashes (which are understood by
> Windows, too)

Using forward slash in place of backslash is generally fine, but you
need to be aware of common exceptions, such as the following:

(1) Paths with forward slashes aren't generally accepted in command lines.

(2) Forward slash is just another name character in the kernel object
namespace. Thus "Global/Spam" is a local name with a slash in it,
while r"Global\Spam" is a "Spam" object created in the global
r"\BaseNamedObjects" directory because "Global" is a local object
symbolic link to the global r"\BaseNamedObjects".

(3) Extended paths (i.e. paths prefixed by \\?\) bypass the user-mode
path normalization that replaces slash with backslash. Such paths
cannot use forward slashes to delimit filesystem path components.
Given (2), forward slash potentially could be parsed as part of a
filename. Fortunately, slash is a reserved character in all Microsoft
filesystems. Thus "dir1/dir2" is an invalid 9-character name.

You may ask why Windows doesn't hard-code replacing slash with
backslash, even for extended paths. Some filesystems may allow slash
in names, or for some other purpose (no that I know of any). Also,
device names may contain slashes, just like any other Windows object
name. For example, let's define a DOS pseudo-device (really an object
symbolic link) named "Eggs/Spam" to reference Python's installation
directory:

    import os, sys, ctypes
    kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

    device_name = 'Eggs/Spam'
    target_path = os.path.dirname(sys.executable)
    kernel32.DefineDosDeviceW(0, device_name, target_path)

    >>> os.listdir(r'\\?\Eggs/Spam\Doc')
    ['python352.chm']

Note that the final component, "Doc", must be delimited by a
backslash. If it instead used slash, Windows would look for a device
named "Eggs/Spam/Doc". For example:

    >>> os.listdir(r'\\?\Eggs/Spam/Doc')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    FileNotFoundError: [WinError 3] The system cannot find the
    path specified: '\\\\?\\Eggs/Spam/Doc'

For the case of r"\\?\Eggs/Spam\Doc/python352.chm", parsing the path
succeeds up to the last component, "Doc/python352.chm", which is an
invalid name:

    >>> os.stat(r'\\?\Eggs/Spam\Doc/python352.chm')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    OSError: [WinError 123] The filename, directory name, or volume
    label syntax is incorrect: '\\\\?\\Eggs/Spam\\Doc/python352.chm'

Windows reparses the object symbolic link "Eggs/Spam" to its target
path. In my case that's r"\??\C:\Program Files\Python35". The "C:"
drive in my case is an object symbolic link to
r"\Device\HarddiskVolume2" (typical for Windows 10), so the path gets
reparsed as r"\Device\HarddiskVolume2\Program
Files\Python35\Doc/python352.chm". The volume device "HarddiskVolume2"
contains an NTFS filesystem, so the NTFS driver parses the remaining
path, r"\Program Files\Python35\Doc/python352.chm", and rejects
"Doc/python352.chm" as an invalid name.



More information about the Python-list mailing list