The File System Interface
Let's look at the interface provided by the file system to the users, in this lesson.
We'll cover the following
Let’s now discuss the file system interface in more detail. We’ll start with the basics of creating, accessing, and deleting files. You may think this is straightforward, but along the way we’ll discover the mysterious call that is used to remove files, known as unlink()
. Hopefully, by the end of this chapter, this mystery won’t be so mysterious to you!
Creating files
We’ll start with the most basic of operations: creating a file. This can be accomplished with the open
system call; by calling open()
and passing it the O_CREAT
flag, a program can create a new file. Here is some example code to create a file called “foo” in the current working directory:
int fd = open("foo", O_CREAT|O_WRONLY|O_TRUNC,S_IRUSR|S_IWUSR);
ASIDE: THE
creat()
SYSTEM CALLThe older way of creating a file is to call
creat()
, as follows:// option: add second flag to set permissions int fd = creat("foo");
You can think of
creat()
asopen()
with the following flags:O_CREAT | O_WRONLY | O_TRUNC
. Becauseopen()
can create a file, the usage ofcreat()
has somewhat fallen out of favor (indeed, it could just be implemented as a library call toopen()
); however, it does hold a special place in UNIX lore. Specifically, when Ken Thompson was asked what he would do differently if he were redesigning UNIX, he replied: “I’d spell creat with an e.”
The routine open()
takes a number of different flags. In this example, the second parameter creates the file (O_CREAT
) if it does not exist, ensures that the file can only be written to (O_WRONLY
), and, if the file already exists, truncates it to a size of zero bytes thus removing any existing content (O TRUNC). The third parameter specifies permissions, in this case making the file readable and writable by the owner.
One important aspect of open()
is what it returns: a file descriptor. A file descriptor is just an integer, private per process, and is used in UNIX systems to access files; thus, once a file is opened, you use the file descriptor to read or write the file, assuming you have permission to do so. In this way, a file descriptor is a read()
and write()
(we’ll see how to do so below).
As stated above, file descriptors are managed by the operating system on a per-process basis. This means some kind of simple structure (e.g., an array) is kept in the proc
structure on UNIX systems. Here is the relevant piece from the
struct proc {...struct file *ofile[NOFILE]; // Open files...};
A simple array (with a maximum of NOFILE
open files) tracks which files are opened on a per-process basis. Each entry of the array is actually just a pointer to a struct file
, which will be used to track information about the file being read or written; we’ll discuss this further in the coming lessons.
Get hands-on with 1400+ tech skills courses.