The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Net::SFTP::Foreign - Secure File Transfer Protocol client

SYNOPSIS

    use Net::SFTP::Foreign;
    my $sftp = Net::SFTP::Foreign->new($host);
    $sftp->get("foo", "bar");
    $sftp->put("bar", "baz");

DESCRIPTION

SFTP stands for Secure File Transfer Protocol and is a method of transferring files between machines over a secure, encrypted connection (as opposed to regular FTP, which functions over an insecure connection). The security in SFTP comes through its integration with SSH, which provides an encrypted transport layer over which the SFTP commands are executed.

Net::SFTP::Foreign is a Perl client for the SFTP. It provides a subset of the commands listed in the SSH File Transfer Protocol IETF draft, which can be found at http://www.openssh.org/txt/draft-ietf-secsh-filexfer-02.txt (also included on this package distribution, on the rfc directory).

Net::SFTP::Foreign uses any compatible ssh command installed on your system (for instance, OpenSSH ssh) to establish the secure connection to the remote server.

Formerly, Net::SFTP::Foreign was a hacked version of Net::SFTP, but from version 0.90 it has been rewritten almost completely from scratch and a new much improved API introduced (an adaptor module, Net::SFTP::Foreign::Compat, is also provided for backward compatibility).

Net::SFTP::Foreign Vs. Net::SFTP

Why should I prefer Net::SFTP::Foreign over Net::SFTP?

Well, both modules have their pros and cons:

Net::SFTP::Foreign does not requiere a bunch of additional modules and external libraries to work, just the OpenBSD SSH client (or any other client compatible enough).

I trust OpenSSH SSH client more than Net::SSH::Perl, there are lots of paranoid people ensuring that OpenSSH doesn't have security holes!!!

If you have an SSH infrastructure already deployed, by using the same binary SSH client, Net::SFTP::Foreign ensures a seamless integration within your environment (configuration files, keys, etc.).

Net::SFTP::Foreign is much faster transferring files, specially over networks with high (relative) latency.

Net::SFTP::Foreign provides several high level methods not available from Net::SFTP as for instance find, rget, rput.

On the other hand, using the external command means an additional proccess being launched and running, depending on your OS this could eat more resources than the in process pure perl implementation provided by Net::SSH::Perl.

Net::SFTP::Foreign supports version 2 of the SSH protocol only.

Finally Net::SFTP::Foreign does not (and will never) allow to use passwords for authentication while Net::SFTP does... though, see the FAQ below.

USAGE

Most of the methods available from this package return undef on failure and a true value or the requested data on success. $sftp->error can be used to explicitly check for errors after every method call.

Net::SFTP::Foreign->new($host, %args)
Net::SFTP::Foreign->new(%args)

Opens a new SFTP connection with a remote host $host, and returns a Net::SFTP::Foreign object representing that open connection.

%args can contain:

host => $hostname

remote host name

user => $username

username to log in to the remote server. This should be your SSH login, and can be empty, in which case the username is drawn from the user executing the process.

port => $portnumber

port number where the remote SSH server is listening

more => [@more_ssh_args]

additional args passed to ssh command.

For debugging purposes you can run ssh in verbose mode passing it the -v option:

  my $sftp = Net::SFTP::Foreign->new($host, more => '-v');
ssh_cmd => $sshcmd

name of the external SSH client. By default ssh is used.

open2_cmd => [@cmd]
open2_cmd => $cmd;

allows to completely redefine how ssh is called. Its arguments are passed to IPC::Open2::open2 to open a pipe to the remote server.

autoflush => $bool

by default, and for performance reasons, write operations are cached, and only when the write buffer becomes big enough is the data written to the remote file. Setting this flag makes the write operations inmediate.

timeout => $seconds

when this parameter is set, the connection is dropped if no data arrives on the ssh socket for the given time while waiting for some command to complete.

When the timeout expires, the current method is aborted and the SFTP connection becomes invalid.

transport => $fh
transport => [$in_fh, $out_fh]
transport => [$in_fh, $out_fh, $pid]

