I have a file, partitioned in fixed sized blocks. I am copying a test_file.txt into the 3rd block of the file. I read and copied 18 bytes.
Then I am trying to copy from the file that very same .txt file I just imported to a newly created .txt, but I am writing 256 bytes to the new file. Moreover, when I try to read it, it is full of garbage.
The first function is used to import the .txt and the second one to export it.
void copy_file(int mfs_desc, char* filename, Superblock* s, MDS mds) {
if(mds.size == 0)
return;
char buffer[s->block_size];
int i = 0;
for (; i < s->block_size; ++i) {
buffer[i] = '\0';
}
int source_desc = open(filename, O_RDONLY);
// error handling
if (source_desc == -1) {
perror("opening file in copy file");
exit(1);
}
ssize_t nread;
int total = 0;
off_t seek = lseek(mfs_desc,
sizeof(Superblock) + mds.datablocks[0] * s->block_size,
SEEK_SET);
printf("offset = %d\n", mds.datablocks[0]);
if (seek < 0) {
perror("seek");
exit(1);
}
total = 0;
while ((nread = read(source_desc, buffer, s->block_size)) > 0) {
total += nread;
write(mfs_desc, buffer, s->block_size);
}
printf("read and copied: %d bytes\n", total);
if (close(source_desc) == -1) {
perror("closing file in copy file");
exit(1);
}
}
int copy_file_export(int mfs_desc, char* filename, Superblock s, MDS mds) {
if(mds.size == 0) {
printf("File is empty, abort\n");
return 0;
}
char buffer[s.block_size];
int i = 0;
for (; i < s.block_size; ++i) {
buffer[i] = '\0';
}
int destination_desc = open(filename, O_CREAT | O_WRONLY);
// error handling
if (destination_desc == -1) {
printf("filename = |%s|\n", filename);
perror("opening file in copy file export");
exit(1);
}
ssize_t nread;
int total = 0;
off_t seek = lseek(mfs_desc,
sizeof(Superblock) + mds.datablocks[0] * s.block_size,
SEEK_SET);
printf("offset = %d\n", mds.datablocks[0]);
if (seek < 0) {
perror("seek");
exit(1);
}
for(i = 0; i < mds.size; ++i) {
nread = read(mfs_desc, buffer, s.block_size);
total += nread;
write(destination_desc, buffer, nread);
}
printf("wrote: %d bytes\n", total);
if (close(destination_desc) == -1) {
perror("closing file in copy file");
exit(1);
}
return 1;
}
Output:
import test_file.txt ... / <-- just a command
offset = 2
read and copied: 18 bytes
export test_file.txt ... ../../ <-- just a command
offset = 2
wrote: 256 bytes
What I am doing wrong?
I would replace
write(mfs_desc, buffer, s->block_size);
with
write(mfs_desc, buffer, nread);
In this chunk of code:
while ((nread = read(source_desc, buffer, s->block_size)) > 0) {
total += nread;
write(mfs_desc, buffer, s->block_size);
}
You're very likely handling the last write() incorrectly. You need to write only the bytes you read.
write(mfs_desc, buffer, nread);
Also, these lines are most likely bogus:
char buffer[s->block_size];
char buffer[s.block_size];
You're trying to use a variable sized allocation for an array on the stack. You Can't Do That. Those allocations have to be fixed (compile time constant) sized.
Related
I managed to compile ncat. I am using -k option to keep server open. Instead of accepting data to STDOUT, my goal is to write to files instead. So far I was able to write to a file instead of STDOUT but my goal is to loop through new files on each new connection. Right now it is appending to the same filename_0 and f++ is not incrementing. Here is what I have so far. The original code will be below. The difference is in the else clause, basically if n is actually greater than 0. On each loop, n is 512 bytes until the last chunk. I just want to be able to have new files from each new connection. filename_0, filename_1, filename_3, etc.
MODIFIED CODE:
/* Read from a client socket and write to stdout. Return the number of bytes
read from the socket, or -1 on error. */
int read_socket(int recv_fd)
{
char buf[DEFAULT_TCP_BUF_LEN];
struct fdinfo *fdn;
int nbytes, pending;
int f = 0;
fdn = get_fdinfo(&client_fdlist, recv_fd);
ncat_assert(fdn != NULL);
nbytes = 0;
do {
int n, s;
n = ncat_recv(fdn, buf, 512, &pending);
if (n <= 0) {
if (o.debug)
logdebug("Closing fd %d.\n", recv_fd);
#ifdef HAVE_OPENSSL
if (o.ssl && fdn->ssl) {
if (nbytes == 0)
SSL_shutdown(fdn->ssl);
SSL_free(fdn->ssl);
}
#endif
close(recv_fd);
checked_fd_clr(recv_fd, &master_readfds);
rm_fd(&client_fdlist, recv_fd);
checked_fd_clr(recv_fd, &master_broadcastfds);
rm_fd(&broadcast_fdlist, recv_fd);
conn_inc--;
if (get_conn_count() == 0)
checked_fd_clr(STDIN_FILENO, &master_readfds);
return n;
}
else {
char filename[20];
snprintf(filename, sizeof(char) * 20, "filename_%i", f);
FILE *fp = fopen(filename, "a");
if (fp == NULL)
{
printf("Could not open file");
return 0;
}
//Write(STDOUT_FILENO, buf, n);
s = fwrite(buf, 1, n, fp);
fclose(fp);
f++;
nbytes += n;
}
} while (pending);
return nbytes;
}
ORIGINAL CODE:
int read_socket(int recv_fd)
{
char buf[DEFAULT_TCP_BUF_LEN];
struct fdinfo *fdn;
int nbytes, pending;
fdn = get_fdinfo(&client_fdlist, recv_fd);
ncat_assert(fdn != NULL);
nbytes = 0;
do {
int n;
n = ncat_recv(fdn, buf, sizeof(buf), &pending);
if (n <= 0) {
if (o.debug)
logdebug("Closing fd %d.\n", recv_fd);
#ifdef HAVE_OPENSSL
if (o.ssl && fdn->ssl) {
if (nbytes == 0)
SSL_shutdown(fdn->ssl);
SSL_free(fdn->ssl);
}
#endif
close(recv_fd);
checked_fd_clr(recv_fd, &master_readfds);
rm_fd(&client_fdlist, recv_fd);
checked_fd_clr(recv_fd, &master_broadcastfds);
rm_fd(&broadcast_fdlist, recv_fd);
conn_inc--;
if (get_conn_count() == 0)
checked_fd_clr(STDIN_FILENO, &master_readfds);
return n;
}
else {
Write(STDOUT_FILENO, buf, n);
nbytes += n;
}
} while (pending);
return nbytes;
}
I was able to figure out using the other functions involved. i passed a pointer into this function to write to it. the handler is a function i added the open() file pointer to.
I want to encrypt/decrypt a long file with RSA (I know AES is better, but this is just for a comparison) in openssl/libcrypto. I am splitting the input file into blocks of size numBlocks = inputFileLength/maxlen+1 where maxlen = 200. I can successfully encode and decode in the same loop as follows:
for (int i = 0; i < chunks; i++)
{
int bytesDone = i * maxlen;
int remainingLen = inLength - bytesDone;
int thisLen;
if (remainingLen > maxlen)
{
thisLen = maxlen;
} else
{
thisLen = remainingLen;
}
if((encBytes=RSA_public_encrypt(thisLen, data + bytesDone, encryptdata + bytesDone,
rsa_public, RSA_PKCS1_PADDING)) == -1)
{
printf("error\n");
}
if((decBytes=RSA_private_decrypt(encBytes, encryptdata + bytesDone, decryptdata + bytesDone,
rsa_private, RSA_PKCS1_PADDING)) == -1)
{
printf("error\n");
}
}
However, I want to save the encoded buffer encryptdata in a binary file, reading the binary file back and decryption. I try to do this as follows:
for (int i = 0; i < chunks; i++)
{
int bytesDone = i * maxlen;
int remainingLen = inLength - bytesDone;
int thisLen;
if (remainingLen > maxlen)
{
thisLen = maxlen;
} else
{
thisLen = remainingLen;
}
if((encBytes=RSA_public_encrypt(thisLen, data + bytesDone, encryptdata + bytesDone,
rsa_public, RSA_PKCS1_PADDING)) == -1)
{
printf("error\n");
}
}
writeFile("encoded.bin",encryptdata,strlen(encryptdata));
size_t size;
unsigned char *readData = readFile("encoded.bin", size);
int inputlen = size;
for (int i = 0; (i * keylen) < inputlen; i++) //keylen = 256
{
int bytesDone = i * keylen;
if((decBytes=RSA_private_decrypt(encBytes, readData + bytesDone, decryptdata + bytesDone,
rsa_private, RSA_PKCS1_PADDING)) == -1)
{
printf("error\n");
}
}
printf("Decrypted text: %s",decryptdata);
The readFile and writeFile functions are as follows:
void writeFile(char *filename, unsigned char *file, size_t fileLength
{
FILE *fd = fopen(filename, "wb");
if(fd == NULL) {
fprintf(stderr, "Failed to open file: %s\n", strerror(errno));
exit(1);
}
size_t bytesWritten = fwrite(file, 1, fileLength, fd);
if(bytesWritten != fileLength) {
fprintf(stderr, "Failed to write file\n");
exit(1);
}
fclose(fd);
}
unsigned char* readFile(char *filename, size_t size) {
FILE *fd = fopen(filename, "rb");
if(fd == NULL) {
fprintf(stderr, "Failed to open file: %s\n", strerror(errno));
exit(1);
}
// Determine size of the file
fseek(fd, 0, SEEK_END);
size_t fileLength = ftell(fd);
fseek(fd, 0, SEEK_SET);
size = fileLength;
// Allocate space for the file
unsigned char* buffer = (unsigned char*)malloc(fileLength);
// Read the file into the buffer
size_t bytesRead = fread(buffer, 1, fileLength, fd);
if(bytesRead != fileLength) {
fprintf(stderr, "Error reading file\n");
exit(1);
}
fclose(fd);
return buffer;
}
However, the decryption fails with the error message segmentation fault (core dump) and the decrypt function only returns -1 for every block. Any help will be appreciated.
ReadFile modifies the parameter "size" which is passed by value, thus when the readfile function returns, size is not affected.
I would change readfile proto as follows :
unsigned char* readFile(char *filename, size_t *size)
and then change the call into
unsigned char *readData = readFile("encoded.bin", &size);
and finally modify the readFile size update to
size = fileLength;
Your have various technical errors in your code like doing a strlen(..) on binary data in this statement:
writeFile("encoded.bin",encryptdata,strlen(encryptdata));
encryptdata is binary data that can include 0 that would be interprited as a string termination by strlen(..)
But the main problem is that you try to use RSA as a block cipher. Your encrypted blocks are bigger that what you encrypt, but you don't handle that in your code. You might be able to get your code to handle this, but the right approach is to use ciphers invented for bulk encryption, like AES. When you do that, you automatically get support for 'blocking' out of the box.
In addition to this you get something like a factor 1000 faster encryption.
So this code works ok for small files of up to 20KB but when i try to send or receive larger files it stops reading at some point. Two functions for client and server, to send and receive files. I know it might have some leaks and stuff but I will fix that later. At first I want it to work properly. BUF_SIZE=512
// SENDING BYTES
void send_bytes(int connfd, int client_number, char **command_parts)
{
FILE *fp;
fp = fopen(command_parts[1], "r");
int i = 0;
// FINDING BYTE SIZE OF THE FILE
fseek(fp, 0, SEEK_END); /* PUTTING FILE POINTER TO THE END OF THE FILE */
int num_of_bytes = ftell(fp);
fseek(fp, 0, SEEK_SET); /* RESETTING FILE POINTER TO THE BEGINNING OF THE FILE */
char *sendbuff = malloc(num_of_bytes * sizeof(char));
memset(sendbuff, '\0', num_of_bytes);
// SENDING TOTAL BYTES TO SEND
while (write(connfd, itoa(num_of_bytes), 10) < 0)
{
}
printf("\nClient #%d --> Size of file sent: %d\n", client_number, num_of_bytes);
// IF BYTES MORE THAN 512 SENDING IT IN PARTS
if(num_of_bytes > BUF_SIZE)
{
int bytes_left_to_send = num_of_bytes;
char *tempbuff = calloc(BUF_SIZE, sizeof(char));
while(bytes_left_to_send > 0)
{
if(bytes_left_to_send >= BUF_SIZE)
{
// READING 512 BYTES AND PASSING IT TO TEMPBUFF
for (i = 0; i < BUF_SIZE; i++)
{
fread(&tempbuff[i], 1, 1, fp);
}
// SENDING BYTES
while (write(connfd, tempbuff, BUF_SIZE) < 0)
{
}
bytes_left_to_send = bytes_left_to_send - BUF_SIZE;
memset(tempbuff, '\0', BUF_SIZE);
}
else
{
// READING 512 BYTES AND PASSING IT TO TEMPBUFF
for (i = 0; i < bytes_left_to_send; i++)
{
fread(&tempbuff[i], 1, 1, fp);
}
// SENDING BYTES
while (write(connfd, tempbuff, bytes_left_to_send) < 0)
{
}
bytes_left_to_send = bytes_left_to_send - bytes_left_to_send;
memset(tempbuff, '\0', BUF_SIZE);
}
}
}
else
{
// READING EACH BYTE AND PASSING IT TO SENDBUFF
for (i = 0; i < num_of_bytes; i++)
{
fread(&sendbuff[i], 1, 1, fp);
}
// SENDING BYTES
while (write(connfd, sendbuff, num_of_bytes) < 0)
{
}
}
// FREEING MEMORY
fclose(fp);
free(sendbuff);
printf("\nClient #%d --> File sent\n", client_number);
}
// RECEIVING BYTES
void recv_bytes(int connfd, int client_number, char **command_parts)
{
int bytes_read = 0, bytes_read_in_total = 0, i = 0;
char *num_of_bytes = malloc(10 * sizeof(char));
char *recvbuff = NULL;
FILE *fp;
fp = fopen(command_parts[2], "w");
// RECEIVING BYTES TO RECEIVE
while (read(connfd, num_of_bytes, 10) < 0)
{
}
printf("\nClient #%d --> Size of file received: %d\n", client_number, atoi(num_of_bytes));
recvbuff = malloc(atoi(num_of_bytes) * sizeof(char)); /* ALLOCATING recvbuff WITH RECEIVED SIZE */
memset(recvbuff, '\0', atoi(num_of_bytes));
// IF BYTES MORE THAN 512 RECEIVING IT IN PARTS
if(atoi(num_of_bytes) > BUF_SIZE)
{
int bytes_left_to_read = atoi(num_of_bytes);
char *tempbuff = calloc(BUF_SIZE, sizeof(char));
while(bytes_left_to_read > 0)
{
if(bytes_left_to_read >= BUF_SIZE)
{
// READING BYTES
while (bytes_read = read(connfd, tempbuff, BUF_SIZE) < 0)
{
}
bytes_read = strlen(tempbuff);
// WRITING BYTES READ SO FAR TO THE FILE
for (i = 0; i < bytes_read; i++)
{
fwrite(&tempbuff[i], 1, 1, fp);
}
bytes_left_to_read = bytes_left_to_read - bytes_read;
memset(tempbuff, '\0', BUF_SIZE);
}
else
{
// READING BYTES
while (bytes_read = read(connfd, tempbuff, bytes_left_to_read) < 0)
{
}
bytes_read = strlen(tempbuff);
// WRITING BYTES READ SO FAR TO THE FILE
for (i = 0; i < bytes_read; i++)
{
fwrite(&tempbuff[i], 1, 1, fp);
}
bytes_left_to_read = bytes_left_to_read - bytes_read;
memset(tempbuff, '\0', BUF_SIZE);
}
}
}
else
{
// RECEIVING BYTES
while (bytes_read_in_total < atoi(num_of_bytes))
{
while (bytes_read = read(connfd, recvbuff, atoi(num_of_bytes)) < 0)
{
}
bytes_read = strlen(recvbuff);
bytes_read_in_total = bytes_read_in_total + bytes_read;
// WRITING BYTES READ SO FAR TO THE FILE
for (i = 0; i < bytes_read; i++)
{
fwrite(&recvbuff[i], 1, 1, fp);
}
memset(recvbuff, '\0', atoi(num_of_bytes));
}
}
free(recvbuff);
fclose(fp);
printf("\nClient #%d --> File received\n", client_number);
}
I am new in this field, and writing one server and client, but it really confusing that I can't get all the content, but some small clip.
My server code:
read(connfd, name, 20);
//recv(connfd,name,1024,0);
char* a=name;
while(a[0]!='\n'){
a++;
}
a[0]='\0';
printf("name:%s\n", name);
read(connfd, size, 20);
printf("size:%s\n", size);
recv(connfd,buf,8192,0);
printf("buf:%s\n", buf);
if((stream = fopen(name,"w+t"))==NULL){
printf("The file was not opened! \n");
}
int write_length = fwrite(buf,sizeof(char),8192,stream);
bzero(buf,8192);
if(put){
char *res="OK\n";
write(connfd, res, 1024);
}
fclose(stream);
and my client code is:
char buffer[8192];
bzero(buffer,8192);
char * put="PUT\n";
if ((write(fd, put, 8192)) <= 0) {
if (errno != EINTR) {
fprintf(stderr, "Write error: %s\n", strerror(errno));
exit(0);
}
}
struct stat st ;
stat( put_name, &st );
char str[100];
sprintf(str, "%d", st.st_size);
int len;
char *current=NULL;
len=strlen(put_name);
char sendname[1024];
strcpy(sendname,put_name);
strcat(sendname,"\n");
write(fd, sendname, 10);
strcat(str,"\n");
write(fd, str, 10);
FILE *stream;
if((stream = fopen(put_name,"r"))==NULL)
{
printf("The file was not opened! \n");
exit(1);
}
int lengsize = 0;
while((lengsize = fread(buffer,1,8192,stream)) > 0){
if(send(fd,buffer,8192,0)<0){
printf("Send File is Failed\n");
break;
}
bzero(buffer, 8192);
}
Now, I can send all content, but can receive part of them. for example, on my mac, server can receive name but the str is neglected, when I printf the str in the server, it shows the content of file. and the content of file is not the whole file content. Some content disappear. Could you tell me why?
The read and write functions are not guaranteed to send or receive the entire message with a single call. Instead, you're expected to sit in a loop, writing the message incrementally until everything has been sent and reading everything incrementally until everything has been read. For example, if you know exactly how much has been sent, you can do this:
char recvBuffer[BUFFER_SIZE];
int bytesRead = 0;
while (bytesRead < BUFFER_SIZE) {
int readThisTime = read(file, recvBuffer + bytesRead, BUFFER_SIZE - bytesRead);
if (readThisTime == -1) {
// handle error...
}
bytesRead += readThisTime;
}
If you don't know exactly how much has been sent, try this:
char recvBuffer[BUFFER_SIZE];
int bytesRead = 0;
while (bytesRead < BUFFER_SIZE) {
int readThisTime = read(file, recvBuffer + bytesRead, BUFFER_SIZE - bytesRead);
if (readThisTime == -1) {
// handle error...
}
if (readThisTime == 0) break; // Done!
bytesRead += readThisTime;
}
You are ignoring the return values of send() and recv(). You MUST check return values!
When sending the file, lengsize receives how many bytes were actually read from the file. Your client is sending too many bytes when lengsize is < 8192 (typically the last block of the file if the file size is not an even multiple of 8192).
But more importantly, although the client is telling the server the file size, the server is ignoring it to know when to stop reading. The server is also ignoring the return value of recv() to know how many bytes were actually received so it knows how many bytes can safely be written to the output file.
Try something more like this instead:
common:
int readData(int s, void *buf, int buflen)
{
int total = 0;
char *pbuf = (char*) buf;
while (buflen > 0) {
int numread = recv(s, pbuf, buflen, 0);
if (numread <= 0) return numread;
pbuf += numread;
buflen -= numread;
total += numread;
}
return total;
}
int sendData(int s, void *buf, int buflen)
{
int total = 0;
char *pbuf = (char*) buf;
while (buflen > 0) {
int numsent = send(s, pbuf, buflen, 0);
if (numsent <= 0) return numsent;
pbuf += numsent;
buflen -= numsent;
total += numsent;
}
return total;
}
int readInt32(int s, int32_t *value)
{
int res = readData(s, value, sizeof(*value));
if (res > 0) *value = ntohl(*value);
return res;
}
int sendInt32(int s, int32_t value)
{
value = htonl(value);
return sendData(s, &value, sizeof(value));
}
char* readStr(int s)
{
int32_t size;
if (readInt32(s, &size) <= 0)
return NULL;
char *str = malloc(size+1);
if (!str)
return NULL;
if (readData(s, str, size) <= 0) {
free(str);
return NULL;
}
str[size] = '\0';
return str;
}
int sendStr(int s, const char *str)
{
int len = strlen(str);
int res = sendInt32(s, len);
if (res > 0)
res = sendData(s, str, len);
return res;
}
server:
char buffer[8192];
char *name = readStr(connfd);
if (!name) {
// error handling ...
sendStr(connfd, "Socket read error");
return;
}
printf("name:%s\n", name);
int32_t filesize;
if (readInt32(connfd, &filesize) <= 0) {
// error handling ...
free(name);
sendStr(connfd, "Socket read error");
return;
}
printf("size:%d\n", filesize);
if ((stream = fopen(name, "wb")) == NULL) {
// error handling ...
printf("The file was not opened!\n");
free(name);
sendStr(connfd, "File not opened");
return;
}
while (filesize > 0) {
int numread = readData(connfd, buf, min(filesize, sizeof(buffer)));
if (numread <= 0) {
// error handling ...
close(stream);
free(name);
sendStr(connfd, "Socket read error");
return;
}
printf("buf:%.*s\n", numread, buf);
if (fwrite(buf, 1, numread, stream) != numread) {
// error handling ...
close(stream);
free(name);
sendStr(connfd, "File write error");
return;
}
filesize -= numread;
}
fclose(stream);
free(name);
sendStr(connfd, "OK");
client:
char buffer[8192];
struct stat st;
if (stat( put_name, &st ) != 0) {
// error handling ...
exit(0);
}
if ((stream = fopen(put_name, "rb")) == NULL) {
// error handling ...
printf("The file was not opened!\n");
exit(0);
}
if (sendStr(fd, put_name) <= 0) {
// error handling ...
close(stream);
exit(0);
}
int32_t filesize = st.st_size;
if (sendInt32(fd, filesize) <= 0) {
// error handling ...
close(stream);
exit(0);
}
int lengsize;
while (filesize > 0) {
lengsize = fread(buffer, 1, min(filesize , sizeof(buffer)), stream);
if (lengsize <= 0) {
printf("Read File Failed\n");
// error handling ...
close(stream);
exit(0);
}
if (sendData(fd, buffer, lengsize) <= 0) {
printf("Send File Failed\n");
// error handling ...
close(stream);
exit(0);
}
filesize -= lengsize;
}
close(stream);
char *resp = readStr(fd);
if (!resp) {
// error handling ...
exit(0);
}
if (strcmp(resp, "OK") == 0)
printf("Send File OK\n");
else
printf("Send File Failed: %s\n", resp);
free(resp);
I read xml file with tlv format, xml file has 593 byte, i reading the below code. Fırst 512 byte is true, but the remaining bytes is false. I read the remainder byte is 00.
int fd,ret;
unsigned char *filebuffer[6400];
fd = open("filename" , O_RDONLY);
printf("file open return value : %d \n", fd);
if (fd == -1)
{
printf("Error in openning the file!\n");
exit(0);
}
//read the file
int i = 0;
do {
ret = read(fd,&filebuffer[i],512);
printf("file read return value : %d \n", ret);
if (ret == -1)
{
printf("Error in reading!\n");
exit(0);
}
i += ret;
printf("i = %d, ret = %d",i,ret);
} while (ret > 0);
int k;
char tmp[6400];
memcpy(tmp,filebuffer,i);
printf("file buffer\n");
for (k = 0; k < i; ++k) {
printf("%02x",tmp[i]);
}
close(fd);}
I filling the filebuffer with i'm reading xml file.
filebuffer example; filebuffer : 1F0583212 ..... (512 byte) 000000
The definition for filebuffer is incorrect. Change it to:
unsigned char filebuffer[6400];