Unix uses device independence.
I/O is done through device drivers that have a standard interface.
5 main system calls for I/O:
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
read
#include <unistd.h> ssize_t read(int fildes, void *buf, size_t nbyte);
write
#include <unistd.h> ssize_t write(int fildes, const void *buf, size_t nbyte);
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");
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:
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.
select
Look at Program 4.11 that uses two processes to monitor 2 file descriptors.
How would you print out the total number of bytes read from the two files?
#include <sys/select.h> int select(int nfds, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict errorfds, struct timeval *restrict timeout); void FD_CLR(int fd, fd_set *fdset); int FD_ISSET(int fd, fd_set *fdset); void FD_SET(int fd, fd_set *fdset); void FD_ZERO(fd_set *fdset);
Look at Program 4.12, whichisready, a function returns a file descriptor that is ready to be read.
Look at Program 4.13, copy2files that uses select to concurrently copy two files.
Look at Program 4.14, monitorselect, a function that monitors an array of file descriptors.
Look at Program 4.15, waitfdtimed, a function that uses the timeout feature of select to wait for a file descriptor with a timeout.
Look at Program 4.16, reatimed, a function that uses waitfdtimed.
File Representation
Figure 4.2 (page 120): Relationship between the file descriptor table, the system file table and the in-memory inode table.
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.
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
parents 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.
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?
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.
Figure 4.7 (page 131): The status of the file descriptor table during the execution of Program 4.18.