Blame doc/scp.dox

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