File I/O: Basics

File Descriptors

  • Universal handle for everything that’s got to do with I/O

  • Type: int

  • File is only one shape of I/O

  • Alternative shapes

    • Pipes

    • Sockets

    • FIFOs

    • Terminals

    • Device Special Files ⟶ entry point into arbitrary kernel drivers

  • Linux specific ingenuities: signalfd(), timerfd_create(), eventfd()

Standard Filedescriptors

Number

POSIX Macro

stdio.h equivalent

0

STDIN_FILENO

stdin

1

STDOUT_FILENO

stdout

2

STDERR_FILENO

stderr

  • Interactive shell: all three associated with terminal

  • Standard input and output used for I/O redirection and pipes

  • Standard error receives errors, warnings, and debug output

Caution

Windows-Programmers: no errors, warnings, and debug output to standard output!!

File I/O: System Calls

open()

Opens a file (or creates it ⟶ tons of flags)

read()

Reads bytes

write()

Writes bytes

close()

Closes the file

open() creates file descriptors that are associated with path names (files, named pipes, device special files, …). Other “factory” functions …

Network programming:

  • connect()

  • accept()

Miscellaneous:

  • pipe()

  • timerfd_create()

open()

#include <fcntl.h>

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

Swiss army knife among system calls. Multiple actions, governed by bitwise-or’ed flags:

  • Create/Open/Truncate/…

  • Access mode (Read, Write)

  • Hundreds of others

open() Flags

Access Mode

  • O_RDONLY: Can only read(); error on write()

  • O_WRONLY: Can only write(); error on read()

  • O_RDWR: …

Creating a File

  • O_CREAT: create if not exists, else simply open

  • O_CREAT|O_EXCL: exclusive creation

    • error if file exists

    • ⟶ to prevent race conditions when two parties try to create a file at the smae time

    • security measure

Miscellaneous

  • O_APPEND: write access appends at the end

  • O_TRUNC: truncate file to zero length if already exists

  • O_CLOEXEC: exec() closes the file descriptor (⟶ later)

read()

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);
  • Return value: number of bytes read (-1 on error, as always)

  • 0 is End of File (EOF)

  • Can read less than count (usually with network I/O)

write()

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);
  • Return value: number of bytes written (-1 on error, as always)

  • Can write less than count (usually with network I/O)

  • SIGPIPE (process termination) when …

    • Writing on a network connection that has been closed by peer

    • Writing on a pip where receiver end has exited (hence SIGPIPE)

File Offset: lseek()

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

read() and write() manipulate the offset (position where the next operation begins).

Explicit positioning. whence is one of

Macro

Description

SEEK_SET

The file offset is set to offset bytes.

SEEK_CUR

The file offset is set to its current location plus offset bytes.

SEEK_END

The file offset is set to the size of the file plus offset bytes.

Obscure feature: files with holes

  • positioning beyond file size

  • write to that position

  • holes, occupying no space

  • read() across a hole give 0-bytes

The Rest: ioctl()

#include <sys/ioctl.h>

int ioctl(int fd, unsigned long request, ...);
  • Tunnel for functionality not declarable as I/O

  • Most commonly used to communicate with drivers (e.g.: “Open that CD drive!”)

  • Mostly deprecated nowadays (though easily implemented in a driver)

  • Better (because more obvious): use /proc and /sys