blob: 615014f4ea1694bb201b4df9f235a166fe2d70b2 [file] [log] [blame]
Alex Deymoaea4c1c2015-08-19 20:24:43 -07001//
2// Copyright (C) 2012 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
Darin Petkov30030592010-07-27 13:53:20 -070016
Alex Deymo39910dc2015-11-09 17:04:30 -080017#include "update_engine/common/prefs.h"
Darin Petkov30030592010-07-27 13:53:20 -070018
Alex Deymod6f60072015-10-12 12:22:27 -070019#include <algorithm>
20
Andrew065d78d2020-04-07 15:43:07 -070021#include <base/files/file_enumerator.h>
Ben Chan06c76a42014-09-05 08:21:06 -070022#include <base/files/file_util.h>
Darin Petkov36275772010-10-01 11:40:57 -070023#include <base/logging.h>
Alex Vakulenko75039d72014-03-25 12:36:28 -070024#include <base/strings/string_number_conversions.h>
Andrew065d78d2020-04-07 15:43:07 -070025#include <base/strings/string_split.h>
Alex Vakulenko75039d72014-03-25 12:36:28 -070026#include <base/strings/string_util.h>
Darin Petkov36275772010-10-01 11:40:57 -070027
Alex Deymo39910dc2015-11-09 17:04:30 -080028#include "update_engine/common/utils.h"
Darin Petkov30030592010-07-27 13:53:20 -070029
30using std::string;
Jae Hoon Kimc1f36922020-05-11 18:20:18 -070031using std::vector;
Darin Petkov30030592010-07-27 13:53:20 -070032
33namespace chromeos_update_engine {
34
Jae Hoon Kimc1f36922020-05-11 18:20:18 -070035namespace {
36
Jae Hoon Kim29a80e02020-05-11 20:18:49 -070037const char kKeySeparator = '/';
38
Jae Hoon Kimc1f36922020-05-11 18:20:18 -070039void DeleteEmptyDirectories(const base::FilePath& path) {
40 base::FileEnumerator path_enum(
41 path, false /* recursive */, base::FileEnumerator::DIRECTORIES);
42 for (base::FilePath dir_path = path_enum.Next(); !dir_path.empty();
43 dir_path = path_enum.Next()) {
44 DeleteEmptyDirectories(dir_path);
45 if (base::IsDirectoryEmpty(dir_path))
46 base::DeleteFile(dir_path, false);
47 }
48}
49
50} // namespace
51
Alex Deymoa0284ac2016-07-22 12:51:41 -070052bool PrefsBase::GetString(const string& key, string* value) const {
53 return storage_->GetKey(key, value);
Darin Petkov30030592010-07-27 13:53:20 -070054}
55
Alex Deymoa0284ac2016-07-22 12:51:41 -070056bool PrefsBase::SetString(const string& key, const string& value) {
57 TEST_AND_RETURN_FALSE(storage_->SetKey(key, value));
Alex Deymod6f60072015-10-12 12:22:27 -070058 const auto observers_for_key = observers_.find(key);
59 if (observers_for_key != observers_.end()) {
60 std::vector<ObserverInterface*> copy_observers(observers_for_key->second);
61 for (ObserverInterface* observer : copy_observers)
62 observer->OnPrefSet(key);
63 }
Darin Petkov30030592010-07-27 13:53:20 -070064 return true;
65}
66
Alex Deymoa0284ac2016-07-22 12:51:41 -070067bool PrefsBase::GetInt64(const string& key, int64_t* value) const {
Darin Petkov30030592010-07-27 13:53:20 -070068 string str_value;
Jay Srinivasan08fce042012-06-07 16:31:01 -070069 if (!GetString(key, &str_value))
70 return false;
Ben Chan736fcb52014-05-21 18:28:22 -070071 base::TrimWhitespaceASCII(str_value, base::TRIM_ALL, &str_value);
Chris Masone790e62e2010-08-12 10:41:18 -070072 TEST_AND_RETURN_FALSE(base::StringToInt64(str_value, value));
Darin Petkov30030592010-07-27 13:53:20 -070073 return true;
74}
75
Alex Deymoa0284ac2016-07-22 12:51:41 -070076bool PrefsBase::SetInt64(const string& key, const int64_t value) {
hscham00b6aa22020-02-20 12:32:06 +090077 return SetString(key, base::NumberToString(value));
Darin Petkov30030592010-07-27 13:53:20 -070078}
79
Alex Deymoa0284ac2016-07-22 12:51:41 -070080bool PrefsBase::GetBoolean(const string& key, bool* value) const {
Alex Deymoefb7c4c2013-07-09 14:34:00 -070081 string str_value;
82 if (!GetString(key, &str_value))
83 return false;
Ben Chan736fcb52014-05-21 18:28:22 -070084 base::TrimWhitespaceASCII(str_value, base::TRIM_ALL, &str_value);
Alex Deymoefb7c4c2013-07-09 14:34:00 -070085 if (str_value == "false") {
86 *value = false;
87 return true;
88 }
89 if (str_value == "true") {
90 *value = true;
91 return true;
92 }
93 return false;
94}
95
Alex Deymoa0284ac2016-07-22 12:51:41 -070096bool PrefsBase::SetBoolean(const string& key, const bool value) {
Alex Deymoefb7c4c2013-07-09 14:34:00 -070097 return SetString(key, value ? "true" : "false");
98}
99
Alex Deymoa0284ac2016-07-22 12:51:41 -0700100bool PrefsBase::Exists(const string& key) const {
101 return storage_->KeyExists(key);
Jay Srinivasan480ddfa2012-06-01 19:15:26 -0700102}
103
Alex Deymoa0284ac2016-07-22 12:51:41 -0700104bool PrefsBase::Delete(const string& key) {
105 TEST_AND_RETURN_FALSE(storage_->DeleteKey(key));
Alex Deymod6f60072015-10-12 12:22:27 -0700106 const auto observers_for_key = observers_.find(key);
107 if (observers_for_key != observers_.end()) {
108 std::vector<ObserverInterface*> copy_observers(observers_for_key->second);
109 for (ObserverInterface* observer : copy_observers)
110 observer->OnPrefDeleted(key);
111 }
112 return true;
113}
114
Jae Hoon Kim29a80e02020-05-11 20:18:49 -0700115bool PrefsBase::GetSubKeys(const string& ns, vector<string>* keys) const {
116 return storage_->GetSubKeys(ns, keys);
117}
118
Alex Deymoa0284ac2016-07-22 12:51:41 -0700119void PrefsBase::AddObserver(const string& key, ObserverInterface* observer) {
Alex Deymod6f60072015-10-12 12:22:27 -0700120 observers_[key].push_back(observer);
121}
122
Alex Deymoa0284ac2016-07-22 12:51:41 -0700123void PrefsBase::RemoveObserver(const string& key, ObserverInterface* observer) {
Alex Deymod6f60072015-10-12 12:22:27 -0700124 std::vector<ObserverInterface*>& observers_for_key = observers_[key];
125 auto observer_it =
126 std::find(observers_for_key.begin(), observers_for_key.end(), observer);
127 if (observer_it != observers_for_key.end())
128 observers_for_key.erase(observer_it);
Jay Srinivasan480ddfa2012-06-01 19:15:26 -0700129}
130
Jae Hoon Kimc1f36922020-05-11 18:20:18 -0700131string PrefsInterface::CreateSubKey(const vector<string>& ns_and_key) {
132 return base::JoinString(ns_and_key, string(1, kKeySeparator));
Andrew065d78d2020-04-07 15:43:07 -0700133}
134
Alex Deymoa0284ac2016-07-22 12:51:41 -0700135// Prefs
136
137bool Prefs::Init(const base::FilePath& prefs_dir) {
138 return file_storage_.Init(prefs_dir);
139}
140
141bool Prefs::FileStorage::Init(const base::FilePath& prefs_dir) {
142 prefs_dir_ = prefs_dir;
Andrew065d78d2020-04-07 15:43:07 -0700143 // Delete empty directories. Ignore errors when deleting empty directories.
Jae Hoon Kimc1f36922020-05-11 18:20:18 -0700144 DeleteEmptyDirectories(prefs_dir_);
Alex Deymoa0284ac2016-07-22 12:51:41 -0700145 return true;
146}
147
148bool Prefs::FileStorage::GetKey(const string& key, string* value) const {
149 base::FilePath filename;
150 TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
151 if (!base::ReadFileToString(filename, value)) {
Alex Deymoa0284ac2016-07-22 12:51:41 -0700152 return false;
153 }
154 return true;
155}
156
Jae Hoon Kim29a80e02020-05-11 20:18:49 -0700157bool Prefs::FileStorage::GetSubKeys(const string& ns,
158 vector<string>* keys) const {
159 base::FilePath filename;
160 TEST_AND_RETURN_FALSE(GetFileNameForKey(ns, &filename));
161 base::FileEnumerator namespace_enum(
162 prefs_dir_, true, base::FileEnumerator::FILES);
163 for (base::FilePath f = namespace_enum.Next(); !f.empty();
164 f = namespace_enum.Next()) {
165 auto filename_str = filename.value();
166 if (f.value().compare(0, filename_str.length(), filename_str) == 0) {
167 // Only return the key portion excluding the |prefs_dir_| with slash.
168 keys->push_back(f.value().substr(
169 prefs_dir_.AsEndingWithSeparator().value().length()));
170 }
171 }
172 return true;
173}
174
Alex Deymoa0284ac2016-07-22 12:51:41 -0700175bool Prefs::FileStorage::SetKey(const string& key, const string& value) {
176 base::FilePath filename;
177 TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
178 if (!base::DirectoryExists(filename.DirName())) {
179 // Only attempt to create the directory if it doesn't exist to avoid calls
180 // to parent directories where we might not have permission to write to.
181 TEST_AND_RETURN_FALSE(base::CreateDirectory(filename.DirName()));
182 }
183 TEST_AND_RETURN_FALSE(base::WriteFile(filename, value.data(), value.size()) ==
184 static_cast<int>(value.size()));
185 return true;
186}
187
188bool Prefs::FileStorage::KeyExists(const string& key) const {
189 base::FilePath filename;
190 TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
191 return base::PathExists(filename);
192}
193
194bool Prefs::FileStorage::DeleteKey(const string& key) {
195 base::FilePath filename;
196 TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
Jae Hoon Kim29a80e02020-05-11 20:18:49 -0700197 TEST_AND_RETURN_FALSE(base::DeleteFile(filename, false));
Alex Deymoa0284ac2016-07-22 12:51:41 -0700198 return true;
199}
200
201bool Prefs::FileStorage::GetFileNameForKey(const string& key,
202 base::FilePath* filename) const {
Jae Hoon Kim29a80e02020-05-11 20:18:49 -0700203 // Allows only non-empty keys containing [A-Za-z0-9_-/].
Darin Petkov30030592010-07-27 13:53:20 -0700204 TEST_AND_RETURN_FALSE(!key.empty());
Jae Hoon Kim29a80e02020-05-11 20:18:49 -0700205 for (char c : key)
Alex Vakulenko0103c362016-01-20 07:56:15 -0800206 TEST_AND_RETURN_FALSE(base::IsAsciiAlpha(c) || base::IsAsciiDigit(c) ||
Andrew065d78d2020-04-07 15:43:07 -0700207 c == '_' || c == '-' || c == kKeySeparator);
Darin Petkov30030592010-07-27 13:53:20 -0700208 *filename = prefs_dir_.Append(key);
209 return true;
210}
211
Alex Deymoa0284ac2016-07-22 12:51:41 -0700212// MemoryPrefs
213
214bool MemoryPrefs::MemoryStorage::GetKey(const string& key,
215 string* value) const {
216 auto it = values_.find(key);
217 if (it == values_.end())
218 return false;
219 *value = it->second;
220 return true;
221}
222
Jae Hoon Kim29a80e02020-05-11 20:18:49 -0700223bool MemoryPrefs::MemoryStorage::GetSubKeys(const string& ns,
224 vector<string>* keys) const {
225 using value_type = decltype(values_)::value_type;
226 using key_type = decltype(values_)::key_type;
227 auto lower_comp = [](const value_type& pr, const key_type& ns) {
228 return pr.first.substr(0, ns.length()) < ns;
229 };
230 auto upper_comp = [](const key_type& ns, const value_type& pr) {
231 return ns < pr.first.substr(0, ns.length());
232 };
233 auto lower_it =
234 std::lower_bound(begin(values_), end(values_), ns, lower_comp);
235 auto upper_it = std::upper_bound(lower_it, end(values_), ns, upper_comp);
236 while (lower_it != upper_it)
237 keys->push_back((lower_it++)->first);
238 return true;
239}
240
Alex Deymoa0284ac2016-07-22 12:51:41 -0700241bool MemoryPrefs::MemoryStorage::SetKey(const string& key,
242 const string& value) {
243 values_[key] = value;
244 return true;
245}
246
247bool MemoryPrefs::MemoryStorage::KeyExists(const string& key) const {
248 return values_.find(key) != values_.end();
249}
250
251bool MemoryPrefs::MemoryStorage::DeleteKey(const string& key) {
252 auto it = values_.find(key);
Andrew914f5542020-04-21 10:56:33 -0700253 if (it != values_.end())
254 values_.erase(it);
Alex Deymoa0284ac2016-07-22 12:51:41 -0700255 return true;
256}
257
Darin Petkov30030592010-07-27 13:53:20 -0700258} // namespace chromeos_update_engine