# Native File System

## Draft Community Group Report, 1 January 1970

This version:
  https://wicg.github.io/native-file-system/
Editor:
  Marijn Kruisselbrink (Google)

Copyright © 1970 the Contributors to the Native File System Specification, published by the Web Platform Incubator Community Group under the W3C Community Contributor License Agreement (CLA). A human-readable summary is available.

## Abstract

This document defines a web platform API that lets websites gain write access to the native file system. It builds on [FILE-API], but adds lots of new functionality on top.

## Status of this document

This specification was published by the Web Platform Incubator Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.

## 1. Introduction

This section is non-normative.

TODO

This provides similar functionality as earlier drafts of the [file-system-api] as well as the [entries-api], but with a more modern API.

## 2. Files and Directories

### 2.1. Concepts

A entry is either a file entry or a directory entry.

Each entry has an associated name.

A file entry additionally consists of binary data and a modification timestamp.

A directory entry additionally consists of a set of entries. Each member is either a file or a directory.

TODO: Explain how entries map to files on disk (multiple entries can map to the same file or directory on disk but doesn’t have to map to any file on disk).

### 2.2. The `FileSystemHandle` interface

    dictionary FileSystemHandlePermissionDescriptor {
      boolean writable = false;
    };

    [Exposed=(Window,Worker), SecureContext, Serializable]
    interface FileSystemHandle {
      readonly attribute boolean isFile;
      readonly attribute boolean isDirectory;
      readonly attribute USVString name;

      Promise<PermissionState> queryPermission(optional FileSystemHandlePermissionDescriptor descriptor = {});
      Promise<PermissionState> requestPermission(optional FileSystemHandlePermissionDescriptor descriptor = {});
    };

A `FileSystemHandle` object represents a entry. Each `FileSystemHandle` object is assocaited with a entry (a entry). Multiple separate objects implementing the `FileSystemHandle` interface can all be associated with the same entry simultaneously.

`FileSystemHandle` objects are serializable objects.

In the Origin Trial as available in Chrome 78, these objects are not yet serializable.

Their serialization steps, given value, serialized and forStorage are:

1. Set serialized.[[Origin]] to value’s relevant settings object's origin.

2. TODO

Their deserialization steps, given serialized and value are:

1. If serialized.[[Origin]] is not same origin with value’s relevant settings object's origin, then throw a `DataCloneError`.

2. TODO

handle . `isFile`

  Returns true iff handle is a `FileSystemFileHandle`.

handle . `isDirectory`

  Returns true iff handle is a `FileSystemDirectoryHandle`.

handle . `name`

  Returns the name of the entry represented by handle.

The `isFile` attribute must return true if the associated entry is a file entry, and false otherwise.

The `isDirectory` attribute must return true if the associated entry is a directory entry, and false otherwise.

The `name` attribute must return the name of the associated entry.

#### 2.2.1. The `queryPermission()` method

the currently described API here assumes a model where it is not possible to have a write-only handle. I.e. it is not possible to have or request write access without also having read access. There definitely are use cases for write-only handles (i.e. directory downloads), so we might have to reconsider this.

status = await handle . `queryPermission`({ `writable` = false })
status = await handle . `queryPermission()`

  Queries the current state of the read permission of this handle. If this returns `"prompt"` the website will have to call `requestPermission()` before any operations on the handle can be done. If this returns `"denied"` any operations will reject.

  Usually handles returned by `chooseFileSystemEntries` will initially return `"granted"` for their read permission state, however other than through the user revoking permission, a handle retrieved from IndexedDB is also likely to return `"prompt"`.

status = await handle . `queryPermission`({ `writable` = true })

  Queries the current state of the write permission of this handle. If this returns `"prompt"`, attempting to modify the file or directory this handle represents will require user activation and will result in a confirmation prompt being shown to the user. However if the state of the read permission of this handle is also `"prompt"` the website will need to call `requestPermission()`. There is no automatic prompting for read access when attempting to read from a file or directory.

The `queryPermission(descriptor)` method, when invoked, must run these steps:

1. TODO

#### 2.2.2. The `requestPermission()` method

status = await handle . `requestPermission`({ `writable` = false })
status = await handle . `requestPermission()`

  If the state of the read permission of this handle is anything other than `"prompt"`, this will return that state directly. If it is `"prompt"` however, user activation is needed and this will show a confirmation prompt to the user. The new read permission state is then returned, depending on the user’s response to the prompt.

status = await handle . `requestPermission`({ `writable` = true })

  If the state of the write permission of this handle is anything other than `"prompt"`, this will return that state directly. If the status of the read permission of this handle is `"denied"` this will return that.

  Otherwise the state of the write permission is `"prompt"` and this will show a confirmation prompt to the user. The new write permission state is then returned, depending on what the user selected.

The `requestPermission(descriptor)` method, when invoked, must run these steps:

1. TODO

### 2.3. The `FileSystemFileHandle` interface

    dictionary FileSystemCreateWriterOptions {
      boolean keepExistingData = false;
    };

    [Exposed=(Window,Worker), SecureContext, Serializable]
    interface FileSystemFileHandle : FileSystemHandle {
      Promise<File> getFile();
      Promise<FileSystemWriter> createWriter(optional FileSystemCreateWriterOptions options = {});
    };

`FileSystemFileHandle` objects are serializable objects. Their serialization steps and deserialization steps are the same as those for `FileSystemHandle`.

