| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "rlz/win/lib/rlz_value_store_registry.h" | |
| 6 | |
| 7 #include "base/win/registry.h" | |
| 8 #include "base/stringprintf.h" | |
| 9 #include "base/utf_string_conversions.h" | |
| 10 #include "rlz/lib/assert.h" | |
| 11 #include "rlz/lib/lib_values.h" | |
| 12 #include "rlz/lib/rlz_lib.h" | |
| 13 #include "rlz/lib/string_utils.h" | |
| 14 #include "rlz/win/lib/registry_util.h" | |
| 15 | |
| 16 namespace rlz_lib { | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 // | |
| 21 // Registry keys: | |
| 22 // | |
| 23 // RLZ's are stored as: | |
| 24 // <AccessPointName> = <RLZ value> @ kRootKey\kLibKeyName\kRlzsSubkeyName. | |
| 25 // | |
| 26 // Events are stored as: | |
| 27 // <AccessPointName><EventName> = 1 @ | |
| 28 // HKCU\kLibKeyName\kEventsSubkeyName\GetProductName(product). | |
| 29 // | |
| 30 // The OEM Deal Confirmation Code (DCC) is stored as | |
| 31 // kDccValueName = <DCC value> @ HKLM\kLibKeyName | |
| 32 // | |
| 33 // The last ping time, per product is stored as: | |
| 34 // GetProductName(product) = <last ping time> @ | |
| 35 // HKCU\kLibKeyName\kPingTimesSubkeyName. | |
| 36 // | |
| 37 // The server does not care about any of these constants. | |
| 38 // | |
| 39 const char kLibKeyName[] = "Software\\Google\\Common\\Rlz"; | |
| 40 const wchar_t kGoogleKeyName[] = L"Software\\Google"; | |
| 41 const wchar_t kGoogleCommonKeyName[] = L"Software\\Google\\Common"; | |
| 42 const char kRlzsSubkeyName[] = "RLZs"; | |
| 43 const char kEventsSubkeyName[] = "Events"; | |
| 44 const char kStatefulEventsSubkeyName[] = "StatefulEvents"; | |
| 45 const char kPingTimesSubkeyName[] = "PTimes"; | |
| 46 | |
| 47 std::wstring GetWideProductName(Product product) { | |
| 48 return ASCIIToWide(GetProductName(product)); | |
| 49 } | |
| 50 | |
| 51 void AppendBrandToString(std::string* str) { | |
| 52 std::string brand(SupplementaryBranding::GetBrand()); | |
| 53 if (!brand.empty()) | |
| 54 base::StringAppendF(str, "\\_%s", brand.c_str()); | |
| 55 } | |
| 56 | |
| 57 // Function to get the specific registry keys. | |
| 58 bool GetRegKey(const char* name, REGSAM access, base::win::RegKey* key) { | |
| 59 std::string key_location; | |
| 60 base::StringAppendF(&key_location, "%s\\%s", kLibKeyName, name); | |
| 61 AppendBrandToString(&key_location); | |
| 62 | |
| 63 LONG ret = ERROR_SUCCESS; | |
| 64 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) { | |
| 65 ret = key->Create(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(), | |
| 66 access); | |
| 67 } else { | |
| 68 ret = key->Open(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(), | |
| 69 access); | |
| 70 } | |
| 71 | |
| 72 return ret == ERROR_SUCCESS; | |
| 73 } | |
| 74 | |
| 75 bool GetPingTimesRegKey(REGSAM access, base::win::RegKey* key) { | |
| 76 return GetRegKey(kPingTimesSubkeyName, access, key); | |
| 77 } | |
| 78 | |
| 79 | |
| 80 bool GetEventsRegKey(const char* event_type, | |
| 81 const rlz_lib::Product* product, | |
| 82 REGSAM access, base::win::RegKey* key) { | |
| 83 std::string key_location; | |
| 84 base::StringAppendF(&key_location, "%s\\%s", kLibKeyName, | |
| 85 event_type); | |
| 86 AppendBrandToString(&key_location); | |
| 87 | |
| 88 if (product != NULL) { | |
| 89 std::string product_name = GetProductName(*product); | |
| 90 if (product_name.empty()) | |
| 91 return false; | |
| 92 | |
| 93 base::StringAppendF(&key_location, "\\%s", product_name.c_str()); | |
| 94 } | |
| 95 | |
| 96 LONG ret = ERROR_SUCCESS; | |
| 97 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) { | |
| 98 ret = key->Create(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(), | |
| 99 access); | |
| 100 } else { | |
| 101 ret = key->Open(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(), | |
| 102 access); | |
| 103 } | |
| 104 | |
| 105 return ret == ERROR_SUCCESS; | |
| 106 } | |
| 107 | |
| 108 bool GetAccessPointRlzsRegKey(REGSAM access, base::win::RegKey* key) { | |
| 109 return GetRegKey(kRlzsSubkeyName, access, key); | |
| 110 } | |
| 111 | |
| 112 bool ClearAllProductEventValues(rlz_lib::Product product, const char* key) { | |
| 113 std::wstring product_name = GetWideProductName(product); | |
| 114 if (product_name.empty()) | |
| 115 return false; | |
| 116 | |
| 117 base::win::RegKey reg_key; | |
| 118 GetEventsRegKey(key, NULL, KEY_WRITE, ®_key); | |
| 119 reg_key.DeleteKey(product_name.c_str()); | |
| 120 | |
| 121 // Verify that the value no longer exists. | |
| 122 base::win::RegKey product_events( | |
| 123 reg_key.Handle(), product_name.c_str(), KEY_READ); | |
| 124 if (product_events.Valid()) { | |
| 125 ASSERT_STRING("ClearAllProductEvents: Key deletion failed"); | |
| 126 return false; | |
| 127 } | |
| 128 | |
| 129 return true; | |
| 130 } | |
| 131 | |
| 132 // Deletes a registry key if it exists and has no subkeys or values. | |
| 133 // TODO: Move this to a registry_utils file and add unittest. | |
| 134 bool DeleteKeyIfEmpty(HKEY root_key, const wchar_t* key_name) { | |
| 135 if (!key_name) { | |
| 136 ASSERT_STRING("DeleteKeyIfEmpty: key_name is NULL"); | |
| 137 return false; | |
| 138 } else { // Scope needed for RegKey | |
| 139 base::win::RegKey key(root_key, key_name, KEY_READ); | |
| 140 if (!key.Valid()) | |
| 141 return true; // Key does not exist - nothing to do. | |
| 142 | |
| 143 base::win::RegistryKeyIterator key_iter(root_key, key_name); | |
| 144 if (key_iter.SubkeyCount() > 0) | |
| 145 return true; // Not empty, so nothing to do | |
| 146 | |
| 147 base::win::RegistryValueIterator value_iter(root_key, key_name); | |
| 148 if (value_iter.ValueCount() > 0) | |
| 149 return true; // Not empty, so nothing to do | |
| 150 } | |
| 151 | |
| 152 // The key is empty - delete it now. | |
| 153 base::win::RegKey key(root_key, L"", KEY_WRITE); | |
| 154 return key.DeleteKey(key_name) == ERROR_SUCCESS; | |
| 155 } | |
| 156 | |
| 157 } // namespace | |
| 158 | |
| 159 // static | |
| 160 std::wstring RlzValueStoreRegistry::GetWideLibKeyName() { | |
| 161 return ASCIIToWide(kLibKeyName); | |
| 162 } | |
| 163 | |
| 164 bool RlzValueStoreRegistry::HasAccess(AccessType type) { | |
| 165 return HasUserKeyAccess(type == kWriteAccess); | |
| 166 } | |
| 167 | |
| 168 bool RlzValueStoreRegistry::WritePingTime(Product product, int64 time) { | |
| 169 base::win::RegKey key; | |
| 170 std::wstring product_name = GetWideProductName(product); | |
| 171 return GetPingTimesRegKey(KEY_WRITE, &key) && | |
| 172 key.WriteValue(product_name.c_str(), &time, sizeof(time), | |
| 173 REG_QWORD) == ERROR_SUCCESS; | |
| 174 } | |
| 175 | |
| 176 bool RlzValueStoreRegistry::ReadPingTime(Product product, int64* time) { | |
| 177 base::win::RegKey key; | |
| 178 std::wstring product_name = GetWideProductName(product); | |
| 179 return GetPingTimesRegKey(KEY_READ, &key) && | |
| 180 key.ReadInt64(product_name.c_str(), time) == ERROR_SUCCESS; | |
| 181 } | |
| 182 | |
| 183 bool RlzValueStoreRegistry::ClearPingTime(Product product) { | |
| 184 base::win::RegKey key; | |
| 185 GetPingTimesRegKey(KEY_WRITE, &key); | |
| 186 | |
| 187 std::wstring product_name = GetWideProductName(product); | |
| 188 key.DeleteValue(product_name.c_str()); | |
| 189 | |
| 190 // Verify deletion. | |
| 191 uint64 value; | |
| 192 DWORD size = sizeof(value); | |
| 193 if (key.ReadValue( | |
| 194 product_name.c_str(), &value, &size, NULL) == ERROR_SUCCESS) { | |
| 195 ASSERT_STRING("RlzValueStoreRegistry::ClearPingTime: Failed to delete."); | |
| 196 return false; | |
| 197 } | |
| 198 | |
| 199 return true; | |
| 200 } | |
| 201 | |
| 202 bool RlzValueStoreRegistry::WriteAccessPointRlz(AccessPoint access_point, | |
| 203 const char* new_rlz) { | |
| 204 const char* access_point_name = GetAccessPointName(access_point); | |
| 205 if (!access_point_name) | |
| 206 return false; | |
| 207 | |
| 208 std::wstring access_point_name_wide(ASCIIToWide(access_point_name)); | |
| 209 base::win::RegKey key; | |
| 210 GetAccessPointRlzsRegKey(KEY_WRITE, &key); | |
| 211 | |
| 212 if (!RegKeyWriteValue(key, access_point_name_wide.c_str(), new_rlz)) { | |
| 213 ASSERT_STRING("SetAccessPointRlz: Could not write the new RLZ value"); | |
| 214 return false; | |
| 215 } | |
| 216 return true; | |
| 217 } | |
| 218 | |
| 219 bool RlzValueStoreRegistry::ReadAccessPointRlz(AccessPoint access_point, | |
| 220 char* rlz, | |
| 221 size_t rlz_size) { | |
| 222 const char* access_point_name = GetAccessPointName(access_point); | |
| 223 if (!access_point_name) | |
| 224 return false; | |
| 225 | |
| 226 size_t size = rlz_size; | |
| 227 base::win::RegKey key; | |
| 228 GetAccessPointRlzsRegKey(KEY_READ, &key); | |
| 229 if (!RegKeyReadValue(key, ASCIIToWide(access_point_name).c_str(), | |
| 230 rlz, &size)) { | |
| 231 rlz[0] = 0; | |
| 232 if (size > rlz_size) { | |
| 233 ASSERT_STRING("GetAccessPointRlz: Insufficient buffer size"); | |
| 234 return false; | |
| 235 } | |
| 236 } | |
| 237 return true; | |
| 238 } | |
| 239 | |
| 240 bool RlzValueStoreRegistry::ClearAccessPointRlz(AccessPoint access_point) { | |
| 241 const char* access_point_name = GetAccessPointName(access_point); | |
| 242 if (!access_point_name) | |
| 243 return false; | |
| 244 | |
| 245 std::wstring access_point_name_wide(ASCIIToWide(access_point_name)); | |
| 246 base::win::RegKey key; | |
| 247 GetAccessPointRlzsRegKey(KEY_WRITE, &key); | |
| 248 | |
| 249 key.DeleteValue(access_point_name_wide.c_str()); | |
| 250 | |
| 251 // Verify deletion. | |
| 252 DWORD value; | |
| 253 if (key.ReadValueDW(access_point_name_wide.c_str(), &value) == | |
| 254 ERROR_SUCCESS) { | |
| 255 ASSERT_STRING("SetAccessPointRlz: Could not clear the RLZ value."); | |
| 256 return false; | |
| 257 } | |
| 258 return true; | |
| 259 } | |
| 260 | |
| 261 bool RlzValueStoreRegistry::AddProductEvent(Product product, | |
| 262 const char* event_rlz) { | |
| 263 std::wstring event_rlz_wide(ASCIIToWide(event_rlz)); | |
| 264 base::win::RegKey reg_key; | |
| 265 GetEventsRegKey(kEventsSubkeyName, &product, KEY_WRITE, ®_key); | |
| 266 if (reg_key.WriteValue(event_rlz_wide.c_str(), 1) != ERROR_SUCCESS) { | |
| 267 ASSERT_STRING("AddProductEvent: Could not write the new event value"); | |
| 268 return false; | |
| 269 } | |
| 270 | |
| 271 return true; | |
| 272 } | |
| 273 | |
| 274 bool RlzValueStoreRegistry::ReadProductEvents(Product product, | |
| 275 std::vector<std::string>* events) { | |
| 276 // Open the events key. | |
| 277 base::win::RegKey events_key; | |
| 278 GetEventsRegKey(kEventsSubkeyName, &product, KEY_READ, &events_key); | |
| 279 if (!events_key.Valid()) | |
| 280 return false; | |
| 281 | |
| 282 // Append the events to the buffer. | |
| 283 int num_values = 0; | |
| 284 LONG result = ERROR_SUCCESS; | |
| 285 for (num_values = 0; result == ERROR_SUCCESS; ++num_values) { | |
| 286 // Max 32767 bytes according to MSDN, but we never use that much. | |
| 287 const size_t kMaxValueNameLength = 2048; | |
| 288 char buffer[kMaxValueNameLength]; | |
| 289 DWORD size = arraysize(buffer); | |
| 290 | |
| 291 result = RegEnumValueA(events_key.Handle(), num_values, buffer, &size, | |
| 292 NULL, NULL, NULL, NULL); | |
| 293 if (result == ERROR_SUCCESS) | |
| 294 events->push_back(std::string(buffer)); | |
| 295 } | |
| 296 | |
| 297 return result == ERROR_NO_MORE_ITEMS; | |
| 298 } | |
| 299 | |
| 300 bool RlzValueStoreRegistry::ClearProductEvent(Product product, | |
| 301 const char* event_rlz) { | |
| 302 std::wstring event_rlz_wide(ASCIIToWide(event_rlz)); | |
| 303 base::win::RegKey key; | |
| 304 GetEventsRegKey(kEventsSubkeyName, &product, KEY_WRITE, &key); | |
| 305 key.DeleteValue(event_rlz_wide.c_str()); | |
| 306 | |
| 307 // Verify deletion. | |
| 308 DWORD value; | |
| 309 if (key.ReadValueDW(event_rlz_wide.c_str(), &value) == ERROR_SUCCESS) { | |
| 310 ASSERT_STRING("ClearProductEvent: Could not delete the event value."); | |
| 311 return false; | |
| 312 } | |
| 313 | |
| 314 return true; | |
| 315 } | |
| 316 | |
| 317 bool RlzValueStoreRegistry::ClearAllProductEvents(Product product) { | |
| 318 return ClearAllProductEventValues(product, kEventsSubkeyName); | |
| 319 } | |
| 320 | |
| 321 bool RlzValueStoreRegistry::AddStatefulEvent(Product product, | |
| 322 const char* event_rlz) { | |
| 323 base::win::RegKey key; | |
| 324 std::wstring event_rlz_wide(ASCIIToWide(event_rlz)); | |
| 325 if (!GetEventsRegKey(kStatefulEventsSubkeyName, &product, KEY_WRITE, &key) || | |
| 326 key.WriteValue(event_rlz_wide.c_str(), 1) != ERROR_SUCCESS) { | |
| 327 ASSERT_STRING( | |
| 328 "AddStatefulEvent: Could not write the new stateful event"); | |
| 329 return false; | |
| 330 } | |
| 331 | |
| 332 return true; | |
| 333 } | |
| 334 | |
| 335 bool RlzValueStoreRegistry::IsStatefulEvent(Product product, | |
| 336 const char* event_rlz) { | |
| 337 DWORD value; | |
| 338 base::win::RegKey key; | |
| 339 GetEventsRegKey(kStatefulEventsSubkeyName, &product, KEY_READ, &key); | |
| 340 std::wstring event_rlz_wide(ASCIIToWide(event_rlz)); | |
| 341 return key.ReadValueDW(event_rlz_wide.c_str(), &value) == ERROR_SUCCESS; | |
| 342 } | |
| 343 | |
| 344 bool RlzValueStoreRegistry::ClearAllStatefulEvents(Product product) { | |
| 345 return ClearAllProductEventValues(product, kStatefulEventsSubkeyName); | |
| 346 } | |
| 347 | |
| 348 void RlzValueStoreRegistry::CollectGarbage() { | |
| 349 // Delete each of the known subkeys if empty. | |
| 350 const char* subkeys[] = { | |
| 351 kRlzsSubkeyName, | |
| 352 kEventsSubkeyName, | |
| 353 kStatefulEventsSubkeyName, | |
| 354 kPingTimesSubkeyName | |
| 355 }; | |
| 356 | |
| 357 for (int i = 0; i < arraysize(subkeys); i++) { | |
| 358 std::string subkey_name; | |
| 359 base::StringAppendF(&subkey_name, "%s\\%s", kLibKeyName, subkeys[i]); | |
| 360 AppendBrandToString(&subkey_name); | |
| 361 | |
| 362 VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, | |
| 363 ASCIIToWide(subkey_name).c_str())); | |
| 364 } | |
| 365 | |
| 366 // Delete the library key and its parents too now if empty. | |
| 367 VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, GetWideLibKeyName().c_str())); | |
| 368 VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, kGoogleCommonKeyName)); | |
| 369 VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, kGoogleKeyName)); | |
| 370 } | |
| 371 | |
| 372 ScopedRlzValueStoreLock::ScopedRlzValueStoreLock() { | |
| 373 if (!lock_.failed()) | |
| 374 store_.reset(new RlzValueStoreRegistry); | |
| 375 } | |
| 376 | |
| 377 ScopedRlzValueStoreLock::~ScopedRlzValueStoreLock() { | |
| 378 } | |
| 379 | |
| 380 RlzValueStore* ScopedRlzValueStoreLock::GetStore() { | |
| 381 return store_.get(); | |
| 382 } | |
| 383 | |
| 384 } // namespace rlz_lib | |
| OLD | NEW |