Skip to content

Commit d98b0c9

Browse files
authored
Add explainer for FileSystemHandle.remove()
2 parents 274a106 + 9eaccd7 commit d98b0c9

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

explainers/Remove.md

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# The FileSystemHandle.remove() method
2+
3+
# Authors:
4+
5+
* Austin Sullivan ([email protected])
6+
7+
## Participate
8+
9+
* [Issue tracker](https://github.com/whatwg/fs/issues)
10+
11+
## Introduction
12+
13+
This explainer proposes a "remove self" method for a `FileSystemHandle`.
14+
15+
Currently, it is not possible to remove a file or directory given its handle.
16+
You must obtain the handle of the parent directory, which there is no
17+
straightforward way to do and may not be possible in some cases, and call
18+
`FileSystemDirectoryHandle.removeEntry()`.
19+
20+
## Goals
21+
22+
* Allow removal of any entry a site has write access to
23+
* Avoid surprises by matching the behavior and API shape of
24+
`FileSystemDirectoryHandle.removeEntry()`
25+
26+
## Use Cases
27+
28+
### Removing a handle selected via showSaveFilePicker()
29+
30+
It's quite common for a site to obtain a file handle from
31+
`showSaveFilePicker()`, but then decide not to save after all, and want
32+
to delete the file.
33+
34+
Currently, this requires obtaining write access to the parent directory and
35+
calling `removeEntry()` on the file. However, files selected from
36+
`showSaveFilePicker()` are often in the Downloads/ or Documents/ folders, which
37+
we do not allow the site to acquire directory handles to.
38+
39+
```javascript
40+
// Acquire a file handle to save some data
41+
const handle = await window.showSaveFilePicker();
42+
// Write some data to the file
43+
const writable = await handle.createWritable();
44+
await writable.write(contents);
45+
46+
// ... some time later ...
47+
48+
// Nevermind - remove the file
49+
await handle.remove();
50+
```
51+
52+
### Allow applications to clear data not managed by the browser
53+
54+
One use case of the File System Access API is for a site to show a directory
55+
picker to a location where the user would like its application data stored.
56+
Unlike other storage mechanisms provided by the browser, files on the user's
57+
machine are not tracked by the browser's quota system (meaning it can't be
58+
evicted), nor will it be cleared when the user clears site data.
59+
60+
The `id` and `startIn` fields can be specified to suggest the directory in
61+
which the file picker opens. See
62+
[details in the spec](https://wicg.github.io/file-system-access/#api-filepickeroptions-starting-directory).
63+
64+
There some significant downsides to this approach, most notably the inability
65+
to use the `FileSystemSyncAccessHandle` interface for non-OPFS files.
66+
Additionally, if a well-behaving application wants to clear all its associated
67+
data, it currently cannot remove the root of the directory.
68+
69+
```javascript
70+
// Application asks "Where shall I save my data?"
71+
// User selects a new directory: /user/blah/AwesomeAppData/
72+
const dirHandle = await window.showDirectoryPicker();
73+
74+
// ... some time later ...
75+
76+
// User asks "Please clear my data"
77+
78+
// Before: /user/blah/AwesomeAppData/ can be emptied, but the application
79+
// _cannot_ remove the directory itself
80+
await dirHandle.removeEntry({ recursive: true });
81+
// After: /user/blah/AwesomeAppData/ is removed
82+
await dirHandle.remove({ recursive: true });
83+
```
84+
85+
### Improve ergonomics of the API
86+
87+
Currently, removing an entry requires not only write access to the parent
88+
directory, but the parent directory itself. This can be a hassle, especially
89+
because the API [does not have an easy way to get the parent](https://github.com/whatwg/fs/issues/38)
90+
of a handle.
91+
92+
```javascript
93+
// Given `handle` that I want to remove…
94+
95+
// Before: Somehow acquire the parent directory. Hopefully you've kept around
96+
// its root. You'll need to:
97+
// - resolve the handle to the root to get the intermediate path components
98+
const pathComponents = await root.resolve(handle);
99+
// - create the directory handle for each intermediate directory
100+
let parent = root;
101+
for (const component of pathComponents)
102+
parent = await parent.GetDirectoryHandle(component);
103+
// - finally, remove based on the handle's name
104+
await parent.removeEntry(handle.name);
105+
106+
// After: just remove the handle
107+
await handle.remove();
108+
```
109+
110+
## Security Considerations
111+
112+
* Removing a file or directory requires write access to the associated entry.
113+
For example, files selected via `showOpenFilePicker()` are read-only by
114+
default and will not be removable unless the user explicitly grants write
115+
access to the entry
116+
* Recursive directory removal is currently possible via the `removeEntry()`
117+
method of the `FileSystemDirectoryHandle`
118+
* This method allows for removal of the root entry selected from the file
119+
picker, but since applications are
120+
[not able to obtain a handle to sensitive directories](https://github.com/WICG/file-system-access/blob/main/security-privacy-questionnaire.md#26-what-information-from-the-underlying-platform-eg-configuration-data-is-exposed-by-this-specification-to-an-origin)
121+
in the first place, this root entry is guaranteed not to be considered
122+
sensitive
123+
124+
## Stakeholder Feedback / Opposition
125+
126+
* Developers: [Positive](https://github.com/WICG/file-system-access/issues/214)
127+
* Gecko: [Positive](https://github.com/WICG/file-system-access/pull/283#issuecomment-1036085470)
128+
* WebKit: No signals

0 commit comments

Comments
 (0)