Skip to content

File I/O - the universal I/O model

Universality of I/O

  • One of the distinguishing features of the I/O model on UNIX systems is the concept of universality of I/O. This means that the same system calls (open(),read(), write(), close(), and so on) are used to perform I/O on all types of files, including devices. Thus, a program that employing these systems will work on any type of file.
Terminal window
$ ./copy test test.old # Copy a regular file
$ ./copy a.txt /dev/tty # Copy a regular file to this terminal
$ ./copy /dev/tty b.txt # Copy input from this terminal to a regular file
$ ./copy /dev/pts/16 /dev/tty # Copy input from another terminal
  • All system calls for performing I/O refer to open files using a file descriptor (a nonnegative integer). File descriptors are used to refer to all types of open files: pipes, FIFOs, sockets, terminals, devices and regular files. Each process has its own set of file descriptors.

Opening a file: open()

  • A call to open() creates a new open file description, an entry in the system-wide table of open files. The open file description records the file offset and the file status flags (see below). A file descriptor is a non-negative integer that act as an abstract to handle file or I/O resources 0,1,2 are taken by STDIN, STDOUT, and STDERR.
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags, ... /* mode_t mode */);
// Returns file descriptor on success, or –1 on error

Explain

  • The file to be opened is identified by the pathname argument. If pathname is a symbolic link, it is dereferenced.

  • The flags argument is a bitmask that specifies the access mode for the file:

    Access modeDescriptionGroup
    O_RDONLYOpen for reading onlyFile access mode flags
    O_WRONLYOpen for writing onlyFile access mode flags
    O_RDWROpen for reading and writingFile access mode flags
    O_CLOEXECSet the close-on-exec flag (since Linux 2.6.23)File creation flags
    O_CREATCreate file if it doesn’t already existFile creation flags
    O_DIRECTFile I/O bypasses buffer cacheFile creation flags
    O_DIRECTORYFail if pathname is not a directoryFile creation flags
    O_EXCLWith O_CREAT: create file exclusivelyFile creation flags
    O_LARGEFILEUsed on 32-bit systems to open large filesFile creation flags
    O_NOATIMEDon’t update file last access time on read() (since Linux 2.6.8)File creation flags
    O_NOCTTYDon’t let pathname become the controlling terminalFile creation flags
    O_NOFOLLOWDon’t dereference symbolic linksFile creation flags
    O_TRUNCTruncate existing file to zero lengthFile creation flags
    O_APPENDWrites are always appended to end of fileOpen file status flags
    O_ASYNCGenerate a signal when I/O is possibleOpen file status flags
    O_DSYNCProvide synchronized I/O data integerity (since Linux 2.6.33)Open file status flags
    O_NONBLOCKOpen in nonblocking modeOpen file status flags
    O_SYNCMake file write synchronousOpen file status flags
    • File access mode flags: can be retrieved using the fcntl() F_GETFL operation
    • File creation mode flags: these flags control various aspects of the behavior of the open() call and options for subsequent I/O operations. They can’t be retrieved or changed.
    • Open file status flags: these flags can be retrieved and modified using the fcntl() F_GETFL and F_SETFL operations

Errors handling

  • If an error occurs while trying to open the file, open() returns –1, and errno identifies the cause of the error

    NAMEDescription
    EACCESThe 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.
    EISDIRThe specified file is a directory, and the caller attempted to open it for writing. This isn’t allowed.
    EMFILEThe process resource limit on the number of open file descriptors has been reached
    ENFILEThe system-wide limit on the number of open files has been reached.
    ENOENTThe 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).
    EROFSThe specified file is on a read-only file system and the caller tried to open it for writing.
    ETXTBSYThe 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.)

Example

Reading from a file: read()

#include <tlpi_hdr.h>
#define MAX_READ 20
int main(){
char buffer[MAX_READ + 1];
ssize_t numRead = read(STDIN_FILENO, buffer, MAX_READ);
if (numRead == -1)
errExit("read");
printf("The input data was: %s\n", buffer);
buffer[numRead] = '\0';
printf("The input data was: %s\n", buffer);
}
  • This system call doesn’t place a terminating null byte at the end of the string.