Type: Package
Title: Robust SFTP Interface Using 'curl'
Version: 0.2.0
Description: Provides a high-level, object-oriented interface for Secure File Transfer Protocol (SFTP) operations built upon the 'curl' package. The package implements an 'R6' class to manage persistent connections and provides 'tidyverse'-style functions for common file system tasks. Key features include recursive directory creation with idempotency support, "smart" local path resolution that distinguishes between files and directories, and the ability to download remote resources directly into memory as raw vectors for seamless integration into data processing pipelines. It is designed to handle common SFTP edge cases gracefully, providing informative error messages and robust path sanitization to ensure compatibility across different server configurations.
License: MIT + file LICENSE
URL: https://mikuo0628.github.io/sftpR/, https://github.com/mikuo0628/sftpR
BugReports: https://github.com/mikuo0628/sftpR/issues
Encoding: UTF-8
SystemRequirements: libcurl: libcurl (with libssh2 support)
Depends: R (≥ 4.1.0)
Imports: curl (≥ 7.0.0), R6 (≥ 2.6.1)
RoxygenNote: 7.3.3
Suggests: knitr, rmarkdown, testthat (≥ 3.0.0), withr
Config/testthat/edition: 3
VignetteBuilder: knitr
Collate: 'sftp_connect.R' 'sftp_delete.R' 'sftp_download.R' 'sftp_list.R' 'sftp_mkdir.R' 'sftp_rename.R' 'sftp_upload.R' 'utils.R' 'shared_docs.R'
NeedsCompilation: no
Packaged: 2026-04-03 17:10:35 UTC; rstudio
Author: Michael Kuo [aut, cre]
Maintainer: Michael Kuo <michael.kuo@bccdc.ca>
Repository: CRAN
Date/Publication: 2026-04-09 15:40:02 UTC

Build SFTP URL components

Description

Helper (stateless) function to construct a full SFTP URL and its components from the given protocol, hostname, port, and path Hostname will be sanitized for minor formatting issues; if a port or path are found inside 'hostname' they will override the corresponding arguments.

Usage

.build_sftp_url(
  protocol = "sftp",
  user = NULL,
  hostname = NULL,
  port = "22",
  path = NULL,
  .verbose = TRUE
)

Arguments

protocol

Character. Protocol string. Defaults to "sftp".

user

Character. SFTP account name.

hostname

Character. Server URL or IP. Defaults to "localhost".

port

Character. Port number. Defaults to "22".

path

Character. Sub-path on server.

.verbose

Logical. Defaults to TRUE. Prints helpful messages.

Value

A list with components: full_url, protocol, hostname, port, path.


Parse and Validate SFTP URL Components

Description

Internal utility to deconstruct an SFTP URL into its constituent parts (protocol, user, hostname, port, and path). It enforces security by disallowing absolute paths (indicated by double slashes) and performs basic sanitization.

Usage

.parse_sftp_url(url, .verbose = TRUE)

Arguments

url

A character string containing the SFTP URL.

.verbose

Logical. Defaults to TRUE. Prints helpful messages.

Details

The function uses a single-pass regular expression to extract components. It specifically blocks "Root Access" attempts (e.g., 'sftp://host//etc') by checking if the captured path starts with a forward slash.

Value

A named list containing:

protocol

The scheme (e.g., "sftp").

user

The username if provided (e.g., "john").

hostname

The server address (IPv4, IPv6, or domain).

port

The port number as a string.

path

The file or directory path relative to the home directory.


Parse SFTP Directory Listings into Data Frames

Description

A utility function that converts the raw binary content of an SFTP directory listing (returned by curl) into a structured R data.frame.

Usage

.sftp_parse(resp = NULL, sftp_url = NULL, h = NULL)

Arguments

resp

A response list from curl::curl_fetch_memory. If NULL, the function will attempt to fetch data using sftp_url and h.

sftp_url

Character. The SFTP URL to fetch if resp is NULL. This function will assume URL is valid (ie. dir or file).

h

A curl handle. Required only if resp is NULL.

Details

