@@ -332,6 +332,9 @@ interface FileSystemHandle {
332
332
readonly attribute USVString name;
333
333
334
334
Promise<boolean> isSameEntry(FileSystemHandle other);
335
+ Promise<undefined> move(USVString newEntryName);
336
+ Promise<undefined> move(FileSystemDirectoryHandle destinationDirectory);
337
+ Promise<undefined> move(FileSystemDirectoryHandle destinationDirectory, USVString newEntryName);
335
338
};
336
339
</xmp>
337
340
@@ -416,6 +419,204 @@ The <dfn method for=FileSystemHandle>isSameEntry(|other|)</dfn> method steps are
416
419
417
420
</div>
418
421
422
+ ### The {{FileSystemHandle/move(destinationDirectory, newEntryName)|move()}} method ### {#api-filesystemhandle-move}
423
+
424
+ <div class="note domintro">
425
+ : await |handle| . {{FileSystemHandle/move(newEntryName)|move}} ({ {{USVString}} : |newEntryName|})
426
+ :: Renames the [=file system entry=] [=locate an entry|locatable=] by
427
+ |handle|'s [=FileSystemHandle/locator=] to |newEntryName|.
428
+
429
+ : await |handle| . {{FileSystemHandle/move(destinationDirectory)|move}} ({ {{FileSystemDirectoryHandle}} : |destinationDirectory|})
430
+ :: Moves the [=file system entry=] [=locate an entry|locatable=] by
431
+ |handle|'s [=FileSystemHandle/locator=] to the [=directory entry=]
432
+ [=locate an entry|locatable=] by |destinationDirectory|'s
433
+ [=FileSystemHandle/locator=] , while keeping its existing name.
434
+
435
+ : await |handle| . {{FileSystemHandle/move(destinationDirectory, newEntryName)|move}} ({ {{FileSystemDirectoryHandle}} : |destinationDirectory|, {{USVString}} : |newEntryName|})
436
+ :: Moves the [=file system entry=] [=locate an entry|locatable=] by
437
+ |handle|'s [=FileSystemHandle/locator=] to the [=directory entry=]
438
+ [=locate an entry|locatable=] by |destinationDirectory|'s
439
+ [=FileSystemHandle/locator=] , as well as renaming to |newEntryName|.
440
+
441
+ If the [=file system locator/root|roots=] of the respective
442
+ [=FileSystemHandle/locator|locators=] of |destinationDirectory| and
443
+ |handle| are not the same, this operation may abort or fail non-atomically.
444
+ </div>
445
+
446
+ <div algorithm>
447
+ The <dfn method for=FileSystemHandle>move({{FileSystemDirectoryHandle}}: |destinationDirectory|)</dfn>
448
+ method steps are to [=FileSystemHandle/move=] |handle|
449
+ given |handle|'s {{FileSystemHandle/name}} and |destinationDirectory|.
450
+
451
+ </div>
452
+
453
+ <div algorithm>
454
+ The <dfn method for=FileSystemHandle>move({{USVString}}: |newEntryName|)</dfn>
455
+ method steps are to [=FileSystemHandle/move=] |handle|
456
+ given |newEntryName|.
457
+
458
+ </div>
459
+
460
+ <div algorithm>
461
+ The <dfn method for=FileSystemHandle>move({{FileSystemDirectoryHandle}}: |destinationDirectory|, {{USVString}}: |newEntryName|)</dfn>
462
+ method steps are to [=FileSystemHandle/move=] |handle|
463
+ given |newEntryName| and |destinationDirectory|.
464
+
465
+ </div>
466
+
467
+ <div algorithm>
468
+
469
+ To <dfn for=FileSystemHandle>move</dfn> a {{FileSystemHandle}} |handle| given
470
+ a {{USVString}} |newEntryName| and
471
+ an optional {{FileSystemDirectoryHandle}} |destinationDirectory|:
472
+
473
+ 1. Let |result| be [=a new promise=] .
474
+ 1. Let |locator| be |handle|'s [=FileSystemHandle/locator=] .
475
+ 1. Let |global| be |handle|'s [=relevant global object=] .
476
+ 1. Let |isInABucketFileSystem| be true if
477
+ |handle| [=FileSystemHandle/is in a bucket file system=] ;
478
+ otherwise false.
479
+ 1. [=Enqueue the following steps=] to the [=file system queue=] :
480
+ 1. If |newEntryName| is not a [=valid file name=] ,
481
+ [=queue a storage task=] with |global| to [=/reject=] |result|
482
+ with a {{TypeError}} and abort these steps.
483
+
484
+ 1. Let |entry| be the result of [=locating an entry=] given |locator|.
485
+ 1. Let |accessResult| be the result of running |entry|'s
486
+ [=file system entry/request access=] given "`readwrite`".
487
+ 1. If |accessResult|'s [=file system access result/permission state=]
488
+ is not "{{PermissionState/granted}} ", [=queue a storage task=] with
489
+ |global| to [=/reject=] |result| with a {{DOMException}} of
490
+ |accessResult|'s [=file system access result/error name=] and
491
+ abort these steps.
492
+
493
+ 1. If |destinationDirectory| was given:
494
+ 1. Let |destinationDirectoryLocator| be
495
+ |destinationDirectory|'s [=FileSystemHandle/locator=] .
496
+ 1. Let |destinationDirectoryEntry| be the result of [=locating an entry=]
497
+ given |destinationDirectoryLocator|.
498
+
499
+ 1. Let |destinationDirectoryAccessResult| be the result of running
500
+ |destinationDirectoryEntry|'s
501
+ [=file system entry/request access=] given "`readwrite`".
502
+ 1. If |destinationDirectoryAccessResult|'s
503
+ [=file system access result/permission state=]
504
+ is not "{{PermissionState/granted}} ", [=queue a storage task=] with
505
+ |global| to [=/reject=] |result| with a {{DOMException}} of
506
+ |accessResult|'s [=file system access result/error name=] and
507
+ abort these steps.
508
+
509
+ 1. If |destinationDirectoryLocator|'s [=file system locator/root=] is not
510
+ |locator|'s [=file system locator/root=] , [=queue a storage task=] with
511
+ |global| to [=/reject=] |result| with an
512
+ "{{NotSupportedError}} " {{DOMException}} and abort these steps.
513
+
514
+ Issue(114): Decide which moves across file systems, if any, should be
515
+ supported, or if this should be left up to individual user-agent
516
+ implementations.
517
+
518
+ 1. Let |destinationPath| be the result of [=list/clone|cloning=]
519
+ |destinationDirectoryLocator|'s [=file system locator/path=] and
520
+ [=list/append|appending=] |newEntryName|.
521
+ 1. Otherwise:
522
+ 1. Let |destinationPath| be the result of [=list/clone|cloning=]
523
+ |locator|'s [=file system locator/path=] , [=list/remove|removing=]
524
+ the last [=list/item=] , and [=list/append|appending=] |newEntryName|.
525
+
526
+ 1. Let |destinationLocator| be a [=/file system locator=] whose
527
+ [=file system locator/kind=] is |locator|'s [=file system locator/kind=] ,
528
+ [=file system locator/root=] is |locator|'s [=file system locator/root=] , and
529
+ [=file system locator/path=] is |destinationPath|.
530
+ 1. Let |destinationEntry| be the result of [=locating an entry=]
531
+ given |destinationLocator|.
532
+
533
+ 1. If |destinationDirectory| was not given:
534
+ 1. Let |destinationAccessResult| be the result of running
535
+ |destinationEntry|'s [=file system entry/request access=]
536
+ given "`readwrite`".
537
+
538
+ Issue(101): Make sure this still makes sense once access check algorithms
539
+ are no longer associated with an entry.
540
+ 1. Otherwise:
541
+ 1. Let |destinationAccessResult| be |destinationDirectoryAccessResult|.
542
+
543
+ 1. Let |isTheRootOfABucketFileSystem| be true if
544
+ |isInABucketFileSystem| is true and
545
+ |entry|'s [=file system entry/parent=] is `null`;
546
+ otherwise false.
547
+ 1. If |isTheRootOfABucketFileSystem| is true,
548
+ [=queue a storage task=] with |global| to [=/reject=] |result| with a
549
+ "{{InvalidModificationError}} " {{DOMException}} and abort these steps.
550
+
551
+ Issue: Do not allow |entry| to be moved if it is a
552
+ <a href=https://wicg.github.io/file-system-access/#wellknowndirectory-too-sensitive-or-dangerous>sensitive directory</a>
553
+
554
+ 1. If |destinationAccessResult|'s
555
+ [=file system access result/permission state=] is not
556
+ "{{PermissionState/granted}} ":
557
+ 1. If |destinationEntry| is not `null`, [=queue a storage task=] with
558
+ |global| to [=/reject=] |result| with a {{DOMException}} of
559
+ |destinationAccessResult|'s [=file system access result/error name=] and
560
+ abort these steps
561
+
562
+ Note: This prevents overwriting an existing file or directory which the
563
+ site does not have access to.
564
+
565
+ 1. Let |settingsGlobal| be |handle|'s [=relevant settings object=]' s
566
+ [=environment settings object/global object=] .
567
+ 1. If |settingsGlobal| does not have [=transient activation=] ,
568
+ [=queue a storage task=] with |global| to [=/reject=] |result|
569
+ with a "{{NotAllowedError}} " {{DOMException}} .
570
+
571
+ 1. If |entry| is `null`, [=queue a storage task=] with |global| to [=/reject=]
572
+ |result| with a "{{NotFoundError}} " {{DOMException}} and abort these steps.
573
+ 1. If |destinationDirectory| was given and |destinationDirectoryEntry|
574
+ is `null`, [=queue a storage task=] with |global| to [=/reject=] |result|
575
+ with a "{{NotFoundError}} " {{DOMException}} and abort these steps.
576
+
577
+ 1. Let |lockResult| be the result of [=file entry/lock/take|taking a lock=]
578
+ with "`exclusive`" on |entry|.
579
+
580
+ Issue(137): Support locking directory entries.
581
+
582
+ 1. If |destinationEntry| is not `null`:
583
+ 1. Let |destinationLockResult| be the result of
584
+ [=file entry/lock/take|taking a lock=] with "`exclusive`"
585
+ on |destinationEntry|.
586
+ 1. Otherwise:
587
+ 1. Let |destinationLockResult| be "`not taken`".
588
+
589
+ Issue: Consider whether it should be possible to lock a
590
+ [=/file system entry=] which does not (yet) exist.
591
+
592
+ 1. [=Queue a storage task=] with |global| to run these steps:
593
+ 1. If |lockResult| is "`failure`", [=/reject=] |result| with a
594
+ "{{NoModificationAllowedError}} " {{DOMException}} and abort these steps.
595
+ 1. If |destinationLockResult| is "`failure`", [=/reject=] |result| with a
596
+ "{{NoModificationAllowedError}} " {{DOMException}} and abort these steps.
597
+
598
+ 1. If |destinationDirectory| was given:
599
+ 1. If |entry|'s [=file system entry/parent=] is not `null`,
600
+ [=set/remove=] |entry| from |entry|'s [=file system entry/parent=]' s
601
+ [=directory entry/children=] .
602
+ 1. [=set/Append=] |entry| to |destinationDirectoryEntry|'s
603
+ [=directory entry/children=] .
604
+
605
+ 1. If |entry| is a [=file entry=] and |isInABucketFileSystem| is false,
606
+ run [=implementation-defined=] malware scans and safe browsing checks.
607
+ If these checks fail, [=/reject=] |result| with an
608
+ "{{AbortError}} " {{DOMException}} and abort these steps.
609
+
610
+ 1. Attempt to move |entry| to |destinationEntry| in the underlying file
611
+ system. If that throws an exception, [=/reject=] |result| with that
612
+ exception and abort these steps.
613
+
614
+ 1. [=/Resolve=] |result| with `undefined`.
615
+
616
+ 1. Return |result|.
617
+
618
+ </div>
619
+
419
620
## The {{FileSystemFileHandle}} interface ## {#api-filesystemfilehandle}
420
621
421
622
<xmp class=idl>
0 commit comments