Opening a File: open()

The open() system call either opens an existing file or creates and opens a new file.

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

int open(const char *pathname, int flags, ... /* mode_t mode */);

Note

Returns file descriptor on success, or -1 on error

The file to be opened is identified by the pathname argument. If pathname is a symbolic link, it is dereferenced. On success, open() returns a file descriptor that is used to refer to the file in subsequent system calls. If an error occurs, open() returns -1 and errno is set accordingly.

The flags argument is a bit mask that specifies the access mode for the file, using one of the constants shown in Table 4-2.

Note

Early UNIX implementations used the numbers 0, 1, and 2 instead of the names shown in Table 4-2. Most modern UNIX implementations define these constants to have those values. Thus, we can see that O_RDWR is not equivalent to O_RDONLY | O_WRONLY; the latter combination is a logical error.

When open() is used to create a new file, the mode bit-mask argument specifies the permissions to be placed on the file. (The mode_t data type used to type mode is an integer type specified in SUSv3.) If the open() call doesn’t specify O_CREAT, mode can be omitted.

Table 4-2. File access modes

Access mode

Description

O_RDONLY

Open the file for reading only

O_WRONLY

Open the file for writing only

O_RDWR

Open the file for both reading and writing

We describe file permissions in detail in Section 15.4. Later, we’ll see that the permissions actually placed on a new file depend not just on the mode argument, but also on the process umask (The Process File Mode Creation Mask: umask()) and the (optionally present) default access control list (Default ACLs and File Creation) of the parent directory. In the meantime, we’ll just note that the mode argument can be specified as a number (typically in octal) or, preferably, by ORing (|) together zero or more of the bit-mask constants listed in Table 15-4, in File Permissions.

Example 4-2 shows examples of the use of open(), some of which employ additional flags bits that we describe shortly.

Example 4-2. Examples of the use of open()

