libssh2_channel_read file last bytes only - c++

I have an remote big file, and only need to read the last bytes of it.
How can I do this?
I got this for the whole file, but I don't see where I can only write the last bytes without reading it all.
channel = libssh2_scp_recv2(session, remotefile.c_str(), &fileinfo);
if (!channel) {
fprintf(stderr, "Unable to open a session: %d\n",
libssh2_session_last_errno(session));
return;
}
FILE* pFile = fopen (filename.c_str(), "wb");
while(got < fileinfo.st_size) {
char mem[1024];
int amount=sizeof(mem);
if((fileinfo.st_size -got) < amount) {
amount = (int)(fileinfo.st_size -got);
}
rc = libssh2_channel_read(channel, mem, amount);
if(rc > 0) {
fwrite (mem , sizeof(char), rc, pFile);
//write(1, mem, rc);
}
else if(rc < 0) {
fprintf(stderr, "libssh2_channel_read() failed: %d\n", rc);
break;
}
got += rc;
}
fclose (pFile);
libssh2_channel_free(channel);

Ok I managed using libssh2_sftp_open instead with libssh2_sftp_seek64
Thanks

Related

Correctly reading and writing from socket stream

So, I'm a relative newbie to network programming and programming in general, and I'm attempting to write a simple client/server text file transfer service. My code asks for the user to choose an upload or download option. When the user selects upload, the new file is created on the server's end, but isn't written with the data until the socket is closed. Also the string "upload" is appended onto the end of the text in the file.
I can't seem to find where my errors are, so any help would be greatly appreciated!
server.cpp
#define SIZE 1024
void write_file(int sockfd) // writing data to file function
{
int n;
FILE *fp;
char const *filename = "recv.txt";
char buffer[SIZE];
fp = fopen(filename, "w");
while (1)
{
n = recv(sockfd, buffer, SIZE, 0);
if (n <= 0)
{
break;
}
fprintf(fp, "%s", buffer);
bzero(buffer, SIZE);
}
fclose(fp);
return;
}
// in main
char msgRecv[10];
int n = 10;
while (n > 0)
{
rcv = read(connected_sd, &msgRecv, 10);
n -= rcv;
}
char msgUpload[10] = "upload";
if(strcmp(msgUpload, msgRecv) == 0)
{
write_file(connected_sd);
}
client.cpp
void send_file(FILE *points, int sockfd) // sending file through socket function
{
char bytes[SIZE] = {0};
bzero(bytes, SIZE);
while(fgets(bytes, SIZE, points) != NULL)
{
if(send(sockfd, bytes, sizeof(bytes), 0) == -1)
{
perror("Error in sending file.");
exit(1);
}
bzero(bytes, SIZE);
}
}
// in main
char msgUpload[10] = "upload";
send(sd, msgUpload, sizeof(msgUpload), 0);
string fileN;
cout << "What is the name of the file you wish to upload?\n";
cin >> fileN;
bzero(msgUpload, sizeof(msgUpload));
FILE *file;
char const *filename = fileN.c_str();
file = fopen(filename, "r");
if (file == NULL)
{
perror("Error in reading file.\n");
exit(1);
}
send_file(file, sd);
printf("File data sent successfully.\n\n");
fclose(file);

Download file from SFTP server with libssh and write it to ofstream by using C++?

