CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ssh2

SSH2 client and server modules written in pure JavaScript for node.js

Pending
Overview
Eval results
Files

sftp-operations.mddocs/

SFTP Operations

Comprehensive SFTP (SSH File Transfer Protocol) implementation supporting both client and server operations with full OpenSSH extension support for advanced file system operations.

Capabilities

SFTP Class

Complete SFTP client and server implementation with extensive file system operations.

/**
 * SFTP client/server implementation
 * Extends EventEmitter for operation events
 */
class SFTP extends EventEmitter {
  maxOpenHandles: number;
}

File Operations

Core file manipulation operations for reading, writing, and managing files.

/**
 * Open a file for reading/writing
 * @param path - Remote file path
 * @param flags - Open flags (string like 'r', 'w', 'a' or numeric)
 * @param attrs - Optional file attributes to set
 * @param callback - Callback receiving file handle
 * @returns false if SFTP not ready, true otherwise
 */
open(path: string, flags: string | number, attrs?: Attributes, callback?: OpenCallback): boolean;
open(path: string, flags: string | number, callback: OpenCallback): boolean;

/**
 * Close a file handle
 * @param handle - File handle buffer to close
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
close(handle: Buffer, callback?: StatusCallback): boolean;

/**
 * Read data from file handle
 * @param handle - File handle to read from
 * @param buffer - Buffer to read data into
 * @param offset - Offset in buffer to start writing
 * @param length - Number of bytes to read
 * @param position - Position in file to read from
 * @param callback - Callback with read result
 * @returns false if SFTP not ready, true otherwise
 */
read(
  handle: Buffer, 
  buffer: Buffer, 
  offset: number, 
  length: number, 
  position: number, 
  callback?: ReadCallback
): boolean;

/**
 * Write data to file handle
 * @param handle - File handle to write to
 * @param buffer - Buffer containing data to write
 * @param offset - Offset in buffer to start reading
 * @param length - Number of bytes to write
 * @param position - Position in file to write to
 * @param callback - Callback with write result
 * @returns false if SFTP not ready, true otherwise
 */
write(
  handle: Buffer, 
  buffer: Buffer, 
  offset: number, 
  length: number, 
  position: number, 
  callback?: WriteCallback
): boolean;

type OpenCallback = (err: Error | null, handle?: Buffer) => void;
type StatusCallback = (err: Error | null) => void;
type ReadCallback = (err: Error | null, bytesRead?: number, buffer?: Buffer, position?: number) => void;
type WriteCallback = (err: Error | null, bytesWritten?: number) => void;

Usage Examples:

// Open and read a file
sftp.open('/remote/path/file.txt', 'r', (err, handle) => {
  if (err) throw err;
  
  const buffer = Buffer.alloc(1024);
  sftp.read(handle, buffer, 0, 1024, 0, (err, bytesRead, buffer, position) => {
    if (err) throw err;
    console.log('Read', bytesRead, 'bytes:', buffer.slice(0, bytesRead).toString());
    
    sftp.close(handle, (err) => {
      if (err) throw err;
      console.log('File closed');
    });
  });
});

// Open and write to a file
sftp.open('/remote/path/output.txt', 'w', (err, handle) => {
  if (err) throw err;
  
  const data = Buffer.from('Hello, SFTP world!');
  sftp.write(handle, data, 0, data.length, 0, (err, bytesWritten) => {
    if (err) throw err;
    console.log('Wrote', bytesWritten, 'bytes');
    sftp.close(handle);
  });
});

High-Level File Operations

Convenient methods for complete file operations without manual handle management.

/**
 * Fast download of remote file to local filesystem
 * @param remotePath - Remote file path
 * @param localPath - Local file path
 * @param options - Transfer options
 * @param callback - Callback with transfer result
 * @returns false if SFTP not ready, true otherwise
 */
fastGet(remotePath: string, localPath: string, options?: TransferOptions, callback?: TransferCallback): boolean;
fastGet(remotePath: string, localPath: string, callback: TransferCallback): boolean;