This option allows to use an already open pipe or socket as the transport for the SFTP protocol.

It can be (ab)used to make this module work with password authentication or with keys requiring a passphrase.

On some systems, when using a pipe as the transport, closing it, does not cause the process at the other side to exit. The additional $pid argument can be used to instruct this module to kill that process if it doesn't exit by itself.

An explicit check for errors should be included always after the constructor call:

  my $sftp = Net::SFTP::Foreign->new(...);
  $sftp->error and die "SSH connection failed: " . $sftp->error;
$sftp->error

Returns the error code from the last executed command. The value returned is similar to $!, when used as a string it yields the corresponding error string.

See Net::SFTP::Foreign::Constants for a list of possible error codes and how to import them on your scripts.

$sftp->status

Returns the code from the last SSH2_FXP_STATUS response. It is also a dualvar that yields the status string when used as a string.

Usually $sftp->error should be checked first to see if there was any error and then $sftp->status to find out its low level cause.

$sftp->get($remote, $local, %options)

Copies remote file $remote to local $local. By default file attributes are also copied (permissions, atime and mtime).

The method accepts several options (not all combinations are possible):

copy_time => $bool

determines if access and modification time attributes have to be copied from remote file. Default is to copy them.

copy_perms => $bool

determines if permision attributes have to be copied from remote file. Default is to copy them after applying the local process umask.

umask => $umask

allows to select the umask to apply when setting the permissions of the copied file. Default is to use the umask for the current process.

perm => $perm

sets the permision mask of the file to be $perm, umask and remote permissions are ignored.

block_size => $bytes

size of the blocks the file is being splittered on for transfer. Incrementing this value can improve performance but some servers limit its size.

callback => $callback

$callback is a reference to a subroutine that will be called after every iteration of the download process.

The callback function will receive as arguments: the current Net::SFTP::Foreign object; the data read from the remote file; the offset from the beginning of the file in bytes; and the total size of the file in bytes.

This mechanism can be used to provide status messages, download progress meters, etc.:

    sub callback {
        my($sftp, $data, $offset, $size) = @_;
        print "Read $offset / $size bytes\r";
    }

The abort method can be called from inside the callback to abort the transfer:

    sub callback {
        my($sftp, $data, $offset, $size) = @_;
        if (want_to_abort_transfer()) {
            $sftp->abort("You wanted to abort the transfer");
        }
    }
$sftp->get_content($remote)

Returns the content of the remote file.

$sftp->put($local, $remote, %opts)

Uploads a file $local from the local host to the remote host, and saves it as $remote. By default file attributes are also copied.

This method accepts several options:

copy_time => $bool

determines if access and modification time attributes have to be copied from remote file. Default is to copy them.

copy_perms => $bool

determines if permision attributes have to be copied from remote file. Default is to copy them after applying the local process umask.

umask => $umask

allows to select the umask to apply when setting the permissions of the copied file. Default is to use the umask for the current process.

perm => $perm

sets the permision mask of the file to be $perm, umask and local permissions are ignored.

block_size => $bytes

size of the blocks the file is being splittered on for transfer. Incrementing this value can improve performance but some servers limit its size and if this limit is overpassed the command will fail.

callback => $callback

$callback is a reference to a subrutine that will be called after every iteration of the upload process.

The callback function will receive as arguments: the current Net::SFTP::Foreign object; the data that is going to be written to the remote file; the offset from the beginning of the file in bytes; and the total size of the file in bytes.

This mechanism can be used to provide status messages, download progress meters, etc.

The abort method can be called from inside the callback to abort the transfer.

$sftp->abort()
$sftp->abort($msg)

This method, when called from inside a callback sub, causes the current transfer to be aborted

The error state is set to SFTP_ERR_ABORTED and the optional $msg argument is used as its textual value.

$sftp->ls($remote, %opts)

Fetches a directory listing of the remote directory $remote.

Returns a reference to a list of entries. Every entry is a reference to a hash with three keys: filename, the name of the entry; longname, an entry in a "long" listing like ls -l; and a, a Net::SFTP::Foreign::Attributes object containing file atime, mtime, permissions and size.

    my $ls = $sftp->ls('/home/foo')
        or die "unable to retrieve directory: ".$sftp->error;

    print "$_->{filename}\n" for (@$ls);

The options accepted by this method are:

wanted => qr/.../

Only elements which filename match the regular expresion are included on the listing.

wanted => sub {...}

Only elements for which the callback returns a true value are included on the listing. The callback is called with two arguments: the $sftp object and the current entry (a hash reference as described before). For instance:

  use Fcntl ':mode';

  my $files = $sftp->ls ( '/home/hommer',
                          wanted => sub {
                              my $entry = $_[1];
                              S_ISREG($entry->{a}->perm)
                          } )
        or die "ls failed: ".$sftp->error;
no_wanted => qr/.../
no_wanted => sub {...}

those options have the oposite result to their wanted counterparts:

  my $no_hidden = $sftp->ls( '/home/homer',
                             no_wanted => qr/^\./ )
        or die "ls failed";

When both no_wanted and wanted rules are used, the no_wanted rule is applied first and then the wanted one (order is important if the callbacks have side effects).

ordered => 1

the list of entries is ordered by filename.

by default, the attributes on the listing correspond to a lstat operation, setting this option causes the method to perform stat requests instead. lstat attributes will stil appear for links pointing to non existant places.

atomic_readdir => 1

Reading a directory is not an atomic SFTP operation and the protocol draft does not define what happens if readdir requests and write operations (for instance remove or open) affecting the same directory are intermixed.

This flag ensures that no callback call (wanted, no_wanted) is performed in the middle of reading a directory and has to be set if any of the callbacks can modify the file system.

$sftp->find($path, %opts)
$sftp->find(\@paths, %opts)

Does a recursive seach over the given directory $path (or directories @path) and returns a list of the entries found or the total number of them on scalar context.

Every entry is a reference to a hash with two keys: filename, the full path of the entry; and a, a Net::SFTP::Foreign::Attributes object containing file atime, mtime, permissions and size.

This method tries to recover and continue under error conditions.

The options accepted:

on_error => sub { ... }

the callback is called when some error is detected, two arguments are passed: the $sftp object and the entry that was being processed when the error happened. For instance:

  my @find = $sftp->find( '/',
                          on_error => sub {
                              my ($sftp, $e) = @_;
                              print STDERR "error processing $e->{filename}: "
                                   . $sftp->error;
                          } );
realpath => 1

calls method realpath for every entry, the result is stored under the key realpath. This option slows down the process as a new remote query is performed for every entry, specially on networks with high latency.

By default symbolic links are not resolved and appear as that on the final listing. This option causes then to be resolved and substituted by the target file system object. Dangling links are ignored, though they generate a call to the on_error callback when stat'ing them fails.

Following sym links can introduce loops on the search. Infinite loops are detected and broken but files can still appear repeated on the final listing under different names unless the option realpath is also actived.

ordered => 1

By default, the file system is searched in an implementation dependant order (actually optimized for low memory comsumption). If this option is included, the file system is searched in a deep-first, sorted by filename fashion.

wanted => qr/.../
wanted => sub { ... }
no_wanted => qr/.../
no_wanted => sub { ... }

These options have the same effect as on the ls method, allowing to filter out unwanted entries (note that filename keys contain full paths here).

The callbacks can also be used to perform some action instead of creating the full listing of entries in memory (that could use huge amounts of RAM for big file trees):

  $sftp->find($src_dir,
              wanted => sub {
                  my $fn = $_[1]->{filename}
                  print "$fn\n" if $fn =~ /\.p[ml]$/;
                  return undef # so it is discarded
              });
descend => qr/.../
descend => sub { ... }
no_descend => qr/.../
no_descend => sub { ... }

These options, similar to the wanted ones, allow to prune the search, discarding full subdirectories. For instance:

    use Fcntl ':mode';
    my @files = $sftp->find( '.',
                             no_descend => qr/\.svn$/,
                             wanted => sub {
                                 S_ISREG($_[1]->{a}->perm)
                             } );

descend and wanted rules are unrelated. A directory discarded by a wanted rule will still be recursively searched unless it is also discarded on a descend rule and vice-versa.

atomic_readdir => 1

see ls method documentation.

$sftp->glob($pattern, %opts)

performs a remote glob and returns the list of matching entries in the same format as find method.

This method tries to recover and continue under error conditions.

The options accepted:

ignore_case => 1

by default the matching over the file system is carried out in a case sensitive fashion, this flag changes it to be case insensitive.

strict_leading_dot => 0

by default, a dot character at the begining of a file or directory name is not matched by willcards (* or ?). Setting this flags to a false value changes the behaviour.

ordered => 1
on_error => sub { ... }
wanted => ...
no_wanted => ...

these options perform as on the ls method.

$sftp->rget($remote, $local, %opts)

Recursively copies the contents of remote directory $remote to local directory $local. Returns the total number of elements (files, dirs and symbolic links) successfully copied.

This method tries to recover and continue when some error happens.

The options accepted are:

umask => $umask

use umask $umask to set permissions on the files and directories created.

copy_perms => $bool;

if set to a true value, file and directory permissions are copied from the remote server (after applying the umask). By default is on.

copy_time => $bool;

if set to a true value, file atime and mtime are copied from the remote server. By default is on.

overwrite => $bool

if set to a true value, when a local file already exists it is overwritten. By default is on.

newer_only => $bool

if set to a true value, when a local file already exists it is overwritten only if the remote file is newer.

if set to a true value, symbolic links on the remote file system are skipped.

on_error => sub { ... }

the passed sub is called when some error happens. It is called with two arguments, the $sftp object and the entry causing the error.

wanted => ...
no_wanted => ...

This option allows to select which files and directories have to be copied. See also ls method docs.

If a directory is discarded all of its contents are also discarded (as it is not possible to copy child files without creating the directory first!).

block_size => $block_size
queue_size => $queue_size

see docs for get method.

$sftp->rput($local, $remote, %opts)

Recursively copies the contents of local directory $local to remote directory $remote. Not implemented yet.

$sftp->rremove($dir, %opts)
$sftp->rremove(\@dirs, %opts)

recursively remove directory $dir (or directories @dirs) and its contents. Returns the number of elements successfully removed.

This method tries to recover and continue when some error happens.

The options accepted are:

on_error => sub { ... }

This callback is called when some error is occurs. The arguments passed are the $sftp object and the current entry (see ls docs for more information).

wanted => ...
no_wanted => ...

Allow to select which file system objects have to be deleted.

$sftp->join(@paths)

returns the given path fragments joined in one path (currently the remote file system is expected to be Unix like).

$sftp->open($path, $flags [, $attrs ])

Sends the SSH_FXP_OPEN command to open a remote file $path, and returns an open handle on success. On failure returns undef.

The returned value is a tied handle that can be used to access the remote file both with the methods available from this module and with perl built-ins, for instance:

  # reading from the remote file
  my $fh1 = $sftp->open("/etc/passwd")
    or die $sftp->error;
  while (<$fh1>) { ... }

  # writting to the remote file
  my $fh2 = $sftp->open("/foo/bar", SSH2_FXF_WRITE|SSH2_FXF_CREAT)
    or die $sftp->error;
  print $fh2 "printing on the remote file\n";
  $sftp->write($fh2, "writting more");

$flags should be a bitmask of open flags, whose values can be obtained from Net::SFTP::Foreign::Constants:

    use Net::SFTP::Foreign::Constants qw( :flags );

$attrs should be a Net::SFTP::Foreign::Attributes object, specifying the initial attributes for the file $path. If you're opening the file for reading only, $attrs can be left blank, in which case it will be initialized to an empty set of attributes.

