blob: c161541fb0ee7eef1f38095b6cc593f417385e52 [file] [log] [blame] [edit]
// 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