The function automatically filters out the special Unix directory entries "." and "..". It determines object types based on the first character of the permission string (e.g., 'd' for directory).

Value

A data.frame with parsed Unix-style directory metadata, or NULL if the directory is empty.


Validate and Sanitize SFTP URLs against a Connection Object

Description

This internal utility ensures that a user-provided URL matches the "Source of Truth" defined in an SFTPConn object. It prevents common formatting errors, warns against security-risky root access attempts (double slashes), and corrects any incongruities in the protocol, hostname, or port.

Usage

.validate_sftp_url(sftp_conn, user_url, .verbose = sftp_conn$.verbose)

Arguments

sftp_conn

An SFTPConn object containing connection details and authentication. Created by sftp_connect.

user_url

Character string. The destination SFTP URL or path provided by the user.

.verbose

Logical. Defaults to TRUE. Prints helpful messages.

Details

The function performs the following steps:

Value

A sanitized character string containing the validated SFTP URL.


SFTP Connection Class

Description

An R6 class to safely store information needed for SFTP connection, with convenient methods to check connections and existence of files or directories, and create specific handles for sftp_* function family of CRUD operations.

Details

One important goal of this design choice is to keep user credentials safe, as private fields. Credentails are used to create specific handles for sftp_* family, and are reused where approrpiate. SFTPConn This class checks if credential is valid, and has a internal convenience methods such as safe printing for basic information, checking destination existence, and ensuring URL is correctly formatted.

Value

SFTPConn R6 class object, used in sftp_* family.

Public fields

protocol

The connection protocol.

hostname

The server address or IP.

path

The target subdirectory on the server.

port

The port number.

timeout

Connection timeout in seconds.

h

The internal curl handle used for connection checks, listing directories, and download files.

.verbose

Logical; if TRUE, prints detailed curl output.

last_error

Character string of the last connection error.

Active bindings

clean_url

Returns the processed SFTP URL via internal .build_sftp_url.

Methods

Public methods


Method new()

Initialize 'SFTPConn' class R6 object.

Usage
sftp_conn_generator$new(
  protocol = "sftp",
  hostname = "localhost",
  path = NULL,
  port = "22",
  user = NA_character_,
  password = NA_character_,
  timeout = 30L,
  ...,
  .verbose = TRUE
)
Arguments
protocol

Character. Protocol string. Defaults to "sftp".

hostname

Character. Server URL or IP. Defaults to "localhost".

path

Character. Sub-path on server.

port

Character. Port number. Defaults to "22".

user

Character. SFTP account name.

password

Character. SFTP password.

timeout

Integer. Connection timeout.

...

Additional arguments passed to curl::handle_setopt().

.verbose

Logical. Defaults to TRUE. Prints helpful messages.

Returns

An 'SFTPConn' object with safely stored user credential and convenience methods for various operations, such as checking connection and existence, and creating handles for CRUD operations.


Method connection_ok()

Checks if the current connection settings and credentials are valid.

Usage
sftp_conn_generator$connection_ok()
Returns

Logical; TRUE if connection is successful.


Method print()

Custom print method to display connection status without exposing passwords.

Usage
sftp_conn_generator$print(...)
Arguments
...

Unused.


Method .upload_handle()

Internal method to generate a specialized upload handle with streaming. Adapted from curl::curl_upload().

Usage
sftp_conn_generator$.upload_handle(
  local_file,
  reuse = TRUE,
  .verbose = self$.verbose,
  ...
)
Arguments
local_file

Path to file, data.frame, or connection.

reuse

Logical; try to keep connection alive.

.verbose

Logical. Defaults to TRUE. Prints helpful messages.

...

Additional options for curl::handle_setopt().


Method .quote_handle()

Createshandle that uses 'quote' option. Specifically for deleting, creating directories, and renaming files or directories.

Usage
sftp_conn_generator$.quote_handle(
  remote_url_from = NULL,
  remote_url_to = NULL,
  purpose = c("rm", "mkdir", "rename"),
  .verbose = self$.verbose,
  .ignore_error = FALSE,
  ...
)
Arguments
remote_url_from

