diff -r 000000000000 -r 6474c204b198 dom/file/FileHelper.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/file/FileHelper.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,231 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FileHelper.h" + +#include "nsIFileStorage.h" + +#include "nsError.h" +#include "nsProxyRelease.h" + +#include "FileHandle.h" +#include "FileRequest.h" +#include "FileService.h" +#include "nsIRequest.h" +#include "nsThreadUtils.h" + +USING_FILE_NAMESPACE + +namespace { + +LockedFile* gCurrentLockedFile = nullptr; + +} // anonymous namespace + +FileHelper::FileHelper(LockedFile* aLockedFile, + FileRequest* aFileRequest) +: mFileStorage(aLockedFile->mFileHandle->mFileStorage), + mLockedFile(aLockedFile), + mFileRequest(aFileRequest), + mResultCode(NS_OK), + mFinished(false) +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); +} + +FileHelper::~FileHelper() +{ + NS_ASSERTION(!mFileStorage && !mLockedFile && !mFileRequest && !mListener && + !mRequest, "Should have cleared this!"); +} + +NS_IMPL_ISUPPORTS(FileHelper, nsIRequestObserver) + +nsresult +FileHelper::Enqueue() +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + FileService* service = FileService::GetOrCreate(); + NS_ENSURE_TRUE(service, NS_ERROR_FAILURE); + + nsresult rv = service->Enqueue(mLockedFile, this); + NS_ENSURE_SUCCESS(rv, rv); + + if (mLockedFile) { + mLockedFile->OnNewRequest(); + } + + return NS_OK; +} + +nsresult +FileHelper::AsyncRun(FileHelperListener* aListener) +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + // Assign the listener early, so we can use it synchronously if the code + // below fails. + mListener = aListener; + + nsresult rv; + + nsCOMPtr stream; + if (mLockedFile->mRequestMode == LockedFile::PARALLEL) { + rv = mLockedFile->CreateParallelStream(getter_AddRefs(stream)); + } + else { + rv = mLockedFile->GetOrCreateStream(getter_AddRefs(stream)); + } + + if (NS_SUCCEEDED(rv)) { + NS_ASSERTION(stream, "This should never be null!"); + + rv = DoAsyncRun(stream); + } + + if (NS_FAILED(rv)) { + mResultCode = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR; + Finish(); + } + + return NS_OK; +} + +NS_IMETHODIMP +FileHelper::OnStartRequest(nsIRequest* aRequest, nsISupports* aCtxt) +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + return NS_OK; +} + +NS_IMETHODIMP +FileHelper::OnStopRequest(nsIRequest* aRequest, nsISupports* aCtxt, + nsresult aStatus) +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + if (NS_FAILED(aStatus)) { + if (aStatus == NS_ERROR_FILE_NO_DEVICE_SPACE) { + mResultCode = NS_ERROR_DOM_FILEHANDLE_QUOTA_ERR; + } + else { + mResultCode = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR; + } + } + + Finish(); + + return NS_OK; +} + +void +FileHelper::OnStreamProgress(uint64_t aProgress, uint64_t aProgressMax) +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + if (mLockedFile->IsAborted()) { + NS_ASSERTION(mRequest, "Should have a request!\n"); + + nsresult rv = mRequest->Cancel(NS_BINDING_ABORTED); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to cancel the request!"); + } + + return; + } + + if (mFileRequest) { + mFileRequest->OnProgress(aProgress, aProgressMax); + } +} + +// static +LockedFile* +FileHelper::GetCurrentLockedFile() +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + return gCurrentLockedFile; +} + +nsresult +FileHelper::GetSuccessResult(JSContext* aCx, + JS::MutableHandle aVal) +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + aVal.setUndefined(); + return NS_OK; +} + +void +FileHelper::ReleaseObjects() +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + mFileStorage = nullptr; + mLockedFile = nullptr; + mFileRequest = nullptr; + mListener = nullptr; + mRequest = nullptr; +} + +void +FileHelper::Finish() +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + if (mFinished) { + return; + } + + mFinished = true; + + if (mLockedFile->IsAborted()) { + // Always fire a "error" event with ABORT_ERR if the transaction was + // aborted, even if the request succeeded or failed with another error. + mResultCode = NS_ERROR_DOM_FILEHANDLE_ABORT_ERR; + } + + LockedFile* oldLockedFile = gCurrentLockedFile; + gCurrentLockedFile = mLockedFile; + + if (mFileRequest) { + nsresult rv = mFileRequest->NotifyHelperCompleted(this); + if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) { + mResultCode = rv; + } + } + + NS_ASSERTION(gCurrentLockedFile == mLockedFile, "Should be unchanged!"); + gCurrentLockedFile = oldLockedFile; + + mLockedFile->OnRequestFinished(); + + mListener->OnFileHelperComplete(this); + + ReleaseObjects(); + + NS_ASSERTION(!(mFileStorage || mLockedFile || mFileRequest || mListener || + mRequest), "Subclass didn't call FileHelper::ReleaseObjects!"); + +} + +void +FileHelper::OnStreamClose() +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + Finish(); +} + +void +FileHelper::OnStreamDestroy() +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + Finish(); +}