@@ -124,34 +124,35 @@ Issue: We should consider having further normative restrictions on file names th
124
124
never be allowed using this API, rather than leaving it entirely up to underlying file
125
125
systems.
126
126
127
+ A <dfn for="file entry">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
+
127
131
A <dfn export id=file>file entry</dfn> additionally consists of
128
132
<dfn for="file entry" export>binary data</dfn> (a [=byte sequence=] ), a
129
133
<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`")
134
+ a <dfn for="file entry">lock</dfn> (a [=file entry/lock type=] ),
131
135
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).
132
136
133
137
A user agent has an associated <dfn>file system queue</dfn> which is the
134
138
result of [=starting a new parallel queue=] . This queue is to be used for all
135
139
file system operations.
136
140
137
141
<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 [=file entry/lock type=] )
143
+ on a given [=file entry=] |file|:
140
144
145
+ 1. [=Assert=] : |lockType| is not "`open`".
141
146
1. Let |lock| be the |file|'s [=file entry/lock=] .
142
147
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`".
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`".
155
156
1. Return "`failure`".
156
157
157
158
Note: These steps have to be run on the [=file system queue=] .
@@ -164,10 +165,9 @@ To <dfn for="file entry/lock">release</dfn> a [=file entry/lock=] on a given
164
165
165
166
1. Let |lock| be the |file|'s associated [=file entry/lock=] .
166
167
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`".
168
+ 1. [=Assert=] : |count| is greater than 0.
169
+ 1. Decrease |count| by 1.
170
+ 1. If |count| is 0, set |lock| to "`open`".
171
171
172
172
Note: These steps have to be run on the [=file system queue=] .
173
173
@@ -420,16 +420,32 @@ The <dfn method for=FileSystemHandle>isSameEntry(|other|)</dfn> method steps are
420
420
## The {{FileSystemFileHandle}} interface ## {#api-filesystemfilehandle}
421
421
422
422
<xmp class=idl>
423
+ enum FileSystemWritableFileStreamMode {
424
+ "exclusive",
425
+ "siloed",
426
+ };
427
+
423
428
dictionary FileSystemCreateWritableOptions {
424
429
boolean keepExistingData = false;
430
+ FileSystemWritableFileStreamMode mode = "siloed";
431
+ };
432
+
433
+ enum FileSystemSyncAccessHandleMode {
434
+ "readwrite",
435
+ "read-only",
436
+ "readwrite-unsafe",
437
+ };
438
+
439
+ dictionary FileSystemCreateSyncAccessHandleOptions {
440
+ FileSystemSyncAccessHandleMode mode = "readwrite";
425
441
};
426
442
427
443
[Exposed=(Window,Worker), SecureContext, Serializable]
428
444
interface FileSystemFileHandle : FileSystemHandle {
429
445
Promise<File> getFile();
430
446
Promise<FileSystemWritableFileStream> createWritable(optional FileSystemCreateWritableOptions options = {});
431
447
[Exposed=DedicatedWorker]
432
- Promise<FileSystemSyncAccessHandle> createSyncAccessHandle();
448
+ Promise<FileSystemSyncAccessHandle> createSyncAccessHandle(optional FileSystemCreateSyncAccessHandleOptions options = {} );
433
449
};
434
450
</xmp>
435
451
@@ -538,10 +554,12 @@ The <dfn method for=FileSystemFileHandle>getFile()</dfn> method steps are:
538
554
the temporary file starts out empty,
539
555
otherwise the existing file is first copied to this temporary file.
540
556
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.
557
+ Creating a {{FileSystemWritableFileStream}} [=file entry/take a lock|takes a lock=] on the
558
+ [=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=]
559
+ and a |lockType| determined by {{FileSystemCreateWritableOptions/mode}} . Until the stream is
560
+ closed, both {{FileSystemCreateWritableOptions/mode|modes}} prevent any file operation or the
561
+ creation of a file primitive on the [=file entry=] , but "`siloed`" will allow the creation of other
562
+ {{FileSystemWritableFileStream}} in "`siloed`" {{FileSystemCreateWritableOptions/mode}} .
545
563
</div>
546
564
547
565
<p class=XXX> See <a href=https://github.com/WICG/file-system-access/issues/67>WICG/file-system-access issue #67</a>
@@ -575,8 +593,15 @@ The <dfn method for=FileSystemFileHandle>createWritable(|options|)</dfn> method
575
593
|result| with a "{{NotFoundError}} " {{DOMException}} and abort these steps.
576
594
1. [=Assert=] : |entry| is a [=file entry=] .
577
595
596
+ 1. Let |lockType| be the empty string.
597
+ 1. Let |mode| be |options|["{{FileSystemCreateWritableOptions/mode}}"] .
598
+ 1. If |mode| is "`exclusive`":
599
+ 1. Set |lockType| to "`exclusive`".
600
+ 1. Otherwise:
601
+ 1. [=Assert=] : |mode| is "`siloed`".
602
+ 1. Set |lockType| to "`writable-siloed`".
578
603
1. Let |lockResult| be the result of [=file entry/take a lock|taking a lock=]
579
- with "`shared`" on |entry|.
604
+ with |lockType| on |entry|.
580
605
581
606
1. [=Queue a storage task=] with |global| to run these steps:
582
607
1. If |lockResult| is "`failure`", [=/reject=] |result| with a
@@ -603,11 +628,12 @@ The <dfn method for=FileSystemFileHandle>createWritable(|options|)</dfn> method
603
628
[=file entry=] [=locate an entry|locatable=] by |fileHandle|'s [=FileSystemHandle/locator=] .
604
629
To ensure the changes are reflected in this file, the handle can be flushed.
605
630
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.
631
+ Creating a {{FileSystemSyncAccessHandle}} [=file entry/take a lock|takes a lock=] on the
632
+ [=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=]
633
+ and a |lockType| determined by {{FileSystemCreateSyncAccessHandleOptions/mode}} . Until the access handle is
634
+ closed, all {{FileSystemCreateSyncAccessHandleOptions/mode|modes}} prevent any file operation or the
635
+ creation of a file primitive on the [=file entry=] , but "`read-only`" and "`readwrite-unsafe`" will allow the creation of other
636
+ {{FileSystemSyncAccessHandle}} in their respective {{FileSystemCreateSyncAccessHandleOptions/mode|modes}} .
611
637
612
638
The returned {{FileSystemSyncAccessHandle}} offers synchronous methods. This allows for higher performance
613
639
on contexts where asynchronous operations come with high overhead, e.g., WebAssembly.
@@ -617,7 +643,7 @@ The <dfn method for=FileSystemFileHandle>createWritable(|options|)</dfn> method
617
643
</div>
618
644
619
645
<div algorithm>
620
- The <dfn method for=FileSystemFileHandle>createSyncAccessHandle()</dfn> method steps are:
646
+ The <dfn method for=FileSystemFileHandle>createSyncAccessHandle(|options| )</dfn> method steps are:
621
647
622
648
1. Let |result| be [=a new promise=] .
623
649
1. Let |locator| be [=this=] 's [=FileSystemHandle/locator=] .
@@ -645,15 +671,28 @@ The <dfn method for=FileSystemFileHandle>createSyncAccessHandle()</dfn> method s
645
671
|result| with a "{{NotFoundError}} " {{DOMException}} and abort these steps.
646
672
1. [=Assert=] : |entry| is a [=file entry=] .
647
673
674
+ 1. Let |lockType| be the empty string.
675
+ 1. Let |writeAccess| be the empty string.
676
+ 1. Let |mode| be |options|["{{FileSystemCreateSyncAccessHandleOptions/mode}}"] .
677
+ 1. If |mode| is "`readwrite`":
678
+ 1. Set |lockType| to "`exclusive`".
679
+ 1. Set |writeAccess| to "`writable`".
680
+ 1. Otherwise, if |mode| is "`read-only`":
681
+ 1. Set |lockType| to "`sync-access-handle-read-only`".
682
+ 1. Set |writeAccess| to "`not-writable`".
683
+ 1. Otherwise:
684
+ 1. [=Assert=] : |mode| is "`readwrite-unsafe`".
685
+ 1. Set |lockType| to "`sync-access-handle-read-write-unsafe`".
686
+ 1. Set |writeAccess| to "`writable`".
648
687
1. Let |lockResult| be the result of [=file entry/take a lock|taking a lock=]
649
- with "`exclusive`" on |entry|.
688
+ with |lockType| on |entry|.
650
689
651
690
1. [=Queue a storage task=] with |global| to run these steps:
652
691
1. If |lockResult| is "`failure`", [=/reject=] |result| with a
653
692
"{{NoModificationAllowedError}} " {{DOMException}} and abort these steps.
654
693
655
694
1. Let |handle| be the result of <a>creating a new `FileSystemSyncAccessHandle`</a>
656
- for |entry| in |realm|.
695
+ with |entry| and |writeAccess | in |realm|.
657
696
1. [=/Resolve=] |result| with |handle|.
658
697
659
698
1. Return |result|.
@@ -1440,6 +1479,9 @@ A {{FileSystemSyncAccessHandle}} has an associated <dfn for=FileSystemSyncAccess
1440
1479
A {{FileSystemSyncAccessHandle}} has an associated <dfn for=FileSystemSyncAccessHandle>\[[state]]</dfn> ,
1441
1480
a string that may exclusively be "`open`" or "`closed`".
1442
1481
1482
+ A {{FileSystemSyncAccessHandle}} has an associated <dfn for=FileSystemSyncAccessHandle>\[[writeAccess]]</dfn> ,
1483
+ a [=string=] that may exclusively be "`writable`" or "`not-writable`".
1484
+
1443
1485
A {{FileSystemSyncAccessHandle}} is an object that is capable of reading from/writing to,
1444
1486
as well as obtaining and changing the size of, a single file.
1445
1487
@@ -1451,11 +1493,13 @@ A {{FileSystemSyncAccessHandle}} has a <dfn for="FileSystemSyncAccessHandle">fil
1451
1493
<div algorithm>
1452
1494
To
1453
1495
<dfn local-lt="creating a new FileSystemSyncAccessHandle">create a new `FileSystemSyncAccessHandle`</dfn>
1454
- given a [=file entry=] |file| in a [=/Realm=] |realm|:
1496
+ given a [=file entry=] |file| and a [=string=] |writeAccess| in a [=/Realm=] |realm|:
1455
1497
1498
+ 1. [=Assert=] : |writeAccess| is "`writable`" or "`not-writable`".
1456
1499
1. Let |handle| be a [=new=] {{FileSystemSyncAccessHandle}} in |realm|.
1457
1500
1. Set |handle|'s [=FileSystemSyncAccessHandle/[[file]]=] to |file|.
1458
1501
1. Set |handle|'s [=FileSystemSyncAccessHandle/[[state]]=] to "`open`".
1502
+ 1. Set |handle|'s [=FileSystemSyncAccessHandle/[[writeAccess]]=] to |writeAccess|.
1459
1503
1. Return |handle|.
1460
1504
1461
1505
</div>
@@ -1518,6 +1562,8 @@ The <dfn method for=FileSystemSyncAccessHandle>write(|buffer|, {{FileSystemReadW
1518
1562
1519
1563
1. If [=this=] 's [=[[state]]=] is "`closed`",
1520
1564
[=throw=] an "{{InvalidStateError}} " {{DOMException}} .
1565
+ 1. If [=this=] 's [=[[writeAccess]]=]' is "`not-writable`",
1566
+ [=throw=] a "{{NoModificationAllowedError}} " {{DOMException}} .
1521
1567
1. Let |writePosition| be |options|["{{FileSystemReadWriteOptions/at}}"] if
1522
1568
|options|["{{FileSystemReadWriteOptions/at}}"] [=map/exists=] ; otherwise
1523
1569
[=this=] 's [=FileSystemSyncAccessHandle/file position cursor=] .
@@ -1578,6 +1624,8 @@ The <dfn method for=FileSystemSyncAccessHandle>truncate(|newSize|)</dfn> method
1578
1624
1579
1625
1. If [=this=] 's [=[[state]]=] is "`closed`",
1580
1626
[=throw=] an "{{InvalidStateError}} " {{DOMException}} .
1627
+ 1. If [=this=] 's [=[[writeAccess]]=]' is "`not-writable`",
1628
+ [=throw=] a "{{NoModificationAllowedError}} " {{DOMException}} .
1581
1629
1. Let |fileContents| be a copy of [=this=] 's
1582
1630
[=FileSystemSyncAccessHandle/[[file]]=] 's [=file entry/binary data=] .
1583
1631
1. Let |oldSize| be the [=byte sequence/length=] of [=this=] 's
@@ -1634,6 +1682,8 @@ The <dfn method for=FileSystemSyncAccessHandle>flush()</dfn> method steps are:
1634
1682
1635
1683
1. If [=this=] 's [=[[state]]=] is "`closed`",
1636
1684
[=throw=] an "{{InvalidStateError}} " {{DOMException}} .
1685
+ 1. If [=this=] 's [=[[writeAccess]]=]' is "`not-writable`",
1686
+ [=throw=] a "{{NoModificationAllowedError}} " {{DOMException}} .
1637
1687
1. Attempt to transfer all cached modifications of the file's content to the
1638
1688
file system's underlying storage device.
1639
1689
0 commit comments