123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- // Copyright (c) 2012 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 "storage/browser/file_system/file_system_usage_cache.h"
- #include <stddef.h>
- #include <stdint.h>
- #include <memory>
- #include <utility>
- #include "base/bind.h"
- #include "base/containers/contains.h"
- #include "base/files/file_util.h"
- #include "base/pickle.h"
- #include "base/time/time.h"
- #include "base/trace_event/trace_event.h"
- namespace storage {
- namespace {
- constexpr base::TimeDelta kCloseDelay = base::Seconds(5);
- const size_t kMaxHandleCacheSize = 2;
- } // namespace
- FileSystemUsageCache::FileSystemUsageCache(bool is_incognito)
- : is_incognito_(is_incognito) {
- DETACH_FROM_SEQUENCE(sequence_checker_);
- }
- FileSystemUsageCache::~FileSystemUsageCache() {
- CloseCacheFiles();
- }
- const base::FilePath::CharType FileSystemUsageCache::kUsageFileName[] =
- FILE_PATH_LITERAL(".usage");
- const char FileSystemUsageCache::kUsageFileHeader[] = "FSU5";
- const size_t FileSystemUsageCache::kUsageFileHeaderSize = 4;
- // Pickle::{Read,Write}Bool treat bool as int
- const int FileSystemUsageCache::kUsageFileSize =
- sizeof(base::Pickle::Header) + FileSystemUsageCache::kUsageFileHeaderSize +
- sizeof(int) + sizeof(int32_t) + sizeof(int64_t); // NOLINT
- bool FileSystemUsageCache::GetUsage(const base::FilePath& usage_file_path,
- int64_t* usage_out) {
- TRACE_EVENT0("FileSystem", "UsageCache::GetUsage");
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(usage_out);
- bool is_valid = true;
- uint32_t dirty = 0;
- int64_t usage = 0;
- if (!Read(usage_file_path, &is_valid, &dirty, &usage))
- return false;
- *usage_out = usage;
- return true;
- }
- bool FileSystemUsageCache::GetDirty(const base::FilePath& usage_file_path,
- uint32_t* dirty_out) {
- TRACE_EVENT0("FileSystem", "UsageCache::GetDirty");
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(dirty_out);
- bool is_valid = true;
- uint32_t dirty = 0;
- int64_t usage = 0;
- if (!Read(usage_file_path, &is_valid, &dirty, &usage))
- return false;
- *dirty_out = dirty;
- return true;
- }
- bool FileSystemUsageCache::IncrementDirty(
- const base::FilePath& usage_file_path) {
- TRACE_EVENT0("FileSystem", "UsageCache::IncrementDirty");
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- bool is_valid = true;
- uint32_t dirty = 0;
- int64_t usage = 0;
- bool new_handle = !HasCacheFileHandle(usage_file_path);
- if (!Read(usage_file_path, &is_valid, &dirty, &usage))
- return false;
- bool success = Write(usage_file_path, is_valid, dirty + 1, usage);
- if (success && dirty == 0 && new_handle)
- FlushFile(usage_file_path);
- return success;
- }
- bool FileSystemUsageCache::DecrementDirty(
- const base::FilePath& usage_file_path) {
- TRACE_EVENT0("FileSystem", "UsageCache::DecrementDirty");
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- bool is_valid = true;
- uint32_t dirty = 0;
- int64_t usage = 0;
- if (!Read(usage_file_path, &is_valid, &dirty, &usage) || dirty == 0)
- return false;
- return Write(usage_file_path, is_valid, dirty - 1, usage);
- }
- bool FileSystemUsageCache::Invalidate(const base::FilePath& usage_file_path) {
- TRACE_EVENT0("FileSystem", "UsageCache::Invalidate");
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- bool is_valid = true;
- uint32_t dirty = 0;
- int64_t usage = 0;
- if (!Read(usage_file_path, &is_valid, &dirty, &usage))
- return false;
- return Write(usage_file_path, false, dirty, usage);
- }
- bool FileSystemUsageCache::IsValid(const base::FilePath& usage_file_path) {
- TRACE_EVENT0("FileSystem", "UsageCache::IsValid");
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- bool is_valid = true;
- uint32_t dirty = 0;
- int64_t usage = 0;
- if (!Read(usage_file_path, &is_valid, &dirty, &usage))
- return false;
- return is_valid;
- }
- bool FileSystemUsageCache::AtomicUpdateUsageByDelta(
- const base::FilePath& usage_file_path,
- int64_t delta) {
- TRACE_EVENT0("FileSystem", "UsageCache::AtomicUpdateUsageByDelta");
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- bool is_valid = true;
- uint32_t dirty = 0;
- int64_t usage = 0;
- if (!Read(usage_file_path, &is_valid, &dirty, &usage))
- return false;
- return Write(usage_file_path, is_valid, dirty, usage + delta);
- }
- bool FileSystemUsageCache::UpdateUsage(const base::FilePath& usage_file_path,
- int64_t fs_usage) {
- TRACE_EVENT0("FileSystem", "UsageCache::UpdateUsage");
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return Write(usage_file_path, true, 0, fs_usage);
- }
- bool FileSystemUsageCache::Exists(const base::FilePath& usage_file_path) {
- TRACE_EVENT0("FileSystem", "UsageCache::Exists");
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (is_incognito_)
- return base::Contains(incognito_usages_, usage_file_path);
- return base::PathExists(usage_file_path);
- }
- bool FileSystemUsageCache::Delete(const base::FilePath& usage_file_path) {
- TRACE_EVENT0("FileSystem", "UsageCache::Delete");
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- CloseCacheFiles();
- if (is_incognito_) {
- if (!base::Contains(incognito_usages_, usage_file_path))
- return false;
- incognito_usages_.erase(incognito_usages_.find(usage_file_path));
- return true;
- }
- return base::DeleteFile(usage_file_path);
- }
- void FileSystemUsageCache::CloseCacheFiles() {
- TRACE_EVENT0("FileSystem", "UsageCache::CloseCacheFiles");
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- cache_files_.clear();
- timer_.Stop();
- }
- bool FileSystemUsageCache::Read(const base::FilePath& usage_file_path,
- bool* is_valid,
- uint32_t* dirty_out,
- int64_t* usage_out) {
- TRACE_EVENT0("FileSystem", "UsageCache::Read");
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(is_valid);
- DCHECK(dirty_out);
- DCHECK(usage_out);
- char buffer[kUsageFileSize];
- const char* header;
- if (usage_file_path.empty() ||
- !ReadBytes(usage_file_path, buffer, kUsageFileSize))
- return false;
- base::Pickle read_pickle(buffer, kUsageFileSize);
- base::PickleIterator iter(read_pickle);
- uint32_t dirty = 0;
- int64_t usage = 0;
- if (!iter.ReadBytes(&header, kUsageFileHeaderSize) ||
- !iter.ReadBool(is_valid) || !iter.ReadUInt32(&dirty) ||
- !iter.ReadInt64(&usage))
- return false;
- if (header[0] != kUsageFileHeader[0] || header[1] != kUsageFileHeader[1] ||
- header[2] != kUsageFileHeader[2] || header[3] != kUsageFileHeader[3])
- return false;
- *dirty_out = dirty;
- *usage_out = usage;
- return true;
- }
- bool FileSystemUsageCache::Write(const base::FilePath& usage_file_path,
- bool is_valid,
- int32_t dirty,
- int64_t usage) {
- TRACE_EVENT0("FileSystem", "UsageCache::Write");
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- base::Pickle write_pickle;
- write_pickle.WriteBytes(kUsageFileHeader, kUsageFileHeaderSize);
- write_pickle.WriteBool(is_valid);
- write_pickle.WriteUInt32(dirty);
- write_pickle.WriteInt64(usage);
- if (!WriteBytes(usage_file_path,
- static_cast<const char*>(write_pickle.data()),
- write_pickle.size())) {
- Delete(usage_file_path);
- return false;
- }
- return true;
- }
- base::File* FileSystemUsageCache::GetFile(const base::FilePath& file_path) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (is_incognito_) {
- NOTREACHED();
- return nullptr;
- }
- if (cache_files_.size() >= kMaxHandleCacheSize)
- CloseCacheFiles();
- ScheduleCloseTimer();
- auto& entry = cache_files_[file_path];
- if (entry)
- return entry.get();
- // Because there are no null entries in cache_files_, the [] inserted a blank
- // pointer, so let's populate the cache.
- entry = std::make_unique<base::File>(file_path, base::File::FLAG_OPEN_ALWAYS |
- base::File::FLAG_READ |
- base::File::FLAG_WRITE);
- if (!entry->IsValid()) {
- cache_files_.erase(file_path);
- return nullptr;
- }
- return entry.get();
- }
- bool FileSystemUsageCache::ReadBytes(const base::FilePath& file_path,
- char* buffer,
- int64_t buffer_size) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (is_incognito_) {
- if (!base::Contains(incognito_usages_, file_path))
- return false;
- memcpy(buffer, incognito_usages_[file_path].data(), buffer_size);
- return true;
- }
- base::File* file = GetFile(file_path);
- if (!file)
- return false;
- return file->Read(0, buffer, buffer_size) == buffer_size;
- }
- bool FileSystemUsageCache::WriteBytes(const base::FilePath& file_path,
- const char* buffer,
- int64_t buffer_size) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (is_incognito_) {
- if (!base::Contains(incognito_usages_, file_path))
- incognito_usages_[file_path] = std::vector<uint8_t>(buffer_size);
- memcpy(incognito_usages_[file_path].data(), buffer, buffer_size);
- return true;
- }
- base::File* file = GetFile(file_path);
- if (!file)
- return false;
- return file->Write(0, buffer, buffer_size) == buffer_size;
- }
- bool FileSystemUsageCache::FlushFile(const base::FilePath& file_path) {
- TRACE_EVENT0("FileSystem", "UsageCache::FlushFile");
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (is_incognito_)
- return base::Contains(incognito_usages_, file_path);
- base::File* file = GetFile(file_path);
- if (!file)
- return false;
- return file->Flush();
- }
- void FileSystemUsageCache::ScheduleCloseTimer() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // This will restart the timer if it is already running.
- timer_.Start(FROM_HERE, kCloseDelay, this,
- &FileSystemUsageCache::CloseCacheFiles);
- }
- bool FileSystemUsageCache::HasCacheFileHandle(const base::FilePath& file_path) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK_LE(cache_files_.size(), kMaxHandleCacheSize);
- return base::Contains(cache_files_, file_path);
- }
- } // namespace storage
|