Character. The URL to delete, to create, or to rename from.

remote_url_to

Character. The URL to rename to. Ignored for delete or directory create operations.

purpose

Character. Choose one of 3 options:

  • "rm": to delete file or directory.

  • "mkdir": to create directory. Path should be a directory.

  • "rename": to rename

.verbose

Logical. Defaults to TRUE. Prints helpful messages.

.ignore_error

Logical. Defaults to 'FALSE'. If TRUE, error will not interrupt subsequent execution. See 'Details'.

...

Options that for curl::handle_setopt().

Details

In 'curl', adding an asterisk ('*') at the very beginning of a command (ie. one of the 3 used in 'purpose' argument) acts as a "fail-safe" or "ignore-error" prefix. It silently ignores any failure returned by the command, and continues without being interrupted by the error. Check if a remote path exists


Method .exists()

An internal helper that pings the SFTP/FTP server to verify the existence of a file or directory.

Usage
sftp_conn_generator$.exists(sftp_url = NULL)
Arguments
sftp_url

Character. The full URL to the remote resource. If NULL, returns FALSE.

Details

This method uses CURLOPT_NOBODY = TRUE to perform a protocol-level STAT request. This is highly efficient as it retrieves only metadata and does not attempt to download or list contents.

Because STAT is slash-agnostic in the SFTP protocol, this check will return TRUE for a directory regardless of whether a trailing forward-slash is provided in the URL.

However, this is the only operation where URL is "safe" from the consequences of un-normalized URLs. Be wary of incorrect multiple slash placements as they will be collapsed into one slash and won't throw errors.

Returns

Logical. TRUE if the resource exists and is accessible; FALSE otherwise. URL "fixing" via range probing


Method .fix_url_type()

An internal diagnostic method that determines if a remote URL requires a trailing slash by attempting to read a single byte (Range: 0-0).

Usage
sftp_conn_generator$.fix_url_type(remote_url)
Arguments
remote_url

Character. The full SFTP/FTP URL to validate.

Details

This method leverages a protocol behavior:

If the initial probe fails, the method "flips" the trailing slash (adds one if missing, or removes one if present) and returns the modified URL. This addresses the common 'libcurl' issue where directory listings fail without an explicit trailing slash.

Returns

A character string containing the "fixed" URL. Note that if the path truly does not exist, the flipped URL is still returned; the final operation (upload/list) will handle the ultimate failure.


Method clone()

The objects of this class are cloneable with this method.

Usage
sftp_conn_generator$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.

Note

This method uses a 5-second connecttimeout to ensure the probe doesn't hang on unresponsive servers.


Create an SFTPConn R6 object that contains important connection information safely

Description

An R6 class to safely store information needed for SFTP connection, with convenient methods to check connections and existence of files or directories, and create specific handles for sftp_* function family of CRUD operations.

Usage

sftp_connect(
  protocol = "sftp",
  hostname = "localhost",
  path = NULL,
  port = "22",
  user = NA_character_,
  password = NA_character_,
  timeout = 30L,
  ...,
  .verbose = TRUE
)

Arguments

protocol

Character. Protocol string. Defaults to "sftp".

hostname

Character. Server URL or IP. Defaults to "localhost".

path

Character. Sub-path on server.

port

Character. Port number. Defaults to "22".

user

Character. SFTP account name.

password

Character. SFTP password.

timeout

Integer. Connection timeout.

...

Additional arguments passed to curl::handle_setopt().

.verbose

Logical. Defaults to TRUE. Prints helpful messages.

Details

One important goal of this design choice is to keep user credentials safe, as private fields. Credentails are used to create specific handles for sftp_* family, and are reused where approrpiate. SFTPConn This class checks if credential is valid, and has a internal convenience methods such as safe printing for basic information, checking destination existence, and ensuring URL is correctly formatted.

Value

SFTPConn R6 class object, used in sftp_* family.

Examples