/**
 * Fast upload of local file to remote filesystem
 * @param localPath - Local file path
 * @param remotePath - Remote file path  
 * @param options - Transfer options
 * @param callback - Callback with transfer result
 * @returns false if SFTP not ready, true otherwise
 */
fastPut(localPath: string, remotePath: string, options?: TransferOptions, callback?: TransferCallback): boolean;
fastPut(localPath: string, remotePath: string, callback: TransferCallback): boolean;

/**
 * Read entire file contents
 * @param path - Remote file path
 * @param options - Read options
 * @param callback - Callback receiving file data
 * @returns false if SFTP not ready, true otherwise
 */
readFile(path: string, options?: ReadFileOptions, callback?: ReadFileCallback): boolean;
readFile(path: string, callback: ReadFileCallback): boolean;

/**
 * Write data to file, creating or replacing it
 * @param path - Remote file path
 * @param data - Data to write
 * @param options - Write options
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
writeFile(path: string, data: Buffer | string, options?: WriteFileOptions, callback?: StatusCallback): boolean;
writeFile(path: string, data: Buffer | string, callback: StatusCallback): boolean;

/**
 * Append data to existing file
 * @param path - Remote file path
 * @param data - Data to append
 * @param options - Append options
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
appendFile(path: string, data: Buffer | string, options?: WriteFileOptions, callback?: StatusCallback): boolean;
appendFile(path: string, data: Buffer | string, callback: StatusCallback): boolean;

interface TransferOptions {
  concurrency?: number;
  chunkSize?: number;
  step?: (totalTransferred: number, chunk: number, total: number) => void;
  mode?: number;
}

interface ReadFileOptions {
  encoding?: string;
  flag?: string;
}

interface WriteFileOptions {
  encoding?: string;
  mode?: number;
  flag?: string;
}

type TransferCallback = (err: Error | null) => void;
type ReadFileCallback = (err: Error | null, data?: Buffer | string) => void;

Directory Operations

Directory listing, creation, and management operations.

/**
 * Open directory for reading
 * @param path - Directory path to open
 * @param callback - Callback receiving directory handle
 * @returns false if SFTP not ready, true otherwise
 */
opendir(path: string, callback?: OpenCallback): boolean;

/**
 * Read directory contents
 * @param path - Directory path to read
 * @param options - Read options
 * @param callback - Callback receiving directory listing
 * @returns false if SFTP not ready, true otherwise
 */
readdir(path: string, options?: ReaddirOptions, callback?: ReaddirCallback): boolean;
readdir(path: string, callback: ReaddirCallback): boolean;

/**
 * Create directory
 * @param path - Directory path to create
 * @param attrs - Optional directory attributes
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
mkdir(path: string, attrs?: Attributes, callback?: StatusCallback): boolean;
mkdir(path: string, callback: StatusCallback): boolean;

/**
 * Remove directory
 * @param path - Directory path to remove
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
rmdir(path: string, callback?: StatusCallback): boolean;

interface ReaddirOptions {
  encoding?: string;
}

type ReaddirCallback = (err: Error | null, list?: FileEntry[]) => void;

interface FileEntry {
  filename: string;
  longname: string;
  attrs: Stats;
}

File System Operations

File and directory metadata operations and path manipulation.

/**
 * Get file/directory attributes
 * @param path - File or directory path
 * @param callback - Callback receiving file attributes
 * @returns false if SFTP not ready, true otherwise
 */
stat(path: string, callback?: AttrsCallback): boolean;

/**
 * Get symlink attributes (don't follow link)
 * @param path - Symlink path
 * @param callback - Callback receiving link attributes
 * @returns false if SFTP not ready, true otherwise
 */
lstat(path: string, callback?: AttrsCallback): boolean;

/**
 * Get file handle attributes
 * @param handle - File handle
 * @param callback - Callback receiving file attributes
 * @returns false if SFTP not ready, true otherwise
 */
