In Unix, Everything is a File…
foo/
|
+-----+---+---+--------+
| | | |
bar/ baz/ info.txt hello.c
| |
img.png |
|
+--------+-------+-------+-------+
| | | | |
meme.gif run.sh items.csv main.s letter.docx
fork, wait, and exec)The POSIX File API works with file descriptors
These are integers that represent open files
Each process has its own file descriptor table
In xv6:
struct proc {
// ...
struct file *ofile[NOFILE]; // Open files
// ...
};In Linux:
struct task_struct {
// ...
/* Open file information: */
struct files_struct *files;
// ...
}The file descriptor that the API uses is usually the literal index into the above array
| Descriptor | Purpose |
|---|---|
| 0 | standard input (stdin) |
| 1 | standard output (stdout) |
| 2 | standard error output (stderr) |
To open a file, we issue the open system call
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);We need to give it a filename (with path) and flags
Flags give specifics about how a file should be open
Access mode flags (one of them is required):
O_RDONLYO_WRONLYO_RDWROther flags:
O_APPENDO_CREATrwr)
O_TRUNCMultiple flags are “orred” using |, e.g.,
open("foo.txt", O_RDWR | O_CREAT | O_TRUNC, 0644)If we are CREAT-ing a file, we also need to supply
permissions for the new file - e.g., the 0644 above
corresponds to rw-r--r--
(For an explanation of file permissions in Linux, see https://www.linuxfoundation.org/blog/blog/classic-sysadmin-understanding-linux-file-permissions)
When successful, open will return a file descriptor
≥ 0
On error, it will return -1 and the
errno variable is set to the error code
Full usage info: man 2 open
To close an open file, call close with the file
descriptor as argument
The read syscall allows reading from a file
It takes a file descriptor, a buffer to be written to and the maximum number of bytes to be read
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);On success, it will return the number of bytes actually read
On error, it will return -1 and the
errno variable is set to the error code
The write syscall is for writing
Args: file descriptor, a buffer containing the contents to be written, and the number of bytes to write
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);Success: the number of bytes written
On error, it will return -1 and the
errno variable is set to the error code
(Use strace to trace cat foo)
lseek
fsync
rename
stat
link
unlink