In the Origin Trial as available in Chrome 78, these objects are not yet serializable.

#### 2.3.1. The `getFile()` method

file = await fileHandle . `getFile()`

  Returns a `File` representing the state on disk of the entry represented by handle. If the file on disk changes or is removed after this method is called, the returned `File` object will likely be no longer readable.

The `getFile()` method, when invoked, must run these steps:

1. TODO

#### 2.3.2. The `createWriter()` method

writer = await fileHandle . `createWriter()`
writer = await fileHandle . `createWriter`({ `keepExistingData`: true/false })

  Returns a `FileSystemWriter` that can be used to write to the file. Any changes made through writer won’t be reflected in the file represented by fileHandle until its `close()` method is called. User agents try to ensure that no partial writes happen, i.e. the file represented by fileHandle will either contains its old contents or it will contain whatever data was written through writer up until `close()` was called.

  This is typically implemented by writing data to a temporary file, and only replacing the file represented by fileHandle with the temporary file when the writer is closed.

  If `keepExistingData` is `false` or not specified, the temporary file starts out empty, otherwise the existing file is first copied to this temporary file.

There has been some discussion around and desire for a "inPlace" mode for createWriter (where changes will be written to the actual underlying file as they are written to the writer, for example to support in-place modification of large files or things like databases). This is not currently implemented in Chrome. Implementing this is currently blocked on figuring out how to combine the desire to run malware checks with the desire to let websites make fast in-place modifications to existing large files.

The `createWriter(options)` method, when invoked, must run these steps:

1. TODO

### 2.4. The `FileSystemDirectoryHandle` interface

    dictionary FileSystemGetFileOptions {
      boolean create = false;
    };

    dictionary FileSystemGetDirectoryOptions {
      boolean create = false;
    };

    dictionary FileSystemRemoveOptions {
      boolean recursive = false;
    };

    [Exposed=(Window,Worker), SecureContext, Serializable]
    interface FileSystemDirectoryHandle : FileSystemHandle {
      Promise<FileSystemFileHandle> getFile(USVString name, optional FileSystemGetFileOptions options = {});
      Promise<FileSystemDirectoryHandle> getDirectory(USVString name, optional FileSystemGetDirectoryOptions options = {});

      // This really returns an async iterable, but that is not yet expressable in WebIDL.
      object getEntries();

      Promise<void> removeEntry(USVString name, optional FileSystemRemoveOptions options = {});
    };

`FileSystemDirectoryHandle` objects are serializable objects. Their serialization steps and deserialization steps are the same as those for `FileSystemHandle`.

In the Origin Trial as available in Chrome 78, these objects are not yet serializable.

Should we have separate getFile and getDirectory methods, or just a single getChild/getEntry method?

Having getFile methods in both FileSystemDirectoryHandle and FileSystemFileHandle, but with very different behavior might be confusing? Perhaps rename at least one of them (but see also previous issue).

Should getEntries be its own method, or should FileSystemDirectoryHandle just be an async iterable itself?

We will probably want some method to make it possible to compare two handles, and/or determine if one handle represents a descendant of another handle. Such a method will enable for example an IDE to detect that the user tries to open a file (through the file picker), where that file actually is part of the "project" the IDE has open, allowing the IDE to highlight the selected file in a directory tree.

#### 2.4.1. The `getFile()` method

fileHandle = await directoryHandle . `getFile`(name)
fileHandle = await directoryHandle . `getFile`(name, { `create`: false })

  Returns a handle for a file named name in the directory represented by directoryHandle. If no such file exists, this rejects.

fileHandle = await directoryHandle . `getFile`(name, { `create`: true })

  Returns a handle for a file named name in the directory represented by directoryHandle. If no such file exists, this creates a new file. If no file with named name can be created this rejects. Creation can fail because there already is a directory with the same name, because the name uses characters that aren’t supported in file names on the underlying file system, or because the user agent for security reasons decided not to allow creation of the file.

  This operation requires write permission, even if the file being returned already exists. If this handle doesn’t already have write permission, this could result in a prompt being shown to the user. To get an existing file without needing write permission, call this method with `{ `create`: false }`.

The `getFile(name, options)` method, when invoked, must run these steps:

1. TODO

#### 2.4.2. The `getDirectory()` method

subdirHandle = await directoryHandle . `getDirectory`(name)
subdirHandle = await directoryHandle . `getDirectory`(name, { `create`: false })

  Returns a handle for a directory named name in the directory represented by directoryHandle. If no such directory exists, this rejects.

subdirHandle = await directoryHandle . `getDirectory`(name, { `create`: true })

  Returns a handle for a directory named name in the directory represented by directoryHandle. If no such directory exists, this creates a new directory. If creating the directory failed, this rejects. Creation can fail because there already is a file with the same name, or because the name uses characters that aren’t supported in file names on the underlying file system.

  This operation requires write permission, even if the directory being returned already exists. If this handle doesn’t already have write permission, this could result in a prompt being shown to the user. To get an existing directory without needing write permission, call this method with `{ `create`: false }`.

The `getDirectory(name, options)` method, when invoked, must run these steps:

1. TODO

#### 2.4.3. The `getEntries()` method

for await (const handle of directoryHandle . `getEntries()`) {}

  Iterates over all entries whose parent is the entry represented by directoryHandle.

The `getEntries()` method, when invoked, must run these steps:

1. TODO

#### 2.4.4. The `removeEntry()` method

await directoryHandle . `removeEntry`(name)
await directoryHandle . `removeEntry`(name, { `recursive`: false })

  If the directory represented by directoryHandle contains a file named name, or an empty directory named name, this will attempt to delete that file or directory.

  Attempting to delete a file or directory that does not exist is considered success, while attempting to delete a non-empty directory will result in a promise rejection.

await directoryHandle . `removeEntry`(name, { `recursive`: true })

  Removes the entry named name in the directory represented by directoryHandle. If that entry is a directory, its contents will also be deleted recursively. recursively.

  Attempting to delete a file or directory that does not exist is considered success.

The `removeEntry(name, options)` method, when invoked, must run these steps:

1. TODO

### 2.5. The `FileSystemWriter` interface

    [Exposed=(Window,Worker), SecureContext]
    interface FileSystemWriter {
      Promise<void> write(unsigned long long position, (BufferSource or Blob or USVString) data);
      Promise<void> truncate(unsigned long long size);
      Promise<void> close();
    };

We want some kind of integration with writable streams. One possible option is to make FileStreamWriter inherit from WritableStream, but other options should be considered as well. <https://github.com/wicg/native-file-system/issues/19>

#### 2.5.1. The `write()` method

await writer . `write`(position, data)

  Writes the content of data into the file associated with writer at position position. If position is past the end of the file writing will fail and this method rejects.

  No changes are written to the actual file until on disk until `close()` is called. Changes are typically written to a temporary file instead.

The `write(position, data)` method, when invoked, must run these steps:

1. TODO

#### 2.5.2. The `truncate()` method

await writer . `truncate`(size)

  Resizes the file associated with writer to be size bytes long. If size is larger than the current file size this pads the file with zero bytes, otherwise it truncates the file.

  No changes are written to the actual file until on disk until `close()` is called. Changes are typically written to a temporary file instead.

The `truncate(size)` method, when invoked, must run these steps:

1. TODO

#### 2.5.3. The `close()` method

await writer . `close()`

  First flushes any data written so far to disk, and then closes the writer. No changes will be visible in the destination file until this method is called. Furthermore, if the file on disk changed between creating this writer and this invocation of `close()`, this will reject and all future operations on the writer will fail.

  This operation can take some time to complete, as user agents might use this moment to run malware scanners or perform other security checks if the website isn’t sufficiently trusted.

The `close()` method, when invoked, must run these steps:

1. TODO

## 3. Accessing native filesystem

### 3.1. The `chooseFileSystemEntries()` method

    enum ChooseFileSystemEntriesType { "open-file", "save-file", "open-directory" };

    dictionary ChooseFileSystemEntriesOptionsAccepts {
      USVString description;
      sequence<USVString> mimeTypes;
      sequence<USVString> extensions;
    };

    dictionary ChooseFileSystemEntriesOptions {
        ChooseFileSystemEntriesType type = "open-file";
        boolean multiple = false;
        sequence<ChooseFileSystemEntriesOptionsAccepts> accepts;
        boolean excludeAcceptAllOption = false;
    };

    [SecureContext]
    partial interface Window {
        Promise<(FileSystemHandle or sequence<FileSystemHandle>)>
            chooseFileSystemEntries(optional ChooseFileSystemEntriesOptions options = {});
    };

result = await window . `chooseFileSystemEntries`(options)

  Shows a file picker dialog to the user and returns handles for the selected files or directories.

  The options argument sets options that influence the behavior of the shown file picker.

  options.`type` specifies the type of the entry the website wants the user to pick. When set to `"open-file"` (the default), the user can select only existing files. When set to `"save-file"` the dialog will additionally let the user select files that don’t yet exist, and if the user selects a file that does exist already, its contents will be cleared before the handle is returned to the website. Finally when set to `"open-directory"`, the dialog will let the user select directories instead of files.

  If options.`multiple` is false (or absent) the user can only select a single file, and the result will be a single `FileSystemHandle`. If on the other hand options.`multiple` is true, the dialog can let the user select more than one file, and result will be an array of `FileSystemHandle` instances (even if the user did select a single file, if `multiple` is true this will be returned as a single-element array).

  Finally options.`accepts` and options.`excludeAcceptAllOption` specify the types of files the dialog will let the user select. Each entry in options.`accepts` describes a single type of file, consisting of a `description`, zero or more `mimeTypes` and zero or more `extensions`. Options with no valid `mimeTypes` and no `extensions` are invalid and are ignored. If no `description` is provided one will be generated.

  If options.`excludeAcceptAllOption` is true, or if no valid entries exist in options.`accepts`, a option matching all files will be included in the file types the dialog lets the user select.

The `chooseFileSystemEntries(options)` method, when invoked, must run these steps:

1. Let environment be the current settings object.

2. If environment’s origin is an opaque origin, return a promise rejected with a `SecurityError`.

3. Let browsing context be environment’s responsible browsing context.

4. Let top-level context be browsing context’s top-level browsing context.

5. If environment’s origin is not same origin with browsing context’s top-level browsing context's active document's origin, return a promise rejected with a `SecurityError`.

   There must be a better way to express this "no third-party iframes" constraint.

6. TODO

## 4. Accessing special filesystems

### 4.1. The `getSystemDirectory()` method

    enum SystemDirectoryType {
      "sandbox"
    };

    dictionary GetSystemDirectoryOptions {
      required SystemDirectoryType type;
    };

    [SecureContext]
    partial interface FileSystemDirectoryHandle {
      static Promise<FileSystemDirectoryHandle> getSystemDirectory(GetSystemDirectoryOptions options);
    };

directoryHandle = `FileSystemDirectoryHandle` . `getSystemDirectory`({ `type`: `"sandbox"` })

  Returns the sandboxed filesystem.

getSystemDirectory might not be the best name. Also perhaps should be on Window rather than on FileSystemDirectoryHandle. <https://github.com/wicg/native-file-system/issues/27>

The `getSystemDirectory(options)` method, when invoked, must run these steps:

1. Let environment be the current settings object.

2. If environment’s origin is an opaque origin, return a promise rejected with a `SecurityError`.

3. TODO

## 5. Privacy Considerations

This section is non-normative.

This API does not give websites any more read access to data than the existing `<input type=file>` and `<input type=file webkitdirectory>` APIs already do. Furthermore similarly to those APIs, all access to files and directories is explicitly gated behind a file or directory picker.

There are however several major privacy risks with this new API:

### 5.1. Users giving access to more, or more sensitive files than they intended.

This isn’t a new risk with this API, but user agents should try to make sure that users are aware of what exactly they’re giving websites access to. This is particularly important when giving access to a directory, where it might not be immediately clear to a user just how many files actually exist in that directory.

A related risk is having a user give access to particularly sensitive data. This could include some of a user agent’s configuration data, network cache or cookie store, or operating system configuration data such as password files. To protect against this, user agents are encouraged to restrict which directories a user is allowed to select in a directory picker, and potentially even restrict which files the user is allowed to select. This will make it much harder to accidentally give access to a directory that contains particularly sensitive data. Care must be taken to strike the right balance between restricting what the API can access while still having the API be useful. After all, this API intentionally lets the user use websites to interact with some of their most private personal data.

### 5.2. Websites trying to use this API for tracking.

This API could be used by websites to track the user across clearing browsing data. This is because, in contrast with existing file access APIs, user agents are able to grant persistent access to files or directories and can re-prompt. In combination with the ability to write to files, websites will be able to persist an identifier on the users' disk. Clearing browsing data will not affect those files in any way, making these identifiers persist through those actions.

This risk is somewhat mitigated by the fact that clearing browsing data will also clear IndexedDB, so websites won’t have any handles to re-prompt for permission after browsing data was cleared. Furthermore user agents are encouraged to make it clear what files and directories a website has access to, and to automatically expire permission grants except for particularly well trusted origins (for example persistent permissions could be limited to "installed" web applications).

User agents also are encouraged to provide a way for users to revoke permissions granted. Clearing browsing data is expected to revoke all permissions as well.

### 5.3. First-party vs third-party contexts.

In third-party contexts (i.e. an iframe whose origin does not match that of the top-level frame) websites can’t gain access to data they don’t already have access to. This includes both getting access to new files or directories via the `chooseFileSystemEntries` API, as well as requesting more permissions to existing handles via the `requestPermission` API.

Handles can also only be post-messaged to same-origin destinations. Attempts to send a handle to a cross-origin destination will result in a `messageerror` event.

## 6. Security Considerations

This section is non-normative.

This API gives websites the ability to modify existing files on disk, as well as write to new files. This has a couple of important security considerations:

### 6.1. Malware

This API could be used by websites to try to store and/or execute malware on the users system. To mitigate this risk, this API does not provide any way to mark files as executable (on the other hand files that are already executable likely remain that way, even after the files are modified through this API). Furthermore user agents are encouraged to apply things like Mark-of-the-Web to files created or modified by this API.

Finally, user agents are encouraged to verify the contents of files modified by this API via malware scans and safe browsing checks, unless some kind of external strong trust relation already exists. This of course has effects on the performance characteristics of this API.

"Atomic writes" attempts to make it explicit what this API can and can’t do, and how performance can be effected by safe browsing checks. <https://github.com/wicg/native-file-system/issues/51>

### 6.2. Ransomware attacks

Another risk factor is that of ransomware attacks. The limitations described above regarding blocking access to certain sensitive directories helps limit the damage such an attack can do. Additionally user agents can grant write access to files at whatever granularity they deem appropriate.

## Conformance

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with `class="example"`, like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with `class="note"`, like this:

Note, this is an informative note.

## Index

### Terms defined by this specification

- accepts, in §3.1
- binary data, in §2.1
- chooseFileSystemEntries(), in §3.1
- chooseFileSystemEntries(options), in §3.1
- ChooseFileSystemEntriesOptions, in §3.1
- ChooseFileSystemEntriesOptionsAccepts, in §3.1
- ChooseFileSystemEntriesType, in §3.1
- close(), in §2.5.3
- create
  - dict-member for FileSystemGetDirectoryOptions, in §2.4
  - dict-member for FileSystemGetFileOptions, in §2.4
- createWriter(), in §2.3.2
- createWriter(options), in §2.3.2
- description, in §3.1
- directory, in §2.1
- directory entry, in §2.1
- entries, in §2.1
- entry
  - definition of, in §2.1
  - dfn for FileSystemHandle, in §2.2