fstat(handle: Buffer, callback?: AttrsCallback): boolean;

/**
 * Set file/directory attributes
 * @param path - File or directory path
 * @param attrs - Attributes to set
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
setstat(path: string, attrs: Attributes, callback?: StatusCallback): boolean;

/**
 * Set file handle attributes
 * @param handle - File handle
 * @param attrs - Attributes to set
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
fsetstat(handle: Buffer, attrs: Attributes, callback?: StatusCallback): boolean;

/**
 * Test if file exists
 * @param path - File path to test
 * @param callback - Callback with existence result
 * @returns false if SFTP not ready, true otherwise
 */
exists(path: string, callback?: ExistsCallback): boolean;

/**
 * Delete file
 * @param path - File path to delete
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
unlink(path: string, callback?: StatusCallback): boolean;

/**
 * Rename/move file or directory
 * @param oldPath - Current file path
 * @param newPath - New file path
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
rename(oldPath: string, newPath: string, callback?: StatusCallback): boolean;

type AttrsCallback = (err: Error | null, attrs?: Stats) => void;
type ExistsCallback = (exists: boolean) => void;

Link Operations

Symbolic and hard link management operations.

/**
 * Read symbolic link target
 * @param path - Symbolic link path
 * @param callback - Callback receiving link target
 * @returns false if SFTP not ready, true otherwise
 */
readlink(path: string, callback?: ReadlinkCallback): boolean;

/**
 * Create symbolic link
 * @param targetPath - Target path for the link
 * @param linkPath - Path where link will be created
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
symlink(targetPath: string, linkPath: string, callback?: StatusCallback): boolean;

/**
 * Resolve absolute path (follow all symlinks)
 * @param path - Path to resolve
 * @param callback - Callback receiving resolved path
 * @returns false if SFTP not ready, true otherwise
 */
realpath(path: string, callback?: ReadlinkCallback): boolean;

type ReadlinkCallback = (err: Error | null, target?: string) => void;

Convenience Methods

Additional utility methods for common file operations.

/**
 * Set file handle access and modification times
 * @param handle - File handle
 * @param atime - Access time
 * @param mtime - Modification time
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
futimes(handle: Buffer, atime: number | Date, mtime: number | Date, callback?: StatusCallback): boolean;

/**
 * Set file access and modification times
 * @param path - File path
 * @param atime - Access time
 * @param mtime - Modification time
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
utimes(path: string, atime: number | Date, mtime: number | Date, callback?: StatusCallback): boolean;

/**
 * Change file handle ownership
 * @param handle - File handle
 * @param uid - New user ID
 * @param gid - New group ID
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
fchown(handle: Buffer, uid: number, gid: number, callback?: StatusCallback): boolean;

/**
 * Change file ownership
 * @param path - File path
 * @param uid - New user ID  
 * @param gid - New group ID
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
chown(path: string, uid: number, gid: number, callback?: StatusCallback): boolean;

/**
 * Change file handle permissions
 * @param handle - File handle
 * @param mode - New permission mode
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
fchmod(handle: Buffer, mode: number, callback?: StatusCallback): boolean;

/**
 * Change file permissions
 * @param path - File path
 * @param mode - New permission mode
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
chmod(path: string, mode: number, callback?: StatusCallback): boolean;

Stream Operations

Stream-based file operations for efficient data handling.

/**
 * Create readable stream for file
 * @param path - Remote file path
 * @param options - Stream options
 * @returns Readable stream
 */
createReadStream(path: string, options?: ReadStreamOptions): ReadableStream;

/**
 * Create writable stream for file
 * @param path - Remote file path
 * @param options - Stream options
 * @returns Writable stream
 */
createWriteStream(path: string, options?: WriteStreamOptions): WritableStream;

interface ReadStreamOptions {
  flags?: string;
  encoding?: string;
  handle?: Buffer;
  mode?: number;
  autoClose?: boolean;
  start?: number;
  end?: number;
}

