refactor: mmap asar files (#24470)

This commit is contained in:
Jeremy Rose 2020-08-04 11:48:04 -07:00 committed by GitHub
parent 15ee34a1f2
commit 01a2e23194
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 133 additions and 114 deletions

View file

@ -117,78 +117,51 @@ bool FillFileInfoWithNode(Archive::FileInfo* info,
} // namespace
Archive::Archive(const base::FilePath& path)
: path_(path), file_(base::File::FILE_OK) {
Archive::Archive(const base::FilePath& path) : path_(path) {
base::ThreadRestrictions::ScopedAllowIO allow_io;
file_.Initialize(path_, base::File::FLAG_OPEN | base::File::FLAG_READ);
#if defined(OS_WIN)
fd_ = _open_osfhandle(reinterpret_cast<intptr_t>(file_.GetPlatformFile()), 0);
#elif defined(OS_POSIX)
fd_ = file_.GetPlatformFile();
#endif
if (!file_.Initialize(path_)) {
LOG(ERROR) << "Failed to open ASAR archive at '" << path_.value() << "'";
}
}
Archive::~Archive() {
#if defined(OS_WIN)
if (fd_ != -1) {
_close(fd_);
// Don't close the handle since we already closed the fd.
file_.TakePlatformFile();
}
#endif
base::ThreadRestrictions::ScopedAllowIO allow_io;
file_.Close();
}
Archive::~Archive() {}
bool Archive::Init() {
if (!file_.IsValid()) {
if (file_.error_details() != base::File::FILE_ERROR_NOT_FOUND) {
LOG(WARNING) << "Opening " << path_.value() << ": "
<< base::File::ErrorToString(file_.error_details());
}
return false;
}
std::vector<char> buf;
int len;
buf.resize(8);
{
base::ThreadRestrictions::ScopedAllowIO allow_io;
len = file_.ReadAtCurrentPos(buf.data(), buf.size());
}
if (len != static_cast<int>(buf.size())) {
PLOG(ERROR) << "Failed to read header size from " << path_.value();
if (file_.length() < 8) {
LOG(ERROR) << "Malformed ASAR file at '" << path_.value()
<< "' (too short)";
return false;
}
uint32_t size;
if (!base::PickleIterator(base::Pickle(buf.data(), buf.size()))
.ReadUInt32(&size)) {
LOG(ERROR) << "Failed to parse header size from " << path_.value();
base::PickleIterator size_pickle(
base::Pickle(reinterpret_cast<const char*>(file_.data()), 8));
if (!size_pickle.ReadUInt32(&size)) {
LOG(ERROR) << "Failed to read header size at '" << path_.value() << "'";
return false;
}
buf.resize(size);
{
base::ThreadRestrictions::ScopedAllowIO allow_io;
len = file_.ReadAtCurrentPos(buf.data(), buf.size());
}
if (len != static_cast<int>(buf.size())) {
PLOG(ERROR) << "Failed to read header from " << path_.value();
if (file_.length() - 8 < size) {
LOG(ERROR) << "Malformed ASAR file at '" << path_.value()
<< "' (incorrect header)";
return false;
}
base::PickleIterator header_pickle(
base::Pickle(reinterpret_cast<const char*>(file_.data() + 8), size));
std::string header;
if (!base::PickleIterator(base::Pickle(buf.data(), buf.size()))
.ReadString(&header)) {
LOG(ERROR) << "Failed to parse header from " << path_.value();
if (!header_pickle.ReadString(&header)) {
LOG(ERROR) << "Failed to read header string at '" << path_.value() << "'";
return false;
}
base::Optional<base::Value> value = base::JSONReader::Read(header);
if (!value || !value->is_dict()) {
LOG(ERROR) << "Failed to parse header";
LOG(ERROR) << "Header was not valid JSON at '" << path_.value() << "'";
return false;
}
@ -291,11 +264,24 @@ bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) {
return true;
}
base::CheckedNumeric<uint64_t> safe_offset(info.offset);
auto safe_end = safe_offset + info.size;
if (!safe_end.IsValid() || safe_end.ValueOrDie() > file_.length())
return false;
auto temp_file = std::make_unique<ScopedTemporaryFile>();
base::FilePath::StringType ext = path.Extension();
if (!temp_file->InitFromFile(&file_, ext, info.offset, info.size))
if (!temp_file->Init(ext))
return false;
base::File dest(temp_file->path(),
base::File::FLAG_OPEN | base::File::FLAG_WRITE);
if (!dest.IsValid())
return false;
dest.WriteAtCurrentPos(
reinterpret_cast<const char*>(file_.data() + info.offset), info.size);
#if defined(OS_POSIX)
if (info.executable) {
// chmod a+x temp_file;
@ -308,8 +294,4 @@ bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) {
return true;
}
int Archive::GetFD() const {
return fd_;
}
} // namespace asar