fune/xpcom/build/FileLocation.cpp
Doug Thayer b274aafa4b Bug 1627075 - Route Omnijar requests through StartupCache r=froydnj
This should be a relatively straightforward patch. Essentially, we implement
a wrapper class (and friends) around nsZipArchive (and friends), which transparently
caches entries from the underlying zip archive in the StartupCache. This will break
without changes to the StartupCache, made in the patch after this, which allow it
to be used off of the main thread, and outside the main process.

Depends on D77635

Differential Revision: https://phabricator.services.mozilla.com/D77634
2020-07-08 02:46:34 +00:00

206 lines
5 KiB
C++

/* -*- 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 "FileLocation.h"
#include "nsZipArchive.h"
#include "nsURLHelper.h"
#include "mozilla/Omnijar.h"
namespace mozilla {
FileLocation::FileLocation() = default;
FileLocation::~FileLocation() = default;
FileLocation::FileLocation(nsIFile* aFile) { Init(aFile); }
FileLocation::FileLocation(CacheAwareZipReader* aZip, const char* aPath) {
Init(aZip, aPath);
}
FileLocation::FileLocation(nsZipArchive* aZip, const char* aPath) {
Init(new CacheAwareZipReader(aZip, nullptr), aPath);
}
FileLocation::FileLocation(const FileLocation& aOther)
= default;
FileLocation::FileLocation(FileLocation&& aOther)
: mBaseFile(std::move(aOther.mBaseFile)),
mBaseZip(std::move(aOther.mBaseZip)),
mPath(std::move(aOther.mPath)) {
aOther.mPath.Truncate();
}
FileLocation::FileLocation(const FileLocation& aFile, const char* aPath) {
if (aFile.IsZip()) {
if (aFile.mBaseFile) {
Init(aFile.mBaseFile, aFile.mPath.get());
} else {
Init(aFile.mBaseZip, aFile.mPath.get());
}
if (aPath) {
int32_t i = mPath.RFindChar('/');
if (kNotFound == i) {
mPath.Truncate(0);
} else {
mPath.Truncate(i + 1);
}
mPath += aPath;
}
} else {
if (aPath) {
nsCOMPtr<nsIFile> cfile;
aFile.mBaseFile->GetParent(getter_AddRefs(cfile));
#if defined(XP_WIN)
nsAutoCString pathStr(aPath);
char* p;
uint32_t len = pathStr.GetMutableData(&p);
for (; len; ++p, --len) {
if ('/' == *p) {
*p = '\\';
}
}
cfile->AppendRelativeNativePath(pathStr);
#else
cfile->AppendRelativeNativePath(nsDependentCString(aPath));
#endif
Init(cfile);
} else {
Init(aFile.mBaseFile);
}
}
}
void FileLocation::Init(nsIFile* aFile) {
mBaseZip = nullptr;
mBaseFile = aFile;
mPath.Truncate();
}
void FileLocation::Init(nsIFile* aFile, const char* aPath) {
mBaseZip = nullptr;
mBaseFile = aFile;
mPath = aPath;
}
void FileLocation::Init(CacheAwareZipReader* aZip, const char* aPath) {
mBaseZip = aZip;
mBaseFile = nullptr;
mPath = aPath;
}
void FileLocation::Init(nsZipArchive* aZip, const char* aPath) {
mBaseZip = new CacheAwareZipReader(aZip, nullptr);
mBaseFile = nullptr;
mPath = aPath;
}
void FileLocation::GetURIString(nsACString& aResult) const {
if (mBaseFile) {
net_GetURLSpecFromActualFile(mBaseFile, aResult);
} else if (mBaseZip) {
mBaseZip->GetURIString(aResult);
}
if (IsZip()) {
aResult.InsertLiteral("jar:", 0);
aResult += "!/";
aResult += mPath;
}
}
already_AddRefed<nsIFile> FileLocation::GetBaseFile() {
if (IsZip() && mBaseZip) {
return mBaseZip->GetBaseFile();
}
nsCOMPtr<nsIFile> file = mBaseFile;
return file.forget();
}
bool FileLocation::Equals(const FileLocation& aFile) const {
if (mPath != aFile.mPath) {
return false;
}
nsCOMPtr<nsIFile> a = mBaseFile;
nsCOMPtr<nsIFile> b = aFile.mBaseFile;
if (!mBaseFile && mBaseZip) {
a = mBaseZip->GetBaseFile();
}
if (!aFile.mBaseFile && aFile.mBaseZip) {
b = mBaseZip->GetBaseFile();
}
bool eq;
return NS_SUCCEEDED(a->Equals(b, &eq)) && eq;
}
nsresult FileLocation::GetData(Data& aData) {
if (!IsZip()) {
return mBaseFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &aData.mFd.rwget());
}
aData.mZip = mBaseZip;
if (!aData.mZip) {
aData.mZip = new CacheAwareZipReader();
aData.mZip->OpenArchive(mBaseFile);
}
aData.mItem = aData.mZip->GetItem(mPath.get());
if (aData.mItem) {
return NS_OK;
}
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
}
nsresult FileLocation::Data::GetSize(uint32_t* aResult) {
if (mFd) {
PRFileInfo64 fileInfo;
if (PR_SUCCESS != PR_GetOpenFileInfo64(mFd, &fileInfo)) {
return NS_ErrorAccordingToNSPR();
}
if (fileInfo.size > int64_t(UINT32_MAX)) {
return NS_ERROR_FILE_TOO_BIG;
}
*aResult = fileInfo.size;
return NS_OK;
}
if (mItem) {
*aResult = mItem->RealSize();
return NS_OK;
}
return NS_ERROR_NOT_INITIALIZED;
}
nsresult FileLocation::Data::Copy(char* aBuf, uint32_t aLen) {
if (mFd) {
for (uint32_t totalRead = 0; totalRead < aLen;) {
int32_t read = PR_Read(mFd, aBuf + totalRead,
XPCOM_MIN(aLen - totalRead, uint32_t(INT32_MAX)));
if (read < 0) {
return NS_ErrorAccordingToNSPR();
}
totalRead += read;
}
return NS_OK;
}
if (mItem) {
CacheAwareZipCursor cursor(mItem, mZip, reinterpret_cast<uint8_t*>(aBuf),
aLen, true);
uint32_t readLen;
cursor.Copy(&readLen);
if (readLen != aLen) {
return NS_ERROR_FILE_CORRUPTED;
}
return NS_OK;
}
return NS_ERROR_NOT_INITIALIZED;
}
} /* namespace mozilla */