Chapter 9
OSKit File System Framework

9.1 Introduction

The OSKit file system framework has parallel goals to the OSKit device driver framework; the framework provides a file system interface specification designed to allow existing filesystem implementations to be borrowed from well-established operating systems in source form and used mostly unchanged to provide file system support in new operating systems. The framework is also designed to allow file systems to be implemented in diverse ways and then composed together.

The OSKit file system framework encompasses a collection of COM interfaces used by the client operating system to invoke the file system libraries, and a collection of interfaces used by the file system libraries to request services from the client operating system. The individual file system libraries supply additional interfaces to the client operating system for initialization, and may supply additional interfaces for supporting extended features unique to particular file system implementations.

The OSKit File, Directory and Open File COM interfaces inherit from several general COM interfaces, such as Stream, Absolute IO and POSIX IO. The inheritance relationships among these COM interfaces are shown in Figure 9.1. Refer to Section 4 for more details on COM interfaces.


PIC

Figure 9.1: Interface hierarchy. Solid lines indicate that the child interface directly inherits the methods of the parent interface. Dashed lines indicate that the child interface may optionally support the parent interface; this may be determined by querying the object.

9.2 oskit_principal: Principal Interface

The oskit_principal COM interface defines an interface for obtaining identity information about a principal (aka subject or client). The filesystem libraries obtain an oskit_principal object for the current client by invoking oskit_get_call_context on oskit_principal_iid.

The oskit_principal COM interface inherits from IUnknown, and has one additional method:

getid:
Obtain identity attributes of principal.

9.2.1 getid: Get the identity attributes of this principal

SYNOPSIS

#include <oskit/principal.h>

oskit_error_t oskit_principal_getid(oskit_principal_t *p, [out] oskit_identity_t *out_id);

DIRECTION

filesystem library --> client OS

DESCRIPTION

This method returns the identity attributes of this principal. out_id is a pointer to an oskit_identity_t structure defined as follows:

struct oskit_identity {

  oskit_uid_t uid; /* effective user id */
  oskit_gid_t gid; /* effective group id */
  oskit_u32_t ngroups; /* number of groups */
  oskit_u32_t *groups; /* supplemental groups */

};
PARAMETERS
p:
The principal whose identity is desired.
out_id:
The identity attributes of this principal.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.3 oskit_filesystem: File System Interface

The oskit_filesystem COM interface defines an interface for operating on a filesystem, which is a logical collection of files and a tree-structured namespace with a single root. The filesystem itself exists independent of any given namespace, for there is no notion of mounts in this interface. That functionality must be implemented at a higher level.

The oskit_filesystem COM interface inherits from IUnknown, and has the following additional methods:

statfs:
Get attributes of this filesystem
sync:
Write this filesystem’s data to permanent storage
getroot:
Get this filesystem’s root directory
remount:
Update this filesystem’s mount flags
unmount:
Forcibly unmount this filesystem
lookupi:
Lookup a file by inode number

9.3.1 statfs: Get attributes of this filesystem

SYNOPSIS

#include <oskit/fs/filesystem.h>

oskit_error_t oskit_filesystem_statfs(oskit_filesystem_t *f, [out] oskit_statfs_t *out_stats);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method returns the attributes of this filesystem. out_stats is a pointer to an oskit_statfs_t structure defined as follows:

struct oskit_statfs {

  oskit_u32_t bsize; /* file system block size */
  oskit_u32_t frsize; /* fundamental file system block size */
  oskit_u32_t blocks; /* total blocks in fs in units of frsize */
  oskit_u32_t bfree; /* free blocks in fs */
  oskit_u32_t bavail; /* free blocks avail to non-superuser */
  oskit_u32_t files; /* total file nodes in file system */
  oskit_u32_t ffree; /* free file nodes in fs */
  oskit_u32_t favail; /* free file nodes avail to non-superuser */
  oskit_u32_t fsid; /* file system id */
  oskit_u32_t flag; /* mount flags */
  oskit_u32_t namemax; /* max bytes in a file name */

};
PARAMETERS
f :
The filesystem whose attributes are desired.
out_stats:
The attributes of the specified filesystem.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.3.2 sync: Synchronize in-core filesystem data with permanent storage

SYNOPSIS

#include <oskit/fs/filesystem.h>

oskit_error_t oskit_filesystem_sync(oskit_filesystem_t *f, oskit_bool_t wait);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method writes all of this filesystem’s data back to permanent storage. If wait is TRUE, then the call does not return until all pending data has been completely written.

PARAMETERS
f :
The filesystem to sync.
wait:
TRUE if the call should wait for completion.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.3.3 getroot: Return a reference to the root directory of this filesystem

SYNOPSIS

#include <oskit/fs/filesystem.h>

oskit_error_t oskit_filesystem_getroot(oskit_filesystem_t *f, [out] oskit_dir_t **out_dir);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method returns a reference to the root directory of this filesystem. out_dir is a pointer to the oskit_dir COM interface for the root directory.

PARAMETERS
f :
The filesystem whose root directory is desired.
out_dir:
The oskit_dir COM interface for the root directory.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.3.4 remount: Update the mount flags of this filesystem

SYNOPSIS

#include <oskit/fs/filesystem.h>

oskit_error_t oskit_filesystem_remount(oskit_filesystem_t *f, oskit_u32_t flags);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method changes the mount flags associated with this filesystem. For example, this method might be used to change a filesystem from read-only to read-write, or vice versa.

PARAMETERS
f :
The filesystem whose flags are to be changed.
flags:
The new mount flags value.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.3.5 unmount: Forcibly unmount this filesystem

SYNOPSIS

#include <oskit/fs/filesystem.h>

oskit_error_t oskit_filesystem_unmount(oskit_filesystem_t *f);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method forcibly unmounts this filesystem. Ordinarily, a filesystem is unmounted when the last reference to it is released; in contrast, this method forces an unmount regardless of external references to the filesystem, and is consequently unsafe. Subsequent attempts to use references to the filesystem or to use references to files within the filesystem may yield undefined results.

PARAMETERS
f :
The filesystem to be forcibly unmounted.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.3.6 lookupi: Lookup a file by inode number

SYNOPSIS

#include <oskit/fs/filesystem.h>

oskit_error_t oskit_filesystem_lookupi(oskit_filesystem_t *f, oskit_ino_t ino, [out] oskit_file_t **out_file);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method looks up a file given its inode number. If the inode number is invalid, the behavior is undefined.

PARAMETERS
f :
The filesystem to find the inode in.
ino:
The inode number of the file to find.
out_file:
Upon success, will point to a oskit_file_t for the file.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.4 oskit_file: File Interface

The oskit_file COM interface defines an interface for operating on a file. The interface does not imply any per-open state; per-open methods are defined by the oskit_openfile COM interface.

The oskit_file COM interface inherits from the oskit_posixio COM interface, and has the following additional methods:

sync:
Write this file’s data and metadata to permanent storage.
datasync:
Write this file’s data to permanent storage.
access:
Check accessibility of this file.
readlink:
Read the contents of this symbolic link.
open:
Create an open instance of this file.
getfs:
Get the filesystem in which this file resides.

Additionally, an oskit_file object may export a oskit_absio COM interface; this may be determined by querying the object.

9.4.1 sync: Write this file’s data and metadata to permanent storage

SYNOPSIS

#include <oskit/fs/file.h>

oskit_error_t oskit_file_sync(oskit_file_t *f, oskit_bool_t wait);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method synchronizes the in-core copy of this file’s data and metadata with the on-disk copy. If wait is TRUE, then the call does not return until all pending data has been completely written.

PARAMETERS
f :
The file to sync.
wait:
TRUE if the call should wait for completion.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.4.2 datasync: Write this file’s data to permanent storage

SYNOPSIS

#include <oskit/fs/file.h>

oskit_error_t oskit_file_datasync(oskit_file_t *f, oskit_bool_t wait);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method synchronizes the in-core copy of this file’s data with the on-disk copy. The file metadata need not be sychronized by this method. If wait is TRUE, then the call does not return until all pending data has been completely written.

PARAMETERS
f :
The file to sync.
wait:
TRUE if the call should wait for completion.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.4.3 access: Check accessibility of this file

SYNOPSIS

#include <oskit/fs/file.h>