$sftp->close($handle)

Closes the remote file handle $handle.

Files are automatically closed on the handle DESTROY method when not done explicitelly.

Returns true on success and undef on failure.

$sftp->read($handle, $length)

reads $length bytes from an open file handle $handle. On success returns the data read from the remote file and undef on failure (including EOF).

$sftp->write($handle, $data)

writes $data to the remote file $handle. Returns the number of bytes written or undef on failure.

$sftp->readline($handle)
$sftp->readline($handle, $sep)

in scalar context reads and returns the next line from the remote file. In list context, it returns all the lines from the current position to the end of the file.

By default "\n" is used as the separator between lines, but a different one can be used passing it as the second method argument. If the empty string is used, it returns all the data from the current position to the end of the file as one line.

$sftp->getc($handle)

returns the next character from the file.

$sftp->seek($handle, $pos, $whence)

sets the current position for the remote file handle $handle. If $whence is 0, the position is set relative to the beginning of the file; if $whence is 1, position is relative to current position and if $<$whence> is 2, position is relative to the end of the file.

returns a trues value on success, undef on failure.

$sftp->tell($fh)

returns the current position for the remote file handle $handle.

$sftp->eof($fh)

reports whether the remote file handler points at the end of the file.

$sftp->flush($fh)

writes to the remote file any pending data and discards the read cache.

$sftp->sftpread($handle, $offset, $length)

low level method that sends a SSH2_FXP_READ request to read from an open file handle $handle, $length bytes starting at $offset.

Returns the data read on success and undef on failure.

Some servers (for instance OpenSSH SFTP server) limit the size of the read requests and so the length of data returned can be smaller than requested.

$sftp->sftpwrite($handle, $offset, $data)

low level method that sends a SSH_FXP_WRITE request to write to an open file handle $handle, starting at $offset, and where the data to be written is in $data.

Returns true on success and undef on failure.

$sftp->opendir($path)

Sends a SSH_FXP_OPENDIR command to open the remote directory $path, and returns an open handle on success (unfortunatelly, current versions of perl does not support directory operations via tied handles, so it is not possible to use the returned handle as a native one).

On failure returns undef.

$sftp->closedir($handle)

closes the remote directory handle $handle.

Directory handles are closed from their DESTROY method when not done explicitly.

Return true on success, undef on failure.

$sftp->readdir($handle)

returns the next entry from the remote directory $handle (or all the remaining entries when called in list context).

The return values are a hash with three keys: filename, longname and a. The a value contains a Net::SFTP::Foreign::Attributes object describing the entry.

Returns undef on error or when no more entries exist on the directory.

$sftp->stat($path)

performs a stat on the remote file $path and returns a Net::SFTP::Foreign::Attributes object with the result values.

Returns undef on failure.

$sftp->fstat($handle)

is similar to the previous method but its argument has to be a handle to an already open remote file instead of a file name.

$sftp->lstat($path)

is similar to stat method but stats a symbolic link instead of the file the symbolic links points to.

$sftp->setstat($path, $attrs)

sets file attributes on remote file $path.

Returns true on success and undef on failure.

$sftp->fsetstat($handle, $attrs)

is similar to setstat but its first argument has to be an open remote file handle instead of a file name.

$sftp->remove($path)

Sends a SSH_FXP_REMOVE command to remove the remote file $path. Returns a true value on success and undef on failure.

$sftp->mkdir($path)
$sftp->mkdir($path, $attrs)

Sends a SSH_FXP_MKDIR command to create a remote directory $path whose attributes are initialized to $attrs (a Net::SFTP::Foreign::Attributes object) if given.

Returns a true value on success and undef on failure.

$sftp->rmdir($path)

Sends a SSH_FXP_RMDIR command to remove a remote directory $path. Returns a true value on success and undef on failure.

$sftp->realpath($path)

Sends a SSH_FXP_REALPATH command to canonicalise $path to an absolute path. This can be useful for turning paths containing '..' into absolute paths.

