Why does open() create my file with the wrong permissions?

102,178

Solution 1

open() takes a third argument which is the set of permissions, i.e.

open(filename, O_RDWR|O_CREAT, 0666)

0666 is an octal number, i.e. every one of the 6's corresponds to three permission bits

6 = rw

7 = rwx

first three bits for owner permission, next three bits for group permission and next is for the world the first digit - represents that is file or directory. (0 - file, d - directory) here we used 0 means file

It's a typical pitfall. The compiler allows you to leave the permission argument away because when you open an existing file the permission bits don't make sense. But when you forget the argument when you create a file, you get a random set of permissions, e.g. 0000 in your case (---).

Solution 2

Reading http://linux.die.net/man/2/open it seems you missed the mode parameter for open:

mode must be specified when O_CREAT is in the flags, and is ignored otherwise. The argument mode specifies the permissions to use in case a new file is created.

Solution 3

This question recently helped me out, so I wanted to do my part to add a bit more depth as to what's going on. Like it was stated before, you were missing the third argument to open(). However, the permissions you see aren't random; they're coming from the stack. Look at the following code snippet:

    asm("push $0");
    asm("push $0");
    asm("push $0");
    fd = open("base", O_RDWR|O_CREAT);

Note the following result:

    ----------. 1 user user 4 Feb 26 08:21 base

Let's change the first push to 1, i.e. execute permission:

    asm("push $1;push $0;push $0");
    fd = open("base", O_RDWR|O_CREAT);

and we get:

    ---------x. 1 user user 4 Feb 26 08:25 base

Change the push to 4, i.e. read permission, and mess with the other two values:

    asm("push $4;push $5;push $6");
    fd = open("base", O_RDWR|O_CREAT);

and we get:

    -------r--. 1 user user 4 Feb 26 08:27 base

Thus we can see the third value popped off the stack (first pushed) is what really matters. Finally for fun we can try 5 and then 50, which respectively result in:

    -------r-x. 1 user user 4 Feb 26 08:27 base
    ----rw----. 1 user user 4 Feb 26 08:28 base

Hope this adds some clarity!

Solution 4

Actually umask() only filters permissions and does not set them. The typical umask() value is 0002 ("don't give away write permission to the world") and if your mode value in the open( "file", O_CREAT, 0777) gave all permissions, the resulting file would have 775 as its permssions.

Solution 5

This is kind of an old thread, but I think people should be aware of the "sys/stat.h" library. This includes a bunch of symbolic constants for setting permission bits.

For example: To open a file with Read/Write permissions enabled for the user

#include <fcntl.h>
#include <sys/stat.h>

open("Your/File/Path", O_RDWR | O_CREAT, S_IWUSR | S_IRUSR);

where:

S_IWUSR // Sets the Users Write bit
S_IRUSR // Sets the Users Read bit

This library includes a bunch of others, I won't list them all here but you can read up on it all here.

Of course you can put in the octal values to set these bits, however some may argue that it is poor coding practice.

Share:
102,178
Chaitanya
Author by

Chaitanya

Updated on December 03, 2020

Comments

  • Chaitanya
    Chaitanya over 3 years

    I am trying to read some text from a file and write it to another using open(), read() and write().

    This is my open() for the file-to-write-to (I want to create a new file and write into it):

    fOut = open ("test-1", O_RDWR | O_CREAT | O_SYNC);
    

    This is setting file-permissions to something I don't understand at all. This is the output of ls -l:

    ---------T 1 chaitanya chaitanya 0 2010-02-11 09:38 test-1
    

    Even the read permission is locked. I tried searching for this, but could not find ANYTHING. Strangely, write() still successfully writes data to the file.

    Also, if I do a 'chmod 777 test-1', things start working properly again.

    Could someone please let me know where I am going wrong in my open call?

    Thanks!

    For your reference, I have pasted the complete program below:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    
    int main () {
    
        char buffer[512], ch;
    
        int fIn, fOut, i;
        ssize_t bytes;
        FILE *fp = NULL;
    
        //open a file
        fIn = open ("test", O_RDONLY);
        if (fIn == -1) {
            printf("\nfailed to open file.");
            return 1;
        }
    
        //read from file
        bytes =  read (fIn, buffer, sizeof(buffer));
        //and close it
        close (fIn);
    
        printf("\nSuccessfully read %d bytes.\n", bytes);
    
        //Create a new file
        fOut = open ("test-1", O_RDWR | O_CREAT | O_SYNC);
    
        printf("\nThese are the permissions for test-1\n");
        fflush(stdout);
        system("ls -l test-1");
    
        //write to it and close it.
        write (fOut, buffer, bytes);
        close (fOut);
    
    
        //write is somehow locking even the read permission to the file. Change it.
        system("chmod 777 test-1");
    
        fp = fopen ("test-1", "r");
        if (fp == NULL) {
            printf("\nCan't open test-1");
            return 1;
        }
    
        while (1)
        {
            ch = fgetc(fp);
            if (ch == EOF)
                break;
            printf("\n%c", ch);
        }
    
        fclose (fp);
    
        return 0;
    }
    
    • Jonathan Leffler
      Jonathan Leffler about 14 years
      You probably don't need 777 permission; you probably only need 666 at most, and usually you don't want public write permission either. You don't want people executing your data files.
  • Sam Post
    Sam Post about 14 years
    For completeness, octal 4 = r
  • Jonathan Leffler
    Jonathan Leffler about 14 years
    @Adam Liss: hex 4 = octal 4. Octal is convenient for permissions because each group of 3 bits makes up a unit of permissions and an octal digit. 0644 = 0x1A4, but it is a lot easier to see the permissions in the octal notation than it is in hexadecimal. (Partly experience, but mainly the appropriate grouping of bits).
  • Jay Conrod
    Jay Conrod about 14 years
    0666 is usually a good setting, even if you don't intend for "other" to be able to write to it. umask is usually set to 0022, which removes write permissions for everyone except the owner.
  • Alexey
    Alexey about 6 years
    it’s worth pointing that umask out have has effect on the whole process and thus poses a risk for race conditions in a multithreaded program
  • Bhupesh Pant
    Bhupesh Pant about 6 years
    I think what you are saying is general subjective stuff and the question is that even after setting the permission we cannot see permission bits set. This holds true for both stdlb api or system apis.
  • Meevs
    Meevs about 6 years
    @BhupeshPant The question asks why the permission bits of the file are being set to "---------T 1 chaitanya chaitanya 0 2010-02-11 09:38 test-1" That is, why does the file have no permission bits set. In his open call, ie.) "fOut = open ("test-1", O_RDWR | O_CREAT | O_SYNC);" He has the O_CREAT flag, which will create the file "test-1" if it does not exist. Assuming this is the case, (that the file is being created at the open call), he must also specify the permission bits to be associated with the file. He corrects this later in his code with the system call to chmod.
  • Billy
    Billy almost 6 years
    Sorry what do you mean by making C use that version of open? From the man page: "This argument must be supplied when O_CREAT is specified in flags; if O_CREAT is not specified, then mode is ignored. The effective permissions are modified by the process's umask in the usual way: The permissions of the created file are (mode & ~umask)." Arguments are passed on the stack; by using inline assembly to manually set up the stack, we can demonstrate where the seemingly "random" permissions are coming from.
  • PyWalker2797
    PyWalker2797 about 4 years
    I don't understand how the last argument is obtained, this is not on the man pages?