Implement FileSystemDirectoryEntry.getDirectory()
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 2 Sep 2017 21:31:49 +0000 (21:31 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 2 Sep 2017 21:31:49 +0000 (21:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=176168
<rdar://problem/34187787>

Reviewed by Darin Adler.

Source/WebCore:

Implement FileSystemDirectoryEntry.getDirectory() as per:
- https://wicg.github.io/entries-api/#dom-filesystemdirectoryentry-getdirectory

Test: editing/pasteboard/datatransfer-items-drop-getDirectory.html

* Modules/entriesapi/DOMFileSystem.cpp:
(WebCore::isValidVirtualPath):
(WebCore::resolveRelativeVirtualPath):
(WebCore::DOMFileSystem::getEntry):
* Modules/entriesapi/DOMFileSystem.h:
* Modules/entriesapi/FileSystemDirectoryEntry.cpp:
(WebCore::FileSystemDirectoryEntry::getEntry):
(WebCore::FileSystemDirectoryEntry::getFile):
(WebCore::FileSystemDirectoryEntry::getDirectory):
* Modules/entriesapi/FileSystemDirectoryEntry.h:

LayoutTests:

Add layout test coverage.

* editing/pasteboard/datatransfer-items-drop-getDirectory-expected.txt: Added.
* editing/pasteboard/datatransfer-items-drop-getDirectory.html: Added.
* platform/wk2/TestExpectations:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@221540 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/editing/pasteboard/datatransfer-items-drop-getDirectory-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/datatransfer-items-drop-getDirectory.html [new file with mode: 0644]
LayoutTests/platform/wk2/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/Modules/entriesapi/DOMFileSystem.cpp
Source/WebCore/Modules/entriesapi/DOMFileSystem.h
Source/WebCore/Modules/entriesapi/FileSystemDirectoryEntry.cpp
Source/WebCore/Modules/entriesapi/FileSystemDirectoryEntry.h

index 4118ffc..34cabb4 100644 (file)
@@ -1,3 +1,17 @@
+2017-09-02  Chris Dumez  <cdumez@apple.com>
+
+        Implement FileSystemDirectoryEntry.getDirectory()
+        https://bugs.webkit.org/show_bug.cgi?id=176168
+        <rdar://problem/34187787>
+
+        Reviewed by Darin Adler.
+
+        Add layout test coverage.
+
+        * editing/pasteboard/datatransfer-items-drop-getDirectory-expected.txt: Added.
+        * editing/pasteboard/datatransfer-items-drop-getDirectory.html: Added.
+        * platform/wk2/TestExpectations:
+
 2017-09-01  Sam Weinig  <sam@webkit.org>
 
         DOMMatrix and DOMMatrixReadOnly should be available in workers
diff --git a/LayoutTests/editing/pasteboard/datatransfer-items-drop-getDirectory-expected.txt b/LayoutTests/editing/pasteboard/datatransfer-items-drop-getDirectory-expected.txt
new file mode 100644 (file)
index 0000000..e21efae
--- /dev/null
@@ -0,0 +1,50 @@
+Basic test coverage for fileSystemDirectoryEntry.getDirectory()
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS dataTransfer.items.length is 1
+* Error case: create flag is set to true
+PASS ex.name is "SecurityError"
+* Regular case: getDirectory('subfolder1')
+PASS subfolder1Entry.name is "subfolder1"
+PASS subfolder1Entry.fullPath is "/testFiles/subfolder1"
+PASS subfolder1Entry.isDirectory is true
+* Error case: calling getDirectory() with path to file
+PASS ex.name is "TypeMismatchError"
+* Error case: calling getDirectory() with path containing backslash
+PASS ex.name is "TypeMismatchError"
+* Error case: calling getDirectory() with path which does not exist
+PASS ex.name is "NotFoundError"
+* Error case: calling getDirectory() with path containing a NUL character
+PASS ex.name is "TypeMismatchError"
+* Regular case: calling getDirectory() with path to root
+PASS rootEntry.name is ""
+PASS rootEntry.fullPath is "/"
+PASS rootEntry.isDirectory is true
+* Regular case: calling getDirectory() with absolute path
+PASS subfolder2aEntry.name is "subfolder2a"
+PASS subfolder2aEntry.fullPath is "/testFiles/subfolder2/subfolder2a"
+PASS subfolder2aEntry.isDirectory is true
+* Edge case: calling getDirectory() with relative path containing '.' and '..'
+PASS subfolder2aEntry.name is "subfolder2a"
+PASS subfolder2aEntry.fullPath is "/testFiles/subfolder2/subfolder2a"
+PASS subfolder2aEntry.isDirectory is true
+* Edge case: calling getDirectory() with relative path containing too many '..'
+PASS subfolder1Entry.name is "subfolder1"
+PASS subfolder1Entry.fullPath is "/testFiles/subfolder1"
+PASS subfolder1Entry.isDirectory is true
+* Edge case: calling getDirectory() with absolute path containing '..'
+PASS subfolder1Entry.name is "subfolder1"
+PASS subfolder1Entry.fullPath is "/testFiles/subfolder1"
+PASS subfolder1Entry.isDirectory is true
+* Edge case: calling getDirectory() with absolute path containing too many '..'
+PASS subfolder1Entry.name is "subfolder1"
+PASS subfolder1Entry.fullPath is "/testFiles/subfolder1"
+PASS subfolder1Entry.isDirectory is true
+* Error case: calling getDirectory() with empty path
+PASS ex.name is "TypeMismatchError"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/editing/pasteboard/datatransfer-items-drop-getDirectory.html b/LayoutTests/editing/pasteboard/datatransfer-items-drop-getDirectory.html
new file mode 100644 (file)
index 0000000..fde7d0c
--- /dev/null
@@ -0,0 +1,197 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+<script src="../editing.js"></script>
+</head>
+<body>
+<div id="dropzone" style="width: 200px; height: 200px; background-color: grey;"></div>
+<script>
+description("Basic test coverage for fileSystemDirectoryEntry.getDirectory()");
+jsTestIsAsync = true;
+
+function getDirectoryAsPromise(directory, path, flags)
+{
+    return new Promise((resolve, reject) => {
+        directory.getDirectory(path, flags, resolve, reject);
+    });
+}
+
+function test1() {
+    debug("* Error case: create flag is set to true");
+    return getDirectoryAsPromise(directoryEntry, "subfolder1", { create: true }).then(entry => {
+        testFailed("Should fail when create flag is true");
+    }, e => {
+        ex = e;
+        shouldBeEqualToString("ex.name", "SecurityError");
+    });
+}
+
+function test2() {
+    debug("* Regular case: getDirectory('subfolder1')");
+    return getDirectoryAsPromise(directoryEntry, "subfolder1", {}).then(entry => {
+        subfolder1Entry = entry;
+        shouldBeEqualToString("subfolder1Entry.name", "subfolder1");
+        shouldBeEqualToString("subfolder1Entry.fullPath", "/testFiles/subfolder1");
+        shouldBeTrue("subfolder1Entry.isDirectory");
+    }, e => {
+        testFailed("getDirectory('subfolder1') should succeed");
+    });
+}
+
+function test3() {
+    debug("* Error case: calling getDirectory() with path to file");
+    return getDirectoryAsPromise(directoryEntry, "file1.txt", {}).then(entry => {
+        testFailed("Should fail when path points to a file");
+    }, e => {
+        ex = e;
+        shouldBeEqualToString("ex.name", "TypeMismatchError");
+    });
+}
+
+function test4() {
+    debug("* Error case: calling getDirectory() with path containing backslash");
+    return getDirectoryAsPromise(directoryEntry, "\\subfolder1", {}).then(entry => {
+        testFailed("Should fail when path is invalid");
+    }, e => {
+        ex = e;
+        shouldBeEqualToString("ex.name", "TypeMismatchError");
+    });
+}
+
+function test5() {
+    debug("* Error case: calling getDirectory() with path which does not exist");
+    return getDirectoryAsPromise(directoryEntry, "doesnotexist", {}).then(entry => {
+        testFailed("Should fail when path does not exist");
+    }, e => {
+        ex = e;
+        shouldBeEqualToString("ex.name", "NotFoundError");
+    });
+}
+
+function test6() {
+    debug("* Error case: calling getDirectory() with path containing a NUL character");
+    return getDirectoryAsPromise(directoryEntry, "subfolder1\0", {}).then(entry => {
+        testFailed("Should fail when path is invalid");
+    }, e => {
+        ex = e;
+        shouldBeEqualToString("ex.name", "TypeMismatchError");
+    });
+}
+
+function test7() {
+    debug("* Regular case: calling getDirectory() with path to root");
+    return getDirectoryAsPromise(directoryEntry, "/", {}).then(entry => {
+        rootEntry = entry;
+        shouldBeEqualToString("rootEntry.name", "");
+        shouldBeEqualToString("rootEntry.fullPath", "/");
+        shouldBeTrue("rootEntry.isDirectory");
+    }, e => {
+        testFailed("getDirectory('/') should succeed");
+    });
+}
+
+function test8() {
+    debug("* Regular case: calling getDirectory() with absolute path");
+    return getDirectoryAsPromise(directoryEntry, "/testFiles/subfolder2/subfolder2a", {}).then(entry => {
+        subfolder2aEntry = entry;
+        shouldBeEqualToString("subfolder2aEntry.name", "subfolder2a");
+        shouldBeEqualToString("subfolder2aEntry.fullPath", "/testFiles/subfolder2/subfolder2a");
+        shouldBeTrue("subfolder2aEntry.isDirectory");
+    }, e => {
+        testFailed("getDirectory('/testFiles/subfolder2/subfolder2a') should succeed");
+    });
+}
+
+function test9() {
+    debug("* Edge case: calling getDirectory() with relative path containing '.' and '..'");
+    return getDirectoryAsPromise(directoryEntry, "../testFiles/././subfolder2/../subfolder2/./subfolder2a", {}).then(entry => {
+        subfolder2aEntry = entry;
+        shouldBeEqualToString("subfolder2aEntry.name", "subfolder2a");
+        shouldBeEqualToString("subfolder2aEntry.fullPath", "/testFiles/subfolder2/subfolder2a");
+        shouldBeTrue("subfolder2aEntry.isDirectory");
+    }, e => {
+        testFailed("getDirectory('../testFiles/././subfolder2/../subfolder2/./subfolder2a') should succeed");
+    });
+}
+
+function test10() {
+    debug("* Edge case: calling getDirectory() with relative path containing too many '..'");
+    return getDirectoryAsPromise(directoryEntry, "../../../../../testFiles/subfolder1", {}).then(entry => {
+        subfolder1Entry = entry;
+        shouldBeEqualToString("subfolder1Entry.name", "subfolder1");
+        shouldBeEqualToString("subfolder1Entry.fullPath", "/testFiles/subfolder1");
+        shouldBeTrue("subfolder1Entry.isDirectory");
+    }, e => {
+        testFailed("getDirectory('../../../../../testFiles/subfolder1') should succeed");
+    });
+}
+
+function test11() {
+    debug("* Edge case: calling getDirectory() with absolute path containing '..'");
+    return getDirectoryAsPromise(directoryEntry, "/testFiles/../testFiles/subfolder1", {}).then(entry => {
+        subfolder1Entry = entry;
+        shouldBeEqualToString("subfolder1Entry.name", "subfolder1");
+        shouldBeEqualToString("subfolder1Entry.fullPath", "/testFiles/subfolder1");
+        shouldBeTrue("subfolder1Entry.isDirectory");
+    }, e => {
+        testFailed("getDirectory('../../../../../testFiles/subfolder1') should succeed");
+    });
+}
+
+function test12() {
+    debug("* Edge case: calling getDirectory() with absolute path containing too many '..'");
+    return getDirectoryAsPromise(directoryEntry, "/../../../../../testFiles/subfolder1", {}).then(entry => {
+        subfolder1Entry = entry;
+        shouldBeEqualToString("subfolder1Entry.name", "subfolder1");
+        shouldBeEqualToString("subfolder1Entry.fullPath", "/testFiles/subfolder1");
+        shouldBeTrue("subfolder1Entry.isDirectory");
+    }, e => {
+        testFailed("getDirectory('../../../../../testFiles/subfolder1') should succeed");
+    });
+}
+
+function test13() {
+    debug("* Error case: calling getDirectory() with empty path");
+    return getDirectoryAsPromise(directoryEntry, "", {}).then(entry => {
+        testFailed("Should fail when path is invalid");
+    }, e => {
+        ex = e;
+        shouldBeEqualToString("ex.name", "TypeMismatchError");
+    });
+}
+
+var dropzone = document.getElementById('dropzone');
+dropzone.ondrop = function(e) {
+    e.preventDefault();
+    dataTransfer = e.dataTransfer;
+
+    shouldBe("dataTransfer.items.length", "1");
+
+    directoryEntry = dataTransfer.items[0].webkitGetAsEntry();
+    test1()
+    .then(test2)
+    .then(test3)
+    .then(test4)
+    .then(test5)
+    .then(test6)
+    .then(test7)
+    .then(test8)
+    .then(test9)
+    .then(test10)
+    .then(test11)
+    .then(test12)
+    .then(test13)
+    .then(finishJSTest);
+};
+
+dropzone.ondragover = function(ev) {
+    ev.preventDefault();
+}
+
+onload = function() {
+    dragFilesOntoElement(dropzone, ['../../fast/forms/file/resources/testFiles']);
+}
+</script>
+</body>
+</html>
index 1a6db1f..67948b4 100644 (file)
@@ -567,6 +567,7 @@ editing/pasteboard/datatransfer-items-drop-directoryReader.html
 editing/pasteboard/datatransfer-items-drop-directoryReader-error.html
 editing/pasteboard/datatransfer-items-drop-directoryReader-root.html
 editing/pasteboard/datatransfer-items-drop-getAsEntry.html
+editing/pasteboard/datatransfer-items-drop-getDirectory.html
 editing/pasteboard/datatransfer-items-drop-getFile.html
 editing/pasteboard/datatransfer-items-drop-getParent-root.html
 editing/pasteboard/datatransfer-items-drop-getParent.html
index 54b39b2..fb3eb50 100644 (file)
@@ -1,3 +1,27 @@
+2017-09-02  Chris Dumez  <cdumez@apple.com>
+
+        Implement FileSystemDirectoryEntry.getDirectory()
+        https://bugs.webkit.org/show_bug.cgi?id=176168
+        <rdar://problem/34187787>
+
+        Reviewed by Darin Adler.
+
+        Implement FileSystemDirectoryEntry.getDirectory() as per:
+        - https://wicg.github.io/entries-api/#dom-filesystemdirectoryentry-getdirectory
+
+        Test: editing/pasteboard/datatransfer-items-drop-getDirectory.html
+
+        * Modules/entriesapi/DOMFileSystem.cpp:
+        (WebCore::isValidVirtualPath):
+        (WebCore::resolveRelativeVirtualPath):
+        (WebCore::DOMFileSystem::getEntry):
+        * Modules/entriesapi/DOMFileSystem.h:
+        * Modules/entriesapi/FileSystemDirectoryEntry.cpp:
+        (WebCore::FileSystemDirectoryEntry::getEntry):
+        (WebCore::FileSystemDirectoryEntry::getFile):
+        (WebCore::FileSystemDirectoryEntry::getDirectory):
+        * Modules/entriesapi/FileSystemDirectoryEntry.h:
+
 2017-09-02  Joseph Pecoraro  <pecoraro@apple.com>
 
         Performance / PerformanceObserver leaks seen on bots
index 6b0a3bb..48c417f 100644 (file)
@@ -130,7 +130,7 @@ static bool isValidVirtualPath(StringView virtualPath)
     if (virtualPath.isEmpty())
         return false;
     if (virtualPath[0] == '/')
-        return isValidRelativeVirtualPath(virtualPath.substring(1));
+        return virtualPath.length() == 1 || isValidRelativeVirtualPath(virtualPath.substring(1));
     return isValidRelativeVirtualPath(virtualPath);
 }
 
@@ -164,7 +164,7 @@ static String resolveRelativeVirtualPath(const String& baseVirtualPath, StringVi
 {
     ASSERT(baseVirtualPath[0] == '/');
     if (relativeVirtualPath[0] == '/')
-        return resolveRelativeVirtualPath(ASCIILiteral("/"), relativeVirtualPath.substring(1));
+        return relativeVirtualPath.length() == 1 ? relativeVirtualPath.toString() : resolveRelativeVirtualPath(ASCIILiteral("/"), relativeVirtualPath.substring(1));
 
     auto virtualPathSegments = baseVirtualPath.split('/');
     auto relativePathSegments = relativeVirtualPath.split('/');
@@ -261,22 +261,9 @@ void DOMFileSystem::getParent(ScriptExecutionContext& context, FileSystemEntry&
     });
 }
 
-static ExceptionOr<String> validatePathIsFile(const String& fullPath, String&& virtualPath)
-{
-    ASSERT(!isMainThread());
-
-    FileMetadata metadata;
-    if (!getFileMetadata(fullPath, metadata, ShouldFollowSymbolicLinks::No))
-        return Exception { NotFoundError, ASCIILiteral("File does not exist") };
-
-    if (metadata.type != FileMetadata::TypeFile)
-        return Exception { TypeMismatchError, ASCIILiteral("Entry at path is not a file") };
-
-    return WTFMove(virtualPath);
-}
-
 // https://wicg.github.io/entries-api/#dom-filesystemdirectoryentry-getfile
-void DOMFileSystem::getFile(ScriptExecutionContext& context, FileSystemDirectoryEntry& directory, const String& virtualPath, const FileSystemDirectoryEntry::Flags& flags, GetFileCallback&& completionCallback)
+// https://wicg.github.io/entries-api/#dom-filesystemdirectoryentry-getdirectory
+void DOMFileSystem::getEntry(ScriptExecutionContext& context, FileSystemDirectoryEntry& directory, const String& virtualPath, const FileSystemDirectoryEntry::Flags& flags, GetEntryCallback&& completionCallback)
 {
     ASSERT(&directory.filesystem() == this);
 
@@ -297,13 +284,28 @@ void DOMFileSystem::getFile(ScriptExecutionContext& context, FileSystemDirectory
     String resolvedVirtualPath = resolveRelativeVirtualPath(directory.virtualPath(), virtualPath);
     ASSERT(resolvedVirtualPath[0] == '/');
     String fullPath = evaluatePath(resolvedVirtualPath);
+    if (fullPath == m_rootPath) {
+        callOnMainThread([this, context = makeRef(context), completionCallback = WTFMove(completionCallback)]() mutable {
+            completionCallback(Ref<FileSystemEntry> { root(context) });
+        });
+        return;
+    }
+
     m_workQueue->dispatch([this, context = makeRef(context), fullPath = crossThreadCopy(fullPath), resolvedVirtualPath = crossThreadCopy(resolvedVirtualPath), completionCallback = WTFMove(completionCallback)]() mutable {
-        auto validatedVirtualPath = validatePathIsFile(fullPath, WTFMove(resolvedVirtualPath));
-        callOnMainThread([this, context = WTFMove(context), validatedVirtualPath = crossThreadCopy(validatedVirtualPath), completionCallback = WTFMove(completionCallback)]() mutable {
-            if (validatedVirtualPath.hasException())
-                completionCallback(validatedVirtualPath.releaseException());
-            else
-                completionCallback(FileSystemFileEntry::create(context, *this, validatedVirtualPath.releaseReturnValue()));
+        FileMetadata metadata;
+        getFileMetadata(fullPath, metadata, ShouldFollowSymbolicLinks::No);
+        callOnMainThread([this, context = WTFMove(context), resolvedVirtualPath = crossThreadCopy(resolvedVirtualPath), entryType = metadata.type, completionCallback = WTFMove(completionCallback)]() mutable {
+            switch (entryType) {
+            case FileMetadata::TypeDirectory:
+                completionCallback(Ref<FileSystemEntry> { FileSystemDirectoryEntry::create(context, *this, resolvedVirtualPath) });
+                break;
+            case FileMetadata::TypeFile:
+                completionCallback(Ref<FileSystemEntry> { FileSystemFileEntry::create(context, *this, resolvedVirtualPath) });
+                break;
+            default:
+                completionCallback(Exception { NotFoundError, ASCIILiteral("Cannot find entry at given path") });
+                break;
+            }
         });
     });
 }
index a83398e..324f157 100644 (file)
@@ -58,8 +58,8 @@ public:
     using GetParentCallback = WTF::Function<void(ExceptionOr<Ref<FileSystemDirectoryEntry>>&&)>;
     void getParent(ScriptExecutionContext&, FileSystemEntry&, GetParentCallback&&);
 
-    using GetFileCallback = WTF::Function<void(ExceptionOr<Ref<FileSystemFileEntry>>&&)>;
-    void getFile(ScriptExecutionContext&, FileSystemDirectoryEntry&, const String& virtualPath, const FileSystemDirectoryEntry::Flags&, GetFileCallback&&);
+    using GetEntryCallback = WTF::Function<void(ExceptionOr<Ref<FileSystemEntry>>&&)>;
+    void getEntry(ScriptExecutionContext&, FileSystemDirectoryEntry&, const String& virtualPath, const FileSystemDirectoryEntry::Flags&, GetEntryCallback&&);
 
 private:
     explicit DOMFileSystem(Ref<File>&&);
index 1c28116..5656a41 100644 (file)
@@ -46,26 +46,36 @@ Ref<FileSystemDirectoryReader> FileSystemDirectoryEntry::createReader(ScriptExec
     return FileSystemDirectoryReader::create(context, *this);
 }
 
-void FileSystemDirectoryEntry::getFile(ScriptExecutionContext& context, const String& path, const Flags& flags, RefPtr<FileSystemEntryCallback>&& successCallback, RefPtr<ErrorCallback>&& errorCallback)
+void FileSystemDirectoryEntry::getEntry(ScriptExecutionContext& context, const String& path, const Flags& flags, EntryMatchingFunction&& matches, RefPtr<FileSystemEntryCallback>&& successCallback, RefPtr<ErrorCallback>&& errorCallback)
 {
     if (!successCallback && !errorCallback)
         return;
 
-    filesystem().getFile(context, *this, path, flags, [this, pendingActivity = makePendingActivity(*this), successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback)](auto&& result) {
+    filesystem().getEntry(context, *this, path, flags, [this, pendingActivity = makePendingActivity(*this), matches = WTFMove(matches), successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback)](auto&& result) {
         if (result.hasException()) {
             if (errorCallback)
                 errorCallback->handleEvent(DOMException::create(result.releaseException()));
             return;
         }
+        auto entry = result.releaseReturnValue();
+        if (!matches(entry)) {
+            if (errorCallback)
+                errorCallback->handleEvent(DOMException::create(Exception { TypeMismatchError, ASCIILiteral("Entry at given path does not match expected type") }));
+            return;
+        }
         if (successCallback)
-            successCallback->handleEvent(result.releaseReturnValue());
+            successCallback->handleEvent(WTFMove(entry));
     });
 }
 
-void FileSystemDirectoryEntry::getDirectory(ScriptExecutionContext& context, const String&, const Flags&, RefPtr<FileSystemEntryCallback>&&, RefPtr<ErrorCallback>&& errorCallback)
+void FileSystemDirectoryEntry::getFile(ScriptExecutionContext& context, const String& path, const Flags& flags, RefPtr<FileSystemEntryCallback>&& successCallback, RefPtr<ErrorCallback>&& errorCallback)
+{
+    getEntry(context, path, flags, [](auto& entry) { return entry.isFile(); }, WTFMove(successCallback), WTFMove(errorCallback));
+}
+
+void FileSystemDirectoryEntry::getDirectory(ScriptExecutionContext& context, const String& path, const Flags& flags, RefPtr<FileSystemEntryCallback>&& successCallback, RefPtr<ErrorCallback>&& errorCallback)
 {
-    if (errorCallback)
-        errorCallback->scheduleCallback(context, DOMException::create(NotSupportedError));
+    getEntry(context, path, flags, [](auto& entry) { return entry.isDirectory(); }, WTFMove(successCallback), WTFMove(errorCallback));
 }
 
 } // namespace WebCore
index 3cdfe9b..e4ea33f 100644 (file)
@@ -53,6 +53,8 @@ public:
 
 private:
     bool isDirectory() const final { return true; }
+    using EntryMatchingFunction = WTF::Function<bool(const FileSystemEntry&)>;
+    void getEntry(ScriptExecutionContext&, const String& path, const Flags& options, EntryMatchingFunction&&, RefPtr<FileSystemEntryCallback>&&, RefPtr<ErrorCallback>&&);
 
     FileSystemDirectoryEntry(ScriptExecutionContext&, DOMFileSystem&, const String& virtualPath);
 };