/* -*- 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_ISUPPORTS1(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(); }