ddn.net.sftp.client

SFTP client (draft-ietf-secsh-filexfer-02, protocol version 3).

A non-blocking SFTP client operating on any SshChannel from the DDN core API. The client depends only on the channel interface, never on a concrete SSH implementation or a cryptographic library; applications wire an opened subsystem channel from any transport.

Driving model: construct on a channel, call pump to move bytes and advance pending operations, and poll the returned operation objects. Every potentially-blocking step reports progress instead of blocking.

Types 9

SFTP client limits from the support matrix.

packetMax = 35000Maximum packet payload length
pathMax = 4096Maximum path length in bytes
handleMax = 4096Maximum handle length
diagnosticMax = 8192Maximum server diagnostic text
namesMax = 4096Maximum name entries in one reply
extendedMax = 64Maximum extended attribute pairs in one attrs block
requestsMax = 256Maximum simultaneous requests
handlesMax = 256Maximum locally tracked server handles, independent of server limits
pumpBytesMax = 256 * 1024Maximum channel bytes processed by one pump
pumpFramesMax = 64Maximum complete frames dispatched by one pump
outboundMax = 2 * 1024 * 1024Maximum queued outbound protocol bytes
defaultChunk = 32768Default transfer chunk size before negotiated limits
classSftpException : Exception

Raised for SFTP client violations: framing errors, unexpected responses, or unsupported versions.

Constructors
this(string msg, string file = __FILE__, size_t line = __LINE__)Constructs an SFTP exception.

Progress of an SFTP operation.

pendingOperation is running; call pump again
doneOperation completed successfully
errorOperation failed
structSftpError

Typed SFTP operation error.

Fields
uint codeSFTP status code (0 when the failure is local)
string messageHuman-readable description
Methods
bool isNone() const pure nothrow @safe @nogcReturns: true when no error occurred.

Pollable SFTP operation; pump() on the owning client advances it.

Fields
private T value_
private SftpError error_
private SftpProgress progress_
Methods
void complete(T value)
void fail(SftpError error)
SftpProgress progress() @property constReturns: current progress.
bool done() @property constReturns: true when the operation reached a terminal state.
bool succeeded() @property constReturns: true when the operation succeeded.
SftpError error() @property constReturns: the error when failed.
T value() @propertyReturns: the value when succeeded.
void cancel()Cancels caller interest in this operation. The owning client keeps the request ID reserved until its late reply arrives.

SFTP version 3 client on a caller-supplied channel.

The client is single-threaded and driven by explicit pumping. The channel belongs to the caller; closing the channel terminates all pending operations.

