2012-12-17 23:25:10 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2015-05-03 22:32:37 +03:00
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-12-17 23:25:10 +04:00
|
|
|
/* 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/. */
|
|
|
|
|
|
|
|
#ifndef mozilla_dom_quota_quotacommon_h__
|
|
|
|
#define mozilla_dom_quota_quotacommon_h__
|
|
|
|
|
2021-06-08 19:27:28 +03:00
|
|
|
#include "mozilla/dom/quota/Config.h"
|
|
|
|
|
2020-10-21 16:16:19 +03:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cstddef>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <type_traits>
|
|
|
|
#include <utility>
|
2020-12-14 13:42:36 +03:00
|
|
|
#include "mozIStorageStatement.h"
|
2020-10-21 16:16:19 +03:00
|
|
|
#include "mozilla/Assertions.h"
|
2021-01-05 12:27:18 +03:00
|
|
|
#include "mozilla/Atomics.h"
|
2020-10-21 16:16:19 +03:00
|
|
|
#include "mozilla/Attributes.h"
|
|
|
|
#include "mozilla/Likely.h"
|
|
|
|
#include "mozilla/MacroArgs.h"
|
2020-12-21 12:32:12 +03:00
|
|
|
#include "mozilla/Maybe.h"
|
2020-10-21 16:16:19 +03:00
|
|
|
#include "mozilla/Result.h"
|
|
|
|
#include "mozilla/ResultExtensions.h"
|
2021-06-08 19:27:28 +03:00
|
|
|
#if defined(QM_LOG_ERROR_ENABLED) && defined(QM_ERROR_STACKS_ENABLED)
|
2021-05-28 19:33:40 +03:00
|
|
|
# include "mozilla/Variant.h"
|
|
|
|
#endif
|
2021-06-08 19:27:29 +03:00
|
|
|
#include "mozilla/dom/QMResult.h"
|
2021-07-31 15:37:36 +03:00
|
|
|
#include "mozilla/dom/quota/FirstInitializationAttemptsImpl.h"
|
2020-09-08 18:05:06 +03:00
|
|
|
#include "mozilla/ipc/ProtocolUtils.h"
|
2012-12-17 23:25:10 +04:00
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsDebug.h"
|
2020-10-21 16:16:19 +03:00
|
|
|
#include "nsError.h"
|
2021-01-05 12:27:18 +03:00
|
|
|
#include "nsIDirectoryEnumerator.h"
|
2020-10-21 16:16:19 +03:00
|
|
|
#include "nsIEventTarget.h"
|
2021-01-05 12:27:18 +03:00
|
|
|
#include "nsIFile.h"
|
2020-10-21 16:16:19 +03:00
|
|
|
#include "nsLiteralString.h"
|
2015-02-03 09:29:51 +03:00
|
|
|
#include "nsPrintfCString.h"
|
2020-12-17 17:58:18 +03:00
|
|
|
#include "nsReadableUtils.h"
|
2013-09-23 21:25:00 +04:00
|
|
|
#include "nsString.h"
|
2020-12-15 13:26:08 +03:00
|
|
|
#include "nsTArray.h"
|
2020-10-21 16:16:19 +03:00
|
|
|
#include "nsTLiteralString.h"
|
2012-12-17 23:25:10 +04:00
|
|
|
|
2020-12-15 13:26:08 +03:00
|
|
|
namespace mozilla {
|
|
|
|
template <typename T>
|
|
|
|
class NotNull;
|
|
|
|
}
|
|
|
|
|
2020-09-07 21:00:00 +03:00
|
|
|
// Proper use of unique variable names can be tricky (especially if nesting of
|
|
|
|
// the final macro is required).
|
|
|
|
// See https://lifecs.likai.org/2016/07/c-preprocessor-hygienic-macros.html
|
|
|
|
#define MOZ_UNIQUE_VAR(base) MOZ_CONCAT(base, __COUNTER__)
|
2020-08-11 14:17:56 +03:00
|
|
|
|
2020-09-07 21:00:00 +03:00
|
|
|
// See
|
|
|
|
// https://stackoverflow.com/questions/24481810/how-to-remove-the-enclosing-parentheses-with-macro
|
2020-08-18 11:25:49 +03:00
|
|
|
#define MOZ_REMOVE_PAREN(X) MOZ_REMOVE_PAREN_HELPER2(MOZ_REMOVE_PAREN_HELPER X)
|
|
|
|
#define MOZ_REMOVE_PAREN_HELPER(...) MOZ_REMOVE_PAREN_HELPER __VA_ARGS__
|
|
|
|
#define MOZ_REMOVE_PAREN_HELPER2(...) MOZ_REMOVE_PAREN_HELPER3(__VA_ARGS__)
|
|
|
|
#define MOZ_REMOVE_PAREN_HELPER3(...) MOZ_REMOVE_PAREN_HELPER4_##__VA_ARGS__
|
|
|
|
#define MOZ_REMOVE_PAREN_HELPER4_MOZ_REMOVE_PAREN_HELPER
|
|
|
|
|
2020-08-24 20:41:30 +03:00
|
|
|
// See https://florianjw.de/en/passing_overloaded_functions.html
|
|
|
|
// TODO: Add a test for this macro.
|
|
|
|
#define MOZ_SELECT_OVERLOAD(func) \
|
|
|
|
[](auto&&... aArgs) -> decltype(auto) { \
|
|
|
|
return func(std::forward<decltype(aArgs)>(aArgs)...); \
|
|
|
|
}
|
|
|
|
|
2013-06-30 06:25:15 +04:00
|
|
|
#define DSSTORE_FILE_NAME ".DS_Store"
|
2018-09-20 15:54:42 +03:00
|
|
|
#define DESKTOP_FILE_NAME ".desktop"
|
|
|
|
#define DESKTOP_INI_FILE_NAME "desktop.ini"
|
2019-06-03 19:22:43 +03:00
|
|
|
#define THUMBS_DB_FILE_NAME "thumbs.db"
|
2013-06-30 06:25:15 +04:00
|
|
|
|
2015-02-03 09:29:51 +03:00
|
|
|
#define QM_WARNING(...) \
|
|
|
|
do { \
|
|
|
|
nsPrintfCString str(__VA_ARGS__); \
|
|
|
|
mozilla::dom::quota::ReportInternalError(__FILE__, __LINE__, str.get()); \
|
|
|
|
NS_WARNING(str.get()); \
|
|
|
|
} while (0)
|
|
|
|
|
2021-02-09 13:42:23 +03:00
|
|
|
#define QM_LOG_TEST() MOZ_LOG_TEST(GetQuotaManagerLogger(), LogLevel::Info)
|
|
|
|
#define QM_LOG(_args) MOZ_LOG(GetQuotaManagerLogger(), LogLevel::Info, _args)
|
|
|
|
|
2020-05-26 10:02:07 +03:00
|
|
|
#define UNKNOWN_FILE_WARNING(_leafName) \
|
|
|
|
NS_WARNING( \
|
|
|
|
nsPrintfCString("Something (%s) in the directory that doesn't belong!", \
|
|
|
|
NS_ConvertUTF16toUTF8(_leafName).get()) \
|
|
|
|
.get())
|
|
|
|
|
2020-06-25 10:16:47 +03:00
|
|
|
// This macro should be used in directory traversals for files or directories
|
|
|
|
// that are unknown for given directory traversal. It should only be called
|
|
|
|
// after all known (directory traversal specific) files or directories have
|
|
|
|
// been checked and handled.
|
|
|
|
#ifdef DEBUG
|
|
|
|
# define WARN_IF_FILE_IS_UNKNOWN(_file) \
|
|
|
|
mozilla::dom::quota::WarnIfFileIsUnknown(_file, __FILE__, __LINE__)
|
|
|
|
#else
|
|
|
|
# define WARN_IF_FILE_IS_UNKNOWN(_file) Result<bool, nsresult>(false)
|
|
|
|
#endif
|
|
|
|
|
2020-07-24 10:11:24 +03:00
|
|
|
/**
|
2020-08-27 14:10:10 +03:00
|
|
|
* There are multiple ways to handle unrecoverable conditions (note that the
|
2020-08-28 13:42:39 +03:00
|
|
|
* patterns are put in reverse chronological order and only the first pattern
|
2020-10-14 15:14:14 +03:00
|
|
|
* QM_TRY/QM_TRY_UNWRAP/QM_TRY_INSPECT/QM_TRY_RETURN/QM_FAIL should be used in
|
|
|
|
* new code):
|
2020-08-27 14:10:10 +03:00
|
|
|
*
|
2020-10-14 15:14:14 +03:00
|
|
|
* 1. Using QM_TRY/QM_TRY_UNWRAP/QM_TRY_INSPECT/QM_TRY_RETURN/QM_FAIL macros
|
|
|
|
* (Quota manager specific, defined below)
|
2020-07-24 10:11:24 +03:00
|
|
|
*
|
|
|
|
* Typical use cases:
|
|
|
|
*
|
|
|
|
* nsresult MyFunc1(nsIFile& aFile) {
|
|
|
|
* bool exists;
|
2020-08-28 13:42:39 +03:00
|
|
|
* QM_TRY(aFile.Exists(&exists));
|
|
|
|
* QM_TRY(OkIf(exists), NS_ERROR_FAILURE);
|
2020-07-24 10:11:24 +03:00
|
|
|
*
|
2020-08-27 14:10:10 +03:00
|
|
|
* // The file exists, and data could be read from it here.
|
|
|
|
*
|
2020-07-24 10:11:24 +03:00
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* nsresult MyFunc2(nsIFile& aFile) {
|
|
|
|
* bool exists;
|
2020-08-28 13:42:39 +03:00
|
|
|
* QM_TRY(aFile.Exists(&exists), NS_ERROR_UNEXPECTED);
|
|
|
|
* QM_TRY(OkIf(exists), NS_ERROR_UNEXPECTED);
|
2020-07-24 10:11:24 +03:00
|
|
|
*
|
2020-08-27 14:10:10 +03:00
|
|
|
* // The file exists, and data could be read from it here.
|
|
|
|
*
|
2020-07-24 10:11:24 +03:00
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* void MyFunc3(nsIFile& aFile) {
|
|
|
|
* bool exists;
|
2020-08-28 13:42:39 +03:00
|
|
|
* QM_TRY(aFile.Exists(&exists), QM_VOID);
|
|
|
|
* QM_TRY(OkIf(exists), QM_VOID);
|
2020-08-27 14:10:10 +03:00
|
|
|
*
|
|
|
|
* // The file exists, and data could be read from it here.
|
2020-07-24 10:11:24 +03:00
|
|
|
* }
|
|
|
|
*
|
2020-08-21 11:11:25 +03:00
|
|
|
* nsresult MyFunc4(nsIFile& aFile) {
|
2020-08-28 13:42:39 +03:00
|
|
|
* bool exists;
|
|
|
|
* QM_TRY(storageFile->Exists(&exists), QM_PROPAGATE,
|
|
|
|
* []() { NS_WARNING("The Exists call failed!"); });
|
|
|
|
* QM_TRY(OkIf(exists), NS_ERROR_FAILURE,
|
|
|
|
* []() { NS_WARNING("The file doesn't exist!"); });
|
|
|
|
*
|
|
|
|
* // The file exists, and data could be read from it here.
|
2020-08-21 11:11:25 +03:00
|
|
|
*
|
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
2020-08-27 14:10:10 +03:00
|
|
|
* nsresult MyFunc5(nsIFile& aFile) {
|
|
|
|
* bool exists;
|
2020-08-28 13:42:39 +03:00
|
|
|
* QM_TRY(aFile.Exists(&exists));
|
2020-08-27 14:10:10 +03:00
|
|
|
* if (exists) {
|
|
|
|
* // The file exists, and data could be read from it here.
|
|
|
|
* } else {
|
2020-08-28 13:42:39 +03:00
|
|
|
* QM_FAIL(NS_ERROR_FAILURE);
|
2020-08-27 14:10:10 +03:00
|
|
|
* }
|
|
|
|
*
|
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* nsresult MyFunc6(nsIFile& aFile) {
|
2020-08-28 13:42:39 +03:00
|
|
|
* bool exists;
|
|
|
|
* QM_TRY(aFile.Exists(&exists));
|
|
|
|
* if (exists) {
|
|
|
|
* // The file exists, and data could be read from it here.
|
|
|
|
* } else {
|
|
|
|
* QM_FAIL(NS_ERROR_FAILURE,
|
|
|
|
* []() { NS_WARNING("The file doesn't exist!"); });
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* 2. Using MOZ_TRY/MOZ_TRY_VAR macros
|
|
|
|
*
|
|
|
|
* Typical use cases:
|
|
|
|
*
|
|
|
|
* nsresult MyFunc1(nsIFile& aFile) {
|
|
|
|
* // MOZ_TRY can't return a custom return value
|
|
|
|
*
|
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* nsresult MyFunc2(nsIFile& aFile) {
|
|
|
|
* // MOZ_TRY can't return a custom return value
|
|
|
|
*
|
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* void MyFunc3(nsIFile& aFile) {
|
|
|
|
* // MOZ_TRY can't return a custom return value, "void" in this case
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* nsresult MyFunc4(nsIFile& aFile) {
|
|
|
|
* // MOZ_TRY can't return a custom return value and run an additional
|
|
|
|
* // cleanup function
|
|
|
|
*
|
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* nsresult MyFunc5(nsIFile& aFile) {
|
|
|
|
* // There's no MOZ_FAIL, MOZ_TRY can't return a custom return value
|
|
|
|
*
|
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* nsresult MyFunc6(nsIFile& aFile) {
|
|
|
|
* // There's no MOZ_FAIL, MOZ_TRY can't return a custom return value and run
|
|
|
|
* // an additional cleanup function
|
2020-08-27 14:10:10 +03:00
|
|
|
*
|
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
2020-08-28 13:42:39 +03:00
|
|
|
* 3. Using NS_WARN_IF and NS_WARNING macro with own control flow handling
|
2020-07-24 10:11:24 +03:00
|
|
|
*
|
|
|
|
* Typical use cases:
|
|
|
|
*
|
|
|
|
* nsresult MyFunc1(nsIFile& aFile) {
|
|
|
|
* bool exists;
|
|
|
|
* nsresult rv = aFile.Exists(&exists);
|
|
|
|
* if (NS_WARN_IF(NS_FAILED(rv)) {
|
|
|
|
* return rv;
|
|
|
|
* }
|
|
|
|
* if (NS_WARN_IF(!exists) {
|
|
|
|
* return NS_ERROR_FAILURE;
|
|
|
|
* }
|
|
|
|
*
|
2020-08-27 14:10:10 +03:00
|
|
|
* // The file exists, and data could be read from it here.
|
|
|
|
*
|
2020-07-24 10:11:24 +03:00
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* nsresult MyFunc2(nsIFile& aFile) {
|
|
|
|
* bool exists;
|
|
|
|
* nsresult rv = aFile.Exists(&exists);
|
|
|
|
* if (NS_WARN_IF(NS_FAILED(rv)) {
|
|
|
|
* return NS_ERROR_UNEXPECTED;
|
|
|
|
* }
|
|
|
|
* if (NS_WARN_IF(!exists) {
|
|
|
|
* return NS_ERROR_UNEXPECTED;
|
|
|
|
* }
|
|
|
|
*
|
2020-08-27 14:10:10 +03:00
|
|
|
* // The file exists, and data could be read from it here.
|
|
|
|
*
|
2020-07-24 10:11:24 +03:00
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* void MyFunc3(nsIFile& aFile) {
|
|
|
|
* bool exists;
|
|
|
|
* nsresult rv = aFile.Exists(&exists);
|
|
|
|
* if (NS_WARN_IF(NS_FAILED(rv)) {
|
|
|
|
* return;
|
|
|
|
* }
|
|
|
|
* if (NS_WARN_IF(!exists) {
|
|
|
|
* return;
|
|
|
|
* }
|
2020-08-27 14:10:10 +03:00
|
|
|
*
|
|
|
|
* // The file exists, and data could be read from it here.
|
2020-07-24 10:11:24 +03:00
|
|
|
* }
|
|
|
|
*
|
2020-08-21 11:11:25 +03:00
|
|
|
* nsresult MyFunc4(nsIFile& aFile) {
|
|
|
|
* bool exists;
|
|
|
|
* nsresult rv = aFile.Exists(&exists);
|
|
|
|
* if (NS_WARN_IF(NS_FAILED(rv)) {
|
|
|
|
* NS_WARNING("The Exists call failed!");
|
|
|
|
* return rv;
|
|
|
|
* }
|
|
|
|
* if (NS_WARN_IF(!exists) {
|
|
|
|
* NS_WARNING("The file doesn't exist!");
|
|
|
|
* return NS_ERROR_FAILURE;
|
|
|
|
* }
|
|
|
|
*
|
2020-08-27 14:10:10 +03:00
|
|
|
* // The file exists, and data could be read from it here.
|
|
|
|
*
|
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* nsresult MyFunc5(nsIFile& aFile) {
|
|
|
|
* bool exists;
|
|
|
|
* nsresult rv = aFile.Exists(&exists);
|
|
|
|
* if (NS_WARN_IF(NS_FAILED(rv)) {
|
|
|
|
* return rv;
|
|
|
|
* }
|
|
|
|
* if (exists) {
|
|
|
|
* // The file exists, and data could be read from it here.
|
|
|
|
* } else {
|
|
|
|
* return NS_ERROR_FAILURE;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* nsresult MyFunc6(nsIFile& aFile) {
|
|
|
|
* bool exists;
|
|
|
|
* nsresult rv = aFile.Exists(&exists);
|
|
|
|
* if (NS_WARN_IF(NS_FAILED(rv)) {
|
|
|
|
* return rv;
|
|
|
|
* }
|
|
|
|
* if (exists) {
|
|
|
|
* // The file exists, and data could be read from it here.
|
|
|
|
* } else {
|
|
|
|
* NS_WARNING("The file doesn't exist!");
|
|
|
|
* return NS_ERROR_FAILURE;
|
|
|
|
* }
|
|
|
|
*
|
2020-08-21 11:11:25 +03:00
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
2020-08-28 13:42:39 +03:00
|
|
|
* 4. Using NS_ENSURE_* macros
|
2020-07-24 10:11:24 +03:00
|
|
|
*
|
2020-08-28 13:42:39 +03:00
|
|
|
* Mainly:
|
|
|
|
* - NS_ENSURE_SUCCESS
|
|
|
|
* - NS_ENSURE_SUCCESS_VOID
|
|
|
|
* - NS_ENSURE_TRUE
|
|
|
|
* - NS_ENSURE_TRUE_VOID
|
2020-07-24 10:11:24 +03:00
|
|
|
*
|
|
|
|
* Typical use cases:
|
|
|
|
*
|
|
|
|
* nsresult MyFunc1(nsIFile& aFile) {
|
|
|
|
* bool exists;
|
2020-08-28 13:42:39 +03:00
|
|
|
* nsresult rv = aFile.Exists(&exists);
|
|
|
|
* NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
* NS_ENSURE_TRUE(exists, NS_ERROR_FAILURE);
|
2020-07-24 10:11:24 +03:00
|
|
|
*
|
2020-08-27 14:10:10 +03:00
|
|
|
* // The file exists, and data could be read from it here.
|
|
|
|
*
|
2020-07-24 10:11:24 +03:00
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* nsresult MyFunc2(nsIFile& aFile) {
|
|
|
|
* bool exists;
|
2020-08-28 13:42:39 +03:00
|
|
|
* nsresult rv = aFile.Exists(&exists);
|
|
|
|
* NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
|
|
|
|
* NS_ENSURE_TRUE(exists, NS_ERROR_UNEXPECTED);
|
2020-07-24 10:11:24 +03:00
|
|
|
*
|
2020-08-27 14:10:10 +03:00
|
|
|
* // The file exists, and data could be read from it here.
|
|
|
|
*
|
2020-07-24 10:11:24 +03:00
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* void MyFunc3(nsIFile& aFile) {
|
|
|
|
* bool exists;
|
2020-08-28 13:42:39 +03:00
|
|
|
* nsresult rv = aFile.Exists(&exists);
|
|
|
|
* NS_ENSURE_SUCCESS_VOID(rv);
|
|
|
|
* NS_ENSURE_TRUE_VOID(exists);
|
2020-08-27 14:10:10 +03:00
|
|
|
*
|
|
|
|
* // The file exists, and data could be read from it here.
|
2020-07-24 10:11:24 +03:00
|
|
|
* }
|
|
|
|
*
|
2020-08-21 11:11:25 +03:00
|
|
|
* nsresult MyFunc4(nsIFile& aFile) {
|
2020-08-28 13:42:39 +03:00
|
|
|
* // NS_ENSURE_SUCCESS/NS_ENSURE_TRUE can't run an additional cleanup
|
|
|
|
* // function
|
2020-08-27 14:10:10 +03:00
|
|
|
*
|
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* nsresult MyFunc5(nsIFile& aFile) {
|
|
|
|
* bool exists;
|
2020-08-28 13:42:39 +03:00
|
|
|
* nsresult rv = aFile.Exists(&exists);
|
|
|
|
* NS_ENSURE_SUCCESS(rv, rv);
|
2020-08-27 14:10:10 +03:00
|
|
|
* if (exists) {
|
|
|
|
* // The file exists, and data could be read from it here.
|
|
|
|
* } else {
|
2020-08-28 13:42:39 +03:00
|
|
|
* NS_ENSURE_TRUE(false, NS_ERROR_FAILURE);
|
2020-08-27 14:10:10 +03:00
|
|
|
* }
|
|
|
|
*
|
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* nsresult MyFunc6(nsIFile& aFile) {
|
2020-08-28 13:42:39 +03:00
|
|
|
* // NS_ENSURE_TRUE can't run an additional cleanup function
|
2020-08-27 14:10:10 +03:00
|
|
|
*
|
2020-08-21 11:11:25 +03:00
|
|
|
* return NS_OK;
|
|
|
|
* }
|
|
|
|
*
|
2020-10-14 15:14:14 +03:00
|
|
|
* QM_TRY/QM_TRY_UNWRAP/QM_TRY_INSPECT is like MOZ_TRY/MOZ_TRY_VAR but if an
|
|
|
|
* error occurs it additionally calls a generic function HandleError to handle
|
|
|
|
* the error and it can be used to return custom return values as well and even
|
|
|
|
* call an additional cleanup function.
|
2020-07-24 10:11:24 +03:00
|
|
|
* HandleError currently only warns in debug builds, it will report to the
|
|
|
|
* browser console and telemetry in the future.
|
2020-10-14 15:14:14 +03:00
|
|
|
* The other advantage of QM_TRY/QM_TRY_UNWRAP/QM_TRY_INSPECT is that a local
|
|
|
|
* nsresult is not needed at all in all cases, all calls can be wrapped
|
|
|
|
* directly. If an error occurs, the warning contains a concrete call instead
|
|
|
|
* of the rv local variable. For example:
|
2020-07-24 10:11:24 +03:00
|
|
|
*
|
|
|
|
* 1. WARNING: NS_ENSURE_SUCCESS(rv, rv) failed with result 0x80004005
|
|
|
|
* (NS_ERROR_FAILURE): file XYZ, line N
|
|
|
|
*
|
|
|
|
* 2. WARNING: 'NS_FAILED(rv)', file XYZ, line N
|
|
|
|
*
|
|
|
|
* 3. Nothing (MOZ_TRY doesn't warn)
|
|
|
|
*
|
|
|
|
* 4. WARNING: Error: 'aFile.Exists(&exists)', file XYZ, line N
|
|
|
|
*
|
2020-09-17 17:01:01 +03:00
|
|
|
* QM_TRY_RETURN is a supplementary macro for cases when the result's success
|
|
|
|
* value can be directly returned (instead of assigning to a variable as in the
|
2020-10-14 15:14:14 +03:00
|
|
|
* QM_TRY_UNWRAP/QM_TRY_INSPECT case).
|
2020-09-17 17:01:01 +03:00
|
|
|
*
|
2020-08-27 14:10:10 +03:00
|
|
|
* QM_FAIL is a supplementary macro for cases when an error needs to be
|
|
|
|
* returned without evaluating an expression. It's possible to write
|
|
|
|
* QM_TRY(OkIf(false), NS_ERROR_FAILURE), but QM_FAIL(NS_ERROR_FAILURE) looks
|
|
|
|
* more straightforward.
|
2020-07-24 10:11:24 +03:00
|
|
|
*
|
2020-10-14 15:14:14 +03:00
|
|
|
* It's highly recommended to use
|
|
|
|
* QM_TRY/QM_TRY_UNWRAP/QM_TRY_INSPECT/QM_TRY_RETURN/QM_FAIL in new code for
|
|
|
|
* quota manager and quota clients. Existing code should be incrementally
|
|
|
|
* converted as needed.
|
2020-08-27 14:10:10 +03:00
|
|
|
*
|
2020-10-14 15:14:14 +03:00
|
|
|
* QM_TRY_VOID/QM_TRY_UNWRAP_VOID/QM_TRY_INSPECT_VOID/QM_FAIL_VOID is not
|
|
|
|
* defined on purpose since it's possible to use
|
|
|
|
* QM_TRY/QM_TRY_UNWRAP/QM_TRY_INSPECT/QM_FAIL even in void functions.
|
2020-08-27 14:10:10 +03:00
|
|
|
* However, QM_TRY(Task(), ) would look odd so it's recommended to use a dummy
|
|
|
|
* define QM_VOID that evaluates to nothing instead: QM_TRY(Task(), QM_VOID)
|
2020-07-24 10:11:24 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
#define QM_VOID
|
|
|
|
|
2020-10-02 13:04:37 +03:00
|
|
|
#define QM_PROPAGATE Err(tryTempError)
|
2020-08-21 11:11:25 +03:00
|
|
|
|
2020-10-19 15:43:13 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
# define QM_ASSERT_UNREACHABLE \
|
|
|
|
[]() -> ::mozilla::GenericErrorResult<nsresult> { \
|
|
|
|
MOZ_CRASH("Should never be reached."); \
|
|
|
|
}()
|
|
|
|
|
|
|
|
# define QM_ASSERT_UNREACHABLE_VOID \
|
|
|
|
[] { MOZ_CRASH("Should never be reached."); }()
|
|
|
|
#endif
|
2020-10-14 16:03:35 +03:00
|
|
|
|
2020-10-19 15:43:13 +03:00
|
|
|
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
|
|
|
# define QM_DIAGNOSTIC_ASSERT_UNREACHABLE \
|
|
|
|
[]() -> ::mozilla::GenericErrorResult<nsresult> { \
|
|
|
|
MOZ_CRASH("Should never be reached."); \
|
|
|
|
}()
|
|
|
|
|
|
|
|
# define QM_DIAGNOSTIC_ASSERT_UNREACHABLE_VOID \
|
|
|
|
[] { MOZ_CRASH("Should never be reached."); }()
|
|
|
|
#endif
|
2020-10-14 16:03:35 +03:00
|
|
|
|
2020-08-28 14:44:46 +03:00
|
|
|
// QM_MISSING_ARGS and QM_HANDLE_ERROR macros are implementation details of
|
2020-10-14 15:14:14 +03:00
|
|
|
// QM_TRY/QM_TRY_UNWRAP/QM_TRY_INSPECT/QM_FAIL and shouldn't be used directly.
|
2020-08-28 14:44:46 +03:00
|
|
|
|
2020-07-24 10:01:37 +03:00
|
|
|
#define QM_MISSING_ARGS(...) \
|
|
|
|
do { \
|
|
|
|
static_assert(false, "Did you forget arguments?"); \
|
2020-07-24 10:11:24 +03:00
|
|
|
} while (0)
|
|
|
|
|
2020-08-28 14:44:46 +03:00
|
|
|
#ifdef DEBUG
|
2021-03-24 15:27:53 +03:00
|
|
|
# define QM_HANDLE_ERROR(expr, error, severity) \
|
|
|
|
HandleError(#expr, error, __FILE__, __LINE__, severity)
|
2020-08-28 14:44:46 +03:00
|
|
|
#else
|
2021-03-24 15:27:53 +03:00
|
|
|
# define QM_HANDLE_ERROR(expr, error, severity) \
|
|
|
|
HandleError("Unavailable", error, __FILE__, __LINE__, severity)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
# define QM_HANDLE_ERROR_RETURN_NOTHING(expr, error, severity) \
|
|
|
|
HandleErrorReturnNothing(#expr, error, __FILE__, __LINE__, severity)
|
|
|
|
#else
|
|
|
|
# define QM_HANDLE_ERROR_RETURN_NOTHING(expr, error, severity) \
|
|
|
|
HandleErrorReturnNothing("Unavailable", error, __FILE__, __LINE__, severity)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
# define QM_HANDLE_ERROR_WITH_CLEANUP_RETURN_NOTHING(expr, error, severity, \
|
|
|
|
cleanup) \
|
|
|
|
HandleErrorWithCleanupReturnNothing(#expr, error, __FILE__, __LINE__, \
|
|
|
|
severity, cleanup)
|
|
|
|
#else
|
|
|
|
# define QM_HANDLE_ERROR_WITH_CLEANUP_RETURN_NOTHING(expr, error, severity, \
|
|
|
|
cleanup) \
|
|
|
|
HandleErrorWithCleanupReturnNothing("Unavailable", error, __FILE__, \
|
|
|
|
__LINE__, severity, cleanup)
|
2020-08-28 14:44:46 +03:00
|
|
|
#endif
|
|
|
|
|
2020-09-07 21:00:00 +03:00
|
|
|
// QM_TRY_PROPAGATE_ERR, QM_TRY_CUSTOM_RET_VAL,
|
|
|
|
// QM_TRY_CUSTOM_RET_VAL_WITH_CLEANUP and QM_TRY_GLUE macros are implementation
|
|
|
|
// details of QM_TRY and shouldn't be used directly.
|
2020-07-24 10:01:37 +03:00
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// Handles the two arguments case when the error is propagated.
|
|
|
|
#define QM_TRY_PROPAGATE_ERR(tryResult, expr) \
|
|
|
|
auto tryResult = ::mozilla::ToResult(expr); \
|
|
|
|
static_assert(std::is_empty_v<typename decltype(tryResult)::ok_type>); \
|
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
|
|
|
mozilla::dom::quota::QM_HANDLE_ERROR( \
|
|
|
|
expr, tryResult.inspectErr(), mozilla::dom::quota::Severity::Error); \
|
|
|
|
return tryResult.propagateErr(); \
|
2020-08-21 11:11:25 +03:00
|
|
|
}
|
2020-07-24 10:11:24 +03:00
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// Handles the three arguments case when a custom return value needs to be
|
2020-08-21 11:11:25 +03:00
|
|
|
// returned
|
2021-05-03 22:44:40 +03:00
|
|
|
#define QM_TRY_CUSTOM_RET_VAL(tryResult, expr, customRetVal) \
|
2020-09-18 17:51:54 +03:00
|
|
|
auto tryResult = ::mozilla::ToResult(expr); \
|
|
|
|
static_assert(std::is_empty_v<typename decltype(tryResult)::ok_type>); \
|
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
2020-10-02 13:04:37 +03:00
|
|
|
auto tryTempError MOZ_MAYBE_UNUSED = tryResult.unwrapErr(); \
|
2021-05-03 22:44:40 +03:00
|
|
|
mozilla::dom::quota::QM_HANDLE_ERROR( \
|
|
|
|
expr, tryTempError, mozilla::dom::quota::Severity::Error); \
|
2020-09-18 17:51:54 +03:00
|
|
|
return customRetVal; \
|
2020-08-21 11:11:25 +03:00
|
|
|
}
|
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// Handles the four arguments case when a cleanup function needs to be called
|
2020-08-21 11:11:25 +03:00
|
|
|
// before a custom return value is returned
|
2021-05-03 22:44:40 +03:00
|
|
|
#define QM_TRY_CUSTOM_RET_VAL_WITH_CLEANUP(tryResult, expr, customRetVal, \
|
|
|
|
cleanup) \
|
|
|
|
auto tryResult = ::mozilla::ToResult(expr); \
|
|
|
|
static_assert(std::is_empty_v<typename decltype(tryResult)::ok_type>); \
|
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
|
|
|
auto tryTempError = tryResult.unwrapErr(); \
|
|
|
|
mozilla::dom::quota::QM_HANDLE_ERROR( \
|
|
|
|
expr, tryTempError, mozilla::dom::quota::Severity::Error); \
|
|
|
|
cleanup(tryTempError); \
|
|
|
|
return customRetVal; \
|
2020-08-21 11:11:25 +03:00
|
|
|
}
|
2020-07-24 10:11:24 +03:00
|
|
|
|
2020-07-24 10:01:37 +03:00
|
|
|
// Chooses the final implementation macro for given argument count.
|
2020-09-07 21:00:00 +03:00
|
|
|
// This could use MOZ_PASTE_PREFIX_AND_ARG_COUNT, but explicit named suffxes
|
|
|
|
// read slightly better than plain numbers.
|
|
|
|
// See also
|
|
|
|
// https://stackoverflow.com/questions/3046889/optional-parameters-with-c-macros
|
2020-09-08 15:52:00 +03:00
|
|
|
#define QM_TRY_META(...) \
|
|
|
|
{ \
|
2021-05-03 22:44:40 +03:00
|
|
|
MOZ_ARG_6( \
|
|
|
|
, ##__VA_ARGS__, QM_TRY_CUSTOM_RET_VAL_WITH_CLEANUP(__VA_ARGS__), \
|
|
|
|
QM_TRY_CUSTOM_RET_VAL(__VA_ARGS__), QM_TRY_PROPAGATE_ERR(__VA_ARGS__), \
|
|
|
|
QM_MISSING_ARGS(__VA_ARGS__), QM_MISSING_ARGS(__VA_ARGS__)) \
|
2020-09-08 15:52:00 +03:00
|
|
|
}
|
2020-09-07 21:00:00 +03:00
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// Generates unique variable name. This extra internal macro (along with
|
|
|
|
// __COUNTER__) allows nesting of the final macro.
|
|
|
|
#define QM_TRY_GLUE(...) QM_TRY_META(MOZ_UNIQUE_VAR(tryResult), ##__VA_ARGS__)
|
2020-07-24 10:01:37 +03:00
|
|
|
|
2020-07-24 10:11:24 +03:00
|
|
|
/**
|
2020-08-21 11:11:25 +03:00
|
|
|
* QM_TRY(expr[, customRetVal, cleanup]) is the C++ equivalent of Rust's
|
2021-03-24 15:27:53 +03:00
|
|
|
* `try!(expr);`. First, it evaluates expr, which must produce a Result value
|
|
|
|
* with empty ok_type. On Success, it does nothing else. On error, it calls
|
2020-08-21 11:11:25 +03:00
|
|
|
* HandleError and an additional cleanup function (if the third argument was
|
|
|
|
* passed) and finally returns an error Result from the enclosing function or a
|
|
|
|
* custom return value (if the second argument was passed).
|
2020-07-24 10:11:24 +03:00
|
|
|
*/
|
2020-09-07 21:00:00 +03:00
|
|
|
#define QM_TRY(...) QM_TRY_GLUE(__VA_ARGS__)
|
2020-07-24 10:11:24 +03:00
|
|
|
|
2020-10-14 15:14:14 +03:00
|
|
|
// QM_TRY_ASSIGN_PROPAGATE_ERR, QM_TRY_ASSIGN_CUSTOM_RET_VAL,
|
|
|
|
// QM_TRY_ASSIGN_CUSTOM_RET_VAL_WITH_CLEANUP and QM_TRY_ASSIGN_GLUE macros are
|
|
|
|
// implementation details of QM_TRY_UNWRAP/QM_TRY_INSPECT and shouldn't be used
|
|
|
|
// directly.
|
2020-07-24 10:11:24 +03:00
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// Handles the four arguments case when the error is propagated.
|
|
|
|
#define QM_TRY_ASSIGN_PROPAGATE_ERR(tryResult, accessFunction, target, expr) \
|
|
|
|
auto tryResult = (expr); \
|
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
|
|
|
mozilla::dom::quota::QM_HANDLE_ERROR( \
|
|
|
|
expr, tryResult.inspectErr(), mozilla::dom::quota::Severity::Error); \
|
|
|
|
return tryResult.propagateErr(); \
|
|
|
|
} \
|
2020-09-29 13:57:14 +03:00
|
|
|
MOZ_REMOVE_PAREN(target) = tryResult.accessFunction();
|
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// Handles the five arguments case when a custom return value needs to be
|
2020-08-21 11:11:25 +03:00
|
|
|
// returned
|
2021-05-03 22:44:40 +03:00
|
|
|
#define QM_TRY_ASSIGN_CUSTOM_RET_VAL(tryResult, accessFunction, target, expr, \
|
|
|
|
customRetVal) \
|
|
|
|
auto tryResult = (expr); \
|
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
|
|
|
auto tryTempError MOZ_MAYBE_UNUSED = tryResult.unwrapErr(); \
|
|
|
|
mozilla::dom::quota::QM_HANDLE_ERROR( \
|
|
|
|
expr, tryTempError, mozilla::dom::quota::Severity::Error); \
|
|
|
|
return customRetVal; \
|
|
|
|
} \
|
2020-09-29 13:57:14 +03:00
|
|
|
MOZ_REMOVE_PAREN(target) = tryResult.accessFunction();
|
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// Handles the six arguments case when a cleanup function needs to be called
|
2020-08-21 11:11:25 +03:00
|
|
|
// before a custom return value is returned
|
2021-05-03 22:44:40 +03:00
|
|
|
#define QM_TRY_ASSIGN_CUSTOM_RET_VAL_WITH_CLEANUP( \
|
|
|
|
tryResult, accessFunction, target, expr, customRetVal, cleanup) \
|
|
|
|
auto tryResult = (expr); \
|
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
|
|
|
auto tryTempError = tryResult.unwrapErr(); \
|
|
|
|
mozilla::dom::quota::QM_HANDLE_ERROR( \
|
|
|
|
expr, tryTempError, mozilla::dom::quota::Severity::Error); \
|
|
|
|
cleanup(tryTempError); \
|
|
|
|
return customRetVal; \
|
|
|
|
} \
|
2020-09-29 13:57:14 +03:00
|
|
|
MOZ_REMOVE_PAREN(target) = tryResult.accessFunction();
|
2020-07-24 10:11:24 +03:00
|
|
|
|
2020-07-24 10:01:37 +03:00
|
|
|
// Chooses the final implementation macro for given argument count.
|
2020-09-07 21:00:00 +03:00
|
|
|
// See also the comment for QM_TRY_META.
|
2021-05-03 22:44:40 +03:00
|
|
|
#define QM_TRY_ASSIGN_META(...) \
|
|
|
|
MOZ_ARG_8(, ##__VA_ARGS__, \
|
|
|
|
QM_TRY_ASSIGN_CUSTOM_RET_VAL_WITH_CLEANUP(__VA_ARGS__), \
|
|
|
|
QM_TRY_ASSIGN_CUSTOM_RET_VAL(__VA_ARGS__), \
|
|
|
|
QM_TRY_ASSIGN_PROPAGATE_ERR(__VA_ARGS__), \
|
|
|
|
QM_MISSING_ARGS(__VA_ARGS__), QM_MISSING_ARGS(__VA_ARGS__), \
|
|
|
|
QM_MISSING_ARGS(__VA_ARGS__), QM_MISSING_ARGS(__VA_ARGS__))
|
|
|
|
|
|
|
|
// Generates unique variable name. This extra internal macro (along with
|
|
|
|
// __COUNTER__) allows nesting of the final macro.
|
|
|
|
#define QM_TRY_ASSIGN_GLUE(accessFunction, ...) \
|
|
|
|
QM_TRY_ASSIGN_META(MOZ_UNIQUE_VAR(tryResult), accessFunction, ##__VA_ARGS__)
|
2020-07-24 10:01:37 +03:00
|
|
|
|
2020-07-24 10:11:24 +03:00
|
|
|
/**
|
2020-10-02 16:23:49 +03:00
|
|
|
* QM_TRY_UNWRAP(target, expr[, customRetVal, cleanup]) is the C++ equivalent of
|
2020-08-21 11:11:25 +03:00
|
|
|
* Rust's `target = try!(expr);`. First, it evaluates expr, which must produce
|
2020-09-29 13:57:14 +03:00
|
|
|
* a Result value. On success, the result's success value is unwrapped and
|
|
|
|
* assigned to target. On error, it calls HandleError and an additional cleanup
|
|
|
|
* function (if the fourth argument was passed) and finally returns the error
|
|
|
|
* result or a custom return value (if the third argument was passed). |target|
|
|
|
|
* must be an lvalue.
|
|
|
|
*/
|
2020-10-14 15:14:14 +03:00
|
|
|
#define QM_TRY_UNWRAP(...) QM_TRY_ASSIGN_GLUE(unwrap, __VA_ARGS__)
|
2020-09-29 13:57:14 +03:00
|
|
|
|
|
|
|
/**
|
2020-10-14 15:14:14 +03:00
|
|
|
* QM_TRY_INSPECT is similar to QM_TRY_UNWRAP, but it does not unwrap a success
|
2020-09-29 13:57:14 +03:00
|
|
|
* value, but inspects it and binds it to the target. It can therefore only be
|
|
|
|
* used when the target declares a const&. In general,
|
|
|
|
*
|
|
|
|
* QM_TRY_INSPECT(const auto &target, DoSomething())
|
|
|
|
*
|
|
|
|
* should be preferred over
|
|
|
|
*
|
2020-10-02 16:23:49 +03:00
|
|
|
* QM_TRY_UNWRAP(const auto target, DoSomething())
|
2020-09-29 13:57:14 +03:00
|
|
|
*
|
|
|
|
* as it avoids unnecessary moves/copies.
|
2020-07-24 10:11:24 +03:00
|
|
|
*/
|
2020-10-14 15:14:14 +03:00
|
|
|
#define QM_TRY_INSPECT(...) QM_TRY_ASSIGN_GLUE(inspect, __VA_ARGS__)
|
2020-07-24 10:11:24 +03:00
|
|
|
|
2020-09-17 17:01:01 +03:00
|
|
|
// QM_TRY_RETURN_PROPAGATE_ERR, QM_TRY_RETURN_CUSTOM_RET_VAL,
|
|
|
|
// QM_TRY_RETURN_CUSTOM_RET_VAL_WITH_CLEANUP and QM_TRY_RETURN_GLUE macros are
|
|
|
|
// implementation details of QM_TRY_RETURN and shouldn't be used directly.
|
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// Handles the two arguments case when the error is (also) propagated.
|
2020-10-02 13:03:29 +03:00
|
|
|
// Note that this deliberately uses a single return statement without going
|
|
|
|
// through unwrap/unwrapErr/propagateErr, so that this does not prevent NRVO or
|
|
|
|
// tail call optimizations when possible.
|
2021-05-03 22:44:40 +03:00
|
|
|
#define QM_TRY_RETURN_PROPAGATE_ERR(tryResult, expr) \
|
|
|
|
auto tryResult = ::mozilla::ToResult(expr); \
|
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
|
|
|
mozilla::dom::quota::QM_HANDLE_ERROR( \
|
|
|
|
expr, tryResult.inspectErr(), mozilla::dom::quota::Severity::Error); \
|
|
|
|
} \
|
2020-10-02 13:03:29 +03:00
|
|
|
return tryResult;
|
2020-09-17 17:01:01 +03:00
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// Handles the three arguments case when a custom return value needs to be
|
2020-09-17 17:01:01 +03:00
|
|
|
// returned
|
2021-05-03 22:44:40 +03:00
|
|
|
#define QM_TRY_RETURN_CUSTOM_RET_VAL(tryResult, expr, customRetVal) \
|
|
|
|
auto tryResult = ::mozilla::ToResult(expr); \
|
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
|
|
|
auto tryTempError MOZ_MAYBE_UNUSED = tryResult.unwrapErr(); \
|
|
|
|
mozilla::dom::quota::QM_HANDLE_ERROR( \
|
|
|
|
expr, tryResult.inspectErr(), mozilla::dom::quota::Severity::Error); \
|
|
|
|
return customRetVal; \
|
|
|
|
} \
|
2020-09-17 17:01:01 +03:00
|
|
|
return tryResult.unwrap();
|
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// Handles the four arguments case when a cleanup function needs to be called
|
2020-09-17 17:01:01 +03:00
|
|
|
// before a custom return value is returned
|
2021-05-03 22:44:40 +03:00
|
|
|
#define QM_TRY_RETURN_CUSTOM_RET_VAL_WITH_CLEANUP(tryResult, expr, \
|
2020-09-17 17:01:01 +03:00
|
|
|
customRetVal, cleanup) \
|
2021-01-13 14:12:22 +03:00
|
|
|
auto tryResult = ::mozilla::ToResult(expr); \
|
2020-09-17 17:01:01 +03:00
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
2020-10-02 13:04:37 +03:00
|
|
|
auto tryTempError = tryResult.unwrapErr(); \
|
2021-05-03 22:44:40 +03:00
|
|
|
mozilla::dom::quota::QM_HANDLE_ERROR( \
|
|
|
|
expr, tryTempError, mozilla::dom::quota::Severity::Error); \
|
2020-10-02 13:04:37 +03:00
|
|
|
cleanup(tryTempError); \
|
2020-09-17 17:01:01 +03:00
|
|
|
return customRetVal; \
|
|
|
|
} \
|
|
|
|
return tryResult.unwrap();
|
|
|
|
|
|
|
|
// Chooses the final implementation macro for given argument count.
|
|
|
|
// See also the comment for QM_TRY_META.
|
|
|
|
#define QM_TRY_RETURN_META(...) \
|
|
|
|
{ \
|
2021-05-03 22:44:40 +03:00
|
|
|
MOZ_ARG_6(, ##__VA_ARGS__, \
|
2020-09-17 17:01:01 +03:00
|
|
|
QM_TRY_RETURN_CUSTOM_RET_VAL_WITH_CLEANUP(__VA_ARGS__), \
|
|
|
|
QM_TRY_RETURN_CUSTOM_RET_VAL(__VA_ARGS__), \
|
|
|
|
QM_TRY_RETURN_PROPAGATE_ERR(__VA_ARGS__), \
|
2021-05-03 22:44:40 +03:00
|
|
|
QM_MISSING_ARGS(__VA_ARGS__), QM_MISSING_ARGS(__VA_ARGS__)) \
|
2020-09-17 17:01:01 +03:00
|
|
|
}
|
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// Generates unique variable name. This extra internal macro (along with
|
|
|
|
// __COUNTER__) allows nesting of the final macro.
|
|
|
|
#define QM_TRY_RETURN_GLUE(...) \
|
|
|
|
QM_TRY_RETURN_META(MOZ_UNIQUE_VAR(tryResult), ##__VA_ARGS__)
|
2020-09-17 17:01:01 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* QM_TRY_RETURN(expr[, customRetVal, cleanup]) evaluates expr, which must
|
|
|
|
* produce a Result value. On success, the result's success value is returned.
|
|
|
|
* On error, it calls HandleError and an additional cleanup function (if the
|
|
|
|
* third argument was passed) and finally returns the error result or a custom
|
|
|
|
* return value (if the second argument was passed).
|
|
|
|
*/
|
|
|
|
#define QM_TRY_RETURN(...) QM_TRY_RETURN_GLUE(__VA_ARGS__)
|
|
|
|
|
2020-08-27 14:10:10 +03:00
|
|
|
// QM_FAIL_RET_VAL and QM_FAIL_RET_VAL_WITH_CLEANUP macros are implementation
|
|
|
|
// details of QM_FAIL and shouldn't be used directly.
|
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// Handles the one argument case when just an error is returned
|
|
|
|
#define QM_FAIL_RET_VAL(retVal) \
|
|
|
|
mozilla::dom::quota::QM_HANDLE_ERROR(Failure, 0, \
|
|
|
|
mozilla::dom::quota::Severity::Error); \
|
2020-08-27 14:10:10 +03:00
|
|
|
return retVal;
|
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// Handles the two arguments case when a cleanup function needs to be called
|
2020-08-27 14:10:10 +03:00
|
|
|
// before a return value is returned
|
2021-05-03 22:44:40 +03:00
|
|
|
#define QM_FAIL_RET_VAL_WITH_CLEANUP(retVal, cleanup) \
|
|
|
|
mozilla::dom::quota::QM_HANDLE_ERROR(Failure, 0, \
|
|
|
|
mozilla::dom::quota::Severity::Error); \
|
|
|
|
cleanup(); \
|
2020-08-27 14:10:10 +03:00
|
|
|
return retVal;
|
|
|
|
|
|
|
|
// Chooses the final implementation macro for given argument count.
|
2020-09-07 21:00:00 +03:00
|
|
|
// See also the comment for QM_TRY_META.
|
2020-08-27 14:10:10 +03:00
|
|
|
#define QM_FAIL_META(...) \
|
2021-05-03 22:44:40 +03:00
|
|
|
MOZ_ARG_4(, ##__VA_ARGS__, QM_FAIL_RET_VAL_WITH_CLEANUP(__VA_ARGS__), \
|
2020-08-27 14:10:10 +03:00
|
|
|
QM_FAIL_RET_VAL(__VA_ARGS__), QM_MISSING_ARGS(__VA_ARGS__))
|
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// This extra internal macro allows nesting of the final macro.
|
|
|
|
#define QM_FAIL_GLUE(...) QM_FAIL_META(__VA_ARGS__)
|
2020-09-07 21:00:00 +03:00
|
|
|
|
2020-08-27 14:10:10 +03:00
|
|
|
/**
|
|
|
|
* QM_FAIL(retVal[, cleanup]) calls HandleError and an additional cleanup
|
|
|
|
* function (if the second argument was passed) and returns a return value.
|
|
|
|
*/
|
2020-09-07 21:00:00 +03:00
|
|
|
#define QM_FAIL(...) QM_FAIL_GLUE(__VA_ARGS__)
|
2020-08-27 14:10:10 +03:00
|
|
|
|
2021-03-24 15:27:53 +03:00
|
|
|
// QM_REPORTONLY_TRY, QM_REPORTONLY_TRY_WITH_CLEANUP, QM_REPORTONLY_TRY_GLUE
|
|
|
|
// macros are implementation details of QM_WARNONLY_TRY/QM_NOTEONLY_TRY and
|
|
|
|
// shouldn't be used directly.
|
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// Handles the three arguments case when only a warning/note is reported.
|
|
|
|
#define QM_REPORTONLY_TRY(tryResult, severity, expr) \
|
2021-03-24 15:27:53 +03:00
|
|
|
auto tryResult = ::mozilla::ToResult(expr); \
|
|
|
|
static_assert(std::is_empty_v<typename decltype(tryResult)::ok_type>); \
|
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
2021-05-03 22:44:40 +03:00
|
|
|
mozilla::dom::quota::QM_HANDLE_ERROR( \
|
|
|
|
expr, tryResult.unwrapErr(), mozilla::dom::quota::Severity::severity); \
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handles the four arguments case when a cleanup function needs to be called
|
|
|
|
#define QM_REPORTONLY_TRY_WITH_CLEANUP(tryResult, severity, expr, cleanup) \
|
|
|
|
auto tryResult = ::mozilla::ToResult(expr); \
|
|
|
|
static_assert(std::is_empty_v<typename decltype(tryResult)::ok_type>); \
|
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
|
|
|
auto tryTempError = tryResult.unwrapErr(); \
|
|
|
|
mozilla::dom::quota::QM_HANDLE_ERROR( \
|
|
|
|
expr, tryTempError, mozilla::dom::quota::Severity::severity); \
|
|
|
|
cleanup(tryTempError); \
|
2021-03-24 15:27:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Chooses the final implementation macro for given argument count.
|
|
|
|
// See also the comment for QM_TRY_META.
|
|
|
|
#define QM_REPORTONLY_TRY_META(...) \
|
|
|
|
{ \
|
2021-05-03 22:44:40 +03:00
|
|
|
MOZ_ARG_6(, ##__VA_ARGS__, QM_REPORTONLY_TRY_WITH_CLEANUP(__VA_ARGS__), \
|
2021-03-24 15:27:53 +03:00
|
|
|
QM_REPORTONLY_TRY(__VA_ARGS__), QM_MISSING_ARGS(__VA_ARGS__), \
|
2021-05-03 22:44:40 +03:00
|
|
|
QM_MISSING_ARGS(__VA_ARGS__), QM_MISSING_ARGS(__VA_ARGS__)) \
|
2021-03-24 15:27:53 +03:00
|
|
|
}
|
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// Generates unique variable name. This extra internal macro (along with
|
|
|
|
// __COUNTER__) allows nesting of the final macro.
|
|
|
|
#define QM_REPORTONLY_TRY_GLUE(severity, ...) \
|
|
|
|
QM_REPORTONLY_TRY_META(MOZ_UNIQUE_VAR(tryResult), severity, ##__VA_ARGS__)
|
2021-03-24 15:27:53 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* QM_WARNONLY_TRY(expr[, cleanup]) evaluates expr, which must produce a
|
|
|
|
* Result value with empty ok_type. On Success, it does nothing else. On error,
|
|
|
|
* it calls HandleError and an additional cleanup function (if the second
|
|
|
|
* argument was passed). This macro never returns and failures are always
|
|
|
|
* reported using a lower level of severity relative to failures reported by
|
|
|
|
* QM_TRY. The macro is intended for failures that should not be propagated.
|
|
|
|
*/
|
|
|
|
#define QM_WARNONLY_TRY(...) QM_REPORTONLY_TRY_GLUE(Warning, __VA_ARGS__)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* QM_NOTEONLY_TRY is like QM_WARNONLY_TRY. The only difference is that
|
|
|
|
* failures are reported using a lower level of severity relative to failures
|
|
|
|
* reported by QM_WARNONLY_TRY.
|
|
|
|
*/
|
|
|
|
#define QM_NOTEONLY_TRY(...) QM_REPORTONLY_TRY_GLUE(Note, __VA_ARGS__)
|
|
|
|
|
|
|
|
// QM_REPORTONLY_TRY_ASSIGN, QM_REPORTONLY_TRY_ASSIGN_WITH_CLEANUP,
|
|
|
|
// QM_REPORTONLY_TRY_ASSIGN_GLUE macros are implementation details of
|
|
|
|
// QM_WARNONLY_TRY_UNWRAP/QM_NOTEONLY_TRY_UNWRAP and shouldn't be used
|
|
|
|
// directly.
|
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// Handles the four arguments case when only a warning/note is reported.
|
|
|
|
#define QM_REPORTONLY_TRY_ASSIGN(tryResult, severity, target, expr) \
|
|
|
|
auto tryResult = (expr); \
|
|
|
|
MOZ_REMOVE_PAREN(target) = \
|
|
|
|
MOZ_LIKELY(tryResult.isOk()) \
|
|
|
|
? Some(tryResult.unwrap()) \
|
|
|
|
: mozilla::dom::quota::QM_HANDLE_ERROR_RETURN_NOTHING( \
|
|
|
|
expr, tryResult.unwrapErr(), \
|
2021-03-24 15:27:53 +03:00
|
|
|
mozilla::dom::quota::Severity::severity);
|
|
|
|
|
2021-05-03 22:44:40 +03:00
|
|
|
// Handles the five arguments case when a cleanup function needs to be called
|
|
|
|
#define QM_REPORTONLY_TRY_ASSIGN_WITH_CLEANUP(tryResult, severity, target, \
|
|
|
|
expr, cleanup) \
|
|
|
|
auto tryResult = (expr); \
|
|
|
|
MOZ_REMOVE_PAREN(target) = \
|
|
|
|
MOZ_LIKELY(tryResult.isOk()) \
|
|
|
|
? Some(tryResult.unwrap()) \
|
|
|
|
: mozilla::dom::quota::QM_HANDLE_ERROR_WITH_CLEANUP_RETURN_NOTHING( \
|
|
|
|
expr, tryResult.unwrapErr(), \
|
2021-03-24 15:27:53 +03:00
|
|
|
mozilla::dom::quota::Severity::severity, cleanup);
|
|
|
|
|
|
|
|
// Chooses the final implementation macro for given argument count.
|
|
|
|
// See also the comment for QM_TRY_META.
|
2021-05-03 22:44:40 +03:00
|
|
|
#define QM_REPORTONLY_TRY_ASSIGN_META(...) \
|
|
|
|
MOZ_ARG_7(, ##__VA_ARGS__, \
|
|
|
|
QM_REPORTONLY_TRY_ASSIGN_WITH_CLEANUP(__VA_ARGS__), \
|
|
|
|
QM_REPORTONLY_TRY_ASSIGN(__VA_ARGS__), \
|
|
|
|
QM_MISSING_ARGS(__VA_ARGS__), QM_MISSING_ARGS(__VA_ARGS__), \
|
|
|
|
QM_MISSING_ARGS(__VA_ARGS__), QM_MISSING_ARGS(__VA_ARGS__))
|
|
|
|
|
|
|
|
// Generates unique variable name. This extra internal macro (along with
|
|
|
|
// __COUNTER__) allows nesting of the final macro.
|
|
|
|
#define QM_REPORTONLY_TRY_ASSIGN_GLUE(severity, ...) \
|
|
|
|
QM_REPORTONLY_TRY_ASSIGN_META(MOZ_UNIQUE_VAR(tryResult), severity, \
|
|
|
|
##__VA_ARGS__)
|
2021-03-24 15:27:53 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* QM_WARNONLY_TRY_UNWRAP(target, expr[, cleanup]) evaluates expr, which must
|
|
|
|
* produce a Result value. On success, the result's success value is first
|
|
|
|
* unwrapped from the Result, then wrapped in a Maybe and finally assigned to
|
|
|
|
* target. On error, it calls HandleError and an additional cleanup
|
|
|
|
* function (if the third argument was passed) and finally assigns Nothing to
|
|
|
|
* target. |target| must be an lvalue. This macro never returns and failures
|
|
|
|
* are always reported using a lower level of severity relative to failures
|
|
|
|
* reported by QM_TRY_UNWRAP/QM_TRY_INSPECT. The macro is intended for failures
|
|
|
|
* that should not be propagated.
|
|
|
|
*/
|
|
|
|
#define QM_WARNONLY_TRY_UNWRAP(...) \
|
|
|
|
QM_REPORTONLY_TRY_ASSIGN_GLUE(Warning, __VA_ARGS__)
|
|
|
|
|
|
|
|
// QM_WARNONLY_TRY_INSPECT doesn't make sense.
|
|
|
|
|
|
|
|
/**
|
|
|
|
* QM_NOTEONLY_TRY_UNWRAP is like QM_WARN_CHECK_UNWRAP. The only difference is
|
|
|
|
* that failures are reported using a lower level of severity relative to
|
|
|
|
* failures reported by QM_WARN_CHECK_UNWRAP.
|
|
|
|
*/
|
|
|
|
#define QM_NOTEONLY_TRY_UNWRAP(...) \
|
|
|
|
QM_REPORTONLY_TRY_ASSIGN_GLUE(Note, __VA_ARGS__)
|
|
|
|
|
|
|
|
// QM_NOTEONLY_TRY_INSPECT doesn't make sense.
|
|
|
|
|
2021-05-29 08:05:38 +03:00
|
|
|
// QM_OR_ELSE_REPORT macro is an implementation detail of
|
2021-06-01 15:12:27 +03:00
|
|
|
// QM_OR_ELSE_WARN/QM_OR_ELSE_NOTE/QM_OR_ELSE_LOG_VERBOSE and shouldn't be used
|
2021-05-29 08:05:38 +03:00
|
|
|
// directly.
|
|
|
|
|
2021-05-29 08:05:39 +03:00
|
|
|
#define QM_OR_ELSE_REPORT(severity, expr, fallback) \
|
2021-05-29 08:05:38 +03:00
|
|
|
(expr).orElse([&](const auto& firstRes) { \
|
|
|
|
mozilla::dom::quota::QM_HANDLE_ERROR( \
|
|
|
|
#expr, firstRes, mozilla::dom::quota::Severity::severity); \
|
2021-05-29 08:05:39 +03:00
|
|
|
return fallback(firstRes); \
|
2021-05-29 08:05:38 +03:00
|
|
|
})
|
|
|
|
|
2021-03-24 15:27:53 +03:00
|
|
|
/*
|
2021-05-29 08:05:39 +03:00
|
|
|
* QM_OR_ELSE_WARN(expr, fallback) evaluates expr, which must produce a Result
|
2021-03-24 15:27:53 +03:00
|
|
|
* value. On Success, it just moves the success over. On error, it calls
|
2021-05-29 08:05:39 +03:00
|
|
|
* HandleError (with the Warning severity) and a fallback function (passed as
|
|
|
|
* the second argument) which produces a new result. Failed expr is always
|
|
|
|
* reported as a warning (the macro essentially wraps the fallback function
|
|
|
|
* with a warning). QM_OR_ELSE_WARN is a sub macro and is intended to be used
|
|
|
|
* along with one of the main macros such as QM_TRY.
|
2021-03-24 15:27:53 +03:00
|
|
|
*/
|
2021-05-29 08:05:38 +03:00
|
|
|
#define QM_OR_ELSE_WARN(...) QM_OR_ELSE_REPORT(Warning, __VA_ARGS__)
|
2021-03-24 15:27:53 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* QM_OR_ELSE_NOTE is like QM_OR_ELSE_WARN. The only difference is that
|
|
|
|
* failures are reported using a lower level of severity relative to failures
|
|
|
|
* reported by QM_OR_ELSE_WARN.
|
|
|
|
*/
|
2021-05-29 08:05:38 +03:00
|
|
|
#define QM_OR_ELSE_NOTE(...) QM_OR_ELSE_REPORT(Note, __VA_ARGS__)
|
2021-03-24 15:27:53 +03:00
|
|
|
|
2021-05-21 12:30:29 +03:00
|
|
|
/**
|
2021-06-01 15:12:27 +03:00
|
|
|
* QM_OR_ELSE_LOG_VERBOSE is like QM_OR_ELSE_WARN. The only difference is that
|
2021-05-21 12:30:29 +03:00
|
|
|
* failures are reported using the lowest severity which is currently ignored
|
|
|
|
* in LogError, so nothing goes to the console, browser console and telemetry.
|
|
|
|
* Since nothing goes to the telemetry, the macro can't signal the end of the
|
|
|
|
* underlying error stack or change the type of the error stack in the
|
|
|
|
* telemetry. For that reason, the expression shouldn't contain nested QM_TRY
|
|
|
|
* macro uses.
|
|
|
|
*/
|
2021-06-01 15:12:27 +03:00
|
|
|
#define QM_OR_ELSE_LOG_VERBOSE(...) QM_OR_ELSE_REPORT(Log, __VA_ARGS__)
|
2021-05-21 12:30:29 +03:00
|
|
|
|
2021-05-30 09:37:27 +03:00
|
|
|
namespace mozilla::dom::quota {
|
|
|
|
|
|
|
|
// XXX Support orElseIf directly in mozilla::Result
|
|
|
|
template <typename V, typename E, typename P, typename F>
|
|
|
|
auto OrElseIf(Result<V, E>&& aResult, P&& aPred, F&& aFunc) -> Result<V, E> {
|
|
|
|
return MOZ_UNLIKELY(aResult.isErr())
|
|
|
|
? (std::forward<P>(aPred)(aResult.inspectErr()))
|
|
|
|
? std::forward<F>(aFunc)(aResult.unwrapErr())
|
|
|
|
: aResult.propagateErr()
|
|
|
|
: aResult.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace mozilla::dom::quota
|
|
|
|
|
|
|
|
// QM_OR_ELSE_REPORT_IF macro is an implementation detail of
|
2021-06-01 15:12:27 +03:00
|
|
|
// QM_OR_ELSE_WARN_IF/QM_OR_ELSE_NOTE_IF/QM_OR_ELSE_LOG_VERBOSE_IF and
|
|
|
|
// shouldn't be used directly.
|
2021-05-30 09:37:27 +03:00
|
|
|
|
|
|
|
#define QM_OR_ELSE_REPORT_IF(severity, expr, predicate, fallback) \
|
|
|
|
mozilla::dom::quota::OrElseIf( \
|
|
|
|
(expr), \
|
|
|
|
[&](const auto& firstRes) { \
|
|
|
|
bool res = predicate(firstRes); \
|
|
|
|
mozilla::dom::quota::QM_HANDLE_ERROR( \
|
|
|
|
#expr, firstRes, \
|
|
|
|
res ? mozilla::dom::quota::Severity::severity \
|
|
|
|
: mozilla::dom::quota::Severity::Error); \
|
|
|
|
return res; \
|
|
|
|
}, \
|
|
|
|
fallback)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* QM_OR_ELSE_WARN_IF(expr, predicate, fallback) evaluates expr first, which
|
|
|
|
* must produce a Result value. On Success, it just moves the success over.
|
|
|
|
* On error, it calls a predicate function (passed as the second argument) and
|
|
|
|
* then it either calls HandleError (with the Warning severity) and a fallback
|
|
|
|
* function (passed as the third argument) which produces a new result if the
|
|
|
|
* predicate returned true. Or it calls HandleError (with the Error severity)
|
|
|
|
* and propagates the error result if the predicate returned false. So failed
|
|
|
|
* expr can be reported as a warning or as an error depending on the predicate.
|
|
|
|
* QM_OR_ELSE_WARN_IF is a sub macro and is intended to be used along with one
|
|
|
|
* of the main macros such as QM_TRY.
|
|
|
|
*/
|
|
|
|
#define QM_OR_ELSE_WARN_IF(...) QM_OR_ELSE_REPORT_IF(Warning, __VA_ARGS__)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* QM_OR_ELSE_NOTE_IF is like QM_OR_ELSE_WARN_IF. The only difference is that
|
|
|
|
* failures are reported using a lower level of severity relative to failures
|
|
|
|
* reported by QM_OR_ELSE_WARN_IF.
|
|
|
|
*/
|
|
|
|
#define QM_OR_ELSE_NOTE_IF(...) QM_OR_ELSE_REPORT_IF(Note, __VA_ARGS__)
|
|
|
|
|
|
|
|
/**
|
2021-06-01 15:12:27 +03:00
|
|
|
* QM_OR_ELSE_LOG_VERBOSE_IF is like QM_OR_ELSE_WARN_IF. The only difference is
|
|
|
|
* that failures are reported using the lowest severity which is currently
|
|
|
|
* ignored in LogError, so nothing goes to the console, browser console and
|
|
|
|
* telemetry. Since nothing goes to the telemetry, the macro can't signal the
|
|
|
|
* end of the underlying error stack or change the type of the error stack in
|
|
|
|
* the telemetry. For that reason, the expression shouldn't contain nested
|
|
|
|
* QM_TRY macro uses.
|
2021-05-30 09:37:27 +03:00
|
|
|
*/
|
2021-06-01 15:12:27 +03:00
|
|
|
#define QM_OR_ELSE_LOG_VERBOSE_IF(...) \
|
|
|
|
QM_OR_ELSE_REPORT_IF(Verbose, __VA_ARGS__)
|
2021-05-30 09:37:27 +03:00
|
|
|
|
2019-01-17 20:12:27 +03:00
|
|
|
// Telemetry probes to collect number of failure during the initialization.
|
|
|
|
#ifdef NIGHTLY_BUILD
|
|
|
|
# define RECORD_IN_NIGHTLY(_recorder, _status) \
|
|
|
|
do { \
|
|
|
|
if (NS_SUCCEEDED(_recorder)) { \
|
|
|
|
_recorder = _status; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
2019-01-18 12:16:18 +03:00
|
|
|
|
2021-01-05 12:27:18 +03:00
|
|
|
# define OK_IN_NIGHTLY_PROPAGATE_IN_OTHERS \
|
|
|
|
Ok {}
|
2019-06-04 16:44:11 +03:00
|
|
|
|
|
|
|
# define RETURN_STATUS_OR_RESULT(_status, _rv) \
|
2021-01-05 12:27:18 +03:00
|
|
|
return Err(NS_FAILED(_status) ? (_status) : (_rv))
|
2019-01-17 20:12:27 +03:00
|
|
|
#else
|
|
|
|
# define RECORD_IN_NIGHTLY(_dummy, _status) \
|
|
|
|
{}
|
|
|
|
|
2021-01-05 12:27:18 +03:00
|
|
|
# define OK_IN_NIGHTLY_PROPAGATE_IN_OTHERS QM_PROPAGATE
|
2019-06-04 16:44:11 +03:00
|
|
|
|
2021-01-05 12:27:18 +03:00
|
|
|
# define RETURN_STATUS_OR_RESULT(_status, _rv) return Err(_rv)
|
2019-01-17 20:12:27 +03:00
|
|
|
#endif
|
|
|
|
|
2020-12-04 17:56:18 +03:00
|
|
|
class mozIStorageConnection;
|
|
|
|
class mozIStorageStatement;
|
2020-04-01 10:26:27 +03:00
|
|
|
class nsIFile;
|
2015-11-22 12:43:55 +03:00
|
|
|
|
2019-03-21 23:08:00 +03:00
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
class LogModule;
|
|
|
|
|
2021-07-31 15:37:36 +03:00
|
|
|
struct CreateIfNonExistent {};
|
|
|
|
|
2020-07-24 13:20:42 +03:00
|
|
|
struct NotOk {};
|
|
|
|
|
|
|
|
// Allow MOZ_TRY/QM_TRY to handle `bool` values by wrapping them with OkIf.
|
|
|
|
// TODO: Maybe move this to mfbt/ResultExtensions.h
|
|
|
|
inline Result<Ok, NotOk> OkIf(bool aValue) {
|
|
|
|
if (aValue) {
|
|
|
|
return Ok();
|
|
|
|
}
|
|
|
|
return Err(NotOk());
|
|
|
|
}
|
|
|
|
|
2020-08-24 19:36:08 +03:00
|
|
|
// TODO: Maybe move this to mfbt/ResultExtensions.h
|
|
|
|
template <auto SuccessValue>
|
|
|
|
auto OkToOk(Ok) -> Result<decltype(SuccessValue), nsresult> {
|
|
|
|
return SuccessValue;
|
|
|
|
}
|
2020-07-24 10:01:35 +03:00
|
|
|
|
2020-08-24 19:36:08 +03:00
|
|
|
template <nsresult ErrorValue, auto SuccessValue,
|
|
|
|
typename V = decltype(SuccessValue)>
|
|
|
|
auto ErrToOkOrErr(nsresult aValue) -> Result<V, nsresult> {
|
|
|
|
if (aValue == ErrorValue) {
|
|
|
|
return V{SuccessValue};
|
2020-07-24 10:01:35 +03:00
|
|
|
}
|
|
|
|
return Err(aValue);
|
|
|
|
}
|
|
|
|
|
2021-03-24 15:27:53 +03:00
|
|
|
template <nsresult ErrorValue, typename V = mozilla::Ok>
|
2020-08-28 18:51:23 +03:00
|
|
|
auto ErrToDefaultOkOrErr(nsresult aValue) -> Result<V, nsresult> {
|
|
|
|
if (aValue == ErrorValue) {
|
|
|
|
return V{};
|
|
|
|
}
|
|
|
|
return Err(aValue);
|
|
|
|
}
|
|
|
|
|
2021-05-30 09:37:28 +03:00
|
|
|
// Helper template function so that QM_TRY predicates checking for a specific
|
|
|
|
// error can be concisely written as IsSpecificError<NS_SOME_ERROR> instead of
|
|
|
|
// as a more verbose lambda.
|
|
|
|
template <nsresult ErrorValue>
|
|
|
|
bool IsSpecificError(const nsresult aValue) {
|
|
|
|
return aValue == ErrorValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helper template function so that QM_TRY fallback functions that are
|
|
|
|
// converting errors into specific in-band success values can be concisely
|
|
|
|
// written as ErrToOk<SuccessValueToReturn> (with the return type inferred).
|
|
|
|
// For example, many file-related APIs that access information about a file may
|
|
|
|
// return an nsresult error code if the file does not exist. From an
|
|
|
|
// application perspective, the file not existing is not actually exceptional
|
|
|
|
// and can instead be handled by the success case.
|
|
|
|
template <auto SuccessValue, typename V = decltype(SuccessValue)>
|
|
|
|
auto ErrToOk(const nsresult aValue) -> Result<V, nsresult> {
|
|
|
|
return V{SuccessValue};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helper template function so that QM_TRY fallback functions that are
|
|
|
|
// suppressing errors by converting them into (generic) success can be
|
|
|
|
// concisely written as ErrToDefaultOk<>.
|
|
|
|
template <typename V = mozilla::Ok>
|
|
|
|
auto ErrToDefaultOk(const nsresult aValue) -> Result<V, nsresult> {
|
|
|
|
return V{};
|
|
|
|
}
|
|
|
|
|
2020-08-24 20:41:30 +03:00
|
|
|
// TODO: Maybe move this to mfbt/ResultExtensions.h
|
|
|
|
template <typename R, typename Func, typename... Args>
|
|
|
|
Result<R, nsresult> ToResultGet(const Func& aFunc, Args&&... aArgs) {
|
|
|
|
nsresult rv;
|
|
|
|
R res = aFunc(std::forward<Args>(aArgs)..., &rv);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return Err(rv);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2020-08-28 18:51:06 +03:00
|
|
|
// Like Rust's collect with a step function, not a generic iterator/range.
|
|
|
|
//
|
|
|
|
// Cond must be a function type with a return type to Result<V, E>, where
|
|
|
|
// V is convertible to bool
|
|
|
|
// - success converts to true indicates that collection shall continue
|
|
|
|
// - success converts to false indicates that collection is completed
|
|
|
|
// - error indicates that collection shall stop, propagating the error
|
|
|
|
//
|
|
|
|
// Body must a function type accepting a V xvalue with a return type convertible
|
|
|
|
// to Result<empty, E>.
|
|
|
|
template <typename Step, typename Body>
|
2020-11-17 12:04:28 +03:00
|
|
|
auto CollectEach(Step aStep, const Body& aBody)
|
2020-08-28 18:51:06 +03:00
|
|
|
-> Result<mozilla::Ok, typename std::result_of_t<Step()>::err_type> {
|
|
|
|
using StepResultType = typename std::result_of_t<Step()>::ok_type;
|
|
|
|
|
|
|
|
static_assert(std::is_empty_v<
|
|
|
|
typename std::result_of_t<Body(StepResultType &&)>::ok_type>);
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
StepResultType element;
|
|
|
|
MOZ_TRY_VAR(element, aStep());
|
|
|
|
|
|
|
|
if (!static_cast<bool>(element)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_TRY(aBody(std::move(element)));
|
|
|
|
}
|
|
|
|
|
|
|
|
return mozilla::Ok{};
|
|
|
|
}
|
|
|
|
|
2020-11-17 12:04:28 +03:00
|
|
|
// This is like std::reduce with a to-be-defined execution policy (we don't want
|
|
|
|
// to std::terminate on an error, but probably it's fine to just propagate any
|
|
|
|
// error that occurred), operating not on a pair of iterators but rather a
|
|
|
|
// generator function.
|
|
|
|
template <typename InputGenerator, typename T, typename BinaryOp>
|
|
|
|
auto ReduceEach(InputGenerator aInputGenerator, T aInit,
|
|
|
|
const BinaryOp& aBinaryOp)
|
|
|
|
-> Result<T, typename std::invoke_result_t<InputGenerator>::err_type> {
|
|
|
|
T res = std::move(aInit);
|
|
|
|
|
|
|
|
// XXX This can be done in parallel!
|
|
|
|
MOZ_TRY(CollectEach(
|
|
|
|
std::move(aInputGenerator),
|
|
|
|
[&res, &aBinaryOp](const auto& element)
|
|
|
|
-> Result<Ok,
|
|
|
|
typename std::invoke_result_t<InputGenerator>::err_type> {
|
|
|
|
MOZ_TRY_VAR(res, aBinaryOp(std::move(res), element));
|
|
|
|
|
|
|
|
return Ok{};
|
|
|
|
}));
|
|
|
|
|
|
|
|
return std::move(res);
|
|
|
|
}
|
|
|
|
|
2020-12-16 22:10:57 +03:00
|
|
|
// This is like std::reduce with a to-be-defined execution policy (we don't want
|
|
|
|
// to std::terminate on an error, but probably it's fine to just propagate any
|
|
|
|
// error that occurred).
|
|
|
|
template <typename Range, typename T, typename BinaryOp>
|
|
|
|
auto Reduce(Range&& aRange, T aInit, const BinaryOp& aBinaryOp) {
|
|
|
|
using std::begin;
|
|
|
|
using std::end;
|
|
|
|
return ReduceEach(
|
|
|
|
[it = begin(aRange), end = end(aRange)]() mutable {
|
|
|
|
auto res = ToMaybeRef(it != end ? &*it++ : nullptr);
|
|
|
|
return Result<decltype(res), typename std::invoke_result_t<
|
|
|
|
BinaryOp, T, decltype(res)>::err_type>(
|
|
|
|
res);
|
|
|
|
},
|
|
|
|
aInit, aBinaryOp);
|
|
|
|
}
|
|
|
|
|
2020-10-15 17:33:36 +03:00
|
|
|
template <typename Range, typename Body>
|
2021-01-18 11:49:48 +03:00
|
|
|
auto CollectEachInRange(Range&& aRange, const Body& aBody)
|
2020-10-15 17:33:36 +03:00
|
|
|
-> Result<mozilla::Ok, nsresult> {
|
2021-01-18 11:49:48 +03:00
|
|
|
for (auto&& element : aRange) {
|
2020-10-15 17:33:36 +03:00
|
|
|
MOZ_TRY(aBody(element));
|
|
|
|
}
|
|
|
|
|
|
|
|
return mozilla::Ok{};
|
|
|
|
}
|
|
|
|
|
2020-08-28 18:51:06 +03:00
|
|
|
// Like Rust's collect with a while loop, not a generic iterator/range.
|
|
|
|
//
|
|
|
|
// Cond must be a function type accepting no parameters with a return type
|
|
|
|
// convertible to Result<bool, E>, where
|
|
|
|
// - success true indicates that collection shall continue
|
|
|
|
// - success false indicates that collection is completed
|
|
|
|
// - error indicates that collection shall stop, propagating the error
|
|
|
|
//
|
|
|
|
// Body must a function type accepting no parameters with a return type
|
|
|
|
// convertible to Result<empty, E>.
|
|
|
|
template <typename Cond, typename Body>
|
|
|
|
auto CollectWhile(const Cond& aCond, const Body& aBody)
|
|
|
|
-> Result<mozilla::Ok, typename std::result_of_t<Cond()>::err_type> {
|
|
|
|
return CollectEach(aCond, [&aBody](bool) { return aBody(); });
|
|
|
|
}
|
|
|
|
|
2020-09-08 18:05:06 +03:00
|
|
|
template <>
|
|
|
|
class MOZ_MUST_USE_TYPE GenericErrorResult<mozilla::ipc::IPCResult> {
|
|
|
|
mozilla::ipc::IPCResult mErrorValue;
|
|
|
|
|
|
|
|
template <typename V, typename E2>
|
|
|
|
friend class Result;
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit GenericErrorResult(mozilla::ipc::IPCResult aErrorValue)
|
|
|
|
: mErrorValue(aErrorValue) {
|
|
|
|
MOZ_ASSERT(!aErrorValue);
|
|
|
|
}
|
|
|
|
|
2021-05-25 10:28:20 +03:00
|
|
|
GenericErrorResult(mozilla::ipc::IPCResult aErrorValue,
|
|
|
|
const ErrorPropagationTag&)
|
|
|
|
: GenericErrorResult(aErrorValue) {}
|
|
|
|
|
2020-09-08 18:05:06 +03:00
|
|
|
operator mozilla::ipc::IPCResult() const { return mErrorValue; }
|
|
|
|
};
|
|
|
|
|
2019-03-21 23:08:00 +03:00
|
|
|
namespace dom {
|
|
|
|
namespace quota {
|
2013-06-05 12:11:23 +04:00
|
|
|
|
2019-10-02 07:28:23 +03:00
|
|
|
extern const char kQuotaGenericDelimiter;
|
|
|
|
|
2019-01-17 20:12:27 +03:00
|
|
|
// Telemetry keys to indicate types of errors.
|
|
|
|
#ifdef NIGHTLY_BUILD
|
2019-07-20 18:56:31 +03:00
|
|
|
extern const nsLiteralCString kQuotaInternalError;
|
|
|
|
extern const nsLiteralCString kQuotaExternalError;
|
2019-01-17 20:12:27 +03:00
|
|
|
#else
|
2019-01-19 01:52:06 +03:00
|
|
|
// No need for these when we're not collecting telemetry.
|
2019-07-20 18:56:31 +03:00
|
|
|
# define kQuotaInternalError
|
|
|
|
# define kQuotaExternalError
|
2019-01-17 20:12:27 +03:00
|
|
|
#endif
|
|
|
|
|
2015-11-22 12:43:55 +03:00
|
|
|
class BackgroundThreadObject {
|
|
|
|
protected:
|
|
|
|
nsCOMPtr<nsIEventTarget> mOwningThread;
|
|
|
|
|
|
|
|
public:
|
|
|
|
void AssertIsOnOwningThread() const
|
|
|
|
#ifdef DEBUG
|
|
|
|
;
|
|
|
|
#else
|
|
|
|
{
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
nsIEventTarget* OwningThread() const;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
BackgroundThreadObject();
|
|
|
|
|
|
|
|
explicit BackgroundThreadObject(nsIEventTarget* aOwningThread);
|
|
|
|
};
|
|
|
|
|
2013-06-05 12:11:23 +04:00
|
|
|
void AssertIsOnIOThread();
|
2013-09-11 08:18:36 +04:00
|
|
|
|
|
|
|
void AssertCurrentThreadOwnsQuotaMutex();
|
|
|
|
|
|
|
|
bool IsOnIOThread();
|
2013-06-05 12:11:23 +04:00
|
|
|
|
2020-09-14 15:14:17 +03:00
|
|
|
MOZ_COLD void ReportInternalError(const char* aFile, uint32_t aLine,
|
|
|
|
const char* aStr);
|
2015-02-03 09:29:51 +03:00
|
|
|
|
2019-03-21 23:08:00 +03:00
|
|
|
LogModule* GetQuotaManagerLogger();
|
|
|
|
|
2019-10-02 07:28:23 +03:00
|
|
|
void AnonymizeCString(nsACString& aCString);
|
2019-06-09 22:46:34 +03:00
|
|
|
|
2020-08-26 17:12:45 +03:00
|
|
|
inline auto AnonymizedCString(const nsACString& aCString) {
|
|
|
|
nsAutoCString result{aCString};
|
|
|
|
AnonymizeCString(result);
|
|
|
|
return result;
|
|
|
|
}
|
2019-10-02 07:28:23 +03:00
|
|
|
|
|
|
|
void AnonymizeOriginString(nsACString& aOriginString);
|
|
|
|
|
2020-08-26 17:12:45 +03:00
|
|
|
inline auto AnonymizedOriginString(const nsACString& aOriginString) {
|
|
|
|
nsAutoCString result{aOriginString};
|
|
|
|
AnonymizeOriginString(result);
|
|
|
|
return result;
|
|
|
|
}
|
2019-10-02 07:28:23 +03:00
|
|
|
|
2020-04-06 12:28:35 +03:00
|
|
|
#ifdef XP_WIN
|
|
|
|
void CacheUseDOSDevicePathSyntaxPrefValue();
|
|
|
|
#endif
|
|
|
|
|
2020-04-01 10:26:27 +03:00
|
|
|
Result<nsCOMPtr<nsIFile>, nsresult> QM_NewLocalFile(const nsAString& aPath);
|
|
|
|
|
2020-09-08 10:40:46 +03:00
|
|
|
nsDependentCSubstring GetLeafName(const nsACString& aPath);
|
|
|
|
|
2020-10-26 17:51:32 +03:00
|
|
|
Result<nsCOMPtr<nsIFile>, nsresult> CloneFileAndAppend(
|
|
|
|
nsIFile& aDirectory, const nsAString& aPathElement);
|
|
|
|
|
2021-01-21 17:38:30 +03:00
|
|
|
enum class nsIFileKind {
|
|
|
|
ExistsAsDirectory,
|
|
|
|
ExistsAsFile,
|
|
|
|
DoesNotExist,
|
|
|
|
};
|
|
|
|
|
|
|
|
// XXX We can use this outside of QM and its clients as well, probably. Maybe it
|
|
|
|
// could be moved to xpcom/io?
|
|
|
|
Result<nsIFileKind, nsresult> GetDirEntryKind(nsIFile& aFile);
|
|
|
|
|
2020-12-04 18:15:31 +03:00
|
|
|
Result<nsCOMPtr<mozIStorageStatement>, nsresult> CreateStatement(
|
|
|
|
mozIStorageConnection& aConnection, const nsACString& aStatementString);
|
|
|
|
|
2020-12-04 18:10:07 +03:00
|
|
|
enum class SingleStepResult { AssertHasResult, ReturnNullIfNoResult };
|
|
|
|
|
|
|
|
template <SingleStepResult ResultHandling>
|
|
|
|
using SingleStepSuccessType =
|
|
|
|
std::conditional_t<ResultHandling == SingleStepResult::AssertHasResult,
|
|
|
|
NotNull<nsCOMPtr<mozIStorageStatement>>,
|
|
|
|
nsCOMPtr<mozIStorageStatement>>;
|
|
|
|
|
2020-12-04 18:15:31 +03:00
|
|
|
template <SingleStepResult ResultHandling>
|
|
|
|
Result<SingleStepSuccessType<ResultHandling>, nsresult> ExecuteSingleStep(
|
|
|
|
nsCOMPtr<mozIStorageStatement>&& aStatement);
|
|
|
|
|
2020-12-04 17:56:18 +03:00
|
|
|
// Creates a statement with the specified aStatementString, executes a single
|
2020-12-04 18:10:07 +03:00
|
|
|
// step, and returns the statement.
|
|
|
|
// Depending on the value ResultHandling,
|
|
|
|
// - it is asserted that there is a result (default resp.
|
|
|
|
// SingleStepResult::AssertHasResult), and the success type is
|
|
|
|
// MovingNotNull<nsCOMPtr<mozIStorageStatement>>
|
|
|
|
// - it is asserted that there is no result, and the success type is Ok
|
|
|
|
// - in case there is no result, nullptr is returned, and the success type is
|
|
|
|
// nsCOMPtr<mozIStorageStatement>
|
|
|
|
// Any other errors are always propagated.
|
|
|
|
template <SingleStepResult ResultHandling = SingleStepResult::AssertHasResult>
|
|
|
|
Result<SingleStepSuccessType<ResultHandling>, nsresult>
|
2020-12-04 17:56:18 +03:00
|
|
|
CreateAndExecuteSingleStepStatement(mozIStorageConnection& aConnection,
|
|
|
|
const nsACString& aStatementString);
|
|
|
|
|
Bug 1686191 - Remove module argument from LogError. r=dom-workers-and-storage-reviewers,janv
The module argument in LogError is redundant: the module information can
already be determined from the source file path. Indeed, reporting the module
separately in the telemetry events seems unnecessary. Instead, the relative
path is now reported. This is what the analysis of the telemetry data did
reconstruct anyway.
As a consequence, it's no longer necessary to define module-specific
HandleError functions, and therefore it's also unnecessary to define
module-specific TRY macros. These are retained as simple aliases for now,
but can be removed in a later patch entirely.
This also avoids misuses of a TRY macros in the wrong module, which were
happening a few times before, resulting in confusing output or telemetry
events.
Since Bug 1686191 will add some more TRY macro variants that warn, so
simplifying the module-specific aspects will simplify that task. Furthermore,
this is in preparation of moving the TRY macro extensions to MFBT.
Differential Revision: https://phabricator.services.mozilla.com/D102767
2021-03-12 18:01:21 +03:00
|
|
|
namespace detail {
|
|
|
|
|
2021-04-23 16:59:42 +03:00
|
|
|
// Determine the absolute path of the root of our built source tree so we can
|
|
|
|
// derive source-relative paths for non-exported header files in
|
|
|
|
// MakeSourceFileRelativePath. Exported header files end up in the objdir and
|
|
|
|
// we have GetObjdirDistIncludeTreeBase for that.
|
Bug 1686191 - Remove module argument from LogError. r=dom-workers-and-storage-reviewers,janv
The module argument in LogError is redundant: the module information can
already be determined from the source file path. Indeed, reporting the module
separately in the telemetry events seems unnecessary. Instead, the relative
path is now reported. This is what the analysis of the telemetry data did
reconstruct anyway.
As a consequence, it's no longer necessary to define module-specific
HandleError functions, and therefore it's also unnecessary to define
module-specific TRY macros. These are retained as simple aliases for now,
but can be removed in a later patch entirely.
This also avoids misuses of a TRY macros in the wrong module, which were
happening a few times before, resulting in confusing output or telemetry
events.
Since Bug 1686191 will add some more TRY macro variants that warn, so
simplifying the module-specific aspects will simplify that task. Furthermore,
this is in preparation of moving the TRY macro extensions to MFBT.
Differential Revision: https://phabricator.services.mozilla.com/D102767
2021-03-12 18:01:21 +03:00
|
|
|
nsDependentCSubstring GetSourceTreeBase();
|
|
|
|
|
2021-04-23 16:59:42 +03:00
|
|
|
// Determine the absolute path of the root of our built OBJDIR/dist/include
|
|
|
|
// directory. The aQuotaCommonHPath argument cleverly defaults to __FILE__
|
|
|
|
// initialized in our exported header; no argument should ever be provided to
|
|
|
|
// this method. GetSourceTreeBase handles identifying the root of the source
|
|
|
|
// tree.
|
|
|
|
nsDependentCSubstring GetObjdirDistIncludeTreeBase(
|
|
|
|
const nsLiteralCString& aQuotaCommonHPath = nsLiteralCString(__FILE__));
|
|
|
|
|
2021-04-23 15:02:58 +03:00
|
|
|
nsDependentCSubstring MakeSourceFileRelativePath(
|
|
|
|
const nsACString& aSourceFilePath);
|
Bug 1686191 - Remove module argument from LogError. r=dom-workers-and-storage-reviewers,janv
The module argument in LogError is redundant: the module information can
already be determined from the source file path. Indeed, reporting the module
separately in the telemetry events seems unnecessary. Instead, the relative
path is now reported. This is what the analysis of the telemetry data did
reconstruct anyway.
As a consequence, it's no longer necessary to define module-specific
HandleError functions, and therefore it's also unnecessary to define
module-specific TRY macros. These are retained as simple aliases for now,
but can be removed in a later patch entirely.
This also avoids misuses of a TRY macros in the wrong module, which were
happening a few times before, resulting in confusing output or telemetry
events.
Since Bug 1686191 will add some more TRY macro variants that warn, so
simplifying the module-specific aspects will simplify that task. Furthermore,
this is in preparation of moving the TRY macro extensions to MFBT.
Differential Revision: https://phabricator.services.mozilla.com/D102767
2021-03-12 18:01:21 +03:00
|
|
|
|
|
|
|
} // namespace detail
|
|
|
|
|
2021-03-24 15:27:53 +03:00
|
|
|
enum class Severity {
|
|
|
|
Error,
|
|
|
|
Warning,
|
|
|
|
Note,
|
2021-06-01 15:12:27 +03:00
|
|
|
Verbose,
|
2021-03-24 15:27:53 +03:00
|
|
|
};
|
|
|
|
|
2021-06-08 19:27:28 +03:00
|
|
|
#ifdef QM_LOG_ERROR_ENABLED
|
2021-05-25 12:06:11 +03:00
|
|
|
# ifdef QM_ERROR_STACKS_ENABLED
|
2021-05-25 12:06:10 +03:00
|
|
|
using ResultType = Variant<QMResult, nsresult, Nothing>;
|
|
|
|
|
|
|
|
void LogError(const nsACString& aExpr, const ResultType& aResult,
|
2021-04-23 15:02:58 +03:00
|
|
|
const nsACString& aSourceFilePath, int32_t aSourceFileLine,
|
2021-05-27 19:33:32 +03:00
|
|
|
Severity aSeverity)
|
|
|
|
# else
|
2021-05-28 19:33:41 +03:00
|
|
|
void LogError(const nsACString& aExpr, Maybe<nsresult> aMaybeRv,
|
2021-05-27 19:33:32 +03:00
|
|
|
const nsACString& aSourceFilePath, int32_t aSourceFileLine,
|
|
|
|
Severity aSeverity)
|
|
|
|
# endif
|
|
|
|
;
|
2021-05-25 12:06:11 +03:00
|
|
|
#endif
|
2020-09-08 10:40:46 +03:00
|
|
|
|
2020-06-25 10:16:47 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
Result<bool, nsresult> WarnIfFileIsUnknown(nsIFile& aFile,
|
2021-04-23 15:02:58 +03:00
|
|
|
const char* aSourceFilePath,
|
2021-04-23 15:02:58 +03:00
|
|
|
int32_t aSourceFileLine);
|
2020-06-25 10:16:47 +03:00
|
|
|
#endif
|
|
|
|
|
Bug 1686191 - Remove module argument from LogError. r=dom-workers-and-storage-reviewers,janv
The module argument in LogError is redundant: the module information can
already be determined from the source file path. Indeed, reporting the module
separately in the telemetry events seems unnecessary. Instead, the relative
path is now reported. This is what the analysis of the telemetry data did
reconstruct anyway.
As a consequence, it's no longer necessary to define module-specific
HandleError functions, and therefore it's also unnecessary to define
module-specific TRY macros. These are retained as simple aliases for now,
but can be removed in a later patch entirely.
This also avoids misuses of a TRY macros in the wrong module, which were
happening a few times before, resulting in confusing output or telemetry
events.
Since Bug 1686191 will add some more TRY macro variants that warn, so
simplifying the module-specific aspects will simplify that task. Furthermore,
this is in preparation of moving the TRY macro extensions to MFBT.
Differential Revision: https://phabricator.services.mozilla.com/D102767
2021-03-12 18:01:21 +03:00
|
|
|
// As HandleError is a function that will only be called in error cases, it is
|
|
|
|
// marked with MOZ_COLD to avoid bloating the code of calling functions, if it's
|
|
|
|
// not empty.
|
2020-09-14 15:14:17 +03:00
|
|
|
//
|
2020-09-08 10:40:30 +03:00
|
|
|
// For the same reason, the string-ish parameters are of type const char* rather
|
|
|
|
// than any ns*String type, to minimize the code at each call site. This
|
|
|
|
// deliberately de-optimizes runtime performance, which is uncritical during
|
|
|
|
// error handling.
|
|
|
|
//
|
Bug 1686191 - Remove module argument from LogError. r=dom-workers-and-storage-reviewers,janv
The module argument in LogError is redundant: the module information can
already be determined from the source file path. Indeed, reporting the module
separately in the telemetry events seems unnecessary. Instead, the relative
path is now reported. This is what the analysis of the telemetry data did
reconstruct anyway.
As a consequence, it's no longer necessary to define module-specific
HandleError functions, and therefore it's also unnecessary to define
module-specific TRY macros. These are retained as simple aliases for now,
but can be removed in a later patch entirely.
This also avoids misuses of a TRY macros in the wrong module, which were
happening a few times before, resulting in confusing output or telemetry
events.
Since Bug 1686191 will add some more TRY macro variants that warn, so
simplifying the module-specific aspects will simplify that task. Furthermore,
this is in preparation of moving the TRY macro extensions to MFBT.
Differential Revision: https://phabricator.services.mozilla.com/D102767
2021-03-12 18:01:21 +03:00
|
|
|
// This functions are not intended to be called
|
2020-09-08 10:40:30 +03:00
|
|
|
// directly, they should only be called from the QM_* macros.
|
2021-06-08 19:27:28 +03:00
|
|
|
#ifdef QM_LOG_ERROR_ENABLED
|
Bug 1686191 - Remove module argument from LogError. r=dom-workers-and-storage-reviewers,janv
The module argument in LogError is redundant: the module information can
already be determined from the source file path. Indeed, reporting the module
separately in the telemetry events seems unnecessary. Instead, the relative
path is now reported. This is what the analysis of the telemetry data did
reconstruct anyway.
As a consequence, it's no longer necessary to define module-specific
HandleError functions, and therefore it's also unnecessary to define
module-specific TRY macros. These are retained as simple aliases for now,
but can be removed in a later patch entirely.
This also avoids misuses of a TRY macros in the wrong module, which were
happening a few times before, resulting in confusing output or telemetry
events.
Since Bug 1686191 will add some more TRY macro variants that warn, so
simplifying the module-specific aspects will simplify that task. Furthermore,
this is in preparation of moving the TRY macro extensions to MFBT.
Differential Revision: https://phabricator.services.mozilla.com/D102767
2021-03-12 18:01:21 +03:00
|
|
|
template <typename T>
|
2021-06-08 19:27:32 +03:00
|
|
|
MOZ_COLD MOZ_NEVER_INLINE void HandleError(const char* aExpr, const T& aRv,
|
|
|
|
const char* aSourceFilePath,
|
|
|
|
int32_t aSourceFileLine,
|
|
|
|
const Severity aSeverity) {
|
2021-05-25 12:06:11 +03:00
|
|
|
# ifdef QM_ERROR_STACKS_ENABLED
|
2021-05-25 12:06:10 +03:00
|
|
|
if constexpr (std::is_same_v<T, QMResult> || std::is_same_v<T, nsresult>) {
|
|
|
|
mozilla::dom::quota::LogError(nsDependentCString(aExpr), ResultType(aRv),
|
2021-04-23 15:02:58 +03:00
|
|
|
nsDependentCString(aSourceFilePath),
|
2021-04-23 15:02:58 +03:00
|
|
|
aSourceFileLine, aSeverity);
|
Bug 1686191 - Remove module argument from LogError. r=dom-workers-and-storage-reviewers,janv
The module argument in LogError is redundant: the module information can
already be determined from the source file path. Indeed, reporting the module
separately in the telemetry events seems unnecessary. Instead, the relative
path is now reported. This is what the analysis of the telemetry data did
reconstruct anyway.
As a consequence, it's no longer necessary to define module-specific
HandleError functions, and therefore it's also unnecessary to define
module-specific TRY macros. These are retained as simple aliases for now,
but can be removed in a later patch entirely.
This also avoids misuses of a TRY macros in the wrong module, which were
happening a few times before, resulting in confusing output or telemetry
events.
Since Bug 1686191 will add some more TRY macro variants that warn, so
simplifying the module-specific aspects will simplify that task. Furthermore,
this is in preparation of moving the TRY macro extensions to MFBT.
Differential Revision: https://phabricator.services.mozilla.com/D102767
2021-03-12 18:01:21 +03:00
|
|
|
} else {
|
2021-05-25 12:06:10 +03:00
|
|
|
mozilla::dom::quota::LogError(
|
|
|
|
nsDependentCString(aExpr), ResultType(Nothing{}),
|
|
|
|
nsDependentCString(aSourceFilePath), aSourceFileLine, aSeverity);
|
Bug 1686191 - Remove module argument from LogError. r=dom-workers-and-storage-reviewers,janv
The module argument in LogError is redundant: the module information can
already be determined from the source file path. Indeed, reporting the module
separately in the telemetry events seems unnecessary. Instead, the relative
path is now reported. This is what the analysis of the telemetry data did
reconstruct anyway.
As a consequence, it's no longer necessary to define module-specific
HandleError functions, and therefore it's also unnecessary to define
module-specific TRY macros. These are retained as simple aliases for now,
but can be removed in a later patch entirely.
This also avoids misuses of a TRY macros in the wrong module, which were
happening a few times before, resulting in confusing output or telemetry
events.
Since Bug 1686191 will add some more TRY macro variants that warn, so
simplifying the module-specific aspects will simplify that task. Furthermore,
this is in preparation of moving the TRY macro extensions to MFBT.
Differential Revision: https://phabricator.services.mozilla.com/D102767
2021-03-12 18:01:21 +03:00
|
|
|
}
|
2021-05-27 19:33:32 +03:00
|
|
|
# else
|
|
|
|
if constexpr (std::is_same_v<T, nsresult>) {
|
|
|
|
mozilla::dom::quota::LogError(nsDependentCString(aExpr), Some(aRv),
|
|
|
|
nsDependentCString(aSourceFilePath),
|
|
|
|
aSourceFileLine, aSeverity);
|
|
|
|
} else {
|
|
|
|
mozilla::dom::quota::LogError(nsDependentCString(aExpr), Nothing{},
|
|
|
|
nsDependentCString(aSourceFilePath),
|
|
|
|
aSourceFileLine, aSeverity);
|
|
|
|
}
|
|
|
|
# endif
|
Bug 1686191 - Remove module argument from LogError. r=dom-workers-and-storage-reviewers,janv
The module argument in LogError is redundant: the module information can
already be determined from the source file path. Indeed, reporting the module
separately in the telemetry events seems unnecessary. Instead, the relative
path is now reported. This is what the analysis of the telemetry data did
reconstruct anyway.
As a consequence, it's no longer necessary to define module-specific
HandleError functions, and therefore it's also unnecessary to define
module-specific TRY macros. These are retained as simple aliases for now,
but can be removed in a later patch entirely.
This also avoids misuses of a TRY macros in the wrong module, which were
happening a few times before, resulting in confusing output or telemetry
events.
Since Bug 1686191 will add some more TRY macro variants that warn, so
simplifying the module-specific aspects will simplify that task. Furthermore,
this is in preparation of moving the TRY macro extensions to MFBT.
Differential Revision: https://phabricator.services.mozilla.com/D102767
2021-03-12 18:01:21 +03:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
template <typename T>
|
|
|
|
MOZ_ALWAYS_INLINE constexpr void HandleError(const char* aExpr, const T& aRv,
|
2021-04-23 15:02:58 +03:00
|
|
|
const char* aSourceFilePath,
|
2021-04-23 15:02:58 +03:00
|
|
|
int32_t aSourceFileLine,
|
2021-03-24 15:27:53 +03:00
|
|
|
const Severity aSeverity) {}
|
Bug 1686191 - Remove module argument from LogError. r=dom-workers-and-storage-reviewers,janv
The module argument in LogError is redundant: the module information can
already be determined from the source file path. Indeed, reporting the module
separately in the telemetry events seems unnecessary. Instead, the relative
path is now reported. This is what the analysis of the telemetry data did
reconstruct anyway.
As a consequence, it's no longer necessary to define module-specific
HandleError functions, and therefore it's also unnecessary to define
module-specific TRY macros. These are retained as simple aliases for now,
but can be removed in a later patch entirely.
This also avoids misuses of a TRY macros in the wrong module, which were
happening a few times before, resulting in confusing output or telemetry
events.
Since Bug 1686191 will add some more TRY macro variants that warn, so
simplifying the module-specific aspects will simplify that task. Furthermore,
this is in preparation of moving the TRY macro extensions to MFBT.
Differential Revision: https://phabricator.services.mozilla.com/D102767
2021-03-12 18:01:21 +03:00
|
|
|
#endif
|
2020-07-24 10:11:24 +03:00
|
|
|
|
2021-03-24 15:27:53 +03:00
|
|
|
template <typename T>
|
|
|
|
Nothing HandleErrorReturnNothing(const char* aExpr, const T& aRv,
|
2021-04-23 15:02:58 +03:00
|
|
|
const char* aSourceFilePath,
|
2021-04-23 15:02:58 +03:00
|
|
|
int32_t aSourceFileLine,
|
2021-03-24 15:27:53 +03:00
|
|
|
const Severity aSeverity) {
|
2021-04-23 15:02:58 +03:00
|
|
|
HandleError(aExpr, aRv, aSourceFilePath, aSourceFileLine, aSeverity);
|
2021-03-24 15:27:53 +03:00
|
|
|
return Nothing();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, typename CleanupFunc>
|
|
|
|
Nothing HandleErrorWithCleanupReturnNothing(const char* aExpr, const T& aRv,
|
2021-04-23 15:02:58 +03:00
|
|
|
const char* aSourceFilePath,
|
2021-04-23 15:02:58 +03:00
|
|
|
int32_t aSourceFileLine,
|
2021-03-24 15:27:53 +03:00
|
|
|
const Severity aSeverity,
|
|
|
|
CleanupFunc&& aCleanupFunc) {
|
2021-04-23 15:02:58 +03:00
|
|
|
HandleError(aExpr, aRv, aSourceFilePath, aSourceFileLine, aSeverity);
|
2021-03-24 15:27:53 +03:00
|
|
|
std::forward<CleanupFunc>(aCleanupFunc)(aRv);
|
|
|
|
return Nothing();
|
|
|
|
}
|
|
|
|
|
2020-12-04 18:15:31 +03:00
|
|
|
template <SingleStepResult ResultHandling = SingleStepResult::AssertHasResult,
|
|
|
|
typename BindFunctor>
|
|
|
|
Result<SingleStepSuccessType<ResultHandling>, nsresult>
|
|
|
|
CreateAndExecuteSingleStepStatement(mozIStorageConnection& aConnection,
|
|
|
|
const nsACString& aStatementString,
|
|
|
|
BindFunctor aBindFunctor) {
|
|
|
|
QM_TRY_UNWRAP(auto stmt, CreateStatement(aConnection, aStatementString));
|
|
|
|
|
|
|
|
QM_TRY(aBindFunctor(*stmt));
|
|
|
|
|
|
|
|
return ExecuteSingleStep<ResultHandling>(std::move(stmt));
|
|
|
|
}
|
|
|
|
|
2020-12-14 13:42:36 +03:00
|
|
|
template <typename StepFunc>
|
|
|
|
Result<Ok, nsresult> CollectWhileHasResult(mozIStorageStatement& aStmt,
|
|
|
|
StepFunc&& aStepFunc) {
|
|
|
|
return CollectWhile(
|
|
|
|
[&aStmt] { QM_TRY_RETURN(MOZ_TO_RESULT_INVOKE(aStmt, ExecuteStep)); },
|
|
|
|
[&aStmt, &aStepFunc] { return aStepFunc(aStmt); });
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename StepFunc,
|
|
|
|
typename ArrayType = nsTArray<typename std::invoke_result_t<
|
|
|
|
StepFunc, mozIStorageStatement&>::ok_type>>
|
|
|
|
auto CollectElementsWhileHasResult(mozIStorageStatement& aStmt,
|
|
|
|
StepFunc&& aStepFunc)
|
|
|
|
-> Result<ArrayType, nsresult> {
|
|
|
|
ArrayType res;
|
|
|
|
|
|
|
|
QM_TRY(CollectWhileHasResult(
|
|
|
|
aStmt, [&aStepFunc, &res](auto& stmt) -> Result<Ok, nsresult> {
|
|
|
|
QM_TRY_UNWRAP(auto element, aStepFunc(stmt));
|
|
|
|
res.AppendElement(std::move(element));
|
|
|
|
return Ok{};
|
|
|
|
}));
|
|
|
|
|
|
|
|
return std::move(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename ArrayType, typename StepFunc>
|
|
|
|
auto CollectElementsWhileHasResultTyped(mozIStorageStatement& aStmt,
|
|
|
|
StepFunc&& aStepFunc) {
|
|
|
|
return CollectElementsWhileHasResult<StepFunc, ArrayType>(
|
|
|
|
aStmt, std::forward<StepFunc>(aStepFunc));
|
|
|
|
}
|
|
|
|
|
2021-01-05 12:27:18 +03:00
|
|
|
namespace detail {
|
|
|
|
template <typename Cancel, typename Body>
|
|
|
|
Result<mozilla::Ok, nsresult> CollectEachFile(nsIFile& aDirectory,
|
|
|
|
const Cancel& aCancel,
|
|
|
|
const Body& aBody) {
|
|
|
|
QM_TRY_INSPECT(const auto& entries,
|
|
|
|
MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<nsIDirectoryEnumerator>,
|
|
|
|
aDirectory, GetDirectoryEntries));
|
|
|
|
|
|
|
|
return CollectEach(
|
|
|
|
[&entries, &aCancel]() -> Result<nsCOMPtr<nsIFile>, nsresult> {
|
|
|
|
if (aCancel()) {
|
|
|
|
return nsCOMPtr<nsIFile>{};
|
|
|
|
}
|
|
|
|
|
|
|
|
QM_TRY_RETURN(MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<nsIFile>, entries,
|
|
|
|
GetNextFile));
|
|
|
|
},
|
|
|
|
aBody);
|
|
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
|
|
|
|
template <typename Body>
|
|
|
|
Result<mozilla::Ok, nsresult> CollectEachFile(nsIFile& aDirectory,
|
|
|
|
const Body& aBody) {
|
|
|
|
return detail::CollectEachFile(
|
|
|
|
aDirectory, [] { return false; }, aBody);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Body>
|
|
|
|
Result<mozilla::Ok, nsresult> CollectEachFileAtomicCancelable(
|
|
|
|
nsIFile& aDirectory, const Atomic<bool>& aCanceled, const Body& aBody) {
|
|
|
|
return detail::CollectEachFile(
|
|
|
|
aDirectory, [&aCanceled] { return static_cast<bool>(aCanceled); }, aBody);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, typename Body>
|
|
|
|
auto ReduceEachFileAtomicCancelable(nsIFile& aDirectory,
|
|
|
|
const Atomic<bool>& aCanceled, T aInit,
|
|
|
|
const Body& aBody) -> Result<T, nsresult> {
|
|
|
|
QM_TRY_INSPECT(const auto& entries,
|
|
|
|
MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<nsIDirectoryEnumerator>,
|
|
|
|
aDirectory, GetDirectoryEntries));
|
|
|
|
|
|
|
|
return ReduceEach(
|
|
|
|
[&entries, &aCanceled]() -> Result<nsCOMPtr<nsIFile>, nsresult> {
|
|
|
|
if (aCanceled) {
|
|
|
|
return nsCOMPtr<nsIFile>{};
|
|
|
|
}
|
|
|
|
|
|
|
|
QM_TRY_RETURN(MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<nsIFile>, entries,
|
|
|
|
GetNextFile));
|
|
|
|
},
|
|
|
|
std::move(aInit), aBody);
|
|
|
|
}
|
|
|
|
|
2021-02-04 14:43:22 +03:00
|
|
|
constexpr bool IsDatabaseCorruptionError(const nsresult aRv) {
|
|
|
|
return aRv == NS_ERROR_FILE_CORRUPTED || aRv == NS_ERROR_STORAGE_IOERR;
|
|
|
|
}
|
|
|
|
|
2021-02-19 22:48:30 +03:00
|
|
|
template <typename Func>
|
|
|
|
auto CallWithDelayedRetriesIfAccessDenied(Func&& aFunc, uint32_t aMaxRetries,
|
|
|
|
uint32_t aDelayMs)
|
|
|
|
-> Result<typename std::result_of_t<Func()>::ok_type, nsresult> {
|
|
|
|
uint32_t retries = 0;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
auto result = std::forward<Func>(aFunc)();
|
|
|
|
|
|
|
|
if (result.isOk()) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result.inspectErr() != NS_ERROR_FILE_IS_LOCKED &&
|
|
|
|
result.inspectErr() != NS_ERROR_FILE_ACCESS_DENIED) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retries++ >= aMaxRetries) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
PR_Sleep(PR_MillisecondsToInterval(aDelayMs));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-31 15:37:36 +03:00
|
|
|
namespace detail {
|
|
|
|
|
|
|
|
template <bool flag = false>
|
|
|
|
void UnsupportedReturnType() {
|
|
|
|
static_assert(flag, "Unsupported return type!");
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace detail
|
|
|
|
|
|
|
|
template <typename Initialization, typename StringGenerator, typename Func>
|
|
|
|
auto ExecuteInitialization(
|
2021-07-31 15:37:36 +03:00
|
|
|
FirstInitializationAttempts<Initialization, StringGenerator>&
|
|
|
|
aFirstInitializationAttempts,
|
2021-07-31 15:37:36 +03:00
|
|
|
const Initialization aInitialization, Func&& aFunc)
|
|
|
|
-> std::invoke_result_t<Func> {
|
|
|
|
using RetType = std::invoke_result_t<Func>;
|
|
|
|
|
|
|
|
auto res = std::forward<Func>(aFunc)();
|
|
|
|
|
|
|
|
const auto rv = [&res]() -> nsresult {
|
|
|
|
if constexpr (std::is_same_v<RetType, nsresult>) {
|
|
|
|
return res;
|
|
|
|
} else if constexpr (mozilla::detail::IsResult<RetType>::value &&
|
|
|
|
std::is_same_v<typename RetType::err_type, nsresult>) {
|
|
|
|
return res.isOk() ? NS_OK : res.inspectErr();
|
|
|
|
} else {
|
|
|
|
detail::UnsupportedReturnType();
|
|
|
|
}
|
|
|
|
}();
|
|
|
|
|
2021-07-31 15:37:36 +03:00
|
|
|
// NS_ERROR_ABORT signals a non-fatal, recoverable problem during
|
|
|
|
// initialization. We do not want these kind of failures to count against our
|
|
|
|
// overall first initialization attempt telemetry. Thus we just ignore this
|
|
|
|
// kind of failure and keep aFirstInitializationAttempts unflagged to stay
|
|
|
|
// ready to record a real success or failure on the next attempt.
|
2021-07-31 15:37:36 +03:00
|
|
|
if (rv == NS_ERROR_ABORT) {
|
|
|
|
return res;
|
2021-07-31 15:37:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!aFirstInitializationAttempts.FirstInitializationAttemptRecorded(
|
|
|
|
aInitialization)) {
|
|
|
|
aFirstInitializationAttempts.RecordFirstInitializationAttempt(
|
2021-07-31 15:37:36 +03:00
|
|
|
aInitialization, rv);
|
2021-07-31 15:37:36 +03:00
|
|
|
}
|
|
|
|
|
2021-07-31 15:37:36 +03:00
|
|
|
return res;
|
2021-07-31 15:37:36 +03:00
|
|
|
}
|
|
|
|
|
2019-03-21 23:08:00 +03:00
|
|
|
} // namespace quota
|
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|
2013-06-05 12:11:23 +04:00
|
|
|
|
2012-12-17 23:25:10 +04:00
|
|
|
#endif // mozilla_dom_quota_quotacommon_h__
|