Skip to content

Commit 46e0062

Browse files
a-sullychromium-wpt-export-bot
authored andcommitted
Add FileSystemHandle::move() method
Currently, it is not possible to move or rename a file or directory without creating a new file/directory, copying over data (recursively, in the case of a directory), and removing the original. This CL allows for the atomic moving of a file or directory on the local file system without needing to duplicate data. Moves to non-local file systems will are not guaranteed to be atomic and will involve duplicating data. PR: WICG/file-system-access#317 Bug: 1140805 Change-Id: I774ed1d9616249b6ecc80783db48a7bfee915aab
1 parent 6746e79 commit 46e0062

File tree

3 files changed

+340
-0
lines changed

3 files changed

+340
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!doctype html>
2+
<meta charset=utf-8>
3+
4+
<script src="/resources/testharness.js"></script>
5+
<script src="/resources/testharnessreport.js"></script>
6+
<script src="/resources/testdriver.js"></script>
7+
<script src="/resources/testdriver-vendor.js"></script>
8+
<script src="resources/test-helpers.js"></script>
9+
<script src="resources/local-fs-test-helpers.js"></script>
10+
<script src="script-tests/FileSystemBaseHandle-move.js"></script>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// META: script=resources/test-helpers.js
2+
// META: script=resources/sandboxed-fs-test-helpers.js
3+
// META: script=script-tests/FileSystemBaseHandle-move.js
Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
// META: script=resources/test-helpers.js
2+
3+
'use strict';
4+
5+
directory_test(async (t, root) => {
6+
const handle = await createFileWithContents(t, 'file-before', 'foo', root);
7+
await handle.move(root, 'file-after');
8+
9+
assert_array_equals(await getSortedDirectoryEntries(root), ['file-after']);
10+
assert_equals(await getFileContents(handle), 'foo');
11+
assert_equals(await getFileSize(handle), 3);
12+
}, 'move(dir, name) to rename a file');
13+
14+
directory_test(async (t, root) => {
15+
const handle = await createFileWithContents(t, 'file-before', 'foo', root);
16+
await handle.move(root, 'file-before');
17+
18+
assert_array_equals(await getSortedDirectoryEntries(root), ['file-before']);
19+
assert_equals(await getFileContents(handle), 'foo');
20+
assert_equals(await getFileSize(handle), 3);
21+
}, 'move(dir, name) to rename a file the same name');
22+
23+
directory_test(async (t, root) => {
24+
const dir = await root.getDirectoryHandle('dir-before', {create: true});
25+
await dir.move(root, 'dir-after');
26+
27+
assert_array_equals(await getSortedDirectoryEntries(root), ['dir-after/']);
28+
assert_array_equals(await getSortedDirectoryEntries(dir), []);
29+
}, 'move(dir, name) to rename an empty directory');
30+
31+
directory_test(async (t, root) => {
32+
const dir = await root.getDirectoryHandle('dir-before', {create: true});
33+
await createFileWithContents(t, 'file-in-dir', 'abc', dir);
34+
await dir.move(root, 'dir-after');
35+
36+
assert_array_equals(await getSortedDirectoryEntries(root), ['dir-after/']);
37+
assert_array_equals(await getSortedDirectoryEntries(dir), ['file-in-dir']);
38+
}, 'move(dir, name) to rename a non-empty directory');
39+
40+
directory_test(async (t, root) => {
41+
const dir_src = await root.getDirectoryHandle('dir-src', {create: true});
42+
const dir_dest = await root.getDirectoryHandle('dir-dest', {create: true});
43+
const file = await createFileWithContents(t, 'file', 'abc', dir_src);
44+
await file.move(dir_dest);
45+
46+
assert_array_equals(
47+
await getSortedDirectoryEntries(root), ['dir-dest/', 'dir-src/']);
48+
assert_array_equals(await getSortedDirectoryEntries(dir_src), []);
49+
assert_array_equals(await getSortedDirectoryEntries(dir_dest), ['file']);
50+
assert_equals(await getFileContents(file), 'abc');
51+
assert_equals(await getFileSize(file), 3);
52+
}, 'move(dir) to move a file to a new directory');
53+
54+
directory_test(async (t, root) => {
55+
const dir_src = await root.getDirectoryHandle('dir-src', {create: true});
56+
const dir_dest = await root.getDirectoryHandle('dir-dest', {create: true});
57+
const file = await createFileWithContents(t, 'file', 'abc', dir_src);
58+
await file.move(dir_dest, null);
59+
60+
assert_array_equals(
61+
await getSortedDirectoryEntries(root), ['dir-dest/', 'dir-src/']);
62+
assert_array_equals(await getSortedDirectoryEntries(dir_src), []);
63+
assert_array_equals(await getSortedDirectoryEntries(dir_dest), ['file']);
64+
assert_equals(await getFileContents(file), 'abc');
65+
assert_equals(await getFileSize(file), 3);
66+
}, 'move(dir, null) to move a file to a new directory');
67+
68+
directory_test(async (t, root) => {
69+
const dir_src = await root.getDirectoryHandle('dir-src', {create: true});
70+
const dir_dest = await root.getDirectoryHandle('dir-dest', {create: true});
71+
const file = await createFileWithContents(t, 'file', 'abc', dir_src);
72+
await file.move(dir_dest, '');
73+
74+
assert_array_equals(
75+
await getSortedDirectoryEntries(root), ['dir-dest/', 'dir-src/']);
76+
assert_array_equals(await getSortedDirectoryEntries(dir_src), []);
77+
assert_array_equals(await getSortedDirectoryEntries(dir_dest), ['file']);
78+
assert_equals(await getFileContents(file), 'abc');
79+
assert_equals(await getFileSize(file), 3);
80+
}, 'move(dir, "") to move a file to a new directory');
81+
82+
directory_test(async (t, root) => {
83+
const dir_src = await root.getDirectoryHandle('dir-src', {create: true});
84+
const dir_dest = await root.getDirectoryHandle('dir-dest', {create: true});
85+
const file =
86+
await createFileWithContents(t, 'file-in-dir-src', 'abc', dir_src);
87+
await file.move(dir_dest, 'file-in-dir-dest');
88+
89+
assert_array_equals(
90+
await getSortedDirectoryEntries(root), ['dir-dest/', 'dir-src/']);
91+
assert_array_equals(await getSortedDirectoryEntries(dir_src), []);
92+
assert_array_equals(
93+
await getSortedDirectoryEntries(dir_dest), ['file-in-dir-dest']);
94+
assert_equals(await getFileContents(file), 'abc');
95+
assert_equals(await getFileSize(file), 3);
96+
}, 'move(dir, name) to move a file to a new directory');
97+
98+
directory_test(async (t, root) => {
99+
const dir_src = await root.getDirectoryHandle('dir-src', {create: true});
100+
const dir_dest = await root.getDirectoryHandle('dir-dest', {create: true});
101+
const dir_in_dir =
102+
await dir_src.getDirectoryHandle('dir-in-dir', {create: true});
103+
await dir_in_dir.move(dir_dest);
104+
105+
assert_array_equals(
106+
await getSortedDirectoryEntries(root), ['dir-dest/', 'dir-src/']);
107+
assert_array_equals(await getSortedDirectoryEntries(dir_src), []);
108+
assert_array_equals(
109+
await getSortedDirectoryEntries(dir_dest), ['dir-in-dir/']);
110+
assert_array_equals(await getSortedDirectoryEntries(dir_in_dir), []);
111+
}, 'move(dir) to move an empty directory to a new directory');
112+
113+
directory_test(async (t, root) => {
114+
const dir_src = await root.getDirectoryHandle('dir-src', {create: true});
115+
const dir_dest = await root.getDirectoryHandle('dir-dest', {create: true});
116+
const dir_in_dir =
117+
await dir_src.getDirectoryHandle('dir-in-dir', {create: true});
118+
await dir_in_dir.move(dir_dest, null);
119+
120+
assert_array_equals(
121+
await getSortedDirectoryEntries(root), ['dir-dest/', 'dir-src/']);
122+
assert_array_equals(await getSortedDirectoryEntries(dir_src), []);
123+
assert_array_equals(
124+
await getSortedDirectoryEntries(dir_dest), ['dir-in-dir/']);
125+
assert_array_equals(await getSortedDirectoryEntries(dir_in_dir), []);
126+
}, 'move(dir, null) to move an empty directory to a new directory');
127+
128+
directory_test(async (t, root) => {
129+
const dir_src = await root.getDirectoryHandle('dir-src', {create: true});
130+
const dir_dest = await root.getDirectoryHandle('dir-dest', {create: true});
131+
const dir_in_dir =
132+
await dir_src.getDirectoryHandle('dir-in-dir', {create: true});
133+
await dir_in_dir.move(dir_dest, 'dir-in-dir');
134+
135+
assert_array_equals(
136+
await getSortedDirectoryEntries(root), ['dir-dest/', 'dir-src/']);
137+
assert_array_equals(await getSortedDirectoryEntries(dir_src), []);
138+
assert_array_equals(
139+
await getSortedDirectoryEntries(dir_dest), ['dir-in-dir/']);
140+
assert_array_equals(await getSortedDirectoryEntries(dir_in_dir), []);
141+
}, 'move(dir, name) to move an empty directory to a new directory');
142+
143+
directory_test(async (t, root) => {
144+
const dir_src = await root.getDirectoryHandle('dir-src', {create: true});
145+
const dir_dest = await root.getDirectoryHandle('dir-dest', {create: true});
146+
const dir_in_dir =
147+
await dir_src.getDirectoryHandle('dir-in-dir', {create: true});
148+
const file =
149+
await createFileWithContents(t, 'file-in-dir', 'abc', dir_in_dir);
150+
await dir_in_dir.move(dir_dest, null);
151+
152+
assert_array_equals(
153+
await getSortedDirectoryEntries(root), ['dir-dest/', 'dir-src/']);
154+
assert_array_equals(await getSortedDirectoryEntries(dir_src), []);
155+
assert_array_equals(
156+
await getSortedDirectoryEntries(dir_dest), ['dir-in-dir/']);
157+
assert_array_equals(
158+
await getSortedDirectoryEntries(dir_in_dir), ['file-in-dir']);
159+
// `file` should be invalidated after moving directories.
160+
await promise_rejects_dom(t, 'NotFoundError', getFileContents(file));
161+
}, 'move(dir, null) to move a non-empty directory to a new directory');
162+
163+
directory_test(async (t, root) => {
164+
const dir_src = await root.getDirectoryHandle('dir-src', {create: true});
165+
const dir_dest = await root.getDirectoryHandle('dir-dest', {create: true});
166+
const dir_in_dir =
167+
await dir_src.getDirectoryHandle('dir-in-dir', {create: true});
168+
const file =
169+
await createFileWithContents(t, 'file-in-dir', 'abc', dir_in_dir);
170+
await dir_in_dir.move(dir_dest, 'dir-in-dir');
171+
172+
assert_array_equals(
173+
await getSortedDirectoryEntries(root), ['dir-dest/', 'dir-src/']);
174+
assert_array_equals(await getSortedDirectoryEntries(dir_src), []);
175+
assert_array_equals(
176+
await getSortedDirectoryEntries(dir_dest), ['dir-in-dir/']);
177+
assert_array_equals(
178+
await getSortedDirectoryEntries(dir_in_dir), ['file-in-dir']);
179+
// `file` should be invalidated after moving directories.
180+
await promise_rejects_dom(t, 'NotFoundError', getFileContents(file));
181+
}, 'move(dir, name) to move a non-empty directory to a new directory');
182+
183+
directory_test(async (t, root) => {
184+
const dir1 = await root.getDirectoryHandle('dir1', {create: true});
185+
const dir2 = await root.getDirectoryHandle('dir2', {create: true});
186+
const handle = await createFileWithContents(t, 'file', 'foo', root);
187+
188+
await handle.move(dir1);
189+
assert_array_equals(
190+
await getSortedDirectoryEntries(root), ['dir1/', 'dir2/']);
191+
assert_array_equals(await getSortedDirectoryEntries(dir1), ['file']);
192+
assert_array_equals(await getSortedDirectoryEntries(dir2), []);
193+
assert_equals(await getFileContents(handle), 'foo');
194+
195+
await handle.move(dir2);
196+
assert_array_equals(
197+
await getSortedDirectoryEntries(root), ['dir1/', 'dir2/']);
198+
assert_array_equals(await getSortedDirectoryEntries(dir1), []);
199+
assert_array_equals(await getSortedDirectoryEntries(dir2), ['file']);
200+
assert_equals(await getFileContents(handle), 'foo');
201+
202+
await handle.move(root);
203+
assert_array_equals(
204+
await getSortedDirectoryEntries(root), ['dir1/', 'dir2/', 'file']);
205+
assert_array_equals(await getSortedDirectoryEntries(dir1), []);
206+
assert_array_equals(await getSortedDirectoryEntries(dir2), []);
207+
assert_equals(await getFileContents(handle), 'foo');
208+
}, 'move(dir) can be called multiple times');
209+
210+
directory_test(async (t, root) => {
211+
const dir1 = await root.getDirectoryHandle('dir1', {create: true});
212+
const dir2 = await root.getDirectoryHandle('dir2', {create: true});
213+
const handle = await createFileWithContents(t, 'file', 'foo', root);
214+
215+
await handle.move(dir1, null);
216+
assert_array_equals(
217+
await getSortedDirectoryEntries(root), ['dir1/', 'dir2/']);
218+
assert_array_equals(await getSortedDirectoryEntries(dir1), ['file']);
219+
assert_array_equals(await getSortedDirectoryEntries(dir2), []);
220+
assert_equals(await getFileContents(handle), 'foo');
221+
222+
await handle.move(dir2, null);
223+
assert_array_equals(
224+
await getSortedDirectoryEntries(root), ['dir1/', 'dir2/']);
225+
assert_array_equals(await getSortedDirectoryEntries(dir1), []);
226+
assert_array_equals(await getSortedDirectoryEntries(dir2), ['file']);
227+
assert_equals(await getFileContents(handle), 'foo');
228+
229+
await handle.move(root, null);
230+
assert_array_equals(
231+
await getSortedDirectoryEntries(root), ['dir1/', 'dir2/', 'file']);
232+
assert_array_equals(await getSortedDirectoryEntries(dir1), []);
233+
assert_array_equals(await getSortedDirectoryEntries(dir2), []);
234+
assert_equals(await getFileContents(handle), 'foo');
235+
}, 'move(dir, null) can be called multiple times');
236+
237+
directory_test(async (t, root) => {
238+
const dir1 = await root.getDirectoryHandle('dir1', {create: true});
239+
const dir2 = await root.getDirectoryHandle('dir2', {create: true});
240+
const handle = await createFileWithContents(t, 'file', 'foo', root);
241+
242+
await handle.move(dir1, 'file-1');
243+
assert_array_equals(
244+
await getSortedDirectoryEntries(root), ['dir1/', 'dir2/']);
245+
assert_array_equals(await getSortedDirectoryEntries(dir1), ['file-1']);
246+
assert_array_equals(await getSortedDirectoryEntries(dir2), []);
247+
assert_equals(await getFileContents(handle), 'foo');
248+
249+
await handle.move(dir2, 'file-2');
250+
assert_array_equals(
251+
await getSortedDirectoryEntries(root), ['dir1/', 'dir2/']);
252+
assert_array_equals(await getSortedDirectoryEntries(dir1), []);
253+
assert_array_equals(await getSortedDirectoryEntries(dir2), ['file-2']);
254+
assert_equals(await getFileContents(handle), 'foo');
255+
256+
await handle.move(root, 'file-3');
257+
assert_array_equals(
258+
await getSortedDirectoryEntries(root), ['dir1/', 'dir2/', 'file-3']);
259+
assert_array_equals(await getSortedDirectoryEntries(dir1), []);
260+
assert_array_equals(await getSortedDirectoryEntries(dir2), []);
261+
assert_equals(await getFileContents(handle), 'foo');
262+
}, 'move(dir, name) can be called multiple times');
263+
264+
directory_test(async (t, root) => {
265+
const handle = await createFileWithContents(t, 'file-before', 'foo', root);
266+
await promise_rejects_js(
267+
t, TypeError, handle.move(root, '#$23423@352^*3243'));
268+
269+
assert_array_equals(await getSortedDirectoryEntries(root), ['file-before']);
270+
assert_equals(await getFileContents(handle), 'foo');
271+
assert_equals(await getFileSize(handle), 3);
272+
}, 'move(dir, name) with a name with invalid characters should fail');
273+
274+
directory_test(async (t, root) => {
275+
const dir = await root.getDirectoryHandle('dir', {create: true});
276+
await promise_rejects_dom(
277+
t, 'InvalidModificationError', dir.move(dir));
278+
279+
assert_array_equals(await getSortedDirectoryEntries(root), ['dir/']);
280+
assert_array_equals(await getSortedDirectoryEntries(dir), []);
281+
}, 'move(dir, name) to move a directory within itself fails');
282+
283+
directory_test(async (t, root) => {
284+
const dir = await root.getDirectoryHandle('dir', {create: true});
285+
await promise_rejects_dom(
286+
t, 'InvalidModificationError', dir.move(dir, 'dir-fail'));
287+
288+
assert_array_equals(await getSortedDirectoryEntries(root), ['dir/']);
289+
assert_array_equals(await getSortedDirectoryEntries(dir), []);
290+
}, 'move(dir, name) to move a directory within itself fails');
291+
292+
directory_test(async (t, root) => {
293+
const dir = await root.getDirectoryHandle('dir', {create: true});
294+
await promise_rejects_dom(
295+
t, 'InvalidModificationError', dir.move(dir, 'dir-fail'));
296+
297+
assert_array_equals(await getSortedDirectoryEntries(root), ['dir/']);
298+
assert_array_equals(await getSortedDirectoryEntries(dir), []);
299+
}, 'move(dir, name) to move a directory within itself and rename fails');
300+
301+
directory_test(async (t, root) => {
302+
const parent_dir =
303+
await root.getDirectoryHandle('parent-dir', {create: true});
304+
const child_dir =
305+
await parent_dir.getDirectoryHandle('child-dir', {create: true});
306+
await promise_rejects_dom(
307+
t, 'InvalidModificationError', parent_dir.move(child_dir));
308+
309+
assert_array_equals(await getSortedDirectoryEntries(root), ['parent-dir/']);
310+
assert_array_equals(
311+
await getSortedDirectoryEntries(parent_dir), ['child-dir/']);
312+
assert_array_equals(await getSortedDirectoryEntries(child_dir), []);
313+
}, 'move(dir) to move a directory within a descendent fails');
314+
315+
directory_test(async (t, root) => {
316+
const parent_dir =
317+
await root.getDirectoryHandle('parent-dir', {create: true});
318+
const child_dir =
319+
await parent_dir.getDirectoryHandle('child-dir', {create: true});
320+
await promise_rejects_dom(
321+
t, 'InvalidModificationError', parent_dir.move(child_dir, 'dir'));
322+
323+
assert_array_equals(await getSortedDirectoryEntries(root), ['parent-dir/']);
324+
assert_array_equals(
325+
await getSortedDirectoryEntries(parent_dir), ['child-dir/']);
326+
assert_array_equals(await getSortedDirectoryEntries(child_dir), []);
327+
}, 'move(dir, name) to move a directory within a descendent fails');

0 commit comments

Comments
 (0)