I wrote the following code from this.
#define MAX_XFER_BUF_SIZE 16384
int main()
{
char buffer[MAX_XFER_BUF_SIZE];
//..some content
access_type = O_RDONLY;
sftp_file file = sftp_open(sftp, "/home/ra/Desktop/sami/s.txt", access_type, 0);
ofstream fin("C:/Users/s.txt", ios::binary | ios::in | std::ofstream::out | std::ofstream::app);
nbytes = sftp_read(file, buffer, sizeof(buffer));
fin.write(buffer, sizeof(buffer));
But the buffer maximum size is predefined. So it only works for small files. I want to get the SFTP file size which size is much bigger. For that I need to send the data as chunks by append mode.
for (int i=0;i<sizeof(buffer);i++)
{
fin.write(buffer, buffer[i]);
}
I went through this answer, but i'm stuck in this > How can i solve this issue.
You have removed the loop that is in the Reading a file from the remote computer example.
Return it back. The important part of the example modified to use ofstream is like:
char buffer[MAX_XFER_BUF_SIZE];
// ...
for (;;)
{
nbytes = sftp_read(file, buffer, sizeof(buffer));
if (nbytes == 0)
{
break; // EOF
}
else if (nbytes < 0)
{
fprintf(stderr, "Error while reading file: %s\n", ssh_get_error(session));
sftp_close(file);
return SSH_ERROR;
}
fin.write(buffer, nbytes);
if (!fin)
{
fprintf(stderr, "Error writing");
sftp_close(file);
return SSH_ERROR;
}
}
fin.close();
if (!fin)
{
fprintf(stderr, "Error writing");
sftp_close(file);
return SSH_ERROR;
}
Imo, fin seems like a bad name to me. Shouldn't it be fout ("file output")?

fread loses binary data

I am using fread function to read file, which I am sending via TCP. I found out, that fread doesn't read the whole file, if the file is binary. I tried everything what i found on the internet, but nothing helped. My code is:
#define BUFSIZE 1024
char buf[BUFSIZE];
FILE *file = fopen(soubor,"rb"); //I do a check which i won't write here
size_t bytes_loaded = 0;
while (!feof(file))
{
bytes_loaded = fread(buf,1,BUFSIZE,file);
if(bytes_loaded != BUFSIZE)
{
if(!feof(file))
{
for(int i = 0; i < 100;i++)
{
fseek(file,-strlen(buf),SEEK_CUR);
bytes_loaded = fread(buf,1,BUFSIZE,file);
if(bytes_loaded == BUFSIZE)
{
break;
}
else if(i == 99)
{
fprintf(stderr,"C could't read the file\n");
fclose(file);
close(client_socket);
return 1;
}
}
}
}
bytestx = send(client_socket, buf, BUFSIZE, 0);
if (bytestx < 0)
perror("ERROR in sendto");
bzero(buf, BUFSIZE);
bytes_loaded = 0;
}
Am I doing something wrong? For example that fread check...
Your whole fread() error handling is wrong, get rid of it (using strlen() on a binary buffer is wrong anyway).
In fact, you shouldn't be using feof() to control your loop. Simply call fread() in a loop until it returns < 1 on EOF or error (use feof() and ferror() to differentiate). And when it returns > 0, you need to pass that value to send instead of passing BUFSIZE.
Try something more like this:
#define BUFSIZE 1024
char buf[BUFSIZE], *pbuf;
FILE *file = fopen(soubor, "rb");
...
size_t bytes_loaded;
do
{
bytes_loaded = fread(buf, 1, BUFSIZE, file);
if (bytes_loaded < 1)
{
if ((!feof(file)) && ferror(file))
fprintf(stderr, "Couldn't read the file\n");
break;
}
pbuf = buf;
do
{
bytestx = send(client_socket, pbuf, bytes_loaded, 0);
if (bytestx < 0)
{
perror("ERROR in send");
break;
}
pbuf += bytestx;
bytes_loaded -= bytestx;
}
while (bytes_loaded > 0);
}
while (bytes_loaded == 0);
fclose(file);
...
If you are just shifting bytes from the file to the socket then you can just keep looping on the return value from std::fread which tells you how many bytes you read and then send exactly that many bytes to your send() command.
Something like this (untested) code:
if(FILE* fp = std::fopen(soubor, "rb"))
{
char buf[1024];
std::size_t bytesrx;
while((bytesrx = std::fread(0, 1, sizeof(buf), fp)) > 0)
{
int bytestx;
if((bytestx = send(client_socket, buf, bytesrx, 0) < 0))
{
// socket error
std::cout << "socket error: " << std::strerror(errno) << '\n';
return EXIT_FAILURE;
}
}
if(bytesrx < 0)
{
// file error
std::cout << "file error: " << std::strerror(errno) << '\n';
return EXIT_FAILURE;
}
}
else
{
// error opening file
}

Linux server, upload a file to windows client (Socket)

When i send the file to the client it gets corrupted, and with a size in bytes higher.
I have a version of this server running on Windows and works perfectly,but I'm not having the same result on Linux.
The file size on disk may be the error in time to send the size in bytes to the client that runs on another platform?
fread function is being used correctly?
an expert can analyze and help find the error?
LINUX SERVER SIDE
// FUNCTION TO UPLOAD A FILE TO CLIENT WINDOWS
int Socket_Setup::FILE_UPLOAD(int iD, std::string DIR_UPLOAD)
{
char Block[1024];
long FileSize;
int BytesRead;
fp = fopen(DIR_UPLOAD.c_str(), "rb");
if (!fp)
{
errno_message.append((char*)strerror(errno));
FUNCTION_LOG(errno_message);
return 1;
}
fseek(fp, 0, SEEK_END);
FileSize = ftell(fp);
rewind(fp);
long Size_Send = htonl(FileSize);
Total = FileSize;
// Sending the file size to the Windows Client
iResult = send(client[iD].socket, (const char*)&Size_Send, sizeof(long), 0);
if (iResult <= 0)
{
errno_message.append((char*)strerror(errno));
FUNCTION_LOG(errno_message);
return 1;
}
// LOOP TO SEND FILE
while (FileSize > 0)
{
BytesRead = fread(Block, 1, sizeof(Block), fp);
if (BytesRead <= 0)
{
errno_message.append((char*)strerror(errno));
FUNCTION_LOG(errno_message);
fclose(fp);
return 1;
}
if (send(client[iD].socket, Block, BytesRead, 0) != BytesRead)
{
errno_message.append((char*)strerror(errno));
FUNCTION_LOG(errno_message);
fclose(fp);
return 1;
}
FileSize -= BytesRead;
}
fclose(fp);
return 0;
}
WINDOWS CLIENT SIDE:
int readBytes(SOCKET s, void *buffer, int buflen)
{
int total = 0;
char *pbuf = (char*)buffer;
while (buflen > 0)
{
int iResult = recv(s, pbuf, buflen, 0);
if (iResult < 0)
{
if (WSAGetLastError() == WSAEWOULDBLOCK)
continue;
return SOCKET_ERROR;
}
else if (iResult == 0)
return 0;
else
{
pbuf += iResult;
buflen -= iResult;
total += iResult;
}
}
return total;
}
// FUNCTION TO DOWNLOAD FILE FROM SERVER
int Remote_Manip::FILE_DOWNLOAD(std::string directory, Socket_Setup &socket_setup)
{
unsigned long FileSize;
char mfcc[65535];
File = fopen(directory.c_str(), "wb");
if (File == NULL)
{
closesocket(socket_setup.ConnectSocket);
WSACleanup();
return 1;
}
// Receiving file size from server
int iResult = readBytes(socket_setup.ConnectSocket, &FileSize, sizeof(FileSize));
if (iResult <= 0)
{
fclose(File);
closesocket(socket_setup.ConnectSocket);
WSACleanup();
return 1;
}
FileSize = ntohl(FileSize);
// LOOP TO RECEIVING FILE
while (FileSize > 0)
{
int Received = recv(socket_setup.ConnectSocket, mfcc, sizeof(mfcc),0);
if (Received <= 0)
{
fclose(File);
closesocket(socket_setup.ConnectSocket);
WSACleanup();
return 1;
}
if (fwrite(mfcc, 1, Received, File) != Received)
{
fclose(File);
closesocket(socket_setup.ConnectSocket);
WSACleanup();
return 1;
}
FileSize -= Received;
}
fflush(File);
fclose(File);
return 0;
}

Failed to send file via socket

I'm working with some C++ socket examples. The client run and can connect to the server but can't send the file. I think there's a problem with the send() but I can't fix it.Edit: the error message is "connection reset by peer"
Any ideas are welcomed.
I use OpenSuSE with QT 4.7.4
Here's the send and receive function
void str_server(int sock)
{
char buf[1025];
const char* filename = "//home//romanov//Documents//HelloWorld-build-desktop-Qt_4_7_4_in_PATH__System__Release//ss.png";
FILE *file = fopen(filename, "rb");
if (!file)
{
cerr<<"Can't open file for reading";
return;
}
while (!feof(file))
{
int rval = fread(buf, 1, sizeof(buf), file);//read value
if (rval < 1)
{
cerr<<"Can't read from file";
fclose(file);
return;
}
int off = 0;
do
{
int sent = send(sock, &buf[off], rval - off, 0);
if (sent < 1)
{
// if the socket is non-blocking, then check
// the socket error for WSAEWOULDBLOCK/EAGAIN
// (depending on platform) and if true then
// use select() to wait for a small period of
// time to see if the socket becomes writable
// again before failing the transfer...
cout<<"Can't write to socket";
fclose(file);
return;
}
off += sent;
}
while (off < rval);
}
fclose(file);
}
//===================
void RecvFile(int winsock)
{
int rval;
char buf[1025];
FILE *file = fopen("//home//romanov//Documents//HelloWorld-build-desktop-Qt_4_7_4_in_PATH__System__Release//ss2.png", "wb");
if (!file)
{
printf("Can't open file for writing");
return;
}
do
{
rval = recv(winsock, buf, sizeof(buf), 0);
if (rval < 0)
{
// if the socket is non-blocking, then check
// the socket error for WSAEWOULDBLOCK/EAGAIN
// (depending on platform) and if true then
// use select() to wait for a small period of
// time to see if the socket becomes readable
// again before failing the transfer...
printf("Can't read from socket");
fclose(file);
return;
}
if (rval == 0)
break; //line 159
int off = 0;
do
{
int written = fwrite(&buf[off], 1, rval - off, file);
if (written < 1)
{
printf("Can't write to file");
fclose(file);
return;
}
off += written;
}
while (off < rval);
} //line 175
while (1);
fclose(file);
}
Well , the problem is my bad, I read the wrong socket in the recvFile() , if you guys encounter the same problem, you should check it out.