if (interactive() || Sys.getenv("R_SFTP_TEST_SERVER") == "true") {
  # Create a new SFTP connection
  sftp_conn <- sftp_connect(
    hostname = "127.0.0.1",
    port     = 2222,
    user     = "tester",
    password = "password123"
  )
}



Delete Files or Directories from SFTP Server

Description

Deletes a specific file or directory from the remote server. If the target is a directory, it must be empty unless .recursive = TRUE is specified.

Usage

sftp_delete(
  sftp_conn,
  remote_url = NULL,
  .recursive = FALSE,
  .verbose = TRUE,
  .validate = TRUE
)

Arguments

sftp_conn

An SFTPConn object containing connection details and authentication. Created by sftp_connect.

remote_url

Character. The full URL or path of the file or directory to be operated on.

.recursive

Logical. Defaults to FALSE. If TRUE, will recursively perform the SFTP operation:

  • sftp_delete(): deletes the directory and everything within.

  • sftp_list(): lists all the directories and files.

  • sftp_mkdir(): creates all the missing parent directories.

  • sftp_rename(): see sftp_mkdir().

.verbose

Logical. Defaults to TRUE. Prints helpful messages.

.validate

Logical. Whether to validate the remote_url against the connection object. Defaults to TRUE, which will parse remote_url, comapre to that of SFTPConn, and replaces parts incongruent with SFTPConn. Internally set to FALSE when .recursive = TRUE because the URLs produced by the listing operation aren't subjected to human errors, thus do not need further validation. This provides a minor performance boost.

Value

TRUE (invisibly) if the operation was successful.

Safety Warnings

Examples


if (interactive() || Sys.getenv("R_SFTP_TEST_SERVER") == "true") {
  # Create new SFTP connection
  sftp_conn <- sftp_connect(
    hostname = "127.0.0.1",
    port     = "2222",
    user     = "tester",
    password = "password123"
  )

  # Delete a single file
  sftp_delete(sftp_conn, "project/old_report.csv")

  # Delete an entire directory and its contents
  sftp_delete(sftp_conn, "project/temp_outputs/", .recursive = TRUE)
}



Download Files from SFTP Server

Description

Downloads a file from a remote SFTP server to a local disk location or directly into R's memory as a raw vector.

Usage

sftp_download(
  sftp_conn,
  remote_file,
  local_file = NA_character_,
  .create_dir = FALSE,
  .overwrite = FALSE,
  .verbose = TRUE,
  ...
)

Arguments

sftp_conn

An SFTPConn object containing connection details and authentication. Created by sftp_connect.

remote_file

Character. The path or URL of the file on the SFTP server.

local_file

Character or NULL.

  • If NA (default) or an "": The file is saved to the current working directory while using remote_file filename.

  • If character: The local path where the file should be saved.

  • If NULL: The file is downloaded to memory and returned as a raw vector.

.create_dir

Logical. Defaults to FALSE. If TRUE, creates the necessary parent directories if needed.

.overwrite

Logical. Defaults to FALSE. If TRUE, will overwrite destination file.

.verbose

Logical. Defaults to TRUE. Prints helpful messages.

...

Additional arguments passed to curl::curl_download.

Value

If local_file is NULL, a raw vector of the file contents. Otherwise, the resolved local path to the saved file (invisibly).

Local Path Resolution Caveats

To provide a "smart" user experience, the function guesses if local_file is intended to be a directory or a specific filename:

Examples


if (interactive() || Sys.getenv("R_SFTP_TEST_SERVER") == "true") {
  # Create new SFTP connection
  sftp_conn <- sftp_connect(
    hostname = "127.0.0.1",
    port     = "2222",
    user     = "tester",
    password = "password123"
  )

  # Download and use the remote filename
  sftp_download(sftp_conn, "data/raw_logs.zip")

  # Download to a specific local name
  sftp_download(sftp_conn, "remote_file.csv", "local_name.csv")

  # Download to memory for immediate processing
  raw_bytes <- sftp_download(sftp_conn, "data.json", local_file = NULL)
  # Parse with appropriate packages
  # data <- jsonlite::fromJSON(rawToChar(raw_bytes))
}



