michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 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 "FileHelper.h" michael@0: michael@0: #include "nsIFileStorage.h" michael@0: michael@0: #include "nsError.h" michael@0: #include "nsProxyRelease.h" michael@0: michael@0: #include "FileHandle.h" michael@0: #include "FileRequest.h" michael@0: #include "FileService.h" michael@0: #include "nsIRequest.h" michael@0: #include "nsThreadUtils.h" michael@0: michael@0: USING_FILE_NAMESPACE michael@0: michael@0: namespace { michael@0: michael@0: LockedFile* gCurrentLockedFile = nullptr; michael@0: michael@0: } // anonymous namespace michael@0: michael@0: FileHelper::FileHelper(LockedFile* aLockedFile, michael@0: FileRequest* aFileRequest) michael@0: : mFileStorage(aLockedFile->mFileHandle->mFileStorage), michael@0: mLockedFile(aLockedFile), michael@0: mFileRequest(aFileRequest), michael@0: mResultCode(NS_OK), michael@0: mFinished(false) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: } michael@0: michael@0: FileHelper::~FileHelper() michael@0: { michael@0: NS_ASSERTION(!mFileStorage && !mLockedFile && !mFileRequest && !mListener && michael@0: !mRequest, "Should have cleared this!"); michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(FileHelper, nsIRequestObserver) michael@0: michael@0: nsresult michael@0: FileHelper::Enqueue() michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: FileService* service = FileService::GetOrCreate(); michael@0: NS_ENSURE_TRUE(service, NS_ERROR_FAILURE); michael@0: michael@0: nsresult rv = service->Enqueue(mLockedFile, this); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (mLockedFile) { michael@0: mLockedFile->OnNewRequest(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: FileHelper::AsyncRun(FileHelperListener* aListener) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: // Assign the listener early, so we can use it synchronously if the code michael@0: // below fails. michael@0: mListener = aListener; michael@0: michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr stream; michael@0: if (mLockedFile->mRequestMode == LockedFile::PARALLEL) { michael@0: rv = mLockedFile->CreateParallelStream(getter_AddRefs(stream)); michael@0: } michael@0: else { michael@0: rv = mLockedFile->GetOrCreateStream(getter_AddRefs(stream)); michael@0: } michael@0: michael@0: if (NS_SUCCEEDED(rv)) { michael@0: NS_ASSERTION(stream, "This should never be null!"); michael@0: michael@0: rv = DoAsyncRun(stream); michael@0: } michael@0: michael@0: if (NS_FAILED(rv)) { michael@0: mResultCode = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR; michael@0: Finish(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: FileHelper::OnStartRequest(nsIRequest* aRequest, nsISupports* aCtxt) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: FileHelper::OnStopRequest(nsIRequest* aRequest, nsISupports* aCtxt, michael@0: nsresult aStatus) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: if (NS_FAILED(aStatus)) { michael@0: if (aStatus == NS_ERROR_FILE_NO_DEVICE_SPACE) { michael@0: mResultCode = NS_ERROR_DOM_FILEHANDLE_QUOTA_ERR; michael@0: } michael@0: else { michael@0: mResultCode = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR; michael@0: } michael@0: } michael@0: michael@0: Finish(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: FileHelper::OnStreamProgress(uint64_t aProgress, uint64_t aProgressMax) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: if (mLockedFile->IsAborted()) { michael@0: NS_ASSERTION(mRequest, "Should have a request!\n"); michael@0: michael@0: nsresult rv = mRequest->Cancel(NS_BINDING_ABORTED); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("Failed to cancel the request!"); michael@0: } michael@0: michael@0: return; michael@0: } michael@0: michael@0: if (mFileRequest) { michael@0: mFileRequest->OnProgress(aProgress, aProgressMax); michael@0: } michael@0: } michael@0: michael@0: // static michael@0: LockedFile* michael@0: FileHelper::GetCurrentLockedFile() michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: return gCurrentLockedFile; michael@0: } michael@0: michael@0: nsresult michael@0: FileHelper::GetSuccessResult(JSContext* aCx, michael@0: JS::MutableHandle aVal) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: aVal.setUndefined(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: FileHelper::ReleaseObjects() michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: mFileStorage = nullptr; michael@0: mLockedFile = nullptr; michael@0: mFileRequest = nullptr; michael@0: mListener = nullptr; michael@0: mRequest = nullptr; michael@0: } michael@0: michael@0: void michael@0: FileHelper::Finish() michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: if (mFinished) { michael@0: return; michael@0: } michael@0: michael@0: mFinished = true; michael@0: michael@0: if (mLockedFile->IsAborted()) { michael@0: // Always fire a "error" event with ABORT_ERR if the transaction was michael@0: // aborted, even if the request succeeded or failed with another error. michael@0: mResultCode = NS_ERROR_DOM_FILEHANDLE_ABORT_ERR; michael@0: } michael@0: michael@0: LockedFile* oldLockedFile = gCurrentLockedFile; michael@0: gCurrentLockedFile = mLockedFile; michael@0: michael@0: if (mFileRequest) { michael@0: nsresult rv = mFileRequest->NotifyHelperCompleted(this); michael@0: if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) { michael@0: mResultCode = rv; michael@0: } michael@0: } michael@0: michael@0: NS_ASSERTION(gCurrentLockedFile == mLockedFile, "Should be unchanged!"); michael@0: gCurrentLockedFile = oldLockedFile; michael@0: michael@0: mLockedFile->OnRequestFinished(); michael@0: michael@0: mListener->OnFileHelperComplete(this); michael@0: michael@0: ReleaseObjects(); michael@0: michael@0: NS_ASSERTION(!(mFileStorage || mLockedFile || mFileRequest || mListener || michael@0: mRequest), "Subclass didn't call FileHelper::ReleaseObjects!"); michael@0: michael@0: } michael@0: michael@0: void michael@0: FileHelper::OnStreamClose() michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: Finish(); michael@0: } michael@0: michael@0: void michael@0: FileHelper::OnStreamDestroy() michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: Finish(); michael@0: }