Files

Files provides file and directory handles on a connected POSIX host. It is the backend for SFTP through sshmux, but you can use it directly through either Connection or Protocol. The target needs Python 3.11+ and its standard library; rmote transfers the Tool code automatically.

Use FileSystem for operations by path, Files for open descriptors, and FileSync or Rsync for synchronization. Files writes directly to the opened file. It does not stage an upload for atomic replacement.

Open, read, and write

This runnable example uses a local Python subprocess as the target. Replace Connection.from_local() with another transport to reach a remote host; file paths then refer to that host.

import tempfile
from pathlib import Path

from rmote.sync import Connection
from rmote.tools import Files
from rmote.tools.files import OpenFlags

with tempfile.TemporaryDirectory() as directory:
    path = str(Path(directory) / "example.txt")
    with Connection.from_local() as remote:
        session_id = remote(Files.start)
        try:
            handle = remote(
                Files.open, session_id, path,
                OpenFlags.READ | OpenFlags.WRITE | OpenFlags.CREAT | OpenFlags.EXCL,
            )
            remote(Files.write, session_id, handle, 0, b"hello\n")
            assert remote(Files.read, session_id, handle, 0, 6) == b"hello\n"
            remote(Files.fsync, session_id, handle)
            remote(Files.close, session_id, handle)
        finally:
            remote(Files.release, session_id)

With async Protocol, use await remote(Files.method, ...) for each call.

Session and descriptor ownership

Files.start() returns a new session ID. It also accepts a caller-generated unique ID. Every subsequent operation requires that ID. File and directory handles are opaque bytes, valid only in their owning session. A wrong session, closed handle, or wrong handle type raises OSError; an unknown session does not create one. This prevents accidental handle reuse across mux sessions. It does not isolate paths or restrict the remote user’s permissions.

close closes one handle. release closes all remaining file and directory handles and removes the session; repeated release is safe. A file descriptor continues to refer to the opened file after it is renamed or unlinked. Keep the connection open until all operations and cleanup have finished.

A timeout or cancellation stops local waiting, not a remote file operation. Before calling release, wait for outstanding operations, including start and open, to complete. In async code, retain and shield the call task, then await its completion during cancellation cleanup. Otherwise, a late start can create a session after cleanup. The SFTP adapter handles this ordering.

Each session permits 128 handles. Calls in one session are serialized; independent sessions can proceed concurrently. read and write use explicit non-negative offsets and transfer at most 256 KiB per call. Reads can return fewer bytes; empty bytes indicate EOF for a nonzero request. Writes complete the supplied data before returning, but do not imply fsync.

opendir returns a directory handle. Call readdir until it returns an empty list; each batch has at most 64 (name, stat_result) pairs. Entry order is unspecified. Close the handle or release the session after iteration.

Open flags

Import OpenFlags from rmote.tools.files and combine members with |. These are SFTP values, not local os.O_* flags. Files.open translates them on the target OS and also accepts integer wire values.

Flag

Value

Effect

READ

0x01

Permit reads

WRITE

0x02

Permit writes

APPEND

0x04

Append writes, regardless of their supplied offset

CREAT

0x08

Create the file if absent

TRUNC

0x10

Truncate the file on open

EXCL

0x20

Fail if the file already exists

At least READ or WRITE is required. APPEND and TRUNC require WRITE; TRUNC and EXCL require CREAT. Unknown bits raise ValueError. Only regular files can be opened; special files such as FIFOs are rejected. Creation uses mode (default 0o666) subject to the target process’s umask.

setstat and fsetstat accept a dictionary with optional size, permissions, uid/gid, and atime/mtime fields. Supply ownership and timestamp fields in pairs. Times are Unix timestamps in seconds. These operations can partially succeed before an OS error; they are not a transaction.

The SFTP adapter separately uses AttrFlags from rmote.cli.sftp to encode attribute presence on the wire. Direct Files callers pass dictionaries and do not need that enum. Extended SFTP attributes are unsupported.

API reference

class rmote.tools.files.Files[source]

Bases: Tool

Keep file and directory handles within an explicit session.

Start a session and pass its session_id on every operation. Always call release(), including after cancellation. Handles are opaque and cannot be used by another session. Paths use the remote process’s working directory and permissions; this tool is not a sandbox.

Synchronous methods run in the protocol executor. A per-session lock serializes access with release; independent sessions can run concurrently. The owning remote process also releases descriptors when it exits.

MAX_HANDLES: ClassVar[int] = 128
MAX_IO: ClassVar[int] = 262144
classmethod close(session_id, handle)[source]
Return type:

None

classmethod fsetstat(session_id, handle, attrs)[source]
Return type:

None

classmethod fstat(session_id, handle)[source]
Return type:

stat_result

classmethod fsync(session_id, handle)[source]
Return type:

None

classmethod mkdir(session_id, path, mode=511)[source]
Return type:

None

classmethod open(session_id, path, flags, mode=438)[source]

Open a regular file with SFTP v3 flags and return an opaque handle.

Combine OpenFlags members; integer wire values are also accepted. The flags are translated on the remote OS, never on the caller’s OS. Special files are rejected; nonblocking open prevents a FIFO hang.

Return type:

bytes

classmethod opendir(session_id, path)[source]
Return type:

bytes

classmethod read(session_id, handle, offset, size)[source]
Return type:

bytes

classmethod readdir(session_id, handle)[source]

Return at most 64 entries. An empty batch marks end of directory.

Return type:

list[tuple[Text, stat_result]]

Return type:

Text

classmethod realpath(session_id, path)[source]
Return type:

Text

classmethod release(session_id)[source]

Close all handles, including directory iterators. Safe to repeat.

Return type:

None

classmethod remove(session_id, path, directory=False)[source]
Return type:

None

classmethod rename(session_id, source, target, replace=False)[source]
Return type:

None

classmethod session(cls, session_id)[source]
Return type:

Iterator[FileSession]

classmethod setstat(session_id, path, attrs)[source]
Return type:

None

classmethod start(session_id=None)[source]

Return the ID of a new empty session.

A caller may supply its own unique ID when it needs to release a session after a lost or cancelled start response. Existing IDs fail.

Return type:

Text

classmethod stat(session_id, path, follow=True)[source]
Return type:

stat_result

Return type:

None

classmethod write(session_id, handle, offset, data)[source]

Complete every byte of a write before returning success.

Return type:

None

class rmote.tools.files.OpenFlags(*values)[source]

Bases: IntFlag

SFTP v3 file open flags, independent of the remote OS.

ALL = 63
APPEND = 4
CREAT = 8
EXCL = 32
READ = 1
TRUNC = 16
WRITE = 2