Returns the absolute path on success, undef on failure.

$sftp->rename($old, $new)

Sends a SSH_FXP_RENAME command to rename $old to $new. Returns a true value on success and undef on failure.

$sftp->readlink($path)

Sends a SSH_FXP_READLINK command to read the path where the simbolic link is pointing.

Returns the target path on success and undef on failure.

$sftp->symlink($target, $path)

Sends a SSH_FXP_SYMLINK command to create a new symbolic link $path pointing to $target.

FAQ

Using Net::SFTP::Foreign from a cron script:

Q: I wrote a script for performing sftp file transfers that works beautifully from the command line. However when I try to run the same script from cron it fails with a broken pipe error:

  open2: exec of ssh -l user some.location.com -s sftp
    failed at Net/SFTP/Foreign.pm line 67

A: ssh is not on your cron PATH.

The remedy is either to add the location of the ssh application to your cron PATH or to use the ssh_cmd option on the new method to hardcode the location of ssh inside your script, for instance:

  my $ssh = Net::SFTP::Foreign->new($host,
                                    ssh_cmd => '/usr/local/ssh/bin/ssh');
Login/password authentication:

Q: I noticed that the examples/synopsis that is provided has no mention of using a password to login. How is one, able to login to a SFTP server that requires uid/pwd for login?

A: You can't! ...

Well, actually you can, using the transport option on the constructor and Expect to handle the password authentication part on your script:

  use Expect;

  my $conn = Expect->new;
  $conn->raw_pty(1);
  $conn->log_user(0);

  $conn->spawn('/usr/bin/ssh', -l => $user, $host, -s => 'sftp')
      or die $errstr;

  $conn->expect($timeout, "Password:")
      or die "Password not requested as expected";
  $conn->send("$passwd\n");
  $conn->expect($timeout, "\n");

  my $sftp = Net::SFTP::Foreign->new(transport => $conn);
  die "unable to stablish SSH connection: ". $sftp->error
      if $sftp->error;

The full example is available from the samples directory in this package.

Anyway, I highly discourage this practice. You better use public-key authentication instead!

Using passphrase protected keys:

Q: How can I use keys protected by a passphrase?

A: You can't ... well, ok, see answer to previous question.

Constructor more argument expects an array reference:

Q: I'm trying to pass in the private key file using the -i option, but it keep saying it couldn't find the key. What I'm doing wrong?

A: The more argument on the constructor expects a single option or a reference to an array of options. It will not split an string containing several options.

Arguments to SSH options have to be also passed as different entries on the array:

  my $sftp = Net::SFTP::Foreign->new($host,
                                      more => [qw(-i /home/foo/.ssh/id_dsa)]);

BUGS

On some operative systems, closing the pipes used to comunicate with the slave ssh process does not terminate it and a work around has to be applied. If you find that your scripts hung when the sftp object gets out of scope, try setting $Net::SFTP::Foreign::dirty_cleanup to a true value and also send me a report including the value of $^O on your machine and the OpenSSH version.

From version 0.90_18 upwards, a dirty cleanup is performed anyway when the ssh process does not terminate by itself in 8 seconds or less.

Support for Windows OSs is still experimental!

To report bugs, please, send me and email or use http://rt.cpan.org.

SEE ALSO

Information about the constants used on this module is available from Net::SFTP::Foreign::Constants. Information about attribute objects is available from Net::SFTP::Foreign::Attributes.

General information about SSH and the OpenSSH implementation is available from the OpenSSH web site at http://www.openssh.org/ and from the sftp(1) and sftp-server(8) manual pages.

Other modules offering similar functionality are Net::SFTP or Net::SSH2.

COPYRIGHT

Copyright (c) 2005-2007 Salvador Fandiño.

Copyright (c) 2001 Benjamin Trott, Copyright (c) 2003 David Rolsky.

_glob_to_regex method based on code (c) 2002 Richard Clamp.

All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

The full text of the license can be found in the LICENSE file included with this module.