File Descriptors, File Descriptor Tables, and File Structures
Yes, to access a file, the file system go through multiple structures. Among them, we find the three elements mentioned in the title. I use the word “element” here since the file descriptor is not a structure but merely a number identifying an open file. Without further ado let’s demystify those confusing terms.
A file descriptor is an element returned by an open(2) system call. It is a number that can have a value between 0 and N. The value of N depends on the system. To find this value, we can execute this command (on my system the command returns 4096):
$ ulimit -Hn
The file descriptor effectively identifies an open file. Once obtained through the open(2) system call, it can be used to access the opened file with the read(2) and write(2) system calls. Once the file is no longer needed, it can be closed with the close(2) system call.
File Descriptor Table
The file descriptor is an index of the “file descriptor table”. The content of the table is a set of pointers to an (open) file structure. The below figure shows the relation between these elements:
The role of the file descriptor table is to identify a file structure “safely”. A naive alternative will be to give the address of the (open) file structure directly to the user space application as an identifier for the (open) file. However, the user space can tamper with this address and give the address to another structure when accessing the file. This can corrupt the kernel.
(Open) File Structure
This structure represents an open file. It contains two pieces of information. The first is a pointer to a Dentry or Inode: two structures representing a file. The second is the current position in the file. This position starts at 0 when the file is opened and is incremented after each read(2) or write(2) operation. It can also be directly modified through the lseek(2) system call.