An open file is an object! If we use the UNIX/C model, the object has the following methods:
Of course, in UNIX, because the system interface is not itself object oriented, we add a first parameter to each of these, so instead of calling f.read(buf,len), we call read(fd,buf,len). In addition, because UNIX was originally a 16-bit system, seek(fd,pos,base) was defined as taking a 16-bit position parameter, and when UNIX was extended to allow longer files in the early 1970's, a new service, lseek, was introduced, allowing a 32-bit position to be passed. This involves no change in the abstraction.
In UNIX, the open-file object is a member of a polymorphic class. You can open a disk file, but you can also open a network socket, an interprocess pipe, or a physical device such as the parallel port or the floppy disk. When you open a physical device, you do so with no file system on that device, so if you read the floppy disk, your file position is relative to the raw hardware, with file position zero being track 0, sector 0, surface 0.
Some subclasses of the device class do not fully support the interface given here. You can't seek or write on a mouse or keyboard. You can't read from or seek on a printer. Other subclasses need extra operations, for example, on an asynchronous communications line, it is possible to set the baud rate, byte size, number of stop bits and parity. Because the UNIX interface is not object oriented, all devices support one additional operation:
In addition, because file handles are stored in a special address space, the open file table of the process calling program, indexed by integers, we cannot manipulate file handles using normal memory addressing tools. Therefore, the system interface includes a special tool
For each object, we expect there to be an object constructor, and there is such a constructor in UNIX, the open service.
In fact, open in UNIX is interpreted in the context of the environment of the current process, where, from the context of the open system call, the environment contains a pair of hidden objects, the current working directory of a process and the root directory of the process. Usually, the root is the root of the entire file system, but it need not be (the file system supports a method, chroot, that changes the process's root).
A UNIX directory is just a kind of file; from the object oriented viewpoint, an open directory is a kind of open file, and the current process has, at any instant, one open directory for the root of the file system, and one open directory for the current working directory. These environment attributes may be manipulated by the following:
The behavior of chroot and cd are not entirely rational and include features that are afterthoughts. The descriptions above are a bit idealized.
A directory is just a kind of disk file, and it can be read by the same read routine used to read a normal disk file. The following operations write directories:
These primitives are not visible to the user! Instead, there is a link kernel primitive (used to implement the ln shell command) that includes two full file names. It uses the first name to as the name of the file being linked to, and it splits the second name into a final file name and a directory name, opens that directory, and uses the makelink primitive on that directory to create a link to the first name.
The unlink kernel primitive primitve (used to implement the rm and rmdir shell commands) parses the given file name into a directory name and a file name in that directory, opens the directory and then applies the delete-link primitive to the named directory entry.
The rename kernel primitive (used to implement the mv shell command) is like link followed by unlink (or ln followed by rm in the shell), except that it is executed in a critical section, so that it appears atomic.
Opening a file is done by opening each directory along the path to that file, reading the directory to find the named directory entry, and opening that, until the named entry is the final name in the pathname provided. The initial directory used in this process is either the process's root or the process's current working directory, depending on whether the first character of the file name is / or not.
The following items may be associated with a directory entry, and therefore, each is a subclass of the class open-file-object, since it is legal to open any directory entry:
By convention, the directory /dev contains one entry for each device on the system. Frequently, system administrators leave large numbers of nonexistant devices here, since the default system installation includes huge numbers of devices that nobody has. Here is a list of the /dev file of a real system:
bpf0 disk0s7 ptyp5 ptyq2 ptyqf stdout ttypa ttyq7 bpf1 disk0s8 ptyp6 ptyq3 rdisk0 tty ttypb ttyq8 bpf2 disk0s9 ptyp7 ptyq4 rdisk0s1 tty.modem ttypc ttyq9 bpf3 fd ptyp8 ptyq5 rdisk0s2 ttyp0 ttypd ttyqa console klog ptyp9 ptyq6 rdisk0s3 ttyp1 ttype ttyqb cu.modem kmem ptypa ptyq7 rdisk0s4 ttyp2 ttypf ttyqc disk0 mem ptypb ptyq8 rdisk0s5 ttyp3 ttyq0 ttyqd disk0s1 null ptypc ptyq9 rdisk0s6 ttyp4 ttyq1 ttyqe disk0s2 ptyp0 ptypd ptyqa rdisk0s7 ttyp5 ttyq2 ttyqf disk0s3 ptyp1 ptype ptyqb rdisk0s8 ttyp6 ttyq3 zero disk0s4 ptyp2 ptypf ptyqc rdisk0s9 ttyp7 ttyq4 disk0s5 ptyp3 ptyq0 ptyqd stderr ttyp8 ttyq5 disk0s6 ptyp4 ptyq1 ptyqe stdin ttyp9 ttyq6Some of these devices are obvious: /dev/disk0 is the disk. /dev/fd is the floppy disk. The fact that the system doesn't have a floppy disk isn't apparent from the /dev file! Some are curious: /dev/null references a driver that returns EOF for all read attempts and ignores all write attempts. If a program insists on producing huge ammounts of output that nobody wants, redirecting it to /dev/null is a convenient way to suppress that output. /dev/kmem is a driver that allows access to the kernel memory of the machine as if it was an I/O device -- this is useful as a debugging tool. /dev/mem is similar, providing access to the memory of the current running process.
The huge array of ttyp and ptyp devices refer to drivers that exist for network interprocess communication. These look like interactive terminals to processes that read or write them, but they are connected by the network driver, so they may be used to communicate with remote systems. They also get used to communicate locally, so each open window, for example, is typically connected to one of these by the window manager.
Open disk files have an interface that is extremely similar to open disks! In fact, it is proper to think in terms of the same I/O driver used for both, except that there is a virtual disk address to physical disk address translator between the disk file interface and the physical disk. This is similar, in an abstract sense, to the function of the MMU, but it is done entirely in software within the implementation of the file system!