From 90773a3ad8d75c51419c72f06b0f128fe160d71e Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Fri, 21 Jun 2024 10:53:35 +0200 Subject: [PATCH] fix #627: PermissionError may occur on Windows when binding ports from a pre-configured PASV range. --- HISTORY.rst | 5 +++++ pyftpdlib/_compat.py | 13 +++++++++---- pyftpdlib/handlers.py | 6 ++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 99523ade..1a8ad2cf 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -9,6 +9,11 @@ Version: 1.5.10 - (UNRELEASED) * #626: use argparse instead of deprecated optparse. * #628: use pytest instead of unittest. +**Bug fixes** + +* #627: PermissionError may occur on Windows when binding ports from a + pre-configured PASV range. + Version: 1.5.9 - 2023-10-25 =========================== diff --git a/pyftpdlib/_compat.py b/pyftpdlib/_compat.py index 0ab85d02..410fd65d 100644 --- a/pyftpdlib/_compat.py +++ b/pyftpdlib/_compat.py @@ -58,6 +58,7 @@ def callable(obj): FileNotFoundError = FileNotFoundError # NOQA FileExistsError = FileExistsError # NOQA InterruptedError = InterruptedError # NOQA + PermissionError = PermissionError # NOQA else: # https://github.com/PythonCharmers/python-future/blob/exceptions/ # src/future/types/exceptions/pep3151.py @@ -96,14 +97,18 @@ def __subclasscheck__(cls, classinfo): def FileNotFoundError(inst): return getattr(inst, 'errno', _SENTINEL) == errno.ENOENT - @_instance_checking_exception(EnvironmentError) - def FileExistsError(inst): - return getattr(inst, 'errno', _SENTINEL) == errno.EEXIST - @_instance_checking_exception(EnvironmentError) def InterruptedError(inst): return getattr(inst, 'errno', _SENTINEL) == errno.EINTR + @_instance_checking_exception(EnvironmentError) + def PermissionError(inst): + return getattr(inst, 'errno', _SENTINEL) in (errno.EACCES, errno.EPERM) + + @_instance_checking_exception(EnvironmentError) + def FileExistsError(inst): + return getattr(inst, 'errno', _SENTINEL) == errno.EEXIST + if platform.python_implementation() != "CPython": try: raise OSError(errno.EEXIST, "perm") diff --git a/pyftpdlib/handlers.py b/pyftpdlib/handlers.py index 4d66ed22..afd78742 100644 --- a/pyftpdlib/handlers.py +++ b/pyftpdlib/handlers.py @@ -34,6 +34,7 @@ from . import __ver__ from ._compat import PY3 +from ._compat import PermissionError from ._compat import b from ._compat import getcwdu from ._compat import super @@ -477,6 +478,11 @@ def __init__(self, cmd_channel, extmode=False): self.set_reuse_addr() try: self.bind((local_ip, port)) + except PermissionError: + self.cmd_channel.log( + "ignoring EPERM when bind()ing port %s" % port, + logfun=logger.debug, + ) except socket.error as err: if err.errno == errno.EADDRINUSE: # port already in use if ports: