1

The program I wrote gets the size of one file, reads partSize amount of bytes from that file and writes partSize amount of bytes to a newly created file. The problem is that it only works for small text files. If I try to run the program with text file of a few hundred lines or a picture I get a segmentation fault and significantly less than partSize bytes are stored to the new file.

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h> 
#include <sys/types.h> 
#include <errno.h>

int main()
{
    int createDescriptor;
    int openDescriptorOriginal;
    int closeCreateDescriptor;

    //   char fileNameOriginal[] = "picture.jpg";
    char fileNameOriginal[] = "myFile.txt";

    int parts;
    int partSize;

    parts=2;

    int bytesRemaining;
    int partNumber;
    char BUFFER[512];
    int readDescriptor;

    int buffer[1];
    oid *pbuffer = &buffer;

    int bytes, infile, outfile;

    if ((openDescriptorOriginal = open(fileNameOriginal, O_RDONLY )) == -1)
    {
        printf("Error opening %s", fileNameOriginal);
        exit(EXIT_FAILURE);
    }

    struct stat buf;
    int r = fstat(openDescriptorOriginal, &buf);
    if (r)
    {
        fprintf(stderr, "error: fstat: %s\n", (char *) strerror(errno));
        exit(1);
    }

    int originalFileSize = buf.st_size;
    printf("The file is %.9f bytes large.\n",(double)originalFileSize);

    partSize = ((originalFileSize + parts) - 1)/parts;
    printf("Part size: %.9f bytes large\n",(double)partSize);
    umask(0000);
    //create and open new file
    if ( (outfile = open("NewPicture.jpg", O_CREAT|O_WRONLY,0777))==-1 ) 
    {
        printf("ERROR %s\n", "NewPicture.jpg");
    }

    ssize_t count, total;
    total = 0;
    char *bufff = BUFFER;
    while (partSize) {
        count = read(openDescriptorOriginal, bufff, partSize);
        if (count < 0) {
            break;
        }
        if (count == 0)
            break;
        bufff += count;
        total += count;
        partSize -= count;

    }

    write (outfile, BUFFER, total);
    printf("\n");

    return 0;

}
louxiu
  • 2,651
  • 3
  • 24
  • 37
John
  • 25
  • 4

4 Answers4

2

You are using buffer with 512 bytes only.

BUFFER[512];

if the content in that file goes beyond this limit seg fault will occurs.

Jeyaram
  • 8,315
  • 5
  • 35
  • 59
1

count = read(openDescriptorOriginal, bufff, partSize); In this line 3rd argument is wrong,

In your code you have defined char BUFFER[512]; use BUFFER to read from file just 511 bytes at a time.

count = read(openDescriptorOriginal, BUFFER, 512);      

Reason why not working with big likes:
If partSize > then 512 then there may be buffer overrun(buffer overflow) happen. that's why your does not work for large files. Because the read() function shall attempt to read partSize bytes from the file associated with the open file descriptor openDescriptorOriginal, fildes, into the buffer pointed to by BUFFER that is just of 512 bytes long. This buffer overrun is cause of segmentation fault in your program.

If file size is small then code will work.


I have corrected your code some extend:

ssize_t count=0, total=0;
total = 0;
char *bufff = calloc(partSize+1, sizeof(char));
char *b = bufff;
while (partSize > 0) {
    count = read(openDescriptorOriginal, b, 512);

    if (count < 0) {
        break;
    }
    if (count == 0)
        break;
    b = b + count;
    total = total + count;
    partSize = partSize - count; 

}
write (outfile, bufff, total);
close(openDescriptorOriginal);
close(outfile);
Grijesh Chauhan
  • 52,958
  • 19
  • 127
  • 190
  • If the buffer size is 512, there's no need to use a value other than 512 in the read. In general, you should use `sizeof(buffer)` (upper-case names should be reserved for macros and constants) when the variable is a local variable. When the buffer is passed as a parameter to the function, a size should be passed too: `function(..., char *buffer, size_t buflen, ...)` and you use the passed buffer length. The only occasion for using a shorter length is if you are going to null terminate the string; for copying from one file to another, null termination is irrelevant. – Jonathan Leffler Jan 03 '13 at 07:31
  • What does this do: BUFFER[count]=0; – John Jan 03 '13 at 07:31
  • It null terminates the 'string'. – Jonathan Leffler Jan 03 '13 at 07:32
  • @John to add `\0` at the end of buffer string. – Grijesh Chauhan Jan 03 '13 at 07:33
  • @JonathanLeffler are your sure? because I am not. – Grijesh Chauhan Jan 03 '13 at 07:35
  • So these two lines are together: `count = read(openDescriptorOriginal, BUFFER, 511);` `BUFFER[count]='\0';` correct? or do I put the second one somewhere else? – John Jan 03 '13 at 07:36
  • I just tried the program on a picture of jpg format and 740 664 bytes in size, it created a new file 8192 bytes in size. no segmentation fault though – John Jan 03 '13 at 07:39
  • @John there may be other reason for that I written for segmentation fault. – Grijesh Chauhan Jan 03 '13 at 07:41
  • I see, thanks for the help. Should I post a new question then? – John Jan 03 '13 at 07:47
  • @GrijeshChauhan You found the segmentation fault error you mean? Or you found the error to why the program doesn't create a file partSize bytes large? – John Jan 03 '13 at 07:55
  • @John copies `bufff += count;` then read in bufff. that is also a problem, Do you wan to copy file? – Grijesh Chauhan Jan 03 '13 at 07:59
  • @GrijeshChauhan yes I would like to copy partSize bytes of original file to new file – John Jan 03 '13 at 08:02
1

Your buffer is too small. You need a larger buffer variable. If your file size is more than 512 bytes you will have segfault.

Ideally, you should read from the file in fixed chunks. That is, read maybe 30-40 or a constant number of characters in every read and then write it to the new file. Repeat until the complete file has been read.

asheeshr
  • 3,918
  • 5
  • 30
  • 49
  • How large should I make it? – John Jan 03 '13 at 07:08
  • Any convenient size. I often use a buffer size of 4096 bytes. You simply create a loop which reads up to a buffer full of bytes, and then writes as many bytes as were just read. For example, see [File Chunking and Buffering](http://stackoverflow.com/a/14107038/15168) and [Clearest way to read and print .txt files in C](http://stackoverflow.com/q/14062910/15168). – Jonathan Leffler Jan 03 '13 at 07:25
0

this here makes no sense

partSize = ((originalFileSize + parts) - 1)/parts;

you have initialized parts to two then you add two to the original file size and subtract one and then divide with two again even though at the end of the day your buffer size is 512?

what you need to do is to use the buffer size when reading from the file and checking how many bytes were actually read, this value you subtract from the original file size, repeat until the actual read bytes is smaller than buffer size and/or when original file size is 0.

also it would probably be better if you use file buffered I/O i.e. fopen/fread/fwrite/fclose - if you do not have any special reason why you want to use unbuffered I/O.

AndersK
  • 33,910
  • 6
  • 56
  • 81