classification
Title: pathlib: "Incorrect function" during resolve()
Type: Stage:
Components: Windows Versions: Python 3.8
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: earonesty2, eryksun, maciozo, paul.moore, steve.dower, tim.golden, zach.ware, zombie110year
Priority: normal Keywords:

Created on 2017-10-22 21:31 by earonesty2, last changed 2019-12-02 18:23 by eryksun.

Messages (4)
msg304767 - (view) Author: Erik Aronesty (earonesty2) * Date: 2017-10-22 21:31
When strict is "false", pathlib should not fail if the network share is inaccessible.  It should, as documented, catch the exception and continue with as much of the path as it has.



>>> pathlib.Path("v:").resolve()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\erik\AppData\Local\Programs\Python\Python36\lib\pathlib.py", line 1119, in resolve
    s = self._flavour.resolve(self, strict=strict)
  File "C:\Users\erik\AppData\Local\Programs\Python\Python36\lib\pathlib.py", line 193, in resolve
    s = self._ext_to_normal(_getfinalpathname(s))
OSError: [WinError 1] Incorrect function: 'v:'
msg356199 - (view) Author: (maciozo) Date: 2019-11-07 16:30
Same error occurs when attempting to resolve a path on an ImDisk RAM disk:

>>> pathlib.Path("T:\\").resolve()
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "C:\Users\maciozo\AppData\Local\Continuum\miniconda3\envs\brainboxes\lib\pathlib.py", line 1151, in resolve
    s = self._flavour.resolve(self, strict=strict)
  File "C:\Users\maciozo\AppData\Local\Continuum\miniconda3\envs\brainboxes\lib\pathlib.py", line 202, in resolve
    s = self._ext_to_normal(_getfinalpathname(s))
OSError: [WinError 1] Incorrect function: 'T:\\'
msg357702 - (view) Author: LiJiayuan (zombie110year) * Date: 2019-12-02 05:39
Same Error.

It happend by resolving a path which is not under C: driver,
in Windows System.

>>> Path().resolve()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\zom\scoop\apps\miniconda3\current\envs\web\lib\pathlib.py", line 1159, in resolve
    s = self._flavour.resolve(self, strict=strict)
  File "C:\Users\zom\scoop\apps\miniconda3\current\envs\web\lib\pathlib.py", line 202, in resolve
    s = self._ext_to_normal(_getfinalpathname(s))
OSError: [WinError 1] Incorrect function: '.'
>>> Path().absolute()
WindowsPath('R:/fileshare/fileshare-s')
>>> Path().absolute().resolve()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\zom\scoop\apps\miniconda3\current\envs\web\lib\pathlib.py", line 1159, in resolve
    s = self._flavour.resolve(self, strict=strict)
  File "C:\Users\zom\scoop\apps\miniconda3\current\envs\web\lib\pathlib.py", line 202, in resolve
    s = self._ext_to_normal(_getfinalpathname(s))
OSError: [WinError 1] Incorrect function: 'R:\\fileshare\\fileshare-s'
msg357725 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2019-12-02 18:23
> When strict is "false", pathlib should not fail if the network 
> share is inaccessible.

A redirected filesystem (i.e. a share, whether local or remote) that's physically inaccessible should fail with a FileNotFoundError -- due to underlying errors such as ERROR_BAD_NETPATH (53) or ERROR_BAD_NET_NAME (67). This case is already handled by resolve() in non-strict mode. But error handling for other cases does need to be expanded.

A PermissionError should be ignored, from OS errors such as ERROR_ACCESS_DENIED (5), ERROR_SHARING_VIOLATION (32), and ERROR_NOT_READY (21). 

It should ignore errors due to bad reparse points (e.g. filesystem symlinks and mount points), such as ERROR_INVALID_REPARSE_DATA (4392) and ERROR_REPARSE_TAG_INVALID (4393). 

The resolve() method is supposed to raise a RuntimeError for a symlink loop (i.e. reparse loop). In Windows, the system detects this case as ERROR_CANT_RESOLVE_FILENAME (1921). It's not necessarily due to a reparse loop, but in practice it usually is. (It's actually due to the upper limit for the number of reparse attempts, which as of Windows 10 is no more than 63 attempts.) Maybe this error should be re-raised as a RuntimeError for the sake of compatibility with the POSIX implementation.

The above-mentioned cases are all due to WINAPI CreateFileW failing. 
Additionally, the GetFinalPathNameByHandleW call in nt._getfinalpathname relies on several low-level system calls, any one of which can fail with ERROR_INVALID_FUNCTION (1) or ERROR_INVALID_PARAMETER (87) -- and possibly ERROR_NOT_SUPPORTED (50). These errors should be ignored in non-strict mode. 

At a lower level, the reliability of nt._getfinalpathname could be improved for non-strict operation. It could fall back on other forms of the final name that may be supported. It could try FILE_NAME_OPENED instead of FILE_NAME_NORMALIZED to handle a filesystem that does not support normalizing 8.3 short names as long names. Try VOLUME_NAME_GUID instead of VOLUME_NAME_DOS to handle a volume that only has a GUID name (i.e. a volume device that's registered with the mount-point manager but lacks a DOS drive name or even a mountpoint on a volume that has a DOS drive name). Try VOLUME_NAME_NT to handle legacy volume/filesystem devices ('legacy' because they do not support the mount-point manager interface that was introduced almost 20 years ago in NT 5). For the sake of simplicity and performance, the latter case could be limited to well-known DOS device names such as r"\\?\PIPE" -> r"\Device\NamedPipe". The NT device path for the comparison should be queried instead of hard coded, e.g. via QueryDosDeviceW(L"PIPE", ...).
History
Date User Action Args
2019-12-02 18:23:12eryksunsetmessages: + msg357725
2019-12-02 06:47:04xtreaksetnosy: + eryksun
2019-12-02 05:39:48zombie110yearsetnosy: + zombie110year

messages: + msg357702
versions: + Python 3.8, - Python 3.7
2019-11-07 16:30:50maciozosetnosy: + maciozo
messages: + msg356199
2017-10-22 21:31:34earonesty2setnosy: + paul.moore, tim.golden, steve.dower, zach.ware
components: + Windows
2017-10-22 21:31:13earonesty2create