// Copyright 2022 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "components/update_client/crx_cache.h" #include #include #include #include "base/bind.h" #include "base/callback.h" #include "base/check.h" #include "base/files/file_enumerator.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/notreached.h" #include "base/path_service.h" #include "base/sequence_checker.h" #include "base/strings/strcat.h" #include "base/strings/string_util.h" #include "base/task/task_runner.h" #include "base/task/thread_pool.h" #include "base/threading/sequenced_task_runner_handle.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace update_client { CrxCache::CrxCache(const CrxCache::Options& options) : crx_cache_root_path_(options.crx_cache_root_path) {} CrxCache::~CrxCache() = default; base::FilePath CrxCache::BuildCrxFilePath(const std::string& id, const std::string& fp) { return crx_cache_root_path_.AppendASCII(base::JoinString({id, fp}, "_")); } void CrxCache::Get(const std::string& id, const std::string& fp, base::OnceCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_); task_runner_->PostTaskAndReplyWithResult( FROM_HERE, base::BindOnce(&CrxCache::ProcessGet, this, id, fp), base::BindOnce(&CrxCache::EndRequest, this, std::move(callback))); } CrxCache::Result CrxCache::ProcessGet(const std::string& id, const std::string& fp) { CrxCache::Result result; absl::optional opt_file_path; base::FilePath file_path = BuildCrxFilePath(id, fp); if (!base::PathExists(file_path)) { result.error = UnpackerError::kPuffinMissingPreviousCrx; } else { result.error = UnpackerError::kNone; result.crx_cache_path = BuildCrxFilePath(id, fp); } return result; } void CrxCache::Put(const base::FilePath& crx_path, const std::string& id, const std::string& fp, base::OnceCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_); task_runner_->PostTaskAndReplyWithResult( FROM_HERE, base::BindOnce(&CrxCache::ProcessPut, this, crx_path, id, fp), base::BindOnce(&CrxCache::EndRequest, this, std::move(callback))); } CrxCache::Result CrxCache::ProcessPut(const base::FilePath& crx_path, const std::string& id, const std::string& fp) { CrxCache::Result result; base::FilePath dest_path = BuildCrxFilePath(id, fp); RemoveAll(id); result.error = MoveFileToCache(crx_path, dest_path); if (result.error == UnpackerError::kNone) { result.crx_cache_path = dest_path; } return result; } void CrxCache::RemoveAll(const std::string& id) { if (base::PathExists(crx_cache_root_path_)) { base::FileEnumerator file_enum(crx_cache_root_path_, false, base::FileEnumerator::FILES, FILE_PATH_LITERAL(base::StrCat({id, "*"}))); for (base::FilePath file_path = file_enum.Next(); !file_path.empty(); file_path = file_enum.Next()) { base::DeleteFile(file_path); } } } UnpackerError CrxCache::MoveFileToCache(const base::FilePath& src_path, const base::FilePath& dest_path) { if (!base::CreateDirectory(crx_cache_root_path_)) { return update_client::UnpackerError::kFailedToCreateCacheDir; } if (!base::Move(src_path, dest_path)) { return update_client::UnpackerError::kFailedToAddToCache; } return update_client::UnpackerError::kNone; } void CrxCache::EndRequest( base::OnceCallback callback, CrxCache::Result result) { DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_); base::SequencedTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(std::move(callback), result)); } } // namespace update_client