diff --git a/index.bs b/index.bs index 2b34491..0293c29 100644 --- a/index.bs +++ b/index.bs @@ -55,6 +55,12 @@ before a user has picked a location to save to, without forcing the website to u different storage mechanism with a different API for such files. The entry point for this is the {{StorageManager/getDirectory()|navigator.storage.getDirectory()}} method. +It also defines an API to listen to file system change events. Without it, sites +can recursively poll the file system to find changes in the files or folder +structure. This can be time consuming especially for large directories. The +{{FileSystemObserver}} provides an API to listen for change events so that +polling for them isn't required. + # Files and Directories # {#files-and-directories} @@ -62,9 +68,8 @@ different storage mechanism with a different API for such files. The entry point ### File System ### {#concept-file-system} -A file system is an [=implementation-defined=] -[=storage endpoint=] that maintains a mapping of [=file system path=]s to -[=file system entry|file system entries=]. +A file system maintains an [=implementation-defined=] mapping + of [=file system path=]s to [=file system entries=]. Each [=/file system=] has an associated root, an opaque [=string=] whose value is [=implementation-defined=]. @@ -83,7 +88,7 @@ A [=/file system path=] |a| is the same path as Each [=/file system=] has an associated @@ -111,12 +116,273 @@ return value |path| must adhere to these constraints: +A file system event is a [=struct=] consisting of a +type (a +{{FileSystemChangeType}}), an +entry type (a +{{FileSystemHandleKind}} or null), a +modified path (a +[=/file system path=]), and a +from path (a +[=/file system path=] or null). + +Note: A [=/file system=] fires these events in response to file operations. + +The [=file system/file system event/from path=] must be set when +[=file system/file system event/type=] is "{{FileSystemChangeType/moved}}" and +must be null otherwise. + +Note: The [=file system/file system event/entry type=] is null when the +[=/file system=] cannot determine the {{FileSystemHandleKind}} of the +[=file system/file system event/modified path=] due to the underlying +[=file system entry=] no longer being there. + +A [=/file system=] has an associated [=/set=] of +[=file system observer registrations=] +observer registrations which is initialized to the +empty set. + +When a user agent receives a [=/list=] of [=file system/file system events=] +|events| for a [=/file system=] |fileSystem|, the user agent MUST +[=file system/notify observer registrations=] of the |fileSystem| of |events|. + +Note: The [=file system/file system events=] fired by a [=/file system=] may be +unreliable and can be inaccurate, out of order, or missing. + +
+To notify observer registrations of a [=/file system=] +|fileSystem| of a [=/list=] of [=file system/file system events=] |events|: + +1. [=Enqueue the following steps=] to the [=file system queue=]: + 1. [=list/For each=] |observerRegistration| of the |fileSystem|'s + [=file system/observer registrations=]. + 1. [=file system observer registration/Notify=] |observerRegistration| of |events| + from |fileSystem|. + +
+ +When a user agent receives an error event for a [=/file system=] |fileSystem| +and |observerRegistrations| (a [=subset=] of the |fileSystem|'s +[=file system/observer registrations=]), the user agent MUST +[=file system/send an error|send the error=] to |observerRegistrations| of |fileSystem|. + +
+To send an error to a [=/set=] of +[=file system observer registrations=] |observerRegistrations| of a +[=/file system=] |fileSystem|: + +1. [=Enqueue the following steps=] to the [=file system queue=]: + 1. [=Assert=] |observerRegistrations| is a [=subset=] of |fileSystem|'s + [=file system/observer registrations=]. + 1. [=list/For each=] |observerRegistration| of |observerRegistrations|: + 1. [=file system observer registration/Destroy=] |observerRegistration|. + 1. Let |observer| be |observerRegistration|'s + [=file system observer registration/observer=]. + 1. Let |global| be |observer|'s [=relevant global object=]. + 1. [=Queue a storage task=] with |global| to run these steps: + 1. Let |changedHandle| be the |observerRegistration|'s + [=file system observer registration/root handle=]. + 1. Let |record| be the result of + creating a new `FileSystemChangeRecord` for + |observerRegistration| given |changedHandle|, + "{{FileSystemChangeType/errored}}", and null. + + 1. Invoke |observer|'s [=FileSystemObserver/callback=] with «|record|» as + the first argument and |observer| as the second argument. + +
+ + + +A file system observer registration consists of a +{{FileSystemObserver}} +observer, a +{{FileSystemHandle}} +root handle, and a +[=/boolean=] recursive. + +
+To create an observer registration +for {{FileSystemObserver}} |observer| on {{FileSystemHandle}} |rootHandle| with +[=/boolean=] |recursive|: + + +1. Let |observerRegistration| be a [=file system observer registration=] whose + [=file system observer registration/observer=] is |observer|, + [=file system observer registration/root handle=] is |rootHandle|, and + [=file system observer registration/recursive=] is |recursive|. + +1. Let |observerRegistrationLocator| be |rootHandle|'s [=FileSystemHandle/locator=]. +1. Let |observerRegistrationMap| be |observer|'s [=FileSystemObserver/observerRegistrations=]. +1. Let |fileSystem| be the |observerRegistrationLocator|'s + [=file system locator/file system=]. + +1. [=list/Append=] |observerRegistration| to the |fileSystem|'s + [=file system/observer registrations=]. +1. [=map/set=] |observerRegistrationMap|[|observerRegistrationLocator|] to |observerRegistration|. + +Note: These steps have to be run on the [=file system queue=]. + +
+ +
+To destroy +[=file system observer registration=] |observerRegistration|: + +1. Let |observer| be |observerRegistration|'s [=file system observer registration/observer=]. +1. Let |rootHandle| be |observerRegistration|'s [=file system observer registration/root handle=]. +1. Let |observerRegistrationLocator| be |rootHandle|'s [=FileSystemHandle/locator=]. +1. Let |fileSystem| be |observerRegistrationLocator|'s + [=file system locator/file system=]. +1. [=list/Remove=] |observerRegistration| from the |fileSystem|'s + [=file system/observer registrations=]. +1. [=map/Remove=] |observerRegistrationLocator| from |observer|'s + [=FileSystemObserver/observerRegistrations=]. + +Note: These steps have to be run on the [=file system queue=]. + +
+ +
+To notify a +[=file system observer registration=] |observerRegistration| of a [=/list=] of +[=file system/file system events=] |events| from a [=/file system=] +|fileSystem|: + +1. Let |rootHandle| be |observerRegistration|'s [=file system observer registration/root handle=]. +1. Let |observerRegistrationLocator| be |rootHandle|'s [=FileSystemHandle/locator=]. + +1. [=Assert=]: |observerRegistrationLocator|'s [=file system locator/file system=] is equal to + |fileSystem|. + +1. Let |realm| be |rootHandle|'s [=relevant realm=]. + +1. Let |observer| be |observerRegistration|'s [=file system observer registration/observer=]. +1. Let |global| be |observer|'s [=relevant global object=]. +1. [=Queue a storage task=] with |global| to run these steps: + 1. Let |records| be a [=/list=] of {{FileSystemChangeRecord}}. + 1. [=list/For each=] |event| of |events|: + + 1. Let |eventType| be |event|'s [=file system/file system event/type=]. + + 1. [=Assert=] |eventType| is not equal to + "{{FileSystemChangeType/errored}}". + + Note: "{{FileSystemChangeType/errored}}" events are sent in the + [=file system/send an error=] steps. + + 1. Let |eventEntryType| be |event|'s [=file system/file system event/entry type=]. + + 1. If |eventType| is "{{FileSystemChangeType/modified}}" and + |eventEntryType| is + "{{FileSystemHandleKind/directory}}" or null, [=continue=]. + + Note: We can safely ignore "{{FileSystemChangeType/modified}}" events for + "{{FileSystemHandleKind/directory}}". These might be sent when one of its + children receives an event which the page will be made aware of through + that child event. Or they might be sent when some OS specific property + changes which the web page cannot observe through web APIs. Similarly when + we don't know the {{FileSystemHandleKind}}, we can ignore it since the + [=/file system entry=] at the + [=file system/file system event/modified path=] no longer exists. + + 1. If |eventEntryType| is null: + 1. Set |eventEntryType| to |observerRegistrationLocator|'s + [=file system locator/kind=]. + + Note: When we don't know the {{FileSystemHandleKind}} of the + [=file system/file system event/modified path=], we have to arbitrarily + choose one to construct the {{FileSystemChangeRecord/changedHandle}}. + Setting it to |observerRegistrationLocator|'s [=file system locator/kind=] + atleast means it'll be right for events on the root handle. + + 1. Let |modifiedPath| be |event|'s [=file system/file system event/modified path=]. + 1. Let |fromPath| be |event|'s [=file system/file system event/from path=]. + + 1. Let |changedHandle| be the result of + creating a new `FileSystemHandle` given |fileSystem|, + |modifiedPath|, and |eventEntryType| in |realm|. + 1. Let |movedFromHandle| be null. + + 1. Let |modifiedPathInScope| be equal to |changedHandle| + [=file system observer registration/is in scope=] of |observerRegistration|. + 1. Let |fromPathInScope| be false. + + 1. If |eventType| is "{{FileSystemChangeType/moved}}": + 1. [=Assert=]: |fromPath| is not null. + 1. Set |movedFromHandle| to the result of + creating a new `FileSystemHandle` given |fileSystem|, + |fromPath|, and |eventEntryType| in |realm|. + 1. Set |fromPathInScope| equal to |movedFromHandle| + [=file system observer registration/is in scope=] of |observerRegistration|. + + 1. If both |modifiedPathInScope| and |fromPathInScope| are false, [=continue=]. + + 1. If |eventType| is "{{FileSystemChangeType/moved}}": + 1. If |modifiedPathInScope| is false: + 1. Set |eventType| to "{{FileSystemChangeType/disappeared}}". + 1. Set |changedHandle| to |movedFromHandle|. + 1. Set |fromPath| to null. + 1. If |fromPathInScope| is false: + 1. Set |eventType| to "{{FileSystemChangeType/appeared}}". + 1. Set |fromPath| to null. + + Note: Some [=/file systems=] convert "{{FileSystemChangeType/moved}}" events + in and out of scope to "{{FileSystemChangeType/appeared}}" and + "{{FileSystemChangeType/disappeared}}" respectively before we can. So to + maintain consistency, we do it here. + + 1. Let |record| be the result of creating a new `FileSystemChangeRecord` for + |observerRegistration| given |changedHandle|, |eventType|, and |fromPath|. + 1. [=list/Append=] |record| to |records|. + + 1. If |eventType| is equal to "{{FileSystemChangeType/disappeared}}" and + |changedHandle|'s [=FileSystemHandle/locator=] is equal to + |observerRegistrationLocator|: + 1. Set |errorRecord| to the result of + creating a new `FileSystemChangeRecord` for |observerRegistration| given + |changedHandle|, "{{FileSystemChangeType/errored}}", and null. + 1. [=list/Append=] |errorRecord| to |records|. + 1. [=file system observer registration/Destroy=] |observerRegistration|. + 1. [=break=]. + + 1. If |records| is not [=set/is empty|empty=]: + 1. Invoke |observer|'s [=FileSystemObserver/callback=] with |records| as the + first argument and |observer| as the second argument. + +Note: These steps have to be run on the [=file system queue=]. + +
+ +
+To determine if a {{FileSystemHandle}} |handle| +is in scope of a +[=file system observer registration=] |observerRegistration|: + + +1. Let |observerRegistrationLocator| be |observerRegistration|'s [=file system observer registration/root handle=]'s + [=FileSystemHandle/locator=]. +1. Let |observerRegistrationRecursive| be |observerRegistration|'s [=file system observer registration/recursive=]. +1. Let |handleLocator| be |handle|'s [=FileSystemHandle/locator=]. + +1. Let |pathRelation| be the result of [=file system locator/getting the relationship=] + between |observerRegistrationLocator| and |handleLocator|. + +1. If |pathRelation| is "`other`" or "`ancestor`", return false. +1. If |pathRelation| is "`descendant`" and |observerRegistrationRecursive| is false, + return false. +1. Return true. + +Note: These steps have to be run on the [=file system queue=]. + +
+ ### File System Entry ### {#concept-file-system-entry} A file system entry is either a [=file entry=] or a [=directory entry=]. -Each [=/file system entry=] has an associated -file system (a [=/file system=]). +Each [=/file system entry=] has an associated [=/file system=] +file system. Each [=/file system entry=] has an associated query access @@ -290,34 +556,49 @@ a [=/file system locator=] |b| if
To resolve a -[=/file system locator=] |child| relative to a [=directory locator=] |root|: +[=/file system locator=] |child| relative to a [=file system locator=] |root|: -1. Let |result| be [=a new promise=]. -1. [=Enqueue the following steps=] to the [=file system queue=]: - 1. If |child|'s [=FileSystemHandle/locator=]'s [=file system locator/file system=] - is not |root|'s [=FileSystemHandle/locator=]'s [=file system locator/file system=], - [=/resolve=] |result| with null, and abort these steps. +1. Let |relationship| be the result of [=file system locator/getting the relationship=] + between |root| and |child|. +1. If |relationship| is equal to "`other`" or "`ancestor`", return null. +1. If |relationship| is equal to "`self`", return « ». - 1. Let |childPath| be |child|'s [=FileSystemHandle/locator=]'s [=file system locator/path=]. - 1. Let |rootPath| be |root|'s [=FileSystemHandle/locator=]'s [=file system locator/path=]. - 1. If |childPath| is [=the same path as=] |rootPath|, - [=/resolve=] |result| with « », and abort these steps. +1. Let |childPath| be |child|'s [=file system locator/path=]. +1. Let |rootPath| be |root|'s [=file system locator/path=]. - 1. If |rootPath|'s [=list/size=] is greater than |childPath|'s [=list/size=], - [=/resolve=] |result| with null, and abort these steps. +1. Let |relativePath| be « ». +1. [=list/For each=] |index| of [=the range=] from |rootPath|'s [=list/size=] + to |childPath|'s [=list/size=], exclusive, + [=list/append=] |childPath|[|index|] to |relativePath|. - 1. [=list/For each=] |index| of |rootPath|'s [=list/indices=]: - 1. If |rootPath|.\[[|index|]] is not |childPath|.\[[|index|]], then - [=/resolve=] |result| with null, and abort these steps. +1. Return |relativePath|. - 1. Let |relativePath| be « ». - 1. [=list/For each=] |index| of [=the range=] from |rootPath|'s [=list/size=] - to |rootPath|'s [=list/size=], exclusive, - [=list/append=] |childPath|.\[[|index|]] to |relativePath|. +Note: These steps have to be run on the [=file system queue=]. - 1. [=/Resolve=] |result| with |relativePath|. +
-1. Return |result|. +
+To get the relationship from a +[=/file system locator=] |self| to a [=file system locator=] |related|: + +1. If |self|'s [=file system locator/file system=] is not |related|'s + [=file system locator/file system=], return "`other`". + +1. Let |selfPath| be |self|'s [=file system locator/path=]. +1. Let |relatedPath| be |related|'s [=file system locator/path=]. + +1. Let |selfPathSize| be |selfPath|'s [=list/size=]. +1. Let |relatedPathSize| be |relatedPath|'s [=list/size=]. + +1. [=list/For each=] |index| of |selfPath|'s [=list/indices=]: + 1. If |index| is greater than or equal to |relatedPathSize|, return "`ancestor`". + 1. If |selfPath|[|index|] is not |relatedPath|[|index|], return "`other`". + +1. If |selfPathSize| equals |relatedPathSize|, return "`self`". +1. If |selfPathSize| + 1 equals |relatedPathSize|, return "`direct child`". +1. Return "`descendant`". + +Note: These steps have to be run on the [=file system queue=].
@@ -330,8 +611,6 @@ The locate an entry algorithm give 1. Let |entry| be the result of running |fileSystem|'s [=file system/locate an entry=] given |path|. 1. If |entry| is null, return null. -1. If |locator| is a [=file locator=], [=Assert=]: |entry| is a [=file entry=]. -1. If |locator| is a [=directory locator=], [=Assert=]: |entry| is a [=directory entry=]. 1. Return |entry|. @@ -380,6 +659,20 @@ A {{FileSystemHandle}} object is associated with a +To create a new `FileSystemHandle` given a +[=/file system=] |fileSystem|, a [=/file system path=] |path|, and a +{{FileSystemHandleKind}} |kind| in a [=/Realm=] |realm|: + +1. If |kind| is "`file`": + 1. Set |changedHandle| to the result of creating a new `FileSystemFileHandle` + given |fileSystem| and |path| in |realm|. +1. Otherwise: + 1. Set |changedHandle| to the result of creating a new `FileSystemDirectoryHandle` + given |fileSystem| and |path| in |realm|. + + + A {{FileSystemHandle}} is in a bucket file system if the first [=list/item=] of its [=FileSystemHandle/locator=]'s @@ -481,7 +774,7 @@ given a [=directory locator=] |parentLocator| and a string |name| in a [=/Realm= 1. Let |handle| be a [=new=] {{FileSystemFileHandle}} in |realm|. 1. Let |childType| be "{{FileSystemHandleKind/file}}". -1. Let |childFileSystem| be the |parentLocator|'s [=file system locator/file system=] +1. Let |childFileSystem| be the |parentLocator|'s [=file system locator/file system=]. 1. Let |childPath| be the result of [=list/clone|cloning=] |parentLocator|'s [=file system locator/path=] and [=list/append|appending=] |name|. 1. Set |handle|'s [=FileSystemHandle/locator=] to a [=/file system locator=] whose @@ -1123,10 +1416,18 @@ if (relative_path === null) {
-The resolve(|possibleDescendant|) method steps are -to return the result of [=file system locator/resolving=] -|possibleDescendant|'s [=FileSystemHandle/locator=] -relative to [=this=]'s [=FileSystemHandle/locator=]. +The resolve(|possibleDescendant|) +method steps are: + +1. Let |result| be [=a new promise=]. +1. Let |global| be [=this=]'s [=relevant global object=]. +1. [=Enqueue the following steps=] to the [=file system queue=]: + 1. Let |relativePath| be the result of [=file system locator/resolving=] + |possibleDescendant|'s [=FileSystemHandle/locator=] + relative to [=this=]'s [=FileSystemHandle/locator=]. + 1. [=Queue a storage task=] with |global| to run these steps: + 1. [=/resolve=] |result| with |relativePath|. +1. Return |result|.
@@ -1713,14 +2014,15 @@ guarantee. # Accessing the Bucket File System # {#sandboxed-filesystem} -The bucket file system -is a [=/file system=] implementation -whose [=file system/root=] is an [=implementation-defined=] opaque [=string=] -and whose [=storage endpoint=]'s -identifier of `"fileSystem"`, +The bucket file system is a +[=storage endpoint=] whose +identifier is `"fileSystem"`, types are `« "local" »`, and quota is null. +The [=/bucket file system=] implements [=/file system=] with +[=file system/root=] as an [=implementation-defined=] opaque [=string=]. + Note: [=/bucket file system=]'s [=file system/root=] might include relevant identifying information such as the [=storage bucket=]. @@ -1776,6 +2078,197 @@ The getDirectory() method steps are: +# Observing file system change events # {#observing-the-file-system} + +## The {{FileSystemObserver}} interface ## {#api-filesystemobserver} + + +dictionary FileSystemObserverObserveOptions { + boolean recursive = false; +}; + +callback FileSystemObserverCallback = undefined ( + sequence<FileSystemChangeRecord> records, + FileSystemObserver observer +); + +[ + Exposed=(DedicatedWorker,SharedWorker,Window), + SecureContext +] interface FileSystemObserver { + constructor(FileSystemObserverCallback callback); + + Promise<undefined> observe(FileSystemHandle handle, + optional FileSystemObserverObserveOptions options = {}); + undefined unobserve(FileSystemHandle handle); + undefined disconnect(); +}; + + +
+ The {{FileSystemObserver}} interface can be used to observe + [=file system/file system events=]. +
+ +The {{FileSystemObserver}} has an asociated {{FileSystemObserverCallback}} +callback. + +The {{FileSystemObserver}} has an associated +observerRegistrations (a [=map=] of +[=/file system locators=] to [=file system observer registrations=]). + +### The {{FileSystemObserver}} constructor ### {#api-filesystemobsever-constructor} + +
+The new FileSystemObserver(FileSystemObserverCallback |callback|) +steps are: + +1. Let [=this=] be a new {{FileSystemObserver}}. +1. Set [=this=]'s [=FileSystemObserver/callback=] to |callback|. +1. Set [=this=]'s [=FileSystemObserver/observerRegistrations=] be the empty map. + +
+ +### The {{FileSystemObserver/observe()}} method ### {#api-filesystemobserver-observe} + +
+ +The observe(FileSystemHandle |handle|, +FileSystemObserverObserveOptions |options|) steps are: + +1. Let |result| be [=a new promise=]. + +1. Let |recursive| be |options|["{{FileSystemObserverObserveOptions/recursive}}"]. +1. Let |observerRegistrationMap| be [=this=]'s [=FileSystemObserver/observerRegistrations=]. +1. Let |locator| be |handle|'s [=FileSystemHandle/locator=]. +1. Let |global| be [=this=]'s [=relevant global object=]. + +1. [=Enqueue the following steps=] to the [=file system queue=]: + 1. If |observerRegistrationMap|[|locator|] [=map/exists=], abort these steps. + + 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=] + is not "{{PermissionState/granted}}", [=/reject=] |result| with a + {{DOMException}} of |accessResult|'s + [=file system access result/error name=] and abort these steps. + + 1. If |entry| is null, [=/reject=] |result| with a + "{{NotFoundError}}" {{DOMException}} and abort these steps. + 1. [=Assert=]: |entry| is a [=file entry=]. + + 1. [=Enqueue the following steps=] to the [=file system queue=]: + 1. [=file system observer registration/Create an observer registration=] + for [=this=] on |handle| with |recursive|. + + 1. [=/Resolve=] |result| with null. + +
+ + +### The {{FileSystemObserver/unobserve()}} method ### {#api-filesystemobserver-unobserve} + +
+The unobserve(FileSystemHandle |handle|) +steps are: + +1. Let |locator| be |handle|'s [=FileSystemHandle/locator=]. +1. Let |observerRegistrationMap| be [=this=]'s [=FileSystemObserver/observerRegistrations=]. + +1. [=Enqueue the following steps=] to the [=file system queue=]: + 1. If |observerRegistrationMap|[|locator|] does not [=map/exist=], abort these steps. + 1. [=file system observer registration/Destroy=] |observerRegistrationMap|[|locator|]. + +
+ +### The {{FileSystemObserver/disconnect()}} method ### {#api-filesystemobserver-disconnect} + +
+The disconnect() steps are: + +1. Let |observerRegistrationMap| be [=this=]'s [=FileSystemObserver/observerRegistrations=]. + +1. [=Enqueue the following steps=] to the [=file system queue=]: + 1. Let |observerRegistrations| be the result of [=map/getting the values=] of + |observerRegistrationMap|. + 1. [=list/For each=] |observerRegistration| in |observerRegistrations|: + 1. [=file system observer registration/Destroy=] |observerRegistration|. + +
+ +## The {{FileSystemChangeRecord}} interface ## {#api-filesystemchangerecord} + + +enum FileSystemChangeType { + "appeared", + "disappeared", + "errored", + "modified", + "moved", + "unknown", +}; + +dictionary FileSystemChangeRecord { + FileSystemHandle root; + FileSystemHandle changedHandle; + FrozenArray<USVString> relativePathComponents; + FileSystemChangeType type; + FrozenArray<USVString>? relativePathMovedFrom; +}; + + +
+ : root + :: The handle that was passed to FileSystemObserver.observe(). + : changedHandle + :: The path of `changedHandle` relative to `root`. + : relativePathComponents + :: The path of {{FileSystemChangeRecord/changedHandle}} relative to + {{FileSystemChangeRecord/root}}. + : type + :: The type of change. + : relativePathMovedFrom + :: If {{FileSystemChangeRecord/type}} is "{{FileSystemChangeType/moved}}", + this corresponds to the former path of {{FileSystemChangeRecord/changedHandle}} + relative to {{FileSystemChangeRecord/root}}, if the former path is known; + otherwise null. + +
+ +
+To +create a new `FileSystemChangeRecord` +for a [=file system observer registration=] |observerRegistration| given a {{FileSystemHandle}} +|changedHandle|, a {{FileSystemChangeType}} |type|, and an optional +[=/file system locator=] |movedFromPath|: + +1. Let |root| be |observerRegistration|'s + [=file system observer registration/root handle=]. +1. Let |rootLocator| be |root|'s [=FileSystemHandle/locator=]. +1. Let |changedHandleLocator| be |changedHandle|'s [=FileSystemHandle/locator=]. +1. Let |relativePathComponents| be the result of [=file system locator/resolving=] + |changedHandleLocator| relative to |rootLocator|. +1. Let |relativePathMovedFrom| be null. +1. If |movedFromPath| was given, set |relativePathMovedFrom| to the result of + [=file system locator/resolving=] |movedFromPath| relative to |rootLocator|. + + +1. Let |realm| be |changedHandle|'s [=relevant realm=]. +1. Let |record| be a [=new=] {{FileSystemChangeRecord}} in |realm|. + +1. Set |record|'s {{FileSystemChangeRecord/root}} to |root|. +1. Set |record|'s {{FileSystemChangeRecord/changedHandle}} to |changedHandle|. +1. Set |record|'s {{FileSystemChangeRecord/relativePathComponents}} to |relativePathComponents|. +1. Set |record|'s {{FileSystemChangeRecord/type}} to |type|. +1. Set |record|'s {{FileSystemChangeRecord/relativePathMovedFrom}} to |relativePathMovedFrom|. + +1. Return |record|. + +
+

Acknowledgments