Skip to content

pathlib fast-copy can silently produce an empty destination after a zero-byte syscall #159395

Open

Description

@mhatipog

Bug description

The fast-copy helpers in pathlib._os treat an initial zero-byte result from os.copy_file_range() or os.sendfile() as normal EOF, even when no data was copied.

Some filesystems can return zero for an unsuccessful fast copy. The existing shutil._fastcopy_copy_file_range() code already guards against this case by falling back when zero is returned before any data has been copied (see Lib/shutil.py and the Linux filesystem discussion).

A nonempty Path.copy() source can therefore produce an empty destination without raising an exception. This also affects Path.move() across devices: its fallback copies the source and then deletes it, so the zero-byte result could cause data loss.

Reproducer (Linux, current main)

The example uses fault injection to simulate a zero-byte syscall result. It does not establish that the issue occurs on every filesystem.

from pathlib import Path
from tempfile import TemporaryDirectory
from unittest.mock import patch
import pathlib._os

with TemporaryDirectory() as directory:
    source = Path(directory, "source")
    target = Path(directory, "target")
    source.write_bytes(b"important data")

    with (
        patch("pathlib._os._ficlone", None),
        patch("pathlib._os._fcopyfile", None),
        patch("pathlib._os.os.copy_file_range", return_value=0),
        patch("pathlib._os.os.sendfile", return_value=0),
    ):
        source.copy(target)

    print("source:", source.read_bytes())
    print("target:", target.read_bytes())
    # Before the fix, target is b''.

The proposed fix treats zero bytes copied on the first fast-copy call as a reason to try the next mechanism, eventually using buffered copying if needed. A zero-byte return after some data was copied still ends the fast-copy loop. A truly empty source remains supported.

Environment and validation

  • Affects the implementation in CPython main (also relevant to versions with Path.copy()).
  • The behavior was reproduced with the extracted fast-copy logic on Python 3.13 under Linux and mocked syscall results.
  • The complete CPython development-branch test suite has not yet been run locally.

Linked PRs

Activity

  1. added a commit that references this issue on Oct 14, 2026
  2. added
    type-bugAn unexpected behavior, bug, or error
    stdlibStandard Library Python modules in the Lib/ directory
    on Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytopic-pathlibtype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions