| // Copyright 2017 The Chromium OS 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 <set> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "power_manager/common/file_prefs_store.h" |
| #include "power_manager/common/util.h" |
| |
| #include <base/files/file_enumerator.h> |
| #include <base/files/file_util.h> |
| #include <base/logging.h> |
| #include <base/strings/string_util.h> |
| |
| namespace power_manager { |
| |
| FilePrefsStore::FilePrefsStore(const base::FilePath& pref_path) |
| : pref_path_(pref_path) {} |
| |
| std::string FilePrefsStore::GetDescription() const { |
| return pref_path_.value(); |
| } |
| |
| bool FilePrefsStore::ReadPrefString(const std::string& name, |
| std::string* value_out) { |
| base::FilePath path = pref_path_.Append(name); |
| return util::MaybeReadStringFile(path, value_out); |
| } |
| |
| bool FilePrefsStore::WritePrefString(const std::string& name, |
| const std::string& value) { |
| base::FilePath path = pref_path_.Append(name); |
| return base::WriteFile(path, value.data(), value.size()) != -1; |
| } |
| |
| bool FilePrefsStore::Watch( |
| const PrefsStoreInterface::ChangeCallback& callback) { |
| callback_ = callback; |
| dir_watcher_.reset(new base::FilePathWatcher); |
| return dir_watcher_->Watch( |
| pref_path_, base::FilePathWatcher::Type::kNonRecursive, |
| base::Bind(&FilePrefsStore::HandlePathChanged, base::Unretained(this))); |
| } |
| |
| void FilePrefsStore::HandlePathChanged(const base::FilePath& path, bool error) { |
| if (error) { |
| LOG(ERROR) << "Got error while hearing about change to " << path.value(); |
| return; |
| } |
| |
| if (path == pref_path_) { |
| UpdateFileWatchers(); |
| return; |
| } |
| |
| callback_.Run(path.BaseName().value()); |
| return; |
| } |
| |
| void FilePrefsStore::UpdateFileWatchers() { |
| // Look for files that have been created or unlinked. |
| base::FileEnumerator enumerator(pref_path_, false, |
| base::FileEnumerator::FILES); |
| std::set<std::string> current_prefs; |
| for (base::FilePath path = enumerator.Next(); !path.empty(); |
| path = enumerator.Next()) { |
| current_prefs.insert(path.BaseName().value()); |
| } |
| std::vector<std::string> added_prefs; |
| for (const auto& name : current_prefs) { |
| if (file_watchers_.find(name) == file_watchers_.end()) |
| added_prefs.push_back(name); |
| } |
| std::vector<std::string> removed_prefs; |
| for (const auto& watcher_pair : file_watchers_) { |
| if (current_prefs.find(watcher_pair.first) == current_prefs.end()) |
| removed_prefs.push_back(watcher_pair.first); |
| } |
| |
| // Start watching new files. |
| for (const auto& name : added_prefs) { |
| const base::FilePath path = pref_path_.Append(name); |
| std::unique_ptr<base::FilePathWatcher> watcher = |
| std::make_unique<base::FilePathWatcher>(); |
| if (watcher->Watch(path, base::FilePathWatcher::Type::kNonRecursive, |
| base::Bind(&FilePrefsStore::HandlePathChanged, |
| base::Unretained(this)))) { |
| file_watchers_.insert(std::make_pair(name, std::move(watcher))); |
| } else { |
| LOG(ERROR) << "Unable to watch " << path.value() << " for changes"; |
| } |
| callback_.Run(name); |
| } |
| |
| // Stop watching old files. |
| for (const auto& name : removed_prefs) { |
| file_watchers_.erase(name); |
| callback_.Run(name); |
| } |
| } |
| |
| } // namespace power_manager |