# `Opsmaru.Incus.SFTP.File`
[🔗](https://github.com/upmaru/opsmaru-incus/blob/v0.1.0/lib/opsmaru/incus/sftp/file.ex#L1)

An open SFTP file, matching the pinned `pkg/sftp` v1.13.10 `*sftp.File` as
`GetInstanceFileSFTP` and `GetStoragePoolVolumeFileSFTP` configure it: 128 KiB
packets, pipelined reads with up to 64 requests per file, and writes sent one
at a time unless `read_from_with_concurrency/3` is used.

Any process may use a file. As with Go's per-file lock, cursor calls (`read/2`,
`write/2`, `seek/3`, `write_to/2`, `read_from/2`, `sync/1`, `close/1`) take
turns, while positional and metadata calls may overlap one another but not a
cursor call, and a waiting cursor call holds back later ones. A process that
exits while holding or waiting for the lock releases it.

Reads return `{:ok, data}`, or `{:eof, data}` when they reach the end of the
file. Other failures keep the byte count Go returns in `response.count`, and
for reads the bytes received in `response.data`. A WRITE, CLOSE, FSETSTAT or
FSYNC whose outcome is unknown is `:uncertain` and never resent. After
`close/1`, every call fails with `:file_closed` without I/O.

# `chmod`

Go `Chmod` (FSETSTAT).

# `chown`

Go `Chown` (FSETSTAT): integer ids wrap to uint32 as natively.

# `close`

Go `Close`: invalidates the file before sending CLOSE, as natively.

# `name`

Go `Name`: the path as given to open.

# `read`

Go `Read`: up to `count` bytes at the file's position, which moves past them.

# `read_at`

Go `ReadAt`: up to `count` bytes at `offset`, leaving the position unchanged.

# `read_from`

Go `ReadFrom`: writes an enumerable of binary chunks at the file's position,
grouped into full 128 KiB WRITEs sent one at a time. Returns
`{:ok, bytes_read}`. Unlike Go, a failed final short write is reported rather
than ignored (an approved difference).

# `read_from_with_concurrency`

Go `ReadFromWithConcurrency`: as `read_from/2`, with up to `concurrency` WRITEs
in flight (values below 1 or above 64 mean 64). After a failure no more chunks
are sent and the position moves to the failed chunk's offset.

# `seek`

Go `Seek`: `:start`, `:current` or `:end` (which sends FSTAT). A negative result
fails with `:invalid_arguments` and leaves the position unchanged.

# `set_extended_data`

Go `SetExtendedData` (FSETSTAT): `{type, data}` pairs.

# `stat`

Go `Stat` (FSTAT), named by the base of the opened path.

# `sync`

Go `Sync` (`fsync@openssh.com`). Without the extension announced as `"1"` it
fails locally with status 8, "fsync not supported", as natively.

# `truncate`

Go `Truncate` (FSETSTAT): the size wraps to uint64 as natively.

# `write`

Go `Write`: writes `data` at the file's position, which moves past the bytes written.

# `write_at`

Go `WriteAt`: writes `data` at `offset`, leaving the position unchanged.

# `write_to`

Go `WriteTo`: streams the file from its position into `sink`, a function that
receives each binary chunk and must return `:ok`. It first sends Go's STAT of
the opened path. Regular files larger than 128 KiB are read ahead with up to
64 pipelined requests and delivered in order; others are read one request at a
time. Returns `{:ok, bytes_written}`. As natively, a pipelined copy leaves the
position at the offset of the read that found the end.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
