Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How To Append To File in C, using Open in O_APPEND Mode on linux?

This is part of a homework assignment. Well, I couldn't get things working in my homework, so I've pulled a snippet out and started toying with it to figure out what's wrong.

On linux in C I'm trying to open/create a text file, write something to it, close it, open it in read/write and append mode, and then append anything to the end of it (in this example, the string ", dude"). Nothing is being appended, though, but the write method is also not throwing an error. I'm not sure what's up.

Here's the code:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>

#define BUFFSIZE 4096

int main(){
    mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;

    int fd = open("tempfile.txt", O_RDWR | O_CREAT, mode);

    char buf[BUFFSIZE] = {'t', 'h', 'y', ' ', 'f', 'a', 'l', 'l'};

    size_t n = sizeof(buf);
    if(write (fd, buf, n) < 0){
        printf("Error in write\n");
        printf("%s", strerror(errno));
        return 1;
    }

    close(fd);

    int fd2 = open("tempfile.txt", O_RDWR | O_APPEND);

    printf("appending dude:\n");
    char buf2[6] = {',', ' ', 'd', 'u', 'd', 'e'};
    size_t p = sizeof(buf2);
    if(write (fd2, buf2, p) < 0){
        printf("Error in write\n");
        printf("%s", strerror(errno));
        return 1;
    }

    char buf3[BUFFSIZE];
    lseek(fd2, 0, SEEK_SET);
    if(read (fd2, buf3, BUFFSIZE) < 0){
        printf("Error in read\n");
        printf("%s", strerror(errno));
        return 2;
    }
    int i;
    for (i = 0; i < strlen(buf3); ++i){
        printf("%c", buf3[i]);
    }
    printf("\n");

    close(fd2);

    return 0;
}

I've tried to eliminate the possibility of it being strictly a permissions issue by messing with a few different combinations, changing the mode variable to S_IRWXU | S_IRWXG | S_IRWXO, passing the mode as a third argument in my second open statement, only opening the file in append mode in the second open statement, passing the append mode as a third argument in the second open statement, etc.

The best I can do is open it in RDWR without the APPEND mode, and then write directly over the existing text... but that's not what I want. And note, I'm aware of things like lseek, but the purpose here is strictly to use the append mode to add text to the end of the file. I don't want to lseek.

Any clues from looking at this? I'm sure there's something obvious I just don't understand.

Many thanks.

like image 703
Deranger Avatar asked Oct 03 '13 05:10

Deranger


People also ask

How do I open a file in append mode in Linux?

You need to use the >> to append text to end of file. It is also useful to redirect and append/add line to end of file on Linux or Unix-like system.

Which flag is used to append the contents in the file in open () system call?

O_APPEND flag forces file pointer to point at the end of file only. so if you do lseek from start of the file, it takes the updated file pointer position as a start of file i.e. end position of old file.

What does the open () return on success?

On success, open(), openat(), and creat() return the new file descriptor (a nonnegative integer). On error, -1 is returned and errno is set to indicate the error.


2 Answers

Well, I just tried your program and have an idea of what is going wrong.

Basically, it does work, but with a glitch. When you first write "thy fall" into the file, you use a char array of 4096 bytes, and you write the entire array into the file. Which means you're writing "thy fall" followed by 4088 characters of random nothing. Later, when you append you're appending at the 4097th position onwards. This is probably not what you intended to do.

If you simply cat the file you create, you will see the expected output "thy fall, dude". But when you read it entirely in your code, you are only reading 4096 characters. Hence, the ", dude" part is never read, which is why your program never outputs it.

My solution, you need to change your array size. And when reading, read in chunks of say 100 or 1000, until you hit EOF (read will return -1).

like image 179
Nikhil Avatar answered Oct 18 '22 05:10

Nikhil


The number of bytes you are trying to write is not correct,

char buf[BUFFSIZE] = {'t', 'h', 'y', ' ', 'f', 'a', 'l', 'l'};
size_t n = sizeof(buf);
if(write (fd, buf, n) < 0){

instead of that you should do

char buf[BUFFSIZE] = {'t', 'h', 'y', ' ', 'f', 'a', 'l', 'l', '\0'};
size_t n = strlen(buf); //use strlen 
if(write (fd, buf, n) < 0){

Similarly, do this for other write and reads as well. If you are not writing '\0' in the file to terminate string, you will not get it when you read data from file.

While reading you should try until entire file is read, ie. you get EOF.

like image 33
Rohan Avatar answered Oct 18 '22 06:10

Rohan