oskit_error_t oskit_file_access(oskit_file_t *f, oskit_amode_t mask);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method checks whether the form of access specified by mask would be granted. mask may be any combination of OSKIT_R_OK (read access), OSKIT_W_OK (write access), or OSKIT_X_OK (execute access). If the access would not be granted, then this method will return the error that would be returned if the actual access were attempted.

PARAMETERS
f :
The file whose accessibility is to be checked.
mask:
The access mask.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.4.4 readlink: Read the contents of this symbolic link

SYNOPSIS

#include <oskit/fs/dir.h>

oskit_error_t oskit_file_readlink(oskit_file_t *f, char *buf, oskit_u32_t len, [out] oskit_u32_t *out_actual);

DIRECTION

client OS --> filesystem library

DESCRIPTION

If this file is a symbolic link, then this method reads the contents of the symbolic link into buf. No more than len bytes will be read. out_actual will be set to the actual number of bytes read.

PARAMETERS
f :
The symbolic link file.
buf :
The buffer into which the contents are to be copied.
len:
The maximum number of bytes to read.
out_actual:
The actual bytes read from the symlink.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

If the file is not a symbolic link, then OSKIT_E_NOTIMPL is returned.

9.4.5 open: Create an open instance of this file

SYNOPSIS

#include <oskit/fs/file.h>
#include <oskit/fs/openfile.h>

oskit_error_t oskit_file_open(oskit_file_t *f, oskit_oflags_t flags, [out] oskit_openfile_t **out_openfile);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method returns an oskit_openfile COM interface for an open instance of this file. flags specifies the file open flags, as defined in <oskit/fs/file.h>. If OSKIT_O_TRUNC is specified, then the file will be truncated to zero length.

This method may only be used on regular files and directories. Directories may not be opened with OSKIT_O_WRONLY, OSKIT_O_RDWR or OSKIT_O_TRUNC.

This method may return success but set *out_openfile to NULL, indicating that the requested operation is allowed but the filesystem does not support per-open state; the client operating system must provide this functionality.

PARAMETERS
f :
The file to open.
flags:
The open flags.
out_openfile:
The oskit_openfile COM interface.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.4.6 getfs: Get the filesystem in which this file resides

SYNOPSIS

#include <oskit/fs/file.h>

oskit_error_t oskit_file_getfs(oskit_file_t *f, [out] oskit_filesystem_t **out_fs);

DIRECTION

client OS --> filesystem library

DESCRIPTION

Returns the oskit_filesystem COM interface for the filesystem in which this file resides.

PARAMETERS
f :
The file whose filesystem is desired.
out_fs:
The filesystem in which the file resides.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.5 oskit_dir: Directory Interface

The oskit_dir COM interface defines an interface for operating on a directory. The interface does not imply any per-open state; per-open methods are defined by the oskit_openfile COM interface.

The oskit_dir COM interface inherits from the oskit_file COM interface, and has the following additional methods:

lookup:
Lookup a file in this directory.
create:
Create a regular file in this directory.
link:
Link a file into this directory.
unlink:
Unlink a file from this directory.
rename:
Rename a file from this directory.
mkdir:
Create a directory in this directory.
rmdir:
Remove a directory from this directory.
getdirentries:
Read entries from this directory.
mknod:
Create a special file in this directory.
symlink:
Create a symlink in this directory.
reparent:
Create a virtual directory from this directory.

Additionally, an oskit_dir object may export a oskit_absio COM interface; this may be determined by querying the object.

All name parameters to directory methods must be a single component, ie an entry in one of the specified directories. With the exception of rename, name parameters always refer to entries in the target directory itself.

9.5.1 lookup: Look up a file in this directory

SYNOPSIS

#include <oskit/fs/dir.h>

oskit_error_t oskit_dir_lookup(oskit_dir_t *d, const char *name, [out] oskit_file_t **out_file);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method returns the oskit_file COM interface for the file named by name in this directory. The name may only be a single component; multi-component lookups are not supported. If the file is a symbolic link, then out_file will reference the symbolic link itself.

PARAMETERS
d:
The directory to search.
name:
The name of the file.
out_file:
The oskit_file COM interface for the file.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.5.2 create: Create a regular file in this directory

SYNOPSIS

#include <oskit/fs/dir.h>

oskit_error_t oskit_dir_create(oskit_dir_t *d, const char *name, oskit_bool_t excl, oskit_mode_t mode, [out] oskit_file_t **out_file);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method is the same as oskit_dir_lookup, except that if the file does not exist, then a regular file will be created with the specified name and mode.

If a file with name already exists, and excl is TRUE, then OSKIT_EEXIST will be returned.

The name may only be a single component; multi-component lookups are not supported.

PARAMETERS
d:
The directory to search.
name:
The name of the file.
excl:
TRUE if an error should be returned if the file exists
mode:
The file mode to use if creating a new file.
out_file:
The oskit_file COM interface for the file.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.5.3 link: Link a file into this directory

SYNOPSIS

#include <oskit/fs/dir.h>

oskit_error_t oskit_dir_link(oskit_dir_t *d, const char *name, oskit_file_t *file);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method adds an entry for file into this directory, using name for the new directory entry. Typically, this is only supported if file resides in the same filesystem as d.

file may not be a symbolic link.

The name may only be a single component; multi-component lookups are not supported.

PARAMETERS
d:
The directory to search.
name:
The name for the new link.
file:
The file to be linked.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.5.4 unlink: Unlink a file from this directory

SYNOPSIS

#include <oskit/fs/dir.h>

oskit_error_t oskit_dir_unlink(oskit_dir_t *d, const char *name);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method removes the directory entry for name from d.

The name may only be a single component; multi-component lookups are not supported.

PARAMETERS
d:
The directory to search.
name:
The name of the file to be unlinked.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.5.5 rename: Rename a file from this directory

SYNOPSIS

#include <oskit/fs/dir.h>

oskit_error_t oskit_dir_rename(oskit_dir_t *old_dir, const char *old_name, oskit_dir_t *new_dir, const char *new_name);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method atomically links the file named by old_name in old_dir into new_dir, using new_name for the new directory entry, and unlinks old_name from old_dir.

If a file named new_name already exists in new_dir, then it is first removed. In this case, the source and target files must either both be directories or both be non-directories, and if the target file is a directory, it must be empty.

Typically, this is only supported if new_dir resides in the same filesystem as old_dir.

The old_name and new_name may each only be a single component; multi-component lookups are not supported.

PARAMETERS
old_dir:
This directory.
old_name:
The name of the file to be renamed.
new_dir:
The target directory.
new_name:
The name for the new directory entry.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.5.6 mkdir: Create a subdirectory in this directory

SYNOPSIS

#include <oskit/fs/dir.h>

oskit_error_t oskit_dir_mkdir(oskit_dir_t *d, const char *name, oskit_mode_t mode);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method creates a new subdirectory in this directory, with the specified name and mode.

The name may only be a single component; multi-component lookups are not supported.

PARAMETERS
dir:
The directory in which to create the subdirectory.
name:
The name of the new subdirectory.
mode:
The mode for the new subdirectory.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.5.7 rmdir: Remove a subdirectory from this directory

SYNOPSIS

#include <oskit/fs/dir.h>

oskit_error_t oskit_dir_rmdir(oskit_dir_t *d, const char *name);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method removes the subdirectory named name from this directory. Typically, this is only supported if the subdirectory is empty.

The name may only be a single component; multi-component lookups are not supported.

PARAMETERS
dir:
The directory in which the subdirectory resides.
name:
The name of the subdirectory.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.5.8 getdirentries: Read one or more entries from this directory

SYNOPSIS

#include <oskit/fs/dir.h> #include <oskit/fs/dirents.h>

oskit_error_t oskit_dir_getdirentries(oskit_dir_t *d, oskit_u32_t *inout_ofs, oskit_u32_t nentries, [out] oskit_dirents_t **out_dirents);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method reads one or more entries from this directory. On entry, inout_ofs contains the offset of the first entry to be read. Before returning, this method updates the value at inout_ofs to contain the offset of the next entry after the last entry returned in out_dirents. The returned value of inout_ofs is opaque; it should only be used in subsequent calls to this method.

This method will return at least nentries entries if there are at least that many entries remaining in the directory; however, this method may return more entries.

The return value out_dirents will contain a pointer to an oskit_dirents_t COM object, which holds the individual directory entries. The number of actual entries returned can be determined with the oskit_dirents_getcount method. Each successive directory entry is accessed using the oskit_dirents_getnext method. Once all the entries have been read, the dirents COM object should be released with the oskit_dirents_release method.

The data structure to retrieve the individual entries is:

struct oskit_dirent {

  oskit_size_t namelen; /* name length */
  oskit_ino_t ino; /* entry inode */
  char name[0]; /* entry name */

};

The namelen field should be initialized to the amount of storage available for the name. Upon return from the getnext method, namelen will be set to the actual length of the name. The pointer that is passed should obviously be large enough to hold the size of the structure above, plus the additional size of the character array.

PARAMETERS
d:
The directory to read.
inout_ofs:
On entry, the offset of the first entry to read. On exit, the offset of the next entry to read.
nentries:
The minimum desired number of entries.
out_dirents:
The directory entries oskit_dirents_t COM object.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.5.9 mknod: Create a special file node in this directory

SYNOPSIS

#include <oskit/fs/dir.h>

oskit_error_t oskit_dir_mknod(oskit_dir_t *d, const char *name, oskit_mode_t mode, oskit_dev_t dev);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method creates a device special file in this directory, with the specified name and file mode, and with the specified device number dev. The device number is opaque to the filesystem library.

The name may only be a single component; multi-component lookups are not supported.

PARAMETERS
d:
The directory in which to create the node
name:
The name of the new node.
mode:
The mode for the new node.
dev:
The device number for the new node.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.5.10 symlink: Create a symbolic link in this directory

SYNOPSIS

#include <oskit/fs/dir.h>

oskit_error_t oskit_dir_symlink(oskit_dir_t *d, const char *link_name, char *dest_name);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method creates a symbolic link in this directory, named link_name, with contents dest_name.

The link_name may only be a single component; multi-component lookups are not supported.

PARAMETERS
d:
The directory in which to create the symlink.
link_name:
The name of the new symlink.
dest_name:
The contents of the new symlink.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.5.11 reparent: Create a virtual directory from this directory

SYNOPSIS

#include <oskit/fs/dir.h>

oskit_error_t oskit_dir_reparent(oskit_dir_t *d, oskit_dir_t *parent, [out] oskit_dir_t **out_dir);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method creates a virtual directory out_dir which refers to the same underlying directory as d, but whose logical parent directory is parent. If parent is NULL, then the logical parent directory of out_dir will be itself.

Lookups of the parent directory entry (’..’) in the virtual directory will return a reference to the logical parent directory.

This method may be used to provide equivalent functionality to the Unix chroot operation.

PARAMETERS
d:
The directory
parent:
The logical parent directory
out_dir:
The oskit_dir COM interface for the virtual directory
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.6 oskit_openfile: Open File Interface

The oskit_openfile COM interface defines an interface for operating on an open instance of a file.

The oskit_openfile COM interface inherits from the oskit_stream COM interface, and has the following additional method:

getfile:
Get the underlying file object to which this open file refers.

Additionally, an oskit_openfile object may export a oskit_absio COM interface; this may be determined by querying the object.

9.6.1 getfile: Get the underlying file object to which this open file refers

SYNOPSIS

#include <oskit/fs/openfile.h>

oskit_error_t oskit_openfile_getfile(oskit_openfile_t *f, [out] oskit_file_t **out_file);

DIRECTION

client OS --> filesystem library

DESCRIPTION

This method returns the oskit_file COM interface for the underlying file object to which this open file refers.

PARAMETERS
f :
The open file whose underlying file is desired.
out_file:
The oskit_file COM interface for the underlying file.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.

9.7 Dependencies on the Client Operating System

This section describes the interfaces which must be provided by the client operating system to the filesystem library.

These interfaces consist of:

oskit_get_call_context:
Obtain information about client context.

9.7.1 oskit_get_call_context: Get the caller’s context

SYNOPSIS

#include <oskit/com.h>

oskit_error_t oskit_get_call_context(oskit_guid_t *iid, [out] void **out_if);

DIRECTION

filesystem library --> client OS

DESCRIPTION

This function returns the requested COM interface for the current caller.

Typically, this is used to obtain the oskit_principal object for the current client of the filesystem library.

PARAMETERS
iid:
The desired COM interface identifier.
out_if :
The COM interface.
RETURNS

Returns 0 on success, or an error code specified in <oskit/error.h>, on error.