diff --git a/index.bs b/index.bs index 43da40f..fcfe754 100644 --- a/index.bs +++ b/index.bs @@ -127,7 +127,8 @@ systems. A file entry additionally consists of binary data (a [=byte sequence=]), a modification timestamp (a number representing the number of milliseconds since the Unix Epoch), -a lock (a string that may exclusively be "`open`", "`taken-exclusive`" or "`taken-shared`") +a lock (a [=string=] that may exclusively be "`open`", "`exclusive`", "`writableSiloed`", +"`syncAccessHandleReadOnly`", "`syncAccessHandleReadWriteUnsafe`") and a shared lock count (a number representing the number of shared locks that are taken at a given point in time). A user agent has an associated file system queue which is the @@ -135,23 +136,20 @@ result of [=starting a new parallel queue=]. This queue is to be used for all file system operations.
-To take a lock with a |value| of -"`exclusive`" or "`shared`" on a given [=file entry=] |file|: +To take a lock with a |lockType| (a [=string=]) +on a given [=file entry=] |file|: +1. [=Assert=]: |lockType| is "`exclusive`", "`writableSiloed`", "`syncAccessHandleReadOnly`", or "`syncAccessHandleReadWriteUnsafe`". 1. Let |lock| be the |file|'s [=file entry/lock=]. 1. Let |count| be the |file|'s [=file entry/shared lock count=]. -1. If |value| is "`exclusive`": - 1. If |lock| is "`open`": - 1. Set lock to "`taken-exclusive`". - 1. Return "`success`". -1. If |value| is "`shared`": - 1. If |lock| is "`open`": - 1. Set |lock| to "`taken-shared`". - 1. Set |count| to 1. - 1. Return "`success`". - 1. Otherwise, if |lock| is "`taken-shared`": - 1. Increase |count| by 1. - 1. Return "`success`". +1. If |lock| is null: + 1. Set |lock| to |lockType|. + 1. Set |count| to 1. + 1. Return "`success`". +1. If |lock| is not "`exclusive`": + 1. If |lock| equals |lockType|: + 1. Increase |count| by 1. + 1. Return "`success`". 1. Return "`failure`". Note: These steps have to be run on the [=file system queue=]. @@ -164,10 +162,9 @@ To release a [=file entry/lock=] on a given 1. Let |lock| be the |file|'s associated [=file entry/lock=]. 1. Let |count| be the |file|'s [=file entry/shared lock count=]. -1. If |lock| is "`taken-shared`": - 1. Decrease |count| by 1. - 1. If |count| is 0, set |lock| to "`open`". -1. Otherwise, set |lock| to "`open`". +1. [=Assert=]: |count| is greater than 0. +1. Decrease |count| by 1. +1. If |count| is 0, set |lock| to null. Note: These steps have to be run on the [=file system queue=]. @@ -420,8 +417,24 @@ The isSameEntry(|other|) method steps are ## The {{FileSystemFileHandle}} interface ## {#api-filesystemfilehandle} +enum FileSystemWritableFileStreamMode { + "exclusive", + "siloed", +}; + dictionary FileSystemCreateWritableOptions { boolean keepExistingData = false; + FileSystemWritableFileStreamMode mode = "siloed"; +}; + +enum FileSystemSyncAccessHandleMode { + "readwrite", + "read-only", + "readwrite-unsafe", +}; + +dictionary FileSystemCreateSyncAccessHandleOptions { + FileSystemSyncAccessHandleMode mode = "readwrite"; }; [Exposed=(Window,Worker), SecureContext, Serializable] @@ -429,7 +442,7 @@ interface FileSystemFileHandle : FileSystemHandle { Promise<File> getFile(); Promise<FileSystemWritableFileStream> createWritable(optional FileSystemCreateWritableOptions options = {}); [Exposed=DedicatedWorker] - Promise<FileSystemSyncAccessHandle> createSyncAccessHandle(); + Promise<FileSystemSyncAccessHandle> createSyncAccessHandle(optional FileSystemCreateSyncAccessHandleOptions options = {}); }; @@ -538,10 +551,13 @@ The getFile() method steps are: the temporary file starts out empty, otherwise the existing file is first copied to this temporary file. - Creating a {{FileSystemWritableFileStream}} [=file entry/take a lock|takes a shared lock=] on the - [=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=]. - This prevents the creation of {{FileSystemSyncAccessHandle|FileSystemSyncAccessHandles}} - for the entry, until the stream is closed. + Creating a {{FileSystemWritableFileStream}} [=file entry/take a lock|takes a lock=] on the + [=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=] + and a |lockType| determined by {{FileSystemCreateWritableOptions/mode}}. Until the stream is + closed, both {{FileSystemCreateWritableOptions/mode|modes}} prevent the creation on the entry + of a {{FileSystemWritableFileStream}} in a different {{FileSystemCreateWritableOptions/mode}} + or a {{FileSystemSyncAccessHandle}}, but "`exclusive`" will also prevent the creation of + {{FileSystemWritableFileStream}} in "`exclusive`" {{FileSystemCreateWritableOptions/mode}}.

See WICG/file-system-access issue #67 @@ -575,8 +591,15 @@ The createWritable(|options|) method |result| with a "{{NotFoundError}}" {{DOMException}} and abort these steps. 1. [=Assert=]: |entry| is a [=file entry=]. + 1. Let |lockType| be the empty string. + 1. Let |mode| be |options|["{{FileSystemCreateWritableOptions/mode}}"]. + 1. If |mode| is "`exclusive`": + 1. Set |lockType| to "`exclusive`". + 1. Otherwise: + 1. [=Assert=]: |mode| is "`siloed`". + 1. Set |lockType| to "`writableSiloed`". 1. Let |lockResult| be the result of [=file entry/take a lock|taking a lock=] - with "`shared`" on |entry|. + with |lockType| on |entry|. 1. [=Queue a storage task=] with |global| to run these steps: 1. If |lockResult| is "`failure`", [=/reject=] |result| with a @@ -609,6 +632,14 @@ The createWritable(|options|) method or {{FileSystemWritableFileStream|FileSystemWritableFileStreams}} for the entry, until the access handle is closed. + Creating a {{FileSystemSyncAccessHandle}} [=file entry/take a lock|takes a lock=] on the + [=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=] + and a |lockType| determined by {{FileSystemCreateSyncAccessHandleOptions/mode}}. Until the access handle is + closed, all {{FileSystemCreateSyncAccessHandleOptions/mode|modes}} prevent the creation on the entry + of a {{FileSystemSyncAccessHandle}} in a different {{FileSystemCreateSyncAccessHandleOptions/mode}} + or a {{FileSystemWritableFileStream}}, but "`read-write`" will also prevent the creation of + {{FileSystemSyncAccessHandle}} in "`read-write`" {{FileSystemCreateSyncAccessHandleOptions/mode}}. + The returned {{FileSystemSyncAccessHandle}} offers synchronous methods. This allows for higher performance on contexts where asynchronous operations come with high overhead, e.g., WebAssembly. @@ -617,7 +648,7 @@ The createWritable(|options|) method

-The createSyncAccessHandle() method steps are: +The createSyncAccessHandle(|options|) method steps are: 1. Let |result| be [=a new promise=]. 1. Let |locator| be [=this=]'s [=FileSystemHandle/locator=]. @@ -645,15 +676,28 @@ The createSyncAccessHandle() method s |result| with a "{{NotFoundError}}" {{DOMException}} and abort these steps. 1. [=Assert=]: |entry| is a [=file entry=]. + 1. Let |lockType| be the empty string. + 1. Let |writeAccess| be the empty string. + 1. Let |mode| be |options|["{{FileSystemCreateSyncAccessHandleOptions/mode}}"]. + 1. If |mode| is "`readwrite`": + 1. Set |lockType| to "`exclusive`". + 1. Set |writeAccess| to "`writable`". + 1. Otherwise, if |mode| is "`read-only`": + 1. Set |lockType| to "`syncAccessHandleReadOnly`". + 1. Set |writeAccess| to "`not-writable`". + 1. Otherwise: + 1. [=Assert=]: |mode| is "`readwrite-unsafe`". + 1. Set |lockType| to "`syncAccessHandleReadWriteUnsafe`". + 1. Set |writeAccess| to "`writable`". 1. Let |lockResult| be the result of [=file entry/take a lock|taking a lock=] - with "`exclusive`" on |entry|. + with |lockType| on |entry|. 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|. + with |entry| and |writeAccess| in |realm|. 1. [=/Resolve=] |result| with |handle|. 1. Return |result|. @@ -1440,6 +1484,9 @@ A {{FileSystemSyncAccessHandle}} has an associated \[[state]], a string that may exclusively be "`open`" or "`closed`". +A {{FileSystemSyncAccessHandle}} has an associated \[[writeAccess]], +a string that may exclusively be "`writable`" or "`not-writable`". + A {{FileSystemSyncAccessHandle}} is an object that is capable of reading from/writing to, as well as obtaining and changing the size of, a single file. @@ -1451,11 +1498,13 @@ A {{FileSystemSyncAccessHandle}} has a fil
To create a new `FileSystemSyncAccessHandle` -given a [=file entry=] |file| in a [=/Realm=] |realm|: +given a [=file entry=] |file| and a [=string=] |writeAccess| in a [=/Realm=] |realm|: +1. [=Assert=]: |writeAccess| is "`writable`" or "`notWritable`". 1. Let |handle| be a [=new=] {{FileSystemSyncAccessHandle}} in |realm|. 1. Set |handle|'s [=FileSystemSyncAccessHandle/[[file]]=] to |file|. 1. Set |handle|'s [=FileSystemSyncAccessHandle/[[state]]=] to "`open`". +1. Set |handle|'s [=FileSystemSyncAccessHandle/[[writeAccess]]=] to |writeAccess|. 1. Return |handle|.
@@ -1518,6 +1567,8 @@ The write(|buffer|, {{FileSystemReadW 1. If [=this=]'s [=[[state]]=] is "`closed`", [=throw=] an "{{InvalidStateError}}" {{DOMException}}. +1. If [=this=]'s [=[[writeAccess]]=]' is "`not-writable`", + [=throw=] a "{{NoModificationAllowedError}}" {{DOMException}}. 1. Let |writePosition| be |options|["{{FileSystemReadWriteOptions/at}}"] if |options|["{{FileSystemReadWriteOptions/at}}"] [=map/exists=]; otherwise [=this=]'s [=FileSystemSyncAccessHandle/file position cursor=]. @@ -1578,6 +1629,8 @@ The truncate(|newSize|) method 1. If [=this=]'s [=[[state]]=] is "`closed`", [=throw=] an "{{InvalidStateError}}" {{DOMException}}. +1. If [=this=]'s [=[[writeAccess]]=]' is "`not-writable`", + [=throw=] a "{{NoModificationAllowedError}}" {{DOMException}}. 1. Let |fileContents| be a copy of [=this=]'s [=FileSystemSyncAccessHandle/[[file]]=]'s [=file entry/binary data=]. 1. Let |oldSize| be the [=byte sequence/length=] of [=this=]'s @@ -1634,6 +1687,8 @@ The flush() method steps are: 1. If [=this=]'s [=[[state]]=] is "`closed`", [=throw=] an "{{InvalidStateError}}" {{DOMException}}. +1. If [=this=]'s [=[[writeAccess]]=]' is "`not-writable`", + [=throw=] a "{{NoModificationAllowedError}}" {{DOMException}}. 1. Attempt to transfer all cached modifications of the file's content to the file system's underlying storage device.