Blame doc/sftp.dox

Packit Service 31306d
/**
Packit Service 31306d
@page libssh_tutor_sftp Chapter 5: The SFTP subsystem
Packit Service 31306d
@section sftp_subsystem The SFTP subsystem
Packit Service 31306d
Packit Service 31306d
SFTP stands for "Secure File Transfer Protocol". It enables you to safely
Packit Service 31306d
transfer files between the local and the remote computer. It reminds a lot
Packit Service 31306d
of the old FTP protocol.
Packit Service 31306d
Packit Service 31306d
SFTP is a rich protocol. It lets you do over the network almost everything
Packit Service 31306d
that you can do with local files:
Packit Service 31306d
  - send files
Packit Service 31306d
  - modify only a portion of a file
Packit Service 31306d
  - receive files
Packit Service 31306d
  - receive only a portion of a file
Packit Service 31306d
  - get file owner and group
Packit Service 31306d
  - get file permissions
Packit Service 31306d
  - set file owner and group
Packit Service 31306d
  - set file permissions
Packit Service 31306d
  - remove files
Packit Service 31306d
  - rename files
Packit Service 31306d
  - create a directory
Packit Service 31306d
  - remove a directory
Packit Service 31306d
  - retrieve the list of files in a directory
Packit Service 31306d
  - get the target of a symbolic link
Packit Service 31306d
  - create symbolic links
Packit Service 31306d
  - get information about mounted filesystems.
Packit Service 31306d
Packit Service 31306d
The current implemented version of the SFTP protocol is version 3. All functions
Packit Service 31306d
aren't implemented yet, but the most important are.
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
@subsection sftp_session Opening and closing a SFTP session
Packit Service 31306d
Packit Service 31306d
Unlike with remote shells and remote commands, when you use the SFTP subsystem,
Packit Service 31306d
you don't handle directly the SSH channels. Instead, you open a "SFTP session".
Packit Service 31306d
Packit Service 31306d
The function sftp_new() creates a new SFTP session. The function sftp_init()
Packit Service 31306d
initializes it. The function sftp_free() deletes it.
Packit Service 31306d
Packit Service 31306d
As you see, all the SFTP-related functions start with the "sftp_" prefix
Packit Service 31306d
instead of the usual "ssh_" prefix.
Packit Service 31306d
Packit Service 31306d
The example below shows how to use these functions:
Packit Service 31306d
Packit Service 31306d
@code
Packit Service 31306d
#include <libssh/sftp.h>
Packit Service 31306d
Packit Service 31306d
int sftp_helloworld(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
  sftp_session sftp;
Packit Service 31306d
  int rc;
Packit Service 31306d
Packit Service 31306d
  sftp = sftp_new(session);
Packit Service 31306d
  if (sftp == NULL)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Error allocating SFTP session: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  rc = sftp_init(sftp);
Packit Service 31306d
  if (rc != SSH_OK)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Error initializing SFTP session: code %d.\n",
Packit Service 31306d
            sftp_get_error(sftp));
Packit Service 31306d
    sftp_free(sftp);
Packit Service 31306d
    return rc;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  ...
Packit Service 31306d
Packit Service 31306d
  sftp_free(sftp);
Packit Service 31306d
  return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
@endcode
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
@subsection sftp_errors Analyzing SFTP errors
Packit Service 31306d
Packit Service 31306d
In case of a problem, the function sftp_get_error() returns a SFTP-specific
Packit Service 31306d
error number, in addition to the regular SSH error number returned by
Packit Service 31306d
ssh_get_error_number().
Packit Service 31306d
Packit Service 31306d
Possible errors are:
Packit Service 31306d
  - SSH_FX_OK: no error
Packit Service 31306d
  - SSH_FX_EOF: end-of-file encountered
Packit Service 31306d
  - SSH_FX_NO_SUCH_FILE: file does not exist
Packit Service 31306d
  - SSH_FX_PERMISSION_DENIED: permission denied
Packit Service 31306d
  - SSH_FX_FAILURE: generic failure
Packit Service 31306d
  - SSH_FX_BAD_MESSAGE: garbage received from server
Packit Service 31306d
  - SSH_FX_NO_CONNECTION: no connection has been set up
Packit Service 31306d
  - SSH_FX_CONNECTION_LOST: there was a connection, but we lost it
Packit Service 31306d
  - SSH_FX_OP_UNSUPPORTED: operation not supported by libssh yet
Packit Service 31306d
  - SSH_FX_INVALID_HANDLE: invalid file handle
Packit Service 31306d
  - SSH_FX_NO_SUCH_PATH: no such file or directory path exists
Packit Service 31306d
  - SSH_FX_FILE_ALREADY_EXISTS: an attempt to create an already existing file or directory has been made
Packit Service 31306d
  - SSH_FX_WRITE_PROTECT: write-protected filesystem
Packit Service 31306d
  - SSH_FX_NO_MEDIA: no media was in remote drive
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
@subsection sftp_mkdir Creating a directory
Packit Service 31306d
Packit Service 31306d
The function sftp_mkdir() takes the "SFTP session" we just created as
Packit Service 31306d
its first argument. It also needs the name of the file to create, and the
Packit Service 31306d
desired permissions. The permissions are the same as for the usual mkdir()
Packit Service 31306d
function. To get a comprehensive list of the available permissions, use the
Packit Service 31306d
"man 2 stat" command. The desired permissions are combined with the remote
Packit Service 31306d
user's mask to determine the effective permissions.
Packit Service 31306d
Packit Service 31306d
The code below creates a directory named "helloworld" in the current directory that
Packit Service 31306d
can be read and written only by its owner:
Packit Service 31306d
Packit Service 31306d
@code
Packit Service 31306d
#include <libssh/sftp.h>
Packit Service 31306d
#include <sys/stat.h>
Packit Service 31306d
Packit Service 31306d
int sftp_helloworld(ssh_session session, sftp_session sftp)
Packit Service 31306d
{
Packit Service 31306d
  int rc;
Packit Service 31306d
Packit Service 31306d
  rc = sftp_mkdir(sftp, "helloworld", S_IRWXU);
Packit Service 31306d
  if (rc != SSH_OK)
Packit Service 31306d
  {
Packit Service 31306d
    if (sftp_get_error(sftp) != SSH_FX_FILE_ALREADY_EXISTS)
Packit Service 31306d
    {
Packit Service 31306d
      fprintf(stderr, "Can't create directory: %s\n",
Packit Service 31306d
              ssh_get_error(session));
Packit Service 31306d
        return rc;
Packit Service 31306d
    }
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  ...
Packit Service 31306d
Packit Service 31306d
  return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
@endcode
Packit Service 31306d
Packit Service 31306d
Unlike its equivalent in the SCP subsystem, this function does NOT change the
Packit Service 31306d
current directory to the newly created subdirectory.
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
@subsection sftp_write Copying a file to the remote computer
Packit Service 31306d
Packit Service 31306d
You handle the contents of a remote file just like you would do with a
Packit Service 31306d
local file: you open the file in a given mode, move the file pointer in it,
Packit Service 31306d
read or write data, and close the file.
Packit Service 31306d
Packit Service 31306d
The sftp_open() function is very similar to the regular open() function,
Packit Service 31306d
excepted that it returns a file handle of type sftp_file. This file handle
Packit Service 31306d
is then used by the other file manipulation functions and remains valid
Packit Service 31306d
until you close the remote file with sftp_close().
Packit Service 31306d
Packit Service 31306d
The example below creates a new file named "helloworld.txt" in the
Packit Service 31306d
newly created "helloworld" directory. If the file already exists, it will
Packit Service 31306d
be truncated. It then writes the famous "Hello, World!" sentence to the
Packit Service 31306d
file, followed by a new line character. Finally, the file is closed:
Packit Service 31306d
Packit Service 31306d
@code
Packit Service 31306d
#include <libssh/sftp.h>
Packit Service 31306d
#include <sys/stat.h>
Packit Service 31306d
#include <fcntl.h>
Packit Service 31306d
Packit Service 31306d
int sftp_helloworld(ssh_session session, sftp_session sftp)
Packit Service 31306d
{
Packit Service 31306d
  int access_type = O_WRONLY | O_CREAT | O_TRUNC;
Packit Service 31306d
  sftp_file file;
Packit Service 31306d
  const char *helloworld = "Hello, World!\n";
Packit Service 31306d
  int length = strlen(helloworld);
Packit Service 31306d
  int rc, nwritten;
Packit Service 31306d
Packit Service 31306d
  ...
Packit Service 31306d
Packit Service 31306d
  file = sftp_open(sftp, "helloworld/helloworld.txt",
Packit Service 31306d
                   access_type, S_IRWXU);
Packit Service 31306d
  if (file == NULL)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Can't open file for writing: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  nwritten = sftp_write(file, helloworld, length);
Packit Service 31306d
  if (nwritten != length)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Can't write data to file: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    sftp_close(file);
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  rc = sftp_close(file);
Packit Service 31306d
  if (rc != SSH_OK)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Can't close the written file: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    return rc;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
@endcode
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
@subsection sftp_read Reading a file from the remote computer
Packit Service 31306d
Packit Service 31306d
The nice thing with reading a file over the network through SFTP is that it
Packit Service 31306d
can be done both in a synchronous way or an asynchronous way. If you read the file
Packit Service 31306d
asynchronously, your program can do something else while it waits for the
Packit Service 31306d
results to come.
Packit Service 31306d
Packit Service 31306d
Synchronous read is done with sftp_read().
Packit Service 31306d
Packit Service 31306d
Files are normally transferred in chunks. A good chunk size is 16 KB. The following
Packit Service 31306d
example transfers the remote file "/etc/profile" in 16 KB chunks. For each chunk we
Packit Service 31306d
request, sftp_read blocks till the data has been received:
Packit Service 31306d
Packit Service 31306d
@code
Packit Service 31306d
// Good chunk size
Packit Service 31306d
#define MAX_XFER_BUF_SIZE 16384
Packit Service 31306d
Packit Service 31306d
int sftp_read_sync(ssh_session session, sftp_session sftp)
Packit Service 31306d
{
Packit Service 31306d
  int access_type;
Packit Service 31306d
  sftp_file file;
Packit Service 31306d
  char buffer[MAX_XFER_BUF_SIZE];
Packit Service 31306d
  int nbytes, nwritten, rc;
Packit Service 31306d
  int fd;
Packit Service 31306d
Packit Service 31306d
  access_type = O_RDONLY;
Packit Service 31306d
  file = sftp_open(sftp, "/etc/profile",
Packit Service 31306d
                   access_type, 0);
Packit Service 31306d
  if (file == NULL) {
Packit Service 31306d
      fprintf(stderr, "Can't open file for reading: %s\n",
Packit Service 31306d
              ssh_get_error(session));
Packit Service 31306d
      return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  fd = open("/path/to/profile", O_CREAT);
Packit Service 31306d
  if (fd < 0) {
Packit Service 31306d
      fprintf(stderr, "Can't open file for writing: %s\n",
Packit Service 31306d
              strerror(errno));
Packit Service 31306d
      return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  for (;;) {
Packit Service 31306d
      nbytes = sftp_read(file, buffer, sizeof(buffer));
Packit Service 31306d
      if (nbytes == 0) {
Packit Service 31306d
          break; // EOF
Packit Service 31306d
      } else if (nbytes < 0) {
Packit Service 31306d
          fprintf(stderr, "Error while reading file: %s\n",
Packit Service 31306d
                  ssh_get_error(session));
Packit Service 31306d
          sftp_close(file);
Packit Service 31306d
          return SSH_ERROR;
Packit Service 31306d
      }
Packit Service 31306d
Packit Service 31306d
      nwritten = write(fd, buffer, nbytes);
Packit Service 31306d
      if (nwritten != nbytes) {
Packit Service 31306d
          fprintf(stderr, "Error writing: %s\n",
Packit Service 31306d
                  strerror(errno));
Packit Service 31306d
          sftp_close(file);
Packit Service 31306d
          return SSH_ERROR;
Packit Service 31306d
      }
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  rc = sftp_close(file);
Packit Service 31306d
  if (rc != SSH_OK) {
Packit Service 31306d
      fprintf(stderr, "Can't close the read file: %s\n",
Packit Service 31306d
              ssh_get_error(session));
Packit Service 31306d
      return rc;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
@endcode
Packit Service 31306d
Packit Service 31306d
Asynchronous read is done in two steps, first sftp_async_read_begin(), which
Packit Service 31306d
returns a "request handle", and then sftp_async_read(), which uses that request handle.
Packit Service 31306d
If the file has been opened in nonblocking mode, then sftp_async_read()
Packit Service 31306d
might return SSH_AGAIN, which means that the request hasn't completed yet
Packit Service 31306d
and that the function should be called again later on. Otherwise,
Packit Service 31306d
sftp_async_read() waits for the data to come. To open a file in nonblocking mode,
Packit Service 31306d
call sftp_file_set_nonblocking() right after you opened it. Default is blocking mode.
Packit Service 31306d
Packit Service 31306d
The example below reads a very big file in asynchronous, nonblocking, mode. Each
Packit Service 31306d
time the data is not ready yet, a counter is incremented.
Packit Service 31306d
Packit Service 31306d
@code
Packit Service 31306d
// Good chunk size
Packit Service 31306d
#define MAX_XFER_BUF_SIZE 16384
Packit Service 31306d
Packit Service 31306d
int sftp_read_async(ssh_session session, sftp_session sftp)
Packit Service 31306d
{
Packit Service 31306d
  int access_type;
Packit Service 31306d
  sftp_file file;
Packit Service 31306d
  char buffer[MAX_XFER_BUF_SIZE];
Packit Service 31306d
  int async_request;
Packit Service 31306d
  int nbytes;
Packit Service 31306d
  long counter;
Packit Service 31306d
  int rc;
Packit Service 31306d
Packit Service 31306d
  access_type = O_RDONLY;
Packit Service 31306d
  file = sftp_open(sftp, "some_very_big_file",
Packit Service 31306d
                   access_type, 0);
Packit Service 31306d
  if (file == NULL) {
Packit Service 31306d
    fprintf(stderr, "Can't open file for reading: %s\n",
Packit Service 31306d
                     ssh_get_error(session));
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
  sftp_file_set_nonblocking(file);
Packit Service 31306d
Packit Service 31306d
  async_request = sftp_async_read_begin(file, sizeof(buffer));
Packit Service 31306d
  counter = 0L;
Packit Service 31306d
  usleep(10000);
Packit Service 31306d
  if (async_request >= 0) {
Packit Service 31306d
    nbytes = sftp_async_read(file, buffer, sizeof(buffer),
Packit Service 31306d
                             async_request);
Packit Service 31306d
  } else {
Packit Service 31306d
      nbytes = -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  while (nbytes > 0 || nbytes == SSH_AGAIN) {
Packit Service 31306d
    if (nbytes > 0) {
Packit Service 31306d
      write(1, buffer, nbytes);
Packit Service 31306d
      async_request = sftp_async_read_begin(file, sizeof(buffer));
Packit Service 31306d
    } else {
Packit Service 31306d
        counter++;
Packit Service 31306d
    }
Packit Service 31306d
    usleep(10000);
Packit Service 31306d
Packit Service 31306d
    if (async_request >= 0) {
Packit Service 31306d
      nbytes = sftp_async_read(file, buffer, sizeof(buffer),
Packit Service 31306d
                               async_request);
Packit Service 31306d
    } else {
Packit Service 31306d
        nbytes = -1;
Packit Service 31306d
    }
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (nbytes < 0) {
Packit Service 31306d
    fprintf(stderr, "Error while reading file: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    sftp_close(file);
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  printf("The counter has reached value: %ld\n", counter);
Packit Service 31306d
Packit Service 31306d
  rc = sftp_close(file);
Packit Service 31306d
  if (rc != SSH_OK) {
Packit Service 31306d
    fprintf(stderr, "Can't close the read file: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    return rc;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
@endcode
Packit Service 31306d
Packit Service 31306d
@subsection sftp_ls Listing the contents of a directory
Packit Service 31306d
Packit Service 31306d
The functions sftp_opendir(), sftp_readdir(), sftp_dir_eof(),
Packit Service 31306d
and sftp_closedir() enable to list the contents of a directory.
Packit Service 31306d
They use a new handle_type, "sftp_dir", which gives access to the
Packit Service 31306d
directory being read.
Packit Service 31306d
Packit Service 31306d
In addition, sftp_readdir() returns a "sftp_attributes" which is a pointer
Packit Service 31306d
to a structure with information about a directory entry:
Packit Service 31306d
  - name: the name of the file or directory
Packit Service 31306d
  - size: its size in bytes
Packit Service 31306d
  - etc.
Packit Service 31306d
Packit Service 31306d
sftp_readdir() might return NULL under two conditions:
Packit Service 31306d
  - when the end of the directory has been met
Packit Service 31306d
  - when an error occurred
Packit Service 31306d
Packit Service 31306d
To tell the difference, call sftp_dir_eof().
Packit Service 31306d
Packit Service 31306d
The attributes must be freed with sftp_attributes_free() when no longer
Packit Service 31306d
needed.
Packit Service 31306d
Packit Service 31306d
The following example reads the contents of some remote directory:
Packit Service 31306d
Packit Service 31306d
@code
Packit Service 31306d
int sftp_list_dir(ssh_session session, sftp_session sftp)
Packit Service 31306d
{
Packit Service 31306d
  sftp_dir dir;
Packit Service 31306d
  sftp_attributes attributes;
Packit Service 31306d
  int rc;
Packit Service 31306d
Packit Service 31306d
  dir = sftp_opendir(sftp, "/var/log");
Packit Service 31306d
  if (!dir)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Directory not opened: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  printf("Name                       Size Perms    Owner\tGroup\n");
Packit Service 31306d
Packit Service 31306d
  while ((attributes = sftp_readdir(sftp, dir)) != NULL)
Packit Service 31306d
  {
Packit Service 31306d
    printf("%-20s %10llu %.8o %s(%d)\t%s(%d)\n",
Packit Service 31306d
     attributes->name,
Packit Service 31306d
     (long long unsigned int) attributes->size,
Packit Service 31306d
     attributes->permissions,
Packit Service 31306d
     attributes->owner,
Packit Service 31306d
     attributes->uid,
Packit Service 31306d
     attributes->group,
Packit Service 31306d
     attributes->gid);
Packit Service 31306d
Packit Service 31306d
     sftp_attributes_free(attributes);
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (!sftp_dir_eof(dir))
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Can't list directory: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    sftp_closedir(dir);
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  rc = sftp_closedir(dir);
Packit Service 31306d
  if (rc != SSH_OK)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Can't close directory: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    return rc;
Packit Service 31306d
  }
Packit Service 31306d
}
Packit Service 31306d
@endcode
Packit Service 31306d
Packit Service 31306d
*/