/* Open existing file for reading */

    fd = open("startup", O_RDONLY);
    if (fd == -1)
        errExit("open");

    /* Open new or existing file for reading and writing, truncating to zero
       bytes; file permissions read+write for owner, nothing for all others */

    fd = open("myfile", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
    if (fd == -1)
        errExit("open");

    /* Open new or existing file for writing; writes should always
       append to end of file */

    fd = open("w.log", O_WRONLY | O_CREAT | O_TRUNC | O_APPEND,
                       S_IRUSR | S_IWUSR);
    if (fd == -1)
        errExit("open");

In some of the example open() calls shown in Example 4-2, we included other bits (O_CREAT, O_TRUNC, and O_APPEND) in flags in addition to the file access mode. We now consider the flags argument in more detail. Table 4-3 summarizes the full set of constants that can be bit-wise ORed (|) in flags. The final column indicates which of these constants are standardized in SUSv3 or SUSv4.

The constants in Table 4-3 are divided into the following groups:

  • File access mode flags: These are the O_RDONLY, O_WRONLY, and O_RDWR flags described earlier. Only one of these values should be specified in flags. The access mode can be retrieved using the fcntl() F_GETFL operation (Open File Status Flags).

  • File creation flags: These are the flags shown in the second part of Table 4-3. They control various aspects of the behavior of the open() call, as well as options for subsequent I/O operations. These flags can’t be retrieved or changed.

  • Open file status flags: These are the remaining flags in Table 4-3. They can be retrieved and modified using the fcntl() F_GETFL and F_SETFL operations (Open File Status Flags). These flags are sometimes simply called the file status flags.

    Note

    Since kernel 2.6.22, the Linux-specific files in the directory /proc/PID/fdinfo can be read to obtain information about the file descriptors of any process on the system. There is one file in this directory for each of the process’s open file descriptors, with a name that matches the number of the descriptor. The pos field in this file shows the current file offset (Changing the File Offset: lseek()). The flags field is an octal number that shows the file access mode flags and open file status flags. (To decode this number, we need to look at the numeric values of these flags in the C library header files.)

Details for the flags constants are as follows:

O_APPEND

Writes are always appended to the end of the file. We discuss the significance of this flag in Section 5.1.

O_ASYNC

Generate a signal when I/O becomes possible on the file descriptor returned by open(). This feature, termed signal-driven I/O, is available only for certain file types, such as terminals, FIFOs, and sockets. (The O_ASYNC flag is not specified in SUSv3; however, it, or the older synonym, FASYNC, is found on most UNIX implementations.) On Linux, specifying the O_ASYNC flag when calling open() has no effect. To enable signal-driven I/O, we must instead set this flag using the fcntl() F_SETFL operation (Open File Status Flags). (Several other UNIX implementations behave similarly.) Refer to Signal-Driven I/O for more information about the O_ASYNC flag.

O_CLOEXEC (since Linux 2.6.23)

Enable the close-on-exec flag (FD_CLOEXEC) for the new file descriptor. We describe the FD_CLOEXEC flag in Section 27.4. Using the O_CLOEXEC flag allows a program to avoid additional fcntl() F_GETFD and F_SETFD operations to set the close-on-exec flag. It is also necessary in multithreaded programs to avoid the race conditions that could occur using the latter technique. These races can occur when one thread opens a file descriptor and then tries to mark it close-on-exec at the same time as another thread does a fork() and then an exec() of an arbitrary program. (Suppose that the second thread manages to both fork() and exec() between the time the first thread opens the file descriptor and uses fcntl() to set the close-on-exec flag.) Such races could result in open file descriptors being unintentionally passed to unsafe programs. (We say more about race conditions in Section 5.1.)

O_CREAT

If the file doesn’t already exist, it is created as a new, empty file. This flag is effective even if the file is being opened only for reading. If we specify O_CREAT, then we must supply a mode argument in the open() call; otherwise, the permissions of the new file will be set to some random value from the stack.

O_DIRECT

Allow file I/O to bypass the buffer cache. This feature is described in Section 13.6. The _GNU_SOURCE feature test macro must be defined in order to make this constant definition available from <fcntl.h>.

O_DIRECTORY

Return an error (errno equals ENOTDIR) if pathname is not a directory. This flag is an extension designed specifically for implementing opendir() (Reading Directories: opendir() and readdir()). The _GNU_SOURCE feature test macro must be defined in order to make this constant definition available from <fcntl.h>.

O_DSYNC (since Linux 2.6.33)

Perform file writes according to the requirements of synchronized I/O data integrity completion. See the discussion of kernel I/O buffering in Section 13.3.

O_EXCL

This flag is used in conjunction with O_CREAT to indicate that if the file already exists, it should not be opened; instead, open() should fail, with errno set to EEXIST. In other words, this flag allows the caller to ensure that it is the process creating the file. The check for existence and the creation of the file are performed atomically. We discuss the concept of atomicity in Section 5.1. When both O_CREAT and O_EXCL are specified in flags, open() fails (with the error EEXIST) if pathname is a symbolic link. SUSv3 requires this behavior so that a privileged application can create a file in a known location without there being a possibility that a symbolic link would cause the file to be created in a different location (e.g., a system directory), which would have security implications.

O_LARGEFILE

Open the file with large file support. This flag is used on 32-bit systems in order to work with large files. Although it is not specified in SUSv3, the O_LARGEFILE flag is found on several other UNIX implementations. On 64-bit Linux implementations such as Alpha and IA-64, this flag has no effect. See I/O on Large Files for more information.

O_NOATIME (since Linux 2.6.8)

Don’t update the file last access time (the st_atime field described in Retrieving File Information: stat()) when reading from this file. To use this flag, the effective user ID of the calling process must match the owner of the file, or the process must be privileged (CAP_FOWNER); otherwise, open() fails with the error EPERM. (In reality, for an unprivileged process, it is the process’s file-system user ID, rather than its effective user ID, that must match the user ID of the file when opening a file with the O_NOATIME flag, as described in Section 9.5.) This flag is a nonstandard Linux extension. To expose its definition from <fcntl.h>, we must define the _GNU_SOURCE feature test macro. The O_NOATIME flag is intended for use by indexing and backup programs. Its use can significantly reduce the amount of disk activity, because repeated disk seeks back and forth across the disk are not required to read the contents of a file and to update the last access time in the file’s i-node (I-nodes). Functionality similar to O_NOATIME is available using the MS_NOATIME mount() flag (Mounting a File System: mount()) and the FS_NOATIME_FL flag (I-node Flags (ext2 Extended File Attributes)).

O_NOCTTY

If the file being opened is a terminal device, prevent it from becoming the controlling terminal. Controlling terminals are discussed in Section 34.4. If the file being opened is not a terminal, this flag has no effect.

O_NOFOLLOW

Normally, open() dereferences pathname if it is a symbolic link. However, if the O_NOFOLLOW flag is specified, then open() fails (with errno set to ELOOP) if pathname is a symbolic link. This flag is useful, especially in privileged programs, for ensuring that open() doesn’t dereference a symbolic link. To expose the definition of this flag from <fcntl.h>, we must define the _GNU_SOURCE feature test macro.

O_NONBLOCK

Open the file in nonblocking mode. See Section 5.9.

O_SYNC

Open the file for synchronous I/O. See the discussion of kernel I/O buffering in Section 13.3.

O_TRUNC

If the file already exists and is a regular file, then truncate it to zero length, destroying any existing data. On Linux, truncation occurs whether the file is being opened for reading or writing (in both cases, we must have write permission on the file). SUSv3 leaves the combination of O_RDONLY and O_TRUNC unspecified, but most other UNIX implementations behave in the same way as Linux.

If an error occurs while trying to open the file, open() returns -1, and errno identifies the cause of the error. The following are some possible errors that can occur (in addition to those already noted when describing the flags argument above):

EACCES

The file permissions don’t allow the calling process to open the file in the mode specified by flags. Alternatively, because of directory permissions, the file could not be accessed, or the file did not exist and could not be created.

EISDIR

The specified file is a directory, and the caller attempted to open it for writing. This isn’t allowed. (On the other hand, there are occasions when it can be useful to open a directory for reading. We consider an example in Operating Relative to a Directory File Descriptor.)

EMFILE

The process resource limit on the number of open file descriptors has been reached (RLIMIT_NOFILE, described in Details of Specific Resource Limits).

ENFILE

The system-wide limit on the number of open files has been reached.

ENOENT

The specified file doesn’t exist, and O_CREAT was not specified, or O_CREAT was specified, and one of the directories in pathname doesn’t exist or is a symbolic link pointing to a nonexistent pathname (a dangling link).

EROFS

The specified file is on a read-only file system and the caller tried to open it for writing.

ETXTBSY

The specified file is an executable file (a program) that is currently executing. It is not permitted to modify (i.e., open for writing) the executable file associated with a running program. (We must first terminate the program in order to be able to modify the executable file.)

When we later describe other system calls or library functions, we generally won’t list the range of possible errors that may occur in the above fashion. (Such a list can be found in the corresponding manual page for each system call or library function.) We do so here for two reasons. One of these is that open() is the first system call that we describe in detail, and the above list illustrates that a system call or library function may fail for any of a number of reasons. Second, the specific reasons why open() may fail make an interesting list in themselves, illustrating a number of factors and checks that come into play when a file is accessed. (The above list is incomplete: see the open(2) manual page for more reasons why open() may fail.)

In early UNIX implementations, open() had only two arguments and could not be used to create a new file. Instead, the creat() system call was used to create and open a new file.

#include <fcntl.h>

int creat(const char *pathname, mode_t mode);

Note

Returns file descriptor, or -1 on error

The creat() system call creates and opens a new file with the given pathname, or if the file already exists, opens the file and truncates it to zero length. As its function result, creat() returns a file descriptor that can be used in subsequent system calls. Calling creat() is equivalent to the following open() call:

fd = open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode);

Because the open() flags argument provides greater control over how the file is opened (e.g., we can specify O_RDWR instead of O_WRONLY), creat() is now obsolete, although it may still be seen in older programs.