diff options
Diffstat (limited to 'xpcom/build/Omnijar.cpp')
-rw-r--r-- | xpcom/build/Omnijar.cpp | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/xpcom/build/Omnijar.cpp b/xpcom/build/Omnijar.cpp new file mode 100644 index 0000000000..a816cc083f --- /dev/null +++ b/xpcom/build/Omnijar.cpp @@ -0,0 +1,231 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "Omnijar.h" + +#include "nsDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "mozilla/GeckoArgs.h" +#include "nsIFile.h" +#include "nsZipArchive.h" +#include "nsNetUtil.h" + +namespace mozilla { + +StaticRefPtr<nsIFile> Omnijar::sPath[2]; +StaticRefPtr<nsZipArchive> Omnijar::sReader[2]; +StaticRefPtr<nsZipArchive> Omnijar::sOuterReader[2]; +bool Omnijar::sInitialized = false; +bool Omnijar::sIsUnified = false; + +static const char* sProp[2] = {NS_GRE_DIR, NS_XPCOM_CURRENT_PROCESS_DIR}; + +#define SPROP(Type) ((Type == mozilla::Omnijar::GRE) ? sProp[GRE] : sProp[APP]) + +void Omnijar::CleanUpOne(Type aType) { + if (sReader[aType]) { + sReader[aType] = nullptr; + } + if (sOuterReader[aType]) { + sOuterReader[aType] = nullptr; + } + sPath[aType] = nullptr; +} + +void Omnijar::InitOne(nsIFile* aPath, Type aType) { + nsCOMPtr<nsIFile> file; + if (aPath) { + file = aPath; + } else { + nsCOMPtr<nsIFile> dir; + nsDirectoryService::gService->Get(SPROP(aType), NS_GET_IID(nsIFile), + getter_AddRefs(dir)); + constexpr auto kOmnijarName = nsLiteralCString{MOZ_STRINGIFY(OMNIJAR_NAME)}; + if (NS_FAILED(dir->Clone(getter_AddRefs(file))) || + NS_FAILED(file->AppendNative(kOmnijarName))) { + return; + } + } + bool isFile; + if (NS_FAILED(file->IsFile(&isFile)) || !isFile) { + // If we're not using an omni.jar for GRE, and we don't have an + // omni.jar for APP, check if both directories are the same. + if ((aType == APP) && (!sPath[GRE])) { + nsCOMPtr<nsIFile> greDir, appDir; + bool equals; + nsDirectoryService::gService->Get(sProp[GRE], NS_GET_IID(nsIFile), + getter_AddRefs(greDir)); + nsDirectoryService::gService->Get(sProp[APP], NS_GET_IID(nsIFile), + getter_AddRefs(appDir)); + if (NS_SUCCEEDED(greDir->Equals(appDir, &equals)) && equals) { + sIsUnified = true; + } + } + return; + } + + bool equals; + if ((aType == APP) && (sPath[GRE]) && + NS_SUCCEEDED(sPath[GRE]->Equals(file, &equals)) && equals) { + // If we're using omni.jar on both GRE and APP and their path + // is the same, we're in the unified case. + sIsUnified = true; + return; + } + + RefPtr<nsZipArchive> zipReader = nsZipArchive::OpenArchive(file); + if (!zipReader) { + return; + } + + RefPtr<nsZipArchive> outerReader; + RefPtr<nsZipHandle> handle; + if (NS_SUCCEEDED(nsZipHandle::Init(zipReader, MOZ_STRINGIFY(OMNIJAR_NAME), + getter_AddRefs(handle)))) { + outerReader = zipReader; + zipReader = nsZipArchive::OpenArchive(handle); + if (!zipReader) { + return; + } + } + + CleanUpOne(aType); + sReader[aType] = zipReader; + sOuterReader[aType] = outerReader; + sPath[aType] = file; +} + +void Omnijar::Init(nsIFile* aGrePath, nsIFile* aAppPath) { + InitOne(aGrePath, GRE); + InitOne(aAppPath, APP); + sInitialized = true; +} + +void Omnijar::CleanUp() { + CleanUpOne(GRE); + CleanUpOne(APP); + sInitialized = false; +} + +already_AddRefed<nsZipArchive> Omnijar::GetReader(nsIFile* aPath) { + MOZ_ASSERT(IsInitialized(), "Omnijar not initialized"); + + bool equals; + nsresult rv; + + if (sPath[GRE]) { + rv = sPath[GRE]->Equals(aPath, &equals); + if (NS_SUCCEEDED(rv) && equals) { + return IsNested(GRE) ? GetOuterReader(GRE) : GetReader(GRE); + } + } + if (sPath[APP]) { + rv = sPath[APP]->Equals(aPath, &equals); + if (NS_SUCCEEDED(rv) && equals) { + return IsNested(APP) ? GetOuterReader(APP) : GetReader(APP); + } + } + return nullptr; +} + +already_AddRefed<nsZipArchive> Omnijar::GetInnerReader( + nsIFile* aPath, const nsACString& aEntry) { + MOZ_ASSERT(IsInitialized(), "Omnijar not initialized"); + + if (!aEntry.EqualsLiteral(MOZ_STRINGIFY(OMNIJAR_NAME))) { + return nullptr; + } + + bool equals; + nsresult rv; + + if (sPath[GRE]) { + rv = sPath[GRE]->Equals(aPath, &equals); + if (NS_SUCCEEDED(rv) && equals) { + return IsNested(GRE) ? GetReader(GRE) : nullptr; + } + } + if (sPath[APP]) { + rv = sPath[APP]->Equals(aPath, &equals); + if (NS_SUCCEEDED(rv) && equals) { + return IsNested(APP) ? GetReader(APP) : nullptr; + } + } + return nullptr; +} + +nsresult Omnijar::GetURIString(Type aType, nsACString& aResult) { + MOZ_ASSERT(IsInitialized(), "Omnijar not initialized"); + + aResult.Truncate(); + + // Return an empty string for APP in the unified case. + if ((aType == APP) && sIsUnified) { + return NS_OK; + } + + nsAutoCString omniJarSpec; + if (sPath[aType]) { + nsresult rv = NS_GetURLSpecFromActualFile(sPath[aType], omniJarSpec); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + aResult = "jar:"; + if (IsNested(aType)) { + aResult += "jar:"; + } + aResult += omniJarSpec; + aResult += "!"; + if (IsNested(aType)) { + aResult += "/" MOZ_STRINGIFY(OMNIJAR_NAME) "!"; + } + } else { + nsCOMPtr<nsIFile> dir; + nsDirectoryService::gService->Get(SPROP(aType), NS_GET_IID(nsIFile), + getter_AddRefs(dir)); + nsresult rv = NS_GetURLSpecFromActualFile(dir, aResult); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + aResult += "/"; + return NS_OK; +} + +void Omnijar::ChildProcessInit(int& aArgc, char** aArgv) { + nsCOMPtr<nsIFile> greOmni, appOmni; + + if (auto greOmniStr = geckoargs::sGREOmni.Get(aArgc, aArgv)) { + if (NS_WARN_IF(NS_FAILED( + XRE_GetFileFromPath(*greOmniStr, getter_AddRefs(greOmni))))) { + greOmni = nullptr; + } + } + if (auto appOmniStr = geckoargs::sAppOmni.Get(aArgc, aArgv)) { + if (NS_WARN_IF(NS_FAILED( + XRE_GetFileFromPath(*appOmniStr, getter_AddRefs(appOmni))))) { + appOmni = nullptr; + } + } + + // If we're unified, then only the -greomni flag is present + // (reflecting the state of sPath in the parent process) but that + // path should be used for both (not nullptr, which will try to + // invoke the directory service, which probably isn't up yet.) + if (!appOmni) { + appOmni = greOmni; + } + + if (greOmni) { + Init(greOmni, appOmni); + } else { + // We should never have an appOmni without a greOmni. + MOZ_ASSERT(!appOmni); + } +} + +} /* namespace mozilla */ |