On Sun, Aug 21, 2016 at 8:03 PM, Michael Torrie <torr...@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' -- https://mail.python.org/mailman/listinfo/python-list