ftp(3)
πΈ ftp β Erlang Module Definition πΈ
okay so bestie, welcome to ftp(3), the Erlang module page. yes the manual section is 3 and yes this is the Erlang Module Definition. grab a snack, we're doing this π
β¨ NAME β¨
ftp β A File Transfer Protocol client. that's it, that's the girl π¦
π DESCRIPTION π
This module implements a client for file transfer according to a subset of the File Transfer Protocol (FTP), see RFC 959. lowkey a whole classic πΌ
The FTP client always tries to use passive FTP mode and only resorts to active FTP mode if this fails. This default behavior can be changed by start option mode. so it's passive-first, no cap β¨
For a simple example of an FTP session, see FTP User's Guide. go read it, it's giving tutorial energy π
The return values of the following functions depend much on the implementation of the FTP server at the remote host. In particular, the results from ls and nlist varies. Often real errors are not reported as errors by ls, even if, for example, a file or directory does not exist. nlist is usually more strict, but some implementations have the peculiar behaviour of responding with an error if the request is a listing of the contents of a directory that exists but is empty. π servers are gonna server, bestie
π Errors π
The possible error reasons and the corresponding diagnostic strings returned by formaterror/1 are as follows:
echunkβ Synchronization error during chunk sending according to one of the following:- call is made to
send_chunk/2orsend_chunk_end/1before a call tosend_chunk_start/2. - call has been made to another transfer function during chunk sending, that is, before a call to
send_chunk_end/1.
- call is made to
so basically you skipped a step and the vibe check failed π
eclosedβ The session is closed. it's over, she's gone πeconnβ Connection to the remote server is prematurely closed. rude of them tbh π€ehostβ Host is not found, FTP server is not found, or connection is rejected by FTP server. can't find her, she's not answering π«₯eloginβ User is not logged in. log in first bestie πͺenotbinaryβ Term is not a binary.epathβ No such file or directory, or directory already exists, or permission denied.etypeβ No such type.euserβ Invalid username or password. who even are you πetnospcβ Insufficient storage space in system [452].epnospcβ Exceeded storage allocation (for current directory or dataset) [552].efnamenaβ Filename not allowed [553].
π§ DATA TYPES π§
client() :: pid().
yep, a client is just a pid. tiny, iconic, powerful π
π FUNCTIONS π
heads up bestie: a LOT of these have the same deprecation notice, so I'm gonna say it once here and then keep the exact notice on each one because facts are facts. π Deprecated: the legacy protocol support will be dropped in OTP-30, use a more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
account/2
account(Client :: client(), Acc :: string()) ->
ok | {error, Reason :: term()}.
Deprecated: ftp:account/2 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Sets the account for an operation, if needed. only if needed, so don't stress π«Ά
append/3
append(Pid :: pid(),
LocalFileName :: file:filename(),
RemoteFileName :: file:filename()) ->
ok | {error, Reason :: term()}.
Deprecated: ftp:append/3 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Transfers the file LocalFile to the remote server. If RemoteFile is specified, the name of the remote file that the file is appended to is set to RemoteFile, otherwise to LocalFile. If the file does not exists, it is created. not me appending to a file that doesn't even exist yet... it gets created, slay π
append_bin/3
append_bin(Pid :: pid(), Bin :: binary(), RemoteFile :: string()) ->
ok | {error, Reason :: term()}.
Deprecated: ftp:append_bin/3 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Transfers the binary Bin to the remote server and appends it to the file RemoteFile. If the file does not exist, it is created. binaries on binaries on binaries, she ate π
append_chunk/2
append_chunk(Client :: client(), Bin :: binary()) ->
ok | {error, Reason :: term()}.
Deprecated: ftp:append_chunk/2 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Transfers the chunk Bin to the remote server, which appends it to the file specified in the call to append_chunk_start/2. one lil chunk at a time, tiny bites π
fr fr: for some errors, for example, file system full, it is necessary to call append_chunk_end to get the proper reason. like, the error might be hiding until you close it out. messy but true π
append_chunk_end/1
append_chunk_end(Client :: client()) ->
ok | {error, Reason :: term()}.
Deprecated: ftp:append_chunk_end/1 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Stops transfer of chunks for appending to the remote server. The file at the remote server, specified in the call to append_chunk_start/2, is closed by the server. okay that's a wrap, closing the curtain π
append_chunk_start/2
append_chunk_start(Client :: client(), RemoteFile :: string()) ->
ok | {error, Reason :: term()}.
Deprecated: ftp:append_chunk_start/2 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Starts the transfer of chunks for appending to the file RemoteFile at the remote server. If the file does not exist, it is created. starting era β¨
cd/2
cd(Client :: client(), Dir :: string()) ->
ok | {error, Reason :: term()}.
Deprecated: ftp:cd/2 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Changes the working directory at the remote server to Dir. moving out, moving in, moving on πΆβοΈ
close/1
close(Client :: client()) -> ok.
Deprecated: ftp:close/1 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Ends an FTP session, created using function open. and that's the end of that chapter π
delete/2
delete(Client :: client(), File :: string()) ->
ok | {error, Reason :: term()}.
Deprecated: ftp:delete/2 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Deletes the file File at the remote server. gone, reduced to atoms π
formaterror/1
formaterror(Tag :: atom() | {error, atom()}) -> string().
Deprecated: ftp:formaterror/1 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Given an error return value {error, AtomReason}, this function returns a readable string describing the error. translating the cryptic into the readable, your fave π«Ά
lcd/2
lcd(Client :: client(), Dir :: string()) ->
ok | {error, Reason :: term()}.
Deprecated: ftp:lcd/2 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Changes the working directory to Dir for the local client. note the L bestie, local not remote π
lpwd/1
lpwd(Client :: client()) -> {ok, Dir :: string()}.
Deprecated: ftp:lpwd/1 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Returns the current working directory at the local client. where am I?? local edition π
ls/2
ls(Client :: client(), Dir :: string()) ->
{ok, Listing :: string()} | {error, Reason :: term()}.
Deprecated: ftp:ls/2 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Returns a list of files in long format. the deluxe version β¨
Dir can be a directory or a file. The Dir string can contain wildcards. wildcards?? spicy π
ls/1 implies the current remote directory of the user. (yes, ls/1, not ls/2 β that's what it says, i don't make the rules)
The format of Listing depends on the operating system. On UNIX, it is typically produced from the output of the ls -l shell command. so basically it's ls -l wearing an Erlang hat π
mkdir/2
mkdir(Client :: client(), Dir :: string()) ->
ok | {error, Reason :: term()}.
Deprecated: ftp:mkdir/2 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Creates the directory Dir at the remote server. manifesting a directory into existence π¦
nlist/2
nlist(Client :: client(), Pathname :: string()) ->
{ok, Listing :: string()} | {error, Reason :: term()}.
Deprecated: ftp:nlist/2 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Returns a list of files in short format. the lowkey version, faster and leaner πβοΈ
Pathname can be a directory or a file. The Pathname string can contain wildcards.
nlist/1 implies the current remote directory of the user.
The format of Listing is a stream of filenames where each filename is separated by <CRLF> or <NL>. Contrary to function ls, the purpose of nlist is to enable a program to process filename information automatically. so it's the machine-readable one β nlist is for the computers, ls is for your eyes π
open/2
open(Host :: string() | inet:ip_address(), Opts) ->
{ok, Client :: client()} | {error, Reason :: term()}
when
Opts :: [Opt],
Opt :: StartOption | OpenOption,
StartOption :: {verbose, Verbose} | {debug, Debug},
Verbose :: boolean(),
Debug :: disable | debug | trace,
OpenOption ::
{ipfamily, IpFamily} |
{port, Port :: port()} |
{mode, Mode} |
{tls, TLSOptions :: [ssl:tls_option()]} |
{tls_sec_method, TLSSecMethod :: ftps | ftpes} |
{tls_ctrl_session_reuse,
TLSSessionReuse :: boolean()} |
{timeout, Timeout :: timeout()} |
{dtimeout, DTimeout :: timeout()} |
{progress, Progress} |
{sock_ctrl, SocketCtrls} |
{sock_data_act, [SocketControl]} |
{sock_data_pass, [SocketControl]},
SocketCtrls :: [SocketControl],
IpFamily :: inet | inet6 | inet6fb4,
Mode :: active | passive,
Module :: atom(),
Function :: atom(),
InitialData :: term(),
Progress :: ignore | {Module, Function, InitialData},
SocketControl :: gen_tcp:option().
okay so this is the whole big open situation and it's a LOT of type stuff, so let's break it down gently because the type spec is doing the absolute most π
Hostis either astring()or aninet:ip_address()πOptsis a list ofOpt, where eachOptis either aStartOptionor anOpenOption.StartOptionis one of:{verbose, Verbose}whereVerbose :: boolean(){debug, Debug}whereDebug :: disable | debug | trace
OpenOptionis one of:{ipfamily, IpFamily}{port, Port :: port()}{mode, Mode}{tls, TLSOptions :: [ssl:tls_option()]}{tls_sec_method, TLSSecMethod :: ftps | ftpes}{tls_ctrl_session_reuse, TLSSessionReuse :: boolean()}{timeout, Timeout :: timeout()}{dtimeout, DTimeout :: timeout()}{progress, Progress}{sock_ctrl, SocketCtrls}{sock_data_act, [SocketControl]}{sock_data_pass, [SocketControl]}
- and the helper types are:
SocketCtrls :: [SocketControl]IpFamily :: inet | inet6 | inet6fb4Mode :: active | passiveModule :: atom()Function :: atom()InitialData :: term()Progress :: ignore | {Module, Function, InitialData}SocketControl :: gen_tcp:option()
that's the whole thing, nothing skipped, everything in its place, periodt π
to be continued bestieβ¦ part 2 is on the way π
β οΈ Deprecated: ftp:open/2 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
okay so this one spins up a whole FTP client process π« and opens a session with the FTP server sitting at Host. That's the vibe. That's the function.
A session opened this way is closed using function close/1. Close the door behind you bestie, always. πͺ
The available configuration options are as follows (all of them, no crumbs left behind):
{host, Host}β whereHost = string() | ip_address(). The address of the server you're vibing with. π{port, Port}β Default is0which aliases to21or990when used with{tls_sec_method,ftps}).{mode, Mode}β Default ispassive.{verbose, Verbose}β Determines if the FTP communication is to be verbose or not. Default isfalse.{debug, Debug}β Debugging using thedbgtoolkit. Default isdisable.{ipfamily, IpFamily}β Withinet6fb4the client behaves as before, that is, tries to use IPv6, and only if that does not work it uses IPv4). Default isinet(IPv4).{timeout, Timeout}β Connection time-out. Default is60000(milliseconds). β³{dtimeout, DTimeout}β Data connect time-out. The time the client waits for the server to connect to the data socket. Default isinfinity.{tls, TLSOptions}β The FTP session is transported over tls (ftps, see RFC 4217). The listTLSOptionscan be empty. The functionssl:connect/3is used for securing both the control connection and the data sessions. π{tls_sec_method, TLSSecMethod}β When set toftpswill connect immediately with SSL instead of upgrading with STARTTLS. This suboption is ignored unless the suboptiontlsis also set. Default isftpes. π{tls_ctrl_session_reuse, boolean()}β When set totruethe client will re-use the TLS session from the control channel on the data channel as enforced by many FTP servers as (proposed and implemented first by vsftpd). Default isfalse.{sock_ctrl, SocketCtrls :: [SocketControl :: gen_tcp:option()]}β Passes options fromSocketCtrlsdown to the underlying transport layer (tcp).gen_tcp:option/0except foripv6_v6only,active,packet,mode,packet_sizeandheader. Default value isSocketCtrls = [].{sock_data_act, [SocketControl]}β Passes options from[SocketControl]down to the underlying transport layer (tcp).sock_data_actuses the value ofsock_ctrlas default value.{sock_data_pass, [SocketControl]}β Passes options from[SocketControl]down to the underlying transport layer (tcp).sock_data_passuses the value ofsock_ctrlas default value.{progress, Progress}βProgress = ignore | {Module, Function, InitialData},Module = atom(),Function = atom(),InitialData = term(). Default isignore. π
Option progress is intended to be used by applications that want to create some type of progress report, such as a progress bar in a GUI. Default for the progress option is ignore, that is, the option is not used. When the progress option is specified, the following happens when ftp:send/[3,4] or ftp:recv/[3,4] are called:
- Before a file is transferred, the following call is made to indicate the start of the file transfer and how large the file is. The return value of the callback function is to be a new value for the
UserProgressTermthat will be used as input the next time the callback function is called.
Module:Function(InitialData, File, {file_size, FileSize})
- Every time a chunk of bytes is transferred the following call is made:
Module:Function(UserProgressTerm, File, {transfer_size, TransferSize})
- At the end of the file the following call is made to indicate the end of the transfer:
Module:Function(UserProgressTerm, File, {transfer_size, 0})
The callback function is to be defined as follows:
Module:Function(UserProgressTerm, File, Size) ->
UserProgressTerm
UserProgressTerm = term()
File = string()
Size = {transfer_size, integer()} | {file_size, integer()} |
{file_size, unknown}
For remote files, ftp cannot determine the file size in a platform independent way. In this case the size becomes unknown and it is left to the application to determine the size. π
NOTE: The callback is made by a middleman process, hence the file transfer is not affected by the code in the progress callback function. If the callback crashes, this is detected by the FTP connection process, which then prints an info-report and goes on as if theprogressoption was set toignore.
The file transfer type is set to the default of the FTP server when the session is opened. This is usually ASCII mode.
The current local working directory (compare lpwd/1) is set to the value reported by file:get_cwd/1, the wanted local directory.
The return value Pid is used as a reference to the newly created FTP client in all other functions, and they are to be called by the process that created the connection. The FTP client process monitors the process that created it and terminates if that process terminates. π
πΈ pwd/1
pwd(Client :: client()) ->
{ok, Dir :: string()} | {error, Reason :: term()}.
β οΈ Deprecated: ftp:pwd/1 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Returns the current working directory at the remote server. π Where even am I, bestie?
π quote/2
quote(Client :: client(), Cmd :: string()) ->
[FTPLine :: string()].
β οΈ Deprecated: ftp:quote/2 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
NOTE: The telnet end of line characters, from the FTP protocol definition, CRLF, for example, "\\r\\n" has been removed.
Sends an arbitrary FTP command and returns verbatim a list of the lines sent back by the FTP server. This function is intended to give application accesses to FTP commands that are server-specific or that cannot be provided by this FTP client. So it's like "here, say the thing yourself" energy. π€
NOTE: FTP commands requiring a data connection cannot be successfully issued with this function.
π recv/3
recv(Pid :: pid(),
RemoteFileName :: file:filename(),
LocalFileName :: file:filename()) ->
ok | {error, Reason :: term()}.
β οΈ Deprecated: ftp:recv/3 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Transfers the file RemoteFileName from the remote server to the file system of the local client. If LocalFileName is specified, the local file will be LocalFileName, otherwise RemoteFileName.
If the file write fails, the command is aborted and {error, term()} is returned. However, the file is not removed. π yeah, it just... stays there. Left on read.
π¦ recv_bin/2
recv_bin(Pid :: pid(), RemoteFile :: string()) ->
{ok, Bin :: binary()} | {error, Reason :: term()}.
β οΈ Deprecated: ftp:recv_bin/2 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Transfers the file RemoteFile from the remote server and receives it as a binary. Raw bytes straight into your hands. β¨
π recv_chunk/1
recv_chunk(Client :: client()) ->
ok |
{ok, Bin :: binary()} |
{error, Reason :: term()}.
β οΈ Deprecated: ftp:recv_chunk/1 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Receives a chunk of the remote file (RemoteFile of recv_chunk_start). The return values have the following meaning:
ok= the transfer is complete. π{ok, Bin}= just another chunk of the file.{error, Reason}= transfer failed. π
π recv_chunk_start/2
recv_chunk_start(Pid :: pid(), RemoteFile :: string()) ->
ok | {error, Reason :: term()}.
β οΈ Deprecated: ftp:recv_chunk_start/2 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Starts transfer of the file RemoteFile from the remote server. And then the chunks start rolling in. πΌ
π§ rename/3
rename(Client :: client(), Old :: string(), New :: string()) ->
ok | {error, Reason :: term()}.
β οΈ Deprecated: ftp:rename/3 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Renames Old to New at the remote server. Glow-up for your files, honestly. π
β rmdir/2
rmdir(Client :: client(), Dir :: string()) ->
ok | {error, Reason :: term()}.
β οΈ Deprecated: ftp:rmdir/2 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Removes directory Dir at the remote server. Bye bestie, blocked. ποΈ
π«Ά send/3
send(Pid :: pid(),
LocalFileName :: file:filename(),
RemoteFileName :: file:filename()) ->
ok | {error, Reason :: term()}.
β οΈ Deprecated: ftp:send/3 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Transfers the file LocalFileName to the remote server. If RemoteFileName is specified, the name of the remote file is set to RemoteFileName, otherwise to LocalFileName.
π send_bin/3
send_bin(Client :: client(),
Bin :: binary(),
RemoteFile :: string()) ->
ok | {error, Reason :: term()}.
π Deprecated: ftp:send_bin/3 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
okay so bestie, this one is simple in the best way: you hand it the binary Bin and it transfers that binary straight into the file RemoteFile living on the remote server. that's the whole vibe. π
send_chunk/2 πΈ
send_chunk(Client :: client(), Bin :: binary()) ->
ok | {error, Reason :: term()}.
π Deprecated: ftp:send_chunk/2 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
She transfers the chunk Bin over to the remote server, and the server writes it into whatever file you named when you called send_chunk_start/2. π«Ά
lowkey important: for some errors β file system full being the classic one β you've gotta call send_chunk_end to actually get the proper reason. no skipping that step, bestie, the error won't spill the tea otherwise. π
send_chunk_end/1 π
send_chunk_end(Client :: client()) ->
ok | {error, Reason :: term()}.
π Deprecated: ftp:send_chunk_end/1 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
This stops the chunk transfer to the remote server. And the file on the remote server that you specified back in your send_chunk_start/2 call? the server closes it. done. iconic. β¨
send_chunk_start/2 π¦
send_chunk_start(Client :: client(), RemoteFile :: string()) ->
ok | {error, Reason :: term()}.
π Deprecated: ftp:send_chunk_start/2 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
She starts the transfer of chunks into the file RemoteFile over at the remote server. that's it, that's the beginning of the chunk saga. π
type/2 π
type(Client :: client(), Type :: ascii | binary) ->
ok | {error, Reason :: term()}.
π Deprecated: ftp:type/2 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Sets the file transfer type to ascii or binary, your pick. ngl though, when an FTP session first opens, you just get whatever the server's default transfer type is β most often ascii, because that's the default according to RFC 959. so the server kinda chose for you already. π€·ββοΈ
user/3 π
user(Pid :: pid(), User :: string(), Pass :: string()) ->
ok | {error, Reason :: term()}.
π Deprecated: ftp:user/3 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Performs login of User with Pass. main character login energy, periodt. π
user/4 β
user(Pid :: pid(),
User :: string(),
Pass :: string(),
Account :: string()) ->
ok | {error, Reason :: term()}.
π Deprecated: ftp:user/4 is deprecated; Legacy protocol support will be dropped in OTP-30, use more modern approach for file transfer as for instance SFTP (SSH File Transfer Protocol).
Same login deal, but this time User logs in with Pass to the account you name in Account. extra credentials, extra slay. π
and that's the whole page, bestie, we made it to the end π₯Ή this one's stamped from Ericsson AB, page ftp 1.2.6 (that's the source + version + date line doing its lil footer thing), nestled in the ftp(3) manual. go forth and transfer files responsibly β or better yet, take the page's own advice and use something modern like SFTP. bye bestie, mwah π β¨
π¦ where this page comes from
- nixos 26.05: erlang 29.1.2
- nixpkgs unstable: erlang 29.1.2
- ubuntu stonking: erlang-doc 1:29.0.6+dfsg-1 Β· Apache-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms