| Index: src/DefaultFileSystem.cpp | 
| =================================================================== | 
| --- a/src/DefaultFileSystem.cpp | 
| +++ b/src/DefaultFileSystem.cpp | 
| @@ -14,17 +14,19 @@ | 
| * You should have received a copy of the GNU General Public License | 
| * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
| */ | 
|  | 
| #include <AdblockPlus/DefaultFileSystem.h> | 
| #include <cstdio> | 
| #include <cstring> | 
| #include <fstream> | 
| +#include <sstream> | 
| #include <stdexcept> | 
| +#include <thread> | 
|  | 
| #include <sys/types.h> | 
|  | 
| #ifdef _WIN32 | 
| #include <windows.h> | 
| #include <Shlobj.h> | 
| #include <Shlwapi.h> | 
| #else | 
| @@ -62,47 +64,48 @@ | 
| std::string NormalizePath(const std::string& path) | 
| { | 
| return path; | 
| } | 
| #endif | 
| } | 
|  | 
| std::shared_ptr<std::istream> | 
| -DefaultFileSystem::Read(const std::string& path) const | 
| +DefaultFileSystemSync::Read(const std::string& path) const | 
| { | 
| std::shared_ptr<std::istream> result(new std::ifstream(NormalizePath(path).c_str())); | 
| if (result->fail()) | 
| throw RuntimeErrorWithErrno("Failed to open " + path); | 
| return result; | 
| } | 
|  | 
| -void DefaultFileSystem::Write(const std::string& path, | 
| -                              std::istream& data) | 
| + | 
| +void DefaultFileSystemSync::Write(const std::string& path, | 
| +                                  std::istream& data) | 
| { | 
| std::ofstream file(NormalizePath(path).c_str(), std::ios_base::out | std::ios_base::binary); | 
| file << Utils::Slurp(data); | 
| } | 
|  | 
| -void DefaultFileSystem::Move(const std::string& fromPath, | 
| -                             const std::string& toPath) | 
| +void DefaultFileSystemSync::Move(const std::string& fromPath, | 
| +                                 const std::string& toPath) | 
| { | 
| if (rename(NormalizePath(fromPath).c_str(), NormalizePath(toPath).c_str())) | 
| throw RuntimeErrorWithErrno("Failed to move " + fromPath + " to " + toPath); | 
| } | 
|  | 
| -void DefaultFileSystem::Remove(const std::string& path) | 
| +void DefaultFileSystemSync::Remove(const std::string& path) | 
| { | 
| if (remove(NormalizePath(path).c_str())) | 
| throw RuntimeErrorWithErrno("Failed to remove " + path); | 
| } | 
|  | 
| -FileSystem::StatResult DefaultFileSystem::Stat(const std::string& path) const | 
| +IFileSystem::StatResult DefaultFileSystemSync::Stat(const std::string& path) const | 
| { | 
| -  FileSystem::StatResult result; | 
| +  IFileSystem::StatResult result; | 
| #ifdef WIN32 | 
| WIN32_FILE_ATTRIBUTE_DATA data; | 
| if (!GetFileAttributesExW(NormalizePath(path).c_str(), GetFileExInfoStandard, &data)) | 
| { | 
| DWORD err = GetLastError(); | 
| if (err == ERROR_FILE_NOT_FOUND || | 
| err == ERROR_PATH_NOT_FOUND || | 
| err == ERROR_INVALID_DRIVE) | 
| @@ -156,17 +159,17 @@ | 
| +  static_cast<int64_t>(nativeStat.st_mtim.tv_nsec) / NSEC_IN_MSEC; | 
| #else | 
| result.lastModified = static_cast<int64_t>(nativeStat.st_mtime) * MSEC_IN_SEC; | 
| #endif | 
| return result; | 
| #endif | 
| } | 
|  | 
| -std::string DefaultFileSystem::Resolve(const std::string& path) const | 
| +std::string DefaultFileSystemSync::Resolve(const std::string& path) const | 
| { | 
| if (basePath == "") | 
| { | 
| return path; | 
| } | 
| else | 
| { | 
| #ifdef _WIN32 | 
| @@ -179,18 +182,153 @@ | 
| } | 
| else | 
| { | 
| return path; | 
| } | 
| } | 
| } | 
|  | 
| -void DefaultFileSystem::SetBasePath(const std::string& path) | 
| +void DefaultFileSystemSync::SetBasePath(const std::string& path) | 
| { | 
| basePath = path; | 
|  | 
| if (*basePath.rbegin() == PATH_SEPARATOR) | 
| { | 
| basePath.resize(basePath.size() - 1); | 
| } | 
| } | 
|  | 
| +DefaultFileSystem::DefaultFileSystem(const FileSystemSyncPtr& syncImpl) | 
| +  : syncImpl(syncImpl) | 
| +{ | 
| +} | 
| + | 
| +void DefaultFileSystem::Read(const std::string& path, | 
| +                             const ReadCallback& callback) const | 
| +{ | 
| +  auto impl = syncImpl; | 
| +  std::thread([impl, path, callback] | 
| +  { | 
| +    std::string error; | 
| +    try | 
| +    { | 
| +      auto result = impl->Read(path); | 
| +      std::stringstream output; | 
| +      output << result->rdbuf(); | 
| +      std::string buffer = output.str(); | 
| +      callback(std::move(buffer), error); | 
| +      return; | 
| +    } | 
| +    catch (std::exception& e) | 
| +    { | 
| +      error = e.what(); | 
| +    } | 
| +    catch (...) | 
| +    { | 
| +      error =  "Unknown error while reading from " + path; | 
| +    } | 
| +    callback("", error); | 
| +  }).detach(); | 
| +} | 
| + | 
| +void DefaultFileSystem::Write(const std::string& path, | 
| +                              const std::string& data, | 
| +                              const Callback& callback) | 
| +{ | 
| +  auto impl = syncImpl; | 
| +  std::thread([impl, path, data, callback] | 
| +  { | 
| +    std::string error; | 
| +    try | 
| +    { | 
| +      std::stringstream stream; | 
| +      stream << data; | 
| +      impl->Write(path, stream); | 
| +    } | 
| +    catch (std::exception& e) | 
| +    { | 
| +      error = e.what(); | 
| +    } | 
| +    catch (...) | 
| +    { | 
| +      error = "Unknown error while writing to " + path; | 
| +    } | 
| +    callback(error); | 
| +  }).detach(); | 
| +} | 
| + | 
| +void DefaultFileSystem::Move(const std::string& fromPath, | 
| +                             const std::string& toPath, | 
| +                             const Callback& callback) | 
| +{ | 
| +  auto impl = syncImpl; | 
| +  std::thread([impl, fromPath, toPath, callback] | 
| +  { | 
| +    std::string error; | 
| +    try | 
| +    { | 
| +      impl->Move(fromPath, toPath); | 
| +    } | 
| +    catch (std::exception& e) | 
| +    { | 
| +      error = e.what(); | 
| +    } | 
| +    catch (...) | 
| +    { | 
| +      error = "Unknown error while moving " + fromPath + " to " + toPath; | 
| +    } | 
| +    callback(error); | 
| +  }).detach(); | 
| +} | 
| + | 
| +void DefaultFileSystem::Remove(const std::string& path, | 
| +                               const Callback& callback) | 
| +{ | 
| +  auto impl = syncImpl; | 
| +  std::thread([impl, path, callback] | 
| +  { | 
| +    std::string error; | 
| +    try | 
| +    { | 
| +      impl->Remove(path); | 
| +    } | 
| +    catch (std::exception& e) | 
| +    { | 
| +      error = e.what(); | 
| +    } | 
| +    catch (...) | 
| +    { | 
| +      error = "Unknown error while removing " + path; | 
| +    } | 
| +    callback(error); | 
| +  }).detach(); | 
| +} | 
| + | 
| +void DefaultFileSystem::Stat(const std::string& path, | 
| +                             const StatCallback& callback) const | 
| +{ | 
| +  auto impl = syncImpl; | 
| +  std::thread([impl, path, callback] | 
| +  { | 
| +    std::string error; | 
| +    try | 
| +    { | 
| +      auto result = impl->Stat(path); | 
| +      callback(result, error); | 
| +      return; | 
| +    } | 
| +    catch (std::exception& e) | 
| +    { | 
| +      error = e.what(); | 
| +    } | 
| +    catch (...) | 
| +    { | 
| +      error = "Unknown error while calling stat on " + path; | 
| +    } | 
| +    callback(StatResult(), error); | 
| +  }).detach(); | 
| +} | 
| + | 
| +std::string DefaultFileSystem::Resolve(const std::string& path) const | 
| +{ | 
| +  return syncImpl->Resolve(path); | 
| +} | 
|  |