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

AltStyle によって変換されたページ (->オリジナル) /