Standard library · Network

ftp

An FTP and FTPS client: listing a directory, uploading and downloading files.

import ftp
On this page
  1. Types
  2. Functions

This package connects to FTP servers, for uploading a site to shared hosting or pulling files off old equipment. Plain FTP sends the password and the data unencrypted; wherever the server supports it, use DialTLS, which encrypts both the commands and the data with AUTH TLS.

Transfers go in passive mode (PASV or EPSV), which works from behind a firewall. The parsing functions, such as ParseListLine, are available for writing tools of your own too.

Types

FileInfo

struct FileInfo
The information about one file from the server listing.
NameTypeDescription
namestr = ""The name.
sizei64 = 0The size.
is_dirbool = falseIt is a directory.
is_linkbool = falseIt is a link.
modestr = ""The permissions, such as rw-r--r--.
raw_datestr = ""The date exactly as the server wrote it.
ftp-Parse.salam
import ftp

func main:
    println ftp.ReplyCode("230 Login successful."), ftp.ReplyCode("broken")
    println ftp.IsFinalLine("211-Features:"), ftp.IsFinalLine("211 End")
    println ftp.ParsePasv("227 Entering Passive Mode (192,168,1,10,19,137)")
    println ftp.ParseEpsv("229 Entering Extended Passive Mode (|||50000|)")
    file := ftp.ParseListLine("-rw-r--r--    1 ftp      ftp          1024 Sep 30 12:00 notes.txt")
    println file.name, file.size, file.is_dir, file.is_link, file.mode, file.raw_date
    folder := ftp.ParseListLine("drwxr-xr-x    2 ftp      ftp          4096 Jan 01  2026 backup")
    println folder.name, folder.is_dir
    link := ftp.ParseListLine("lrwxrwxrwx    1 ftp      ftp             7 Mar 03 09:15 current -> backup")
    println link.name, link.is_link
end
Output230 0 false true 192.168.1.10:5001 50000 notes.txt 1024 false false rw-r--r-- Sep 30 12:00 backup true current true

Client

struct Client
One FTP connection.
NameTypeDescription
conntcp.ConnThe TCP connection of the commands.
okbool = falseThe connection is healthy.
hoststr = ""The host.
portint = 21The port.
rxbufstr = ""The data that was read.
last_replystr = ""The last reply of the server.
last_codeint = 0The code of the last reply.
securebool = falseThe command channel is encrypted.
tls_idxint = -1The index of the TLS connection.
prot_pbool = falseThe data channel is encrypted too.
tls_cfgtls.ConfigThe TLS configuration.
ftp-Client.salam
import ftp
import tls

func main:
    mut c := ftp.DialTLS("ftp.example.com", 21)
    if not ftp.Ok(c) or not ftp.Login(c, "ali", "s3cret"):
        println ftp.LastCode(c), ftp.LastReply(c)
        ret
    end
    println ftp.Secure(c), ftp.SecureData(c)
    println ftp.System(c)
    println ftp.Features(c)
    _ := ftp.Binary(c)
    println ftp.Pwd(c)
    _ := ftp.MkdirAll(c, "/site/assets")
    _ := ftp.Cwd(c, "/site")
    _ := ftp.Write(c, "index.html", "<h1>hello</h1>")
    _ := ftp.Append(c, "log.txt", "one more line\n")
    println ftp.Read(c, "index.html")
    println ftp.Upload(c, "logo.png", "assets/logo.png")
    println ftp.Download(c, "log.txt", "log-copy.txt")
    each entry in ftp.List(c, "."):
        println entry.name, entry.size, entry.is_dir
    end
    each name in ftp.NameList(c, "assets"):
        println name
    end
    println ftp.ListRaw(c, ".").len() > 0
    println ftp.Size(c, "index.html"), ftp.ModTime(c, "index.html")
    println ftp.IsDir(c, "assets"), ftp.IsLink(c, "current"), ftp.Exists(c, "old.html")
    _ := ftp.Rename(c, "log.txt", "log-1.txt")
    _ := ftp.Move(c, "log-1.txt", "archive/log-1.txt")
    _ := ftp.Delete(c, "archive/log-1.txt")
    _ := ftp.CdUp(c)
    _ := ftp.Mkdir(c, "tmp")
    _ := ftp.Rmdir(c, "tmp")
    _ := ftp.RemoveAll(c, "/site/old")
    _ := ftp.UploadDir(c, "public", "/site")
    _ := ftp.DownloadDir(c, "/site", "backup")
    println ftp.Command(c, "SITE CHMOD 644 index.html")
    println ftp.Noop(c)
    _ := ftp.Ascii(c)
    ftp.Quit(c)
    ftp.Close(c)

    mut plain := ftp.Dial("ftp.example.com", 21)
    println ftp.AuthTLS(plain)
    mut cfg := tls.NewConfig("ftp.example.com")
    cfg.ca_file = "company-ca.pem"
    mut configured := ftp.DialTLSWith("ftp.example.com", 21, cfg)
    mut upgraded := ftp.Dial("ftp.example.com", 21)
    println ftp.AuthTLSWith(upgraded, cfg)
    ftp.Close(plain)
    ftp.Close(configured)
    ftp.Close(upgraded)
end

Functions

Dial

func Dial(host: str, port: int): Client
Connects to an FTP server; not logged in yet.

The example for this item is shown with the ones above: ftp-Client.salam

AuthTLSWith

func AuthTLSWith(c &: Client, cfg: tls.Config): bool
Secures the connection with AUTH TLS and the given configuration.

The example for this item is shown with the ones above: ftp-Client.salam

AuthTLS

func AuthTLS(c &: Client): bool
Secures the connection with AUTH TLS.

The example for this item is shown with the ones above: ftp-Client.salam

DialTLS

func DialTLS(host: str, port: int): Client
Connects and secures it at once with AUTH TLS; explicit FTPS.

The example for this item is shown with the ones above: ftp-Client.salam

DialTLSWith

func DialTLSWith(host: str, port: int, cfg: tls.Config): Client
The same, with a TLS configuration.

The example for this item is shown with the ones above: ftp-Client.salam

Secure

func Secure(c: Client): bool
The command channel is encrypted.

The example for this item is shown with the ones above: ftp-Client.salam

SecureData

func SecureData(c: Client): bool
The data channel is encrypted too.

The example for this item is shown with the ones above: ftp-Client.salam

Login

func Login(c &: Client, user: str, password: str): bool
Logs in.

The example for this item is shown with the ones above: ftp-Client.salam

Quit

func Quit(c &: Client)
Logs out with QUIT.

The example for this item is shown with the ones above: ftp-Client.salam

Close

func Close(c &: Client)
Closes the connection.

The example for this item is shown with the ones above: ftp-Client.salam

Ok

func Ok(c: Client): bool
The connection is healthy.

The example for this item is shown with the ones above: ftp-Client.salam

LastReply

func LastReply(c: Client): str
The text of the last reply.

The example for this item is shown with the ones above: ftp-Client.salam

LastCode

func LastCode(c: Client): int
The code of the last reply, such as 230.

The example for this item is shown with the ones above: ftp-Client.salam

Command

func Command(c &: Client, line: str): int
Sends a raw command and returns the reply code.

The example for this item is shown with the ones above: ftp-Client.salam

Noop

func Noop(c &: Client): bool
The NOOP command, for keeping the connection alive.

The example for this item is shown with the ones above: ftp-Client.salam

System

func System(c &: Client): str
The system type of the server.

The example for this item is shown with the ones above: ftp-Client.salam

Features

func Features(c &: Client): str
The features the server announces with FEAT.

The example for this item is shown with the ones above: ftp-Client.salam

Binary

func Binary(c &: Client): bool
Binary transfer mode; for everything but plain text.

The example for this item is shown with the ones above: ftp-Client.salam

Ascii

func Ascii(c &: Client): bool
Text transfer mode.

The example for this item is shown with the ones above: ftp-Client.salam

Pwd

func Pwd(c &: Client): str
The current directory.

The example for this item is shown with the ones above: ftp-Client.salam

Cwd

func Cwd(c &: Client, path: str): bool
Changes directory.

The example for this item is shown with the ones above: ftp-Client.salam

CdUp

func CdUp(c &: Client): bool
Goes to the directory above.

The example for this item is shown with the ones above: ftp-Client.salam

Mkdir

