<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[286507] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/286507">286507</a></dd>
<dt>Author</dt> <dd>sihui_liu@apple.com</dd>
<dt>Date</dt> <dd>2021-12-03 12:17:15 -0800 (Fri, 03 Dec 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>Fetch and remove file system data via WKWebsiteDataStore
https://bugs.webkit.org/show_bug.cgi?id=233567

Reviewed by Youenn Fablet.

Source/WebCore:

* Modules/filesystemaccess/FileSystemStorageConnection.h:

Source/WebKit:

Introduce a new WebsiteDataType value FileSystem for FileSystemAccess data. Network process now can fetch and
delete this type of data when fetching and deleteing website data (if FileSystem type is included in target
types).

To track origins that have FileSystem data, this patch introduces a new file named origin in the origin's
directory. This file will be created when OriginStorageManager is created.

To delete existing FileSystem data, network process finds origins that are requested to be deleted and have data
on disk, closes active access handles, and deletes the files. The origin file mentioned above will be deleted if
there is no other file left in the same directory, and empty directories will be deleted.

New API tests: FileSystemAccess.FetchAndRemoveData
               FileSystemAccess.RemoveDataByModificationTime
               FileSystemAccess.FetchDataForThirdParty

* CMakeLists.txt:
* DerivedSources-input.xcfilelist:
* DerivedSources-output.xcfilelist:
* DerivedSources.make:
* NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp:
(WebKit::WebResourceLoadStatisticsStore::monitoredDataTypes):
* NetworkProcess/NetworkProcess.cpp:
(WebKit::NetworkProcess::fetchWebsiteData):
(WebKit::NetworkProcess::deleteWebsiteData):
(WebKit::NetworkProcess::deleteWebsiteDataForOrigins):
(WebKit::NetworkProcess::deleteAndRestrictWebsiteDataForRegistrableDomains):
(WebKit::NetworkProcess::registrableDomainsWithWebsiteData):
* NetworkProcess/storage/FileSystemStorageHandle.h:
(WebKit::FileSystemStorageHandle::activeSyncAccessHandle const):
* NetworkProcess/storage/FileSystemStorageManager.cpp:
(WebKit::FileSystemStorageManager::~FileSystemStorageManager):
(WebKit::FileSystemStorageManager::close):
* NetworkProcess/storage/FileSystemStorageManager.h:
* NetworkProcess/storage/NetworkStorageManager.cpp:
(WebKit::readOriginFromFile):
(WebKit::writeOriginToFileIfNecessary):
(WebKit::deleteOriginFileIfNecessary):
(WebKit::originDirectoryPath):
(WebKit::originFilePath):
(WebKit::NetworkStorageManager::localOriginStorageManager):
(WebKit::NetworkStorageManager::removeOriginStorageManagerIfPossible):
(WebKit::toWebsiteDataType):
(WebKit::NetworkStorageManager::forEachOriginDirectory):
(WebKit::NetworkStorageManager::fetchDataFromDisk):
(WebKit::NetworkStorageManager::fetchData):
(WebKit::NetworkStorageManager::deleteDataOnDisk):
(WebKit::NetworkStorageManager::deleteData):
(WebKit::NetworkStorageManager::deleteDataModifiedSince):
(WebKit::NetworkStorageManager::deleteDataForRegistrableDomains):
(WebKit::originPath): Deleted.
* NetworkProcess/storage/NetworkStorageManager.h:
* NetworkProcess/storage/OriginStorageManager.cpp:
(WebKit::OriginStorageManager::StorageBucket::toStorageIdentifier):
(WebKit::OriginStorageManager::StorageBucket::typeStoragePath const):
(WebKit::OriginStorageManager::StorageBucket::fileSystemStorageManager):
(WebKit::OriginStorageManager::StorageBucket::isActive):
(WebKit::OriginStorageManager::StorageBucket::deleteData):
(WebKit::OriginStorageManager::StorageBucket::deleteFileSystemStorageData):
(WebKit::OriginStorageManager::OriginStorageManager):
(WebKit::OriginStorageManager::isActive):
(WebKit::OriginStorageManager::deleteData):
* NetworkProcess/storage/OriginStorageManager.h:
* Shared/WebsiteData/WebsiteData.cpp:
(WebKit::WebsiteData::ownerProcess):
* Shared/WebsiteData/WebsiteDataType.h:
* UIProcess/API/Cocoa/WKWebsiteDataRecord.mm:
(dataTypesToString):
* UIProcess/API/Cocoa/WKWebsiteDataRecordInternal.h:
(WebKit::toWebsiteDataType):
(WebKit::toWKWebsiteDataTypes):
* UIProcess/API/Cocoa/WKWebsiteDataRecordPrivate.h:
* UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
(+[WKWebsiteDataStore _allWebsiteDataTypesIncludingPrivate]):
* WebKit.xcodeproj/project.pbxproj:
* WebProcess/Network/NetworkProcessConnection.cpp:
(WebKit::NetworkProcessConnection::didReceiveMessage):
* WebProcess/WebCoreSupport/WebFileSystemStorageConnection.messages.in: Added.

Source/WTF:

* wtf/FileSystem.cpp:
(WTF::FileSystemImpl::readEntireFile): Read whole file content into a Vector.
(WTF::FileSystemImpl::deleteAllFilesModifiedSince): Recursively delete files and folders modified after
specified time in a directory.
* wtf/FileSystem.h:

Tools:

* TestWebKitAPI/Tests/WebKitCocoa/FileSystemAccess.mm:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfFileSystemcpp">trunk/Source/WTF/wtf/FileSystem.cpp</a></li>
<li><a href="#trunkSourceWTFwtfFileSystemh">trunk/Source/WTF/wtf/FileSystem.h</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesfilesystemaccessFileSystemStorageConnectionh">trunk/Source/WebCore/Modules/filesystemaccess/FileSystemStorageConnection.h</a></li>
<li><a href="#trunkSourceWebKitCMakeListstxt">trunk/Source/WebKit/CMakeLists.txt</a></li>
<li><a href="#trunkSourceWebKitChangeLog">trunk/Source/WebKit/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitDerivedSourcesinputxcfilelist">trunk/Source/WebKit/DerivedSources-input.xcfilelist</a></li>
<li><a href="#trunkSourceWebKitDerivedSourcesoutputxcfilelist">trunk/Source/WebKit/DerivedSources-output.xcfilelist</a></li>
<li><a href="#trunkSourceWebKitDerivedSourcesmake">trunk/Source/WebKit/DerivedSources.make</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessClassifierWebResourceLoadStatisticsStorecpp">trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessNetworkProcesscpp">trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessstorageFileSystemStorageHandleh">trunk/Source/WebKit/NetworkProcess/storage/FileSystemStorageHandle.h</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessstorageFileSystemStorageManagercpp">trunk/Source/WebKit/NetworkProcess/storage/FileSystemStorageManager.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessstorageFileSystemStorageManagerh">trunk/Source/WebKit/NetworkProcess/storage/FileSystemStorageManager.h</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessstorageNetworkStorageManagercpp">trunk/Source/WebKit/NetworkProcess/storage/NetworkStorageManager.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessstorageNetworkStorageManagerh">trunk/Source/WebKit/NetworkProcess/storage/NetworkStorageManager.h</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessstorageOriginStorageManagercpp">trunk/Source/WebKit/NetworkProcess/storage/OriginStorageManager.cpp</a></li>
<li><a href="#trunkSourceWebKitNetworkProcessstorageOriginStorageManagerh">trunk/Source/WebKit/NetworkProcess/storage/OriginStorageManager.h</a></li>
<li><a href="#trunkSourceWebKitSharedWebsiteDataWebsiteDatacpp">trunk/Source/WebKit/Shared/WebsiteData/WebsiteData.cpp</a></li>
<li><a href="#trunkSourceWebKitSharedWebsiteDataWebsiteDataTypeh">trunk/Source/WebKit/Shared/WebsiteData/WebsiteDataType.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPICocoaWKWebsiteDataRecordmm">trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataRecord.mm</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPICocoaWKWebsiteDataRecordInternalh">trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataRecordInternal.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPICocoaWKWebsiteDataRecordPrivateh">trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataRecordPrivate.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPICocoaWKWebsiteDataStoremm">trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm</a></li>
<li><a href="#trunkSourceWebKitWebKitxcodeprojprojectpbxproj">trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWebKitWebProcessNetworkNetworkProcessConnectioncpp">trunk/Source/WebKit/WebProcess/Network/NetworkProcessConnection.cpp</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKitCocoaFileSystemAccessmm">trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/FileSystemAccess.mm</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebKitWebProcessWebCoreSupportWebFileSystemStorageConnectionmessagesin">trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFileSystemStorageConnection.messages.in</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog       2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WTF/ChangeLog  2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2021-12-03  Sihui Liu  <sihui_liu@apple.com>
+
+        Fetch and remove file system data via WKWebsiteDataStore
+        https://bugs.webkit.org/show_bug.cgi?id=233567
+
+        Reviewed by Youenn Fablet.
+
+        * wtf/FileSystem.cpp:
+        (WTF::FileSystemImpl::readEntireFile): Read whole file content into a Vector.
+        (WTF::FileSystemImpl::deleteAllFilesModifiedSince): Recursively delete files and folders modified after 
+        specified time in a directory.
+        * wtf/FileSystem.h:
+
</ins><span class="cx"> 2021-12-03  Tim Horton  <timothy_horton@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Enable Momentum Event Generator by default
</span></span></pre></div>
<a id="trunkSourceWTFwtfFileSystemcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/FileSystem.cpp (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/FileSystem.cpp      2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WTF/wtf/FileSystem.cpp 2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -514,6 +514,60 @@
</span><span class="cx">     return salt;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+std::optional<Vector<uint8_t>> readEntireFile(PlatformFileHandle handle)
+{
+    if (!FileSystem::isHandleValid(handle))
+        return std::nullopt;
+
+    auto size = FileSystem::fileSize(handle).value_or(0);
+    if (!size)
+        return std::nullopt;
+
+    unsigned bytesToRead;
+    if (!WTF::convertSafely(size, bytesToRead))
+        return std::nullopt;
+
+    Vector<uint8_t> buffer(bytesToRead);
+    unsigned totalBytesRead = FileSystem::readFromFile(handle, buffer.data(), buffer.size());
+    if (totalBytesRead != bytesToRead)
+        return std::nullopt;
+
+    return buffer;
+}
+
+void deleteAllFilesModifiedSince(const String& directory, WallTime time)
+{
+    // This function may delete directory folder.
+    if (time == -WallTime::infinity()) {
+        deleteNonEmptyDirectory(directory);
+        return;
+    }
+
+    auto children = listDirectory(directory);
+    for (auto& child : children) {
+        auto childPath = FileSystem::pathByAppendingComponent(directory, child);
+        auto childType = fileType(childPath);
+        if (!childType)
+            continue;
+
+        switch (*childType) {
+        case FileType::Regular: {
+            if (auto modificationTime = FileSystem::fileModificationTime(childPath); modificationTime && *modificationTime >= time)
+                deleteFile(childPath);
+            break;
+        }
+        case FileType::Directory:
+            deleteAllFilesModifiedSince(childPath, time);
+            deleteEmptyDirectory(childPath);
+            break;
+        case FileType::SymbolicLink:
+            break;
+        }
+    }
+
+    FileSystem::deleteEmptyDirectory(directory);
+}
+
</ins><span class="cx"> #if HAVE(STD_FILESYSTEM) || HAVE(STD_EXPERIMENTAL_FILESYSTEM)
</span><span class="cx"> 
</span><span class="cx"> bool deleteEmptyDirectory(const String& path)
</span></span></pre></div>
<a id="trunkSourceWTFwtfFileSystemh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/FileSystem.h (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/FileSystem.h        2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WTF/wtf/FileSystem.h   2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -108,6 +108,7 @@
</span><span class="cx"> 
</span><span class="cx"> WTF_EXPORT_PRIVATE bool fileExists(const String&);
</span><span class="cx"> WTF_EXPORT_PRIVATE bool deleteFile(const String&);
</span><ins>+WTF_EXPORT_PRIVATE void deleteAllFilesModifiedSince(const String&, WallTime);
</ins><span class="cx"> WTF_EXPORT_PRIVATE bool deleteEmptyDirectory(const String&);
</span><span class="cx"> WTF_EXPORT_PRIVATE bool moveFile(const String& oldPath, const String& newPath);
</span><span class="cx"> WTF_EXPORT_PRIVATE std::optional<uint64_t> fileSize(const String&); // Follows symlinks.
</span><span class="lines">@@ -146,6 +147,7 @@
</span><span class="cx"> 
</span><span class="cx"> using Salt = std::array<uint8_t, 8>;
</span><span class="cx"> WTF_EXPORT_PRIVATE std::optional<Salt> readOrMakeSalt(const String& path);
</span><ins>+WTF_EXPORT_PRIVATE std::optional<Vector<uint8_t>> readEntireFile(PlatformFileHandle);
</ins><span class="cx"> 
</span><span class="cx"> // Prefix is what the filename should be prefixed with, not the full path.
</span><span class="cx"> WTF_EXPORT_PRIVATE String openTemporaryFile(const String& prefix, PlatformFileHandle&, const String& suffix = { });
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebCore/ChangeLog      2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -1,3 +1,12 @@
</span><ins>+2021-12-03  Sihui Liu  <sihui_liu@apple.com>
+
+        Fetch and remove file system data via WKWebsiteDataStore
+        https://bugs.webkit.org/show_bug.cgi?id=233567
+
+        Reviewed by Youenn Fablet.
+
+        * Modules/filesystemaccess/FileSystemStorageConnection.h:
+
</ins><span class="cx"> 2021-12-03  Alan Bujtas  <zalan@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [LFC][IFC] Set the first/last box flag on the (bidi fragmented) inline box type of display boxes
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesfilesystemaccessFileSystemStorageConnectionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/filesystemaccess/FileSystemStorageConnection.h (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/filesystemaccess/FileSystemStorageConnection.h      2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebCore/Modules/filesystemaccess/FileSystemStorageConnection.h 2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include "FileSystemHandleIdentifier.h"
</span><span class="cx"> #include "FileSystemSyncAccessHandleIdentifier.h"
</span><ins>+#include "ProcessQualified.h"
</ins><span class="cx"> #include "ScriptExecutionContextIdentifier.h"
</span><span class="cx"> #include <wtf/CompletionHandler.h>
</span><span class="cx"> #include <wtf/FileSystem.h>
</span></span></pre></div>
<a id="trunkSourceWebKitCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/CMakeLists.txt (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/CMakeLists.txt       2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/CMakeLists.txt  2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -310,6 +310,7 @@
</span><span class="cx"> 
</span><span class="cx">     WebProcess/WebCoreSupport/RemoteWebLockRegistry
</span><span class="cx">     WebProcess/WebCoreSupport/WebBroadcastChannelRegistry
</span><ins>+    WebProcess/WebCoreSupport/WebFileSystemStorageConnection
</ins><span class="cx">     WebProcess/WebCoreSupport/WebSpeechRecognitionConnection
</span><span class="cx"> 
</span><span class="cx">     WebProcess/WebPage/DrawingArea
</span></span></pre></div>
<a id="trunkSourceWebKitChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/ChangeLog (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/ChangeLog    2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/ChangeLog       2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -1,3 +1,88 @@
</span><ins>+2021-12-03  Sihui Liu  <sihui_liu@apple.com>
+
+        Fetch and remove file system data via WKWebsiteDataStore
+        https://bugs.webkit.org/show_bug.cgi?id=233567
+
+        Reviewed by Youenn Fablet.
+
+        Introduce a new WebsiteDataType value FileSystem for FileSystemAccess data. Network process now can fetch and 
+        delete this type of data when fetching and deleteing website data (if FileSystem type is included in target
+        types).
+
+        To track origins that have FileSystem data, this patch introduces a new file named origin in the origin's 
+        directory. This file will be created when OriginStorageManager is created.
+
+        To delete existing FileSystem data, network process finds origins that are requested to be deleted and have data 
+        on disk, closes active access handles, and deletes the files. The origin file mentioned above will be deleted if 
+        there is no other file left in the same directory, and empty directories will be deleted.
+
+        New API tests: FileSystemAccess.FetchAndRemoveData
+                       FileSystemAccess.RemoveDataByModificationTime
+                       FileSystemAccess.FetchDataForThirdParty
+
+        * CMakeLists.txt:
+        * DerivedSources-input.xcfilelist:
+        * DerivedSources-output.xcfilelist:
+        * DerivedSources.make:
+        * NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp:
+        (WebKit::WebResourceLoadStatisticsStore::monitoredDataTypes):
+        * NetworkProcess/NetworkProcess.cpp:
+        (WebKit::NetworkProcess::fetchWebsiteData):
+        (WebKit::NetworkProcess::deleteWebsiteData):
+        (WebKit::NetworkProcess::deleteWebsiteDataForOrigins):
+        (WebKit::NetworkProcess::deleteAndRestrictWebsiteDataForRegistrableDomains):
+        (WebKit::NetworkProcess::registrableDomainsWithWebsiteData):
+        * NetworkProcess/storage/FileSystemStorageHandle.h:
+        (WebKit::FileSystemStorageHandle::activeSyncAccessHandle const):
+        * NetworkProcess/storage/FileSystemStorageManager.cpp:
+        (WebKit::FileSystemStorageManager::~FileSystemStorageManager):
+        (WebKit::FileSystemStorageManager::close):
+        * NetworkProcess/storage/FileSystemStorageManager.h:
+        * NetworkProcess/storage/NetworkStorageManager.cpp:
+        (WebKit::readOriginFromFile):
+        (WebKit::writeOriginToFileIfNecessary):
+        (WebKit::deleteOriginFileIfNecessary):
+        (WebKit::originDirectoryPath):
+        (WebKit::originFilePath):
+        (WebKit::NetworkStorageManager::localOriginStorageManager):
+        (WebKit::NetworkStorageManager::removeOriginStorageManagerIfPossible):
+        (WebKit::toWebsiteDataType):
+        (WebKit::NetworkStorageManager::forEachOriginDirectory):
+        (WebKit::NetworkStorageManager::fetchDataFromDisk):
+        (WebKit::NetworkStorageManager::fetchData):
+        (WebKit::NetworkStorageManager::deleteDataOnDisk):
+        (WebKit::NetworkStorageManager::deleteData):
+        (WebKit::NetworkStorageManager::deleteDataModifiedSince):
+        (WebKit::NetworkStorageManager::deleteDataForRegistrableDomains):
+        (WebKit::originPath): Deleted.
+        * NetworkProcess/storage/NetworkStorageManager.h:
+        * NetworkProcess/storage/OriginStorageManager.cpp:
+        (WebKit::OriginStorageManager::StorageBucket::toStorageIdentifier):
+        (WebKit::OriginStorageManager::StorageBucket::typeStoragePath const):
+        (WebKit::OriginStorageManager::StorageBucket::fileSystemStorageManager):
+        (WebKit::OriginStorageManager::StorageBucket::isActive):
+        (WebKit::OriginStorageManager::StorageBucket::deleteData):
+        (WebKit::OriginStorageManager::StorageBucket::deleteFileSystemStorageData):
+        (WebKit::OriginStorageManager::OriginStorageManager):
+        (WebKit::OriginStorageManager::isActive):
+        (WebKit::OriginStorageManager::deleteData):
+        * NetworkProcess/storage/OriginStorageManager.h:
+        * Shared/WebsiteData/WebsiteData.cpp:
+        (WebKit::WebsiteData::ownerProcess):
+        * Shared/WebsiteData/WebsiteDataType.h:
+        * UIProcess/API/Cocoa/WKWebsiteDataRecord.mm:
+        (dataTypesToString):
+        * UIProcess/API/Cocoa/WKWebsiteDataRecordInternal.h:
+        (WebKit::toWebsiteDataType):
+        (WebKit::toWKWebsiteDataTypes):
+        * UIProcess/API/Cocoa/WKWebsiteDataRecordPrivate.h:
+        * UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
+        (+[WKWebsiteDataStore _allWebsiteDataTypesIncludingPrivate]):
+        * WebKit.xcodeproj/project.pbxproj:
+        * WebProcess/Network/NetworkProcessConnection.cpp:
+        (WebKit::NetworkProcessConnection::didReceiveMessage):
+        * WebProcess/WebCoreSupport/WebFileSystemStorageConnection.messages.in: Added.
+
</ins><span class="cx"> 2021-12-03  Chris Dumez  <cdumez@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Follow-up to r286479 to add API test and address issues found by the test
</span></span></pre></div>
<a id="trunkSourceWebKitDerivedSourcesinputxcfilelist"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/DerivedSources-input.xcfilelist (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/DerivedSources-input.xcfilelist      2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/DerivedSources-input.xcfilelist 2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -221,6 +221,7 @@
</span><span class="cx"> $(PROJECT_DIR)/WebProcess/WebCoreSupport/RemoteWebLockRegistry.messages.in
</span><span class="cx"> $(PROJECT_DIR)/WebProcess/WebCoreSupport/WebBroadcastChannelRegistry.messages.in
</span><span class="cx"> $(PROJECT_DIR)/WebProcess/WebCoreSupport/WebDeviceOrientationUpdateProvider.messages.in
</span><ins>+$(PROJECT_DIR)/WebProcess/WebCoreSupport/WebFileSystemStorageConnection.messages.in
</ins><span class="cx"> $(PROJECT_DIR)/WebProcess/WebCoreSupport/WebSpeechRecognitionConnection.messages.in
</span><span class="cx"> $(PROJECT_DIR)/WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.messages.in
</span><span class="cx"> $(PROJECT_DIR)/WebProcess/WebPage/DrawingArea.messages.in
</span></span></pre></div>
<a id="trunkSourceWebKitDerivedSourcesoutputxcfilelist"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/DerivedSources-output.xcfilelist (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/DerivedSources-output.xcfilelist     2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/DerivedSources-output.xcfilelist        2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -493,6 +493,9 @@
</span><span class="cx"> $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebDeviceOrientationUpdateProviderProxyMessageReceiver.cpp
</span><span class="cx"> $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebDeviceOrientationUpdateProviderProxyMessages.h
</span><span class="cx"> $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebDeviceOrientationUpdateProviderProxyMessagesReplies.h
</span><ins>+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebFileSystemStorageConnectionMessageReceiver.cpp
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebFileSystemStorageConnectionMessages.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebFileSystemStorageConnectionMessagesReplies.h
</ins><span class="cx"> $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebFullScreenManagerMessageReceiver.cpp
</span><span class="cx"> $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebFullScreenManagerMessages.h
</span><span class="cx"> $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebFullScreenManagerMessagesReplies.h
</span></span></pre></div>
<a id="trunkSourceWebKitDerivedSourcesmake"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/DerivedSources.make (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/DerivedSources.make  2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/DerivedSources.make     2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -222,6 +222,7 @@
</span><span class="cx">  WebProcess/WebCoreSupport/RemoteWebLockRegistry \
</span><span class="cx">  WebProcess/WebCoreSupport/WebBroadcastChannelRegistry \
</span><span class="cx">  WebProcess/WebCoreSupport/WebDeviceOrientationUpdateProvider \
</span><ins>+       WebProcess/WebCoreSupport/WebFileSystemStorageConnection \
</ins><span class="cx">   WebProcess/WebCoreSupport/WebSpeechRecognitionConnection \
</span><span class="cx">  WebProcess/Speech/SpeechRecognitionRealtimeMediaSourceManager \
</span><span class="cx">  WebProcess/Storage/WebSWContextManagerConnection \
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessClassifierWebResourceLoadStatisticsStorecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp 2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp    2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -74,6 +74,7 @@
</span><span class="cx"> #if ENABLE(SERVICE_WORKER)
</span><span class="cx">         WebsiteDataType::ServiceWorkerRegistrations,
</span><span class="cx"> #endif
</span><ins>+        WebsiteDataType::FileSystem,
</ins><span class="cx">     }));
</span><span class="cx"> 
</span><span class="cx">     ASSERT(RunLoop::isMain());
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessNetworkProcesscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp    2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp       2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -1555,6 +1555,12 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> #endif
</span><ins>+
+    if (auto iterator = m_storageManagers.find(sessionID); iterator != m_storageManagers.end()) {
+        iterator->value->fetchData(websiteDataTypes, [callbackAggregator](auto entries) mutable {
+            callbackAggregator->m_websiteData.entries.appendVector(WTFMove(entries));
+        });
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void NetworkProcess::deleteWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, WallTime modifiedSince, CompletionHandler<void()>&& completionHandler)
</span><span class="lines">@@ -1629,6 +1635,9 @@
</span><span class="cx">             networkSession->clearAlternativeServices(modifiedSince);
</span><span class="cx">     }
</span><span class="cx"> #endif
</span><ins>+
+    if (auto iterator = m_storageManagers.find(sessionID); iterator != m_storageManagers.end())
+        iterator->value->deleteDataModifiedSince(websiteDataTypes, modifiedSince, [clearTasksHandler] { });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void clearDiskCacheEntries(NetworkCache::Cache* cache, const Vector<SecurityOriginData>& origins, CompletionHandler<void()>&& completionHandler)
</span><span class="lines">@@ -1736,6 +1745,9 @@
</span><span class="cx">     }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    if (auto iterator = m_storageManagers.find(sessionID); iterator != m_storageManagers.end())
+        iterator->value->deleteData(websiteDataTypes, originDatas, [clearTasksHandler] { });
+
</ins><span class="cx">     if (auto* networkSession = this->networkSession(sessionID)) {
</span><span class="cx">         HashSet<WebCore::RegistrableDomain> domainsToDeleteNetworkDataFor;
</span><span class="cx">         for (auto& originData : originDatas)
</span><span class="lines">@@ -1959,6 +1971,13 @@
</span><span class="cx">         });
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    if (auto iterator = m_storageManagers.find(sessionID); iterator != m_storageManagers.end()) {
+        iterator->value->deleteDataForRegistrableDomains(websiteDataTypes, domainsToDeleteAllNonCookieWebsiteDataFor, [callbackAggregator](auto deletedDomains) mutable {
+            for (auto domain : deletedDomains)
+                callbackAggregator->m_domains.add(WTFMove(domain));
+        });
+    }
+
</ins><span class="cx">     auto dataTypesForUIProcess = WebsiteData::filter(websiteDataTypes, WebsiteDataProcessType::UI);
</span><span class="cx">     if (!dataTypesForUIProcess.isEmpty() && !domainsToDeleteAllNonCookieWebsiteDataFor.isEmpty()) {
</span><span class="cx">         CompletionHandler<void(const HashSet<RegistrableDomain>&)> completionHandler = [callbackAggregator] (const HashSet<RegistrableDomain>& domains) {
</span><span class="lines">@@ -2075,6 +2094,12 @@
</span><span class="cx">             });
</span><span class="cx">         });
</span><span class="cx">     }
</span><ins>+
+    if (auto iterator = m_storageManagers.find(sessionID); iterator != m_storageManagers.end()) {
+        iterator->value->fetchData(websiteDataTypes, [callbackAggregator](auto entries) mutable {
+            callbackAggregator->m_websiteData.entries.appendVector(WTFMove(entries));
+        });
+    }
</ins><span class="cx"> }
</span><span class="cx"> #endif // ENABLE(INTELLIGENT_TRACKING_PREVENTION)
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessstorageFileSystemStorageHandleh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/storage/FileSystemStorageHandle.h (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/storage/FileSystemStorageHandle.h     2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/NetworkProcess/storage/FileSystemStorageHandle.h        2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -62,6 +62,7 @@
</span><span class="cx">     using AccessHandleInfo = std::pair<WebCore::FileSystemSyncAccessHandleIdentifier, IPC::SharedFileHandle>;
</span><span class="cx">     Expected<AccessHandleInfo, FileSystemStorageError> createSyncAccessHandle();
</span><span class="cx">     std::optional<FileSystemStorageError> close(WebCore::FileSystemSyncAccessHandleIdentifier);
</span><ins>+    std::optional<WebCore::FileSystemSyncAccessHandleIdentifier> activeSyncAccessHandle() const { return m_activeSyncAccessHandle; }
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     Expected<WebCore::FileSystemHandleIdentifier, FileSystemStorageError> requestCreateHandle(IPC::Connection::UniqueID, Type, String&& name, bool createIfNecessary);
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessstorageFileSystemStorageManagercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/storage/FileSystemStorageManager.cpp (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/storage/FileSystemStorageManager.cpp  2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/NetworkProcess/storage/FileSystemStorageManager.cpp     2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include "FileSystemStorageError.h"
</span><span class="cx"> #include "FileSystemStorageHandleRegistry.h"
</span><ins>+#include "WebFileSystemStorageConnectionMessages.h"
</ins><span class="cx"> 
</span><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><span class="lines">@@ -42,8 +43,7 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx"> 
</span><del>-    for (auto identifier : m_handles.keys())
-        m_registry.unregisterHandle(identifier);
</del><ins>+    close();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Expected<WebCore::FileSystemHandleIdentifier, FileSystemStorageError> FileSystemStorageManager::createHandle(IPC::Connection::UniqueID connection, FileSystemStorageHandle::Type type, String&& path, String&& name, bool createIfNecessary)
</span><span class="lines">@@ -149,4 +149,24 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void FileSystemStorageManager::close()
+{
+    ASSERT(!RunLoop::isMain());
+
+    for (auto& [connectionID, identifiers] : m_handlesByConnection) {
+        for (auto identifier : identifiers) {
+            auto takenHandle = m_handles.take(identifier);
+            m_registry.unregisterHandle(identifier);
+
+            // Send message to web process to invalidate active sync access handle.
+            if (auto accessHandleIdentifier = takenHandle->activeSyncAccessHandle())
+                IPC::Connection::send(connectionID, Messages::WebFileSystemStorageConnection::InvalidateAccessHandle(*accessHandleIdentifier), 0);
+        }
+    }
+
+    ASSERT(m_handles.isEmpty());
+    m_handlesByConnection.clear();
+    m_lockMap.clear();
+}
+
</ins><span class="cx"> } // namespace WebKit
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessstorageFileSystemStorageManagerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/storage/FileSystemStorageManager.h (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/storage/FileSystemStorageManager.h    2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/NetworkProcess/storage/FileSystemStorageManager.h       2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -49,6 +49,8 @@
</span><span class="cx">     bool releaseLockForFile(const String& path, WebCore::FileSystemHandleIdentifier);
</span><span class="cx"> 
</span><span class="cx"> private:
</span><ins>+    void close();
+
</ins><span class="cx">     String m_path;
</span><span class="cx">     FileSystemStorageHandleRegistry& m_registry;
</span><span class="cx">     HashMap<IPC::Connection::UniqueID, HashSet<WebCore::FileSystemHandleIdentifier>> m_handlesByConnection;
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessstorageNetworkStorageManagercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/storage/NetworkStorageManager.cpp (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/storage/NetworkStorageManager.cpp     2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/NetworkProcess/storage/NetworkStorageManager.cpp        2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -30,11 +30,69 @@
</span><span class="cx"> #include "FileSystemStorageManager.h"
</span><span class="cx"> #include "NetworkStorageManagerMessages.h"
</span><span class="cx"> #include "OriginStorageManager.h"
</span><ins>+#include "WebsiteDataType.h"
</ins><span class="cx"> #include <pal/crypto/CryptoDigest.h>
</span><ins>+#include <wtf/Scope.h>
+#include <wtf/persistence/PersistentDecoder.h>
+#include <wtf/persistence/PersistentEncoder.h>
</ins><span class="cx"> #include <wtf/text/Base64.h>
</span><span class="cx"> 
</span><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><ins>+static std::optional<WebCore::ClientOrigin> readOriginFromFile(const String& filePath)
+{
+    ASSERT(!RunLoop::isMain());
+
+    if (!FileSystem::fileExists(filePath))
+        return std::nullopt;
+
+    auto originFileHandle = FileSystem::openFile(filePath, FileSystem::FileOpenMode::Read);
+    auto closeFile = makeScopeExit([&] {
+        FileSystem::closeFile(originFileHandle);
+    });
+
+    if (!FileSystem::isHandleValid(originFileHandle))
+        return std::nullopt;
+
+    auto originContent = FileSystem::readEntireFile(originFileHandle);
+    if (!originContent)
+        return std::nullopt;
+
+    WTF::Persistence::Decoder decoder({ originContent->data(), originContent->size() });
+    std::optional<WebCore::ClientOrigin> origin;
+    decoder >> origin;
+    return origin;
+}
+
+static void writeOriginToFileIfNecessary(const String& filePath, const WebCore::ClientOrigin& origin)
+{
+    if (FileSystem::fileExists(filePath))
+        return;
+
+    FileSystem::makeAllDirectories(FileSystem::parentPath(filePath));
+    auto originFileHandle = FileSystem::openFile(filePath, FileSystem::FileOpenMode::ReadWrite);
+    auto closeFile = makeScopeExit([&] {
+        FileSystem::closeFile(originFileHandle);
+    });
+
+    if (!FileSystem::isHandleValid(originFileHandle)) {
+        LOG_ERROR("writeOriginToFileIfNecessary: Failed to open origin file");
+        return;
+    }
+
+    WTF::Persistence::Encoder encoder;
+    encoder << origin;
+    FileSystem::writeToFile(originFileHandle, encoder.buffer(), encoder.bufferSize());
+}
+
+static void deleteOriginFileIfNecessary(const String& filePath)
+{
+    auto parentPath = FileSystem::parentPath(filePath);
+    auto children = FileSystem::listDirectory(parentPath);
+    if (children.size() == 1)
+        FileSystem::deleteFile(filePath);
+}
+
</ins><span class="cx"> Ref<NetworkStorageManager> NetworkStorageManager::create(PAL::SessionID sessionID, const String& path)
</span><span class="cx"> {
</span><span class="cx">     return adoptRef(*new NetworkStorageManager(sessionID, path));
</span><span class="lines">@@ -116,7 +174,7 @@
</span><span class="cx">     return base64URLEncodeToString(hash.data(), hash.size());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static String originPath(const String& rootPath, const WebCore::ClientOrigin& origin, FileSystem::Salt salt)
</del><ins>+static String originDirectoryPath(const String& rootPath, const WebCore::ClientOrigin& origin, FileSystem::Salt salt)
</ins><span class="cx"> {
</span><span class="cx">     if (rootPath.isEmpty())
</span><span class="cx">         return rootPath;
</span><span class="lines">@@ -126,15 +184,30 @@
</span><span class="cx">     return FileSystem::pathByAppendingComponents(rootPath, { encodedTopOrigin, encodedOpeningOrigin });
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static String originFilePath(const String& directory)
+{
+    return FileSystem::pathByAppendingComponent(directory, "origin"_s);
+}
+
</ins><span class="cx"> OriginStorageManager& NetworkStorageManager::localOriginStorageManager(const WebCore::ClientOrigin& origin)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="cx"> 
</span><span class="cx">     return *m_localOriginStorageManagers.ensure(origin, [&] {
</span><del>-        return makeUnique<OriginStorageManager>(originPath(m_path, origin, m_salt));
</del><ins>+        auto originDirectory = originDirectoryPath(m_path, origin, m_salt);
+        writeOriginToFileIfNecessary(originFilePath(originDirectory), origin);
+        return makeUnique<OriginStorageManager>(WTFMove(originDirectory));
</ins><span class="cx">     }).iterator->value;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void NetworkStorageManager::removeOriginStorageManagerIfPossible(const WebCore::ClientOrigin& origin)
+{
+    if (auto iterator = m_localOriginStorageManagers.find(origin); iterator != m_localOriginStorageManagers.end()) {
+        if (!iterator->value->isActive())
+            m_localOriginStorageManagers.remove(iterator);
+    }
+}
+
</ins><span class="cx"> void NetworkStorageManager::persisted(const WebCore::ClientOrigin& origin, CompletionHandler<void(bool)>&& completionHandler)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><span class="lines">@@ -305,5 +378,162 @@
</span><span class="cx">     completionHandler(handle->getHandle(connection.uniqueID(), WTFMove(name)));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static std::optional<WebsiteDataType> toWebsiteDataType(const String& storageType)
+{
+    if (storageType == "FileSystem")
+        return WebsiteDataType::FileSystem;
+
+    return std::nullopt;
+}
+
+void NetworkStorageManager::forEachOriginDirectory(const Function<void(const String&)>& apply)
+{
+    for (auto& topOrigin : FileSystem::listDirectory(m_path)) {
+        auto topOriginDirectory = FileSystem::pathByAppendingComponent(m_path, topOrigin);
+        auto openingOrigins = FileSystem::listDirectory(topOriginDirectory);
+        if (openingOrigins.isEmpty()) {
+            FileSystem::deleteEmptyDirectory(topOriginDirectory);
+            continue;
+        }
+
+        for (auto& openingOrigin : openingOrigins) {
+            auto openingOriginDirectory = FileSystem::pathByAppendingComponent(topOriginDirectory, openingOrigin);
+            apply(openingOriginDirectory);
+        }
+    }
+}
+
+Vector<WebsiteData::Entry> NetworkStorageManager::fetchDataFromDisk(OptionSet<WebsiteDataType> targetTypes)
+{
+    ASSERT(!RunLoop::isMain());
+
+    HashMap<WebCore::SecurityOriginData, OptionSet<WebsiteDataType>> originTypes;
+    forEachOriginDirectory([&](auto directory) mutable {
+        auto origin = readOriginFromFile(originFilePath(directory));
+        if (!origin)
+            return;
+
+        for (auto& storageType : FileSystem::listDirectory(directory)) {
+            if (auto type = toWebsiteDataType(storageType); type && targetTypes.contains(*type)) {
+                // Return both top origin and opening origin for this data.
+                originTypes.add(origin->clientOrigin, OptionSet<WebsiteDataType> { }).iterator->value.add(*type);
+                originTypes.add(origin->topOrigin, OptionSet<WebsiteDataType> { }).iterator->value.add(*type);
+            }
+        }
+    });
+
+    Vector<WebsiteData::Entry> entries;
+    for (auto [origin, types] : originTypes) {
+        for (auto type : types)
+            entries.append({ WebsiteData::Entry { origin, type, 0 } });
+    }
+
+    return entries;
+}
+
+void NetworkStorageManager::fetchData(OptionSet<WebsiteDataType> types, CompletionHandler<void(Vector<WebsiteData::Entry>&&)>&& completionHandler)
+{
+    ASSERT(RunLoop::isMain());
+    ASSERT(!m_closed);
+
+    m_queue->dispatch([this, protectedThis = Ref { *this }, types, completionHandler = WTFMove(completionHandler)]() mutable {
+        auto entries = fetchDataFromDisk(types);
+        RunLoop::main().dispatch([protectedThis = WTFMove(protectedThis), completionHandler = WTFMove(completionHandler), entries = crossThreadCopy(WTFMove(entries))]() mutable {
+            completionHandler(WTFMove(entries));
+        });
+    });
+}
+
+Vector<WebCore::ClientOrigin> NetworkStorageManager::deleteDataOnDisk(OptionSet<WebsiteDataType> types, WallTime modifiedSinceTime, const Function<bool(const WebCore::ClientOrigin&)>& filter)
+{
+    ASSERT(!RunLoop::isMain());
+
+    Vector<WebCore::ClientOrigin> deletedOrigins;
+    forEachOriginDirectory([&](auto directory) mutable {
+        auto filePath = originFilePath(directory);
+        auto origin = readOriginFromFile(filePath);
+        if (!origin) {
+            // If origin cannot be retrieved, but we are asked to remove data for all origins, remove it.
+            RELEASE_LOG_ERROR(Storage, "NetworkStorageManager::deleteDataOnDisk failed to read origin from '%s'", filePath.utf8().data());
+            if (filter(WebCore::ClientOrigin { })) {
+                FileSystem::deleteAllFilesModifiedSince(directory, modifiedSinceTime);
+                FileSystem::deleteEmptyDirectory(directory);
+            }
+            return;
+        }
+
+        if (!filter(*origin))
+            return;
+
+        deletedOrigins.append(*origin);
+        localOriginStorageManager(*origin).deleteData(types, modifiedSinceTime);
+        removeOriginStorageManagerIfPossible(*origin);
+        deleteOriginFileIfNecessary(filePath);
+        FileSystem::deleteEmptyDirectory(directory);
+    });
+
+    return deletedOrigins;
+}
+
+void NetworkStorageManager::deleteData(OptionSet<WebsiteDataType> types, const Vector<WebCore::SecurityOriginData>& origins, CompletionHandler<void()>&& completionHandler)
+{
+    ASSERT(RunLoop::isMain());
+    ASSERT(!m_closed);
+
+    m_queue->dispatch([this, protectedThis = Ref { *this }, types, origins = crossThreadCopy(origins), completionHandler = WTFMove(completionHandler)]() mutable {
+        HashSet<WebCore::SecurityOriginData> originSet;
+        originSet.reserveInitialCapacity(origins.size());
+        for (auto origin : origins)
+            originSet.add(WTFMove(origin));
+
+        deleteDataOnDisk(types, -WallTime::infinity(), [&originSet](auto origin) {
+            return originSet.contains(origin.topOrigin) || originSet.contains(origin.clientOrigin);
+        });
+
+        RunLoop::main().dispatch([protectedThis = WTFMove(protectedThis), completionHandler = WTFMove(completionHandler)]() mutable {
+            completionHandler();
+        });
+    });
+}
+
+void NetworkStorageManager::deleteDataModifiedSince(OptionSet<WebsiteDataType> types, WallTime modifiedSinceTime, CompletionHandler<void()>&& completionHandler)
+{
+    ASSERT(RunLoop::isMain());
+    ASSERT(!m_closed);
+
+    m_queue->dispatch([this, protectedThis = Ref { *this }, types, modifiedSinceTime, completionHandler = WTFMove(completionHandler)]() mutable {
+        deleteDataOnDisk(types, modifiedSinceTime, [](auto&) {
+            return true;
+        });
+
+        RunLoop::main().dispatch([protectedThis = WTFMove(protectedThis), completionHandler = WTFMove(completionHandler)]() mutable {
+            completionHandler();
+        });
+    });
+}
+
+void NetworkStorageManager::deleteDataForRegistrableDomains(OptionSet<WebsiteDataType> types, const Vector<WebCore::RegistrableDomain>& domains, CompletionHandler<void(HashSet<WebCore::RegistrableDomain>&&)>&& completionHandler)
+{
+    ASSERT(RunLoop::isMain());
+    ASSERT(!m_closed);
+
+    m_queue->dispatch([this, protectedThis = Ref { *this }, types, domains = crossThreadCopy(domains), completionHandler = WTFMove(completionHandler)]() mutable {
+        auto deletedOrigins = deleteDataOnDisk(types, -WallTime::infinity(), [&domains](auto& origin) {
+            auto domain = WebCore::RegistrableDomain::uncheckedCreateFromHost(origin.clientOrigin.host);
+            return domains.contains(domain);
+        });
+
+        HashSet<WebCore::RegistrableDomain> deletedDomains;
+        for (auto origin : deletedOrigins) {
+            auto domain = WebCore::RegistrableDomain::uncheckedCreateFromHost(origin.clientOrigin.host);
+            deletedDomains.add(domain);
+        }
+
+        RunLoop::main().dispatch([protectedThis = WTFMove(protectedThis), completionHandler = WTFMove(completionHandler), domains = crossThreadCopy(WTFMove(deletedDomains))]() mutable {
+            completionHandler(WTFMove(domains));
+        });
+    });
+}
+
</ins><span class="cx"> } // namespace WebKit
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessstorageNetworkStorageManagerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/storage/NetworkStorageManager.h (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/storage/NetworkStorageManager.h       2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/NetworkProcess/storage/NetworkStorageManager.h  2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -28,10 +28,12 @@
</span><span class="cx"> #include "Connection.h"
</span><span class="cx"> #include "FileSystemStorageError.h"
</span><span class="cx"> #include "OriginStorageManager.h"
</span><ins>+#include "WebsiteData.h"
</ins><span class="cx"> #include <WebCore/ClientOrigin.h>
</span><span class="cx"> #include <WebCore/FileSystemHandleIdentifier.h>
</span><span class="cx"> #include <WebCore/FileSystemSyncAccessHandleIdentifier.h>
</span><span class="cx"> #include <pal/SessionID.h>
</span><ins>+#include <wtf/Forward.h>
</ins><span class="cx"> 
</span><span class="cx"> namespace IPC {
</span><span class="cx"> class SharedFileHandle;
</span><span class="lines">@@ -55,13 +57,22 @@
</span><span class="cx">     PAL::SessionID sessionID() const { return m_sessionID; }
</span><span class="cx">     void close();
</span><span class="cx">     void clearStorageForTesting(CompletionHandler<void()>&&);
</span><ins>+    void fetchData(OptionSet<WebsiteDataType>, CompletionHandler<void(Vector<WebsiteData::Entry>&&)>&&);
+    void deleteData(OptionSet<WebsiteDataType>, const Vector<WebCore::SecurityOriginData>&, CompletionHandler<void()>&&);
+    void deleteDataModifiedSince(OptionSet<WebsiteDataType>, WallTime, CompletionHandler<void()>&&);
+    void deleteDataForRegistrableDomains(OptionSet<WebsiteDataType>, const Vector<WebCore::RegistrableDomain>&, CompletionHandler<void(HashSet<WebCore::RegistrableDomain>&&)>&&);
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     NetworkStorageManager(PAL::SessionID, const String& path);
</span><span class="cx">     ~NetworkStorageManager();
</span><span class="cx">     OriginStorageManager& localOriginStorageManager(const WebCore::ClientOrigin&);
</span><ins>+    void removeOriginStorageManagerIfPossible(const WebCore::ClientOrigin&);
</ins><span class="cx">     FileSystemStorageHandleRegistry& fileSystemStorageHandleRegistry();
</span><span class="cx"> 
</span><ins>+    void forEachOriginDirectory(const Function<void(const String&)>&);
+    Vector<WebsiteData::Entry> fetchDataFromDisk(OptionSet<WebsiteDataType>);
+    Vector<WebCore::ClientOrigin> deleteDataOnDisk(OptionSet<WebsiteDataType>, WallTime, const Function<bool(const WebCore::ClientOrigin&)>&);
+
</ins><span class="cx">     // IPC::MessageReceiver (implemented by generated code)
</span><span class="cx">     void didReceiveMessage(IPC::Connection&, IPC::Decoder&);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessstorageOriginStorageManagercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/storage/OriginStorageManager.cpp (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/storage/OriginStorageManager.cpp      2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/NetworkProcess/storage/OriginStorageManager.cpp 2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -51,20 +51,61 @@
</span><span class="cx">             m_fileSystemStorageManager->connectionClosed(connection);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    String typeStoragePath(const String& storageIdentifier) const
</del><ins>+    enum class StorageType : uint8_t {
+        FileSystem,
+    };
+
+    static String toStorageIdentifier(StorageType type)
</ins><span class="cx">     {
</span><del>-        return m_rootPath.isEmpty() ? emptyString() : FileSystem::pathByAppendingComponent(m_rootPath, storageIdentifier);
</del><ins>+        switch (type) {
+        case StorageType::FileSystem:
+            return "FileSystem"_s;
+        default:
+            break;
+        }
+        ASSERT_NOT_REACHED();
+        return ""_s;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    String typeStoragePath(StorageType type) const
+    {
+        auto storageIdentifier = toStorageIdentifier(type);
+        if (m_rootPath.isEmpty() || storageIdentifier.isEmpty())
+            return emptyString();
+
+        return FileSystem::pathByAppendingComponent(m_rootPath, storageIdentifier);
+    }
+
</ins><span class="cx">     FileSystemStorageManager& fileSystemStorageManager(FileSystemStorageHandleRegistry& registry)
</span><span class="cx">     {
</span><span class="cx">         if (!m_fileSystemStorageManager)
</span><del>-            m_fileSystemStorageManager = makeUnique<FileSystemStorageManager>(typeStoragePath("FileSystem"), registry);
</del><ins>+            m_fileSystemStorageManager = makeUnique<FileSystemStorageManager>(typeStoragePath(StorageType::FileSystem), registry);
</ins><span class="cx"> 
</span><span class="cx">         return *m_fileSystemStorageManager;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    bool isActive()
+    {
+        return !!m_fileSystemStorageManager;
+    }
+
+    void deleteData(OptionSet<WebsiteDataType> types, WallTime modifiedSinceTime)
+    {
+        if (types.contains(WebsiteDataType::FileSystem))
+            deleteFileSystemStorageData(modifiedSinceTime);
+
+        FileSystem::deleteNonEmptyDirectory(m_rootPath);
+    }
+
</ins><span class="cx"> private:
</span><ins>+    void deleteFileSystemStorageData(WallTime modifiedSinceTime)
+    {
+        m_fileSystemStorageManager = nullptr;
+
+        auto fileSystemStoragePath = typeStoragePath(StorageType::FileSystem);
+        FileSystem::deleteAllFilesModifiedSince(fileSystemStoragePath, modifiedSinceTime);
+    }
+
</ins><span class="cx">     String m_rootPath;
</span><span class="cx">     String m_identifier;
</span><span class="cx">     StorageBucketMode m_mode { StorageBucketMode::BestEffort };
</span><span class="lines">@@ -74,6 +115,7 @@
</span><span class="cx"> OriginStorageManager::OriginStorageManager(String&& path)
</span><span class="cx">     : m_path(WTFMove(path))
</span><span class="cx"> {
</span><ins>+    ASSERT(!RunLoop::isMain());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> OriginStorageManager::~OriginStorageManager() = default;
</span><span class="lines">@@ -103,5 +145,16 @@
</span><span class="cx">     return defaultBucket().fileSystemStorageManager(registry);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool OriginStorageManager::isActive()
+{
+    return defaultBucket().isActive();
+}
+
+void OriginStorageManager::deleteData(OptionSet<WebsiteDataType> types, WallTime modifiedSince)
+{
+    ASSERT(!RunLoop::isMain());
+    defaultBucket().deleteData(types, modifiedSince);
+}
+
</ins><span class="cx"> } // namespace WebKit
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitNetworkProcessstorageOriginStorageManagerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/NetworkProcess/storage/OriginStorageManager.h (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/NetworkProcess/storage/OriginStorageManager.h        2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/NetworkProcess/storage/OriginStorageManager.h   2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -28,10 +28,15 @@
</span><span class="cx"> #include "Connection.h"
</span><span class="cx"> #include <wtf/text/WTFString.h>
</span><span class="cx"> 
</span><ins>+namespace WebCore {
+struct ClientOrigin;
+}
+
</ins><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><span class="cx"> class FileSystemStorageHandleRegistry;
</span><span class="cx"> class FileSystemStorageManager;
</span><ins>+enum class WebsiteDataType : uint32_t;
</ins><span class="cx"> 
</span><span class="cx"> class OriginStorageManager {
</span><span class="cx">     WTF_MAKE_FAST_ALLOCATED;
</span><span class="lines">@@ -43,6 +48,8 @@
</span><span class="cx">     bool persisted() const { return m_persisted; }
</span><span class="cx">     void persist();
</span><span class="cx">     FileSystemStorageManager& fileSystemStorageManager(FileSystemStorageHandleRegistry&);
</span><ins>+    bool isActive();
+    void deleteData(OptionSet<WebsiteDataType>, WallTime);
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     enum class StorageBucketMode : bool;
</span><span class="lines">@@ -49,6 +56,9 @@
</span><span class="cx">     class StorageBucket;
</span><span class="cx">     StorageBucket& defaultBucket();
</span><span class="cx"> 
</span><ins>+    void createOriginFileIfNecessary(const WebCore::ClientOrigin&);
+    void deleteOriginFileIfNecessary();
+
</ins><span class="cx">     std::unique_ptr<StorageBucket> m_defaultBucket;
</span><span class="cx">     String m_path;
</span><span class="cx">     bool m_persisted { false };
</span></span></pre></div>
<a id="trunkSourceWebKitSharedWebsiteDataWebsiteDatacpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/Shared/WebsiteData/WebsiteData.cpp (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/Shared/WebsiteData/WebsiteData.cpp   2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/Shared/WebsiteData/WebsiteData.cpp      2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -129,6 +129,8 @@
</span><span class="cx">     case WebsiteDataType::AlternativeServices:
</span><span class="cx">         return WebsiteDataProcessType::Network;
</span><span class="cx"> #endif
</span><ins>+    case WebsiteDataType::FileSystem:
+        return WebsiteDataProcessType::Network;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     RELEASE_ASSERT_NOT_REACHED();
</span></span></pre></div>
<a id="trunkSourceWebKitSharedWebsiteDataWebsiteDataTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/Shared/WebsiteData/WebsiteDataType.h (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/Shared/WebsiteData/WebsiteDataType.h 2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/Shared/WebsiteData/WebsiteDataType.h    2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -52,6 +52,7 @@
</span><span class="cx"> #if HAVE(CFNETWORK_ALTERNATIVE_SERVICE)
</span><span class="cx">     AlternativeServices = 1 << 18,
</span><span class="cx"> #endif
</span><ins>+    FileSystem = 1 << 19,
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebKit
</span><span class="lines">@@ -79,10 +80,11 @@
</span><span class="cx"> #endif
</span><span class="cx">         WebKit::WebsiteDataType::DOMCache,
</span><span class="cx">         WebKit::WebsiteDataType::DeviceIdHashSalt,
</span><del>-        WebKit::WebsiteDataType::PrivateClickMeasurements
</del><ins>+        WebKit::WebsiteDataType::PrivateClickMeasurements,
</ins><span class="cx"> #if HAVE(CFNETWORK_ALTERNATIVE_SERVICE)
</span><del>-        , WebKit::WebsiteDataType::AlternativeServices
</del><ins>+        WebKit::WebsiteDataType::AlternativeServices,
</ins><span class="cx"> #endif
</span><ins>+        WebKit::WebsiteDataType::FileSystem
</ins><span class="cx">     >;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPICocoaWKWebsiteDataRecordmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataRecord.mm (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataRecord.mm   2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataRecord.mm      2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -51,6 +51,7 @@
</span><span class="cx"> NSString * const _WKWebsiteDataTypeAdClickAttributions = @"_WKWebsiteDataTypeAdClickAttributions";
</span><span class="cx"> NSString * const _WKWebsiteDataTypePrivateClickMeasurements = @"_WKWebsiteDataTypePrivateClickMeasurements";
</span><span class="cx"> NSString * const _WKWebsiteDataTypeAlternativeServices = @"_WKWebsiteDataTypeAlternativeServices";
</span><ins>+NSString * const _WKWebsiteDataTypeFileSystem = @"_WKWebsiteDataTypeFileSystem";
</ins><span class="cx"> 
</span><span class="cx"> #if PLATFORM(MAC)
</span><span class="cx"> NSString * const _WKWebsiteDataTypePlugInData = @"_WKWebsiteDataTypePlugInData";
</span><span class="lines">@@ -110,6 +111,8 @@
</span><span class="cx">         [array addObject:@"Private Click Measurements"];
</span><span class="cx">     if ([dataTypes containsObject:_WKWebsiteDataTypeAlternativeServices])
</span><span class="cx">         [array addObject:@"Alternative Services"];
</span><ins>+    if ([dataTypes containsObject:_WKWebsiteDataTypeFileSystem])
+        [array addObject:@"File System"];
</ins><span class="cx"> 
</span><span class="cx">     return [array componentsJoinedByString:@", "];
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPICocoaWKWebsiteDataRecordInternalh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataRecordInternal.h (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataRecordInternal.h    2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataRecordInternal.h       2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -77,6 +77,8 @@
</span><span class="cx">     if ([websiteDataType isEqualToString:_WKWebsiteDataTypeAlternativeServices])
</span><span class="cx">         return WebsiteDataType::AlternativeServices;
</span><span class="cx"> #endif
</span><ins>+    if ([websiteDataType isEqualToString:_WKWebsiteDataTypeFileSystem])
+        return WebsiteDataType::FileSystem;
</ins><span class="cx">     return std::nullopt;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -134,6 +136,8 @@
</span><span class="cx">     if (websiteDataTypes.contains(WebsiteDataType::AlternativeServices))
</span><span class="cx">         [wkWebsiteDataTypes addObject:_WKWebsiteDataTypeAlternativeServices];
</span><span class="cx"> #endif
</span><ins>+    if (websiteDataTypes.contains(WebsiteDataType::FileSystem))
+        [wkWebsiteDataTypes addObject:_WKWebsiteDataTypeFileSystem];
</ins><span class="cx"> 
</span><span class="cx">     return wkWebsiteDataTypes;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPICocoaWKWebsiteDataRecordPrivateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataRecordPrivate.h (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataRecordPrivate.h     2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataRecordPrivate.h        2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -37,6 +37,7 @@
</span><span class="cx"> WK_EXTERN NSString * const _WKWebsiteDataTypeAdClickAttributions WK_API_AVAILABLE(macos(10.15), ios(13.0));
</span><span class="cx"> WK_EXTERN NSString * const _WKWebsiteDataTypePrivateClickMeasurements WK_API_AVAILABLE(macos(12.0), ios(15.0));
</span><span class="cx"> WK_EXTERN NSString * const _WKWebsiteDataTypeAlternativeServices WK_API_AVAILABLE(macos(11.0), ios(14.0));
</span><ins>+WK_EXTERN NSString * const _WKWebsiteDataTypeFileSystem WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
</ins><span class="cx"> 
</span><span class="cx"> #if !TARGET_OS_IPHONE
</span><span class="cx"> WK_EXTERN NSString * const _WKWebsiteDataTypePlugInData WK_API_AVAILABLE(macos(10.11));
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPICocoaWKWebsiteDataStoremm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm    2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm       2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -248,7 +248,8 @@
</span><span class="cx">             _WKWebsiteDataTypeCredentials,
</span><span class="cx">             _WKWebsiteDataTypeAdClickAttributions,
</span><span class="cx">             _WKWebsiteDataTypePrivateClickMeasurements,
</span><del>-            _WKWebsiteDataTypeAlternativeServices
</del><ins>+            _WKWebsiteDataTypeAlternativeServices,
+            _WKWebsiteDataTypeFileSystem
</ins><span class="cx"> #if !TARGET_OS_IPHONE
</span><span class="cx">             , _WKWebsiteDataTypePlugInData
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebKitWebKitxcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj     2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj        2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -1499,6 +1499,9 @@
</span><span class="cx">          93D6B7B5255268D70058DD3A /* SpeechRecognitionPermissionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D6B7B2255268A20058DD3A /* SpeechRecognitionPermissionManager.h */; };
</span><span class="cx">          93D6B7B925534A170058DD3A /* WKSpeechRecognitionPermissionCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D6B7B725534A110058DD3A /* WKSpeechRecognitionPermissionCallback.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">          93E6A4EE1BC5DD3900F8A0E7 /* _WKHitTestResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 93E6A4ED1BC5DD3900F8A0E7 /* _WKHitTestResult.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+               93E799852756FA550074008A /* WebFileSystemStorageConnectionMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93E799822756FA540074008A /* WebFileSystemStorageConnectionMessageReceiver.cpp */; };
+               93E799872756FAB40074008A /* WebFileSystemStorageConnectionMessagesReplies.h in Headers */ = {isa = PBXBuildFile; fileRef = 93E799832756FA540074008A /* WebFileSystemStorageConnectionMessagesReplies.h */; };
+               93E799882756FAC20074008A /* WebFileSystemStorageConnectionMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 93E799812756FA530074008A /* WebFileSystemStorageConnectionMessages.h */; };
</ins><span class="cx">           93F549B41E3174B7000E7239 /* WKSnapshotConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 93F549B31E3174B7000E7239 /* WKSnapshotConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
</span><span class="cx">          950F2880252414EA00B74F1C /* WKMouseDeviceObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 950F287E252414E900B74F1C /* WKMouseDeviceObserver.h */; };
</span><span class="cx">          9565083926D87A2B00E15CB7 /* AppleMediaServicesSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 9565083726D87A2B00E15CB7 /* AppleMediaServicesSPI.h */; };
</span><span class="lines">@@ -5301,6 +5304,10 @@
</span><span class="cx">          93D6B7B725534A110058DD3A /* WKSpeechRecognitionPermissionCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKSpeechRecognitionPermissionCallback.h; sourceTree = "<group>"; };
</span><span class="cx">          93D6B7B825534A120058DD3A /* WKSpeechRecognitionPermissionCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKSpeechRecognitionPermissionCallback.cpp; sourceTree = "<group>"; };
</span><span class="cx">          93E6A4ED1BC5DD3900F8A0E7 /* _WKHitTestResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKHitTestResult.h; sourceTree = "<group>"; };
</span><ins>+               93E7997E2756F6700074008A /* WebFileSystemStorageConnection.messages.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebFileSystemStorageConnection.messages.in; sourceTree = "<group>"; };
+               93E799812756FA530074008A /* WebFileSystemStorageConnectionMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebFileSystemStorageConnectionMessages.h; sourceTree = "<group>"; };
+               93E799822756FA540074008A /* WebFileSystemStorageConnectionMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebFileSystemStorageConnectionMessageReceiver.cpp; sourceTree = "<group>"; };
+               93E799832756FA540074008A /* WebFileSystemStorageConnectionMessagesReplies.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebFileSystemStorageConnectionMessagesReplies.h; sourceTree = "<group>"; };
</ins><span class="cx">           93F549B31E3174B7000E7239 /* WKSnapshotConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKSnapshotConfiguration.h; sourceTree = "<group>"; };
</span><span class="cx">          93F549B51E3174DA000E7239 /* WKSnapshotConfiguration.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKSnapshotConfiguration.mm; sourceTree = "<group>"; };
</span><span class="cx">          950F287E252414E900B74F1C /* WKMouseDeviceObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WKMouseDeviceObserver.h; path = ios/WKMouseDeviceObserver.h; sourceTree = "<group>"; };
</span><span class="lines">@@ -10582,6 +10589,7 @@
</span><span class="cx">                          BC032D6810F4378D0058C15A /* WebEditorClient.h */,
</span><span class="cx">                          9354242B2703BDCB005CA72C /* WebFileSystemStorageConnection.cpp */,
</span><span class="cx">                          9354242A2703BDCB005CA72C /* WebFileSystemStorageConnection.h */,
</span><ins>+                               93E7997E2756F6700074008A /* WebFileSystemStorageConnection.messages.in */,
</ins><span class="cx">                           BC111A58112F4FBB00337BAB /* WebFrameLoaderClient.cpp */,
</span><span class="cx">                          BC032D6A10F4378D0058C15A /* WebFrameLoaderClient.h */,
</span><span class="cx">                          BC1BE1DF12D54A410004A228 /* WebGeolocationClient.cpp */,
</span><span class="lines">@@ -12059,6 +12067,9 @@
</span><span class="cx">                          E3866B072399979D00F88FE9 /* WebDeviceOrientationUpdateProviderMessages.h */,
</span><span class="cx">                          E3866B042399979C00F88FE9 /* WebDeviceOrientationUpdateProviderProxyMessageReceiver.cpp */,
</span><span class="cx">                          E3866B052399979C00F88FE9 /* WebDeviceOrientationUpdateProviderProxyMessages.h */,
</span><ins>+                               93E799822756FA540074008A /* WebFileSystemStorageConnectionMessageReceiver.cpp */,
+                               93E799812756FA530074008A /* WebFileSystemStorageConnectionMessages.h */,
+                               93E799832756FA540074008A /* WebFileSystemStorageConnectionMessagesReplies.h */,
</ins><span class="cx">                           CD73BA48131ACD8E00EEDED2 /* WebFullScreenManagerMessageReceiver.cpp */,
</span><span class="cx">                          CD73BA49131ACD8E00EEDED2 /* WebFullScreenManagerMessages.h */,
</span><span class="cx">                          CD73BA45131ACC8800EEDED2 /* WebFullScreenManagerProxyMessageReceiver.cpp */,
</span><span class="lines">@@ -13306,6 +13317,8 @@
</span><span class="cx">                          BC032DBB10F4380F0058C15A /* WebEventConversion.h in Headers */,
</span><span class="cx">                          BC111B5D112F629800337BAB /* WebEventFactory.h in Headers */,
</span><span class="cx">                          9354242C2703BDCB005CA72C /* WebFileSystemStorageConnection.h in Headers */,
</span><ins>+                               93E799882756FAC20074008A /* WebFileSystemStorageConnectionMessages.h in Headers */,
+                               93E799872756FAB40074008A /* WebFileSystemStorageConnectionMessagesReplies.h in Headers */,
</ins><span class="cx">                           1A90C1EE1264FD50003E44D4 /* WebFindOptions.h in Headers */,
</span><span class="cx">                          BCE469541214E6CB000B98EB /* WebFormClient.h in Headers */,
</span><span class="cx">                          BCE469561214E6CB000B98EB /* WebFormSubmissionListenerProxy.h in Headers */,
</span><span class="lines">@@ -15402,6 +15415,7 @@
</span><span class="cx">                          E3866AE52397400400F88FE9 /* WebDeviceOrientationUpdateProviderProxy.mm in Sources */,
</span><span class="cx">                          E3866B092399A2D500F88FE9 /* WebDeviceOrientationUpdateProviderProxyMessageReceiver.cpp in Sources */,
</span><span class="cx">                          2D92A789212B6AB100F493FD /* WebEvent.cpp in Sources */,
</span><ins>+                               93E799852756FA550074008A /* WebFileSystemStorageConnectionMessageReceiver.cpp in Sources */,
</ins><span class="cx">                           CD73BA4E131ACDB700EEDED2 /* WebFullScreenManagerMessageReceiver.cpp in Sources */,
</span><span class="cx">                          CD73BA47131ACC9A00EEDED2 /* WebFullScreenManagerProxyMessageReceiver.cpp in Sources */,
</span><span class="cx">                          BC0E606112D6BA910012A72A /* WebGeolocationManagerMessageReceiver.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceWebKitWebProcessNetworkNetworkProcessConnectioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/WebProcess/Network/NetworkProcessConnection.cpp (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/WebProcess/Network/NetworkProcessConnection.cpp      2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Source/WebKit/WebProcess/Network/NetworkProcessConnection.cpp 2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -37,6 +37,8 @@
</span><span class="cx"> #include "WebCacheStorageProvider.h"
</span><span class="cx"> #include "WebCookieJar.h"
</span><span class="cx"> #include "WebCoreArgumentCoders.h"
</span><ins>+#include "WebFileSystemStorageConnection.h"
+#include "WebFileSystemStorageConnectionMessages.h"
</ins><span class="cx"> #include "WebFrame.h"
</span><span class="cx"> #include "WebIDBConnectionToServer.h"
</span><span class="cx"> #include "WebIDBConnectionToServerMessages.h"
</span><span class="lines">@@ -119,6 +121,10 @@
</span><span class="cx">             storageAreaMap->didReceiveMessage(connection, decoder);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><ins>+    if (decoder.messageReceiverName() == Messages::WebFileSystemStorageConnection::messageReceiverName()) {
+        WebProcess::singleton().fileSystemStorageConnection().didReceiveMessage(connection, decoder);
+        return;
+    }
</ins><span class="cx"> 
</span><span class="cx"> #if USE(LIBWEBRTC)
</span><span class="cx">     if (decoder.messageReceiverName() == Messages::WebRTCMonitor::messageReceiverName()) {
</span></span></pre></div>
<a id="trunkSourceWebKitWebProcessWebCoreSupportWebFileSystemStorageConnectionmessagesin"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFileSystemStorageConnection.messages.in (0 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFileSystemStorageConnection.messages.in                         (rev 0)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFileSystemStorageConnection.messages.in    2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -0,0 +1,25 @@
</span><ins>+# Copyright (C) 2021 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+messages -> WebFileSystemStorageConnection NotRefCounted {
+    InvalidateAccessHandle(WebCore::FileSystemSyncAccessHandleIdentifier identifier)
+}
</ins></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog    2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Tools/ChangeLog       2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -1,3 +1,12 @@
</span><ins>+2021-12-03  Sihui Liu  <sihui_liu@apple.com>
+
+        Fetch and remove file system data via WKWebsiteDataStore
+        https://bugs.webkit.org/show_bug.cgi?id=233567
+
+        Reviewed by Youenn Fablet.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/FileSystemAccess.mm:
+
</ins><span class="cx"> 2021-12-03  Chris Dumez  <cdumez@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Follow-up to r286479 to add API test and address issues found by the test
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKitCocoaFileSystemAccessmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/FileSystemAccess.mm (286506 => 286507)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/FileSystemAccess.mm  2021-12-03 19:52:04 UTC (rev 286506)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/FileSystemAccess.mm     2021-12-03 20:17:15 UTC (rev 286507)
</span><span class="lines">@@ -29,11 +29,13 @@
</span><span class="cx"> 
</span><span class="cx"> #import "DeprecatedGlobalValues.h"
</span><span class="cx"> #import "PlatformUtilities.h"
</span><ins>+#import "TestUIDelegate.h"
</ins><span class="cx"> #import "TestURLSchemeHandler.h"
</span><span class="cx"> #import "TestWKWebView.h"
</span><span class="cx"> #import <WebKit/WKPreferencesPrivate.h>
</span><span class="cx"> #import <WebKit/WKWebViewConfigurationPrivate.h>
</span><span class="cx"> #import <WebKit/WKWebViewPrivate.h>
</span><ins>+#import <WebKit/WKWebsiteDataRecordPrivate.h>
</ins><span class="cx"> 
</span><span class="cx"> @interface FileSystemAccessMessageHandler : NSObject <WKScriptMessageHandler>
</span><span class="cx"> @end
</span><span class="lines">@@ -48,7 +50,7 @@
</span><span class="cx"> 
</span><span class="cx"> @end
</span><span class="cx"> 
</span><del>-static NSString *mainFrameString = @"<script> \
</del><ins>+static NSString *workerFrameString = @"<script> \
</ins><span class="cx">     function start() { \
</span><span class="cx">         var worker = new Worker('worker.js'); \
</span><span class="cx">         worker.onmessage = function(event) { \
</span><span class="lines">@@ -115,7 +117,7 @@
</span><span class="cx">     [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webkit"];
</span><span class="cx"> 
</span><span class="cx">     auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
</span><del>-    [webView loadHTMLString:mainFrameString baseURL:[NSURL URLWithString:@"webkit://webkit.org"]];
</del><ins>+    [webView loadHTMLString:workerFrameString baseURL:[NSURL URLWithString:@"webkit://webkit.org"]];
</ins><span class="cx">     TestWebKitAPI::Util::run(&receivedScriptMessage);
</span><span class="cx">     receivedScriptMessage = false;
</span><span class="cx">     EXPECT_WK_STREQ(@"page is loaded", [lastScriptMessage body]);
</span><span class="lines">@@ -126,7 +128,7 @@
</span><span class="cx">     EXPECT_WK_STREQ(@"success: write 10 bytes", [lastScriptMessage body]);
</span><span class="cx"> 
</span><span class="cx">     auto secondWebView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
</span><del>-    [secondWebView loadHTMLString:mainFrameString baseURL:[NSURL URLWithString:@"webkit://webkit.org"]];
</del><ins>+    [secondWebView loadHTMLString:workerFrameString baseURL:[NSURL URLWithString:@"webkit://webkit.org"]];
</ins><span class="cx">     TestWebKitAPI::Util::run(&receivedScriptMessage);
</span><span class="cx">     receivedScriptMessage = false;
</span><span class="cx">     EXPECT_WK_STREQ(@"page is loaded", [lastScriptMessage body]);
</span><span class="lines">@@ -168,7 +170,7 @@
</span><span class="cx">     [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"webkit"];
</span><span class="cx"> 
</span><span class="cx">     auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
</span><del>-    [webView loadHTMLString:mainFrameString baseURL:[NSURL URLWithString:@"webkit://webkit.org"]];
</del><ins>+    [webView loadHTMLString:workerFrameString baseURL:[NSURL URLWithString:@"webkit://webkit.org"]];
</ins><span class="cx">     TestWebKitAPI::Util::run(&receivedScriptMessage);
</span><span class="cx">     receivedScriptMessage = false;
</span><span class="cx">     EXPECT_WK_STREQ(@"page is loaded", [lastScriptMessage body]);
</span><span class="lines">@@ -258,4 +260,196 @@
</span><span class="cx">     EXPECT_WK_STREQ(@"file is opened", [lastScriptMessage body]);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static NSString *testString = @"<script> \
+    async function open(shouldCreateFile) \
+    { \
+        try { \
+            var rootHandle = await navigator.storage.getDirectory(); \
+            var fileHandle = await rootHandle.getFileHandle('file-system-access.txt', { 'create' : shouldCreateFile }); \
+            window.webkit.messageHandlers.testHandler.postMessage('file is opened'); \
+        } catch(err) { \
+            window.webkit.messageHandlers.testHandler.postMessage('error: ' + err.name + ' - ' + err.message); \
+        } \
+    } \
+    open(true); \
+    </script>";
+
+TEST(FileSystemAccess, FetchAndRemoveData)
+{
+    auto handler = adoptNS([[FileSystemAccessMessageHandler alloc] init]);
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"testHandler"];
+    auto websiteDataStore = [configuration websiteDataStore];
+    auto types = [NSSet setWithObject:_WKWebsiteDataTypeFileSystem];
+
+    // Remove existing data.
+    done = false;
+    [websiteDataStore removeDataOfTypes:types modifiedSince:[NSDate distantPast] completionHandler:^ {
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+
+    auto preferences = [configuration preferences];
+    preferences._fileSystemAccessEnabled = YES;
+    preferences._storageAPIEnabled = YES;
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
+    [webView loadHTMLString:testString baseURL:[NSURL URLWithString:@"https://webkit.org"]];
+    TestWebKitAPI::Util::run(&receivedScriptMessage);
+    receivedScriptMessage = false;
+    EXPECT_WK_STREQ(@"file is opened", [lastScriptMessage body]);
+
+    // Fetch data and remove it by origin.
+    done = false;
+    [websiteDataStore fetchDataRecordsOfTypes:types completionHandler:^(NSArray<WKWebsiteDataRecord *> *records) {
+        EXPECT_EQ(records.count, 1u);
+        auto record = [records objectAtIndex:0];
+        EXPECT_STREQ("webkit.org", [record.displayName UTF8String]);
+
+        // Remove data.
+        [websiteDataStore removeDataOfTypes:types forDataRecords:records completionHandler:^{
+            done = true;
+        }];
+    }];
+    TestWebKitAPI::Util::run(&done);
+
+    // Fetch data after removal.
+    done = false;
+    [websiteDataStore fetchDataRecordsOfTypes:types completionHandler:^(NSArray<WKWebsiteDataRecord *> *records) {
+        EXPECT_EQ(records.count, 0u);
+        done = true;
+    }];
+
+    // File cannot be opened after data removal.
+    [webView evaluateJavaScript:@"open(false)" completionHandler:nil];
+    TestWebKitAPI::Util::run(&receivedScriptMessage);
+    receivedScriptMessage = false;
+    EXPECT_WK_STREQ(@"error: NotFoundError - The object can not be found here.", [lastScriptMessage body]);
+}
+
+TEST(FileSystemAccess, RemoveDataByModificationTime)
+{
+    auto handler = adoptNS([[FileSystemAccessMessageHandler alloc] init]);
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"testHandler"];
+    auto preferences = [configuration preferences];
+    preferences._fileSystemAccessEnabled = YES;
+    preferences._storageAPIEnabled = YES;
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
+    [webView loadHTMLString:testString baseURL:[NSURL URLWithString:@"https://webkit.org"]];
+    TestWebKitAPI::Util::run(&receivedScriptMessage);
+    receivedScriptMessage = false;
+    EXPECT_WK_STREQ(@"file is opened", [lastScriptMessage body]);
+
+    auto websiteDataStore = [configuration websiteDataStore];
+    auto types = [NSSet setWithObject:_WKWebsiteDataTypeFileSystem];
+    done = false;
+    __block NSUInteger recordsCount;
+    [websiteDataStore fetchDataRecordsOfTypes:types completionHandler:^(NSArray<WKWebsiteDataRecord *> *records) {
+        recordsCount = records.count;
+        EXPECT_GT(recordsCount, 0u);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+
+    done = false;
+    [websiteDataStore removeDataOfTypes:types modifiedSince:[NSDate now] completionHandler:^ {
+        [websiteDataStore fetchDataRecordsOfTypes:types completionHandler:^(NSArray<WKWebsiteDataRecord *> *records) {
+            recordsCount = records.count;
+            EXPECT_EQ(records.count, recordsCount);
+            done = true;
+        }];
+    }];
+    TestWebKitAPI::Util::run(&done);
+
+    done = false;
+    [websiteDataStore removeDataOfTypes:types modifiedSince:[NSDate distantPast] completionHandler:^ {
+        [websiteDataStore fetchDataRecordsOfTypes:types completionHandler:^(NSArray<WKWebsiteDataRecord *> *records) {
+            EXPECT_EQ(records.count, 0u);
+            done = true;
+        }];
+    }];
+    TestWebKitAPI::Util::run(&done);
+}
+
+static NSString *mainFrameString = @"<script> \
+    function postResult(event) \
+    { \
+        window.webkit.messageHandlers.testHandler.postMessage(event.data); \
+    } \
+    addEventListener('message', postResult, false); \
+    </script> \
+    <iframe src='https://127.0.0.1:9091/'>";
+
+static const char* frameBytes = R"TESTRESOURCE(
+<script>
+function postMessage(message)
+{
+    parent.postMessage(message, '*');
+}
+async function open()
+{
+    try {
+        var rootHandle = await navigator.storage.getDirectory();
+        var fileHandle = await rootHandle.getFileHandle('file-system-access.txt', { 'create' : true });
+        postMessage('file is opened');
+    } catch(err) {
+        postMessage('error: ' + err.name + ' - ' + err.message);
+    }
+}
+open();
+</script>
+)TESTRESOURCE";
+
+TEST(FileSystemAccess, FetchDataForThirdParty)
+{
+    TestWebKitAPI::HTTPServer server({
+        { "/", { frameBytes } },
+    }, TestWebKitAPI::HTTPServer::Protocol::Https, nullptr, nullptr, 9091);
+
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    auto handler = adoptNS([[FileSystemAccessMessageHandler alloc] init]);
+    [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"testHandler"];
+    auto preferences = [configuration preferences];
+    preferences._fileSystemAccessEnabled = YES;
+    preferences._storageAPIEnabled = YES;
+
+    auto websiteDataStore = [configuration websiteDataStore];
+    auto types = [NSSet setWithObject:_WKWebsiteDataTypeFileSystem];
+    done = false;
+    [websiteDataStore removeDataOfTypes:types modifiedSince:[NSDate distantPast] completionHandler:^ {
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
+    auto navigationDelegate = adoptNS([TestNavigationDelegate new]);
+    [navigationDelegate setDidReceiveAuthenticationChallenge:^(WKWebView *, NSURLAuthenticationChallenge *challenge, void (^callback)(NSURLSessionAuthChallengeDisposition, NSURLCredential *)) {
+        EXPECT_WK_STREQ(challenge.protectionSpace.authenticationMethod, NSURLAuthenticationMethodServerTrust);
+        callback(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
+    }];
+    [navigationDelegate setDecidePolicyForNavigationAction:[&](WKNavigationAction *action, void (^decisionHandler)(WKNavigationActionPolicy)) {
+        decisionHandler(WKNavigationActionPolicyAllow);
+    }];
+    [webView setNavigationDelegate:navigationDelegate.get()];
+
+    [webView loadHTMLString:mainFrameString baseURL:[NSURL URLWithString:@"https://webkit.org"]];
+    TestWebKitAPI::Util::run(&receivedScriptMessage);
+    receivedScriptMessage = false;
+    EXPECT_WK_STREQ(@"file is opened", [lastScriptMessage body]);
+
+    done = false;
+    [websiteDataStore fetchDataRecordsOfTypes:types completionHandler:^(NSArray<WKWebsiteDataRecord *> *records) {
+        // Should return both opening origin and top origin.
+        EXPECT_EQ(records.count, 2u);
+        auto sortFunction = ^(WKWebsiteDataRecord *record1, WKWebsiteDataRecord *record2){
+            return [record1.displayName compare:record2.displayName];
+        };
+        auto sortedRecords = [records sortedArrayUsingComparator:sortFunction];
+        EXPECT_WK_STREQ(@"127.0.0.1", [sortedRecords objectAtIndex:0].displayName);
+        EXPECT_WK_STREQ(@"webkit.org", [sortedRecords objectAtIndex:1].displayName);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+}
+
</ins><span class="cx"> #endif // USE(APPLE_INTERNAL_SDK)
</span></span></pre>
</div>
</div>

</body>
</html>