@@ -124,34 +124,35 @@ Issue: We should consider having further normative restrictions on file names th
124124never be allowed using this API, rather than leaving it entirely up to underlying file
125125systems.
126126
127+ A <dfn>lock type</dfn> is a [=string=] that may exclusively be "`open`",
128+ "`exclusive`", "`writable-siloed`", "`sync-access-handle-read-only`",
129+ "`sync-access-handle-read-write-unsafe`".
130+
127131A <dfn export id=file>file entry</dfn> additionally consists of
128132<dfn for="file entry" export>binary data</dfn> (a [=byte sequence=] ), a
129133<dfn for="file entry">modification timestamp</dfn> (a number representing the number of milliseconds since the <a spec=FileAPI>Unix Epoch</a> ),
130- a <dfn for="file entry">lock</dfn> (a string that may exclusively be "`open`", "`taken-exclusive`" or "`taken-shared`")
131- and a <dfn for="file entry">shared lock count</dfn> (a number representing the number of shared locks that are taken at a given point in time).
134+ a <dfn for="file entry">lock</dfn> (a [=lock type=] ),
135+ and a <dfn for="file entry">lock count</dfn> (a number representing the number of locks that are taken at a given point in time).
132136
133137A user agent has an associated <dfn>file system queue</dfn> which is the
134138result of [=starting a new parallel queue=] . This queue is to be used for all
135139file system operations.
136140
137141<div algorithm>
138- To <dfn for="file entry" id=file-entry-lock-take>take a lock</dfn> with a |value| of
139- "`exclusive`" or "`shared`" on a given [=file entry=] |file|:
142+ To <dfn for="file entry" id=file-entry-lock-take>take a lock</dfn> with a |lockType| (a [=lock type=] )
143+ on a given [=file entry=] |file|:
140144
145+ 1. [=Assert=] : |lockType| is not "`open`".
1411461. Let |lock| be the |file|'s [=file entry/lock=] .
142- 1. Let |count| be the |file|'s [=file entry/shared lock count=] .
143- 1. If |value| is "`exclusive`":
144- 1. If |lock| is "`open`":
145- 1. Set lock to "`taken-exclusive`".
146- 1. Return "`success`".
147- 1. If |value| is "`shared`":
148- 1. If |lock| is "`open`":
149- 1. Set |lock| to "`taken-shared`".
150- 1. Set |count| to 1.
151- 1. Return "`success`".
152- 1. Otherwise, if |lock| is "`taken-shared`":
153- 1. Increase |count| by 1.
154- 1. Return "`success`".
147+ 1. Let |count| be the |file|'s [=file entry/lock count=] .
148+ 1. If |lock| is "`open`":
149+ 1. Set |lock| to |lockType|.
150+ 1. Set |count| to 1.
151+ 1. Return "`success`".
152+ 1. If |lock| is not "`exclusive`":
153+ 1. If |lock| equals |lockType|:
154+ 1. Increase |count| by 1.
155+ 1. Return "`success`".
1551561. Return "`failure`".
156157
157158Note: These steps have to be run on the [=file system queue=] .
@@ -163,18 +164,16 @@ To <dfn for="file entry/lock">release</dfn> a [=file entry/lock=] on a given
163164[=file entry=] |file|:
164165
1651661. Let |lock| be the |file|'s associated [=file entry/lock=] .
166- 1. Let |count| be the |file|'s [=file entry/shared lock count=] .
167- 1. If |lock| is "`taken-shared`":
168- 1. Decrease |count| by 1.
169- 1. If |count| is 0, set |lock| to "`open`".
170- 1. Otherwise, set |lock| to "`open`".
167+ 1. Let |count| be the |file|'s [=file entry/lock count=] .
168+ 1. [=Assert=] : |count| is greater than 0.
169+ 1. Decrease |count| by 1.
170+ 1. If |count| is 0, set |lock| to "`open`".
171171
172172Note: These steps have to be run on the [=file system queue=] .
173173
174174</div>
175175
176- Note: Locks help prevent concurrent modifications to a file. A {{FileSystemWritableFileStream}}
177- requires a shared lock, while a {{FileSystemSyncAccessHandle}} requires an exclusive one.
176+ Note: Locks help prevent concurrent modifications to a file that are incompatible.
178177
179178A <dfn export id=directory>directory entry</dfn> additionally consists of a [=/set=] of
180179<dfn for="directory entry">children</dfn> , which are themselves [=/file system entries=] .
@@ -420,16 +419,32 @@ The <dfn method for=FileSystemHandle>isSameEntry(|other|)</dfn> method steps are
420419## The {{FileSystemFileHandle}} interface ## {#api-filesystemfilehandle}
421420
422421<xmp class=idl>
422+ enum FileSystemWritableFileStreamMode {
423+ "exclusive",
424+ "siloed",
425+ };
426+
423427dictionary FileSystemCreateWritableOptions {
424428 boolean keepExistingData = false;
429+ FileSystemWritableFileStreamMode mode = "siloed";
430+ };
431+
432+ enum FileSystemSyncAccessHandleMode {
433+ "readwrite",
434+ "read-only",
435+ "readwrite-unsafe",
436+ };
437+
438+ dictionary FileSystemCreateSyncAccessHandleOptions {
439+ FileSystemSyncAccessHandleMode mode = "readwrite";
425440};
426441
427442[Exposed=(Window,Worker), SecureContext, Serializable]
428443interface FileSystemFileHandle : FileSystemHandle {
429444 Promise<File> getFile();
430445 Promise<FileSystemWritableFileStream> createWritable(optional FileSystemCreateWritableOptions options = {});
431446 [Exposed=DedicatedWorker]
432- Promise<FileSystemSyncAccessHandle> createSyncAccessHandle();
447+ Promise<FileSystemSyncAccessHandle> createSyncAccessHandle(optional FileSystemCreateSyncAccessHandleOptions options = {} );
433448};
434449</xmp>
435450
@@ -538,10 +553,12 @@ The <dfn method for=FileSystemFileHandle>getFile()</dfn> method steps are:
538553 the temporary file starts out empty,
539554 otherwise the existing file is first copied to this temporary file.
540555
541- Creating a {{FileSystemWritableFileStream}} [=file entry/take a lock|takes a shared lock=] on the
542- [=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=] .
543- This prevents the creation of {{FileSystemSyncAccessHandle|FileSystemSyncAccessHandles}}
544- for the entry, until the stream is closed.
556+ Creating a {{FileSystemWritableFileStream}} [=file entry/take a lock|takes a lock=] on the
557+ [=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=]
558+ and a |lockType| determined by {{FileSystemCreateWritableOptions/mode}} . Until the stream is
559+ closed, both {{FileSystemCreateWritableOptions/mode|modes}} prevent any file operation or the
560+ creation of a file primitive on the [=file entry=] , but "`siloed`" will allow the creation of other
561+ {{FileSystemWritableFileStream}} in "`siloed`" {{FileSystemCreateWritableOptions/mode}} .
545562</div>
546563
547564<p class=XXX> See <a href=https://github.com/WICG/file-system-access/issues/67>WICG/file-system-access issue #67</a>
@@ -575,8 +592,15 @@ The <dfn method for=FileSystemFileHandle>createWritable(|options|)</dfn> method
575592 |result| with a "{{NotFoundError}} " {{DOMException}} and abort these steps.
576593 1. [=Assert=] : |entry| is a [=file entry=] .
577594
595+ 1. Let |lockType| be the empty string.
596+ 1. Let |mode| be |options|["{{FileSystemCreateWritableOptions/mode}}"] .
597+ 1. If |mode| is "`exclusive`":
598+ 1. Set |lockType| to "`exclusive`".
599+ 1. Otherwise:
600+ 1. [=Assert=] : |mode| is "`siloed`".
601+ 1. Set |lockType| to "`writable-siloed`".
578602 1. Let |lockResult| be the result of [=file entry/take a lock|taking a lock=]
579- with "`shared`" on |entry|.
603+ with |lockType| on |entry|.
580604
581605 1. [=Queue a storage task=] with |global| to run these steps:
582606 1. If |lockResult| is "`failure`", [=/reject=] |result| with a
@@ -603,11 +627,12 @@ The <dfn method for=FileSystemFileHandle>createWritable(|options|)</dfn> method
603627 [=file entry=] [=locate an entry|locatable=] by |fileHandle|'s [=FileSystemHandle/locator=] .
604628 To ensure the changes are reflected in this file, the handle can be flushed.
605629
606- Creating a {{FileSystemSyncAccessHandle}} [=file entry/take a lock|takes an exclusive lock=] on the
607- [=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=] .
608- This prevents the creation of further {{FileSystemSyncAccessHandle|FileSystemSyncAccessHandles}}
609- or {{FileSystemWritableFileStream|FileSystemWritableFileStreams}}
610- for the entry, until the access handle is closed.
630+ Creating a {{FileSystemSyncAccessHandle}} [=file entry/take a lock|takes a lock=] on the
631+ [=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=]
632+ and a |lockType| determined by {{FileSystemCreateSyncAccessHandleOptions/mode}} . Until the access handle is
633+ closed, all {{FileSystemCreateSyncAccessHandleOptions/mode|modes}} prevent any file operation or the
634+ creation of a file primitive on the [=file entry=] , but "`read-only`" and "`readwrite-unsafe`" will allow the creation of other
635+ {{FileSystemSyncAccessHandle}} in their respective {{FileSystemCreateSyncAccessHandleOptions/mode|modes}} .
611636
612637 The returned {{FileSystemSyncAccessHandle}} offers synchronous methods. This allows for higher performance
613638 on contexts where asynchronous operations come with high overhead, e.g., WebAssembly.
@@ -617,7 +642,7 @@ The <dfn method for=FileSystemFileHandle>createWritable(|options|)</dfn> method
617642</div>
618643
619644<div algorithm>
620- The <dfn method for=FileSystemFileHandle>createSyncAccessHandle()</dfn> method steps are:
645+ The <dfn method for=FileSystemFileHandle>createSyncAccessHandle(|options| )</dfn> method steps are:
621646
6226471. Let |result| be [=a new promise=] .
6236481. Let |locator| be [=this=] 's [=FileSystemHandle/locator=] .
@@ -645,15 +670,28 @@ The <dfn method for=FileSystemFileHandle>createSyncAccessHandle()</dfn> method s
645670 |result| with a "{{NotFoundError}} " {{DOMException}} and abort these steps.
646671 1. [=Assert=] : |entry| is a [=file entry=] .
647672
673+ 1. Let |lockType| be the empty string.
674+ 1. Let |writeAccess| be the empty string.
675+ 1. Let |mode| be |options|["{{FileSystemCreateSyncAccessHandleOptions/mode}}"] .
676+ 1. If |mode| is "`readwrite`":
677+ 1. Set |lockType| to "`exclusive`".
678+ 1. Set |writeAccess| to "`writable`".
679+ 1. Otherwise, if |mode| is "`read-only`":
680+ 1. Set |lockType| to "`sync-access-handle-read-only`".
681+ 1. Set |writeAccess| to "`not-writable`".
682+ 1. Otherwise:
683+ 1. [=Assert=] : |mode| is "`readwrite-unsafe`".
684+ 1. Set |lockType| to "`sync-access-handle-read-write-unsafe`".
685+ 1. Set |writeAccess| to "`writable`".
648686 1. Let |lockResult| be the result of [=file entry/take a lock|taking a lock=]
649- with "`exclusive`" on |entry|.
687+ with |lockType| on |entry|.
650688
651689 1. [=Queue a storage task=] with |global| to run these steps:
652690 1. If |lockResult| is "`failure`", [=/reject=] |result| with a
653691 "{{NoModificationAllowedError}} " {{DOMException}} and abort these steps.
654692
655693 1. Let |handle| be the result of <a>creating a new `FileSystemSyncAccessHandle`</a>
656- for |entry| in |realm|.
694+ with |entry| and |writeAccess | in |realm|.
657695 1. [=/Resolve=] |result| with |handle|.
658696
6596971. Return |result|.
@@ -1440,6 +1478,9 @@ A {{FileSystemSyncAccessHandle}} has an associated <dfn for=FileSystemSyncAccess
14401478A {{FileSystemSyncAccessHandle}} has an associated <dfn for=FileSystemSyncAccessHandle>\[[state]]</dfn> ,
14411479a string that may exclusively be "`open`" or "`closed`".
14421480
1481+ A {{FileSystemSyncAccessHandle}} has an associated <dfn for=FileSystemSyncAccessHandle>\[[writeAccess]]</dfn> ,
1482+ a [=string=] that may exclusively be "`writable`" or "`not-writable`".
1483+
14431484A {{FileSystemSyncAccessHandle}} is an object that is capable of reading from/writing to,
14441485as well as obtaining and changing the size of, a single file.
14451486
@@ -1451,11 +1492,13 @@ A {{FileSystemSyncAccessHandle}} has a <dfn for="FileSystemSyncAccessHandle">fil
14511492<div algorithm>
14521493To
14531494<dfn local-lt="creating a new FileSystemSyncAccessHandle">create a new `FileSystemSyncAccessHandle`</dfn>
1454- given a [=file entry=] |file| in a [=/Realm=] |realm|:
1495+ given a [=file entry=] |file| and a [=string=] |writeAccess| in a [=/Realm=] |realm|:
14551496
1497+ 1. [=Assert=] : |writeAccess| is "`writable`" or "`not-writable`".
145614981. Let |handle| be a [=new=] {{FileSystemSyncAccessHandle}} in |realm|.
145714991. Set |handle|'s [=FileSystemSyncAccessHandle/[[file]]=] to |file|.
145815001. Set |handle|'s [=FileSystemSyncAccessHandle/[[state]]=] to "`open`".
1501+ 1. Set |handle|'s [=FileSystemSyncAccessHandle/[[writeAccess]]=] to |writeAccess|.
145915021. Return |handle|.
14601503
14611504</div>
@@ -1518,6 +1561,8 @@ The <dfn method for=FileSystemSyncAccessHandle>write(|buffer|, {{FileSystemReadW
15181561
151915621. If [=this=] 's [=[[state]]=] is "`closed`",
15201563 [=throw=] an "{{InvalidStateError}} " {{DOMException}} .
1564+ 1. If [=this=] 's [=[[writeAccess]]=]' is "`not-writable`",
1565+ [=throw=] a "{{NoModificationAllowedError}} " {{DOMException}} .
152115661. Let |writePosition| be |options|["{{FileSystemReadWriteOptions/at}}"] if
15221567 |options|["{{FileSystemReadWriteOptions/at}}"] [=map/exists=] ; otherwise
15231568 [=this=] 's [=FileSystemSyncAccessHandle/file position cursor=] .
@@ -1578,6 +1623,8 @@ The <dfn method for=FileSystemSyncAccessHandle>truncate(|newSize|)</dfn> method
15781623
157916241. If [=this=] 's [=[[state]]=] is "`closed`",
15801625 [=throw=] an "{{InvalidStateError}} " {{DOMException}} .
1626+ 1. If [=this=] 's [=[[writeAccess]]=]' is "`not-writable`",
1627+ [=throw=] a "{{NoModificationAllowedError}} " {{DOMException}} .
158116281. Let |fileContents| be a copy of [=this=] 's
15821629 [=FileSystemSyncAccessHandle/[[file]]=] 's [=file entry/binary data=] .
158316301. Let |oldSize| be the [=byte sequence/length=] of [=this=] 's
@@ -1634,6 +1681,8 @@ The <dfn method for=FileSystemSyncAccessHandle>flush()</dfn> method steps are:
16341681
163516821. If [=this=] 's [=[[state]]=] is "`closed`",
16361683 [=throw=] an "{{InvalidStateError}} " {{DOMException}} .
1684+ 1. If [=this=] 's [=[[writeAccess]]=]' is "`not-writable`",
1685+ [=throw=] a "{{NoModificationAllowedError}} " {{DOMException}} .
163716861. Attempt to transfer all cached modifications of the file's content to the
16381687 file system's underlying storage device.
16391688
0 commit comments