From 5ba280f5af2287b4be5fe096a7f1239840fe6a3a Mon Sep 17 00:00:00 2001 From: Austin Sullivan Date: Fri, 30 Jul 2021 23:38:29 +0000 Subject: [PATCH 1/8] outline of FileSystemHandle::move() --- EXPLAINER.md | 10 ++++------ index.bs | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/EXPLAINER.md b/EXPLAINER.md index 7061206..864a13a 100644 --- a/EXPLAINER.md +++ b/EXPLAINER.md @@ -232,12 +232,10 @@ const file_ref = await dir_ref.getFile('foo.js'); // Get a subdirectory. const subdir = await dir_ref.getDirectory('bla', {create: true}); -// No special API to create copies, but still possible to do so by using -// available read and write APIs. -const new_file = await dir_ref.getFile('new_name', {create: true}); -const new_file_writer = await new_file.createWritable(); -await new_file_writer.write(await file_ref.getFile()); -await new_file_writer.close(); +// Rename a file and/or move it to another directory +await file_ref.move('new_name'); +await file_ref.move(other_dir_ref); +await file_ref.move(dir_ref, 'newer_name'); // Or using streams: const copy2 = await dir_ref.getFile('new_name', {create: true}); diff --git a/index.bs b/index.bs index 6a368a2..b903d23 100644 --- a/index.bs +++ b/index.bs @@ -262,6 +262,8 @@ interface FileSystemHandle { readonly attribute FileSystemHandleKind kind; readonly attribute USVString name; + Promise move(USVString name); + Promise move(FileSystemDirectoryHandle parent, USVString? name); Promise remove(optional FileSystemRemoveOptions options = {}); Promise isSameEntry(FileSystemHandle other); @@ -317,6 +319,43 @@ and return {{FileSystemHandleKind/"directory"}} otherwise. The name attribute must return the [=entry/name=] of the associated [=FileSystemHandle/entry=]. +### The {{FileSystemHandle/move()}} method ### {#api-filesystemhandle-move} + +
+ : await |handle| . {{FileSystemHandle/move()|move}}({|new_entry_name|}) + :: Attempts to atomically rename the entry represented by |handle| to + |new_entry_name| in the underlying file system. + + : await |handle| . {{FileSystemHandle/move()|move}}({|destination_directory|}) + :: Attempts to move the entry represented by |handle| to |destination_directory|, + while keeping its existing name. + + : await |handle| . {{FileSystemHandle/move()|move}}({|destination_directory|, |new_entry_name|}) + :: Attempts to move the entry represented by |handle| to |destination_directory|, + as well as renaming to |new_entry_name|. + + If |destination_directory| is on the same underlying filesystem, this move + will be atomic. Moves to non-local file systems will are not guaranteed to + be atomic and will involve duplicating data. + + In all of these cases, for files or directories with multiple hardlinks or + symlinks, the entry which is renamed is the entry corresponding to the path + which was used to obtain the handle. + + Attempting to rename a file or directory that does not exist or passing an + invalid name will result in a promise rejection. + +
+ +
+The move(|destination_directory|, |new_entry_name|) method, +when invoked, must run these steps: + +1. TODO + +
+ + ### The {{FileSystemHandle/remove()}} method ### {#api-filesystemhandle-remove}
From c447973380f8be59c71ce3af4e60d85137f971c1 Mon Sep 17 00:00:00 2001 From: Austin Sullivan <77407429+a-sully@users.noreply.github.com> Date: Wed, 8 Sep 2021 16:32:47 -0700 Subject: [PATCH 2/8] Update EXPLAINER.md --- EXPLAINER.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EXPLAINER.md b/EXPLAINER.md index 864a13a..2c20796 100644 --- a/EXPLAINER.md +++ b/EXPLAINER.md @@ -233,7 +233,7 @@ const file_ref = await dir_ref.getFile('foo.js'); const subdir = await dir_ref.getDirectory('bla', {create: true}); // Rename a file and/or move it to another directory -await file_ref.move('new_name'); +await file_ref.rename('new_name'); await file_ref.move(other_dir_ref); await file_ref.move(dir_ref, 'newer_name'); From 1d68183e60a39af776d5ccb587a536f73939152a Mon Sep 17 00:00:00 2001 From: Austin Sullivan <77407429+a-sully@users.noreply.github.com> Date: Wed, 8 Sep 2021 16:34:05 -0700 Subject: [PATCH 3/8] Update index.bs --- index.bs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index b903d23..6c452d8 100644 --- a/index.bs +++ b/index.bs @@ -262,8 +262,9 @@ interface FileSystemHandle { readonly attribute FileSystemHandleKind kind; readonly attribute USVString name; - Promise move(USVString name); - Promise move(FileSystemDirectoryHandle parent, USVString? name); + Promise rename(USVString name); + Promise move(FileSystemDirectoryHandle parent); + Promise move(FileSystemDirectoryHandle parent, USVString name); Promise remove(optional FileSystemRemoveOptions options = {}); Promise isSameEntry(FileSystemHandle other); From c716ead9247eb5d8d8dc8be8978a731af1c23a35 Mon Sep 17 00:00:00 2001 From: Austin Sullivan <77407429+a-sully@users.noreply.github.com> Date: Wed, 8 Sep 2021 16:38:15 -0700 Subject: [PATCH 4/8] Update index.bs --- index.bs | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/index.bs b/index.bs index 6c452d8..f6d0d5e 100644 --- a/index.bs +++ b/index.bs @@ -320,13 +320,34 @@ and return {{FileSystemHandleKind/"directory"}} otherwise. The name attribute must return the [=entry/name=] of the associated [=FileSystemHandle/entry=]. -### The {{FileSystemHandle/move()}} method ### {#api-filesystemhandle-move} +### The {{FileSystemHandle/rename()}} method ### {#api-filesystemhandle-rename}
- : await |handle| . {{FileSystemHandle/move()|move}}({|new_entry_name|}) + : await |handle| . {{FileSystemHandle/rename()|rename}}({|new_entry_name|}) :: Attempts to atomically rename the entry represented by |handle| to |new_entry_name| in the underlying file system. + For files or directories with multiple hardlinks or symlinks, the entry + which is renamed is the entry corresponding to the path which was used + to obtain the handle. + + Attempting to rename a file or directory that does not exist or passing an + invalid name will result in a promise rejection. + +
+ +
+The rename(|new_entry_name|) method, +when invoked, must run these steps: + +1. TODO + +
+ + +### The {{FileSystemHandle/move()}} method ### {#api-filesystemhandle-move} + +
: await |handle| . {{FileSystemHandle/move()|move}}({|destination_directory|}) :: Attempts to move the entry represented by |handle| to |destination_directory|, while keeping its existing name. @@ -339,11 +360,11 @@ associated [=FileSystemHandle/entry=]. will be atomic. Moves to non-local file systems will are not guaranteed to be atomic and will involve duplicating data. - In all of these cases, for files or directories with multiple hardlinks or + For files or directories with multiple hardlinks or symlinks, the entry which is renamed is the entry corresponding to the path which was used to obtain the handle. - Attempting to rename a file or directory that does not exist or passing an + Attempting to move a file or directory that does not exist or passing an invalid name will result in a promise rejection.
From f7bc98424927703fe574dc78ff370fab8f1dcb55 Mon Sep 17 00:00:00 2001 From: Austin Sullivan Date: Wed, 8 Sep 2021 23:54:21 +0000 Subject: [PATCH 5/8] move discussion to md file --- MoveAndRename.md | 164 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 MoveAndRename.md diff --git a/MoveAndRename.md b/MoveAndRename.md new file mode 100644 index 0000000..8538c1a --- /dev/null +++ b/MoveAndRename.md @@ -0,0 +1,164 @@ +# Adding FileSystemHandle::move() and FileSystemHandle::rename() methods + +## Authors: + +* Austin Sullivan (asully@chromium.org) + +## Participate + +* [Issue tracker](https://github.com/WICG/file-system-access/issues) + +## Table of Contents + + + + +- [Adding FileSystemHandle::move() and FileSystemHandle::rename() methods](#adding-filesystemhandlemove-and-filesystemhandlerename-methods) + - [Authors:](#authors) + - [Participate](#participate) + - [Table of Contents](#table-of-contents) +- [Overview](#overview) +- [API Surface](#api-surface) + - [Open Questions - Naming](#open-questions---naming) +- [Handling Moves to Other Directories](#handling-moves-to-other-directories) + - [(1) Moving to a Non-Local File System](#1-moving-to-a-non-local-file-system) + - [(2) Moving out of the OPFS](#2-moving-out-of-the-opfs) + - [(3) Moving to a Directory on the Local File System](#3-moving-to-a-directory-on-the-local-file-system) + - [Open Questions - Move](#open-questions---move) + - [Should behavior be different when moving a file vs moving a directory?](#should-behavior-be-different-when-moving-a-file-vs-moving-a-directory) + - [What should happen if the operation cannot be completed successfully?](#what-should-happen-if-the-operation-cannot-be-completed-successfully) +- [Implementation Notes](#implementation-notes) +- [Alternatives Considered](#alternatives-considered) + - [Only support "rename" functionality](#only-support-rename-functionality) + + + +# Overview + +Currently, the API does not support an efficient way to move or rename files or +directories. This requires creating a new file/directory, copying over data +(recursively, in the case of a directory), and removing the original. This +process is slow, error prone (e.g. disk full), and can require re-uploading +files in some cases (e.g. Google Drive files on ChromeOS). + +We propose adding new `FileSystemHandle::rename()` and +`FileSystemHandle::move()` methods. `rename()` guarantees atomic moves of a file +or directory without the need to duplicate data. `move()` only offers atomic +moves of a file or directory if it is moved within the same file system, while +moves to non-local file systems, will not be guaranteed to be atomic and may +involve duplicating data. See the [Open Questions](#open-questions---move). + +# API Surface +We propose adding a `rename()` method and a `move()` method with two variations. + +`rename()` will rename a file or directory. It is guaranteed to be atomic. + +The first `move()` variation allows a user to specify a `destination_directory` +to move to, which may or may not be on the same file system. The name of the +original file or directory is retained. This is not guaranteed to be atomic, +since the destination directory may be on a different file system and/or may be +subject to other checks (ex: Safe Browsing in Chrome). + +The second `move()` variation allows a user to specify a `new_entry_name` as +well as a `destination_directory` to move to. The same (lack of) atomicity +guarantees apply here as the first `move()` variation. + +``` +interface FileSystemHandle { + ... + + Promise rename(USVString new_entry_name); + Promise move(FileSystemDirectoryHandle destination_directory); + Promise move(FileSystemDirectoryHandle destination_directory, USVString new_entry_name); + + ... +}; +``` + +## Open Questions - Naming +- Should we prefer `move()` to move verbose alternatives, such as `moveTo()` or + `moveToDirectory()`? +- Should we bother guaranteeing (in the spec) atomicity to all handles `move()`d + on the same file system, or only for `rename()`d handles? + +# Handling Moves to Other Directories + +There are three cases to consider when moving to other directories: + +## (1) Moving to a Non-Local File System +Moving across file systems cannot be guaranteed to be atomic if the operation +cannot be completed successfully (ex: network connection issues, lack disk +space, etc.). This may result in partial writes to the target directory. + +Note that this approach is no worse than what is available currently. + +## (2) Moving out of the OPFS + +[#310](https://github.com/WICG/file-system-access/pull/310) exposes a strong use +case for fast, atomic moves to other directories on the same file system. Files +can be written efficiently in the Origin Private File System using an +AccessHandle, then efficiently moved to a directory of the user's choice. +However, writes using an AccessHandle are not subjected to Safe Browsing checks +in Chrome. Moving files out of the OPFS to a user's directory will require +running Safe Browsing checks on all moved files. + +For example, moving a large directory across the OPFS -> file system boundary +means locking and performing checks (Safe Browsing in Chrome) for an unbounded +number of files. + +## (3) Moving to a Directory on the Local File System + +This is the most straightforward case. Every `rename()` falls in this case. The +operation should be atomic and fast, since no Safe Browsing checks need to be +performed. However, providing these guarantees for `move()` in only this case +may be confusing. + +## Open Questions - Move + +### Should behavior be different when moving a file vs moving a directory? +- For a file: + - Atomicity is only guaranteed in (2) and (3), though is likely true for (1). + - Speed is only guaranteed in (3). +- For a directory: + - Atomicity is only easily guaranteed in (3). Atomicity for (2) would be + complex (likely requiring locking each file as an unbounded number of files + are scanned) and may not be the best option. + - Speed is only guaranteed in (3), but the implications of this for (1) and + (2) is much greater than when only moving a file. + +### What should happen if the operation cannot be completed successfully? +- Abort the operation + - Least complexity for browser implementers, meaning less room for + implementation-specific behavior. + - Simplest interface. + - Potential for errors not caught in development. + - Apps need code to handle the cross-filesystem case. +- Abort the operation and attempt to remove partial writes + - This may not be possible. Ex: loss of network connection. + - Adds lots of complexity. +- Abort the operation and throw an error + - Less complexity. + - No performance cliff. + - More flexibility in handling errors for the app. + +# Implementation Notes + +- Write permission needs to have been granted to both the source and destination + directories. +- Invalid or unsafe `new_entry_name`s will result in a `Promise` rejection. +- All entries contained within a directory which is moved no longer point to an + existing file/directory. We currently have no plans to explicitly update or + invalidate these handles, which would otherwise be an expensive recursive + operation. + +# Alternatives Considered + +## Only support "rename" functionality + +Pros: +- No need to handle (or spec) the case where moves are non-atomic +- Simpler interface + +Cons: +- We should allow for efficient moves out of the OPFS, as exposed in + [#310](https://github.com/WICG/file-system-access/pull/310) From a7bef638bb36575810e198d98f7c4e8d7d09974f Mon Sep 17 00:00:00 2001 From: Austin Sullivan <77407429+a-sully@users.noreply.github.com> Date: Mon, 13 Sep 2021 20:18:53 +0000 Subject: [PATCH 6/8] Apply suggestions from code review Co-authored-by: Thomas Steiner --- MoveAndRename.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/MoveAndRename.md b/MoveAndRename.md index 8538c1a..f603854 100644 --- a/MoveAndRename.md +++ b/MoveAndRename.md @@ -39,16 +39,17 @@ Currently, the API does not support an efficient way to move or rename files or directories. This requires creating a new file/directory, copying over data (recursively, in the case of a directory), and removing the original. This process is slow, error prone (e.g. disk full), and can require re-uploading -files in some cases (e.g. Google Drive files on ChromeOS). +files in some cases (e.g. Google Drive files on Chrome OS). We propose adding new `FileSystemHandle::rename()` and `FileSystemHandle::move()` methods. `rename()` guarantees atomic moves of a file or directory without the need to duplicate data. `move()` only offers atomic moves of a file or directory if it is moved within the same file system, while -moves to non-local file systems, will not be guaranteed to be atomic and may +moves to non-local file systems will not be guaranteed to be atomic and may involve duplicating data. See the [Open Questions](#open-questions---move). # API Surface + We propose adding a `rename()` method and a `move()` method with two variations. `rename()` will rename a file or directory. It is guaranteed to be atomic. @@ -57,11 +58,11 @@ The first `move()` variation allows a user to specify a `destination_directory` to move to, which may or may not be on the same file system. The name of the original file or directory is retained. This is not guaranteed to be atomic, since the destination directory may be on a different file system and/or may be -subject to other checks (ex: Safe Browsing in Chrome). +subject to other checks (e.g. Safe Browsing in Chrome). The second `move()` variation allows a user to specify a `new_entry_name` as well as a `destination_directory` to move to. The same (lack of) atomicity -guarantees apply here as the first `move()` variation. +guarantees apply here as with the first `move()` variation. ``` interface FileSystemHandle { @@ -76,6 +77,7 @@ interface FileSystemHandle { ``` ## Open Questions - Naming + - Should we prefer `move()` to move verbose alternatives, such as `moveTo()` or `moveToDirectory()`? - Should we bother guaranteeing (in the spec) atomicity to all handles `move()`d @@ -86,8 +88,9 @@ interface FileSystemHandle { There are three cases to consider when moving to other directories: ## (1) Moving to a Non-Local File System + Moving across file systems cannot be guaranteed to be atomic if the operation -cannot be completed successfully (ex: network connection issues, lack disk +cannot be completed successfully (e.g. network connection issues, lack disk space, etc.). This may result in partial writes to the target directory. Note that this approach is no worse than what is available currently. @@ -97,8 +100,8 @@ Note that this approach is no worse than what is available currently. [#310](https://github.com/WICG/file-system-access/pull/310) exposes a strong use case for fast, atomic moves to other directories on the same file system. Files can be written efficiently in the Origin Private File System using an -AccessHandle, then efficiently moved to a directory of the user's choice. -However, writes using an AccessHandle are not subjected to Safe Browsing checks +`AccessHandle`, then efficiently moved to a directory of the user's choice. +However, writes using an `AccessHandle` are not subjected to Safe Browsing checks in Chrome. Moving files out of the OPFS to a user's directory will require running Safe Browsing checks on all moved files. @@ -115,7 +118,8 @@ may be confusing. ## Open Questions - Move -### Should behavior be different when moving a file vs moving a directory? +### Should behavior be different when moving a file vs. moving a directory? + - For a file: - Atomicity is only guaranteed in (2) and (3), though is likely true for (1). - Speed is only guaranteed in (3). @@ -127,6 +131,7 @@ may be confusing. (2) is much greater than when only moving a file. ### What should happen if the operation cannot be completed successfully? + - Abort the operation - Least complexity for browser implementers, meaning less room for implementation-specific behavior. From 60eba9255248e30956d04e9810a41c54e132787e Mon Sep 17 00:00:00 2001 From: Austin Sullivan Date: Thu, 13 Jan 2022 18:15:46 +0000 Subject: [PATCH 7/8] consolidate rename and move --- EXPLAINER.md | 13 ++++-- MoveAndRename.md => Move.md | 93 +++++++++++++++---------------------- 2 files changed, 47 insertions(+), 59 deletions(-) rename MoveAndRename.md => Move.md (56%) diff --git a/EXPLAINER.md b/EXPLAINER.md index 2c20796..14d58a9 100644 --- a/EXPLAINER.md +++ b/EXPLAINER.md @@ -233,9 +233,16 @@ const file_ref = await dir_ref.getFile('foo.js'); const subdir = await dir_ref.getDirectory('bla', {create: true}); // Rename a file and/or move it to another directory -await file_ref.rename('new_name'); -await file_ref.move(other_dir_ref); -await file_ref.move(dir_ref, 'newer_name'); +await file_ref.move('new_name'); // Rename the file. +await file_ref.move(other_dir_ref); // Move to another directory. +await file_ref.move(dir_ref, 'newer_name'); // Move and rename. + +// No special API to create copies, but still possible to do so by using +// available read and write APIs. +const new_file = await dir_ref.getFile('new_name', {create: true}); +const new_file_writer = await new_file.createWritable(); +await new_file_writer.write(await file_ref.getFile()); +await new_file_writer.close(); // Or using streams: const copy2 = await dir_ref.getFile('new_name', {create: true}); diff --git a/MoveAndRename.md b/Move.md similarity index 56% rename from MoveAndRename.md rename to Move.md index f603854..2621460 100644 --- a/MoveAndRename.md +++ b/Move.md @@ -1,4 +1,4 @@ -# Adding FileSystemHandle::move() and FileSystemHandle::rename() methods +# Adding the FileSystemHandle::move() method ## Authors: @@ -13,19 +13,18 @@ -- [Adding FileSystemHandle::move() and FileSystemHandle::rename() methods](#adding-filesystemhandlemove-and-filesystemhandlerename-methods) +- [Adding the FileSystemHandle::move() method](#adding-the-filesystemhandlemove-method) - [Authors:](#authors) - [Participate](#participate) - [Table of Contents](#table-of-contents) - [Overview](#overview) - [API Surface](#api-surface) - - [Open Questions - Naming](#open-questions---naming) - [Handling Moves to Other Directories](#handling-moves-to-other-directories) - [(1) Moving to a Non-Local File System](#1-moving-to-a-non-local-file-system) - [(2) Moving out of the OPFS](#2-moving-out-of-the-opfs) - [(3) Moving to a Directory on the Local File System](#3-moving-to-a-directory-on-the-local-file-system) - - [Open Questions - Move](#open-questions---move) - - [Should behavior be different when moving a file vs moving a directory?](#should-behavior-be-different-when-moving-a-file-vs-moving-a-directory) + - [Open Questions](#open-questions) + - [What, if any, checks need to be run on same-file-system moves?](#what-if-any-checks-need-to-be-run-on-same-file-system-moves) - [What should happen if the operation cannot be completed successfully?](#what-should-happen-if-the-operation-cannot-be-completed-successfully) - [Implementation Notes](#implementation-notes) - [Alternatives Considered](#alternatives-considered) @@ -41,34 +40,19 @@ directories. This requires creating a new file/directory, copying over data process is slow, error prone (e.g. disk full), and can require re-uploading files in some cases (e.g. Google Drive files on Chrome OS). -We propose adding new `FileSystemHandle::rename()` and -`FileSystemHandle::move()` methods. `rename()` guarantees atomic moves of a file -or directory without the need to duplicate data. `move()` only offers atomic -moves of a file or directory if it is moved within the same file system, while -moves to non-local file systems will not be guaranteed to be atomic and may -involve duplicating data. See the [Open Questions](#open-questions---move). +We propose adding a new `FileSystemHandle::move()` method. `move()` will offer +atomic moves of a file or directory if it is moved within the same file system, +while moves to non-local file systems will not be guaranteed to be atomic and +may involve duplicating data. See the [Open Questions](#open-questions). # API Surface - -We propose adding a `rename()` method and a `move()` method with two variations. - -`rename()` will rename a file or directory. It is guaranteed to be atomic. - -The first `move()` variation allows a user to specify a `destination_directory` -to move to, which may or may not be on the same file system. The name of the -original file or directory is retained. This is not guaranteed to be atomic, -since the destination directory may be on a different file system and/or may be -subject to other checks (e.g. Safe Browsing in Chrome). - -The second `move()` variation allows a user to specify a `new_entry_name` as -well as a `destination_directory` to move to. The same (lack of) atomicity -guarantees apply here as with the first `move()` variation. +We propose adding an overloaded `move()` method with three variations. ``` interface FileSystemHandle { ... - Promise rename(USVString new_entry_name); + Promise move(USVString new_entry_name); Promise move(FileSystemDirectoryHandle destination_directory); Promise move(FileSystemDirectoryHandle destination_directory, USVString new_entry_name); @@ -76,12 +60,16 @@ interface FileSystemHandle { }; ``` -## Open Questions - Naming +`move(new_entry_name)` will rename a file or directory to `new_entry_name`. It +is guaranteed to be atomic and will not involve duplicating data. -- Should we prefer `move()` to move verbose alternatives, such as `moveTo()` or - `moveToDirectory()`? -- Should we bother guaranteeing (in the spec) atomicity to all handles `move()`d - on the same file system, or only for `rename()`d handles? +`move(destination_directory)` allows a user to specify a `destination_directory` +to move to, which may or may not be on the same file system. The name of the +original file or directory is retained. This is not guaranteed to be atomic, +since the destination directory may be on a different file system. + +`move(destination_directory, new_entry_name)` allows a user to rename an entry +and while moving it to a new directory. # Handling Moves to Other Directories @@ -100,35 +88,27 @@ Note that this approach is no worse than what is available currently. [#310](https://github.com/WICG/file-system-access/pull/310) exposes a strong use case for fast, atomic moves to other directories on the same file system. Files can be written efficiently in the Origin Private File System using an -`AccessHandle`, then efficiently moved to a directory of the user's choice. -However, writes using an `AccessHandle` are not subjected to Safe Browsing checks -in Chrome. Moving files out of the OPFS to a user's directory will require -running Safe Browsing checks on all moved files. +`AccessHandle`, then moved to a directory of the user's choice. However, writes +using an `AccessHandle` are not subjected to Safe Browsing checks in Chrome. +Moving files out of the OPFS to a user's directory will require running Safe +Browsing checks and adding the mark-of-the-web on all moved files. For example, moving a large directory across the OPFS -> file system boundary -means locking and performing checks (Safe Browsing in Chrome) for an unbounded -number of files. +means locking and performing checks for an unbounded number of files. ## (3) Moving to a Directory on the Local File System -This is the most straightforward case. Every `rename()` falls in this case. The -operation should be atomic and fast, since no Safe Browsing checks need to be -performed. However, providing these guarantees for `move()` in only this case -may be confusing. - -## Open Questions - Move +This is the most straightforward case. The operation should be atomic and fast. +`move(new_entry_name)` is guaranteed to fall in this case. -### Should behavior be different when moving a file vs. moving a directory? +## Open Questions -- For a file: - - Atomicity is only guaranteed in (2) and (3), though is likely true for (1). - - Speed is only guaranteed in (3). -- For a directory: - - Atomicity is only easily guaranteed in (3). Atomicity for (2) would be - complex (likely requiring locking each file as an unbounded number of files - are scanned) and may not be the best option. - - Speed is only guaranteed in (3), but the implications of this for (1) and - (2) is much greater than when only moving a file. +### What, if any, checks need to be run on same-file-system moves? +- The `new_entry_name` may rename the file with an unsafe extension, so Safe + Browsing checks may still need to be performed on same-file-system moves. +- When moving a directory, should all of the containing files be scanned? What + about adding the mark-of-the-web? + - This may require scanning and/or modifying an unbounded number of files. ### What should happen if the operation cannot be completed successfully? @@ -148,8 +128,9 @@ may be confusing. # Implementation Notes -- Write permission needs to have been granted to both the source and destination - directories. +- Write permission needs to have been granted to both: + - the source directory, and + - the destination directory or the destination file. - Invalid or unsafe `new_entry_name`s will result in a `Promise` rejection. - All entries contained within a directory which is moved no longer point to an existing file/directory. We currently have no plans to explicitly update or @@ -161,7 +142,7 @@ may be confusing. ## Only support "rename" functionality Pros: -- No need to handle (or spec) the case where moves are non-atomic +- No need to handle (or spec) cross-file-system moves - Simpler interface Cons: From 250cdbaf9ae9b241e744364471ff7e356e11f271 Mon Sep 17 00:00:00 2001 From: Austin Sullivan Date: Thu, 13 Jan 2022 18:15:46 +0000 Subject: [PATCH 8/8] consolidate rename and move --- index.bs | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/index.bs b/index.bs index f6d0d5e..94c05e2 100644 --- a/index.bs +++ b/index.bs @@ -262,7 +262,7 @@ interface FileSystemHandle { readonly attribute FileSystemHandleKind kind; readonly attribute USVString name; - Promise rename(USVString name); + Promise move(USVString name); Promise move(FileSystemDirectoryHandle parent); Promise move(FileSystemDirectoryHandle parent, USVString name); Promise remove(optional FileSystemRemoveOptions options = {}); @@ -320,34 +320,13 @@ and return {{FileSystemHandleKind/"directory"}} otherwise. The name attribute must return the [=entry/name=] of the associated [=FileSystemHandle/entry=]. -### The {{FileSystemHandle/rename()}} method ### {#api-filesystemhandle-rename} +### The {{FileSystemHandle/move()}} method ### {#api-filesystemhandle-move}
- : await |handle| . {{FileSystemHandle/rename()|rename}}({|new_entry_name|}) + : await |handle| . {{FileSystemHandle/move()|move}}({|new_entry_name|}) :: Attempts to atomically rename the entry represented by |handle| to |new_entry_name| in the underlying file system. - For files or directories with multiple hardlinks or symlinks, the entry - which is renamed is the entry corresponding to the path which was used - to obtain the handle. - - Attempting to rename a file or directory that does not exist or passing an - invalid name will result in a promise rejection. - -
- -
-The rename(|new_entry_name|) method, -when invoked, must run these steps: - -1. TODO - -
- - -### The {{FileSystemHandle/move()}} method ### {#api-filesystemhandle-move} - -
: await |handle| . {{FileSystemHandle/move()|move}}({|destination_directory|}) :: Attempts to move the entry represented by |handle| to |destination_directory|, while keeping its existing name.