- excludeAcceptAllOption, in §3.1
- extensions, in §3.1
- file, in §2.1
- file entry, in §2.1
- FileSystemCreateWriterOptions, in §2.3
- FileSystemDirectoryHandle, in §2.4
- FileSystemFileHandle, in §2.3
- FileSystemGetDirectoryOptions, in §2.4
- FileSystemGetFileOptions, in §2.4
- FileSystemHandle, in §2.2
- FileSystemHandlePermissionDescriptor, in §2.2
- FileSystemRemoveOptions, in §2.4
- FileSystemWriter, in §2.5
- getDirectory(name), in §2.4.2
- getDirectory(name, options), in §2.4.2
- getEntries(), in §2.4.3
- getFile(), in §2.3.1
- getFile(name), in §2.4.1
- getFile(name, options), in §2.4.1
- getSystemDirectory(options), in §4.1
- GetSystemDirectoryOptions, in §4.1
- isDirectory, in §2.2
- isFile, in §2.2
- keepExistingData, in §2.3
- mimeTypes, in §3.1
- modification timestamp, in §2.1
- multiple, in §3.1
- name
  - attribute for FileSystemHandle, in §2.2
  - dfn for entry, in §2.1
- "open-directory", in §3.1
- "open-file", in §3.1
- queryPermission(), in §2.2.1
- queryPermission(descriptor), in §2.2.1
- recursive, in §2.4
- removeEntry(name), in §2.4.4
- removeEntry(name, options), in §2.4.4
- requestPermission(), in §2.2.2
- requestPermission(descriptor), in §2.2.2
- "sandbox", in §4.1
- "save-file", in §3.1
- SystemDirectoryType, in §4.1
- truncate(size), in §2.5.2
- type
  - dict-member for ChooseFileSystemEntriesOptions, in §3.1
  - dict-member for GetSystemDirectoryOptions, in §4.1
- writable, in §2.2
- write(position, data), in §2.5.1

https://w3c.github.io/FileAPI/#dfn-Blob Referenced in:

- 2.5. The FileSystemWriter interface

https://w3c.github.io/FileAPI/#dfn-file Referenced in:

- 2.3. The FileSystemFileHandle interface
- 2.3.1. The getFile() method (2)

https://html.spec.whatwg.org/multipage/structured-data.html#serializable Referenced in:

- 2.2. The FileSystemHandle interface
- 2.3. The FileSystemFileHandle interface
- 2.4. The FileSystemDirectoryHandle interface

https://html.spec.whatwg.org/multipage/window-object.html#window Referenced in:

- 3.1. The chooseFileSystemEntries() method

https://html.spec.whatwg.org/multipage/browsers.html#active-document Referenced in:

- 3.1. The chooseFileSystemEntries() method

https://html.spec.whatwg.org/multipage/webappapis.html#current-settings-object Referenced in:

- 3.1. The chooseFileSystemEntries() method
- 4.1. The getSystemDirectory() method

https://html.spec.whatwg.org/multipage/structured-data.html#deserialization-steps Referenced in:

- 2.2. The FileSystemHandle interface
- 2.3. The FileSystemFileHandle interface
- 2.4. The FileSystemDirectoryHandle interface

https://html.spec.whatwg.org/multipage/indices.html#event-messageerror Referenced in:

- 5.3. First-party vs third-party contexts.

https://html.spec.whatwg.org/multipage/origin.html#concept-origin-opaque Referenced in:

- 3.1. The chooseFileSystemEntries() method
- 4.1. The getSystemDirectory() method

https://html.spec.whatwg.org/multipage/webappapis.html#concept-settings-object-origin Referenced in:

- 2.2. The FileSystemHandle interface (2)
- 3.1. The chooseFileSystemEntries() method (2)
- 4.1. The getSystemDirectory() method

https://html.spec.whatwg.org/multipage/webappapis.html#relevant-settings-object Referenced in:

- 2.2. The FileSystemHandle interface (2)

https://html.spec.whatwg.org/multipage/webappapis.html#responsible-browsing-context Referenced in:

- 3.1. The chooseFileSystemEntries() method

https://html.spec.whatwg.org/multipage/origin.html#same-origin Referenced in:

- 2.2. The FileSystemHandle interface
- 3.1. The chooseFileSystemEntries() method

https://html.spec.whatwg.org/multipage/structured-data.html#serializable-objects Referenced in:

- 2.2. The FileSystemHandle interface
- 2.3. The FileSystemFileHandle interface
- 2.4. The FileSystemDirectoryHandle interface

https://html.spec.whatwg.org/multipage/structured-data.html#serialization-steps Referenced in:

- 2.2. The FileSystemHandle interface
- 2.3. The FileSystemFileHandle interface
- 2.4. The FileSystemDirectoryHandle interface

https://html.spec.whatwg.org/multipage/browsers.html#top-level-browsing-context Referenced in:

- 3.1. The chooseFileSystemEntries() method (2)

https://infra.spec.whatwg.org/#ordered-set Referenced in:

- 2.1. Concepts

https://w3c.github.io/permissions/#enumdef-permissionstate Referenced in:

- 2.2. The FileSystemHandle interface (2)

https://www.w3.org/2001/tag/doc/promises-guide/#a-promise-rejected-with Referenced in:

- 3.1. The chooseFileSystemEntries() method (2)
- 4.1. The getSystemDirectory() method

https://heycam.github.io/webidl/#BufferSource Referenced in:

- 2.5. The FileSystemWriter interface

https://heycam.github.io/webidl/#datacloneerror Referenced in:

- 2.2. The FileSystemHandle interface

https://heycam.github.io/webidl/#Exposed Referenced in:

- 2.2. The FileSystemHandle interface
- 2.3. The FileSystemFileHandle interface
- 2.4. The FileSystemDirectoryHandle interface
- 2.5. The FileSystemWriter interface

https://heycam.github.io/webidl/#SecureContext Referenced in:

- 2.2. The FileSystemHandle interface
- 2.3. The FileSystemFileHandle interface
- 2.4. The FileSystemDirectoryHandle interface
- 2.5. The FileSystemWriter interface
- 3.1. The chooseFileSystemEntries() method
- 4.1. The getSystemDirectory() method

https://heycam.github.io/webidl/#securityerror Referenced in:

- 3.1. The chooseFileSystemEntries() method (2)
- 4.1. The getSystemDirectory() method

https://heycam.github.io/webidl/#idl-USVString Referenced in:

- 2.2. The FileSystemHandle interface
- 2.4. The FileSystemDirectoryHandle interface (2) (3)
- 2.5. The FileSystemWriter interface
- 3.1. The chooseFileSystemEntries() method (2) (3)

https://heycam.github.io/webidl/#idl-boolean Referenced in:

- 2.2. The FileSystemHandle interface (2) (3)
- 2.3. The FileSystemFileHandle interface
- 2.4. The FileSystemDirectoryHandle interface (2) (3)
- 3.1. The chooseFileSystemEntries() method (2)

https://heycam.github.io/webidl/#idl-object Referenced in:

- 2.4. The FileSystemDirectoryHandle interface

https://heycam.github.io/webidl/#idl-unsigned-long-long Referenced in:

- 2.5. The FileSystemWriter interface (2)

### Terms defined by reference

- [FILE-API] defines the following terms:
  - Blob
  - File
- [HTML] defines the following terms:
  - Serializable
  - Window
  - active document
  - current settings object
  - deserialization steps
  - messageerror
  - opaque origin
  - origin (for environment settings object)
  - relevant settings object
  - responsible browsing context
  - same origin
  - serializable objects
  - serialization steps
  - top-level browsing context
- [INFRA] defines the following terms:
  - set
- [permissions] defines the following terms:
  - PermissionState
- [promises-guide] defines the following terms:
  - a promise rejected with
- [WebIDL] defines the following terms:
  - BufferSource
  - DataCloneError
  - Exposed
  - SecureContext
  - SecurityError
  - USVString
  - boolean
  - object
  - unsigned long long

## References

### Normative References

[FILE-API]
  Marijn Kruisselbrink; Arun Ranganathan. File API. 31 May 2019. WD. URL: https://www.w3.org/TR/FileAPI/
[HTML]
  Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
  Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[PERMISSIONS]
  Mounir Lamouri; Marcos Caceres; Jeffrey Yasskin. Permissions. 25 September 2017. WD. URL: https://www.w3.org/TR/permissions/
[PROMISES-GUIDE]
  Domenic Denicola. Writing Promise-Using Specifications. 9 November 2018. TAG Finding. URL: https://www.w3.org/2001/tag/doc/promises-guide
[RFC2119]
  S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[WebIDL]
  Boris Zbarsky. Web IDL. 15 December 2016. ED. URL: https://heycam.github.io/webidl/

### Informative References

[ENTRIES-API]
  File and Directory Entries API. Living Standard. URL: https://wicg.github.io/entries-api/
[FILE-SYSTEM-API]
  Eric Uhrhane. File API: Directories and System. 24 April 2014. NOTE. URL: https://www.w3.org/TR/file-system-api/

## IDL Index

    dictionary FileSystemHandlePermissionDescriptor {
      boolean writable = false;
    };

    [Exposed=(Window,Worker), SecureContext, Serializable]
    interface FileSystemHandle {
      readonly attribute boolean isFile;
      readonly attribute boolean isDirectory;
      readonly attribute USVString name;

      Promise<PermissionState> queryPermission(optional FileSystemHandlePermissionDescriptor descriptor = {});
      Promise<PermissionState> requestPermission(optional FileSystemHandlePermissionDescriptor descriptor = {});
    };

    dictionary FileSystemCreateWriterOptions {
      boolean keepExistingData = false;
    };

    [Exposed=(Window,Worker), SecureContext, Serializable]
    interface FileSystemFileHandle : FileSystemHandle {
      Promise<File> getFile();
      Promise<FileSystemWriter> createWriter(optional FileSystemCreateWriterOptions options = {});
    };

    dictionary FileSystemGetFileOptions {
      boolean create = false;
    };

    dictionary FileSystemGetDirectoryOptions {
      boolean create = false;
    };

    dictionary FileSystemRemoveOptions {
      boolean recursive = false;
    };

    [Exposed=(Window,Worker), SecureContext, Serializable]
    interface FileSystemDirectoryHandle : FileSystemHandle {
      Promise<FileSystemFileHandle> getFile(USVString name, optional FileSystemGetFileOptions options = {});
      Promise<FileSystemDirectoryHandle> getDirectory(USVString name, optional FileSystemGetDirectoryOptions options = {});

      // This really returns an async iterable, but that is not yet expressable in WebIDL.
      object getEntries();

      Promise<void> removeEntry(USVString name, optional FileSystemRemoveOptions options = {});
    };

    [Exposed=(Window,Worker), SecureContext]
    interface FileSystemWriter {
      Promise<void> write(unsigned long long position, (BufferSource or Blob or USVString) data);
      Promise<void> truncate(unsigned long long size);
      Promise<void> close();
    };

    enum ChooseFileSystemEntriesType { "open-file", "save-file", "open-directory" };

    dictionary ChooseFileSystemEntriesOptionsAccepts {
      USVString description;
      sequence<USVString> mimeTypes;
      sequence<USVString> extensions;
    };

    dictionary ChooseFileSystemEntriesOptions {
        ChooseFileSystemEntriesType type = "open-file";
        boolean multiple = false;
        sequence<ChooseFileSystemEntriesOptionsAccepts> accepts;
        boolean excludeAcceptAllOption = false;
    };

    [SecureContext]
    partial interface Window {
        Promise<(FileSystemHandle or sequence<FileSystemHandle>)>
            chooseFileSystemEntries(optional ChooseFileSystemEntriesOptions options = {});
    };

    enum SystemDirectoryType {
      "sandbox"
    };

    dictionary GetSystemDirectoryOptions {
      required SystemDirectoryType type;
    };

    [SecureContext]
    partial interface FileSystemDirectoryHandle {
      static Promise<FileSystemDirectoryHandle> getSystemDirectory(GetSystemDirectoryOptions options);
    };