List and Crawl SFTP Directory Contents

Description

Retrieves a directory listing from an SFTP server. If .recursive = TRUE, it will perform a depth-first crawl of all subdirectories found, implementing a path-tracking algorithm to detect and skip circular symbolic links, preventing infinite recursion and stack overflow errors.

Usage

sftp_list(
  sftp_conn = NULL,
  sftp_url = NULL,
  .verbose = TRUE,
  .recursive = FALSE
)

Arguments

sftp_conn

An SFTPConn object containing connection details and authentication. Created by sftp_connect.

sftp_url

A SFTP URL of which the contents will be listed. If NULL, the base URL in SFTPConn will be used: contents of the SFTP home folder will be listed.

.verbose

Logical. Defaults to TRUE. Prints helpful messages.

.recursive

Logical. Defaults to FALSE. If TRUE, will recursively perform the SFTP operation:

  • sftp_delete(): deletes the directory and everything within.

  • sftp_list(): lists all the directories and files.

  • sftp_mkdir(): creates all the missing parent directories.

  • sftp_rename(): see sftp_mkdir().

Value

A data.frame containing remote file/directory metadata:

Examples


if (interactive() || Sys.getenv("R_SFTP_TEST_SERVER") == "true") {
  # Create a new SFTP connection
  sftp_conn <- sftp_connect(
    hostname = "127.0.0.1",
    port     = "2222",
    user     = "tester",
    password = "password123"
  )

  # List recursively
  sftp_list(sftp_conn, .recursive = TRUE)
}


Create Remote Directories in SFTP

Description

This function creates directories on a remote server using the SFTP protocol. It supports recursive directory creation, effectively behaving like mkdir -p on a Unix-like system.

Usage

sftp_mkdir(
  sftp_conn,
  remote_url = NULL,
  .recursive = TRUE,
  .verbose = TRUE,
  .ignore_error = .recursive
)

Arguments

sftp_conn

An SFTPConn object containing connection details and authentication. Created by sftp_connect.

remote_url

Character. The full URL or path of the file or directory to be operated on.

.recursive

Logical. Defaults to FALSE. If TRUE, will recursively perform the SFTP operation:

  • sftp_delete(): deletes the directory and everything within.

  • sftp_list(): lists all the directories and files.

  • sftp_mkdir(): creates all the missing parent directories.

  • sftp_rename(): see sftp_mkdir().

.verbose

Logical. Defaults to TRUE. Prints helpful messages.

.ignore_error

Logical. If TRUE, the function uses the * prefix in the curl quote command to ignore errors (e.g., if the directory already exists). This is useful in .recursive = TRUE because attempting to create a directory that already exists will return error. While this can be avoided by checking for directory existence, doing so adds extra step that impacts performance.

Details

When .recursive = TRUE, the function splits the path into segments and attempts to create each one sequentially. It uses the * prefix for internal calls to ensure that existing directories do not trigger errors.

Value

invisible(TRUE) on success.

Examples

## Not run: 
if (interactive() || Sys.getenv("R_SFTP_TEST_SERVER") == "true") {
  # Create new SFTP connection
  sftp_conn <- sftp_connect(
    hostname = "127.0.0.1",
    port     = "2222",
    user     = "tester",
    password = "password123"
  )

  # Create a nested directory structure
  sftp_mkdir(sftp_conn, "project/data/results/2026", .recursive = TRUE)

  # Create a single directory and fail if parents are missing
  sftp_mkdir(sftp_conn, "simple_dir", .recursive = FALSE)
}

## End(Not run)


Rename or Move Remote SFTP Resources

Description

Renames a file or directory on the SFTP server. This can also be used to move files between directories.

Usage

sftp_rename(
  sftp_conn,
  remote_url_from = NULL,
  remote_url_to = NULL,
  .recursive = FALSE,
  .verbose = TRUE
)

Arguments

sftp_conn

An SFTPConn object containing connection details and authentication. Created by sftp_connect.

remote_url_from

Character. The current path of the file or directory.

