Added support for handling binary files.
The problem was I was using XDR strings for reading data, storing it
and transferring to the client from the server. But since this is no
better than null-terminated string, whenever data had \000 the data
used to become corrupt from that point. So now I changed all data to
be integer arrays so there is no question of corruption.
#include <rpc/rpc.h>
#include <stdio.h>
#include <string.h>
#include "ftp.h"
extern __thread int errno;
/*
* Gets the requested file from the server by calling the
* remote procedure in a loop
*/
int get_file(char *host, char *name)
{
CLIENT *clnt;
int bytes = 0, write_items;
readfile_res *result;
request req;
FILE *file;
/*
* Initialize the request with the file name
*/
req.name = name;
/*
* Create client handle used for calling FTPPROG on
* the server designated on the command line. Use
* the tcp protocol when contacting the server.
*/
clnt = clnt_create(host, FTPPROG, FTPVER, "tcp");
if (clnt == NULL) {
/*
* Couldn't establish connection with server.
* Print error message and stop.
*/
clnt_pcreateerror(host);
exit(1);
}
/*
* Open the file for writing on the client machine
*/
file = fopen(name, "wb");
/*
* Call the remote procedure retrieve_file on the server.
* During each iteration of the loop remote procedure is
* called and only 1024 bytes of data is read and returned
* by the server. The loop terminates when the data returned
* from the server is less than 1024 bytes
*/
while (1) {
/*
* Specifies the byte position where the next read should be
* started in the server.
*/
req.start = bytes;
result = retrieve_file_1(&req, clnt);
if (result == NULL) {
/*
* An RPC error occurred while calling the server.
* Print error message and stop.
*/
clnt_perror(clnt, host);
exit(1);
}
/*
* We successfully called the remote procedure.
*/
if (result->errno != 0) {
/*
* A remote system error occurred.
* Print error message and stop.
*/
errno = result->errno;
perror(name);
exit(1);
}
/*
* Successfully got a chunk of the file.
* Write into our local file and update the
* total bytes of data read till now.
*/
write_items = fwrite(result->readfile_res_u.chunk.data, sizeof(int), result->readfile_res_u.chunk.items, file);
bytes += result->readfile_res_u.chunk.items * (sizeof(int));
if (result->readfile_res_u.chunk.items < MAXLEN)
break;
}
fclose(file);
return 0;
}
/*
* Stores the file on the server by calling the remote
* procedure in a loop
*/
int put_file(char *host, char *name)
{
CLIENT *clnt;
int *result;
filechunk data;
chunksend chunk;
FILE *file;
/*
* Create client handle used for calling FTPPROG on
* the server designated on the command line. Use
* the tcp protocol when contacting the server.
*/
clnt = clnt_create(host, FTPPROG, FTPVER, "tcp");
if (clnt == NULL) {
/*
* Couldn't establish connection with server.
* Print error message and stop.
*/
clnt_pcreateerror(host);
exit(1);
}
/*
* Open the file that should be stored on the server
*/
file = fopen(name, "rb");
/*
* Initialize the chunk to be sent with the name
* of the file
*/
chunk.name = name;
/*
* Call the remote procedure readdir on the server
* in a loop sending only 1024 bytes of data in each
* iteration. The loop terminates once the data less
* than 1024 bytes is sent.
*/
while (1) {
chunk.items = fread(chunk.data, sizeof(int), MAXLEN, file);
result = send_file_1(&chunk, clnt);
if (result == NULL) {
/*
* An RPC error occurred while calling the server.
* Print error message and stop.
*/
clnt_perror(clnt, host);
exit(1);
}
/*
* Okay, we successfully called the remote procedure.
*/
if (*result != 0) {
/*
* A remote system error occurred.
* Print error message and stop.
*/
errno = *result;
perror(name);
exit(1);
}
/*
* Successfully got a chunk of the file.
* Write into our local file.
*/
if (chunk.items < MAXLEN)
break;
}
fclose(file);
return 0;
}
/*
* Handles commands read on the command line and calls
* the appropriate function to handle the command
*/
int read_command(char *host)
{
char command[MAXLEN];
printf("> ");
fflush(stdin);
gets(command);
if (strncmp(command, "get", 3) == 0) {
return get_file(host, command+4);
} else if(strncmp(command, "put", 3) == 0){
return put_file(host, command+4);
} else if(strncmp(command, "exit", 4) == 0){
exit(0);
} else {
return -1;
}
}
int main(int argc, char *argv[])
{
int result;
if (argc != 2) {
fprintf(stderr, "usage: %s host\n", argv[0]);
exit(1);
}
/*
* Command handling loop
*/
while(TRUE) {
result = read_command(argv[1]);
}
return 0;
}