## Issues Index

TODO: Explain how entries map to files on disk (multiple entries can map to the same file or directory on disk but doesn’t have to map to any file on disk). ↵
the currently described API here assumes a model where it is not possible to have a write-only handle. I.e. it is not possible to have or request write access without also having read access. There definitely are use cases for write-only handles (i.e. directory downloads), so we might have to reconsider this. ↵
There has been some discussion around and desire for a "inPlace" mode for createWriter (where changes will be written to the actual underlying file as they are written to the writer, for example to support in-place modification of large files or things like databases). This is not currently implemented in Chrome. Implementing this is currently blocked on figuring out how to combine the desire to run malware checks with the desire to let websites make fast in-place modifications to existing large files. ↵
Should we have separate getFile and getDirectory methods, or just a single getChild/getEntry method? ↵
Having getFile methods in both FileSystemDirectoryHandle and FileSystemFileHandle, but with very different behavior might be confusing? Perhaps rename at least one of them (but see also previous issue). ↵
Should getEntries be its own method, or should FileSystemDirectoryHandle just be an async iterable itself? ↵
We will probably want some method to make it possible to compare two handles, and/or determine if one handle represents a descendant of another handle. Such a method will enable for example an IDE to detect that the user tries to open a file (through the file picker), where that file actually is part of the "project" the IDE has open, allowing the IDE to highlight the selected file in a directory tree. ↵
We want some kind of integration with writable streams. One possible option is to make FileStreamWriter inherit from WritableStream, but other options should be considered as well. <https://github.com/wicg/native-file-system/issues/19> ↵
There must be a better way to express this "no third-party iframes" constraint. ↵
getSystemDirectory might not be the best name. Also perhaps should be on Window rather than on FileSystemDirectoryHandle. <https://github.com/wicg/native-file-system/issues/27> ↵
"Atomic writes" attempts to make it explicit what this API can and can’t do, and how performance can be effected by safe browsing checks. <https://github.com/wicg/native-file-system/issues/51> ↵
#entry Referenced in:

- 2.1. Concepts
- 2.2. The FileSystemHandle interface (2) (3)

#entry-name Referenced in:

- 2.2. The FileSystemHandle interface (2)

#file Referenced in:

- 2.1. Concepts (2)
- 2.2. The FileSystemHandle interface

#directory Referenced in:

- 2.1. Concepts (2)
- 2.2. The FileSystemHandle interface

#dictdef-filesystemhandlepermissiondescriptor Referenced in:

- 2.2. The FileSystemHandle interface (2)

#dom-filesystemhandlepermissiondescriptor-writable Referenced in:

- 2.2.1. The queryPermission() method (2)
- 2.2.2. The requestPermission() method (2)

#filesystemhandle Referenced in:

- 2.2. The FileSystemHandle interface (2) (3) (4) (5)
- 2.3. The FileSystemFileHandle interface (2)
- 2.4. The FileSystemDirectoryHandle interface (2)
- 3.1. The chooseFileSystemEntries() method (2) (3) (4)

#filesystemhandle-entry Referenced in:

- 2.2. The FileSystemHandle interface (2) (3)

#dom-filesystemhandle-isfile Referenced in:

- 2.2. The FileSystemHandle interface (2)

#dom-filesystemhandle-isdirectory Referenced in:

- 2.2. The FileSystemHandle interface (2)

#dom-filesystemhandle-name Referenced in:

- 2.2. The FileSystemHandle interface (2)

#dom-filesystemhandle-querypermission Referenced in:

- 2.2. The FileSystemHandle interface
- 2.2.1. The queryPermission() method (2) (3) (4)

#dom-filesystemhandle-requestpermission Referenced in:

- 2.2. The FileSystemHandle interface
- 2.2.1. The queryPermission() method (2)
- 2.2.2. The requestPermission() method (2) (3) (4)
- 5.3. First-party vs third-party contexts.

#dictdef-filesystemcreatewriteroptions Referenced in:

- 2.3. The FileSystemFileHandle interface

#dom-filesystemcreatewriteroptions-keepexistingdata Referenced in:

- 2.3.2. The createWriter() method (2)

#filesystemfilehandle Referenced in:

- 2.2. The FileSystemHandle interface
- 2.3. The FileSystemFileHandle interface (2)
- 2.4. The FileSystemDirectoryHandle interface

#dom-filesystemfilehandle-getfile Referenced in:

- 2.3. The FileSystemFileHandle interface
- 2.3.1. The getFile() method (2)

#dom-filesystemfilehandle-createwriter Referenced in:

- 2.3. The FileSystemFileHandle interface
- 2.3.2. The createWriter() method (2) (3)

#dictdef-filesystemgetfileoptions Referenced in:

- 2.4. The FileSystemDirectoryHandle interface

#dom-filesystemgetfileoptions-create Referenced in:

- 2.4.1. The getFile() method (2) (3)

#dictdef-filesystemgetdirectoryoptions Referenced in:

- 2.4. The FileSystemDirectoryHandle interface

#dom-filesystemgetdirectoryoptions-create Referenced in:

- 2.4.2. The getDirectory() method (2) (3)

#dictdef-filesystemremoveoptions Referenced in:

- 2.4. The FileSystemDirectoryHandle interface

#dom-filesystemremoveoptions-recursive Referenced in:

- 2.4.4. The removeEntry() method (2)

#filesystemdirectoryhandle Referenced in:

- 2.2. The FileSystemHandle interface
- 2.4. The FileSystemDirectoryHandle interface (2) (3)
- 4.1. The getSystemDirectory() method (2) (3)

#dom-filesystemdirectoryhandle-getfile Referenced in:

- 2.4. The FileSystemDirectoryHandle interface
- 2.4.1. The getFile() method (2) (3) (4)

#dom-filesystemdirectoryhandle-getdirectory Referenced in:

- 2.4. The FileSystemDirectoryHandle interface
- 2.4.2. The getDirectory() method (2) (3) (4)

#dom-filesystemdirectoryhandle-getentries Referenced in:

- 2.4. The FileSystemDirectoryHandle interface
- 2.4.3. The getEntries() method (2)

#dom-filesystemdirectoryhandle-removeentry Referenced in:

- 2.4. The FileSystemDirectoryHandle interface
- 2.4.4. The removeEntry() method (2) (3) (4)

#filesystemwriter Referenced in:

- 2.3. The FileSystemFileHandle interface
- 2.3.2. The createWriter() method
- 2.5. The FileSystemWriter interface

#dom-filesystemwriter-write Referenced in:

- 2.5. The FileSystemWriter interface
- 2.5.1. The write() method (2)

#dom-filesystemwriter-truncate Referenced in:

- 2.5. The FileSystemWriter interface
- 2.5.2. The truncate() method (2)

#dom-filesystemwriter-close Referenced in:

- 2.3.2. The createWriter() method (2)
- 2.5. The FileSystemWriter interface
- 2.5.1. The write() method
- 2.5.2. The truncate() method
- 2.5.3. The close() method (2) (3)

#enumdef-choosefilesystementriestype Referenced in:

- 3.1. The chooseFileSystemEntries() method

#dom-choosefilesystementriestype-open-file Referenced in:

- 3.1. The chooseFileSystemEntries() method

#dom-choosefilesystementriestype-save-file Referenced in:

- 3.1. The chooseFileSystemEntries() method

#dom-choosefilesystementriestype-open-directory Referenced in:

- 3.1. The chooseFileSystemEntries() method

#dictdef-choosefilesystementriesoptionsaccepts Referenced in:

- 3.1. The chooseFileSystemEntries() method

#dom-choosefilesystementriesoptionsaccepts-description Referenced in:

- 3.1. The chooseFileSystemEntries() method (2)

#dom-choosefilesystementriesoptionsaccepts-mimetypes Referenced in:

- 3.1. The chooseFileSystemEntries() method (2)

#dom-choosefilesystementriesoptionsaccepts-extensions Referenced in:

- 3.1. The chooseFileSystemEntries() method (2)

#dictdef-choosefilesystementriesoptions Referenced in:

- 3.1. The chooseFileSystemEntries() method

#dom-choosefilesystementriesoptions-type Referenced in:

- 3.1. The chooseFileSystemEntries() method

#dom-choosefilesystementriesoptions-multiple Referenced in:

- 3.1. The chooseFileSystemEntries() method (2) (3)

#dom-choosefilesystementriesoptions-accepts Referenced in:

- 3.1. The chooseFileSystemEntries() method (2) (3)

#dom-choosefilesystementriesoptions-excludeacceptalloption Referenced in:

- 3.1. The chooseFileSystemEntries() method (2)

#dom-window-choosefilesystementries Referenced in:

- 2.2.1. The queryPermission() method
- 3.1. The chooseFileSystemEntries() method (2) (3)
- 5.3. First-party vs third-party contexts.

#enumdef-systemdirectorytype Referenced in:

- 4.1. The getSystemDirectory() method

#dom-systemdirectorytype-sandbox Referenced in:

- 4.1. The getSystemDirectory() method

#dictdef-getsystemdirectoryoptions Referenced in:

- 4.1. The getSystemDirectory() method

#dom-getsystemdirectoryoptions-type Referenced in:

- 4.1. The getSystemDirectory() method

#dom-filesystemdirectoryhandle-getsystemdirectory Referenced in:

- 4.1. The getSystemDirectory() method (2) (3)