Handle unsupported ownership transfer in atomic writes

This commit is contained in:
ai-ag2026 2026-07-10 06:26:30 +02:00
parent d5904283ab
commit c7ce0db4fa
2 changed files with 21 additions and 3 deletions

View file

@ -144,7 +144,18 @@ def _atomic_write_text(path: Path, text: str, *, encoding: str = "utf-8") -> Non
if existing_stat is not None and hasattr(os, "fchown"):
try:
os.fchown(fd, existing_stat.st_uid, existing_stat.st_gid)
except (PermissionError, NotImplementedError):
except (OSError, NotImplementedError) as exc:
unsupported_ownership_errnos = {
errno.EINVAL,
errno.ENOSYS,
errno.ENOTSUP,
}
if (
isinstance(exc, OSError)
and not isinstance(exc, PermissionError)
and exc.errno not in unsupported_ownership_errnos
):
raise
os.close(fd)
owns_fd = False
os.unlink(tmp)

View file

@ -99,15 +99,22 @@ def test_atomic_write_preserves_existing_group(tmp_path: Path) -> None:
@pytest.mark.skipif(not hasattr(os, "fchown"), reason="POSIX ownership semantics")
@pytest.mark.parametrize(
"failure",
[
PermissionError("simulated ownership denial"),
OSError(errno.EINVAL, "simulated unsupported ownership transfer"),
],
)
def test_fchown_denial_falls_back_without_temp_debris(
tmp_path: Path, monkeypatch
tmp_path: Path, monkeypatch, failure: OSError
) -> None:
"""A writer unable to transfer ownership must keep the old inode contract."""
target = tmp_path / "config.yaml"
target.write_text("old: true\n", encoding="utf-8")
def _deny_fchown(*_args) -> None:
raise PermissionError("simulated ownership denial")
raise failure
monkeypatch.setattr(os, "fchown", _deny_fchown)