Fields
private SshChannel channel_
private ubyte[] readBuffer_
private ubyte[] writeBuffer_
private size_t writeOffset_
private bool initSent_
private bool initialized_
private uint serverVersion_
private string[string] extensions_
private SftpServerLimits negotiated_
private bool limitsKnown_
private SftpError terminalError_
private bool immediateWork_
private uint nextId_
private SftpPending[uint] pending_
private SftpHandleRecord[] handles_
private const(ubyte)[][] orphanHandles_
Methods
bool initialized() @property constReturns: whether the INIT/VERSION exchange completed.
uint serverVersion() @property constReturns: the negotiated server version (3).
string[string] extensions() @propertyReturns: server extension values by name.
bool failed() @property constReturns: whether channel failure or EOF made the client unusable.
uint outstandingRequests() @property constReturns: the number of request IDs currently reserved by outstanding or cancelled-but-undrained operations.
SftpError error() @property constReturns: the terminal channel-level error, if any.
bool immediateWork() @property constReturns: whether the last pump stopped at its work quota while internal or immediately readable work remained.
bool pump() @trustedAdvances the protocol: sends INIT when needed, moves channel bytes, and dispatches completed server packets.
SftpOperation!(const(ubyte)[]) open(const(ubyte)[] path, uint flags, SftpAttrs attrs = SftpAttrs.init)Opens or creates a remote file.
SftpOperation!bool close(const(ubyte)[] handle)Closes a file or directory handle.
SftpOperation!(const(ubyte)[]) read(const(ubyte)[] handle, ulong offset, uint length)Reads data from a file handle at a position.
SftpOperation!bool write(const(ubyte)[] handle, ulong offset, const(ubyte)[] data)Writes data to a file handle at a position.
SftpOperation!(const(ubyte)[]) opendir(const(ubyte)[] path)Opens a directory for listing.
SftpOperation!(SftpName[]) readdir(const(ubyte)[] handle)Reads the next batch of directory entries.
SftpOperation!bool remove(const(ubyte)[] path)Removes a file.
SftpOperation!bool mkdir(const(ubyte)[] path, SftpAttrs attrs = SftpAttrs.init)Creates a directory.
SftpOperation!bool rmdir(const(ubyte)[] path)Removes a directory.
SftpOperation!(immutable(ubyte)[]) realpath(const(ubyte)[] path)Canonicalizes a path.
SftpOperation!bool rename(const(ubyte)[] oldPath, const(ubyte)[] newPath)Renames a file or directory.
SftpOperation!(immutable(ubyte)[]) readlink(const(ubyte)[] path)Reads a symlink target.
SftpOperation!bool symlink(const(ubyte)[] targetPath, const(ubyte)[] linkPath, SftpSymlinkOrder order = SftpSymlinkOrder.openssh)Creates a symlink.
SftpOperation!SftpServerLimits queryLimits()Queries the server's transfer limits through limits@openssh.com version 1.
SftpOperation!bool posixRename(const(ubyte)[] oldPath, const(ubyte)[] newPath)Renames a path with POSIX replace semantics through posix-rename@openssh.com version 1.
SftpOperation!bool fsync(const(ubyte)[] handle)Flushes written data of an open handle to stable storage through fsync@openssh.com version 1.
SftpOperation!SftpStatVfs statvfs(const(ubyte)[] path)Queries filesystem information for a path through statvfs@openssh.com version 2.
SftpOperation!SftpStatVfs fstatvfs(const(ubyte)[] handle)Queries filesystem information for an open handle through fstatvfs@openssh.com version 2.
SftpOperation!bool hardlink(const(ubyte)[] oldPath, const(ubyte)[] newPath)Creates a hard link through hardlink@openssh.com version 1.
SftpOperation!bool copyData(const(ubyte)[] readHandle, ulong readOffset, ulong readLength, const(ubyte)[] writeHandle, ulong writeOffset)Copies data server-side between two open handles through the copy-data extension version 1 (note: no vendor suffix in the extension name).
uint effectiveReadChunk() const @safe pure nothrowReturns: the maximum READ data length local and negotiated limits allow; server zero-limits leave the local bound in effect.
uint effectiveWriteChunk(size_t handleLength) const @safe pure nothrowParams: handleLength = Length of the handle used in WRITE requests.
SftpOperation!SftpAttrs stat(const(ubyte)[] path)Retrieves attributes for a path while following symbolic links.
SftpOperation!SftpAttrs lstat(const(ubyte)[] path)Retrieves attributes for a path without following symbolic links.
SftpOperation!SftpAttrs fstat(const(ubyte)[] handle)Retrieves attributes for an open handle.
SftpOperation!bool setstat(const(ubyte)[] path, SftpAttrs attrs)Updates attributes for a path.
SftpOperation!bool fsetstat(const(ubyte)[] handle, SftpAttrs attrs)Updates attributes for an open handle.
private SftpHandleRecord handleRecordFor(const(ubyte)[] handle)Finds the tracking record for a server handle.
private SftpHandleRecord requireUsableHandle(const(ubyte)[] handle)Rejects work submitted after close and returns tracking state for handles opened by this client. Unknown handles remain supported.
private SftpHandleRecord recordHandle(const(ubyte)[] handle)Returns existing handle state or creates a locally bounded record.
private ulong effectiveHandleLimit() constReturns: effective local and negotiated open-handle limit.
private size_t activeHandleCount() constReturns: records that may still represent open remote handles.
private size_t ownedHandleCount() constReturns: local handle ownership including deferred orphan cleanup.
private void makeHandleRecordRoom()Evicts only retired tombstones to keep local tracking bounded.
private SftpOperation!bool sendForStatusTracked(const(ubyte)[] payload, SftpHandleRecord record)Sends a status-expecting request and registers it under a handle.
private SftpOperation!bool sendForStatusTracked(const(ubyte)[] payload, SftpHandleRecord[] records)Sends a status request tracked against every participating handle.
private void retireTrackedId(uint id, SftpError error)Retires a completed request from its handle record and releases a pending barrier close when the handle drains.
private void releaseCloseIfDrained(SftpHandleRecord record, bool failWhenBlocked = false)Sends the queued close once every tracked operation on the handle finished. Earlier operation failure is reported only after the wire CLOSE response, so cleanup is never skipped.
private void queueDrainedCloses()Queues every drained close that currently fits local limits.
private bool hasDrainedClose() constReturns: whether a close is ready for immediate local submission.
private void removeHandleRecord(SftpHandleRecord record)Removes a handle record after its close completed.
private void queueOrphanClose(const(ubyte)[] orphanHandle)Sends a best-effort close for a handle whose owning operation was cancelled before its reply arrived.
private void queueOrphanCloses()Submits deferred orphan CLOSE requests while local limits allow.
private bool canQueueOrphanClose() constReturns: whether the next orphan CLOSE fits request/output limits.
private void ensureInitQueued()
private SftpOperation!bool sendForStatus(const(ubyte)[] payload)
private SftpOperation!(const(ubyte)[]) sendForHandle( const(ubyte)[] payload)
private SftpOperation!(SftpName[]) sendNames(const(ubyte)[] payload, bool isReaddir, SftpHandleRecord record = null)
private SftpOperation!(immutable(ubyte)[]) sendSingleName( const(ubyte)[] payload)
private SftpOperation!SftpAttrs pathAttrs(ubyte type, const(ubyte)[] path)
private SftpOperation!SftpAttrs sendForAttrs(const(ubyte)[] payload, SftpHandleRecord record = null)
private SftpOperation!SftpServerLimits sendForLimits( const(ubyte)[] payload)
private SftpOperation!SftpStatVfs sendForStatVfs( const(ubyte)[] payload, SftpHandleRecord record = null)
private void requireExtension(SftpExtensionName name, string expectedVersion = "1")
private uint send(const(ubyte)[] payload)
private uint allocateRequestId()
private void queueBytes(const(ubyte)[] bytes)
private void failAll(string message)
private bool tryDispatch()Attempts to dispatch one complete frame.
private bool hasCompleteFrame() constReturns: whether staging contains a complete validated frame.
private void dispatch(const(ubyte)[] payload)
private void handleVersion(SftpReader reader)
private uint readUint32BE(const(ubyte)[] b) static pure nothrow @nogc @safe
private void encodeAttrs(ref SftpWriter w, SftpAttrs attrs) static
private SftpAttrs decodeAttrs(ref SftpReader reader) static
Constructors
this(SshChannel channel)Constructs a client on an opened channel.
private classSftpHandleRecord

Bookkeeping for one open server handle.

Tracks the request IDs issued against the handle so a barrier close waits for their outcomes, and carries the close operation returned to the caller while that wait lasts.

Fields
const(ubyte)[] handle
uint[] pendingIds
SftpOperation!bool closeOperation
bool closing
bool closeSubmitted
bool closeUncertain
bool closed
SftpError priorError
Constructors
this(const(ubyte)[] serverHandle)Constructs a record for a freshly returned handle.
private enumSftpPendingKind

What a pending operation expects from its response.

status
handle
data
names
singleName
attrs
limits
statvfs
private classSftpPending

Internal pending record carrying response data to the typed operation.

Fields
private Object operation_
SftpStatusCode statusCode
string statusMessage
const(ubyte)[] handleValue
const(ubyte)[] dataValue
SftpName[] namesValue
SftpAttrs attrsValue
SftpServerLimits limitsValue
SftpStatVfs statvfsValue
uint expectedDataLength
SftpHandleRecord[] ownerRecords
SftpHandleRecord closesRecord
Methods
bool operationAlreadyTerminal()Returns: whether the operation was already terminal before the reply arrived (a cancelled attempt whose handle leaked).
SftpError operationError()Returns: an existing cancellation/failure on the public operation.
void finish()Moves the collected response into the typed operation.
void requireKind(SftpPendingKind expected, string response) const
void fail(SftpError error)
Constructors
this(Object operation)Constructs a pending record.