Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

When opening a FIFO with O_RDONLY or O_WRONLY set: If O_NONBLOCK is set:
  An open() for reading only will return without delay. An open() for writing only will return an error if no process currently has the file open for reading.
If O_NONBLOCK is clear:
  An open() for reading only will block the calling thread until a thread opens the file for writing. An open() for writing only will block the calling thread until a thread opens the file for reading.

When opening a block special or character special file that supports non-blocking opens:
If O_NONBLOCK is set:
  The open() function will return without blocking for the device to be ready or available. Subsequent behaviour of the device is device-specific.
If O_NONBLOCK is clear:
  The open() function will block the calling thread until the device is ready or available before returning.

Otherwise, the behaviour of O_NONBLOCK is unspecified.

Wiki MarkupOnce the file is open, programmers can use the POSIX {{lstat()}}/{{fstat()}} functions to obtain information about a named file, and the {{S_ISREG()}} macro to determine if the file is a regular file. (see \[[FIO05-A. Identify files using multiple file attributes]\])

Since the behavior of O_NONBLOCK on subsequent calls to read() or write() is unspecified, it is advisable to disable the flag once we are sure the file in question is not a special device.unmigrated-wiki-markup

When available (Linux 2.1.126+, FreeBSD, Solaris 10, POSIX.1-2008), the {{O_NOFOLLOW}} should also be used , see \[[(see POS01-A. Check for the existence of links]\]). When {{O_NOFOLLOW}} is not available, symbolic link checks should use the method from \[[POS35-C. Avoid race conditions while checking for the existence of a symbolic link]\].

Code Block
bgColor#ccccff
#ifdef O_NOFOLLOW
  #define OPEN_FLAGS O_NOFOLLOW | O_NONBLOCK
#else
  #define OPEN_FLAGS O_NONBLOCK
#endif

/* ... */

struct stat orig_st;
struct stat open_st;
int fildes;
int flags;

if (!fgets(filename, sizeof(filename), stdin)) {
  /* handle error */
}

if ((lstat(file_name, &orig_st) != 0) || (!S_ISREG(orig_st.st_mode))) {
  /* handle error */
}

/* A TOCTOU race condition exists here, see below */

if ((fildes = open(filename, OPEN_FLAGS | O_WRONLY)) == -1) {
  /* handle error */
}

if (fstat(fildes, &open_st) != 0) {
  /* handle error */
}

if ((orig_st.st_mode != open_st.st_mode) ||
    (orig_st.st_ino  != open_st.st_ino) ||
    (orig_st.st_dev  != open_st.st_dev)) {
  /* file was tampered with */
}

/* Optional: drop the O_NONBLOCK now that we are sure this is a good file */
if ((flags = fcntl(fildes, F_GETFL)) == -1) {
  /* handle error */
}

if ((fcntl(fildes, F_SETFL, flags & ~O_NONBLOCK) != 0) {
  /* handle error */
}

/* operate on file */

...