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