From a0294b771f86ca9efae2f68bd5eea2d4f3c80343 Mon Sep 17 00:00:00 2001 From: Nathan Memmott Date: Thu, 6 Jul 2023 13:50:07 -0700 Subject: [PATCH] Support locking of directory entries Moves the locking algorithm from file entry to file system entry. Fixes #137 --- index.bs | 70 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/index.bs b/index.bs index 881fb19..5a75380 100644 --- a/index.bs +++ b/index.bs @@ -110,7 +110,9 @@ specifications do not need to bother implementing [=/file system entry=]'s Issue(101): Make access check algorithms associated with a FileSystemHandle. -Each [=/file system entry=] has an associated name (a [=string=]). +Each [=/file system entry=] has an associated name (a [=string=]), +a lock (a string that may exclusively be "`open`", "`taken-exclusive`" or "`taken-shared`") +and a shared lock count (a number representing the number of shared locks that are taken at a given point in time). A valid file name is a [=string=] that is not an empty string, is not equal to "." or "..", and does not contain '/' or any other character used as path separator on the underlying platform. @@ -124,22 +126,20 @@ Issue: We should consider having further normative restrictions on file names th never be allowed using this API, rather than leaving it entirely up to underlying file 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`") -and a shared lock count (a number representing the number shared locks that are taken at a given point in time). - A user agent has an associated file system queue which is the result of [=starting a new parallel queue=]. This queue is to be used for all file system operations.
-To take a [=file entry/lock=] with a |value| of -"`exclusive`" or "`shared`" on a given [=file entry=] |file|: - -1. Let |lock| be the |file|'s [=file entry/lock=]. -1. Let |count| be the |file|'s [=file entry/shared lock count=]. +To take a lock with a |value| of +"`exclusive`" or "`shared`" on a given [=/file system entry=] |entry|: + +1. Let |lock| be the |entry|'s [=file system entry/lock=]. +1. Let |count| be the |entry|'s [=file system entry/shared lock count=]. +1. If |entry| is a [=directory entry=]: + 1. Let |descendantLockStatus| be the result of [=file system entry/checking for a descendant lock=] on |entry|. + 1. If |descendantLockStatus| is "`taken`": + 1. Return "`failure`". 1. If |value| is "`exclusive`": 1. If |lock| is "`open`": 1. Set lock to "`taken-exclusive`". @@ -159,11 +159,29 @@ Note: These steps have to be run on the [=file system queue=].
-To release a [=file entry/lock=] on a given -[=file entry=] |file|: +To check for a descendant lock on a given +[=directory entry=] |directory|: + +1. [=set/For each=] |child| of |directory|'s [=directory entry/children=]: + 1. Let |lock| be the |child|'s [=file system entry/lock=]. + 1. If |lock| is not "`open`": + 1. Return "`taken`". + 1. If |child| is a [=directory entry=]: + 1. Let |descendantLockStatus| be the result of [=file system entry/checking for a descendant lock=] on |child|. + 1. If |descendantLockStatus| is "`taken`": + 1. Return "`taken`". +1. Return "`open`". -1. Let |lock| be the |file|'s associated [=file entry/lock=]. -1. Let |count| be the |file|'s [=file entry/shared lock count=]. +Note: These steps have to be run on the [=file system queue=]. + +
+ +
+To release a [=file system entry/lock=] on a given +[=/file system entry=] |entry|: + +1. Let |lock| be the |entry|'s associated [=file system entry/lock=]. +1. Let |count| be the |entry|'s [=file system entry/shared lock count=]. 1. If |lock| is "`taken-shared`": 1. Decrease |count| by 1. 1. If |count| is 0, set |lock| to "`open`". @@ -176,6 +194,10 @@ Note: These steps have to be run on the [=file system queue=]. Note: Locks help prevent concurrent modifications to a file. A {{FileSystemWritableFileStream}} requires a shared lock, while a {{FileSystemSyncAccessHandle}} requires an exclusive one. +A file entry additionally consists of +binary data (a [=byte sequence=]) and a +modification timestamp (a number representing the number of milliseconds since the Unix Epoch). + A directory entry additionally consists of a [=/set=] of children, which are themselves [=/file system entries=]. Each member is either a [=/file entry=] or a [=/directory entry=]. @@ -538,7 +560,7 @@ 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/lock/take|takes a shared lock=] on the + Creating a {{FileSystemWritableFileStream}} [=file system 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. @@ -575,7 +597,7 @@ The createWritable(|options|) method |result| with a "{{NotFoundError}}" {{DOMException}} and abort these steps. 1. [=Assert=]: |entry| is a [=file entry=]. - 1. Let |lockResult| be the result of [=file entry/lock/take|taking a lock=] + 1. Let |lockResult| be the result of [=file system entry/take a lock|taking a lock=] with "`shared`" on |entry|. 1. [=Queue a storage task=] with |global| to run these steps: @@ -603,7 +625,7 @@ The createWritable(|options|) method [=file entry=] [=locate an entry|locatable=] by |fileHandle|'s [=FileSystemHandle/locator=]. To ensure the changes are reflected in this file, the handle can be flushed. - Creating a {{FileSystemSyncAccessHandle}} [=file entry/lock/take|takes an exclusive lock=] on the + Creating a {{FileSystemSyncAccessHandle}} [=file system entry/take a lock|takes an exclusive lock=] on the [=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=]. This prevents the creation of further {{FileSystemSyncAccessHandle|FileSystemSyncAccessHandles}} or {{FileSystemWritableFileStream|FileSystemWritableFileStreams}} @@ -645,7 +667,7 @@ The createSyncAccessHandle() method s |result| with a "{{NotFoundError}}" {{DOMException}} and abort these steps. 1. [=Assert=]: |entry| is a [=file entry=]. - 1. Let |lockResult| be the result of [=file entry/lock/take|taking a lock=] + 1. Let |lockResult| be the result of [=file system entry/take a lock|taking a lock=] with "`exclusive`" on |entry|. 1. [=Queue a storage task=] with |global| to run these steps: @@ -1181,7 +1203,7 @@ given a [=file entry=] |file| in a [=/Realm=] |realm|: file on disk being written to. 1. [=Enqueue the following steps=] to the [=file system queue=]: - 1. [=file entry/lock/release|Release the lock=] on + 1. [=file system 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`. @@ -1189,7 +1211,7 @@ given a [=file entry=] |file| in a [=/Realm=] |realm|: 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 system 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`. @@ -1649,7 +1671,7 @@ The flush() method steps are: : |handle| . {{FileSystemSyncAccessHandle/close()}} :: Closes the access handle or no-ops if the access handle is already closed. This disables any further operations on it and - [=file entry/lock/release|releases the lock=] on the + [=file system entry/lock/release|releases the lock=] on the [=FileSystemSyncAccessHandle/[[file]]=] associated with |handle|.
@@ -1661,7 +1683,7 @@ The close() method steps are: 1. Set |lockReleased| to false. 1. Let |file| be [=this=]'s [=FileSystemSyncAccessHandle/[[file]]=]. 1. [=Enqueue the following steps=] to the [=file system queue=]: - 1. [=file entry/lock/release|Release the lock=] on |file|. + 1. [=file system entry/lock/release|Release the lock=] on |file|. 1. Set |lockReleased| to true. 1. [=Pause=] until |lockReleased| is true.