| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/offline_pages/core/archive_manager.h" |
| |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/files/file_enumerator.h" |
| #include "base/files/file_util.h" |
| #include "base/location.h" |
| #include "base/logging.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/sequenced_task_runner.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/system/sys_info.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "build/build_config.h" |
| |
| namespace offline_pages { |
| |
| namespace { |
| |
| using StorageStatsCallback = |
| base::OnceCallback<void(const ArchiveManager::StorageStats& storage_stats)>; |
| |
| void EnsureArchivesDirCreatedImpl(const base::FilePath& archives_dir, |
| bool is_temp) { |
| base::File::Error error = base::File::FILE_OK; |
| if (!base::DirectoryExists(archives_dir)) { |
| if (!base::CreateDirectoryAndGetError(archives_dir, &error)) { |
| LOG(ERROR) << "Failed to create offline pages archive directory: " |
| << base::File::ErrorToString(error); |
| } |
| if (is_temp) { |
| UMA_HISTOGRAM_ENUMERATION( |
| "OfflinePages.ArchiveManager.ArchiveDirsCreationResult2.Temporary", |
| -error, -base::File::FILE_ERROR_MAX); |
| } else { |
| UMA_HISTOGRAM_ENUMERATION( |
| "OfflinePages.ArchiveManager.ArchiveDirsCreationResult2.Persistent", |
| -error, -base::File::FILE_ERROR_MAX); |
| } |
| } |
| } |
| |
| void GetStorageStatsImpl(const base::FilePath& temporary_archives_dir, |
| const base::FilePath& private_archives_dir, |
| const base::FilePath& public_archives_dir, |
| scoped_refptr<base::SequencedTaskRunner> task_runner, |
| StorageStatsCallback callback) { |
| ArchiveManager::StorageStats storage_stats = {0, 0, 0, 0, 0}; |
| |
| // Getting the free disk space of the volume that contains the temporary |
| // archives directory. This value will be -1 if the directory is invalid. |
| // Currently both temporary and private archive directories are in the |
| // internal storage. |
| storage_stats.internal_free_disk_space = |
| base::SysInfo::AmountOfFreeDiskSpace(temporary_archives_dir); |
| storage_stats.external_free_disk_space = |
| base::SysInfo::AmountOfFreeDiskSpace(public_archives_dir); |
| if (!temporary_archives_dir.empty()) { |
| storage_stats.temporary_archives_size = |
| base::ComputeDirectorySize(temporary_archives_dir); |
| } |
| if (!private_archives_dir.empty()) { |
| storage_stats.private_archives_size = |
| base::ComputeDirectorySize(private_archives_dir); |
| } |
| if (!public_archives_dir.empty()) { |
| base::FileEnumerator file_enumerator(public_archives_dir, false, |
| base::FileEnumerator::FILES); |
| while (!file_enumerator.Next().empty()) { |
| #if defined(OS_WIN) |
| std::string extension = base::WideToUTF8( |
| file_enumerator.GetInfo().GetName().FinalExtension()); |
| #else |
| std::string extension = |
| file_enumerator.GetInfo().GetName().FinalExtension(); |
| #endif |
| if (extension == "mhtml" || extension == "mht") |
| storage_stats.public_archives_size += |
| file_enumerator.GetInfo().GetSize(); |
| } |
| } |
| task_runner->PostTask(FROM_HERE, |
| base::BindOnce(std::move(callback), storage_stats)); |
| } |
| |
| } // namespace |
| |
| // protected and used for testing. |
| ArchiveManager::ArchiveManager() {} |
| |
| ArchiveManager::ArchiveManager( |
| const base::FilePath& temporary_archives_dir, |
| const base::FilePath& private_archives_dir, |
| const base::FilePath& public_archives_dir, |
| const scoped_refptr<base::SequencedTaskRunner>& task_runner) |
| : temporary_archives_dir_(temporary_archives_dir), |
| private_archives_dir_(private_archives_dir), |
| public_archives_dir_(public_archives_dir), |
| task_runner_(task_runner) {} |
| |
| ArchiveManager::~ArchiveManager() {} |
| |
| void ArchiveManager::EnsureArchivesDirCreated( |
| base::OnceCallback<void()> callback) { |
| // The callback will only be invoked once both directories are created. |
| if (!temporary_archives_dir_.empty()) { |
| task_runner_->PostTask( |
| FROM_HERE, base::BindOnce(EnsureArchivesDirCreatedImpl, |
| temporary_archives_dir_, true /* is_temp */)); |
| } |
| task_runner_->PostTaskAndReply( |
| FROM_HERE, |
| base::BindOnce(EnsureArchivesDirCreatedImpl, private_archives_dir_, |
| false /* is_temp */), |
| std::move(callback)); |
| } |
| |
| void ArchiveManager::GetStorageStats(StorageStatsCallback callback) const { |
| task_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(GetStorageStatsImpl, temporary_archives_dir_, |
| private_archives_dir_, public_archives_dir_, |
| base::ThreadTaskRunnerHandle::Get(), std::move(callback))); |
| } |
| |
| const base::FilePath& ArchiveManager::GetTemporaryArchivesDir() const { |
| return temporary_archives_dir_; |
| } |
| |
| const base::FilePath& ArchiveManager::GetPrivateArchivesDir() const { |
| return private_archives_dir_; |
| } |
| |
| const base::FilePath& ArchiveManager::GetPublicArchivesDir() { |
| return public_archives_dir_; |
| } |
| |
| } // namespace offline_pages |