Robbiblubber.Util.FileStorageAdapters.Ssh
1.0.2
dotnet add package Robbiblubber.Util.FileStorageAdapters.Ssh --version 1.0.2
NuGet\Install-Package Robbiblubber.Util.FileStorageAdapters.Ssh -Version 1.0.2
<PackageReference Include="Robbiblubber.Util.FileStorageAdapters.Ssh" Version="1.0.2" />
<PackageVersion Include="Robbiblubber.Util.FileStorageAdapters.Ssh" Version="1.0.2" />
<PackageReference Include="Robbiblubber.Util.FileStorageAdapters.Ssh" />
paket add Robbiblubber.Util.FileStorageAdapters.Ssh --version 1.0.2
#r "nuget: Robbiblubber.Util.FileStorageAdapters.Ssh, 1.0.2"
#:package Robbiblubber.Util.FileStorageAdapters.Ssh@1.0.2
#addin nuget:?package=Robbiblubber.Util.FileStorageAdapters.Ssh&version=1.0.2
#tool nuget:?package=Robbiblubber.Util.FileStorageAdapters.Ssh&version=1.0.2
robbiblubber.org SSH File Storage Adapter Library
The robbiblubber.org SSH File Storage Adapter Library provides two independent implementations for
Robbiblubber.Util.FileStorageAdapters:
SshAdapterexposes a remote POSIX file system by executing commands over an SSH connection.SftpAdapteraccesses files through the SSH File Transfer Protocol and does not require a remote shell.
The repository can be found at https://bitbucket.org/robbiblubber/robbiblubber.util.filestorageadapters.net/. API documentation is available from https://robbiblubber.lima-city.org/. For general information see http://robbiblubber.org/.
The library is provided under the MIT license and may be used under the conditions of that license agreement.
Remote System Requirements
SshAdapter currently targets GNU/Linux and similar POSIX systems. The remote login shell must support
ordinary POSIX shell syntax, and GNU find and GNU stat must be installed. Paths are quoted as POSIX
shell words before they are included in commands.
SftpAdapter only requires the server's SFTP subsystem. Both adapters treat / as the actual root exposed
by the server. Their initial directory is only the starting point; navigation above it remains possible when
the account and server permit it. A server-side SFTP chroot remains an unavoidable protocol boundary.
Symbolic links are identified without recursively following them during directory-size, delete, copy, or download operations. A link whose target is a directory is exposed as a directory, but recursive transfer of that directory link is rejected to avoid cycles and unintended traversal.
Opening a Directory
using Robbiblubber.Util.FileStorageAdapters;
using Robbiblubber.Util.FileStorageAdapters.Ssh;
SshAdapterOptions options = new()
{
ConnectTimeout = TimeSpan.FromSeconds(30),
OperationTimeout = TimeSpan.FromMinutes(5),
KeepAliveInterval = TimeSpan.FromSeconds(30),
HostKeyFingerprint = "SHA256:replace-with-the-server-fingerprint"
};
using SshAdapter adapter = new("server.example.org", 22, "alex", "password", options);
IDirectory directory = adapter.OpenDirectory("/srv/data");
The SFTP adapter uses the same authentication and connection settings and adds an optional transfer buffer size:
SftpAdapterOptions options = new()
{
ConnectTimeout = TimeSpan.FromSeconds(30),
OperationTimeout = TimeSpan.FromMinutes(5),
KeepAliveInterval = TimeSpan.FromSeconds(30),
BufferSize = 64 * 1024,
HostKeyFingerprint = "SHA256:replace-with-the-server-fingerprint"
};
using SftpAdapter adapter = new("server.example.org", 22, "alex", "password", options);
IDirectory directory = adapter.OpenDirectory("/srv/data");
The directory must already exist. Keep each adapter alive while using its elements, and dispose it after those operations are complete. Completed read snapshots remain usable after adapter disposal.
Authentication and Host Keys
Private-key authentication is configured through PrivateKeyPath and the optional
PrivateKeyPassphrase. HostKeyFingerprint accepts the SHA-256 fingerprint with or without the
SHA256: prefix. The adapters only install a fingerprint-validation handler when a fingerprint
is configured; they do not implement a known_hosts file or a trust-on-first-use
prompt. Configure a verified fingerprint to pin the server's identity.
Supported Operations
The adapter supports listing, path lookup, name filtering, stream-based reads, file and directory creation and deletion, recursive copy and move, and local upload and download through the common FileStorageAdapters API.
Files can be transferred to and from other adapters through streams. Directory
transfers are recursive. CopyToAsync(destination) places the source inside
the destination directory under its existing name; the overload with a name
argument selects a different destination name.
Existing content is not overwritten unless overwrite is true. Copying a
directory into an existing directory of the same name with overwrite enabled
merges the contents and retains unrelated destination files. Cross-adapter
moves copy the content before deleting the source and are not atomic.
Persisted Attachment Configurations
SshAttachConfig and SftpAttachConfig store connection settings,
authentication parameters, and the initial path. Their adapter discriminators
are ssh and sftp, respectively. For an existing SFTP adapter:
using System.Text.Json.Nodes;
SftpAttachConfig config = new(adapter)
{
InitialPath = "/srv/data"
};
JsonObject data = config.Serialize();
AttachConfig restored = AttachConfig.Open(data);
using SftpAdapter restoredAdapter = (SftpAdapter) restored.CreateAdapter();
IDirectory restoredDirectory = restoredAdapter.OpenDirectory(restored.InitialPath);
For a shell-command SSH adapter, use SshAttachConfig and SshAdapter in the
same pattern. Serialized configurations can contain passwords and private-key
passphrases. Private-key paths refer to local files; the key files must remain
available when the configuration is restored.
Example
With directory opened through either adapter:
IFile source = await directory.GetFileAsync("input/report.txt");
await using Stream content = await source.ReadAsync();
IDirectory output = await directory.CreateDirectoryAsync("output");
IFile copy = await output.CreateFileAsync("report.txt", content, overwrite: true);
Console.WriteLine(copy.Path);
Streams returned by ReadAsync are owned by the caller and must be disposed.
Streams supplied to CreateFileAsync remain owned by the caller and are not
disposed by the adapter.
Concurrent access and buffered reads
Client operations on one adapter are serialized. ReadAsync downloads the entire
file into temporary local storage before returning a read-only, seekable stream.
The returned stream does not hold the adapter connection or its operation gate.
Dispose each returned stream to remove its temporary storage. Each stream supports
one consumer; do not concurrently read, seek or dispose that same stream.
DisposeAsync rejects new client accesses and waits for the active client access
before closing the connection. Dispose waits synchronously for the same result.
A copy or recursive transfer consists of several accesses and can fail between
steps if its adapter is closed early. Neither copies nor moves are transactions.
Use an exclusively owned client; externally supplied streams must not re-enter
the destination adapter from their read or dispose callbacks during an upload.
See THREAD-SAFETY-PLAN.md in the source archive for the implementation stage,
remaining conflict-handling work and validation status.
Conflict guarantees
SSH uploads now stage data beside the destination, verify the expected byte length and publish through GNU ln -T (create-only) or mv -fT (overwrite). This requires GNU mktemp, chmod, wc, ln and mv; create-only requires hard links. Non-seekable input is buffered locally first. SSH temporary files use short names in the destination directory. SSH overwrite preserves existing Unix mode bits, but does not copy ownership or ACLs. SFTP create-only uses FileMode.CreateNew. SFTP overwrite uploads to a temporary file in the destination directory, closes it and publishes it using the server's POSIX rename extension. Unsupported servers reject overwrite uploads without deleting the destination. Cleanup after a failure is best effort. SFTP replacement does not copy ownership, permissions or ACLs.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Robbiblubber.Util.FileStorageAdapters (>= 1.0.2)
- SSH.NET (>= 2026.0.0)
-
net8.0
- Robbiblubber.Util.FileStorageAdapters (>= 1.0.2)
- SSH.NET (>= 2026.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.