Skip to content
Snippets Groups Projects
Verified Commit ceba9fe5 authored by Pier Angelo Vendrame's avatar Pier Angelo Vendrame :jack_o_lantern:
Browse files

Bug 9173: Change the default Firefox profile directory to be relative.

This commit makes Firefox look for the default profile directory in a
directory relative to the binary path.
The directory can be specified through the --with-relative-data-dir.
This is relative to the same directory as the firefox main binary for
Linux and Windows.

On macOS, we remove Contents/MacOS from it.
Or, in other words, the directory is relative to the application
bundle.

This behavior can be overriden at runtime, by placing a file called
system-install adjacent to the firefox main binary (also on macOS).
parent 32771fa2
Branches
Tags
1 merge request!889Bug 42366: Tor Browser 115.7.0esr alpha rebase
......@@ -51,3 +51,5 @@ fi
# tor-browser#42337
ac_add_options --enable-geckodriver
ac_add_options --with-relative-data-dir=BaseBrowser/Data/Browser
......@@ -930,6 +930,25 @@ set_config("ZLIB_IN_MOZGLUE", zlib_in_mozglue)
set_define("ZLIB_IN_MOZGLUE", zlib_in_mozglue)
option(
"--with-relative-data-dir",
nargs=1,
help="Sets the data directories to be relative to the application directory"
)
@depends("--with-relative-data-dir", target)
@imports("json")
def relative_data_dir(value, target):
if value and target.os == "Android":
die("--with-relative-data-dir is not supported on Android")
if value:
return json.dumps(value[0])
set_define("RELATIVE_DATA_DIR", relative_data_dir)
option(
"--with-base-browser-version",
nargs=1,
......
......@@ -7,3 +7,6 @@ ac_add_options --enable-nss-mar
# See bug #41131
ac_add_options --disable-update-agent
# For base-browser we do not enable portable mode on macOS.
ac_add_options --without-relative-data-dir
......@@ -17,6 +17,9 @@
#include <string>
#include <type_traits>
// tor-browser#42163
#include <filesystem>
#define EXPAND_STRING_MACRO2(t) t
#define EXPAND_STRING_MACRO(t) EXPAND_STRING_MACRO2(t)
......@@ -586,6 +589,45 @@ LauncherRegistryInfo::GetBrowserStartTimestamp() {
LauncherResult<std::wstring>
LauncherRegistryInfo::BuildDefaultBlocklistFilename() {
// tor-browser#42163: Make the DLL blocklist obey portable mode
{
std::filesystem::path appDir;
{
mozilla::UniquePtr<wchar_t[]> appDirStr = GetFullBinaryPath();
if (!appDirStr) {
return LAUNCHER_ERROR_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
}
appDir = std::filesystem::path(appDirStr.get()).parent_path();
}
std::error_code ec;
const bool isPortable =
!std::filesystem::exists(appDir / L"system-install", ec);
if (ec) {
// exists is supposed not to set an error when a file does not exist
// (whereas other functions such as is_regular_file sets it).
// The standard is quite opaque about the meaning of the numeric codes.
// Moreover, we use libcxx on Windows, and it seems they created a sort of
// POSIX compatibility layer (e.g., for stat), see
// libcxx/src/filesystem/posix_compat.h.
// std::error_code has a message function, but all the various macro are
// specific to handle Windows errors, so we have to use the generic error.
// At least, at the moment the error is dropped eventually.
return LAUNCHER_ERROR_GENERIC();
}
if (isPortable) {
// RELATIVE_DATA_DIR must have forward slashes, but weakly_canonical
// already changes them to backslashes.
const std::filesystem::path blocklistPath =
std::filesystem::weakly_canonical(
appDir / L"" RELATIVE_DATA_DIR / L"blocklist", ec);
if (ec) {
return LAUNCHER_ERROR_GENERIC();
}
return blocklistPath.wstring();
}
// Normal installation, continue on Mozilla's path
}
// These flags are chosen to avoid I/O, see bug 1363398.
const DWORD flags =
KF_FLAG_SIMPLE_IDLIST | KF_FLAG_DONT_VERIFY | KF_FLAG_NO_ALIAS;
......@@ -618,6 +660,8 @@ LauncherRegistryInfo::BuildDefaultBlocklistFilename() {
}
LauncherResult<std::wstring> LauncherRegistryInfo::GetBlocklistFileName() {
// tor-browser#42163: Make the DLL blocklist obey portable mode
#ifndef BASE_BROWSER_VERSION
LauncherResult<Disposition> disposition = Open();
if (disposition.isErr()) {
return disposition.propagateErr();
......@@ -633,19 +677,19 @@ LauncherResult<std::wstring> LauncherRegistryInfo::GetBlocklistFileName() {
UniquePtr<wchar_t[]> buf = readResult.unwrap();
return std::wstring(buf.get());
}
#endif
LauncherResult<std::wstring> defaultBlocklistPath =
BuildDefaultBlocklistFilename();
if (defaultBlocklistPath.isErr()) {
return defaultBlocklistPath.propagateErr();
}
#ifndef BASE_BROWSER_VERSION
LauncherVoidResult writeResult = WriteRegistryValueString(
mRegKey, ResolveBlocklistValueName(), defaultBlocklistPath.inspect());
if (writeResult.isErr()) {
return writeResult.propagateErr();
}
#endif
return defaultBlocklistPath;
}
......
......@@ -2682,6 +2682,8 @@ static nsresult ProfileMissingDialog(nsINativeAppSupport* aNative) {
#endif // MOZ_WIDGET_ANDROID
}
// If aUnlocker is NULL, it is also OK for the following arguments to be NULL:
// aProfileDir, aProfileLocalDir, aResult.
static ReturnAbortOnError ProfileLockedDialog(nsIFile* aProfileDir,
nsIFile* aProfileLocalDir,
nsIProfileUnlocker* aUnlocker,
......@@ -2689,11 +2691,13 @@ static ReturnAbortOnError ProfileLockedDialog(nsIFile* aProfileDir,
nsIProfileLock** aResult) {
nsresult rv;
if (aProfileDir) {
bool exists;
aProfileDir->Exists(&exists);
if (!exists) {
return ProfileMissingDialog(aNative);
}
}
ScopedXPCOMStartup xpcom;
rv = xpcom.Initialize();
......@@ -2702,7 +2706,7 @@ static ReturnAbortOnError ProfileLockedDialog(nsIFile* aProfileDir,
#if defined(MOZ_TELEMETRY_REPORTING)
// We cannot check if telemetry has been disabled by the user, yet.
// So, rely on the build time settings, instead.
mozilla::Telemetry::WriteFailedProfileLock(aProfileDir);
if (aProfileDir) mozilla::Telemetry::WriteFailedProfileLock(aProfileDir);
#endif
rv = xpcom.SetWindowCreator(aNative);
......
......@@ -109,6 +109,10 @@ nsIFile* gDataDirHome = nullptr;
nsCOMPtr<nsIFile> gDataDirProfileLocal = nullptr;
nsCOMPtr<nsIFile> gDataDirProfile = nullptr;
#if defined(RELATIVE_DATA_DIR)
mozilla::Maybe<nsCOMPtr<nsIFile>> gDataDirPortable;
#endif
// These are required to allow nsXREDirProvider to be usable in xpcshell tests.
// where gAppData is null.
#if defined(XP_MACOSX) || defined(XP_UNIX)
......@@ -1198,10 +1202,96 @@ nsresult nsXREDirProvider::SetUserDataProfileDirectory(nsCOMPtr<nsIFile>& aFile,
return NS_OK;
}
#if defined(RELATIVE_DATA_DIR)
nsresult nsXREDirProvider::GetPortableDataDir(nsIFile** aFile,
bool& aIsPortable) {
if (gDataDirPortable) {
if (*gDataDirPortable) {
nsresult rv = (*gDataDirPortable)->Clone(aFile);
NS_ENSURE_SUCCESS(rv, rv);
aIsPortable = true;
} else {
aIsPortable = false;
}
return NS_OK;
}
nsCOMPtr<nsIFile> exeFile, exeDir;
bool persistent = false;
nsresult rv =
GetFile(XRE_EXECUTABLE_FILE, &persistent, getter_AddRefs(exeFile));
NS_ENSURE_SUCCESS(rv, rv);
rv = exeFile->Normalize();
NS_ENSURE_SUCCESS(rv, rv);
rv = exeFile->GetParent(getter_AddRefs(exeDir));
NS_ENSURE_SUCCESS(rv, rv);
# if defined(XP_MACOSX)
nsAutoString exeDirPath;
rv = exeDir->GetPath(exeDirPath);
NS_ENSURE_SUCCESS(rv, rv);
// When the browser is installed in /Applications, we never run in portable
// mode.
if (exeDirPath.LowerCaseFindASCII("/applications/") == 0) {
aIsPortable = false;
return NS_OK;
}
# endif
nsCOMPtr<nsIFile> systemInstallFile;
rv = exeDir->Clone(getter_AddRefs(systemInstallFile));
NS_ENSURE_SUCCESS(rv, rv);
rv = systemInstallFile->AppendNative("system-install"_ns);
NS_ENSURE_SUCCESS(rv, rv);
bool exists = false;
rv = systemInstallFile->Exists(&exists);
NS_ENSURE_SUCCESS(rv, rv);
if (exists) {
aIsPortable = false;
gDataDirPortable.emplace(nullptr);
return NS_OK;
}
nsCOMPtr<nsIFile> localDir = exeDir;
# if defined(XP_MACOSX)
rv = exeDir->GetParent(getter_AddRefs(localDir));
NS_ENSURE_SUCCESS(rv, rv);
exeDir = localDir;
rv = exeDir->GetParent(getter_AddRefs(localDir));
NS_ENSURE_SUCCESS(rv, rv);
# endif
rv = localDir->SetRelativePath(localDir.get(),
nsLiteralCString(RELATIVE_DATA_DIR));
NS_ENSURE_SUCCESS(rv, rv);
# if defined(XP_MACOSX)
// On macOS we try to create the directory immediately to switch to
// system-install mode if needed (e.g., when running from the DMG).
rv = localDir->Exists(&exists);
NS_ENSURE_SUCCESS(rv, rv);
if (!exists) {
rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
if (NS_FAILED(rv)) {
aIsPortable = false;
return NS_OK;
}
}
# endif
gDataDirPortable.emplace(localDir);
rv = (*gDataDirPortable)->Clone(aFile);
NS_ENSURE_SUCCESS(rv, rv);
aIsPortable = true;
return rv;
}
#endif
nsresult nsXREDirProvider::GetUserDataDirectoryHome(nsIFile** aFile,
bool aLocal) {
// Copied from nsAppFileLocationProvider (more or less)
nsresult rv;
NS_ENSURE_ARG_POINTER(aFile);
nsCOMPtr<nsIFile> localDir;
if (aLocal && gDataDirHomeLocal) {
......@@ -1211,6 +1301,24 @@ nsresult nsXREDirProvider::GetUserDataDirectoryHome(nsIFile** aFile,
return gDataDirHome->Clone(aFile);
}
#if defined(RELATIVE_DATA_DIR)
RefPtr<nsXREDirProvider> singleton = GetSingleton();
if (!singleton) {
return NS_ERROR_OUT_OF_MEMORY;
}
bool isPortable = false;
rv = singleton->GetPortableDataDir(getter_AddRefs(localDir), isPortable);
NS_ENSURE_SUCCESS(rv, rv);
if (isPortable) {
if (aLocal) {
rv = localDir->AppendNative("Caches"_ns);
NS_ENSURE_SUCCESS(rv, rv);
}
NS_IF_ADDREF(*aFile = localDir);
return rv;
}
#endif
#if defined(XP_MACOSX)
FSRef fsRef;
OSType folderType;
......@@ -1404,6 +1512,13 @@ nsresult nsXREDirProvider::AppendProfilePath(nsIFile* aFile, bool aLocal) {
return NS_OK;
}
#if defined(RELATIVE_DATA_DIR)
if (gDataDirPortable && *gDataDirPortable) {
// Do nothing in portable mode
return NS_OK;
}
#endif
nsAutoCString profile;
nsAutoCString appName;
nsAutoCString vendor;
......
......@@ -139,6 +139,14 @@ class nsXREDirProvider final : public nsIDirectoryServiceProvider2,
void Append(nsIFile* aDirectory);
#if defined(RELATIVE_DATA_DIR)
/**
* Get the path to the portable data dir, if the application is running in
* portable mode.
*/
nsresult GetPortableDataDir(nsIFile** aFile, bool& aIsPortable);
#endif
// On OSX, mGREDir points to .app/Contents/Resources
nsCOMPtr<nsIFile> mGREDir;
// On OSX, mGREBinDir points to .app/Contents/MacOS
......
......@@ -164,13 +164,108 @@ nsresult nsAppFileLocationProvider::CloneMozBinDirectory(nsIFile** aLocalFile) {
return NS_OK;
}
#ifdef RELATIVE_DATA_DIR
static nsresult SetupPortableMode(nsIFile** aDirectory, bool aLocal,
bool& aIsPortable) {
// This is almost the same as nsXREDirProvider::GetPortableDataDir.
// However, it seems that this is never called, at least during simple usage
// of the browser.
nsresult rv = NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIProperties> directoryService(
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIFile> exeFile, exeDir;
rv = directoryService->Get(XRE_EXECUTABLE_FILE, NS_GET_IID(nsIFile),
getter_AddRefs(exeFile));
rv = exeFile->Normalize();
NS_ENSURE_SUCCESS(rv, rv);
rv = exeFile->GetParent(getter_AddRefs(exeDir));
NS_ENSURE_SUCCESS(rv, rv);
# if defined(XP_MACOSX)
nsAutoString exeDirPath;
rv = exeDir->GetPath(exeDirPath);
NS_ENSURE_SUCCESS(rv, rv);
// When the browser is installed in /Applications, we never run in portable
// mode.
if (exeDirPath.LowerCaseFindASCII("/applications/") == 0) {
aIsPortable = false;
return NS_OK;
}
# endif
nsCOMPtr<nsIFile> systemInstallFile;
rv = exeDir->Clone(getter_AddRefs(systemInstallFile));
NS_ENSURE_SUCCESS(rv, rv);
rv = systemInstallFile->AppendNative("system-install"_ns);
NS_ENSURE_SUCCESS(rv, rv);
bool exists = false;
rv = systemInstallFile->Exists(&exists);
NS_ENSURE_SUCCESS(rv, rv);
if (exists) {
aIsPortable = false;
return NS_OK;
}
nsCOMPtr<nsIFile> localDir = exeDir;
# if defined(XP_MACOSX)
rv = exeDir->GetParent(getter_AddRefs(localDir));
NS_ENSURE_SUCCESS(rv, rv);
exeDir = localDir;
rv = exeDir->GetParent(getter_AddRefs(localDir));
NS_ENSURE_SUCCESS(rv, rv);
# endif
rv = localDir->SetRelativePath(localDir.get(),
nsLiteralCString(RELATIVE_DATA_DIR));
NS_ENSURE_SUCCESS(rv, rv);
if (aLocal) {
rv = localDir->AppendNative("Caches"_ns);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = localDir->Exists(&exists);
NS_ENSURE_SUCCESS(rv, rv);
if (!exists) {
rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
# if defined(XP_MACOSX)
if (NS_FAILED(rv)) {
// On macOS, we forgive this failure to allow running from the DMG.
aIsPortable = false;
return NS_OK;
}
# else
NS_ENSURE_SUCCESS(rv, rv);
# endif
}
localDir.forget(aDirectory);
aIsPortable = true;
return rv;
}
#endif
//----------------------------------------------------------------------------------------
// GetProductDirectory - Gets the directory which contains the application data
// folder
//
// UNIX : ~/.mozilla/
// WIN : <Application Data folder on user's machine>\Mozilla
// Mac : :Documents:Mozilla:
// If portable mode is enabled:
// - aLocal == false: $APP_ROOT/$RELATIVE_DATA_DIR
// - aLocal == true: $APP_ROOT/$RELATIVE_DATA_DIR/Caches
// where $APP_ROOT is:
// - the parent directory of the executable on Windows and Linux
// - the root of the app bundle on macOS
//
// Otherwise:
// - Windows:
// - aLocal == false: %APPDATA%/$MOZ_USER_DIR
// - aLocal == true: %LOCALAPPDATA%/$MOZ_USER_DIR
// - macOS:
// - aLocal == false: kDomainLibraryFolderType/$MOZ_USER_DIR
// - aLocal == true: kCachedDataFolderType/$MOZ_USER_DIR
// - Unix: ~/$MOZ_USER_DIR
//----------------------------------------------------------------------------------------
nsresult nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
bool aLocal) {
......@@ -178,10 +273,20 @@ nsresult nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
return NS_ERROR_INVALID_ARG;
}
nsresult rv;
nsresult rv = NS_ERROR_UNEXPECTED;
bool exists;
nsCOMPtr<nsIFile> localDir;
#if defined(RELATIVE_DATA_DIR)
bool isPortable = false;
rv = SetupPortableMode(aLocalFile, aLocal, isPortable);
// If portable mode is enabled, we absolutely want it (e.g., to be sure there
// will not be disk leaks), so a failure is to be propagated.
if (NS_FAILED(rv) || isPortable) {
return rv;
}
#endif
#if defined(MOZ_WIDGET_COCOA)
NS_NewLocalFile(u""_ns, true, getter_AddRefs(localDir));
if (!localDir) {
......@@ -239,9 +344,10 @@ nsresult nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
// GetDefaultUserProfileRoot - Gets the directory which contains each user
// profile dir
//
// UNIX : ~/.mozilla/
// WIN : <Application Data folder on user's machine>\Mozilla\Profiles
// Mac : :Documents:Mozilla:Profiles:
// - Windows and macOS: $PRODUCT_DIRECTORY/Profiles
// - Unix: $PRODUCT_DIRECTORY
// See also GetProductDirectory for instructions on how $PRODUCT_DIRECTORY is
// generated.
//----------------------------------------------------------------------------------------
nsresult nsAppFileLocationProvider::GetDefaultUserProfileRoot(
nsIFile** aLocalFile, bool aLocal) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment