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_RDONLY
O_WRONLY
O_RDWR
Other flags:
O_APPEND
O_CREAT
rwr
)
O_TRUNC
Multiple flags are “orred” using |
, e.g.,
("foo.txt", O_RDWR | O_CREAT | O_TRUNC, 0644) open
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