Blame doc/scp.dox

Packit Service 31306d
/**
Packit Service 31306d
@page libssh_tutor_scp Chapter 6: The SCP subsystem
Packit Service 31306d
@section scp_subsystem The SCP subsystem
Packit Service 31306d
Packit Service 31306d
The SCP subsystem has far less functionality than the SFTP subsystem.
Packit Service 31306d
However, if you only need to copy files from and to the remote system,
Packit Service 31306d
it does its job.
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
@subsection scp_session Opening and closing a SCP session
Packit Service 31306d
Packit Service 31306d
Like in the SFTP subsystem, you don't handle the SSH channels directly.
Packit Service 31306d
Instead, you open a "SCP session".
Packit Service 31306d
Packit Service 31306d
When you open your SCP session, you have to choose between read or write mode.
Packit Service 31306d
You can't do both in the same session. So you specify either SSH_SCP_READ or
Packit Service 31306d
SSH_SCP_WRITE as the second parameter of function ssh_scp_new().
Packit Service 31306d
Packit Service 31306d
Another important mode flag for opening your SCP session is SSH_SCP_RECURSIVE.
Packit Service 31306d
When you use SSH_SCP_RECURSIVE, you declare that you are willing to emulate
Packit Service 31306d
the behaviour of "scp -r" command in your program, no matter it is for
Packit Service 31306d
reading or for writing.
Packit Service 31306d
Packit Service 31306d
Once your session is created, you initialize it with ssh_scp_init(). When
Packit Service 31306d
you have finished transferring files, you terminate the SCP connection with
Packit Service 31306d
ssh_scp_close(). Finally, you can dispose the SCP connection with
Packit Service 31306d
ssh_scp_free().
Packit Service 31306d
Packit Service 31306d
The example below does the maintenance work to open a SCP connection for writing in
Packit Service 31306d
recursive mode:
Packit Service 31306d
Packit Service 31306d
@code
Packit Service 31306d
int scp_write(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
  ssh_scp scp;
Packit Service 31306d
  int rc;
Packit Service 31306d
Packit Service 31306d
  scp = ssh_scp_new
Packit Service 31306d
    (session, SSH_SCP_WRITE | SSH_SCP_RECURSIVE, ".");
Packit Service 31306d
  if (scp == NULL)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Error allocating scp 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 = ssh_scp_init(scp);
Packit Service 31306d
  if (rc != SSH_OK)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Error initializing scp session: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    ssh_scp_free(scp);
Packit Service 31306d
    return rc;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  ...
Packit Service 31306d
Packit Service 31306d
  ssh_scp_close(scp);
Packit Service 31306d
  ssh_scp_free(scp);
Packit Service 31306d
  return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
@endcode
Packit Service 31306d
Packit Service 31306d
The example below shows how to open a connection to read a single file:
Packit Service 31306d
Packit Service 31306d
@code
Packit Service 31306d
int scp_read(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
  ssh_scp scp;
Packit Service 31306d
  int rc;
Packit Service 31306d
Packit Service 31306d
  scp = ssh_scp_new
Packit Service 31306d
    (session, SSH_SCP_READ, "helloworld/helloworld.txt");
Packit Service 31306d
  if (scp == NULL)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Error allocating scp 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 = ssh_scp_init(scp);
Packit Service 31306d
  if (rc != SSH_OK)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Error initializing scp session: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    ssh_scp_free(scp);
Packit Service 31306d
    return rc;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  ...
Packit Service 31306d
Packit Service 31306d
  ssh_scp_close(scp);
Packit Service 31306d
  ssh_scp_free(scp);
Packit Service 31306d
  return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
@endcode
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
@subsection scp_write Creating files and directories
Packit Service 31306d
Packit Service 31306d
You create directories with ssh_scp_push_directory(). In recursive mode,
Packit Service 31306d
you are placed in this directory once it is created. If the directory
Packit Service 31306d
already exists and if you are in recursive mode, you simply enter that
Packit Service 31306d
directory.
Packit Service 31306d
Packit Service 31306d
Creating files is done in two steps. First, you prepare the writing with
Packit Service 31306d
ssh_scp_push_file(). Then, you write the data with ssh_scp_write().
Packit Service 31306d
The length of the data to write must be identical between both function calls.
Packit Service 31306d
There's no need to "open" nor "close" the file, this is done automatically
Packit Service 31306d
on the remote end. If the file already exists, it is overwritten and truncated.
Packit Service 31306d
Packit Service 31306d
The following example creates a new directory named "helloworld/", then creates
Packit Service 31306d
a file named "helloworld.txt" in that directory:
Packit Service 31306d
Packit Service 31306d
@code
Packit Service 31306d
int scp_helloworld(ssh_session session, ssh_scp scp)
Packit Service 31306d
{
Packit Service 31306d
  int rc;
Packit Service 31306d
  const char *helloworld = "Hello, world!\n";
Packit Service 31306d
  int length = strlen(helloworld);
Packit Service 31306d
Packit Service 31306d
  rc = ssh_scp_push_directory(scp, "helloworld", S_IRWXU);
Packit Service 31306d
  if (rc != SSH_OK)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Can't create remote directory: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    return rc;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  rc = ssh_scp_push_file
Packit Service 31306d
    (scp, "helloworld.txt", length, S_IRUSR |  S_IWUSR);
Packit Service 31306d
  if (rc != SSH_OK)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Can't open remote file: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    return rc;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  rc = ssh_scp_write(scp, helloworld, length);
Packit Service 31306d
  if (rc != SSH_OK)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Can't write to remote 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 scp_recursive_write Copying full directory trees to the remote server
Packit Service 31306d
Packit Service 31306d
Let's say you want to copy the following tree of files to the remote site:
Packit Service 31306d
Packit Service 31306d
@verbatim
Packit Service 31306d
               +-- file1
Packit Service 31306d
       +-- B --+
Packit Service 31306d
       |       +-- file2
Packit Service 31306d
-- A --+
Packit Service 31306d
       |       +-- file3
Packit Service 31306d
       +-- C --+
Packit Service 31306d
               +-- file4
Packit Service 31306d
@endverbatim
Packit Service 31306d
Packit Service 31306d
You would do it that way:
Packit Service 31306d
  - open the session in recursive mode
Packit Service 31306d
  - enter directory A
Packit Service 31306d
  - enter its subdirectory B
Packit Service 31306d
  - create file1 in B
Packit Service 31306d
  - create file2 in B
Packit Service 31306d
  - leave directory B
Packit Service 31306d
  - enter subdirectory C
Packit Service 31306d
  - create file3 in C
Packit Service 31306d
  - create file4 in C
Packit Service 31306d
  - leave directory C
Packit Service 31306d
  - leave directory A
Packit Service 31306d
Packit Service 31306d
To leave a directory, call ssh_scp_leave_directory().
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
@subsection scp_read Reading files and directories
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
To receive files, you pull requests from the other side with ssh_scp_pull_request().
Packit Service 31306d
If this function returns SSH_SCP_REQUEST_NEWFILE, then you must get ready for
Packit Service 31306d
the reception. You can get the size of the data to receive with ssh_scp_request_get_size()
Packit Service 31306d
and allocate a buffer accordingly. When you are ready, you accept the request with
Packit Service 31306d
ssh_scp_accept_request(), then read the data with ssh_scp_read().
Packit Service 31306d
Packit Service 31306d
The following example receives a single file. The name of the file to
Packit Service 31306d
receive has been given earlier, when the scp session was opened:
Packit Service 31306d
Packit Service 31306d
@code
Packit Service 31306d
int scp_receive(ssh_session session, ssh_scp scp)
Packit Service 31306d
{
Packit Service 31306d
  int rc;
Packit Service 31306d
  int size, mode;
Packit Service 31306d
  char *filename, *buffer;
Packit Service 31306d
Packit Service 31306d
  rc = ssh_scp_pull_request(scp);
Packit Service 31306d
  if (rc != SSH_SCP_REQUEST_NEWFILE)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Error receiving information about file: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  size = ssh_scp_request_get_size(scp);
Packit Service 31306d
  filename = strdup(ssh_scp_request_get_filename(scp));
Packit Service 31306d
  mode = ssh_scp_request_get_permissions(scp);
Packit Service 31306d
  printf("Receiving file %s, size %d, permissions 0%o\n",
Packit Service 31306d
          filename, size, mode);
Packit Service 31306d
  free(filename);
Packit Service 31306d
Packit Service 31306d
  buffer = malloc(size);
Packit Service 31306d
  if (buffer == NULL)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Memory allocation error\n");
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  ssh_scp_accept_request(scp);
Packit Service 31306d
  rc = ssh_scp_read(scp, buffer, size);
Packit Service 31306d
  if (rc == SSH_ERROR)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Error receiving file data: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    free(buffer);
Packit Service 31306d
    return rc;
Packit Service 31306d
  }
Packit Service 31306d
  printf("Done\n");
Packit Service 31306d
Packit Service 31306d
  write(1, buffer, size);
Packit Service 31306d
  free(buffer);
Packit Service 31306d
Packit Service 31306d
  rc = ssh_scp_pull_request(scp);
Packit Service 31306d
  if (rc != SSH_SCP_REQUEST_EOF)
Packit Service 31306d
  {
Packit Service 31306d
    fprintf(stderr, "Unexpected request: %s\n",
Packit Service 31306d
            ssh_get_error(session));
Packit Service 31306d
    return SSH_ERROR;
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
In this example, since we just requested a single file, we expect ssh_scp_request()
Packit Service 31306d
to return SSH_SCP_REQUEST_NEWFILE first, then SSH_SCP_REQUEST_EOF. That's quite a
Packit Service 31306d
naive approach; for example, the remote server might send a warning as well
Packit Service 31306d
(return code SSH_SCP_REQUEST_WARNING) and the example would fail. A more comprehensive
Packit Service 31306d
reception program would receive the requests in a loop and analyze them carefully
Packit Service 31306d
until SSH_SCP_REQUEST_EOF has been received.
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
@subsection scp_recursive_read Receiving full directory trees from the remote server
Packit Service 31306d
Packit Service 31306d
If you opened the SCP session in recursive mode, the remote end will be
Packit Service 31306d
telling you when to change directory.
Packit Service 31306d
Packit Service 31306d
In that case, when ssh_scp_pull_request() answers
Packit Service 31306d
SSH_SCP_REQUEST_NEWDIRECTORY, you should make that local directory (if
Packit Service 31306d
it does not exist yet) and enter it. When ssh_scp_pull_request() answers
Packit Service 31306d
SSH_SCP_REQUEST_ENDDIRECTORY, you should leave the current directory.
Packit Service 31306d
Packit Service 31306d
*/