Creating a File “in the Raw” – with Permissions

Way back in April, I concluded my series on the “raw” file functions with a program that created a new file — but one that had no permissions. Thanks to input from readers and research into file-permission functions, I have a solution to the puzzle.

In an earlier post, I wrote about the open() function, documenting it like this:

int open(const char *path, int oflag, ...);

This format is exactly how open() is presented on its man page. I didn’t explain the ... argument because its man page description is cryptic:

The oflag argument may indicate that the file is to be created if it does not exist (by specifying the O_CREAT flag). In this case, open() and openat() require an additional argument mode_t mode; the file is created with mode mode as described in chmod(2) and modified by the process’ umask value (see umask(2)).

I researched into umask() and chmod(), but never made the connection that the third argument consists of permission flags required when a new file is created.

Worse: A problem presented itself only in OS X where the newly-created file had no permissions whatsoever. Other platforms didn’t show this issue.

Regardless, now I know and can share that the mystery third argument in the open() function represents file permissions. The code below updates my original file-creation program, adding the proper permission bits to the freshly-minted file.

2020_05_16-Lesson.c

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    char filename[] = "file_output.txt";
    char text[] = "What a lovely little file\n";
    int fdes,r;

    /* open the file for writing and creating */
    fdes = open(filename,O_WRONLY|O_CREAT,S_IRUSR+S_IWUSR+S_IRGRP+S_IROTH);
    if( fdes==-1 )
    {
        fprintf(stderr,"Unable to create %s\n",filename);
        return(1);
    }

    /* write the buffer */
    r = write( fdes, text, sizeof(text)-1 );
    if( r != sizeof(text)-1 )
    {
        fprintf(stderr,"Some kind of file writing error\n");
    }
    /* confirm success */
    printf("Data written to %s\n",filename);

    /* close 'er up */
    close(fdes);

    return(0);
}

The sole modification takes place at Line 12. Here’s how it looks in the original code:

fdes = open(filename,O_WRONLY|O_CREAT);

And the updated version above, the only change to the code:

fdes = open(filename,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);

The four constants are:

S_IRUSR owner read permission
S_IWUSR owner write permission
S_IRGRP group (wheel) read permission
S_IROTH other read permission

Each is logically OR’d with each other to cumulatively generate the proper permissions.

And the code works! Unlike the original attempt, the file is created, data output, and the file is blessed with the proper permissions to make it accessible.

Even if the third argument to the open() function remained a mystery to you, it’s possible to use the chmod() function to alter the file’s permissions, as was covered in last week’s Lesson. Thankfully, this redundant step can be omitted.

Leave a Reply