diff --git a/index.bs b/index.bs index 85791f5..6197312 100644 --- a/index.bs +++ b/index.bs @@ -64,16 +64,31 @@ A file system entry is either a [=file entry=] or a Each [=/file system entry=] has an associated query access algorithm, which takes "`read`" or "`readwrite`" mode and -returns either a {{PermissionState}} or an [=exception/error name=] that must be -listed in the [=error names table=]. -Unless specified otherwise it returns "{{PermissionState/denied}}". +returns a [=/file system access result=]. +Unless specified otherwise it returns a [=/file system access result=] with a +[=file system access result/permission state=] of "{{PermissionState/denied}}" +and with a [=file system access result/error name=] of « the empty string ». Each [=/file system entry=] has an associated request access algorithm, which takes "`read`" or "`readwrite`" mode and -returns either a {{PermissionState}} or an [=exception/error name=] that must be -listed in the [=error names table=]. -Unless specified otherwise it returns "{{PermissionState/denied}}". +returns a [=/file system access result=]. +Unless specified otherwise it returns a [=/file system access result=] with a +[=file system access result/permission state=] of "{{PermissionState/denied}}" +and with a [=file system access result/error name=] of « the empty string ». + +A file system access result is a [=struct=] encapsulating the +result of [=file system entry/query access|querying=] or +[=file system entry/request access|requesting=] access to the file system. +It has the following [=struct/items=]: + +: permission state +:: A {{PermissionState}} +: error name +:: A [=string=] which must be either « the empty string » or an + [=exception/error name=] listed in the [=error names table=]. + If [=file system access result/permission state=] is + "{{PermissionState/granted}}" this must be « the empty string »
Dependent specifications may consider this API a [=powerful feature=]. However, unlike other [=powerful features=] whose @@ -81,7 +96,8 @@ Unless specified otherwise it returns "{{PermissionState/denied}}". [=file system entry/query access=] and [=file system entry/request access=] algorithms must run [=in parallel=] on the [=file system queue=] and are therefore not allowed to throw. Instead, the caller is expected to [=/reject=] -as appropriate should these algorithms return an [=exception/error name=]. +as appropriate should these algorithms return an +[=file system access result/error name=] other than « the empty string ». Note: Implementations that only implement this specification and not dependent specifications do not need to bother implementing [=/file system entry=]'s @@ -159,7 +175,7 @@ A directory entry additionally consists of a [=/s children, which are themselves [=/file system entries=]. Each member is either a [=/file entry=] or a [=/directory entry=]. -A [=/file system entry=] |entry| should be [=list/contained=] in the [=children=] of at most one +A [=/file system entry=] |entry| should be [=list/contained=] in the [=directory entry/children=] of at most one [=directory entry=], and that directory entry is also known as |entry|'s parent. A [=/file system entry=]'s [=file system entry/parent=] is null if no such directory entry exists. @@ -170,7 +186,7 @@ parent while the other entry does not have a parent. [=/File system entries=] can (but don't have to) be backed by files on the host operating system's local file system, so it is possible for the [=binary data=], [=modification timestamp=], -and [=children=] of entries to be modified by applications outside of this specification. +and [=directory entry/children=] of entries to be modified by applications outside of this specification. Exactly how external changes are reflected in the data structures defined by this specification, as well as how changes made to the data structures defined here are reflected externally is left up to individual user-agent implementations. @@ -185,22 +201,22 @@ To resolve a [=/file system locator=] |child| relative to a [=directory locator=] |root|: 1. Let |result| be [=a new promise=]. -1. Run these steps [=in parallel=]: +1. [=Enqueue the following steps=] to the [=file system queue=]: 1. If |child|'s [=FileSystemHandle/locator=]'s [=file system locator/root=] is not |root|'s [=FileSystemHandle/locator=]'s [=file system locator/root=], - [=/resolve=] |result| with null, and abort. + [=/resolve=] |result| with null, and abort these steps. 1. Let |childPath| be |child|'s [=FileSystemHandle/locator=]'s [=file system locator/path=]. 1. Let |rootPath| be |root|'s [=FileSystemHandle/locator=]'s [=file system locator/path=]. 1. If |childPath| is [=the same path as=] |rootPath|, - [=/resolve=] |result| with « », and abort. + [=/resolve=] |result| with « », and abort these steps. 1. If |rootPath|'s [=list/size=] is greater than |childPath|'s [=list/size=], - [=/resolve=] |result| with null, and abort. + [=/resolve=] |result| with null, and abort these steps. 1. [=list/For each=] |index| of |rootPath|'s [=list/indices=]: 1. If |rootPath|.\[[|index|]] is not |childPath|.\[[|index|]], then - [=/resolve=] |result| with null, and abort. + [=/resolve=] |result| with null, and abort these steps. 1. Let |relativePath| be « ». 1. [=list/For each=] |index| of [=the range=] from |rootPath|'s [=list/size=] @@ -373,7 +389,7 @@ The isSameEntry(|other|) method steps are 1. Let |realm| be [=this=]'s [=relevant Realm=]. 1. Let |p| be [=a new promise=] in |realm|. -1. Run these steps [=in parallel=]: +1. [=Enqueue the following steps=] to the [=file system queue=]: 1. If [=this=]'s [=FileSystemHandle/locator=] is [=the same locator as=] |other|'s [=FileSystemHandle/locator=], [=/resolve=] |p| with true. @@ -452,27 +468,35 @@ The getFile() method steps are: 1. Let |result| be [=a new promise=]. 1. Let |locator| be [=this=]'s [=FileSystemHandle/locator=]. -1. Run these steps [=in parallel=]: +1. Let |global| be [=this=]'s [=relevant global object=]. +1. [=Enqueue the following steps=] to the [=file system queue=]: 1. Let |entry| be the result of [=locating an entry=] given |locator|. - 1. Let |access| be the result of running |entry|'s + 1. Let |accessResult| be the result of running |entry|'s [=file system entry/query access=] given "`read`". - 1. If |access| is not "{{PermissionState/granted}}", - [=/reject=] |result| with a "{{NotAllowedError}}" {{DOMException}} and abort. - 1. If |entry| is null, [=/reject=] |result| with a - "{{NotFoundError}}" {{DOMException}} and abort. - 1. [=Assert=]: |entry| is a [=file entry=]. - - 1. Let |f| be a new {{File}}. - 1. Set |f|'s snapshot state to the current state of |entry|. - 1. Set |f|'s underlying byte sequence to a copy of |entry|'s [=binary data=]. - 1. Set |f|.{{File/name}} to |entry|'s [=file system entry/name=]. - 1. Set |f|.{{File/lastModified}} to |entry|'s [=file entry/modification timestamp=]. - 1. Set |f|.{{Blob/type}} to an [=implementation-defined=] value, based on for example |entry|'s [=file system entry/name=] or its file extension. - - Issue: The reading and snapshotting behavior needs to be better specified in the [[FILE-API]] spec, - for now this is kind of hand-wavy. - 1. [=/Resolve=] |result| with |f|. + 1. [=Queue a storage task=] with |global| to run these steps: + 1. If |accessResult|'s [=file system access result/permission state=] + is not "{{PermissionState/granted}}": + 1. Set |accessErrorName| to |accessResult|'s + [=file system access result/error name=] if it is not + « the empty string »; otherwise "{{NotAllowedError}}". + 1. [=/Reject=] |result| with an |accessErrorName| {{DOMException}} and + abort these steps. + + 1. If |entry| is null, [=/reject=] |result| with a + "{{NotFoundError}}" {{DOMException}} and abort these steps. + 1. [=Assert=]: |entry| is a [=file entry=]. + + 1. Let |f| be a new {{File}}. + 1. Set |f|'s snapshot state to the current state of |entry|. + 1. Set |f|'s underlying byte sequence to a copy of |entry|'s [=binary data=]. + 1. Set |f|.{{File/name}} to |entry|'s [=file system entry/name=]. + 1. Set |f|.{{File/lastModified}} to |entry|'s [=file entry/modification timestamp=]. + 1. Set |f|.{{Blob/type}} to an [=implementation-defined=] value, based on for example |entry|'s [=file system entry/name=] or its file extension. + + Issue: The reading and snapshotting behavior needs to be better specified in the [[FILE-API]] spec, + for now this is kind of hand-wavy. + 1. [=/Resolve=] |result| with |f|. 1. Return |result|. @@ -522,13 +546,15 @@ The createWritable(|options|) method 1. Let |global| be [=this=]'s [=relevant global object=]. 1. [=Enqueue the following steps=] to the [=file system queue=]: 1. Let |entry| be the result of [=locating an entry=] given |locator|. - 1. Let |access| be the result of running |entry|'s + 1. Let |accessResult| be the result of running |entry|'s [=file system entry/request access=] given "`readwrite`". - 1. If |access| is not "{{PermissionState/granted}}": - 1. Set |requestAccessError| to |access| if |access| is an - [=exception/error name=]; otherwise, "{{NotAllowedError}}". - 1. [=Queue a storage task=] with |global| to [=/reject=] |result| with a - |requestAccessError| {{DOMException}} and abort these steps. + 1. If |accessResult|'s [=file system access result/permission state=] + is not "{{PermissionState/granted}}": + 1. Set |accessErrorName| to |accessResult|'s + [=file system access result/error name=] if it is not + « the empty string »; otherwise "{{NotAllowedError}}". + 1. [=Queue a storage task=] with |global| to [=/reject=] |result| with an + |accessErrorName| {{DOMException}} and abort these steps. 1. If |entry| is `null`, [=queue a storage task=] with |global| to [=/reject=] |result| with a "{{NotFoundError}}" {{DOMException}} and abort these steps. @@ -536,11 +562,11 @@ The createWritable(|options|) method 1. Let |lockResult| be the result of [=file entry/lock/take|taking a lock=] with "`shared`" on |entry|. - 1. If |lockResult| is "`failure`", [=queue a storage task=] with |global| to - [=/reject=] |result| with a - "{{NoModificationAllowedError}}" {{DOMException}} and abort these steps. 1. [=Queue a storage task=] with |global| to run these steps: + 1. If |lockResult| is "`failure`", [=/reject=] |result| with a + "{{NoModificationAllowedError}}" {{DOMException}} and abort these steps. + 1. Let |stream| be the result of creating a new `FileSystemWritableFileStream` for |entry| in |realm|. 1. If |options|'s {{FileSystemCreateWritableOptions/keepExistingData}} is true: @@ -582,13 +608,15 @@ The createSyncAccessHandle() method s 1. Let |global| be [=this=]'s [=relevant global object=]. 1. [=Enqueue the following steps=] to the [=file system queue=]: 1. Let |entry| be the result of [=locating an entry=] given |locator|. - 1. Let |access| be the result of running |entry|'s + 1. Let |accessResult| be the result of running |entry|'s [=file system entry/request access=] given "`readwrite`". - 1. If |access| is not "{{PermissionState/granted}}": - 1. Set |requestAccessError| to |access| if |access| is an - [=exception/error name=]; otherwise, "{{NotAllowedError}}". - 1. [=Queue a storage task=] with |global| to [=/reject=] |result| with a - |requestAccessError| {{DOMException}} and abort these steps. + 1. If |accessResult|'s [=file system access result/permission state=] + is not "{{PermissionState/granted}}": + 1. Set |accessErrorName| to |accessResult|'s + [=file system access result/error name=] if it is not + « the empty string »; otherwise "{{NotAllowedError}}". + 1. [=Queue a storage task=] with |global| to [=/reject=] |result| with an + |accessErrorName| {{DOMException}} and abort these steps. 1. If |entry| is `null`, [=queue a storage task=] with |global| to [=/reject=] |result| with a "{{NotFoundError}}" {{DOMException}} and abort these steps. @@ -601,11 +629,11 @@ The createSyncAccessHandle() method s 1. Let |lockResult| be the result of [=file entry/lock/take|taking a lock=] with "`exclusive`" on |entry|. - 1. If |lockResult| is "`failure`", [=queue a storage task=] with |global| to - [=/reject=] |result| with a - "{{NoModificationAllowedError}}" {{DOMException}} and abort these steps. 1. [=Queue a storage task=] with |global| to run these steps: + 1. If |lockResult| is "`failure`", [=/reject=] |result| with a + "{{NoModificationAllowedError}}" {{DOMException}} and abort these steps. + 1. Let |handle| be the result of creating a new `FileSystemSyncAccessHandle` for |entry| in |realm|. 1. [=/Resolve=] |result| with |handle|. @@ -701,13 +729,17 @@ support for example recursive iteration. The [=asynchronous iterator initialization steps=] for a {{FileSystemDirectoryHandle}} |handle| and its async iterator |iterator| are: -1. Let |entry| be the result of [=locating an entry=] - given |handle|'s [=FileSystemHandle/locator=]. -1. Let |access| be the result of running |entry|'s - [=file system entry/query access=] given "`read`". - -1. If |access| is not "{{PermissionState/granted}}", - [=throw=] a "{{NotAllowedError}}" {{DOMException}}. +1. [=Enqueue the following steps=] to the [=file system queue=]: + 1. Let |entry| be the result of [=locating an entry=] + given |handle|'s [=FileSystemHandle/locator=]. + 1. Let |accessResult| be the result of running |entry|'s + [=file system entry/query access=] given "`read`". + 1. If |accessResult|'s [=file system access result/permission state=] + is not "{{PermissionState/granted}}": + 1. Set |accessErrorName| to |accessResult|'s + [=file system access result/error name=] if it is not + « the empty string »; otherwise "{{NotAllowedError}}". + 1. [=Throw=] an |accessErrorName| {{DOMException}}. 1. Set |iterator|'s past results to an empty [=/set=]. @@ -718,43 +750,54 @@ To [=get the next iteration result=] for a {{FileSystemDirectoryHandle}} |handle and its async iterator |iterator|: 1. Let |promise| be [=a new promise=]. +1. [=Enqueue the following steps=] to the [=file system queue=]: + 1. Let |directory| be the result of [=locating an entry=] + given |handle|'s [=FileSystemHandle/locator=]. + 1. Let |accessResult| be the result of running |directory|'s + [=file system entry/query access=] given "`read`". -1. Let |directory| be the result of [=locating an entry=] - given |handle|'s [=FileSystemHandle/locator=]. -1. If |directory| is `null`, [=/reject=] |result| with a - "{{NotFoundError}}" {{DOMException}} and abort. - 1. [=Assert=]: |directory| is a [=directory entry=]. - -1. Let |access| be the result of running |directory|'s - [=file system entry/query access=] given "`read`". - -1. If |access| is not "{{PermissionState/granted}}", - [=/reject=] |promise| with a "{{NotAllowedError}}" {{DOMException}} and - return |promise|. - -1. Let |child| be a [=/file system entry=] in |directory|'s [=directory entry/children=], - such that |child|'s [=file system entry/name=] is not contained in |iterator|'s [=past results=], - or `null` if no such entry exists. - - Note: This is intentionally very vague about the iteration order. Different platforms - and file systems provide different guarantees about iteration order, and we want it to - be possible to efficiently implement this on all platforms. As such no guarantees are given - about the exact order in which elements are returned. - -1. If |child| is `null`, then: - 1. [=/Resolve=] |promise| with `undefined`. - -1. Otherwise: - 1. [=set/Append=] |child|'s [=file system entry/name=] to |iterator|'s [=past results=]. - 1. If |child| is a [=file entry=]: - 1. Let |result| be the result of creating a child `FileSystemFileHandle` - with |handle|'s [=FileSystemHandle/locator=] and - |child|'s [=file system entry/name=] in |handle|'s [=relevant Realm=]. - 1. Otherwise: - 1. Let |result| be the result of creating a child `FileSystemDirectoryHandle` - with |handle|'s [=FileSystemHandle/locator=] and - |child|'s [=file system entry/name=] in |handle|'s [=relevant Realm=]. - 1. [=/Resolve=] |promise| with (|child|'s [=file system entry/name=], |result|). + 1. [=Queue a storage task=] with |handle|'s [=relevant global object=] to + run these steps: + 1. If |accessResult|'s [=file system access result/permission state=] + is not "{{PermissionState/granted}}": + 1. Set |accessErrorName| to |accessResult|'s + [=file system access result/error name=] if it is not + « the empty string »; otherwise "{{NotAllowedError}}". + 1. [=/Reject=] |promise| with an |accessErrorName| {{DOMException}} + and return |promise|. + + 1. If |directory| is `null`, [=/reject=] |result| with a + "{{NotFoundError}}" {{DOMException}} and abort these steps. + 1. [=Assert=]: |directory| is a [=directory entry=]. + + 1. Let |child| be a [=/file system entry=] in + |directory|'s [=directory entry/children=], such that + |child|'s [=file system entry/name=] is not contained in + |iterator|'s [=past results=], or `null` if no such entry exists. + + Note: This is intentionally very vague about the iteration order. + Different platforms and file systems provide different guarantees about + iteration order, and we want it to be possible to efficiently implement + this on all platforms. As such no guarantees are given about the exact + order in which elements are returned. + + 1. If |child| is `null`, [=/resolve=] |promise| with `undefined` and + abort these steps. + + 1. [=set/Append=] |child|'s [=file system entry/name=] to + |iterator|'s [=past results=]. + 1. If |child| is a [=file entry=]: + 1. Let |result| be the result of + creating a child `FileSystemFileHandle` with + |handle|'s [=FileSystemHandle/locator=] and + |child|'s [=file system entry/name=] in |handle|'s [=relevant Realm=]. + 1. Otherwise: + 1. Let |result| be the result of + creating a child `FileSystemDirectoryHandle` with + |handle|'s [=FileSystemHandle/locator=] and + |child|'s [=file system entry/name=] in |handle|'s [=relevant Realm=]. + 1. [=/Resolve=] |promise| with + (|child|'s [=file system entry/name=], |result|). 1. Return |promise|. @@ -789,47 +832,58 @@ The getFileHandle(|name|, |options|) 1. Let |result| be [=a new promise=]. 1. Let |realm| be [=this=]'s [=relevant Realm=]. 1. Let |locator| be [=this=]'s [=FileSystemHandle/locator=]. -1. Run these steps [=in parallel=]: - 1. If |name| is not a [=valid file name=], [=/reject=] |result| with a {{TypeError}} and abort. +1. Let |global| be [=this=]'s [=relevant global object=]. +1. [=Enqueue the following steps=] to the [=file system queue=]: + 1. If |name| is not a [=valid file name=], [=queue a storage task=] with + |global| to [=/reject=] |result| with a {{TypeError}} and + abort these steps. 1. Let |entry| be the result of [=locating an entry=] given |locator|. 1. If |options|.{{FileSystemGetFileOptions/create}} is true: - 1. Let |access| be the result of running |entry|'s + 1. Let |accessResult| be the result of running |entry|'s [=file system entry/request access=] given "`readwrite`". - If that throws an exception, [=/reject=] |result| with that exception and abort. 1. Otherwise: - 1. Let |access| be the result of running |entry|'s + 1. Let |accessResult| be the result of running |entry|'s [=file system entry/query access=] given "`read`". - 1. If |access| is not "{{PermissionState/granted}}", - [=/reject=] |result| with a "{{NotAllowedError}}" {{DOMException}} and abort. - - 1. If |entry| is `null`, [=/reject=] |result| with a - "{{NotFoundError}}" {{DOMException}} and abort. - 1. [=Assert=]: |entry| is a [=directory entry=]. - - - 1. [=set/For each=] |child| of |entry|'s [=directory entry/children=]: - 1. If |child|'s [=file system entry/name=] equals |name|: - 1. If |child| is a [=directory entry=]: - 1. [=/Reject=] |result| with a "{{TypeMismatchError}}" {{DOMException}} and abort. - 1. [=/Resolve=] |result| with the result of - creating a child `FileSystemFileHandle` with |locator| and - |child|'s [=file system entry/name=] in |realm| and abort. - 1. If |options|.{{FileSystemGetFileOptions/create}} is false: - 1. [=/Reject=] |result| with a "{{NotFoundError}}" {{DOMException}} and abort. - 1. Let |child| be a new [=file entry=] whose [=query access=] and [=request access=] algorithms - are those of |entry|. - 1. Set |child|'s [=file system entry/name=] to |name|. - 1. Set |child|'s [=binary data=] to an empty [=byte sequence=]. - 1. Set |child|'s [=modification timestamp=] to the current time. - 1. [=set/Append=] |child| to |entry|'s [=directory entry/children=]. - 1. If creating |child| in the underlying file system throws an exception, - [=/reject=] |result| with that exception and abort. - - Issue(11): Better specify what possible exceptions this could throw. - 1. [=/Resolve=] |result| with the result of - creating a child `FileSystemFileHandle` with |locator| and - |child|'s [=file system entry/name=] in |realm|. + + 1. [=Queue a storage task=] with |global| to run these steps: + 1. If |accessResult|'s [=file system access result/permission state=] + is not "{{PermissionState/granted}}": + 1. Set |accessErrorName| to |accessResult|'s + [=file system access result/error name=] if it is not + « the empty string »; otherwise "{{NotAllowedError}}". + 1. [=/Reject=] |result| with an |accessErrorName| {{DOMException}} and + abort these steps. + + 1. If |entry| is `null`, [=/reject=] |result| with a + "{{NotFoundError}}" {{DOMException}} and abort these steps. + 1. [=Assert=]: |entry| is a [=directory entry=]. + + 1. [=set/For each=] |child| of |entry|'s [=directory entry/children=]: + 1. If |child|'s [=file system entry/name=] equals |name|: + 1. If |child| is a [=directory entry=]: + 1. [=/Reject=] |result| with a + "{{TypeMismatchError}}" {{DOMException}} and abort these steps. + 1. [=/Resolve=] |result| with the result of + creating a child `FileSystemFileHandle` with |locator| and + |child|'s [=file system entry/name=] in |realm| and + abort these steps. + 1. If |options|.{{FileSystemGetFileOptions/create}} is false: + 1. [=/Reject=] |result| with a "{{NotFoundError}}" {{DOMException}} and + abort these steps. + 1. Let |child| be a new [=file entry=] whose [=query access=] and + [=request access=] algorithms are those of |entry|. + 1. Set |child|'s [=file system entry/name=] to |name|. + 1. Set |child|'s [=binary data=] to an empty [=byte sequence=]. + 1. Set |child|'s [=modification timestamp=] to the current time. + 1. [=set/Append=] |child| to |entry|'s [=directory entry/children=]. + 1. If creating |child| in the underlying file system throws an exception, + [=/reject=] |result| with that exception and abort these steps. + + Issue(11): Better specify what possible exceptions this could throw. + 1. [=/Resolve=] |result| with the result of + creating a child `FileSystemFileHandle` with |locator| and + |child|'s [=file system entry/name=] in |realm|. 1. Return |result|. @@ -863,45 +917,57 @@ The getDirectoryHandle(|name|, |option 1. Let |result| be [=a new promise=]. 1. Let |realm| be [=this=]'s [=relevant Realm=]. 1. Let |locator| be [=this=]'s [=FileSystemHandle/locator=]. -1. Run these steps [=in parallel=]: - 1. If |name| is not a [=valid file name=], [=/reject=] |result| with a {{TypeError}} and abort. +1. Let |global| be [=this=]'s [=relevant global object=]. +1. [=Enqueue the following steps=] to the [=file system queue=]: + 1. If |name| is not a [=valid file name=], [=queue a storage task=] with + |global| to [=/reject=] |result| with a {{TypeError}} and + abort these steps. 1. Let |entry| be the result of [=locating an entry=] given |locator|. 1. If |options|.{{FileSystemGetDirectoryOptions/create}} is true: - 1. Let |access| be the result of running |entry|'s + 1. Let |accessResult| be the result of running |entry|'s [=file system entry/request access=] given "`readwrite`". - If that throws an exception, [=/reject=] |result| with that exception and abort. 1. Otherwise: - 1. Let |access| be the result of running |entry|'s + 1. Let |accessResult| be the result of running |entry|'s [=file system entry/query access=] given "`read`". - 1. If |access| is not "{{PermissionState/granted}}", - [=/reject=] |result| with a "{{NotAllowedError}}" {{DOMException}} and abort. - - 1. If |entry| is `null`, [=/reject=] |result| with a - "{{NotFoundError}}" {{DOMException}} and abort. - 1. [=Assert=]: |entry| is a [=directory entry=]. - - 1. [=set/For each=] |child| of |entry|'s [=directory entry/children=]: - 1. If |child|'s [=file system entry/name=] equals |name|: - 1. If |child| is a [=file entry=]: - 1. [=/Reject=] |result| with a "{{TypeMismatchError}}" {{DOMException}} and abort. - 1. [=/Resolve=] |result| with the result of - creating a child `FileSystemDirectoryHandle` with - |locator| and |child|'s [=file system entry/name=] in |realm| and abort. - 1. If |options|.{{FileSystemGetFileOptions/create}} is false: - 1. [=/Reject=] |result| with a "{{NotFoundError}}" {{DOMException}} and abort. - 1. Let |child| be a new [=directory entry=] whose [=query access=] and [=request access=] - algorithms are those of |entry|. - 1. Set |child|'s [=file system entry/name=] to |name|. - 1. Set |child|'s [=directory entry/children=] to an empty [=/set=]. - 1. [=set/Append=] |child| to |entry|'s [=directory entry/children=]. - 1. If creating |child| in the underlying file system throws an exception, - [=/reject=] |result| with that exception and abort. - - Issue(11): Better specify what possible exceptions this could throw. - 1. [=/Resolve=] |result| with the result of - creating a child `FileSystemDirectoryHandle` with - |locator| and |child|'s [=file system entry/name=] in |realm|. + + 1. [=Queue a storage task=] with |global| to run these steps: + 1. If |accessResult|'s [=file system access result/permission state=] + is not "{{PermissionState/granted}}": + 1. Set |accessErrorName| to |accessResult|'s + [=file system access result/error name=] if it is not + « the empty string »; otherwise "{{NotAllowedError}}". + 1. [=/Reject=] |result| with an |accessErrorName| {{DOMException}} and + abort these steps. + + 1. If |entry| is `null`, [=/reject=] |result| with a + "{{NotFoundError}}" {{DOMException}} and abort these steps. + 1. [=Assert=]: |entry| is a [=directory entry=]. + + 1. [=set/For each=] |child| of |entry|'s [=directory entry/children=]: + 1. If |child|'s [=file system entry/name=] equals |name|: + 1. If |child| is a [=file entry=]: + 1. [=/Reject=] |result| with a + "{{TypeMismatchError}}" {{DOMException}} and abort these steps. + 1. [=/Resolve=] |result| with the result of + creating a child `FileSystemDirectoryHandle` with + |locator| and |child|'s [=file system entry/name=] in |realm| and + abort these steps. + 1. If |options|.{{FileSystemGetFileOptions/create}} is false: + 1. [=/Reject=] |result| with a "{{NotFoundError}}" {{DOMException}} and + abort these steps. + 1. Let |child| be a new [=directory entry=] whose [=query access=] and + [=request access=] algorithms are those of |entry|. + 1. Set |child|'s [=file system entry/name=] to |name|. + 1. Set |child|'s [=directory entry/children=] to an empty [=/set=]. + 1. [=set/Append=] |child| to |entry|'s [=directory entry/children=]. + 1. If creating |child| in the underlying file system throws an exception, + [=/reject=] |result| with that exception and abort these steps. + + Issue(11): Better specify what possible exceptions this could throw. + 1. [=/Resolve=] |result| with the result of + creating a child `FileSystemDirectoryHandle` with + |locator| and |child|'s [=file system entry/name=] in |realm|. 1. Return |result|. @@ -931,36 +997,50 @@ The removeEntry(|name|, |options|) @@ -1085,17 +1165,19 @@ given a [=file entry=] |file| in a [=/Realm=] |realm|: 1. Let |closeAlgorithm| be these steps: 1. Let |closeResult| be [=a new promise=]. 1. [=Enqueue the following steps=] to the [=file system queue=]: - 1. Let |access| be the result of running |file|'s + 1. Let |accessResult| be the result of running |file|'s [=file system entry/query access=] given "`readwrite`". - 1. If |access| is not "{{PermissionState/granted}}": - 1. Set |requestAccessError| to |access| if |access| is an - [=exception/error name=]; otherwise, "{{NotAllowedError}}". - 1. [=Queue a storage task=] with |file|'s [=relevant global object=] to - [=/reject=] |closeResult| with a - |requestAccessError| {{DOMException}} and abort these steps. 1. [=Queue a storage task=] with |file|'s [=relevant global object=] to run these steps: + 1. If |accessResult|'s [=file system access result/permission state=] + is not "{{PermissionState/granted}}": + 1. Set |accessErrorName| to |accessResult|'s + [=file system access result/error name=] if it is not + « the empty string »; otherwise "{{NotAllowedError}}". + 1. [=/Reject=] |closeResult| with an + |accessErrorName| {{DOMException}} and abort these steps. + 1. Run [=implementation-defined=] malware scans and safe browsing checks. If these checks fail, [=/reject=] |closeResult| with an "{{AbortError}}" {{DOMException}} and abort these steps. @@ -1107,14 +1189,16 @@ given a [=file entry=] |file| in a [=/Realm=] |realm|: Note: It is expected that this atomically updates the contents of the file on disk being written to. - 1. [=file entry/lock/release|Release the lock=] on - |stream|'s [=FileSystemWritableFileStream/[[file]]=]. - 1. [=/Resolve=] |closeResult| with `undefined`. + 1. [=Enqueue the following steps=] to the [=file system queue=]: + 1. [=file entry/lock/release|Release the lock=] on + |stream|'s [=FileSystemWritableFileStream/[[file]]=]. + 1. [=Queue a storage task=] with |file|'s [=relevant global object=] + to [=/resolve=] |closeResult| with `undefined`. 1. Return |closeResult|. 1. Let |abortAlgorithm| be these steps: 1. [=enqueue steps|Enqueue this step=] to the [=file system queue=]: - 1. [=file entry/lock/release|release the lock=] on + 1. [=file entry/lock/release|Release the lock=] on |stream|'s [=FileSystemWritableFileStream/[[file]]=]. 1. Let |highWaterMark| be 1. 1. Let |sizeAlgorithm| be an algorithm that returns `1`. @@ -1136,18 +1220,28 @@ runs these steps: 1. Let |input| be the result of [=converted to an IDL value|converting=] |chunk| to a {{FileSystemWriteChunkType}}. If this throws an exception, then return [=a promise rejected with=] that exception. 1. Let |p| be [=a new promise=]. -1. Run these steps [=in parallel=]: - 1. Let |access| be the result of running |stream|'s [=FileSystemWritableFileStream/[[file]]=]'s - [=file system entry/query access=] given "`readwrite`". - 1. If |access| is not "{{PermissionState/granted}}", - [=/reject=] |p| with a "{{NotAllowedError}}" {{DOMException}} and abort. - 1. Let |command| be |input|.{{WriteParams/type}} if |input| is a {{WriteParams}}, - and {{WriteCommandType/"write"}} otherwise. - 1. If |command| is {{WriteCommandType/"write"}}: +1. [=Enqueue the following steps=] to the [=file system queue=]: + 1. Let |accessResult| be the result of running + |stream|'s [=FileSystemWritableFileStream/[[file]]=]'s + [=file system entry/query access=] given "`readwrite`". + + 1. [=Queue a storage task=] with |stream|'s [=relevant global object=] to + run these steps: + 1. If |accessResult|'s [=file system access result/permission state=] + is not "{{PermissionState/granted}}": + 1. Set |accessErrorName| to |accessResult|'s + [=file system access result/error name=] if it is not + « the empty string »; otherwise "{{NotAllowedError}}". + 1. [=/Reject=] |p| with an |accessErrorName| {{DOMException}} and + abort these steps. + + 1. Let |command| be |input|.{{WriteParams/type}} if |input| is a {{WriteParams}}, + and {{WriteCommandType/"write"}} otherwise. + 1. If |command| is {{WriteCommandType/"write"}}: 1. Let |data| be |input|.{{WriteParams/data}} if |input| is a {{WriteParams}}, and |input| otherwise. 1. If |data| is `undefined`, - [=/reject=] |p| with a {{TypeError}} and abort. + [=/reject=] |p| with a {{TypeError}} and abort these steps. 1. Let |writePosition| be |stream|.[=[[seekOffset]]=]. 1. If |input| is a {{WriteParams}} and |input|.{{WriteParams/position}} is not `undefined`, set |writePosition| to |input|.{{WriteParams/position}}. @@ -1157,7 +1251,8 @@ runs these steps: 1. Otherwise, if |data| is a {{Blob}}: 1. Let |dataBytes| be the result of performing the read operation on |data|. - If this throws an exception, [=/reject=] |p| with that exception and abort. + If this throws an exception, [=/reject=] |p| with that exception + and abort these steps. 1. Otherwise: 1. [=Assert=]: |data| is a {{USVString}}. 1. Let |dataBytes| be the result of [=UTF-8 encoding=] |data|. @@ -1176,7 +1271,8 @@ runs these steps: |oldSize| - (|writePosition| + |data|.[=byte sequence/length=]) bytes of |stream|.[=[[buffer]]=]. 1. Set |stream|.[=[[buffer]]=] to the concatenation of |head|, |data| and |tail|. 1. If the operations modifying |stream|.[=[[buffer]]=] in the previous steps failed - due to exceeding the [=storage quota=], [=/reject=] |p| with a "{{QuotaExceededError}}" {{DOMException}} and abort, + due to exceeding the [=storage quota=], [=/reject=] |p| with a + "{{QuotaExceededError}}" {{DOMException}} and abort these steps, leaving |stream|.[=[[buffer]]=] unmodified. Note: [=Storage quota=] only applies to files stored in the [=origin private file system=]. @@ -1184,22 +1280,22 @@ runs these steps: to runs out of disk space. 1. Set |stream|.[=[[seekOffset]]=] to |writePosition| + |data|.[=byte sequence/length=]. 1. [=/Resolve=] |p|. - 1. Otherwise, if |command| is {{WriteCommandType/"seek"}}: + 1. Otherwise, if |command| is {{WriteCommandType/"seek"}}: 1. If |chunk|.{{WriteParams/position}} is `undefined`, - [=/reject=] |p| with a {{TypeError}} and abort. + [=/reject=] |p| with a {{TypeError}} and abort these steps. 1. Set |stream|.[=[[seekOffset]]=] to |chunk|.{{WriteParams/position}}. 1. [=/Resolve=] |p|. - 1. Otherwise, if |command| is {{WriteCommandType/"truncate"}}: + 1. Otherwise, if |command| is {{WriteCommandType/"truncate"}}: 1. If |chunk|.{{WriteParams/size}} is `undefined`, - [=/reject=] |p| with a {{TypeError}} and abort. + [=/reject=] |p| with a {{TypeError}} and abort these steps. 1. Let |newSize| be |chunk|.{{WriteParams/size}}. 1. Let |oldSize| be |stream|.[=[[buffer]]=]'s [=byte sequence/length=]. 1. If |newSize| is larger than |oldSize|: 1. Set |stream|.[=[[buffer]]=] to a [=byte sequence=] formed by concating |stream|.[=[[buffer]]=] with a [=byte sequence=] containing |newSize|-|oldSize| `0x00` bytes. 1. If the operation in the previous step failed due to exceeding the [=storage quota=], - [=/reject=] |p| with a "{{QuotaExceededError}}" {{DOMException}} and abort, - leaving |stream|.[=[[buffer]]=] unmodified. + [=/reject=] |p| with a "{{QuotaExceededError}}" {{DOMException}} and + abort these steps, leaving |stream|.[=[[buffer]]=] unmodified. Note: [=Storage quota=] only applies to files stored in the [=origin private file system=]. However this operation could still fail for other files, for example if the disk being written @@ -1603,8 +1699,12 @@ The getDirectory() method steps are: return [=a promise rejected with=] a "{{SecurityError}}" {{DOMException}}. 1. If |map|["root"] does not [=map/exist=]: - 1. Let |dir| be a new [=directory entry=] whose [=query access=] and [=request access=] algorithms - always return "{{PermissionState/granted}}". + 1. Let |dir| be a new [=directory entry=] whose [=query access=] and + [=request access=] algorithms always return + a [=/file system access result=] + with a [=file system access result/permission state=] + of "{{PermissionState/granted}}" and + with a [=file system access result/error name=] of « the empty string ». 1. Set |dir|'s [=file system entry/name=] to the empty string. 1. Set |dir|'s [=directory entry/children=] to an empty [=/set=]. 1. Set |map|["root"] to |dir|.