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__
|
|
|
|
|
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"
|
2015-02-03 09:29:51 +03:00
|
|
|
#include "nsPrintfCString.h"
|
2013-09-23 21:25:00 +04:00
|
|
|
#include "nsString.h"
|
2012-12-17 23:25:10 +04:00
|
|
|
#include "nsTArray.h"
|
|
|
|
|
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)...); \
|
|
|
|
}
|
|
|
|
|
2012-12-17 23:25:10 +04:00
|
|
|
#define BEGIN_QUOTA_NAMESPACE \
|
|
|
|
namespace mozilla { \
|
|
|
|
namespace dom { \
|
|
|
|
namespace quota {
|
|
|
|
#define END_QUOTA_NAMESPACE \
|
|
|
|
} /* namespace quota */ \
|
|
|
|
} /* namespace dom */ \
|
|
|
|
} /* namespace mozilla */
|
|
|
|
#define USING_QUOTA_NAMESPACE using namespace mozilla::dom::quota;
|
|
|
|
|
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)
|
|
|
|
|
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 13:38:34 +03:00
|
|
|
#define QM_ASSERT_UNREACHABLE \
|
|
|
|
[&tryTempError] { \
|
|
|
|
MOZ_ASSERT(false); \
|
|
|
|
return Err(tryTempError); \
|
|
|
|
}()
|
2020-10-14 16:03:35 +03:00
|
|
|
|
2020-10-19 13:38:34 +03:00
|
|
|
#define QM_ASSERT_UNREACHABLE_VOID [] { MOZ_ASSERT(false); }()
|
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
|
2020-09-08 10:40:30 +03:00
|
|
|
# define QM_HANDLE_ERROR(expr) HandleError(# expr, __FILE__, __LINE__)
|
2020-08-28 14:44:46 +03:00
|
|
|
#else
|
2020-09-08 10:40:30 +03:00
|
|
|
# define QM_HANDLE_ERROR(expr) HandleError("Unavailable", __FILE__, __LINE__)
|
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
|
|
|
|
2020-09-07 21:00:00 +03:00
|
|
|
// Handles the three arguments case when the error is propagated.
|
2020-09-18 17:51:54 +03:00
|
|
|
#define QM_TRY_PROPAGATE_ERR(ns, tryResult, expr) \
|
|
|
|
auto tryResult = ::mozilla::ToResult(expr); \
|
|
|
|
static_assert(std::is_empty_v<typename decltype(tryResult)::ok_type>); \
|
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
|
|
|
ns::QM_HANDLE_ERROR(expr); \
|
|
|
|
return tryResult.propagateErr(); \
|
2020-08-21 11:11:25 +03:00
|
|
|
}
|
2020-07-24 10:11:24 +03:00
|
|
|
|
2020-09-07 21:00:00 +03:00
|
|
|
// Handles the four arguments case when a custom return value needs to be
|
2020-08-21 11:11:25 +03:00
|
|
|
// returned
|
2020-09-18 17:51:54 +03:00
|
|
|
#define QM_TRY_CUSTOM_RET_VAL(ns, tryResult, expr, customRetVal) \
|
|
|
|
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(); \
|
2020-09-18 17:51:54 +03:00
|
|
|
ns::QM_HANDLE_ERROR(expr); \
|
|
|
|
return customRetVal; \
|
2020-08-21 11:11:25 +03:00
|
|
|
}
|
|
|
|
|
2020-09-07 21:00:00 +03:00
|
|
|
// Handles the five 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
|
2020-09-07 21:00:00 +03:00
|
|
|
#define QM_TRY_CUSTOM_RET_VAL_WITH_CLEANUP(ns, tryResult, expr, customRetVal, \
|
|
|
|
cleanup) \
|
|
|
|
auto tryResult = ::mozilla::ToResult(expr); \
|
2020-09-18 17:51:54 +03:00
|
|
|
static_assert(std::is_empty_v<typename decltype(tryResult)::ok_type>); \
|
2020-09-07 21:00:00 +03:00
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
2020-10-02 13:04:37 +03:00
|
|
|
auto tryTempError = tryResult.unwrapErr(); \
|
2020-09-07 21:00:00 +03:00
|
|
|
ns::QM_HANDLE_ERROR(expr); \
|
2020-10-02 13:04:37 +03:00
|
|
|
cleanup(tryTempError); \
|
2020-09-07 21:00:00 +03:00
|
|
|
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.
|
|
|
|
// It can be used by other modules to define module specific error handling.
|
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(...) \
|
|
|
|
{ \
|
|
|
|
MOZ_ARG_7(, ##__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__), QM_MISSING_ARGS(__VA_ARGS__)) \
|
|
|
|
}
|
2020-09-07 21:00:00 +03:00
|
|
|
|
|
|
|
// Specifies the namespace and generates unique variable name. This extra
|
|
|
|
// internal macro (along with __COUNTER__) allows nesting of the final macro.
|
|
|
|
#define QM_TRY_GLUE(...) \
|
|
|
|
QM_TRY_META(mozilla::dom::quota, 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
|
|
|
|
* `try!(expr);`. First, it evaluates expr, which must produce a Result value.
|
|
|
|
* On success, it discards the result altogether. On error, it calls
|
|
|
|
* 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
|
|
|
|
2020-09-29 13:57:14 +03:00
|
|
|
// Handles the five arguments case when the error is propagated.
|
2020-10-14 15:14:14 +03:00
|
|
|
#define QM_TRY_ASSIGN_PROPAGATE_ERR(ns, tryResult, accessFunction, target, \
|
|
|
|
expr) \
|
|
|
|
auto tryResult = (expr); \
|
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
|
|
|
ns::QM_HANDLE_ERROR(expr); \
|
|
|
|
return tryResult.propagateErr(); \
|
|
|
|
} \
|
2020-09-29 13:57:14 +03:00
|
|
|
MOZ_REMOVE_PAREN(target) = tryResult.accessFunction();
|
|
|
|
|
|
|
|
// Handles the six arguments case when a custom return value needs to be
|
2020-08-21 11:11:25 +03:00
|
|
|
// returned
|
2020-10-14 15:14:14 +03:00
|
|
|
#define QM_TRY_ASSIGN_CUSTOM_RET_VAL(ns, tryResult, accessFunction, target, \
|
|
|
|
expr, customRetVal) \
|
|
|
|
auto tryResult = (expr); \
|
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
|
|
|
auto tryTempError MOZ_MAYBE_UNUSED = tryResult.unwrapErr(); \
|
|
|
|
ns::QM_HANDLE_ERROR(expr); \
|
|
|
|
return customRetVal; \
|
|
|
|
} \
|
2020-09-29 13:57:14 +03:00
|
|
|
MOZ_REMOVE_PAREN(target) = tryResult.accessFunction();
|
|
|
|
|
|
|
|
// Handles the seven 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
|
2020-10-14 15:14:14 +03:00
|
|
|
#define QM_TRY_ASSIGN_CUSTOM_RET_VAL_WITH_CLEANUP( \
|
2020-09-29 13:57:14 +03:00
|
|
|
ns, tryResult, accessFunction, target, expr, customRetVal, cleanup) \
|
|
|
|
auto tryResult = (expr); \
|
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
2020-10-02 13:04:37 +03:00
|
|
|
auto tryTempError = tryResult.unwrapErr(); \
|
2020-09-29 13:57:14 +03:00
|
|
|
ns::QM_HANDLE_ERROR(expr); \
|
2020-10-02 13:04:37 +03:00
|
|
|
cleanup(tryTempError); \
|
2020-09-29 13:57:14 +03:00
|
|
|
return customRetVal; \
|
|
|
|
} \
|
|
|
|
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.
|
|
|
|
// It can be used by other modules to define module specific error handling.
|
2020-09-07 21:00:00 +03:00
|
|
|
// See also the comment for QM_TRY_META.
|
2020-10-14 15:14:14 +03:00
|
|
|
#define QM_TRY_ASSIGN_META(...) \
|
|
|
|
MOZ_ARG_9( \
|
|
|
|
, ##__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__), \
|
2020-09-29 13:57:14 +03:00
|
|
|
QM_MISSING_ARGS(__VA_ARGS__), QM_MISSING_ARGS(__VA_ARGS__))
|
2020-09-07 21:00:00 +03:00
|
|
|
|
|
|
|
// Specifies the namespace and generates unique variable name. This extra
|
|
|
|
// internal macro (along with __COUNTER__) allows nesting of the final macro.
|
2020-10-14 15:14:14 +03:00
|
|
|
#define QM_TRY_ASSIGN_GLUE(accessFunction, ...) \
|
|
|
|
QM_TRY_ASSIGN_META(mozilla::dom::quota, 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.
|
|
|
|
|
2020-10-02 13:03:29 +03:00
|
|
|
// Handles the three arguments case when the error is (also) propagated.
|
|
|
|
// 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.
|
2020-09-17 17:01:01 +03:00
|
|
|
#define QM_TRY_RETURN_PROPAGATE_ERR(ns, tryResult, expr) \
|
|
|
|
auto tryResult = (expr); \
|
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
|
|
|
ns::QM_HANDLE_ERROR(expr); \
|
|
|
|
} \
|
2020-10-02 13:03:29 +03:00
|
|
|
return tryResult;
|
2020-09-17 17:01:01 +03:00
|
|
|
|
|
|
|
// Handles the four arguments case when a custom return value needs to be
|
|
|
|
// returned
|
|
|
|
#define QM_TRY_RETURN_CUSTOM_RET_VAL(ns, tryResult, expr, customRetVal) \
|
|
|
|
auto tryResult = (expr); \
|
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
2020-10-02 13:04:37 +03:00
|
|
|
auto tryTempError MOZ_MAYBE_UNUSED = tryResult.unwrapErr(); \
|
2020-09-17 17:01:01 +03:00
|
|
|
ns::QM_HANDLE_ERROR(expr); \
|
|
|
|
return customRetVal; \
|
|
|
|
} \
|
|
|
|
return tryResult.unwrap();
|
|
|
|
|
|
|
|
// Handles the five arguments case when a cleanup function needs to be called
|
|
|
|
// before a custom return value is returned
|
|
|
|
#define QM_TRY_RETURN_CUSTOM_RET_VAL_WITH_CLEANUP(ns, tryResult, expr, \
|
|
|
|
customRetVal, cleanup) \
|
|
|
|
auto tryResult = (expr); \
|
|
|
|
if (MOZ_UNLIKELY(tryResult.isErr())) { \
|
2020-10-02 13:04:37 +03:00
|
|
|
auto tryTempError = tryResult.unwrapErr(); \
|
2020-09-17 17:01:01 +03:00
|
|
|
ns::QM_HANDLE_ERROR(expr); \
|
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.
|
|
|
|
// It can be used by other modules to define module specific error handling.
|
|
|
|
// See also the comment for QM_TRY_META.
|
|
|
|
#define QM_TRY_RETURN_META(...) \
|
|
|
|
{ \
|
|
|
|
MOZ_ARG_7(, ##__VA_ARGS__, \
|
|
|
|
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__), \
|
|
|
|
QM_MISSING_ARGS(__VA_ARGS__), QM_MISSING_ARGS(__VA_ARGS__), \
|
|
|
|
QM_MISSING_ARGS(__VA_ARGS__)) \
|
|
|
|
}
|
|
|
|
|
|
|
|
// Specifies the namespace and 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(mozilla::dom::quota, MOZ_UNIQUE_VAR(tryResult), \
|
|
|
|
##__VA_ARGS__)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
|
|
|
|
// Handles the two arguments case when just an error is returned
|
2020-08-28 14:44:46 +03:00
|
|
|
#define QM_FAIL_RET_VAL(ns, retVal) \
|
|
|
|
ns::QM_HANDLE_ERROR(Failure); \
|
2020-08-27 14:10:10 +03:00
|
|
|
return retVal;
|
|
|
|
|
|
|
|
// Handles the three arguments case when a cleanup function needs to be called
|
|
|
|
// before a return value is returned
|
2020-08-28 14:44:46 +03:00
|
|
|
#define QM_FAIL_RET_VAL_WITH_CLEANUP(ns, retVal, cleanup) \
|
|
|
|
ns::QM_HANDLE_ERROR(Failure); \
|
|
|
|
cleanup(); \
|
2020-08-27 14:10:10 +03:00
|
|
|
return retVal;
|
|
|
|
|
|
|
|
// Chooses the final implementation macro for given argument count.
|
|
|
|
// It can be used by other modules to define module specific error handling.
|
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(...) \
|
|
|
|
MOZ_ARG_5(, ##__VA_ARGS__, QM_FAIL_RET_VAL_WITH_CLEANUP(__VA_ARGS__), \
|
|
|
|
QM_FAIL_RET_VAL(__VA_ARGS__), QM_MISSING_ARGS(__VA_ARGS__))
|
|
|
|
|
2020-09-07 21:00:00 +03:00
|
|
|
// Specifies the namespace. This extra internal macro allows nesting of the
|
|
|
|
// final macro.
|
|
|
|
#define QM_FAIL_GLUE(...) QM_FAIL_META(mozilla::dom::quota, ##__VA_ARGS__)
|
|
|
|
|
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
|
|
|
|
2019-01-17 20:12:27 +03:00
|
|
|
// Telemetry probes to collect number of failure during the initialization.
|
|
|
|
#ifdef NIGHTLY_BUILD
|
|
|
|
# define REPORT_TELEMETRY_INIT_ERR(_key, _label) \
|
|
|
|
mozilla::Telemetry::AccumulateCategoricalKeyed( \
|
|
|
|
mozilla::dom::quota::_key, \
|
|
|
|
mozilla::Telemetry::LABELS_QM_INIT_TELEMETRY_ERROR::_label);
|
2019-01-18 12:16:18 +03:00
|
|
|
|
2019-01-17 20:12:27 +03:00
|
|
|
# define REPORT_TELEMETRY_ERR_IN_INIT(_initializing, _key, _label) \
|
|
|
|
do { \
|
|
|
|
if (_initializing) { \
|
|
|
|
REPORT_TELEMETRY_INIT_ERR(_key, _label) \
|
|
|
|
} \
|
|
|
|
} while (0)
|
2019-01-18 12:16:18 +03:00
|
|
|
|
2019-01-17 20:12:27 +03:00
|
|
|
# define RECORD_IN_NIGHTLY(_recorder, _status) \
|
|
|
|
do { \
|
|
|
|
if (NS_SUCCEEDED(_recorder)) { \
|
|
|
|
_recorder = _status; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
2019-01-18 12:16:18 +03:00
|
|
|
|
2019-01-17 20:12:27 +03:00
|
|
|
# define CONTINUE_IN_NIGHTLY_RETURN_IN_OTHERS(_dummy) continue
|
2019-06-04 16:44:11 +03:00
|
|
|
|
|
|
|
# define RETURN_STATUS_OR_RESULT(_status, _rv) \
|
|
|
|
return NS_FAILED(_status) ? _status : _rv
|
2019-01-17 20:12:27 +03:00
|
|
|
#else
|
|
|
|
# define REPORT_TELEMETRY_INIT_ERR(_key, _label) \
|
|
|
|
{}
|
|
|
|
|
|
|
|
# define REPORT_TELEMETRY_ERR_IN_INIT(_initializing, _key, _label) \
|
|
|
|
{}
|
|
|
|
|
|
|
|
# define RECORD_IN_NIGHTLY(_dummy, _status) \
|
|
|
|
{}
|
|
|
|
|
|
|
|
# define CONTINUE_IN_NIGHTLY_RETURN_IN_OTHERS(_rv) return _rv
|
2019-06-04 16:44:11 +03:00
|
|
|
|
|
|
|
# define RETURN_STATUS_OR_RESULT(_status, _rv) return _rv
|
2019-01-17 20:12:27 +03:00
|
|
|
#endif
|
|
|
|
|
2015-11-22 12:43:55 +03:00
|
|
|
class nsIEventTarget;
|
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;
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-08-28 18:51:23 +03:00
|
|
|
template <nsresult ErrorValue, typename V>
|
|
|
|
auto ErrToDefaultOkOrErr(nsresult aValue) -> Result<V, nsresult> {
|
|
|
|
if (aValue == ErrorValue) {
|
|
|
|
return V{};
|
|
|
|
}
|
|
|
|
return Err(aValue);
|
|
|
|
}
|
|
|
|
|
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>
|
|
|
|
auto CollectEach(const Step& aStep, const Body& aBody)
|
|
|
|
-> 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-10-15 17:33:36 +03:00
|
|
|
template <typename Range, typename Body>
|
|
|
|
auto CollectEachInRange(const Range& aRange, const Body& aBody)
|
|
|
|
-> Result<mozilla::Ok, nsresult> {
|
|
|
|
for (const auto& element : aRange) {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void StringifyTableKeys(const T& aTable, nsACString& aResult) {
|
|
|
|
bool first = true;
|
|
|
|
for (auto iter = aTable.ConstIter(); !iter.Done(); iter.Next()) {
|
|
|
|
if (first) {
|
|
|
|
first = false;
|
|
|
|
} else {
|
2020-07-01 11:29:29 +03:00
|
|
|
aResult.Append(", "_ns);
|
2019-10-02 07:28:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
const auto& key = iter.Get()->GetKey();
|
|
|
|
|
|
|
|
aResult.Append(key);
|
|
|
|
}
|
|
|
|
}
|
2019-06-09 22:46:34 +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-09-08 10:40:30 +03:00
|
|
|
void LogError(const nsLiteralCString& aModule, const nsACString& aExpr,
|
|
|
|
const nsACString& aSourceFile, int32_t aSourceLine);
|
2020-09-08 10:40:46 +03:00
|
|
|
|
2020-06-25 10:16:47 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
Result<bool, nsresult> WarnIfFileIsUnknown(nsIFile& aFile,
|
|
|
|
const char* aSourceFile,
|
|
|
|
int32_t aSourceLine);
|
|
|
|
#endif
|
|
|
|
|
2020-09-30 11:24:18 +03:00
|
|
|
#if defined(EARLY_BETA_OR_EARLIER) || defined(DEBUG)
|
|
|
|
# define QM_ENABLE_SCOPED_LOG_EXTRA_INFO
|
|
|
|
#endif
|
2020-09-21 13:32:55 +03:00
|
|
|
|
|
|
|
struct MOZ_STACK_CLASS ScopedLogExtraInfo {
|
|
|
|
static constexpr const char kTagQuery[] = "query";
|
|
|
|
|
|
|
|
#ifdef QM_ENABLE_SCOPED_LOG_EXTRA_INFO
|
2020-09-30 11:24:18 +03:00
|
|
|
private:
|
|
|
|
static auto FindSlot(const char* aTag);
|
2020-09-21 13:32:55 +03:00
|
|
|
|
2020-09-30 11:24:18 +03:00
|
|
|
public:
|
2020-09-21 13:32:55 +03:00
|
|
|
template <size_t N>
|
|
|
|
ScopedLogExtraInfo(const char (&aTag)[N], const nsACString& aExtraInfo)
|
2020-09-30 11:24:18 +03:00
|
|
|
: mTag{aTag}, mCurrentValue{aExtraInfo} {
|
|
|
|
// Initialize is currently only called in the parent process, we could call
|
|
|
|
// it directly from nsLayoutStatics::Initialize in the content process to
|
|
|
|
// allow use of ScopedLogExtraInfo in that too. The check in GetExtraInfoMap
|
|
|
|
// must be removed then.
|
|
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
|
|
|
|
|
|
AddInfo();
|
2020-09-21 13:32:55 +03:00
|
|
|
}
|
|
|
|
|
2020-09-30 11:24:18 +03:00
|
|
|
~ScopedLogExtraInfo();
|
2020-09-21 13:32:55 +03:00
|
|
|
|
2020-09-30 11:24:18 +03:00
|
|
|
ScopedLogExtraInfo(ScopedLogExtraInfo&& aOther);
|
2020-09-21 13:32:55 +03:00
|
|
|
ScopedLogExtraInfo& operator=(ScopedLogExtraInfo&& aOther) = delete;
|
|
|
|
|
|
|
|
ScopedLogExtraInfo(const ScopedLogExtraInfo&) = delete;
|
|
|
|
ScopedLogExtraInfo& operator=(const ScopedLogExtraInfo&) = delete;
|
|
|
|
|
2020-09-30 11:24:18 +03:00
|
|
|
using ScopedLogExtraInfoMap = std::map<const char*, const nsACString*>;
|
|
|
|
static ScopedLogExtraInfoMap GetExtraInfoMap();
|
|
|
|
|
|
|
|
static void Initialize();
|
2020-09-21 13:32:55 +03:00
|
|
|
|
|
|
|
private:
|
|
|
|
const char* mTag;
|
2020-09-30 11:24:18 +03:00
|
|
|
const nsACString* mPreviousValue;
|
|
|
|
nsCString mCurrentValue;
|
2020-09-21 13:32:55 +03:00
|
|
|
|
2020-09-30 11:24:18 +03:00
|
|
|
static MOZ_THREAD_LOCAL(const nsACString*) sQueryValue;
|
2020-09-21 13:32:55 +03:00
|
|
|
|
2020-09-30 11:24:18 +03:00
|
|
|
void AddInfo();
|
2020-09-21 13:32:55 +03:00
|
|
|
#else
|
|
|
|
template <size_t N>
|
|
|
|
ScopedLogExtraInfo(const char (&aTag)[N], const nsACString& aExtraInfo) {}
|
|
|
|
|
|
|
|
// user-defined to silence unused variable warnings
|
|
|
|
~ScopedLogExtraInfo() {}
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2020-09-14 15:14:17 +03:00
|
|
|
#if defined(EARLY_BETA_OR_EARLIER) || defined(DEBUG)
|
|
|
|
# define QM_META_HANDLE_ERROR(module) \
|
|
|
|
MOZ_COLD inline void HandleError( \
|
|
|
|
const char* aExpr, const char* aSourceFile, int32_t aSourceLine) { \
|
|
|
|
mozilla::dom::quota::LogError(module, nsDependentCString(aExpr), \
|
|
|
|
nsDependentCString(aSourceFile), \
|
|
|
|
aSourceLine); \
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
# define QM_META_HANDLE_ERROR(module) \
|
|
|
|
MOZ_ALWAYS_INLINE constexpr void HandleError( \
|
|
|
|
const char* aExpr, const char* aSourceFile, int32_t aSourceLine) {}
|
|
|
|
#endif
|
|
|
|
|
2020-09-02 18:03:06 +03:00
|
|
|
// As this is a function that will only be called in error cases, this is marked
|
2020-09-14 15:14:17 +03:00
|
|
|
// with MOZ_COLD to avoid bloating the code of calling functions, if it's not
|
|
|
|
// empty.
|
|
|
|
//
|
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.
|
|
|
|
//
|
2020-09-14 15:14:17 +03:00
|
|
|
// The corresponding functions in the quota clients should be defined using
|
|
|
|
// QM_META_HANDLE_ERROR, in particular they should have exactly the same
|
2020-09-08 10:40:30 +03:00
|
|
|
// signature incl. attributes. These functions are not intended to be called
|
|
|
|
// directly, they should only be called from the QM_* macros.
|
2020-09-14 15:14:17 +03:00
|
|
|
|
|
|
|
QM_META_HANDLE_ERROR("QuotaManager"_ns)
|
2020-07-24 10:11:24 +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__
|