2

I am trying to download few files stored on a remote machine. Those files can be either text files, image files (of jpeg,jpg form), video or audio files. Text files are downloaded successfully without issue and I am also able to open it as well in my local machine where I download them.

But image files and other video, audio files do not open after getting downloaded. When I checked, they were not of same size as original file. Like say the original file was of 30kb, but the downloaded file was only of 5kb. And this is the reason that maybe I am not able to open those files locally after downloading?

I am using scp function of libssh. Below is what I am trying:

#include <iostream>
#include <string>
#include <libssh.h>
#include <stdlib.h>
#include <fstream> 
#include <stdio.h>
#include <Windows.h>
#include <fcntl.h>
#include <sstream>
#include <io.h>
using namespace std;

static int fetch_files(ssh_session session){
    int size;
    //char buffer[16384];
    int mode;
    int rc;
    //creating scp session to read from remote host for this file
    ssh_scp scp = ssh_scp_new(session, SSH_SCP_READ | SSH_SCP_RECURSIVE, "/home/snaps.jpg");

    
    //executing the init
    rc = ssh_scp_init(scp);
    
    //pulling from request object
    rc = ssh_scp_pull_request(scp);
    if (rc != SSH_SCP_REQUEST_NEWFILE)
    {
        std::cout << "Error receiving information about file: rc != SSH_SCP_REQUEST_NEWFILE";
        return -3;
    }
    else {
        //trying to download the file from the created scp object
        int t_filesize = ssh_scp_request_get_size(scp);
        cout << "filesize is = " << t_filesize;
        string t_filename = strdup(ssh_scp_request_get_filename(scp));
        cout << "File name read is = " << t_filename;
        int t_filemode = ssh_scp_request_get_permissions(scp);
        cout << "File mode is = " << t_filemode;
        //fprintf(stderr, "Receiving file %s, size %d, permisssions 0%o\n", t_filename, t_filesize, t_filemode);
        FILE *fptr = fopen("file.jpg", "w");
        if (NULL == fptr)
        {
            fprintf(stderr, "Error opening local file: %s, error %s\n", t_filename, strerror(errno));
            ssh_scp_deny_request(scp, "Unable to open local file");

        }
        ssh_scp_accept_request(scp);

        while (rc >= 0)
        {   //reading and storing into buffer to write on local file system
            rc = ssh_scp_read(scp, buffer, sizeof(buffer));
            cout << "Buffer = " << buffer;
            //cout << "RC = " << rc << " and SSH_ERROR is = " << SSH_ERROR;
            if (rc == SSH_ERROR)
            {
                fprintf(stderr, "Error receiving file data: %s\n", ssh_get_error(session));
                fclose(fptr);
                ssh_scp_close(scp);
                ssh_scp_free(scp);
                return rc;
            }
            //fprintf(stderr, "Bytes received = %d\n", rc);
            if (fwrite(buffer, rc, 1, fptr) != t_filesize)
            {
                fprintf(stderr, "Error writing file data: %s\n", strerror(errno));
                fclose(fptr);
                ssh_scp_close(scp);
                ssh_scp_free(scp);
                return rc;
            }
        } 
        cout << "Buffer is = " << buffer;
        fclose(fptr);

    }

How can I resolve it?

halfer
  • 19,824
  • 17
  • 99
  • 186
CodeHunter
  • 2,017
  • 2
  • 21
  • 47
  • Maybe (*I* didn't downvote, so I don't *know*) because the code you posted is *not* a [mcve] that we can copy-n-paste and test ourselves.. I *did* vote to close for that reason though. – Jesper Juhl Feb 25 '19 at 19:17
  • 1
    oh okays. Let me provide the code as per guidelines. Thanks for pointing it out. Appreciate that. – CodeHunter Feb 25 '19 at 19:20
  • My psychic debugging powers tell me you're reading incomplete files from the remote system because some process there is still writing the file when you read it. – Kenster Feb 25 '19 at 23:17
  • @Kenster The files are not being written concurrently. They are already present there actually. Besides, if that is the case, it should read even the text files incompletely. – CodeHunter Feb 26 '19 at 18:48
  • This is still not a minimal complete verifiable example. If I was to guess though, I think you have sent the wrong parameters to `std::fwrite()` and that you areusing the return value wrongly. – Galik Feb 27 '19 at 22:49

1 Answers1

4
if (fwrite(buffer, rc, 1, fptr) != t_filesize)

Should have been

if (fwrite(buffer, 1, rc, fptr) != rc)

Or

if (fwrite(buffer, rc, 1, fptr) != 1)

rc and 1 are swapped. You intended to write rc bytes, second parameter is size of each unit with, third is number of units. Neither has anything to do with t_filesize yet.


while (rc >= 0)

Insufficient, you also need a counter for the total bytes received yet. In the loop increment by rc and break if total >= t_filesize.


rc = ssh_scp_read(scp, buffer, sizeof(buffer));

Extend to

rc = ssh_scp_read(scp, buffer, min(sizeof(buffer), t_filesize - total));

So you don't request read of bytes which are not available.


As for why your files are too small, it's because you run into the faulty error handling mentioned first. You only get the first buffer full (respectively not even that, because the buffer isn't fully used), and the you already return from transfer.

Ext3h
  • 5,713
  • 17
  • 43
  • Thanks a lot for your answer. Let me verify and confirm the same. So regarding that `total >= t_filesize`, I need to add `total = 0` and then `total = total + rc` and in while loop, it would be `while(rc>=0 && total >= t_filesize)`. Correct me if I am wrong. – CodeHunter Feb 28 '19 at 02:25
  • And regarding your last comment, `rc = ssh_scp_read(scp, buffer, min(sizeof(buffer), t_filesize - total));` should take care of that I suppose? Let me try and confirm. – CodeHunter Feb 28 '19 at 02:27