interface WriteStreamOptions {
  flags?: string;
  encoding?: string;
  mode?: number;
  autoClose?: boolean;
  start?: number;
}

Stream Usage Examples:

// Stream file download
const readStream = sftp.createReadStream('/remote/largefile.dat');
const writeStream = fs.createWriteStream('/local/largefile.dat');

readStream.pipe(writeStream);

writeStream.on('close', () => {
  console.log('File downloaded via stream');
});

// Stream file upload  
const readStream = fs.createReadStream('/local/upload.dat');
const writeStream = sftp.createWriteStream('/remote/upload.dat');

readStream.pipe(writeStream);

writeStream.on('close', () => {
  console.log('File uploaded via stream');
});

OpenSSH Extensions

Advanced operations specific to OpenSSH SFTP servers.

/**
 * Atomic rename operation (OpenSSH extension)
 * @param oldPath - Current file path
 * @param newPath - New file path
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
ext_openssh_rename(oldPath: string, newPath: string, callback?: StatusCallback): boolean;

/**
 * Get file system statistics (OpenSSH extension)
 * @param path - Path on filesystem
 * @param callback - Callback receiving filesystem stats
 * @returns false if SFTP not ready, true otherwise
 */
ext_openssh_statvfs(path: string, callback?: StatvfsCallback): boolean;

/**
 * Get file system statistics for handle (OpenSSH extension)
 * @param handle - File handle
 * @param callback - Callback receiving filesystem stats
 * @returns false if SFTP not ready, true otherwise
 */
ext_openssh_fstatvfs(handle: Buffer, callback?: StatvfsCallback): boolean;

/**
 * Create hard link (OpenSSH extension)
 * @param oldPath - Existing file path
 * @param newPath - New hard link path
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
ext_openssh_hardlink(oldPath: string, newPath: string, callback?: StatusCallback): boolean;

/**
 * Synchronize file to disk (OpenSSH extension)
 * @param handle - File handle to sync
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
ext_openssh_fsync(handle: Buffer, callback?: StatusCallback): boolean;

/**
 * Set symlink attributes without following link (OpenSSH extension)
 * @param path - Symlink path
 * @param attrs - Attributes to set
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
ext_openssh_lsetstat(path: string, attrs: Attributes, callback?: StatusCallback): boolean;

/**
 * Expand path with wildcards (OpenSSH extension)
 * @param path - Path with potential wildcards
 * @param callback - Callback receiving expanded paths
 * @returns false if SFTP not ready, true otherwise
 */
ext_openssh_expandPath(path: string, callback?: ExpandPathCallback): boolean;

/**
 * Server-side file copy (OpenSSH extension)
 * @param srcHandle - Source file handle
 * @param srcOffset - Source file offset
 * @param len - Number of bytes to copy
 * @param dstHandle - Destination file handle
 * @param dstOffset - Destination file offset
 * @param callback - Callback with operation result
 * @returns false if SFTP not ready, true otherwise
 */
ext_copy_data(
  srcHandle: Buffer, 
  srcOffset: number, 
  len: number, 
  dstHandle: Buffer, 
  dstOffset: number, 
  callback?: StatusCallback
): boolean;

/**
 * Get user home directory (OpenSSH extension)
 * @param username - Username to get home directory for
 * @param callback - Callback receiving home directory path
 * @returns false if SFTP not ready, true otherwise
 */
ext_home_dir(username: string, callback?: ReadlinkCallback): boolean;

/**
 * Resolve user and group names (OpenSSH extension)
 * @param uids - Array of user IDs to resolve
 * @param gids - Array of group IDs to resolve
 * @param callback - Callback receiving resolved names
 * @returns false if SFTP not ready, true otherwise
 */
ext_users_groups(uids: number[], gids: number[], callback?: UsersGroupsCallback): boolean;

