ftp
FTP and FTPS (RFC 959, explicit AUTH TLS and implicit TLS, both channels protected) over cx-platform/net, and the seven-verb file surface of file_surface.md instantiated over it: list, stat, get, put, rename, delete, mkdir under a bound root no path and no link escapes, resumable transfers over REST, size, time and stall bounds. Every decision is a pure def — the reply reader, the data-endpoint check that refuses the FTP bounce, the TLS posture check, the resolution, the classification of reply codes onto the contract's nine classes, the resume plan — and the nine verbs charge the net capability for both connections.
ftp:resolve
[$ftp:resolve] ($root::string $path::string) -> string — Resolve a path lexically beneath the bound root; a path that resolves outside it raises CXER6805.
[?lib 'cx-platform/ftp']
[$ftp:resolve '/srv/drop' '/etc/shadow']
cx-err:CXER6805
ftp:read-reply
[$ftp:read-reply] ($text::string) -> element — Read one RFC 959 reply, single-line or multiline, as [reply code= text=] with one [line] per line; a reply whose closing line never arrives raises CXER6804.
ftp:check-data-endpoint
[$ftp:check-data-endpoint] ($peer::string $reply) -> element — The endpoint a data connection may be dialed at: the control connection's peer and only the port from a 227 or 229 reply; a 227 naming another host is the FTP bounce and raises CXER6802.
ftp:check-tls
[$ftp:check-tls] ($posture $observed) -> bool — True when the observed control and data channels are both TLS under a declared tls=:explicit or tls=:implicit posture; a refused AUTH TLS or a cleartext data channel raises CXER6801.
ftp:classify
[$ftp:classify] ($reply) -> any — Map an FTP reply code, read with the verb it answered, onto the file surface's nine error classes; a completion answers [classified state=:complete], an unclassified code is :protocol and not retryable.
ftp:plan-transfer
[$ftp:plan-transfer] ($request $partial) -> element — The resume plan — offset, remaining, address, TYPE I and the REST/RETR or REST/STOR pair — or CXER6816 for a partial that does not agree with the source or a peer that refuses REST.
ftp:resolve-pair
[$ftp:resolve-pair] ($root::string $from::string $to::string) -> element — Resolve BOTH of rename's paths beneath the bound root as [pair from= to=]; either one escaping raises CXER6805 — RNFR and RNTO are two commands and both are confined.
ftp:link-target
[$ftp:link-target] ($root::string $entry) -> string — Resolve a listing entry's link target against the root (a relative target from the link's own directory); a target outside the root raises CXER6806, the peer's filesystem and not the caller's path.
ftp:check-name
[$ftp:check-name] ($name::string) -> string — A name is one path segment: a separator, CR, LF or NUL raises CXER6807 where it enters — on FTP's line-oriented control channel a CR is a second command.
ftp:check-binding
[$ftp:check-binding] ($b) -> element — Judge a binding: a credential value raises CXER6310, active mode without a declared mode=:active raises CXER6818, a missing or loosened TLS posture raises CXER6801; a missing root, host, scheme or basic credential handle is reported as [findings].
ftp:check-bounds
[$ftp:check-bounds] ($b $obs $now) -> bool — True when an observation is inside the bounds, every bound inclusive: entries over max-entries raise CXER6813, octets over max-bytes CXER6814, a duration or a stall past the floor CXER6815; $now is an argument.
ftp:bind-bounds
[$ftp:bind-bounds] ($ceiling $bounds) -> element — The effective bounds, each the lower of the ceiling and the deployment's; a deployment raising a bound is refused CXER6813 at binding time.
ftp:read-listing
[$ftp:read-listing] ($root::string $format $text::string $path::string) -> element — Read MLSD (:mlsd) or LIST (:list) output as the file surface's [listing] of [entry] elements, complete or a refusal; a LIST shape this module does not recognize raises CXER6819 and is never half-read.
ftp:read-entry
[$ftp:read-entry] ($root::string $path::string $text::string) -> element — Read MLST's fact line as the [entry] for one path — what the entry is and never what it points at, a link's target checked against the root.
ftp:open
[$ftp:open] ($binding $opts::map) -> element — Open an FTPS session: dial under net, TLS from the first octet or AUTH TLS, then USER/PASS, PBSZ 0, PROT P and TYPE I, both channels held to the declared posture; idempotent per binding.
ftp:close
[$ftp:close] ($session) -> null — QUIT and close the control connection; idempotent.
ftp:list
[$ftp:list] ($session $path::string $opts::map) -> element — List one directory beneath the root over a data connection dialed only at the control peer — MLSD where the peer offers RFC 3659, LIST otherwise — bounded by entries and octets.
ftp:stat
[$ftp:stat] ($session $path::string $opts::map) -> element — MLST one path beneath the root and answer its [entry]; a peer without RFC 3659 is refused CXER6804 rather than guessed at.
ftp:get
[$ftp:get] ($session $path::string $opts::map) -> element — Transfer a file from the peer in TYPE I, resumably over REST from the partial the caller holds; the octets ride as the [transfer]'s [data], and a cut transfer is CXER6800 carrying the partial it resumes from.
ftp:put
[$ftp:put] ($session $path::string $source $opts::map) -> element — Transfer octets to the peer with STOR, resumably with REST and never APPE; an existing path is :exists before a byte is sent — put never overwrites implicitly.
ftp:rename
[$ftp:rename] ($session $from::string $to::string $opts::map) -> element — RNFR then RNTO with both paths resolved beneath the root; never over an existing target.
ftp:delete
[$ftp:delete] ($session $path::string $opts::map) -> element — Delete one file (DELE) or one empty directory (RMD), the kind MLST established; never recursive, and an absent path is :not-found.
ftp:mkdir
[$ftp:mkdir] ($session $path::string $opts::map) -> element — Make one directory (MKD), one segment; there is no implicit parent tree.
ftp:test-server
[$ftp:test-server] ($spec) -> element — Boot the in-process FTPS test server on 127.0.0.1 over an in-memory tree the spec seeds, with the TLS identity and the adversarial postures it declares.
ftp:test-server-stop
[$ftp:test-server-stop] ($server) -> null — Stop an in-process test server.
ftp:test-server-file
[$ftp:test-server-file] ($server $path::string) -> any — The octets the in-process test server holds at a path, or null.