Skip to content

Commit bc337a7

Browse files
authored
[3.11] gh-96005: Handle WASI ENOTCAPABLE in getpath (GH-96006) (GH-96034) (GH-96038)
- On WASI `ENOTCAPABLE` is now mapped to `PermissionError`. - The `errno` modules exposes the new error number. - `getpath.py` now ignores `PermissionError` when it cannot open landmark files `pybuilddir.txt` and `pyenv.cfg`.
1 parent c4cf745 commit bc337a7

File tree

7 files changed

+35
-6
lines changed

7 files changed

+35
-6
lines changed

Doc/library/errno.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,3 +657,12 @@ defined by the module. The specific list of defined symbols is available as
657657
Interface output queue is full
658658

659659
.. versionadded:: 3.11
660+
661+
.. data:: ENOTCAPABLE
662+
663+
Capabilities insufficient. This error is mapped to the exception
664+
:exc:`PermissionError`.
665+
666+
.. availability:: WASI, FreeBSD
667+
668+
.. versionadded:: 3.11.1

Doc/library/exceptions.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,12 @@ depending on the system error code.
746746

747747
Raised when trying to run an operation without the adequate access
748748
rights - for example filesystem permissions.
749-
Corresponds to :c:data:`errno` :py:data:`~errno.EACCES` and :py:data:`~errno.EPERM`.
749+
Corresponds to :c:data:`errno` :py:data:`~errno.EACCES`,
750+
:py:data:`~errno.EPERM`, and :py:data:`~errno.ENOTCAPABLE`.
751+
752+
.. versionchanged:: 3.11.1
753+
WASI's :py:data:`~errno.ENOTCAPABLE` is now mapped to
754+
:exc:`PermissionError`.
750755

751756
.. exception:: ProcessLookupError
752757

Lib/test/test_exception_hierarchy.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def test_select_error(self):
6363
+-- InterruptedError EINTR
6464
+-- IsADirectoryError EISDIR
6565
+-- NotADirectoryError ENOTDIR
66-
+-- PermissionError EACCES, EPERM
66+
+-- PermissionError EACCES, EPERM, ENOTCAPABLE
6767
+-- ProcessLookupError ESRCH
6868
+-- TimeoutError ETIMEDOUT
6969
"""
@@ -75,6 +75,8 @@ def _make_map(s):
7575
continue
7676
excname, _, errnames = line.partition(' ')
7777
for errname in filter(None, errnames.strip().split(', ')):
78+
if errname == "ENOTCAPABLE" and not hasattr(errno, errname):
79+
continue
7880
_map[getattr(errno, errname)] = getattr(builtins, excname)
7981
return _map
8082
_map = _make_map(_pep_map)
@@ -91,7 +93,7 @@ def test_errno_mapping(self):
9193
othercodes = set(errno.errorcode) - set(self._map)
9294
for errcode in othercodes:
9395
e = OSError(errcode, "Some message")
94-
self.assertIs(type(e), OSError)
96+
self.assertIs(type(e), OSError, repr(e))
9597

9698
def test_try_except(self):
9799
filename = "some_hopefully_non_existing_file"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
On WASI :data:`~errno.ENOTCAPABLE` is now mapped to :exc:`PermissionError`.
2+
The :mod:`errno` modules exposes the new error number. ``getpath.py`` now
3+
ignores :exc:`PermissionError` when it cannot open landmark files
4+
``pybuilddir.txt`` and ``pyenv.cfg``.

Modules/errnomodule.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,10 @@ errno_exec(PyObject *module)
927927
#ifdef EQFULL
928928
add_errcode("EQFULL", EQFULL, "Interface output queue is full");
929929
#endif
930+
#ifdef ENOTCAPABLE
931+
// WASI extension
932+
add_errcode("ENOTCAPABLE", ENOTCAPABLE, "Capabilities insufficient");
933+
#endif
930934

931935
Py_DECREF(error_dict);
932936
return 0;

Modules/getpath.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -351,11 +351,11 @@ def search_up(prefix, *landmarks, test=isfile):
351351
try:
352352
# Read pyvenv.cfg from one level above executable
353353
pyvenvcfg = readlines(joinpath(venv_prefix, VENV_LANDMARK))
354-
except FileNotFoundError:
354+
except (FileNotFoundError, PermissionError):
355355
# Try the same directory as executable
356356
pyvenvcfg = readlines(joinpath(venv_prefix2, VENV_LANDMARK))
357357
venv_prefix = venv_prefix2
358-
except FileNotFoundError:
358+
except (FileNotFoundError, PermissionError):
359359
venv_prefix = None
360360
pyvenvcfg = []
361361

@@ -475,7 +475,7 @@ def search_up(prefix, *landmarks, test=isfile):
475475
# File exists but is empty
476476
platstdlib_dir = real_executable_dir
477477
build_prefix = joinpath(real_executable_dir, VPATH)
478-
except FileNotFoundError:
478+
except (FileNotFoundError, PermissionError):
479479
if isfile(joinpath(real_executable_dir, BUILD_LANDMARK)):
480480
build_prefix = joinpath(real_executable_dir, VPATH)
481481
if os_name == 'nt':

Objects/exceptions.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3644,6 +3644,11 @@ _PyExc_InitState(PyInterpreterState *interp)
36443644
ADD_ERRNO(InterruptedError, EINTR);
36453645
ADD_ERRNO(PermissionError, EACCES);
36463646
ADD_ERRNO(PermissionError, EPERM);
3647+
#ifdef ENOTCAPABLE
3648+
// Extension for WASI capability-based security. Process lacks
3649+
// capability to access a resource.
3650+
ADD_ERRNO(PermissionError, ENOTCAPABLE);
3651+
#endif
36473652
ADD_ERRNO(ProcessLookupError, ESRCH);
36483653
ADD_ERRNO(TimeoutError, ETIMEDOUT);
36493654

0 commit comments

Comments
 (0)