Vanreyn
Vanreyn

Reputation: 21

ssh_scp_read returns garbage

I'm trying to download a file from my server; both the client and the server are Linux, yet ssh_scp_read() returns an incorrect integer. According to the documentation the function writes up to 65536 bytes, yet is only reading 16384 when the file is 37980, but that's not my main concern; near the end of this 16384 bytes it starts to fill the buffer with NULL garbage, that will then be written to the file.

The creation of recursive directories works fine; the problem is downloading files larger than 16384 bytes. At this point I'll use sftp instead of scp, but I would like to know what I am doing wrong.

This is the function code:

int get(ssh_session gno_ses,ssh_scp scp)
{
    int rc;
    int size, permissions;
    char *buff, *filename, path[PATH_MAX];

    while(1)
    {
        rc = ssh_scp_pull_request(scp);
        switch (rc)
        {
            // cases [...]
            case SSH_SCP_REQUEST_NEWFILE:
                size = ssh_scp_request_get_size(scp);
                printf("Size is %d\n",size);
                filename = strdup(ssh_scp_request_get_filename(scp));
                permissions = ssh_scp_request_get_permissions(scp);

                FILE *file;
                file = fopen(filename, "w+");
                if (!file)
                {
                    ssh_scp_deny_request(scp,"Unable to open");
                    fprintf(stderr, " %s: %s\n", filename, strerror(errno));
                    fclose(file);
                    break;
                }

                buff = malloc(size);
                printf("Size of buffer is %d\n", size);
                if (!buff)
                {
                    fprintf(stderr, "\nBuff memory allocation error.\n");
                    return SSH_ERROR;
                }

                if( ssh_scp_accept_request(scp) != SSH_OK)
                {
                    fprintf(stderr, "Error accepting request: %s\n", ssh_get_error(gno_ses));
                    break;
                }

                do
                {
                    rc = ssh_scp_read(scp, buff, size);
                    if (rc == SSH_ERROR)
                    {
                        fprintf(stderr, "Error receiving file data: %s\n", ssh_get_error(gno_ses));
                        break;
                    }
                    if (fwrite(buff, 1, size, file) != size)
                    {
                        perror("Error at writting to file: ");
                        break;
                    }
                    printf("ssh_scp_read got %d\n",rc);
                } while (rc != 0);

                fclose(file);
                free(filename);
                free(buff);
                break;
        }
    }
    return SSH_OK;
}

And this is the output:

Size is 37980
Size of buffer is 37980
ssh_scp_read got 16384
ssh_scp_read got 16384
ssh_scp_read got 5212
Error receiving file data: ssh_scp_read called under invalid state

Any input would be appreciated.

Upvotes: 0

Views: 554

Answers (2)

Vanreyn
Vanreyn

Reputation: 21

The problem was that I was writing size bytes when indeed scp_scp_read() had reported that it had read less than that:

rc = ssh_scp_read(scp, buff, size);
fwrite(buff, 1, size, file)

The fix is to write only rc bytes:

            int len_loop = size;
            int len;
            do
            {
                rc = ssh_scp_read(scp, buff, size);
                if (rc == SSH_ERROR || rc < 0)
                {
                    fprintf(stderr, "Error receiving file data: %s\n", ssh_get_error(gno_ses));
                    break;
                }
                else if (!rc)
                {
                    break;
                }
                len = fwrite(buff, 1, rc, file);
                if (len != rc)
                {
                    perror("Error at writting to file: ");
                    break;
                }
                printf("ssh_scp_read got %d\n",rc);
                len_loop -= rc;
            } while(len_loop);

Upvotes: 1

ilia
ilia

Reputation: 1132

change your inner loop as

int len = size;
do
   {
                    rc = ssh_scp_read(scp, buff, size);
                    if (rc == SSH_ERROR)
                    {
                        fprintf(stderr, "Error receiving file data: %s\n", 
                        ssh_get_error(gno_ses));
                        break;
                    }
                    if (fwrite(buff, 1, rc, file) != size)
                    {
                        perror("Error at writting to file: ");
                        break;
                    }
                    printf("ssh_scp_read got %d\n",rc);
                    len-=rc;
    } while (len);

Upvotes: 0

Related Questions