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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Robbiblubber.Util.FileStorageAdapters.Ssh" Version="1.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Robbiblubber.Util.FileStorageAdapters.Ssh" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="Robbiblubber.Util.FileStorageAdapters.Ssh" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Robbiblubber.Util.FileStorageAdapters.Ssh --version 1.0.2
                    
#r "nuget: Robbiblubber.Util.FileStorageAdapters.Ssh, 1.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Robbiblubber.Util.FileStorageAdapters.Ssh@1.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Robbiblubber.Util.FileStorageAdapters.Ssh&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=Robbiblubber.Util.FileStorageAdapters.Ssh&version=1.0.2
                    
Install as a Cake Tool

robbiblubber.org SSH File Storage Adapter Library

The robbiblubber.org SSH File Storage Adapter Library provides two independent implementations for Robbiblubber.Util.FileStorageAdapters:

  • SshAdapter exposes a remote POSIX file system by executing commands over an SSH connection.
  • SftpAdapter accesses 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.2 74 10/20/2026
1.0.1 105 9/28/2026