File and Directory Entries API

Draft Community Group Report,

This version:
https://wicg.github.io/entries-api/
Test Suite:
https://github.com/web-platform-tests/wpt/tree/master/entries-api
Issue Tracking:
GitHub
Inline In Spec
Editor:
(Google Inc.)

Abstract

This specification documents web browser support for file and directory upload by drag-and-drop operations. It introduces types representing directories with methods for asynchronous traversal, and extends HTMLInputElement and DataTransferItem [HTML].

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. Goals

This specification documents the types and operations made available by web browsers to script when a hierarchy of files and directories are dragged and dropped onto a page or selected using form elements, or equivalent user actions.

This is heavily based upon earlier drafts of [file-system-api] which defines similar types in the context of a sandboxed file system, including operations for creating and modifying files and directories, but which has not been broadly adopted by web browsers.

2. Concepts

2.1. Names and Paths

A name is a string which:

A path segment is a name, '.' (U+002E FULL STOP) or '..' (U+002E FULL STOP, U+002E FULL STOP).

A relative path is a string consisting of one or more path segments joined by '/' (U+002F SOLIDUS) that does not start with '/' (U+002F SOLIDUS).

An absolute path is a string consisting of '/' (U+002F SOLIDUS) followed by zero or more path segments joined by '/' (U+002F SOLIDUS).

A path is either a relative path or an absolute path.

A valid path is a USVString which is a path.

2.2. Files and Directories

A file consists of binary data and a name (a non-empty name).

A directory consists of a name (a name) and an ordered list of members. Each member is either a file or a directory. Each member of a directory must have a distinct non-empty name.

A root directory is a directory that is not a member of a directory. A root directory's name is empty.

The parent of a file or directory is the directory it is a member of. A root directory has no parent.

A file system consists of a name and a root which is an associated root directory. The name of a file system is a USVString which is implementation defined but is unique to the file system. A root directory is associated with exactly one file system.

2.3. Entries

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

An entry has an name (a name) and a full path (an absolute path).

An entry also has a root, which is an associated root directory.

The file system of an entry is the file system associated with the entry's root.

2.4. Directory Reader

A directory reader consists of an associated directory entry, an associated directory (initially null), a reading flag (initially unset), a done flag (initially unset), and a reader error (initially null).

3. Algorithms

To resolve a relative path with abspath (an absolute path) and path (an absolute path, a relative path, or the empty string), run the following steps which return an absolute path:

  1. If path is an absolute path, return path.

  2. Let abspath segments be the result of strictly splitting abspath on '/' (U+002F SOLIDUS).

  3. Let path segments be the result of strictly splitting path on '/' (U+002F SOLIDUS).

  4. For each segment in path segments, switch on segment:

    empty string
    Continue.
    '.' (U+002E FULL STOP)
    Continue.
    '..' (U+002E FULL STOP, U+002E FULL STOP)
    Remove the last member of abspath segments unless it is the only member.
    Otherwise
    Append segment to abspath segments.
  1. Return abspath segments joined by '/' (U+002F SOLIDUS).

To evaluate a path with directory (an root directory) and path (an absolute path), run the following steps which return a file, directory, or failure.

  1. Let segments be the result of strictly splitting path on '/' (U+002F SOLIDUS).

  2. Remove the first entry from segments.

  3. For each segment in segments, switch on segment:

    empty string
    Continue.
    '.' (U+002E FULL STOP)
    Continue.
    '..' (U+002E FULL STOP, U+002E FULL STOP)
    Let directory be directory’s parent, or directory if none.
    Otherwise
    Run these substeps:
    1. Let item be the member of directory with name equal to segment, or return failure if none.

    2. If segment is the last item in segments, return item.

    3. If item is a file, return failure.

    4. Let directory be item.

4. The File Interface

partial interface File {
    readonly attribute USVString webkitRelativePath;
};

File/webkitRelativePath

In all current engines.

Firefox49+Safari11.1+Chrome13+
Opera?Edge79+
Edge (Legacy)13+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?

The webkitRelativePath getter steps are to return the file’s relative path, or the empty string if not specified.

5. HTML: Forms

HTMLInputElement/webkitdirectory

In all current engines.

Firefox50+Safari11.1+Chrome6+
Opera?Edge79+
Edge (Legacy)13+IENone
Firefox for AndroidNoneiOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?

HTMLInputElement/webkitEntries

In all current engines.

Firefox50+Safari11.1+Chrome22+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for AndroidNoneiOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
partial interface HTMLInputElement {
    attribute boolean webkitdirectory;
    readonly attribute FrozenArray<FileSystemEntry> webkitEntries;
};

When an input element’s type attribute is in the File Upload state, the rules in this section apply.

The webkitdirectory attribute is a boolean attribute that indicates whether the user is to be allowed to select a directory rather than a file or files. When specified, the behavior on the selection of a directory is as if all files with that directory as an ancestor were selected. In addition, the webkitRelativePath property of each File is set to a relative path starting from (and including) the selected directory to the file.

The webkitEntries IDL attribute allows scripts to access the element’s selected entries. On getting, if the IDL attribute applies, it must return an array of FileSystemEntry objects that represent the current selected files (including directories, if permitted). If the IDL attribute does not apply, then it must instead return null.

6. HTML: Drag and drop

During a drag-and-drop operation, file and directory items are associated with entries. Each entry is a member of a root directory unique to the drag data store.

Additionally, each directory item is represented in the drag data store item list as a File. If it is accessed via getAsFile() a zero-length File is returned.

partial interface DataTransferItem {
    FileSystemEntry? webkitGetAsEntry();
};

DataTransferItem/webkitGetAsEntry

In all current engines.

Firefox50+Safari11.1+Chrome13+
Opera?Edge79+
Edge (Legacy)14+IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?

The webkitGetAsEntry() method steps are:

  1. If the DataTransferItem object is not in the read/write mode or the read-only mode, return null and abort these steps.

  2. If the drag data item kind is not File, then return null and abort these steps.

  3. Return a new FileSystemEntry object representing the entry.

7. Files and Directories

callback ErrorCallback = undefined (DOMException err);

An ErrorCallback function is used for operations that may return an error asynchronously.

7.1. The FileSystemEntry Interface

FileSystemEntry

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera MobileNone
[Exposed=Window]
interface FileSystemEntry {
    readonly attribute boolean isFile;
    readonly attribute boolean isDirectory;
    readonly attribute USVString name;
    readonly attribute USVString fullPath;
    readonly attribute FileSystem filesystem;

    undefined getParent(optional FileSystemEntryCallback successCallback,
                   optional ErrorCallback errorCallback);
};

An FileSystemEntry has an associated entry.

FileSystemEntry/isFile

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera MobileNone

The isFile getter steps are to return true if this is a file entry and false otherwise.

FileSystemEntry/isDirectory

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera MobileNone

The isDirectory getter steps are to return true if this is a directory entry and false otherwise.

FileSystemEntry/name

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera MobileNone

The name getter steps are to return this's name.

FileSystemEntry/fullPath

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera MobileNone

The fullPath getter steps are to return this's full path.

FileSystemEntry/filesystem

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera MobileNone

The filesystem getter steps are to return this's file system.

FileSystemEntry/getParent

In all current engines.

Firefox52+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera MobileNone

The getParent(successCallback, errorCallback) method steps are:

  1. Queue a task to perform the following substeps:

    1. Let path be the result of running the steps to resolve a relative path with this's full path and '..'.

    2. Let item be the result of running the steps to evaluate a path with this's root and path.

    3. If item is failure, invoke errorCallback (if given) with a newly created "NotFoundError" DOMException, and terminate these steps.

    4. Let entry be a new directory entry with item’s name as name and path as full path.

    5. Invoke successCallback with a new FileSystemDirectoryEntry object associated with entry.

7.2. The FileSystemDirectoryEntry Interface

FileSystemDirectoryEntry

In all current engines.

Firefox50+Safari11.1+Chrome8+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera MobileNone
[Exposed=Window]
interface FileSystemDirectoryEntry : FileSystemEntry {
    FileSystemDirectoryReader createReader();
    undefined getFile(optional USVString? path,
                 optional FileSystemFlags options = {},
                 optional FileSystemEntryCallback successCallback,
                 optional ErrorCallback errorCallback);
    undefined getDirectory(optional USVString? path,
                      optional FileSystemFlags options = {},
                      optional FileSystemEntryCallback successCallback,
                      optional ErrorCallback errorCallback);
};

dictionary FileSystemFlags {
    boolean create = false;
    boolean exclusive = false;
};

callback FileSystemEntryCallback = undefined (FileSystemEntry entry);

A FileSystemDirectoryEntry's associated entry is a directory entry.

FileSystemDirectoryEntry/createReader

In all current engines.

Firefox50+Safari11.1+Chrome13+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera MobileNone

The createReader() method steps are:

  1. Let reader be a new directory reader associated with the directory entry's directory.

  2. Return a newly created FileSystemDirectoryReader object associated with reader.

FileSystemDirectoryEntry/getFile

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera MobileNone

The getFile(path, options, successCallback, errorCallback) method steps are:

  1. Queue a task to run the following substeps:

    1. If path is undefined or null let path be the empty string.

    2. If path is not a valid path, invoke errorCallback (if given) with a newly created "TypeMismatchError" DOMException, and terminate these steps.

    3. If options’s create member is true, invoke errorCallback (if given) with a newly created "SecurityError" DOMException, and terminate these steps.

    4. Let path be the result of running the steps to resolve a relative path with this's full path and path.

    5. Let item be the result of running the steps to evaluate a path with this's root and path.

    6. If item is failure, invoke errorCallback (if given) with a newly created "NotFoundError" DOMException, and terminate these steps.

    7. If item is not a file, invoke errorCallback (if given) with a newly created "TypeMismatchError" DOMException, and terminate these steps.

    8. Let entry be a new file entry with item’s name as name and path as full path.

    9. Invoke successCallback (if given) with a new FileSystemFileEntry object associated with entry.

FileSystemDirectoryEntry/getDirectory

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera MobileNone

The getDirectory(path, options, successCallback, errorCallback) method steps are:

  1. Queue a task to run the following substeps:

    1. If path is undefined or null let path be the empty string.

    2. If path is not a valid path, invoke errorCallback (if given) with a newly created "TypeMismatchError" DOMException, and terminate these steps.

    3. If options’s create member is true, invoke errorCallback (if given) with a newly created "SecurityError" DOMException, and terminate these steps.

    4. Let path be the result of running the steps to resolve a relative path with this's full path and path.

    5. Let item be the result of running the steps to evaluate a path with this's root and path.

    6. If item is failure, invoke errorCallback (if given) with a newly created "NotFoundError" DOMException, and terminate these steps.

    7. If item is not a directory, invoke errorCallback (if given) with a newly created "TypeMismatchError" DOMException, and terminate these steps.

    8. Let entry be a new directory entry with item’s name as name and path as full path.

    9. invoke successCallback (if given) with a new FileSystemDirectoryEntry associated with entry.

7.3. The FileSystemDirectoryReader Interface

FileSystemDirectoryReader

In all current engines.

Firefox50+Safari11.1+Chrome8+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera MobileNone

FileSystemDirectoryReader/readEntries

In all current engines.

Firefox50+Safari11.1+Chrome8+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera MobileNone
[Exposed=Window]
interface FileSystemDirectoryReader {
    undefined readEntries(FileSystemEntriesCallback successCallback,
                     optional ErrorCallback errorCallback);
};
callback FileSystemEntriesCallback = undefined (sequence<FileSystemEntry> entries);

A FileSystemDirectoryReader has an associated directory reader.

The readEntries(successCallback, errorCallback) method steps are:

  1. If this's reading flag is set, queue a task to invoke errorCallback with a newly created "InvalidStateError" DOMException, and terminate these steps.

  2. If this's reader error is not null, queue a task to invoke errorCallback (if given) with reader error, and terminate these steps.

  3. If this's done flag is set, queue a task to invoke successCallback with an empty sequence and terminate these steps.

  4. Set this's reading flag.

  5. Queue a task to perform the following substeps:

    1. Clear this's reading flag.

    2. Let dir be this's directory.

    3. If dir is null, run these substeps:

      1. Let dir be the result of running the steps to evaluate a path with this's root and full path.

      2. If dir is failure, set this's reader error to a newly created "NotFoundError" DOMException, invoke errorCallback (if given) with reader error, and terminate these steps.

      3. Set this's directory to dir.

    4. Let entries be a non-zero number of entries from the dir that have not yet been produced by this directory reader, if any.

    5. If the previous step failed (for example, the directory was deleted or permission is denied), then set this's reader error to an appropriate DOMException, invoke errorCallback (if given) with reader error, and terminate these steps.

    6. If entries is empty, set this's done flag.

    7. invoke successCallback with entries.

7.4. The FileSystemFileEntry Interface

FileSystemFileEntry

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera MobileNone
[Exposed=Window]
interface FileSystemFileEntry : FileSystemEntry {
    undefined file(FileCallback successCallback,
              optional ErrorCallback errorCallback);
};
callback FileCallback = undefined (File file);

A FileSystemFileEntry's associated entry is a file entry.

FileSystemFileEntry/file

In all current engines.

Firefox50+Safari11.1+Chrome8+
OperaNoneEdge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera MobileNone

The file(successCallback, errorCallback) method steps are:

  1. Queue a task to perform the following substeps:

    1. Let item be the result of running the steps to evaluate a path with this's root and full path.

    2. If item is failure, invoke errorCallback (if given) with a newly created "NotFoundError" DOMException, and terminate these steps.

    3. If item is a directory, invoke errorCallback (if given) with a newly created "TypeMismatchError" DOMException, and terminate these steps.

    4. invoke successCallback with a new File object representing item.

7.5. The FileSystem Interface

FileSystem

In all current engines.

Firefox50+Safari11.1+Chrome7+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
[Exposed=Window]
interface FileSystem {
    readonly attribute USVString name;
    readonly attribute FileSystemDirectoryEntry root;
};

A FileSystem has an associated file system.

FileSystem/name

In all current engines.

Firefox50+Safari11.1+Chrome7+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?

The name getter steps are to return this's name.

FileSystem/root

In all current engines.

Firefox50+Safari11.1+Chrome7+
Opera?Edge79+
Edge (Legacy)18IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?

The root getter steps are to return a FileSystemDirectoryEntry associated with this's root.

8. Acknowledgements

This specification is based heavily on the work of Eric Uhrhane in [file-system-api], which introduced the FileSystemEntry types.

Thanks to Tab Atkins, Jr. for creating and maintaining Bikeshed, the specification authoring tool used to create this document.

And thanks to Ali Alabbas, Philip Jägenstedt, Marijn Kruisselbrink, Olli Pettay, and Kent Tamura for suggestions, reviews, and other feedback.

Conformance

Document conventions

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.

Conformant Algorithms

Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and abort these steps") are to be interpreted with the meaning of the key word ("must", "should", "may", etc) used in introducing the algorithm.

Conformance requirements phrased as algorithms or specific steps can be implemented in any manner, so long as the end result is equivalent. In particular, the algorithms defined in this specification are intended to be easy to understand and are not intended to be performant. Implementers are encouraged to optimize.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[FileAPI]
Marijn Kruisselbrink; Arun Ranganathan. File API. URL: https://w3c.github.io/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/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

Informative References

[ECMA-262]
ECMAScript Language Specification. URL: https://tc39.es/ecma262/multipage/
[FILE-SYSTEM-API]
Eric Uhrhane. File API: Directories and System. URL: https://dev.w3.org/2009/dap/file-system/file-dir-sys.html

IDL Index

partial interface File {
    readonly attribute USVString webkitRelativePath;
};

partial interface HTMLInputElement {
    attribute boolean webkitdirectory;
    readonly attribute FrozenArray<FileSystemEntry> webkitEntries;
};

partial interface DataTransferItem {
    FileSystemEntry? webkitGetAsEntry();
};

callback ErrorCallback = undefined (DOMException err);

[Exposed=Window]
interface FileSystemEntry {
    readonly attribute boolean isFile;
    readonly attribute boolean isDirectory;
    readonly attribute USVString name;
    readonly attribute USVString fullPath;
    readonly attribute FileSystem filesystem;

    undefined getParent(optional FileSystemEntryCallback successCallback,
                   optional ErrorCallback errorCallback);
};

[Exposed=Window]
interface FileSystemDirectoryEntry : FileSystemEntry {
    FileSystemDirectoryReader createReader();
    undefined getFile(optional USVString? path,
                 optional FileSystemFlags options = {},
                 optional FileSystemEntryCallback successCallback,
                 optional ErrorCallback errorCallback);
    undefined getDirectory(optional USVString? path,
                      optional FileSystemFlags options = {},
                      optional FileSystemEntryCallback successCallback,
                      optional ErrorCallback errorCallback);
};

dictionary FileSystemFlags {
    boolean create = false;
    boolean exclusive = false;
};

callback FileSystemEntryCallback = undefined (FileSystemEntry entry);

[Exposed=Window]
interface FileSystemDirectoryReader {
    undefined readEntries(FileSystemEntriesCallback successCallback,
                     optional ErrorCallback errorCallback);
};
callback FileSystemEntriesCallback = undefined (sequence<FileSystemEntry> entries);

[Exposed=Window]
interface FileSystemFileEntry : FileSystemEntry {
    undefined file(FileCallback successCallback,
              optional ErrorCallback errorCallback);
};
callback FileCallback = undefined (File file);

[Exposed=Window]
interface FileSystem {
    readonly attribute USVString name;
    readonly attribute FileSystemDirectoryEntry root;
};

Issues Index

EDITORIAL: Should directory be defined as a special type of file so that minimal changes are necessary in [HTML]?
EDITORIAL: This section should be merged into [FileAPI] once it is complete.
EDITORIAL: This section should be merged into [HTML] once it is complete. Sections such as the steps to construct the form data set need to be extended to include the webkitRelativePath property.
INTEROP: In Chrome, webkitEntries is only populated as the result of a drag-and-drop operation, not when the element is clicked. Should we fix this so it is always populated?
INTEROP: In Chrome, if webkitdirectory is specified on a HTMLInputElement, webkitEntries is not populated; the files collection and webkitRelativePath properties must be used instead to reconstruct the directory structure. Should we fix this so it is always populated?
EDITORIAL: This section should be merged into [HTML] once it is complete.
WEB COMPAT: The legacy TypeMismatchError has been replaced in most specifications by TypeError, but the name differs. Is it compatible to switch here as well?