Proposal for a filesystem API

Hi WebApps!

There has been a lot of controversy about implementing a file system API in
other browsers. Firefox and IE already support storing files in IndexedDB,
but it seems that web developers need something simpler in some cases and
there's also the filesystem URL scheme that is not covered by files in
IndexedDB.

This new proposal is heavily based on Apple's minimal filesystem API
proposal [1], on Mozilla's DeviceStorage API 2 [2] and on Mozilla's current
FileHandle API [3]. It is only designed for the use case of sandboxed local
file storage.

In Firefox, the FileHandle API provides the ability to write to a file, as
well as the locking mechanisms needed to allow writing safely. The
FileHandle interface is currently supported in IndexedDB and it is also
planned for DeviceStorage API. However, the new proposal for the file
system API uses a modified version of the FileHandle API. The FileHandle
interface acts exactly like LockedFile in the current FileHandle API. I.e.
it represents an opened file and it automatically closes if you stop
posting requests against it (like transactions in IDB except it doesn't
provide any rollback functionality, i.e. only Isolation of the ACID).

There's a documentation for the current FileHandle API [4], which contains
detailed description of the LockedFile interface (that now becomes the new
FileHandle interface).


Here's the proposed file system API:

Getting the root directory:

enum PersistenceType { "temporary", "permanent" };

dictionary FilesystemParameters
{
  PersistenceType storage;
};

partial interface Navigator {
  Directory getSandboxedFilesystem(optional FilesystemParameters
parameters);
};


The Directory interface:

enum FileOpenMode { "read", "write", "append" };

interface Directory {
  readonly attribute DOMString name;

  // Asynchronously returns boolean true or false to indicate success.
  Future<boolean>
  create(DOMString name, optional Blob blob);

  // Asynchronously returns the newly created Directory.
  Future<Directory>
  makeDirectory(DOMString name);

  // Asynchronously returns a File or Directory. If the entry is a File
  // then get() is a shortcut for openForReading().getFile()
  Future<File or Directory>
  get(DOMString name);

  // Deletes a file or directory; Asynchronously returns boolean true or
false
  // to indicate success.
  Future<boolean>
  remove(DOMString name);

  // Atomically renames a file or directory; Asynchronously returns boolean
  // true or false to indicate success.
  Future<boolean>
  rename(DOMString oldName, DOMString newName);

  // alternative method for rename():

  // Atomically moves or renames a file or directory; Asynchronously returns
  // boolean true or false to indicate success.
  Future<boolean>
  moveTo((DOMString or File or Directory) entry, DOMString newName,
                optional Directory newParentDirectory);

  // TODO: maybe add copyTo() method

  // Asynchronously returns a FileHandle; error if called on a Directory.
  // If a File is passed, it must be a descendant of this directory.
  Future<FileHandle>
  openRead((DOMString or File) file);

  // Asynchronously returns a FileHandleWritable;
  // error if called on a Directory.
  // If a File is passed, it must be a descendant of this directory.
  Future<FileHandleWritable>
  openWrite((DOMString or File) file);

  // Asynchronously returns a FileHandleWritable;
  // error if called on a Directory.
  // If a File is passed, it must be a descendant of this directory.
  Future<FileHandleWritable>
  openAppend((DOMString or File) file);

  // alternative method for openRead(), openWrite(), openAppend():

  Future<(FileHandle or FileHandleWritable)>
  open((DOMString or File) file, optional FileOpenMode mode);

  // TODO: Solve futures way of doing a cursor-style API
  // Asynchronously returns File or Directory objects.
  CursorFuture<File or Directory>
  enumerateShallow(); // or readEntries();

  // Asynchronously returns File objects
  CursorFuture<File>
  enumerateDeep(); // or readEntriesRecursively();
};


The FileHandle/FileHandleWritable interface, representing a file open in
read, write or append mode.

dictionary MetadataParameters
{
  boolean size = false;
  boolean lastModified = false;
};

interface FileHandle
{
  // "read" or "write" or "append"
  readonly attribute FileOpenMode mode;

  readonly attribute boolean active;

  // Offset in the file. This value is changed automatically after every
read
  // and every write. Reads and writes always start at the location.
  // null means end-of-file
  attribute any location;

  // Upon success, you receive a read-only "snapshot" of the file's content
in
  // the form of a File instance (that can be used anywhere a Blob is
accepted,
  // like FileReader, XMLHttpRequest, IndexedDB, etc).
  Future<File> getFile();

  // Asynchronously returns an ArrayBuffer of the given size. The operation
  // starts at the location. Moving the location by the number of bytes
read.
  ProgressFuture<ArrayBuffer>
  readAsArrayBuffer(unsigned long long size);

  // Asynchronously returns a string of the given size with the provided
  // encoding. The operation starts at the location.
  // Moving the location by the number of bytes read.
  ProgressFuture<DOMString>
  readAsText(unsigned long long size, optional DOMString encoding);

  // Asynchronously returns an object with requested metadata.
  Future<object>
  getMetadata(optional MetadataParameters parameters);

  // Prevents any further operations from being placed against this
FileHandle.
  void close();

  // Immediately releases the lock and stops any pending or running
operations.
  void abort();

  [SetterThrows]
  attribute EventHandler oncomplete;

  [SetterThrows]
  attribute EventHandler onabort;

  [SetterThrows]
  attribute EventHandler onerror;
};

interface FileHandleWritable : FileHandle
{
  // Asynchronously returns the success or the failure of the write
operation.
  // The write starts at the location, moving the location by the number of
  // bytes written.
  ProgressFuture<boolean>
  write((DOMString or ArrayBuffer or ArrayBufferView or Blob) value);

  // Asynchronously returns the success or the failure of the truncate
  // operation.
  Future<boolean>
  truncate(optional unsigned long long size);

  // Asynchronously returns the success or the failure of the flush
operation.
  // This forces the buffered data to be transferred to disk. If the
operation
  // was successful, you are guaranteed that if the application crashes or
is
  // inadvertently interrupted, the data is on the disk.
  Future<boolean>
  flush();
};


Getting persistent filesystem URLs:

partial interface URL {
  // Gets a persistent URL for a File, if it's part of a local filesystem;
  // otherwise returns null
  DOMString? getPersistentURL(File file);
}


[1] https://trac.webkit.org/wiki/MinimalFileStorage
[2] https://wiki.mozilla.org/WebAPI/DeviceStorageAPI2
[3] https://wiki.mozilla.org/WebAPI/FileHandleAPI
[4] https://developer.mozilla.org/en-US/docs/WebAPI/FileHandle

Jan

Received on Thursday, 25 April 2013 16:18:10 UTC