1aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
2aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Copyright (C) 2012 The Android Open Source Project
3aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
4aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Licensed under the Apache License, Version 2.0 (the "License");
5aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// you may not use this file except in compliance with the License.
6aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// You may obtain a copy of the License at
7aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
8aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//      http://www.apache.org/licenses/LICENSE-2.0
9aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
10aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Unless required by applicable law or agreed to in writing, software
11aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// distributed under the License is distributed on an "AS IS" BASIS,
12aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// See the License for the specific language governing permissions and
14aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// limitations under the License.
15aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
163003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
1739910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/prefs.h"
183003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
19d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo#include <algorithm>
20d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo
2106c76a49bfd29c8abdb8abd5b646a6583783191aBen Chan#include <base/files/file_util.h>
22362757765e7697dd93e8de05fa0a59f29242eb89Darin Petkov#include <base/logging.h>
2375039d7397f03dff77bdf4e26398049ff88edc4cAlex Vakulenko#include <base/strings/string_number_conversions.h>
2475039d7397f03dff77bdf4e26398049ff88edc4cAlex Vakulenko#include <base/strings/string_util.h>
25362757765e7697dd93e8de05fa0a59f29242eb89Darin Petkov
2639910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/utils.h"
273003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
283003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkovusing std::string;
293003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
303003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkovnamespace chromeos_update_engine {
313003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
32a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool PrefsBase::GetString(const string& key, string* value) const {
33a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  return storage_->GetKey(key, value);
343003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov}
353003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
36a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool PrefsBase::SetString(const string& key, const string& value) {
37a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  TEST_AND_RETURN_FALSE(storage_->SetKey(key, value));
38d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  const auto observers_for_key = observers_.find(key);
39d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  if (observers_for_key != observers_.end()) {
40d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo    std::vector<ObserverInterface*> copy_observers(observers_for_key->second);
41d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo    for (ObserverInterface* observer : copy_observers)
42d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo      observer->OnPrefSet(key);
43d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  }
443003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  return true;
453003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov}
463003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
47a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool PrefsBase::GetInt64(const string& key, int64_t* value) const {
483003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  string str_value;
4908fce04e5341c99f308ee7462b1f351f5232eacdJay Srinivasan  if (!GetString(key, &str_value))
5008fce04e5341c99f308ee7462b1f351f5232eacdJay Srinivasan    return false;
51736fcb57ca2dcf09710a797e4c23a64f6cd64e16Ben Chan  base::TrimWhitespaceASCII(str_value, base::TRIM_ALL, &str_value);
52790e62e2d8114647b0785574bea361cf931c482bChris Masone  TEST_AND_RETURN_FALSE(base::StringToInt64(str_value, value));
533003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  return true;
543003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov}
553003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
56a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool PrefsBase::SetInt64(const string& key, const int64_t value) {
57790e62e2d8114647b0785574bea361cf931c482bChris Masone  return SetString(key, base::Int64ToString(value));
583003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov}
593003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
60a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool PrefsBase::GetBoolean(const string& key, bool* value) const {
61efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo  string str_value;
62efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo  if (!GetString(key, &str_value))
63efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo    return false;
64736fcb57ca2dcf09710a797e4c23a64f6cd64e16Ben Chan  base::TrimWhitespaceASCII(str_value, base::TRIM_ALL, &str_value);
65efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo  if (str_value == "false") {
66efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo    *value = false;
67efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo    return true;
68efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo  }
69efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo  if (str_value == "true") {
70efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo    *value = true;
71efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo    return true;
72efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo  }
73efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo  return false;
74efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo}
75efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo
76a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool PrefsBase::SetBoolean(const string& key, const bool value) {
77efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo  return SetString(key, value ? "true" : "false");
78efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo}
79efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo
80a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool PrefsBase::Exists(const string& key) const {
81a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  return storage_->KeyExists(key);
82480ddfa079ebd01ed87e495332dec121d9ae781fJay Srinivasan}
83480ddfa079ebd01ed87e495332dec121d9ae781fJay Srinivasan
84a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool PrefsBase::Delete(const string& key) {
85a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  TEST_AND_RETURN_FALSE(storage_->DeleteKey(key));
86d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  const auto observers_for_key = observers_.find(key);
87d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  if (observers_for_key != observers_.end()) {
88d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo    std::vector<ObserverInterface*> copy_observers(observers_for_key->second);
89d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo    for (ObserverInterface* observer : copy_observers)
90d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo      observer->OnPrefDeleted(key);
91d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  }
92d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  return true;
93d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo}
94d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo
95a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymovoid PrefsBase::AddObserver(const string& key, ObserverInterface* observer) {
96d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  observers_[key].push_back(observer);
97d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo}
98d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo
99a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymovoid PrefsBase::RemoveObserver(const string& key, ObserverInterface* observer) {
100d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  std::vector<ObserverInterface*>& observers_for_key = observers_[key];
101d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  auto observer_it =
102d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo      std::find(observers_for_key.begin(), observers_for_key.end(), observer);
103d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  if (observer_it != observers_for_key.end())
104d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo    observers_for_key.erase(observer_it);
105480ddfa079ebd01ed87e495332dec121d9ae781fJay Srinivasan}
106480ddfa079ebd01ed87e495332dec121d9ae781fJay Srinivasan
107a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo// Prefs
108a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo
109a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool Prefs::Init(const base::FilePath& prefs_dir) {
110a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  return file_storage_.Init(prefs_dir);
111a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo}
112a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo
113a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool Prefs::FileStorage::Init(const base::FilePath& prefs_dir) {
114a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  prefs_dir_ = prefs_dir;
115a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  return true;
116a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo}
117a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo
118a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool Prefs::FileStorage::GetKey(const string& key, string* value) const {
119a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  base::FilePath filename;
120a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
121a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  if (!base::ReadFileToString(filename, value)) {
122a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo    LOG(INFO) << key << " not present in " << prefs_dir_.value();
123a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo    return false;
124a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  }
125a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  return true;
126a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo}
127a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo
128a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool Prefs::FileStorage::SetKey(const string& key, const string& value) {
129a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  base::FilePath filename;
130a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
131a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  if (!base::DirectoryExists(filename.DirName())) {
132a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo    // Only attempt to create the directory if it doesn't exist to avoid calls
133a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo    // to parent directories where we might not have permission to write to.
134a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo    TEST_AND_RETURN_FALSE(base::CreateDirectory(filename.DirName()));
135a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  }
136a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  TEST_AND_RETURN_FALSE(base::WriteFile(filename, value.data(), value.size()) ==
137a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo                        static_cast<int>(value.size()));
138a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  return true;
139a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo}
140a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo
141a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool Prefs::FileStorage::KeyExists(const string& key) const {
142a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  base::FilePath filename;
143a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
144a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  return base::PathExists(filename);
145a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo}
146a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo
147a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool Prefs::FileStorage::DeleteKey(const string& key) {
148a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  base::FilePath filename;
149a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
150a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  TEST_AND_RETURN_FALSE(base::DeleteFile(filename, false));
151a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  return true;
152a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo}
153a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo
154a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool Prefs::FileStorage::GetFileNameForKey(const string& key,
155a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo                                           base::FilePath* filename) const {
1563003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  // Allows only non-empty keys containing [A-Za-z0-9_-].
1573003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  TEST_AND_RETURN_FALSE(!key.empty());
1583003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  for (size_t i = 0; i < key.size(); ++i) {
1593003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov    char c = key.at(i);
1600103c36caa2e38e034e0d22185736b9ccfb35c58Alex Vakulenko    TEST_AND_RETURN_FALSE(base::IsAsciiAlpha(c) || base::IsAsciiDigit(c) ||
1613003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov                          c == '_' || c == '-');
1623003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  }
1633003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  *filename = prefs_dir_.Append(key);
1643003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  return true;
1653003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov}
1663003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
167a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo// MemoryPrefs
168a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo
169a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool MemoryPrefs::MemoryStorage::GetKey(const string& key,
170a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo                                        string* value) const {
171a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  auto it = values_.find(key);
172a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  if (it == values_.end())
173a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo    return false;
174a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  *value = it->second;
175a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  return true;
176a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo}
177a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo
178a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool MemoryPrefs::MemoryStorage::SetKey(const string& key,
179a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo                                        const string& value) {
180a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  values_[key] = value;
181a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  return true;
182a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo}
183a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo
184a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool MemoryPrefs::MemoryStorage::KeyExists(const string& key) const {
185a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  return values_.find(key) != values_.end();
186a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo}
187a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo
188a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymobool MemoryPrefs::MemoryStorage::DeleteKey(const string& key) {
189a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  auto it = values_.find(key);
190a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  if (it == values_.end())
191a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo    return false;
192a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  values_.erase(it);
193a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo  return true;
194a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo}
195a0284ace424d1653f36208da24b5ce878d393c7eAlex Deymo
1963003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov}  // namespace chromeos_update_engine
197