Eryk Sun <[email protected]> added the comment:
> (sidenote: what os.path operation does Path.resolve() match?
> Path('nonexistent').resolve() returns a relative path on Python
> 3.7.1, whereas Path().resolve() returns an absolute path.)
pathlib should resolve 'nonexistent' in Windows. It works as expected in Unix:
>>> os.getcwd()
'/etc'
>>> os.fspath(Path('nonexistent').resolve())
'/etc/nonexistent'
A PR to implement ntpath.realpath is in development for issue 14094. The
proposed implementation calls ntpath.abspath at the start, unless it's an
extended path (i.e. prefixed by \\?\). Unlike Unix, Windows normalizes a path
in user mode as a text operation before passing it to the kernel and file
system. This means there's no problem if abspath removes a reparse point (e.g.
symlink or mountpoint) when it resolves a ".." component.
> The code paths should be audited to check that EINVAL can't mean something
> else.
We'd have to use the Windows error code (e.g. ERROR_INVALID_NAME) if it has to
be specific. EINVAL is the default errno value. In particular, EINVAL includes
some low-level device failures such as ERROR_IO_DEVICE and errors for
operations that a device doesn't implement, which are commonly
ERROR_INVALID_PARAMETER, ERROR_INVALID_FUNCTION, and ERROR_NOT_SUPPORTED.
Also, a few device and files-system errors are mapped to EACCES (e.g.
ERROR_NOT_READY and ERROR_SECTOR_NOT_FOUND). If we include EACCES, then files
that exist but are inaccessible (e.g. the user isn't allowed to list the parent
directory) will be reported as not existing instead of raising an error. It's
what os.path.exists does, but I guess pathlib wants to be more nuanced.
When using C runtime I/O (e.g. open, read, write), it can help to get the last
Windows error code, _doserrno [1]. Its value gets set when errno is set by
mapping an OS error. The last NT status value may also help in some cases. It
gets set whenever an NT status code is mapped to a Windows error via
RtlNtStatusToDosError (usually followed immediately by RtlSetLastWin32Error).
It would be nice if OSError always included these two values, maybe as
"last_winerror" (differentiated from "winerror") and "last_ntstatus".
For example, here's a case of trying to open a file on a CD drive that has no
disk in it.
import ctypes
doserrno = ctypes.WinDLL('ucrtbase').__doserrno
doserrno.restype = ctypes.POINTER(ctypes.c_ulong)
doserrno.errcheck = lambda r, f, a: r[0]
get_last_nt_status = ctypes.WinDLL('ntdll').RtlGetLastNtStatus
get_last_nt_status.restype = ctypes.c_ulong
def test():
try:
open('D:\\test.txt')
except:
winerror, ntstatus = doserrno(), get_last_nt_status()
print('Windows error:', winerror)
print('NT status:', format(ntstatus, '#010x'))
raise
>>> test()
Windows error: 21
NT status: 0xc0000013
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in test
PermissionError: [Errno 13] Permission denied: 'D:\\test.txt'
Windows error 21 is ERROR_NOT_READY, so we're already much better informed than
EACCES (13). NT status 0xC0000013 is STATUS_NO_MEDIA_IN_DEVICE.
[1]:
https://docs.microsoft.com/en-us/cpp/c-runtime-library/errno-doserrno-sys-errlist-and-sys-nerr?view=vs-2017
----------
_______________________________________
Python tracker <[email protected]>
<https://bugs.python.org/issue35306>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com