Section 11.5. Manipulating File Descriptors


11.5. Manipulating File Descriptors

Nearly all the file-related system calls we have talked about, with the exception of lseek(), manipulate a file's inode, which causes their results to be shared among processes that have the file open. There are a few system calls that instead act on the file descriptor itself. The fcntl() system call can be used for numerous file descriptor manipulations. fcntl() looks like this:

 #include <fcntl.h> int fcntl(int fd, int command, long arg); 

For many commands, arg is not used. We discuss most of fcntl()'s uses here. It is also used for file locking, file leases, and nonblocking I/O, which are discussed in Chapter 13, as well as directory change notification, which is presented in Chapter 14.

11.5.1. Changing the Access Mode for an Open File

The append mode (as indicated by the O_APPEND flag when the file is opened) and nonblocking mode (the O_NONBLOCK flag), can be turned on and off after a file has already been opened through the fcntl()'s F_SETFL command. The arg parameter should be the flags that should be set if one of the flags is not specified, it is turned off for fd.

F_GETFL may be used to query the current flags for the file. It returns all the flags, including the read/write mode the file was opened in. F_SETFL allows only setting the flags mentioned above; any other flags that are present in the arg parameter are ignored.

 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_RDONLY); 

is perfectly legal, but it does not accomplish anything. Turning on append mode for a file descriptor looks like this:

 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_APPEND); 

Note that care was taken to preserve the O_NONBLOCK setting. Turning append mode off looks similar:

 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_APPEND); 

11.5.2. Modifiying the close-on-exec Flag

During an exec() system call, file descriptors are normally left open for the new program to use. In certain cases, you may wish to have files closed when you call exec(). Rather than closing them by hand, you can ask the system to close a certain file descriptor when exec() is called through fcntl()'s F_GETFD and F_SETFD commands. If the close-on-exec flag is set when F_GETFD is used, fcntl() returns non-0; otherwise, it returns 0. The close-on-exec flag is set through F_SETFD; it is disabled if arg is 0 and enabled otherwise.

Here is how you would force fd to be closed when the process exec() s:

 fcntl(fd, F_SETFD, 1); 

11.5.3. Duplicating File Descriptors

Occasionally, a process needs to create a new file descriptor that references a file that is already open. Shells use this functionality to redirect standard input, output, and error at the user's request. If the process does not care what file descriptor is used for the new reference, it should use dup().

 #include <unistd.h> int dup(int oldfd); 

dup() returns a file descriptor that references the same inode as oldfd, or-1 on an error. The oldfd is still a valid file descriptor and still references the original file. The new file descriptor is always the smallest file descriptor currently available. If the process needs the new file descriptor to have a particular value (such as 0 to change its standard input), it should use dup2() instead.

 #include <unistd.h> int dup2(int oldfd, int newfd); 

If newfd references an already open file descriptor, that file descriptor is closed. If the call succeeds, it returns the new file descriptor and newfd references the same file as oldfd. The fcntl() system call provides almost the same functionality through the F_DUPFD command. The first argument, fd, is the already open file descriptor. The new file descriptor is the first available file descriptor that is the same or larger than the last argument to fcntl(). (This is different than how dup2() works.) You could implement dup2() through fcntl() like this:

 int dup2(int oldfd, int newfd) {     close(newfd);                   /* ensure newfd is available */     return fcntl(oldfd, F_DUPFD, newfd); } 

Creating two duped file descriptors that reference the same file is not the same as opening a file twice. Nearly all duped file descriptors' attributes are shared; they share a common current position, access mode, and locks. (These items are stored in a file structure,[21] one of which is created each time the file is opened. A file descriptor refers to a file structure, and dup() ed file descriptors refer to a single file structure.) The only attribute that can be independently controlled for the two file descriptors is their close-on-exec status. After the process has fork() ed, the parent's open files are inherited by the child, and those pairs of file descriptors (one in the parent and one in the new child) behave exactly like a file descriptor that has been duped with the current position and most other attributes being shared.[22]

[21] File structures are also known as file table entries or open file objects, depending on the operating system.

[22] The file descriptor in each process refers to the same file structure.


    Linux Application Development
    Linux Application Development (paperback) (2nd Edition)
    ISBN: 0321563220
    EAN: 2147483647
    Year: 2003
    Pages: 168 © 2008-2017.
    If you may any questions please contact us: