Pyr8 User's Manual

« The Capability API | HTTP Client API »

The Filesystem API

The pyr8 Filesystem API provides the local container’s filesystem as a service. By default, the pyr8 exposes the local Unix directory jsapi_fsroot as the filesystem’s root Directory capability. This can be set using the fs flag as shown below.

bash$ pyr8 --fs=path/to/fsroot/

The pyr8 daemon will accept any directory for which the user has permission. If the root directory cannot be opened at initialization time, the server will exit with an error message.

Unlike traditional filesystems, there is no filesystem-specific permissions model. Rather, pyr8’s capabilities model is used to control access. The usual rules of capabilities apply with the following notable consequences:

  • A thread holding the capability to a directory holds capabilities to every descendant.
  • If a thread does not directly hold the capability to an ancestor, it cannot be recovered from its descendant.

The second consequence is notable, since most filesystem APIs permit parent directory traversal. However, parent traversal has been a rich source of both functional and security bugs. As a result, the feature is elided in the core API.

Deployments

The filesystem is guaranteed to live as long as the pyr8 process itself, but no longer. The PyrOS deployment system may keep container filesystems and re-use them, but the filesystem does not guarantee atomic operations or consistency. Applications that require data consistency on the local filesystem should use transactions logs and must accept rollbacks under some circumstances. Applications requiring both consistency and atomicity must use a networked API.

The Directory Class

A directory is a container class containing file objects and directory objects.

At initialization, the process’s root directory is bound to pyr8.fs. Any directory capability can be provided to other threads, granting shared access to the underlying container filesystem.

Methods

All methods throw an exception if the underlying C++ binding is invalid, e.g. if the JavaScript object was somehow incorrectly constructed without a bound C++ object. This should never happen unless pyr8 itself has been extended with custom C++ code.

cap(): Capability<Directory>
Returns a C++-backed capability object for this directory.
close(): boolean
Closes this directory.
create(name: string): File
Opens this directory and creates a new file with the given name in this directory.
createDir(name: string): Directory
Opens this directory and creates a new directory with the given name in this directory.
list(): array
Opens this directory and returns a list of unopened file objects.
listDirs(): array<Directory>
Opens this directory and returns a list of unopened directory objects.
name(): string
Returns the name of this directory.
open(name: string): File
Opens this directory and opens a file object by name.
openDir(name: string): Directory
Opens this directory and opens a subdirectory object by name.
unlink(name: string): boolean
Opens this directory and deletes a file by name. This method is not synchronized. File operations on an unlinked file in other threads will succeed; when all filehandles to the file are closed, the filesystem may collect the space.
unlinkAll(): boolean
Opens this directory and deletes all files and directories in the given directory. This method is not synchronized. As with unlink, other threads doing file operations on these files and directories will succeed, but once the file handles are released, the space may be collected.

When the standard library has been loaded, the Directory delegate class does not have a cap method, and anywhere a method takes a filename it also allows a path relative to this directory.

The File Class

A file is an object that exposes a read/write API to local storage. Bytes written to a file have a zero-indexed position and the object is seekable in the usual way. Local storage is not guaranteed to be implemented by physical, permanent storage: under some circumstances, the file object may be implemented by memory. No files are created at pyr8 initialization time. Files can be created with the create() and createdir() methods of a directory object.

Methods

All methods throw an exception if the underlying C++ binding is invalid, e.g. if the JavaScript object was somehow incorrectly constructed without a bound C++ object. This should never happen unless pyr8 itself has been extended with custom C++ code.

cap(): Capability<File>
Returns a C++-backed capability object for this file.
close(): void
Closes this file.
name(): string
Returns the name of this file.
read(amount: int32): string
Opens this file and reads and returns up to amount bytes of data from the current position.
seek(position: int32): int32
Opens this file and seeks to position. Returns the new position, which may differ from the requested position, e.g. if the requested position is beyond the last byte written.
write(data: string): int32
Opens this file and writes data. Returns the amount actually written, which may differ from the length of the string data. The write method will throw an exception if no arguments are provided or if an unrecoverable error occurs.

When the standard library has been loaded, the File delegate class does not have the cap method.

« The Capability API | HTTP Client API »