chromium/chrome/browser/safe_browsing/incident_reporting/platform_state_store_win.cc

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// State is stored in the Windows registry in a value of the key
// HKEY_CURRENT_USER\Software\<browser>\IncidentsSent for each profile. The
// value names are profile directory BaseNames.

#include "chrome/browser/safe_browsing/incident_reporting/platform_state_store.h"

#include <windows.h>

#include "base/files/file_path.h"
#include "base/numerics/safe_conversions.h"
#include "base/win/registry.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/install_static/install_util.h"

namespace safe_browsing {
namespace platform_state_store {

namespace {

// Returns the path to the registry key holding profile-specific state values.
std::wstring GetStateStoreKeyName() {
  return install_static::GetRegistryPath().append(L"\\IncidentsSent");
}

// Returns the name of the registry value for |profile|'s state.
std::wstring GetValueNameForProfile(Profile* profile) {
  return profile->GetBaseName().value();
}

// Clears |profile|'s state.
PlatformStateStoreLoadResult ClearStoreData(Profile* profile) {
  base::win::RegKey key;

  if (key.Open(HKEY_CURRENT_USER, GetStateStoreKeyName().c_str(),
               KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_WOW64_32KEY) ==
      ERROR_SUCCESS) {
    std::wstring value_name(GetValueNameForProfile(profile));
    if (key.HasValue(value_name.c_str())) {
      if (key.DeleteValue(value_name.c_str()) == ERROR_SUCCESS)
        return PlatformStateStoreLoadResult::CLEARED_DATA;
      return PlatformStateStoreLoadResult::DATA_CLEAR_FAILED;
    }
  }
  return PlatformStateStoreLoadResult::CLEARED_NO_DATA;
}

}  // namespace

PlatformStateStoreLoadResult ReadStoreData(Profile* profile,
                                           std::string* data) {
  // Clear any old state if this is a new profile.
  if (profile->IsNewProfile()) {
    data->clear();
    return ClearStoreData(profile);
  }

  std::wstring value_name(GetValueNameForProfile(profile));
  base::win::RegKey key;
  if (key.Open(HKEY_CURRENT_USER, GetStateStoreKeyName().c_str(),
               KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
    while (true) {
      void* buffer = data->empty() ? nullptr : &(*data)[0];
      DWORD buffer_size = base::saturated_cast<DWORD>(data->size());
      LONG result =
          key.ReadValue(value_name.c_str(), buffer, &buffer_size, nullptr);
      // Trim the output string and return if all data was read.
      if (result == ERROR_SUCCESS && buffer_size <= data->size()) {
        data->resize(buffer_size);
        return PlatformStateStoreLoadResult::SUCCESS;
      }
      // Increase the buffer and retry if more space was needed. Otherwise bail.
      if (buffer_size > data->size())
        data->resize(buffer_size);
      else
        return PlatformStateStoreLoadResult::READ_FAILED;
    }
  }

  return PlatformStateStoreLoadResult::OPEN_FAILED;
}

void WriteStoreData(Profile* profile, const std::string& data) {
  base::win::RegKey key;
  if (key.Create(HKEY_CURRENT_USER, GetStateStoreKeyName().c_str(),
                 KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
    if (data.empty()) {
      key.DeleteValue(GetValueNameForProfile(profile).c_str());
    } else {
      key.WriteValue(GetValueNameForProfile(profile).c_str(), &data[0],
                     base::saturated_cast<DWORD>(data.size()),
                     REG_BINARY);
    }
  }
}

}  // namespace platform_state_store
}  // namespace safe_browsing