// Copyright (c) 2015 GitHub, Inc. // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. #include "atom/common/asar/asar_util.h" #include #include #include "atom/common/asar/archive.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/lazy_instance.h" #include "base/stl_util.h" #include "base/threading/thread_local.h" namespace asar { namespace { // The global instance of ArchiveMap, will be destroyed on exit. typedef std::map> ArchiveMap; base::LazyInstance>::Leaky g_archive_map_tls = LAZY_INSTANCE_INITIALIZER; const base::FilePath::CharType kAsarExtension[] = FILE_PATH_LITERAL(".asar"); } // namespace std::shared_ptr GetOrCreateAsarArchive(const base::FilePath& path) { if (!g_archive_map_tls.Pointer()->Get()) g_archive_map_tls.Pointer()->Set(new ArchiveMap); ArchiveMap& archive_map = *g_archive_map_tls.Pointer()->Get(); if (!ContainsKey(archive_map, path)) { std::shared_ptr archive(new Archive(path)); if (!archive->Init()) return nullptr; archive_map[path] = archive; } return archive_map[path]; } void ClearArchives() { if (g_archive_map_tls.Pointer()->Get()) delete g_archive_map_tls.Pointer()->Get(); } bool GetAsarArchivePath(const base::FilePath& full_path, base::FilePath* asar_path, base::FilePath* relative_path) { base::FilePath iter = full_path; while (true) { base::FilePath dirname = iter.DirName(); if (iter.MatchesExtension(kAsarExtension)) break; else if (iter == dirname) return false; iter = dirname; } base::FilePath tail; if (!iter.AppendRelativePath(full_path, &tail)) return false; *asar_path = iter; *relative_path = tail; return true; } bool ReadFileToString(const base::FilePath& path, std::string* contents) { base::FilePath asar_path, relative_path; if (!GetAsarArchivePath(path, &asar_path, &relative_path)) return base::ReadFileToString(path, contents); std::shared_ptr archive = GetOrCreateAsarArchive(asar_path); if (!archive) return false; Archive::FileInfo info; if (!archive->GetFileInfo(relative_path, &info)) return false; if (info.unpacked) { base::FilePath real_path; // For unpacked file it will return the real path instead of doing the copy. archive->CopyFileOut(relative_path, &real_path); return base::ReadFileToString(real_path, contents); } base::File src(asar_path, base::File::FLAG_OPEN | base::File::FLAG_READ); if (!src.IsValid()) return false; contents->resize(info.size); return static_cast(info.size) == src.Read(info.offset, const_cast(contents->data()), contents->size()); } } // namespace asar