Operating Relative to a Directory File Descriptor

Starting with kernel 2.6.16, Linux provides a range of new system calls that perform similar tasks to various traditional system calls, but provide additional functionality that is useful to some applications. These system calls are summarized in Table 18-2. We describe these system calls in this chapter because they provide variations on the traditional semantics of the process’s current working directory.

Table 18-2. System calls that use a directory file descriptor to interpret relative pathnames

New interface

Traditional analog

Notes

faccessat()

access()

Supports AT_EACCESS and AT_SYMLINK_NOFOLLOW flags

fchmodat()

chmod()

 

fchownat()

chown()

Supports AT_SYMLINK_NOFOLLOW flag

fstatat()

stat()

Supports AT_SYMLINK_NOFOLLOW flag

linkat()

link()

Supports (since Linux 2.6.18) AT_SYMLINK_FOLLOW flag

mkdirat()

mkdir()

 

mkfifoat()

mkfifo()

Library function layered on top of mknodat()

mknodat()

mknod()

 

openat()

open()

 

readlinkat()

readlink()

 

renameat()

rename()

 

symlinkat()

symlink()

 

unlinkat()

unlink()

Supports AT_REMOVEDIR flag

utimensat()

utimes()

Supports AT_SYMLINK_NOFOLLOW flag

In order to describe these system calls, we’ll use a specific example: openat().

#define _XOPEN_SOURCE 700     /* Or define _POSIX_C_SOURCE >= 200809 */
#include <fcntl.h>

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

Note

Returns file descriptor on success, or -1 on error

The openat() system call is similar to the traditional open() system call, but adds an argument, dirfd, that is used as follows:

  • If pathname specifies a relative pathname, then it is interpreted relative to the directory referred to by the open file descriptor dirfd, rather than relative to the process’s current working directory.

  • If pathname specifies a relative pathname, and dirfd contains the special value AT_FDCWD, then pathname is interpreted relative to the process’s current working directory (i.e., the same behavior as open(2)).

  • If pathname specifies an absolute pathname, then dirfd is ignored.

The flags argument of openat() serves the same purpose as for open(). However, some of the system calls listed in Table 18-2 support a flags argument that is not provided by the corresponding traditional system call, and the purpose of this argument is to modify the semantics of the call. The most frequently provided flag is AT_SYMLINK_NOFOLLOW, which specifies that if pathname is a symbolic link, then the system call should operate on the link, rather than the file to which it refers. (The linkat() system call provides the AT_SYMLINK_FOLLOW flag, which performs the converse action, changing the default behavior of linkat() so that it dereferences oldpath if it is a symbolic link.) For details of the other flags, refer to the corresponding manual pages.

The system calls listed in Table 18-2 are supported for two reasons (again, we explain using the example of openat()):

These system calls are not standardized in SUSv3, but are included in SUSv4. In order to expose the declaration of each of these system calls, the _XOPEN_SOURCE feature test macro must be defined with a value greater than or equal to 700 before including the appropriate header file (e.g., <fcntl.h> for open()). Alternatively, the _POSIX_C_SOURCE macro can be defined with a value greater than or equal to 200809. (Before glibc 2.10, the _ATFILE_SOURCE macro needed to be defined to expose the declarations of these system calls.)

Note

Solaris 9 and later provide versions of some of the interfaces listed in Table 18-2, with slightly different semantics.