Skip to content

Commit

Permalink
tie access checks to FileSystemHandle
Browse files Browse the repository at this point in the history
Fixes #101
  • Loading branch information
a-sully committed Jun 15, 2023
1 parent b2644f0 commit 19d13c9
Showing 1 changed file with 92 additions and 85 deletions.
177 changes: 92 additions & 85 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -61,54 +61,6 @@ different storage mechanism with a different API for such files. The entry point

A <dfn export id="entry">file system entry</dfn> is either a [=file entry=] or a [=directory entry=].

Each [=/file system entry=] has an associated
<dfn for="file system entry" id=entry-query-access>query access</dfn>
algorithm, which takes "`read`" or "`readwrite`" <var ignore>mode</var> and
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 an [=file system access result/error name=] of the empty string.

Each [=/file system entry=] has an associated
<dfn for="file system entry" id=entry-request-access>request access</dfn>
algorithm, which takes "`read`" or "`readwrite`" <var ignore>mode</var> and
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 an [=file system access result/error name=] of the empty string.

A <dfn export>file system access result</dfn> 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=]:

: <dfn for="file system access result">permission state</dfn>
:: A {{PermissionState}}
: <dfn for="file system access result">error name</dfn>
:: A [=string=] which must be the empty string if
[=file system access result/permission state=] is
"{{PermissionState/granted}}"; otherwise an
[=DOMException/name=] listed in the [=`DOMException` names table=].
It is expected that in most cases when
[=file system access result/permission state=] is not
"{{PermissionState/granted}}", this should be "{{NotAllowedError}}".

<p class=warning> Dependent specifications may consider this API a
[=powerful feature=]. However, unlike other [=powerful features=] whose
[=permission request algorithm=] may throw, [=/file system entry=]'s
[=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
[=queue a storage task=] to [=/reject=], 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
[=file system entry/query access=] and [=file system entry/request access=].

Issue(101): Make access check algorithms associated with a FileSystemHandle.

Each [=/file system entry=] has an associated <dfn for="file system entry" id=entry-name>name</dfn> (a [=string=]).

A <dfn>valid file name</dfn> is a [=string=] that is not an empty string, is not equal to "." or "..",
Expand Down Expand Up @@ -355,6 +307,52 @@ All other [=list/item=]s of a [=file system locator/path=] will be a
Issue(109): Consider improving this situation by giving each locator a
[=storage bucket=].

Each {{FileSystemHandle}} has an associated
<dfn for=FileSystemHandle export>query access</dfn>
algorithm, which takes "`read`" or "`readwrite`" <var ignore>mode</var> and
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 an [=file system access result/error name=] of the empty string.

Each {{FileSystemHandle}} has an associated
<dfn for=FileSystemHandle export>request access</dfn>
algorithm, which takes "`read`" or "`readwrite`" <var ignore>mode</var> and
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 an [=file system access result/error name=] of the empty string.

A <dfn export>file system access result</dfn> is a [=struct=] encapsulating the
result of [=FileSystemHandle/query access|querying=] or
[=FileSystemHandle/request access|requesting=] access to the file system.
It has the following [=struct/items=]:

: <dfn for="file system access result">permission state</dfn>
:: A {{PermissionState}}
: <dfn for="file system access result">error name</dfn>
:: A [=string=] which must be the empty string if
[=file system access result/permission state=] is
"{{PermissionState/granted}}"; otherwise an
[=DOMException/name=] listed in the [=`DOMException` names table=].
It is expected that in most cases when
[=file system access result/permission state=] is not
"{{PermissionState/granted}}", this should be "{{NotAllowedError}}".

<p class=warning> Dependent specifications may consider this API a
[=powerful feature=]. However, unlike other [=powerful features=] whose
[=permission request algorithm=] may throw, {{FileSystemHandle}}'s
[=FileSystemHandle/query access=] and [=FileSystemHandle/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
[=queue a storage task=] to [=/reject=], 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 {{FileSystemHandle}}'s
[=FileSystemHandle/query access=] and [=FileSystemHandle/request access=].

<div algorithm="serialization steps">
{{FileSystemHandle}} objects are [=serializable objects=].

Expand Down Expand Up @@ -488,9 +486,9 @@ The <dfn method for=FileSystemFileHandle>getFile()</dfn> method steps are:
1. Let |locator| be [=this=]'s [=FileSystemHandle/locator=].
1. Let |global| be [=this=]'s [=relevant global object=].
1. [=Enqueue the following steps=] to the [=file system queue=]:
1. Let |accessResult| be the result of running |global|'s
[=FileSystemHandle/query access=] given "`read`".
1. Let |entry| be the result of [=locating an entry=] given |locator|.
1. Let |accessResult| be the result of running |entry|'s
[=file system entry/query access=] given "`read`".

1. [=Queue a storage task=] with |global| to run these steps:
1. If |accessResult|'s [=file system access result/permission state=]
Expand Down Expand Up @@ -560,15 +558,15 @@ The <dfn method for=FileSystemFileHandle>createWritable(|options|)</dfn> method
1. Let |realm| be [=this=]'s [=relevant Realm=].
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 |accessResult| be the result of running |entry|'s
[=file system entry/request access=] given "`readwrite`".
1. Let |accessResult| be the result of running |global|'s
[=FileSystemHandle/request access=] given "`readwrite`".
1. If |accessResult|'s [=file system access result/permission state=]
is not "{{PermissionState/granted}}", [=queue a storage task=] with
|global| to [=/reject=] |result| with a {{DOMException}} of
|accessResult|'s [=file system access result/error name=] and
abort these steps.

1. Let |entry| be the result of [=locating an entry=] given |locator|.
1. If |entry| is `null`, [=queue a storage task=] with |global| to [=/reject=]
|result| with a "{{NotFoundError}}" {{DOMException}} and abort these steps.
1. [=Assert=]: |entry| is a [=file entry=].
Expand All @@ -581,7 +579,7 @@ The <dfn method for=FileSystemFileHandle>createWritable(|options|)</dfn> method
"{{NoModificationAllowedError}}" {{DOMException}} and abort these steps.

1. Let |stream| be the result of <a>creating a new `FileSystemWritableFileStream`</a>
for |entry| in |realm|.
given |global| and |entry| in |realm|.
1. If |options|'s {{FileSystemCreateWritableOptions/keepExistingData}} is true:
1. Set |stream|'s [=[[buffer]]=] to a copy of |entry|'s [=file entry/binary data=].
1. [=/Resolve=] |result| with |stream|.
Expand Down Expand Up @@ -623,9 +621,8 @@ The <dfn method for=FileSystemFileHandle>createSyncAccessHandle()</dfn> method s
[=this=] [=FileSystemHandle/is in an origin private file system=];
otherwise false.
1. [=Enqueue the following steps=] to the [=file system queue=]:
1. Let |entry| be the result of [=locating an entry=] given |locator|.
1. Let |accessResult| be the result of running |entry|'s
[=file system entry/request access=] given "`readwrite`".
1. Let |accessResult| be the result of running |global|'s
[=FileSystemHandle/request access=] given "`readwrite`".
1. If |accessResult|'s [=file system access result/permission state=]
is not "{{PermissionState/granted}}", [=queue a storage task=] with
|global| to [=/reject=] |result| with a {{DOMException}} of
Expand All @@ -637,6 +634,7 @@ The <dfn method for=FileSystemFileHandle>createSyncAccessHandle()</dfn> method s
[=/reject=] |result| with an "{{InvalidStateError}}" {{DOMException}} and
abort these steps.

1. Let |entry| be the result of [=locating an entry=] given |locator|.
1. If |entry| is `null`, [=queue a storage task=] with |global| to [=/reject=]
|result| with a "{{NotFoundError}}" {{DOMException}} and abort these steps.
1. [=Assert=]: |entry| is a [=file entry=].
Expand Down Expand Up @@ -754,17 +752,17 @@ and its async iterator |iterator|:

1. Let |promise| be [=a new promise=].
1. [=Enqueue the following steps=] to the [=file system queue=]:
1. Let |accessResult| be the result of running |handle|'s
[=FileSystemHandle/query access=] given "`read`".
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. [=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}}", [=/reject=] |promise| with a
{{DOMException}} of |accessResult|'s
[=file system access result/error name=] and abort these steps.:
[=file system access result/error name=] and abort these steps.

1. If |directory| is `null`, [=/reject=] |result| with a
"{{NotFoundError}}" {{DOMException}} and abort these steps.
Expand Down Expand Up @@ -838,13 +836,14 @@ The <dfn method for=FileSystemDirectoryHandle>getFileHandle(|name|, |options|)</
|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 |accessResult| be the result of running |entry|'s
[=file system entry/request access=] given "`readwrite`".
1. Let |accessResult| be the result of running |global|'s
[=FileSystemHandle/request access=] given "`readwrite`".
1. Otherwise:
1. Let |accessResult| be the result of running |entry|'s
[=file system entry/query access=] given "`read`".
1. Let |accessResult| be the result of running |global|'s
[=FileSystemHandle/query access=] given "`read`".

1. Let |entry| be the result of [=locating an entry=] given |locator|.

1. [=Queue a storage task=] with |global| to run these steps:
1. If |accessResult|'s [=file system access result/permission state=]
Expand Down Expand Up @@ -920,13 +919,14 @@ The <dfn method for=FileSystemDirectoryHandle>getDirectoryHandle(|name|, |option
|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 |accessResult| be the result of running |entry|'s
[=file system entry/request access=] given "`readwrite`".
1. Let |accessResult| be the result of running |global|'s
[=FileSystemHandle/request access=] given "`readwrite`".
1. Otherwise:
1. Let |accessResult| be the result of running |entry|'s
[=file system entry/query access=] given "`read`".
1. Let |accessResult| be the result of running |global|'s
[=FileSystemHandle/query access=] given "`read`".

1. Let |entry| be the result of [=locating an entry=] given |locator|.

1. [=Queue a storage task=] with |global| to run these steps:
1. If |accessResult|'s [=file system access result/permission state=]
Expand Down Expand Up @@ -997,9 +997,9 @@ The <dfn method for=FileSystemDirectoryHandle>removeEntry(|name|, |options|)</df
|global| to [=/reject=] |result| with a {{TypeError}} and
abort these steps.

1. Let |accessResult| be the result of running |global|'s
[=FileSystemHandle/request access=] given "`readwrite`".
1. Let |entry| be the result of [=locating an entry=] given |locator|.
1. Let |accessResult| be the result of running |entry|'s
[=file system entry/request access=] given "`readwrite`".

1. [=Queue a storage task=] with |global| to run these steps:
1. If |accessResult|'s [=file system access result/permission state=]
Expand Down Expand Up @@ -1147,19 +1147,24 @@ Similarly, when piping a {{ReadableStream}} into a {{FileSystemWritableFileStrea
<div algorithm>
To
<dfn local-lt="creating a new FileSystemWritableFileStream">create a new `FileSystemWritableFileStream`</dfn>
given a [=file entry=] |file| in a [=/Realm=] |realm|:
given a {{FileSystemFileHandle}} |fileHandle| and a [=file entry=] |fileEntry|
in a [=/Realm=] |realm|:

1. Let |stream| be a [=new=] {{FileSystemWritableFileStream}} in |realm|.
1. Set |stream|'s [=FileSystemWritableFileStream/[[file]]=] to |file|.
1. Set |stream|'s [=FileSystemWritableFileStream/[[file]]=] to |fileEntry|.
1. Let |writeAlgorithm| be an algorithm which takes a |chunk| argument
and returns the result of running the [=write a chunk=] algorithm with |stream| and |chunk|.
and returns the result of running the [=write a chunk=] algorithm with
|fileHandle|, |stream|, and |chunk|.
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 |accessResult| be the result of running |file|'s
[=file system entry/query access=] given "`readwrite`".
1. [=Assert=]: [=locating an entry=] given |fileHandle|'s
[=FileSystemHandle/locator=] returns a [=file entry=] that is
[=the same entry as=] |fileEntry|.
1. Let |accessResult| be the result of running |fileHandle|'s
[=FileSystemHandle/query access=] given "`readwrite`".

1. [=Queue a storage task=] with |file|'s [=relevant global object=]
1. [=Queue a storage task=] with |fileEntry|'s [=relevant global object=]
to run these steps:
1. If |accessResult|'s [=file system access result/permission state=]
is not "{{PermissionState/granted}}", [=/reject=] |closeResult|
Expand All @@ -1179,8 +1184,9 @@ given a [=file entry=] |file| in a [=/Realm=] |realm|:
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. [=Queue a storage task=] with
|fileEntry|'s [=relevant global object=] to
[=/resolve=] |closeResult| with `undefined`.

1. Return |closeResult|.
1. Let |abortAlgorithm| be these steps:
Expand All @@ -1200,17 +1206,18 @@ given a [=file entry=] |file| in a [=/Realm=] |realm|:
</div>

<div algorithm>
The <dfn>write a chunk</dfn> algorithm,
given a {{FileSystemWritableFileStream}} |stream| and |chunk|,
The <dfn>write a chunk</dfn> algorithm, given
a {{FileSystemFileHandle}} |fileHandle|,
a {{FileSystemWritableFileStream}} |stream|,
and a |chunk|,
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. [=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. Let |accessResult| be the result of running |fileHandle|'s
[=FileSystemHandle/query access=] given "`readwrite`".

1. [=Queue a storage task=] with |stream|'s [=relevant global object=] to
run these steps:
Expand Down

0 comments on commit 19d13c9

Please sign in to comment.