michael@0: /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/dom/FileSystemTaskBase.h" michael@0: michael@0: #include "nsNetUtil.h" // Stream transport service. michael@0: #include "mozilla/dom/ContentChild.h" michael@0: #include "mozilla/dom/FileSystemBase.h" michael@0: #include "mozilla/dom/FileSystemRequestParent.h" michael@0: #include "mozilla/dom/FileSystemUtils.h" michael@0: #include "mozilla/dom/Promise.h" michael@0: #include "mozilla/dom/PContent.h" michael@0: #include "mozilla/unused.h" michael@0: #include "nsDOMFile.h" michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: FileSystemTaskBase::FileSystemTaskBase(FileSystemBase* aFileSystem) michael@0: : mErrorValue(NS_OK) michael@0: , mFileSystem(aFileSystem) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); michael@0: MOZ_ASSERT(aFileSystem, "aFileSystem should not be null."); michael@0: } michael@0: michael@0: FileSystemTaskBase::FileSystemTaskBase(FileSystemBase* aFileSystem, michael@0: const FileSystemParams& aParam, michael@0: FileSystemRequestParent* aParent) michael@0: : mErrorValue(NS_OK) michael@0: , mFileSystem(aFileSystem) michael@0: , mRequestParent(aParent) michael@0: { michael@0: MOZ_ASSERT(FileSystemUtils::IsParentProcess(), michael@0: "Only call from parent process!"); michael@0: MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); michael@0: MOZ_ASSERT(aFileSystem, "aFileSystem should not be null."); michael@0: } michael@0: michael@0: FileSystemTaskBase::~FileSystemTaskBase() michael@0: { michael@0: } michael@0: michael@0: FileSystemBase* michael@0: FileSystemTaskBase::GetFileSystem() const michael@0: { michael@0: return mFileSystem.get(); michael@0: } michael@0: michael@0: void michael@0: FileSystemTaskBase::Start() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); michael@0: michael@0: if (HasError()) { michael@0: NS_DispatchToMainThread(this); michael@0: return; michael@0: } michael@0: michael@0: if (FileSystemUtils::IsParentProcess()) { michael@0: // Run in parent process. michael@0: // Start worker thread. michael@0: nsCOMPtr target michael@0: = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); michael@0: NS_ASSERTION(target, "Must have stream transport service."); michael@0: target->Dispatch(this, NS_DISPATCH_NORMAL); michael@0: return; michael@0: } michael@0: michael@0: // Run in child process. michael@0: if (mFileSystem->IsShutdown()) { michael@0: return; michael@0: } michael@0: michael@0: // Retain a reference so the task object isn't deleted without IPDL's michael@0: // knowledge. The reference will be released by michael@0: // mozilla::dom::ContentChild::DeallocPFileSystemRequestChild. michael@0: NS_ADDREF_THIS(); michael@0: ContentChild::GetSingleton()->SendPFileSystemRequestConstructor(this, michael@0: GetRequestParams(mFileSystem->ToString())); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: FileSystemTaskBase::Run() michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: // Run worker thread tasks michael@0: nsresult rv = Work(); michael@0: if (NS_FAILED(rv)) { michael@0: SetError(rv); michael@0: } michael@0: // Dispatch itself to main thread michael@0: NS_DispatchToMainThread(this); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Run main thread tasks michael@0: HandleResult(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: FileSystemTaskBase::HandleResult() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); michael@0: if (mFileSystem->IsShutdown()) { michael@0: return; michael@0: } michael@0: if (mRequestParent && mRequestParent->IsRunning()) { michael@0: unused << mRequestParent->Send__delete__(mRequestParent, michael@0: GetRequestResult()); michael@0: } else { michael@0: HandlerCallback(); michael@0: } michael@0: } michael@0: michael@0: FileSystemResponseValue michael@0: FileSystemTaskBase::GetRequestResult() const michael@0: { michael@0: MOZ_ASSERT(FileSystemUtils::IsParentProcess(), michael@0: "Only call from parent process!"); michael@0: MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); michael@0: if (HasError()) { michael@0: return FileSystemErrorResponse(mErrorValue); michael@0: } else { michael@0: return GetSuccessRequestResult(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: FileSystemTaskBase::SetRequestResult(const FileSystemResponseValue& aValue) michael@0: { michael@0: MOZ_ASSERT(!FileSystemUtils::IsParentProcess(), michael@0: "Only call from child process!"); michael@0: MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); michael@0: if (aValue.type() == FileSystemResponseValue::TFileSystemErrorResponse) { michael@0: FileSystemErrorResponse r = aValue; michael@0: mErrorValue = r.error(); michael@0: } else { michael@0: SetSuccessRequestResult(aValue); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: FileSystemTaskBase::Recv__delete__(const FileSystemResponseValue& aValue) michael@0: { michael@0: SetRequestResult(aValue); michael@0: HandlerCallback(); michael@0: return true; michael@0: } michael@0: michael@0: BlobParent* michael@0: FileSystemTaskBase::GetBlobParent(nsIDOMFile* aFile) const michael@0: { michael@0: MOZ_ASSERT(FileSystemUtils::IsParentProcess(), michael@0: "Only call from parent process!"); michael@0: MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); michael@0: MOZ_ASSERT(aFile); michael@0: michael@0: // Load the lazy dom file data from the parent before sending to the child. michael@0: nsString mimeType; michael@0: aFile->GetType(mimeType); michael@0: uint64_t fileSize; michael@0: aFile->GetSize(&fileSize); michael@0: uint64_t lastModifiedDate; michael@0: aFile->GetMozLastModifiedDate(&lastModifiedDate); michael@0: michael@0: ContentParent* cp = static_cast(mRequestParent->Manager()); michael@0: return cp->GetOrCreateActorForBlob(aFile); michael@0: } michael@0: michael@0: void michael@0: FileSystemTaskBase::SetError(const nsresult& aErrorValue) michael@0: { michael@0: uint16_t module = NS_ERROR_GET_MODULE(aErrorValue); michael@0: if (module == NS_ERROR_MODULE_DOM_FILESYSTEM || michael@0: module == NS_ERROR_MODULE_DOM_FILE || michael@0: module == NS_ERROR_MODULE_DOM) { michael@0: mErrorValue = aErrorValue; michael@0: return; michael@0: } michael@0: michael@0: switch (aErrorValue) { michael@0: case NS_OK: michael@0: mErrorValue = NS_OK; michael@0: return; michael@0: michael@0: case NS_ERROR_FILE_INVALID_PATH: michael@0: case NS_ERROR_FILE_UNRECOGNIZED_PATH: michael@0: mErrorValue = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR; michael@0: return; michael@0: michael@0: case NS_ERROR_FILE_DESTINATION_NOT_DIR: michael@0: mErrorValue = NS_ERROR_DOM_FILESYSTEM_INVALID_MODIFICATION_ERR; michael@0: return; michael@0: michael@0: case NS_ERROR_FILE_ACCESS_DENIED: michael@0: case NS_ERROR_FILE_DIR_NOT_EMPTY: michael@0: mErrorValue = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR; michael@0: return; michael@0: michael@0: case NS_ERROR_FILE_TARGET_DOES_NOT_EXIST: michael@0: case NS_ERROR_NOT_AVAILABLE: michael@0: mErrorValue = NS_ERROR_DOM_FILE_NOT_FOUND_ERR; michael@0: return; michael@0: michael@0: case NS_ERROR_FILE_ALREADY_EXISTS: michael@0: mErrorValue = NS_ERROR_DOM_FILESYSTEM_PATH_EXISTS_ERR; michael@0: return; michael@0: michael@0: case NS_ERROR_FILE_NOT_DIRECTORY: michael@0: mErrorValue = NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR; michael@0: return; michael@0: michael@0: case NS_ERROR_UNEXPECTED: michael@0: default: michael@0: mErrorValue = NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR; michael@0: return; michael@0: } michael@0: } michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla