blob: d749628a1a9695a19d37dba81de8b10c9bf1e7f9 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_UPDATER_UTIL_UTIL_H_
#define CHROME_UPDATER_UTIL_UTIL_H_
#include <cmath>
#include <concepts>
#include <limits>
#include <optional>
#include <ostream>
#include <string>
#include <type_traits>
#include <vector>
#include "base/functional/callback_forward.h"
#include "base/memory/ref_counted.h"
#include "base/types/cxx23_to_underlying.h"
#include "base/version.h"
#include "build/build_config.h"
#include "chrome/updater/tag.h"
#include "chrome/updater/updater_scope.h"
#include "chrome/updater/updater_version.h"
class GURL;
namespace base {
class CommandLine;
class FilePath;
// Enables insertion of optional `base` types. Must be in the `base` namespace
// for insertion into gTest expectations to work.
template <class T>
inline std::ostream& operator<<(std::ostream& os, std::optional<T> opt) {
if (!opt.has_value()) {
return os << "std::nullopt";
}
return os << opt.value();
}
} // namespace base
namespace updater {
struct RegistrationRequest;
// Converts an unsigned integral to a signed one. Returns -1 if the value is
// out of the range of the target type.
template <std::unsigned_integral T>
[[nodiscard]] auto ToSignedIntegral(T value) {
using Result = std::make_signed_t<T>;
return value <= std::numeric_limits<Result>::max()
? static_cast<Result>(value)
: -1;
}
// Inserts an enum value as the underlying type.
template <typename T>
requires(std::is_enum_v<T>)
inline std::ostream& operator<<(std::ostream& os, const T& e) {
return os << base::to_underlying(e);
}
// Returns the versioned install directory under which the program stores its
// executables. For example, on macOS this function may return
// ~/Library/Google/GoogleUpdater/88.0.4293.0 (/Library for system). Does not
// create the directory if it does not exist.
std::optional<base::FilePath> GetVersionedInstallDirectory(
UpdaterScope scope,
const base::Version& version);
// Simpler form of GetVersionedInstallDirectory for the currently running
// version of the updater.
std::optional<base::FilePath> GetVersionedInstallDirectory(UpdaterScope scope);
// Returns the base install directory common to all versions of the updater.
// Does not create the directory if it does not exist.
std::optional<base::FilePath> GetInstallDirectory(UpdaterScope scope);
// Returns the path where cached CRX files should be stored, common to all
// versions of the updater. Does not create the directory if it does not exist.
std::optional<base::FilePath> GetCrxCacheDirectory(UpdaterScope scope);
#if BUILDFLAG(IS_MAC)
// For example: ~/Library/Google/GoogleUpdater/88.0.4293.0/GoogleUpdater.app
std::optional<base::FilePath> GetUpdaterAppBundlePath(UpdaterScope scope);
#endif // BUILDFLAG(IS_MAC)
// For user installations:
// ~/Library/Google/GoogleUpdater/88.0.4293.0/GoogleUpdater.app/Contents/
// MacOS/GoogleUpdater
// For system installations:
// /Library/Google/GoogleUpdater/88.0.4293.0/GoogleUpdater.app/Contents/
// MacOS/GoogleUpdater
std::optional<base::FilePath> GetUpdaterExecutablePath(
UpdaterScope scope,
const base::Version& version);
// Simpler form of GetUpdaterExecutablePath for the currently running version
// of the updater.
std::optional<base::FilePath> GetUpdaterExecutablePath(UpdaterScope scope);
// Returns a relative path to the executable from GetVersionedInstallDirectory.
// "GoogleUpdater.app/Contents/MacOS/GoogleUpdater" on macOS.
// "updater.exe" on Win.
base::FilePath GetExecutableRelativePath();
// Returns the path to the crashpad database directory. The directory is not
// created if it does not exist.
std::optional<base::FilePath> GetCrashDatabasePath(UpdaterScope scope);
// Returns the path to the crashpad database, creating it if it does not exist.
std::optional<base::FilePath> EnsureCrashDatabasePath(UpdaterScope scope);
// Contains the parsed values from the tag. The tag is provided as a command
// line argument to the `--install` or the `--handoff` switch.
struct TagParsingResult {
TagParsingResult();
TagParsingResult(std::optional<tagging::TagArgs> tag_args,
tagging::ErrorCode error);
~TagParsingResult();
TagParsingResult(const TagParsingResult&);
TagParsingResult& operator=(const TagParsingResult&);
std::optional<tagging::TagArgs> tag_args;
tagging::ErrorCode error = tagging::ErrorCode::kSuccess;
};
// These functions return {} if there was no tag at all. An error is set if the
// tag fails to parse.
TagParsingResult GetTagArgsForCommandLine(
const base::CommandLine& command_line);
TagParsingResult GetTagArgs();
std::optional<tagging::AppArgs> GetAppArgs(const std::string& app_id);
std::string GetTagLanguage();
std::string GetDecodedInstallDataFromAppArgs(const std::string& app_id);
std::string GetInstallDataIndexFromAppArgs(const std::string& app_id);
std::optional<base::FilePath> GetLogFilePath(UpdaterScope scope);
// Initializes logging for an executable.
void InitLogging(UpdaterScope updater_scope);
// Returns HTTP user-agent value.
std::string GetUpdaterUserAgent(
const base::Version& updater_version = base::Version(kUpdaterVersion));
// Returns a new GURL by appending the given query parameter name and the
// value. Unsafe characters in the name and the value are escaped like
// %XX%XX. The original query component is preserved if it's present.
//
// Examples:
//
// AppendQueryParameter(GURL("http://example.com"), "name", "value").spec()
// => "http://example.com?name=value"
// AppendQueryParameter(GURL("http://example.com?x=y"), "name", "value").spec()
// => "http://example.com?x=y&name=value"
GURL AppendQueryParameter(const GURL& url,
const std::string& name,
const std::string& value);
#if BUILDFLAG(IS_MAC)
// Recursively update the permissions of a path to 0755 or 0644, depending on
// whether the file is already executable (by any user) or is a directory.
// Returns false if and only if there is a failure lstating or setting a
// permission, except for failures to set permissions on symbolic links.
bool SetFilePermissionsRecursive(const base::FilePath& root_path);
#endif // BUILDFLAG(IS_MAC)
#if BUILDFLAG(IS_WIN)
// Returns the versioned task name prefix in the following format:
// "{ProductName}Task{System/User}{UpdaterVersion}".
// For instance: "ChromiumUpdaterTaskSystem92.0.0.1".
std::wstring GetTaskNamePrefix(
UpdaterScope scope,
const base::Version& version = base::Version(kUpdaterVersion));
// Returns the versioned task display name in the following format:
// "{ProductName} Task {System/User} {UpdaterVersion}".
// For instance: "ChromiumUpdater Task System 92.0.0.1".
std::wstring GetTaskDisplayName(
UpdaterScope scope,
const base::Version& version = base::Version(kUpdaterVersion));
// Parses the command line string in legacy format into `base::CommandLine`.
// The string must be in format like:
// program.exe /switch1 value1 /switch2 /switch3 value3
// Returns empty if a Chromium style switch is found.
std::optional<base::CommandLine> CommandLineForLegacyFormat(
const std::wstring& cmd_string);
// Returns the command line for current process, either in legacy style, or
// in Chromium style.
base::CommandLine GetCommandLineLegacyCompatible();
#endif // BUILDFLAG(IS_WIN)
// Writes the provided string prefixed with the UTF8 byte order mark to a
// temporary file. The temporary file is created in the specified `directory`.
std::optional<base::FilePath> WriteInstallerDataToTempFile(
const base::FilePath& directory,
const std::string& installer_data);
// Creates and starts a thread pool for this process.
void InitializeThreadPool(const char* name);
// Returns whether the user currently running the program is the right user for
// the scope. This can be useful to avoid installing system updaters that are
// owned by non-root accounts, or avoiding the installation of a user level
// updater as root.
bool WrongUser(UpdaterScope scope);
// Returns whether a user has previously accepted a EULA / ToS for at least one
// of the listed apps.
bool EulaAccepted(const std::vector<std::string>& app_ids);
// Imports metadata from legacy updaters.
bool MigrateLegacyUpdaters(
UpdaterScope scope,
base::RepeatingCallback<void(const RegistrationRequest&)>
register_callback);
// Delete everything other than `except` under `except.DirName()`.
[[nodiscard]] bool DeleteExcept(std::optional<base::FilePath> except);
// Returns the quotient of dividing two integer numbers (m/n) rounded up.
template <typename T>
requires(std::integral<T>)
[[nodiscard]] constexpr T CeilingDivide(T m, T n) {
return std::ceil(static_cast<double>(m) / n);
}
// Returns a value in the [0, 100] range or -1 if the progress could not
// be computed.
[[nodiscard]] int GetDownloadProgress(int64_t downloaded_bytes,
int64_t total_bytes);
// Returns the absolute path to the enterprise companion app executable bundled
// with the updater.
[[nodiscard]] std::optional<base::FilePath>
GetBundledEnterpriseCompanionExecutablePath(UpdaterScope scope);
} // namespace updater
#endif // CHROME_UPDATER_UTIL_UTIL_H_