Does This Scare You?
eryk sun
eryksun at gmail.com
Sun Aug 21 20:38:15 EDT 2016
On Sun, Aug 21, 2016 at 8:03 PM, Michael Torrie <torriem at gmail.com> wrote:
> On 08/19/2016 05:42 PM, Lawrence D’Oliveiro wrote:
>> Python 3.5.2+ (default, Aug 5 2016, 08:07:14)
>> [GCC 6.1.1 20160724] on linux
>> Type "help", "copyright", "credits" or "license" for more information.
>> >>> from pathlib import PureWindowsPath
>> >>> PureWindowsPath("prn").is_reserved()
>> True
>> >>> PureWindowsPath("prn.doc").is_reserved()
>> True
>> >>> PureWindowsPath("com9.exe").is_reserved()
>> True
>> >>> PureWindowsPath("c:/my documents/prn.doc").is_reserved()
>> True
>
> Which part are you getting at? That Windows treats certain filenames as
> reserved (a known gotcha that has existed for decades) or that Python
> allows you to test whether a path is valid in Windows?
To me it's scary that this check misses cases because it's trying to
be cross-platform instead of simply relying on GetFullPathName to do
the work. For example, it misses at least the following cases:
Optional 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
It's also a bit disappointing that the author of this function claims
in a comment that "foo/NUL" isn't reserved yet decides to "err on the
side of caution" (obviously not enough). Of course "foo/NUL" is
reserved:
>>> print(os.path._getfullpathname('foo/NUL'))
\\.\NUL
I think what happened is that the author tested by calling open() on a
non-existing path. DOS device names are only reserved for existing
directories, in order to return an error for an invalid path. The
difference is how RtlGetFullPathName_Ustr is called. When
GetFullPathName calls the latter function it doesn't care whether or
not the path is valid. On the other hand, RtlDosPathNameToNtPathName_*
calls RtlGetFullPathName_Ustr with a parameter to check for an invalid
path, which makes the path normalization fail. For example:
Existing directory:
>>> os.path.exists('C:/Temp')
True
>>> f = open('C:/Temp/NUL')
Query the device name:
>>> hFile = msvcrt.get_osfhandle(f.fileno())
>>> ntdll.NtQueryObject(hFile, 1, byref(name), sizeof(name), None)
0
>>> print(name.Buffer[:name.Length//2])
\Device\Null
(\\.\NUL, i.e. \GLOBAL??\NUL, is a symbolic link to NT's \Device\Null.)
Non-existing directory:
>>> os.path.exists('C:/Spam')
False
>>> g = open('C:/Spam/NUL')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: 'C:/Spam/NUL'
More information about the Python-list
mailing list