Skip to content
Snippets Groups Projects
Verified Commit 4595d824 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 1dafa91c
Branches
No related tags found
1 merge request!541Bug 20497: Check if the browser should run in portable mode at runtime (Tor Browser)
......@@ -41,3 +41,5 @@ ac_add_options MOZ_TELEMETRY_REPORTING=
if test -z "$WASI_SYSROOT"; then
ac_add_options --without-wasm-sandboxed-libraries
fi
ac_add_options --with-relative-data-dir=BaseBrowser/Data/Browser
......@@ -1025,6 +1025,25 @@ set_config("BASE_BROWSER", True, when="--enable-base-browser")
set_define("BASE_BROWSER", True, when="--enable-base-browser")
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)
# Tor additions.
option(
......
......
......@@ -111,6 +111,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)
......@@ -1356,10 +1360,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.Find("/Applications/", true /* ignore case */) == 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) {
......@@ -1369,6 +1459,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;
......@@ -1562,6 +1670,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;
......
......
......@@ -155,6 +155,14 @@ class nsXREDirProvider final : public nsIDirectoryServiceProvider2,
private:
static nsresult SetUserDataProfileDirectory(nsCOMPtr<nsIFile>& aFile,
bool aLocal);
#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
};
#endif
......@@ -229,13 +229,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.Find("/Applications/", true /* ignore case */) == 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) {
......@@ -243,10 +338,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)
FSRef fsRef;
OSType folderType =
......@@ -309,9 +414,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