yazi/RCLONE_VFS.md
Oded Falik 6753ade6ff feat(rclone): add read-only rclone VFS provider
Adds an `rclone://<remote>/<path>` scheme backed by the rclone CLI, giving
yazi native browsing of any of rclone's 100+ remotes (S3, GCS, Azure, SFTP,
WebDAV, local, …) without a FUSE mount.

- New SchemeKind::Rclone threaded through the scheme/URL type system,
  mirroring Sftp (remote, virtual, Unix-path, byte-encoded path semantics).
- yazi-vfs rclone provider:
  - read_dir via `rclone lsjson`
  - metadata via `rclone lsjson --stat` (synthesized POSIX mode)
  - seekable read-only File streaming `rclone cat --offset`; seek respawns
    the child at the new offset. Detects premature EOF and unknown sizes.
  - all write ops return Unsupported (read-only for now)
  - `remote:/path` targets preserve the leading slash, so filesystem-like
    backends (local, sftp) work alongside object stores.
- Config: [services.<name>] type = "rclone", remote = "..."
- Tests:
  - tests/rclone_local.rs: hermetic, points an rclone `local` remote at a
    temp fixture dir, so it needs no cloud/credentials and skips if `rclone`
    isn't installed. Covers list, read, seek, missing-object, and a >8 MiB
    parallel multi-chunk copy with position-varying bytes.
  - tests/rclone_read.rs: env-driven live tests against a real remote
    (ignored by default; paths supplied via env vars, nothing hard-coded).
2026-07-07 12:17:38 -07:00

3.8 KiB

rclone VFS provider for yazi

Browse any of rclone's 100+ remotes — S3, GCS, Azure, Backblaze, SFTP, WebDAV, Google Drive, … — natively inside yazi, with no FUSE/NFS mount. It rides on yazi's existing VFS layer (the same infrastructure behind the built-in SFTP provider) and shells out to the rclone binary you already have.

Addresses the "Integrate rclone" item on #3395. Read-only for now.


Usage

Point a VFS service at an existing rclone remote in ~/.config/yazi/vfs.toml:

[services.gcs]
type   = "rclone"
remote = "gcs"          # any remote from `rclone listremotes`

[services.s3]
type       = "rclone"
remote     = "s3"
# binary      = "/opt/homebrew/bin/rclone"   # optional: path to rclone
# config_file = "/path/to/rclone.conf"       # optional: non-default config
# flags       = ["--fast-list"]              # optional: extra rclone args

Then browse with a rclone://<service>//<path> URL:

rclone://gcs//my-bucket/some/dir
rclone://s3//my-bucket

rclone://gcs// (empty path) lists the remote's buckets. Everything else is normal yazi navigation, preview, and copy-out.

What works

  • Directory listingrclone lsjson
  • Metadatarclone lsjson --stat (size + mtime; POSIX mode is synthesized since object stores have no permissions)
  • Reading / preview / copy-out — a seekable file handle that streams rclone cat --offset
  • Object stores and filesystem backendsremote:/path keeps its leading slash, so local, sftp, etc. work alongside S3/GCS/…

What doesn't (yet)

  • Writes — every mutating op returns Unsupported. Read-only by design for a first cut; uploads (rclone rcat/copyto) and mutations are a clean follow-up.
  • Remote search — still disabled globally for remote schemes (per #3395).

How it works

yazi's provider dispatch is a set of static enums, so a new rclone:// scheme threads a SchemeKind::Rclone variant through the scheme/URL type system — mostly folded into the existing Sftp arms, since rclone remotes share the same traits (remote, virtual, Unix-style paths).

The interesting part is the file handle. rclone has no persistent open-file concept, so Provider::File (which must be AsyncRead + AsyncSeek) is implemented by streaming rclone cat from the current position; a seek kills the child process and the next read respawns rclone cat --offset <new>. This is enough for yazi's previewer and for its parallel chunked copier (which opens several handles and seeks each to its 8 MiB slice).

Testing

Two layers, no credentials required to run CI:

  • tests/rclone_local.rs — hermetic. Points an rclone local remote at a generated temp directory, so lsjson/cat run against the filesystem. Needs only the rclone binary; skips itself if rclone isn't installed (so CI without rclone stays green). Covers listing, read, seek, missing-object, and a

    8 MiB parallel multi-chunk copy with position-varying bytes so any offset slip is caught.

  • tests/rclone_read.rs — live, #[ignore]d. Runs against a real remote you point it at via env vars (YAZI_RCLONE_TEST_SMALL / _BIG / _DIR) — nothing is hard-coded.

Verified end-to-end against live GCS and S3 buckets: byte-exact reads, mid-file seeks, and both simple and progressive (parallel multi-chunk) copy-out.

Notes / open questions for upstream

  • CLI vs daemon. This spawns an rclone process per operation — simple, no lifecycle to manage. A long-lived rclone rcd (remote-control daemon) would cut per-op latency and enable connection pooling like the SFTP provider does. Happy to go either way.
  • Read-only scope. Matches the earlier S3 PR (#3843). Writes can follow once the direction is settled.