Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to copy a file in C/C++ with libssh and SFTP

Tags:

c++

c

ssh

sftp

libssh

I want to copy a file from a client to a remote server, but I don't understand how to do it with the libssh library SFTP API.

The situation is that: The SSH session is open and the SFTP session is open too, I can create a file and write in it from the client to the server with the integrated function of libssh.

I did not find an easy way to copy a file from the client to the server with a simple function like sftp_transfer(sourceFile(like c:\my document\hello world.txt),RemoteFile(/home/user/hello world.txt),right(read and write)) ?

With what I have understood from the tutorial it is first creating a file in the remote location (server) then it is opening this file with this line of code:

file = sftp_open(sftp, "/home/helloworld.txt",access_type,1);

After that the file is created on the server, and then it is writing into this created file with a buffer:

const char *helloworld = "Hello, World!\n";
int length = strlen(helloworld);
nwritten = sftp_write(file, helloworld, length);

My question is now if I have a file for example a .doc file and I want to transfer/upload that file from c:\mydocument\document.doc to remote the remote server /home/user/document.doc, how can I do it with this method ?

How can I put this file into the sftp_write() function to send it like the helloworld in the sample function?

I may be not good enough in programming to understand, but I really tried to understand it and I'm stuck with it.

Thanks in advance for your help

See below a sample of the code I used to test:

// Set variable for the communication
char buffer[256];
unsigned int nbytes;

//create a file to send by SFTP
int access_type = O_WRONLY | O_CREAT | O_TRUNC;
const char *helloworld = "Hello, World!\n";
int length = strlen(helloworld);

//Open a SFTP session
sftp = sftp_new(my_ssh_session);
if (sftp == NULL)
{
    fprintf(stderr, "Error allocating SFTP session: %s\n",
    ssh_get_error(my_ssh_session));
    return SSH_ERROR;
}
// Initialize the SFTP session
rc = sftp_init(sftp);
if (rc != SSH_OK)
{
    fprintf(stderr, "Error initializing SFTP session: %s.\n",
    sftp_get_error(sftp));
    sftp_free(sftp);
    return rc;
}

//Open the file into the remote side
file = sftp_open(sftp, "/home/helloworld.txt",access_type,1);
if (file == NULL)
{
    fprintf(stderr, "Can't open file for writing: %s\n",ssh_get_error(my_ssh_session));
    return SSH_ERROR;
}

//Write the file created with what's into the buffer
nwritten = sftp_write(file, helloworld, length);
if (nwritten != length)
{
    fprintf(stderr, "Can't write data to file: %s\n",
    ssh_get_error(my_ssh_session));
    sftp_close(file);
    return SSH_ERROR;
}
like image 568
Raphael Teubner Avatar asked Dec 03 '12 20:12

Raphael Teubner


2 Answers

Open the file in the usual way (using C++'s fstream or C's stdio.h), read its contents to a buffer, and pass the buffer to sftp_write.

Something like this:

ifstream fin("file.doc", ios::binary);
if (fin) {
  fin.seekg(0, ios::end);
  ios::pos_type bufsize = fin.tellg();   // get file size in bytes
  fin.seekg(0);                          // rewind to beginning of file

  std::vector<char> buf(bufsize);        // allocate buffer
  fin.read(buf.data(), bufsize);         // read file contents into buffer

  sftp_write(file, buf.data(), bufsize); // write buffer to remote file
}

Note that this is a very simple implementation. You should probably open the remote file in append mode, then write the data in chunks instead of sending single huge blob of data.

like image 176
Reuben Morais Avatar answered Oct 18 '22 19:10

Reuben Morais


The following example uses ifstream in a loop to avoid loading a whole file into a memory (as the accepted answer does):

ifstream fin("C:\\myfile.zip", ios::binary);

while (fin)
{
    constexpr size_t max_xfer_buf_size = 10240
    char buffer[max_xfer_buf_size];
    fin.read(buffer, sizeof(buffer));
    if (fin.gcount() > 0)
    {
        ssize_t nwritten = sftp_write(NULL, buffer, fin.gcount());
        if (nwritten != fin.gcount())
        {
            fprintf(stderr, "Error writing to file: %s\n", ssh_get_error(ssh_session));
            sftp_close(file);
            return 1;
        }
    }
}
like image 43
Martin Prikryl Avatar answered Oct 18 '22 19:10

Martin Prikryl