remote_url_to

Character. The new path for the file or directory.

.recursive

Logical. Defaults to FALSE. If TRUE, will recursively perform the SFTP operation:

  • sftp_delete(): deletes the directory and everything within.

  • sftp_list(): lists all the directories and files.

  • sftp_mkdir(): creates all the missing parent directories.

  • sftp_rename(): see sftp_mkdir().

.verbose

Logical. Defaults to TRUE. Prints helpful messages.

Details

The SFTP protocol's rename command is typically non-overwriting. If remote_url_to already exists, the operation will fail.

When .recursive = TRUE, parent directories of remote_url_to are identified, and existence ensured before attempting the renaming.

Value

invisible(TRUE) on success.

Examples


if (interactive() || Sys.getenv("R_SFTP_TEST_SERVER") == "true") {
  # Create new SFTP connection
  sftp_conn <- sftp_connect(
    hostname = "127.0.0.1",
    port     = "2222",
    user     = "tester",
    password = "password123"
  )

  # Simple rename in the same folder
  sftp_rename(sftp_conn, "old_name.csv", "new_name.csv")

  # Move a file to a new, potentially non-existent directory
  sftp_rename(
    sftp_conn,
    "data/raw.csv",
    "archive/2026/processed.csv",
    .recursive = TRUE
  )
}



Upload a file to an SFTP server

Description

A robust wrapper to upload local files or data frames to a remote SFTP server. It manages the libcurl handle lifecycle, ensures connections are closed, and validates URLs against the connection's "Source of Truth".

Usage

sftp_upload(
  sftp_conn,
  local_file,
  remote_file = NULL,
  .create_dir = FALSE,
  .verbose = TRUE
)

Arguments

sftp_conn

An SFTPConn object containing connection details and authentication. Created by sftp_connect.

local_file

Character string (path to a file) or a data.frame. Data frames are automatically written to a temp file before upload. The temp file will automatically be cleaned up at the end of function.

remote_file

Character string. The destination path on the server. If NULL, attempts to use the basename of the local_file.

.create_dir

Logical. Defaults to FALSE. If TRUE, creates the necessary parent directories if needed.

.verbose

Logical. Defaults to TRUE. Prints helpful messages.

Details

The function uses a secure lifecycle:

  1. Validates the remote URL to prevent credential leakage.

  2. Opens a file connection to the local source.

  3. Uses on.exit to ensure file handles are released and temporary files are unlinked even if the transfer is interrupted.

Value

Returns TRUE (invisibly) on success. Throws an error on failure.

Examples


if (interactive() || Sys.getenv("R_SFTP_TEST_SERVER") == "true") {
  # Create new SFTP connection
  sftp_conn <- sftp_connect(
    hostname = "127.0.0.1",
    port     = "2222",
    user     = "tester",
    password = "password123"
  )

  # Upload `my_df` as csv
  sftp_upload(conn, my_df, "uploads/data.csv")
}


Shared Parameter Documentation

Description

Shared Parameter Documentation

Arguments

protocol

Character. Protocol string. Defaults to "sftp".

hostname

Character. Server URL or IP. Defaults to "localhost".

path

Character. Sub-path on server.

port

Character. Port number. Defaults to "22".

user

Character. SFTP account name.

password

Character. SFTP password.

timeout

Integer. Connection timeout.

...

Additional arguments passed to curl::handle_setopt().

.verbose

Logical. Defaults to TRUE. Prints helpful messages.

sftp_conn

An SFTPConn object containing connection details and authentication. Created by sftp_connect.

remote_url

Character. The full URL or path of the file or directory to be operated on.

.recursive

Logical. Defaults to FALSE. If TRUE, will recursively perform the SFTP operation:

  • sftp_delete(): deletes the directory and everything within.

  • sftp_list(): lists all the directories and files.

  • sftp_mkdir(): creates all the missing parent directories.

  • sftp_rename(): see sftp_mkdir().

.create_dir

Logical. Defaults to FALSE. If TRUE, creates the necessary parent directories if needed.