interface StatvfsInfo {
  bsize: number;    // File system block size
  frsize: number;   // Fragment size
  blocks: number;   // Size of fs in f_frsize units
  bfree: number;    // Number of free blocks
  bavail: number;   // Number of free blocks for unprivileged users
  files: number;    // Number of inodes
  ffree: number;    // Number of free inodes
  favail: number;   // Number of free inodes for unprivileged users
  fsid: number;     // File system ID
  flag: number;     // Mount flags
  namemax: number;  // Maximum filename length
}

interface UserGroupInfo {
  users: { [uid: number]: string };
  groups: { [gid: number]: string };
}

type StatvfsCallback = (err: Error | null, info?: StatvfsInfo) => void;
type ExpandPathCallback = (err: Error | null, paths?: string[]) => void;
type UsersGroupsCallback = (err: Error | null, info?: UserGroupInfo) => void;

Server-Only Methods

Methods available only when SFTP is operating in server mode.

/**
 * Send file handle response (server mode)
 * @param reqid - Request ID
 * @param handle - File handle to send
 * @returns false if not in server mode, true otherwise
 */
handle(reqid: number, handle: Buffer): boolean;

/**
 * Send status response (server mode)
 * @param reqid - Request ID
 * @param code - Status code
 * @param message - Optional status message
 * @returns false if not in server mode, true otherwise
 */
status(reqid: number, code: number, message?: string): boolean;

/**
 * Send data response (server mode)
 * @param reqid - Request ID
 * @param data - Data to send
 * @param encoding - Optional data encoding
 * @returns false if not in server mode, true otherwise
 */
data(reqid: number, data: Buffer | string, encoding?: string): boolean;

/**
 * Send name response (server mode)
 * @param reqid - Request ID
 * @param names - Array of file entries
 * @returns false if not in server mode, true otherwise
 */
name(reqid: number, names: FileEntry[]): boolean;

/**
 * Send attributes response (server mode)
 * @param reqid - Request ID
 * @param attrs - File attributes
 * @returns false if not in server mode, true otherwise
 */
attrs(reqid: number, attrs: Attributes): boolean;

Type Definitions

File Attributes and Stats

interface Attributes {
  mode?: number;      // File permissions
  uid?: number;       // User ID
  gid?: number;       // Group ID  
  size?: number;      // File size in bytes
  atime?: number | Date;  // Access time
  mtime?: number | Date;  // Modification time
}

interface Stats extends Attributes {
  isFile(): boolean;
  isDirectory(): boolean;
  isBlockDevice(): boolean;
  isCharacterDevice(): boolean;
  isSymbolicLink(): boolean;
  isFIFO(): boolean;
  isSocket(): boolean;
}

Constants

Status Codes

const STATUS_CODE = {
  OK: 0,              // No error
  EOF: 1,             // End of file
  NO_SUCH_FILE: 2,    // File or directory not found
  PERMISSION_DENIED: 3, // Permission denied
  FAILURE: 4,         // Generic failure
  BAD_MESSAGE: 5,     // Bad protocol message
  NO_CONNECTION: 6,   // No connection
  CONNECTION_LOST: 7, // Connection lost
  OP_UNSUPPORTED: 8   // Operation not supported
};

Open Mode Flags

const OPEN_MODE = {
  READ: 0x00000001,   // Read access
  WRITE: 0x00000002,  // Write access
  APPEND: 0x00000004, // Append access
  CREAT: 0x00000008,  // Create if doesn't exist
  TRUNC: 0x00000010,  // Truncate to zero length
  EXCL: 0x00000020    // Fail if file exists (with CREAT)
};

Access via:

const { utils } = require('ssh2');
console.log(utils.sftp.STATUS_CODE.OK);        // 0
console.log(utils.sftp.OPEN_MODE.READ);        // 1
console.log(utils.sftp.flagsToString(0x3));    // "READ,WRITE"
console.log(utils.sftp.stringToFlags('rw'));   // 3

Install with Tessl CLI

npx tessl i tessl/npm-ssh2

docs

http-tunneling.md

index.md

key-management.md

port-forwarding.md

sftp-operations.md

ssh-agents.md

ssh-client.md

ssh-server.md

tile.json