Message273344
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. |
|
Date |
User |
Action |
Args |
2016-08-22 09:33:48 | eryksun | set | recipients:
+ eryksun, paul.moore, tim.golden, zach.ware, steve.dower |
2016-08-22 09:33:48 | eryksun | set | messageid: <1471858428.08.0.847859442583.issue27827@psf.upfronthosting.co.za> |
2016-08-22 09:33:47 | eryksun | link | issue27827 messages |
2016-08-22 09:33:47 | eryksun | create | |
|