4.3 Opening and Closing Files The open function associates a file descriptor (the handle used in the program) with a file or physical device. The path parameter of open points to the pathname of the file or device, and the oflag parameter specifies status flags and access modes for the opened file. You must include a third parameter to specify access permissions if you are creating a file. SYNOPSIS #include <fcntl.h> #include <sys/stat.h> int open(const char *path, int oflag, ...); POSIX
If successful, open returns a nonnegative integer representing the open file descriptor. If unsuccessful, open returns 1 and sets errno. The following table lists the mandatory errors for open.|
EACCES | search permission on component of path prefix denied, or file exists and permissions specified by oflag denied, or file does not exist and write permission on parent directory denied, or O_TRUNC specified and write permission denied | EEXIST | O_CREAT and OEXCL are set and named file already exists | EINTR | signal was caught during open | EISDIR | named file is directory and oflag includes O_WRONLY or O_RDWR | ELOOP | a loop exists in resolution of path | EMFILE | OPEN_MAX file descriptors currently open in calling process | ENAMETOOLONG | the length of path exceeds PATH_MAX, or a pathname component is longer than NAME_MAX | ENFILE | maximum allowable number of files currently open in system | ENOENT | O_CREAT not set and name file does not exist, or O_CREAT is set and either path prefix does not exist or or path is an empty string | ENOSPC | directory or file system for new file cannot be expanded, the file does not exist and O_CREAT is specified | ENOTDIR | a component of the path prefix is not a directory | ENXIO | O_NONBLOCK is set, the named file is a FIFO, O_WRONLY is set, no process has file open for reading; file is a special file and device associated with file does not exist | EOVERFLOW | named file is a regular file and size cannot be represented by an object of type off_t | EROFS | the named file resides on a read-only file system and one of O_WRONLY, O_RDWR, O_CREAT (if the file does not exist), or O_TRUNC is set in oflag | Construct the oflag argument by taking the bitwise OR (|) of the desired combination of the access mode and the additional flags. The POSIX values for the access mode flags are O_RDONLY, O_WRONLY and O_RDWR. You must specify exactly one of these designating read-only, write-only or read-write access, respectively.The additional flags include O_APPEND, O_CREAT, O_EXCL, O_NOCTTY, O_NONBLOCK and O_TRUNC. The O_APPEND flag causes the file offset to be moved to the end of the file before a write, allowing you to add to an existing file. In contrast, O_TRUNC truncates the length of a regular file opened for writing to 0. The O_CREAT flag causes a file to be created if it doesn't already exist. If you include the O_CREAT flag, you must also pass a third argument to open to designate the permissions. If you want to avoid writing over an existing file, use the combination O_CREAT | O_EXCL. This combination returns an error if the file already exists. The O_NOCTTY flag prevents an opened device from becoming a controlling terminal. Controlling terminals are discussed in Section 11.5. The O_NONBLOCK flag controls whether the open returns immediately or blocks until the device is ready. Section 4.8 discusses how the O_NONBLOCK flag affects the behavior of read and write. Certain POSIX extensions specify additional flags. You can find the flags in fcntl.h.Example 4.11 The following code segment opens the file /home/ann/my.dat for reading. int myfd; myfd = open("/home/ann/my.dat", O_RDONLY);
This code does no error checking.Exercise 4.12 How can the call to open of Example 4.11 fail?Answer:The open function returns 1 if the file doesn't exist, the open call was interrupted by a signal or the process doesn't have the appropriate access permissions. If your code uses myfd for a subsequent read or write operation, the operation fails.Example 4.13 The following code segment restarts open after a signal occurs. int myfd; while((myfd = open("/home/ann/my.dat", O_RDONLY)) == -1 && errno == EINTR) ; if (myfd == -1) /* it was a real error, not a signal */ perror("Failed to open the file"); else /* continue on */
Exercise 4.14 How would you modify Example 4.13 to open /home/ann/my.dat for nonblocking read?Answer:You would OR the O_RDONLY and the O_NONBLOCK flags. myfd = open("/home/ann/my.dat", O_RDONLY | O_NONBLOCK);
Each file has three classes associated with it: a user (or owner), a group and everybody else (others). The possible permissions or privileges are read(r), write(w) and execute(x). These privileges are specified separately for the user, the group and others. When you open a file with the O_CREAT flag, you must specify the permissions as the third argument to open in a mask of type mode_t.Historically, the file permissions were laid out in a mask of bits with 1's in designated bit positions of the mask, signifying that a class had the corresponding privilege. Figure 4.1 shows an example of a typical layout of such a permission mask. Although numerically coded permission masks frequently appear in legacy code, you should avoid using numerical values in your programs.
 POSIX defines symbolic names for masks corresponding to the permission bits so that you can specify file permissions independently of the implementation. These names are defined in sys/stat.h. Table 4.1 lists the symbolic names and their meanings. To form the permission mask, bitwise OR the symbols corresponding to the desired permissions.Table 4.1. POSIX symbolic names for file permissions.|
S_IRUSR | read by owner | S_IWUSR | write by owner | S_IXUSR | execute by owner | S_IRWXU | read, write, execute by owner | S_IRGRP | read by group | S_IWGRP | write by group | S_IXGRP | execute by group | S_IRWXG | read, write, execute by group | S_IROTH | read by others | S_IWOTH | write by others | S_IXOTH | execute by others | S_IRWXO | read, write, execute by others | S_ISUID | set user ID on execution | S_ISGID | set group ID on execution |
Example 4.15 The following code segment creates a file, info.dat, in the current directory. If the info.dat file already exists, it is overwritten. The new file can be read or written by the user and only read by everyone else. int fd; mode_t fdmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if ((fd = open("info.dat", O_RDWR | O_CREAT, fdmode)) == -1) perror("Failed to open info.dat");
Program 4.9 copies a source file to a destination file. Both filenames are passed as command-line arguments. Because the open function for the destination file has O_CREAT | O_EXCL, the file copy fails if that file already exists.Program 4.9 copyfilemain.c A program to copy a file. #include <fcntl.h> #include <stdio.h> #include <unistd.h> #include <sys/stat.h> #include "restart.h" #define READ_FLAGS O_RDONLY #define WRITE_FLAGS (O_WRONLY | O_CREAT | O_EXCL) #define WRITE_PERMS (S_IRUSR | S_IWUSR) int main(int argc, char *argv[]) { int bytes; int fromfd, tofd; if (argc != 3) { fprintf(stderr, "Usage: %s from_file to_file\n", argv[0]); return 1; } if ((fromfd = open(argv[1], READ_FLAGS)) == -1) { perror("Failed to open input file"); return 1; } if ((tofd = open(argv[2], WRITE_FLAGS, WRITE_PERMS)) == -1) { perror("Failed to create output file"); return 1; } bytes = copyfile(fromfd, tofd); printf("%d bytes copied from %s to %s\n", bytes, argv[1], argv[2]); return 0; /* the return closes the files */ }
Program 4.9 returns immediately after performing the copy and does not explicitly close the file. The return from main causes the necessary cleanup to release the resources associated with open files. In general, however, you should be careful to release open file descriptors by calling close.The close function has a single parameter, fildes, representing the open file whose resources are to be released. SYNOPSIS #include <unistd.h> int close(int fildes); POSIX
If successful, close returns 0. If unsuccessful, close returns 1 and sets errno. The following table lists the mandatory errors for close.|
EBADF | fildes is not a valid file descriptor | EINTR | the close function was interrupted by a signal | Program 4.10 shows an r_close function that restarts itself after interruption by a signal. Its prototype is in the header file restart.h.Program 4.10 r_close.c The r_close.c function is similar to close except that it restarts itself if interrupted by a signal. #include <errno.h> #include <unistd.h> int r_close(int fd) { int retval; while (retval = close(fd), retval == -1 && errno == EINTR) ; return retval; }
|