Skip to content

Fix EACCES-on-Windows sharing-violation check comparing args tuple to an int - #612

Open
ApparentlyTejas wants to merge 3 commits into
PyFilesystem:masterfrom
ApparentlyTejas:fix-eacces-sharing-violation-check
Open

ApparentlyTejas wants to merge 3 commits into
PyFilesystem:masterfrom
ApparentlyTejas:fix-eacces-sharing-violation-check

Conversation

@ApparentlyTejas

Copy link
Copy Markdown

Summary

In fs/error_tools.py, _ConvertOSErrors special-cases EACCES on Windows to raise ResourceLocked instead of PermissionDenied when the underlying error is actually ERROR_SHARING_VIOLATION (winerror 32), i.e. the file is locked by another process rather than genuinely permission-denied.

The check is:

if getattr(exc_value, "args", None) == 32:  # pragma: no cover
    fserror = errors.ResourceLocked

OSError.args is always a tuple (e.g. (13, 'Permission denied')), so this comparison against the int 32 can never be true. The sharing-violation branch is unreachable dead code, and every EACCES on Windows falls through to PermissionDenied, even when it's really a sharing violation.

The attribute that actually carries the Windows error code is winerror, not args. This PR fixes the check to use getattr(exc_value, "winerror", None) == 32.

Test plan

  • Added test_convert_eacces_sharing_violation_on_windows: constructs an OSError(errno.EACCES, ...) with winerror = 32 set, patches sys.platform to "win32", and asserts convert_os_errors raises ResourceLocked.
  • Added test_convert_eacces_plain_permission_denied_on_windows: same setup without winerror, asserts it still raises PermissionDenied (guards against overcorrecting).
  • Both pass locally; existing test suite unaffected.

… an int

convert_os_errors special-cases EACCES on Windows to report ResourceLocked
when the OS error is really ERROR_SHARING_VIOLATION (winerror 32), not a
plain permission problem. But it checked
getattr(exc_value, "args", None) == 32 -- args is always a tuple
(e.g. (13, 'Permission denied')), so this comparison can never be true
and the sharing-violation branch is dead code. The actual Windows-specific
attribute carrying this code is winerror, not args.
The 2-arg OSError(errno, strerror) form triggers a CPython/Windows legacy
path that reinterprets the first int as a winerror and recomputes .errno
from it, which was corrupting these tests' intended errno on real Windows
CI (caught by AppVeyor). The 3-arg form (errno, strerror, filename) keeps
.errno as given.
It asserted PermissionDenied, but FILE_ERRORS[13] is already remapped to
FileExpected on real Windows builds (_WINDOWS_PLATFORM is computed once
at import time via platform.system(), so mocking sys.platform in the test
doesn't affect it) -- a pre-existing, unrelated quirk in this file. That
assumption isn't something this PR's fix needs; the sharing-violation
test alone already covers the args-vs-winerror bug.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant