-
Notifications
You must be signed in to change notification settings - Fork 110
Filesystem
Basekernel has an abstract filesystem interface (fs.h) and two filesystem implementations:
cdromfs
reads iso9660 cdroms (atapi device) and diskfs
provides a simple unix-like read/write
filesystem for hard disks (ata device).
The abstract filesystem deals with three types of objects:
Name | Details |
---|---|
struct fs |
the driver for a specific filesystem like cdromfs or diskfs
|
struct fs_volume |
an instance of a mounted filesystem on a device |
struct fs_dirent |
an instance of a file or a directory on a volume |
With kernel code, the steps to accessing a file on a specific device are this:
const struct fs *fs = fs_get("cdromfs");
struct device *device = device_open("atapi",2);
struct fs_volume *v = fs_volume_mount(fs,device);
struct fs_dirent *root = fs_volume_root(v);
struct fs_dirent *d = fs_dirent_traverse(root,"/data/example.txt")
while(fs_dirent_read(d, buffer, 1000) > 0) {
// do something with read text
}
fs_dirent_close(d);
fs_dirent_close(root);
fs_volume_close(v);
device_close(device);
Note that dirents, volumes, and devices are all reference counted, and each maintains a reference on its parent. So, it is safe to close
the device, root directory, and volume if you have no other use for them: they will be deleted when the last reference is removed.
In most places throughout the kernel, it is not necessary to open a specific device or volume. Rather, each process already has a filesystem mounted and knows its root directory and current working directory. To map a path name into a fs_dirent
, call fs_resolve
which evaluates a path name within the context of the current process, and returns a fs_dirent
. This object must be closed when no longer needed. For example:
struct fs_dirent *d = fs_resolve("/data/example.txt");
fs_dirent_read(d,buffer,length);
fs_dirent_close(d)
The common aspects of filesystems are in fs.c
. Most functions here implements some basic sanity checking
on a request, perform reference counting, and pass the operation on to the underlying filesystem.
A few functions have added functionality over the basic filesystem driver operations:
-
fs_dirent_traverse
resolves multiple path elements by callingfs_dirent_lookup
multiple times. For example,fs_dirent_traverse(d,"/a/b/c")
callsfs_dirent_lookup(d,"a")
thenfs_dirent_lookup(x,"b")
etc, and returns the final result. -
fs_dirent_read
reads arbitrary ranges from files by callingread_block
on the underlying filesystem, and then assembling multiple or partial blocks as needed. Same withfs_dirent_write
Users can mount filesystems as a name and switch between them using chdir()
This is the current interface for user-level programs
Name | Details |
---|---|
open |
gets a file, or opens a new one if it doesn't exist, and returns a file pointer |
close |
deallocates a file pointer |
mount |
mounts a device as a certain type of filesystem and assigns it a name |
read |
reads a specified number of bytes to a buffer |
write |
writes a specified number of bytes to a buffer |
chdir |
changes the current directory |
Right now, chdir
is used to specify the context of the file-based syscalls (open, close, read, write), and those syscalls do not take a full filename with a device name, i.e. C:/filename
.
There are plenty more things we need to include, but this is enough for basic demo purposes.
Name | Details |
---|---|
ktable |
an array of kobject pointers, some representing files |
root_dir |
the current working directory for the process |
current_dir |
the current working directory for the process |