func Mkdir(c &: Client, path: str): bool
Makes a directory.

The example for this item is shown with the ones above: ftp-Client.salam

Rmdir

func Rmdir(c &: Client, path: str): bool
Deletes an empty directory.

The example for this item is shown with the ones above: ftp-Client.salam

MkdirAll

func MkdirAll(c &: Client, path: str): bool
Makes the directory and the ones above it.

The example for this item is shown with the ones above: ftp-Client.salam

ListRaw

func ListRaw(c &: Client, path: str): str
The directory listing exactly as the server sends it.

The example for this item is shown with the ones above: ftp-Client.salam

List

func List(c &: Client, path: str): Vector<FileInfo>
The directory listing, parsed.

The example for this item is shown with the ones above: ftp-Parse.salam

NameList

func NameList(c &: Client, path: str): Vector<str>
The names in the directory only.

The example for this item is shown with the ones above: ftp-Client.salam

Size

func Size(c &: Client, path: str): i64
The size of a file; -1 when it could not be had.

The example for this item is shown with the ones above: ftp-Client.salam

ModTime

func ModTime(c &: Client, path: str): str
The modification time in YYYYMMDDHHMMSS form.

The example for this item is shown with the ones above: ftp-Client.salam

IsDir

func IsDir(c &: Client, path: str): bool
It is a directory.

The example for this item is shown with the ones above: ftp-Client.salam

func IsLink(c &: Client, path: str): bool
It is a link.

The example for this item is shown with the ones above: ftp-Client.salam

Exists

func Exists(c &: Client, path: str): bool
The file or directory is there.

The example for this item is shown with the ones above: ftp-Client.salam

Read

func Read(c &: Client, remote: str): str
Reads a file.

The example for this item is shown with the ones above: ftp-Client.salam

Write

func Write(c &: Client, remote: str, data: str): bool
Writes text to a file on the server.

The example for this item is shown with the ones above: ftp-Client.salam

Append

func Append(c &: Client, remote: str, data: str): bool
Adds text to the end of a file.

The example for this item is shown with the ones above: ftp-Client.salam

Download

func Download(c &: Client, remote: str, local: str): bool
Downloads a file into a local file.

The example for this item is shown with the ones above: ftp-Client.salam

Upload

func Upload(c &: Client, local: str, remote: str): bool
Sends a local file.

The example for this item is shown with the ones above: ftp-Client.salam

Delete

func Delete(c &: Client, path: str): bool
Deletes a file.

The example for this item is shown with the ones above: ftp-Client.salam

Rename

func Rename(c &: Client, from_path: str, to_path: str): bool
Renames it.

The example for this item is shown with the ones above: ftp-Client.salam

Move

func Move(c &: Client, from_path: str, to_path: str): bool
Moves it; the target directory is made when it is not there.

The example for this item is shown with the ones above: ftp-Client.salam

RemoveAll

func RemoveAll(c &: Client, path: str): bool
Deletes the directory and everything in it.

The example for this item is shown with the ones above: ftp-Client.salam

DownloadDir

func DownloadDir(c &: Client, remote: str, local: str): bool
Downloads a directory with everything in it.

The example for this item is shown with the ones above: ftp-Client.salam

UploadDir

func UploadDir(c &: Client, local: str, remote: str): bool
Sends a local directory with everything in it.

The example for this item is shown with the ones above: ftp-Client.salam

ReplyCode

func ReplyCode(line: str): int
The three digit code of a reply line; zero when there is none.

The example for this item is shown with the ones above: ftp-Parse.salam

IsFinalLine

func IsFinalLine(line: str): bool
It is the closing line of a multi line reply; the closing line has a space after the code, not a dash.

The example for this item is shown with the ones above: ftp-Parse.salam

ParsePasv

func ParsePasv(reply: str): str
Pulls the data address and port out of a PASV reply.

The example for this item is shown with the ones above: ftp-Parse.salam

ParseEpsv

func ParseEpsv(reply: str): int
Pulls the data port out of an EPSV reply.

The example for this item is shown with the ones above: ftp-Parse.salam

ParseListLine

func ParseListLine(line: str): FileInfo
Parses one Unix style listing line.

The example for this item is shown with the ones above: ftp-Parse.salam