I/O is done through device drivers that have a standard interface.
5 main system calls for I/O:
open
close
read
write
ioctl
These calls return -1 on error and set errno
UNIX I/O is done with file descriptors.
Normally, when your program starts, there are 3 file descriptors open: STDIN_FILENO STDOUT_FILENO STDERR_FILENO
It is not an error if this returns a value greater than 0 and less than
nbyte
You must restart the write if it returns fewer bytes than
requested.
a return value of -1 with errno set to EINTR is
not usually an error.
Look at the program simplecopy on page 97 that copies a file using copyfile
Look at Program 4.2 on page 98, copyfile1.
Look at Program 4.3 on page 99, r_read: restart if interrupted by a signal.
Look at Program 4.4 on page 99, r_write: also restarts if fewer bytes written.
Look at Program 4.5 on page 100, readwrite: does one read on one write.
Look at Program 4.6 on page 100, simple implementation of copyfile.
Look at Program 4.7 on page 101, read a specific number of bytes
Example 4.10: Read a pair of integers using readblock
struct {
int x;
int y;
} point;
if (readblock(fd, &point, sizeof(point)) <= 0)
fprintf(stderr, "Cannot read a point.\n");
Write 2 bytes
open and close
#include <fcntl.h>
#include <sys/stat.h>
int open(const char *path, int oflag);
int open(const char *path, int oflag, mode_t mode);
Possible values of the flag include: O_RDONLY: read only O_WRONLY: write only O_RDWR: read and write O_APPEND: writes always write to end O_CREAT: create the file if it does not exist O_EXCL: used with O_CREAT, return an error if file exists O_NOCTTY: do not become a controlling terminal O_NONBLOCK: do not block if not ready to open, also affects reads and writes O_TRUNC: discard previous contents
You must use the 3-parameter form of open if the O_CREAT
flag is used. This specifies permissions.
Figure 4.10 (page 105):
Historical layout of the permissions mask.
You should refer to the permissions with the POSIX symbolic names defined in
sys/stat.h.
S_IRUSR
read permission bit for owner
S_IWUSR
write permission bit for owner
S_IXUSR
execute permission bit for owner
S_IRWXU
read, write, execute for owner
S_IRGRP
read permission bit for group
S_IWGRP
write permission bit for group
S_IXGRP
execute permission bit for group
S_IRWXG
read, write, execute for group
S_IROTH
read permission bit for others
S_IWOTH
write permission bit for others
S_IXOTH
execute permission bit for others
S_IRWXO
read, write, execute for others
S_ISUID
set user ID on execution
S_ISGID
set group ID on execution
Table 4.1, Page 105: POSIX symbolic names for file permission.
Look at program 4.9: copyfilemain that copies a file.
#include <unistd.h>
int close(int fildes);
Open files are closed when your program exits normally.
Look at Program 4.10, r_close on page 107.
Read Example 1
Read Example 1
Suppose the file infile contains "abcdefghijklmnop".
Assuming no errors occur,
what are the possible outputs of the following program:
Read Example 2a
What would happen if the open and fork lines were interchanged?
File Pointers and Buffering
Use fopen, fclose, fread, fwrite, fprintf, fscanf, etc.
Example 4.24 (page 122) shows how to open a file for output using file
pointers.
Example 4.24:
FILE *myfp;
if ((myfp = fopen("/home/ann/my.dat", "w")) == NULL)
perror("Failed to open /home/ann/my.dat");
else
fprintf(myfp, "This is a test");
Figure 4.3 (page 122):
Schematic use of a file pointer after fopen.
I/O using file pointers will read from or write to the buffer.
The buffer will be filled or emptied when necessary.
A write may fill part of the buffer without causing any physical I/O to
the file.
The size of buffer may vary.
If a write is done to standard output and them the program crashes,
the data written may not show up on the screen.
Standard error is not buffered.
Interleaving output to standard output and standard error may cause
output to appear in an unpredictable order.
You can force the physical output to occur with an fflush.
bufferout and bufferinout
Exercise 4.25: How does the output appear when the program bufferout
executes?
Exercise 4.26: How does the output appear when the program bufferinout
executes?
Inheritance of File Descriptors
When fork creates a child, the child inherits a copy of the
parent's address space, including the file descriptor table.
Example 4.27: In the program openfork the child inherits the file
descriptor from the parent. Each process reads and outputs on character
of the file. This is shown in Figure 4.4.
Figure 4.4 (page 126):
If the parent opens my.dat before the fork,
both parent and child share the system file table entry.
Example 4.32 (page 125): The program forkopen
shows a similar code segment in which the fork
is done before the open.
This is shown in Figure 4.5.
Figure 4.5 (page 127):
If the parent and child open my.dat after the fork,
the two processes use different system file table entries.
What output would be generated by the programs fileiofork
and fileioforkline?
Filters and Redirection
Example 4.35 (page 129): Consider the following command: cat > my.file
Figure 4.6 (page 130) shows the file descriptor table for this.
Figure 4.6 (page 130):
The status of the file descriptor table before and after redirection
for the process that is executing cat > my.file
Redirection can be done by copying one entry of the file descriptor table
into another.
This is accomplished with the dup2 system call.
#include <unistd.h>
int dup2(int fildes, int fildes2);
It closes fildes2 and then copies the pointer of entry fildes
into the entry fildes2.
Program 4.18, redirect, shows how this can be done.
Figure 4.7 (page 131):
The status of the file descriptor table during the execution of Program 4.18.