This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author eryksun
Recipients eryksun, paul.moore, steve.dower, tim.golden, zach.ware
Date 2016-08-22.09:33:47
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1471858428.08.0.847859442583.issue27827@psf.upfronthosting.co.za>
In-reply-to
Content
pathlib._WindowsFlavour.is_reserved assumes Windows uses an exact match up to the file extension for reserved DOS device names. However, this misses cases involving trailing spaces and colons, such as the following examples:

Trailing colon:

    >>> pathlib.Path('C:/foo/NUL:').is_reserved()
    False
    >>> print(os.path._getfullpathname('C:/foo/NUL:'))
    \\.\NUL

Trailing spaces:

    >>> pathlib.Path('C:/foo/NUL  ').is_reserved()
    False
    >>> print(os.path._getfullpathname('C:/foo/NUL  '))
    \\.\NUL

Trailing spaces followed by a file extension:

    >>> pathlib.Path('C:/foo/NUL  .txt').is_reserved()
    False
    >>> print(os.path._getfullpathname('C:/foo/NUL  .txt'))
    \\.\NUL

Windows calls RtlIsDosDeviceName_Ustr to check whether a path represents a DOS device name. Here's a link to the reverse-engineered implementation of this function in ReactOS 4.1:

http://code.reactos.org/browse/reactos/branches/ros-branch-0_4_1/reactos/sdk/lib/rtl/path.c?r=71210#to85

The ReactOS implementation performs the following steps:

    * Return false for a UNC or unknown path type or an empty path.
    * Strip a final ":" if present. Return false if it was the
      only character.
    * Strip trailing dot and space characters.
    * Iterate over the path in reverse. If the current character is
      a "\\" or "/" or a ":" drive letter separator (at index 1),
      then if the next character matches the first letter of a DOS
      device name, splice out the base name as a potential match.
      Else return false.
    * Return false if the first character at this point does not 
      match the first letter of a DOS device name.
    * Remove the file extension, starting at the first dot or colon.
    * Remove trailing spaces.
    * Return the name offset and length if it equals
        * "COM" or "LPT" plus a digit
        * "PRN", "AUX", "NUL, or "CON"
    * Else return false.

It seems that ":" and "." are effectively equivalent for the purposes of is_reserved. Given this is the case, it could return whether parts[-1].partition('.')[0].partition(':')[0].rstrip(' ').upper() is in self.reserved_names. Or maybe use a regex for the entire check.

If a script is running on Windows, I think the best approach is to call os.path.abspath, which calls _getfullpathname. This lets Windows itself determine if the path maps to the \\.\ device namespace. However, I realize that is_reserved is intended to be cross-platform.

By the way, the comment for this method says that r"foo\NUL" isn't reserved, but it is. Maybe the author checked by trying to open NUL in a non-existing foo directory. DOS device names are only reserved in practice when opening and creating files in existing directories (as opposed to reserved in principle with GetFullPathName, which doesn't check for a valid path). NT can thus return an error that's consistent with how DOS behaved in the 1980s -- because that's really important, you know.
History
Date User Action Args
2016-08-22 09:33:48eryksunsetrecipients: + eryksun, paul.moore, tim.golden, zach.ware, steve.dower
2016-08-22 09:33:48eryksunsetmessageid: <1471858428.08.0.847859442583.issue27827@psf.upfronthosting.co.za>
2016-08-22 09:33:47eryksunlinkissue27827 messages
2016-08-22 09:33:47eryksuncreate