File Wrappers

Last updated: [98/05/14 Chip]

This page was written by Chip, based on Arturo's excellent template.

Introduction

The file wrapper subsystem provides an alternative API for Java file I/O. It provides essentially the same functionality as the standard java.io classes (if fact, it is built on top of them), but does so in a way that is capability secure and Vat-safe. The idea is to treat file and directory accessors as the objects from which file access is derived, rather than allowing file name strings to designate access.

Requirements

The principal requirement of the file wrapper subsystem was to provide a Vat-safe means for objects running in the Vat to access files. The standard Java file access classes are not suitable because they grant access via static methods and variables (thus preventing control over which objects can access what) and because they cannot be made to behave appropriately in a quake (either by surviving or by letting themselves be cleanly smashed).

Architecture

The ec.e.file package provides capability-secure file access to guest objects in the Vat. This overview describes the basic architecture of the package: what the classes are and how they relate to each other. For the specific details of the interfaces of these classes, consult the appropriate javadoc pages.

Files and directories are represented as objects. There is a set of objects for files and a set of objects for directories. Within each set, different classes of object encapsulate different sorts of access to the files or directories which their instances describe.

There are three varieties of directory object:

EReadableDirectory - read-only access to contained files and directories

EAccessibleDirectory - read-only access to contained directories, edit access to contained files

EEditableDirectory - edit access to contained files and directories

And three varieties of file object:

EReadableFile - read-only access to a file, optionally random access

EAppendableFile - append-only write access to a file

EEditableFile - read/write access to a file, optionally random access

All of the objects of classes EXxxxDirectory or EXxxxFile are instances of EDirectoryEntry and support a common interface that allows you to determine if the described entity in fact exists, find out if it is a file or directory, and find out if it is contained by a particular directory.

All the EXxxxDirectory objects can provide a list of their contents, in the form of a ReadOnlyHashtable which maps from Strings to EDirectoryEntry objects (org.erights.e.elib.util.ReadOnlyHashtable works like a regular Java hashtable, except that you can't modify it).

From an EReadableDirectory object you can obtain EReadableDirectory and EReadableFile objects for the directories and files within that directory.

From an EAccessibleDirectory object you can obtain EAccessibleDirectory and EEditableFile objects for the directories and files within that directory. In addition, from an EAccessibleDirectory object you can obtain an EReadableDirectory object for the same directory.

From an EEditableDirectory object you can obtain EEditableDirectory and EEditableFile objects for the directories and files within that directory. In addition, from an EEditableDirectory object you can obtain an EReadableDirectory or EAccessibleDirectory object for the same directory. Furthermore, an EEditableDirectory object allows you to modify the directory it represents by adding, deleting, renaming and relocating the files and directories within it.

From an EReadableFile or an EEditable file object you can obtain an input stream for sequential read access or an EFileReader object for random access reading of the corresponding file.

From an EEditableFile object or an EAppendableFile object you can obtain an output stream for sequential write access (to the end of) the corresponding file.

From an EEditableFile object you can obtain an EFileEditor object for random access reading and writing of the corresponding file. In addition, from an EEditableFile object you can obtain an EReadableFile or EAppendableFile object for the same file.

Note that the file and directory access provided by the above described objects are circular in nature: the only way to get a file or directory object is from another file or directory object. This raises the question of how you get a file or directory object to begin with. The answer is that there is an EDirectoryRootMaker object (of which only one instance exists) which has the power to produce an EEditableDirectory object given only a string representing the pathname of the directory in question. The EDirectoryRootMaker object is generated at startup time and should be closely held.

The EFileReader and EFileEditor objects, as well as the input and output stream objects obtainable from EXxxxFile objects, are fragile. That is, they get smashed in a quake. Attempts to perform I/O after a quake will result in a SmashedException (which is a type of IOExcpetion). However, the EXxxxDirectory and EXxxxFile objects are sturdy. They survive a quake just fine, though do not guarantee that the state of the file system will be the same after the quake as before (they will, however, always present a correct view of the current state of the file system).

The input and output streams provided by the file classes are implemented by EInputStream and EOutputStream, which are streams that behave appropriately (i.e., the get smashed) in a quake. There is also an alternative version of EOutputStream called QuakeProofAppendFile whose behavior on return from a quake is to seek to the end of the file and resume writing.

The EStdio class provides access in the Vat to the standard I/O streams that the class System provides outside the Vat. The methods EStdio.out(), EStdio.in() and EStdio.err() correspond to the same input or output streams as System.out, System.in and System.err, respectively. The difference is that the streams provided by EStdio are sturdy whereas those provided by System are not. And yes, these are static methods; talk to MarkM or me about why we decided that these were OK even though they break one of the cardinal rules.

Off the shelf alternatives

The obvious alternative to using this package is simply to use the regular Java I/O classes, if Vat safety and/or capability security are not concerns.

Current implementation

Which directories on our tree does this subsystem cover?

All the classes in this subsystem are in the package ec.e.file, which are in the single directory ec4/javasrc/ec/e/file.

Is it JavaDoc'ed?

The file wrapper package is completely JavaDoc'd, except for a mysterious class of unknown provenenance called URLStreamMaker.

Testing and Debugging

In the older ec3 tree, in ec3/E/runtime/e/file, are a couple of test programs, FileTest.e and QuakeFileTest.e. These have not been converted for ec4 or later environments. The file wrapper package itself is fairly small and simple and has not required much further maintenance since it was first released. Thes test programs were fairly ad hoc and informal; they are probably not worth converting.

Design Issues

Open Issues

The future need for this package is debatable. In a future product which allows user-submitted Java code to run in our environment, the capability-secure aspects of this file access paradigm will be essential. However, the Vat-safety aspects are less critical now that we have switched to state-bundle persistence rather than orthogonal persistence. The paradigm is also somewhat awkward to use for programmers used to simply naming a file with a string. And there is a further question as to whether user-submitted Java code should be accessing files at all. On the other hand, the implementation has proven reasonably reliable and trouble free and we have a fair quantity of code in our source base which depends on it. Maintaining a capability-safe source base is probably a wise thing to do, all other cost factors being equal.