15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2010 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shlwapi.h>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "base/files/file_path.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/registry.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/create_reg_key_work_item.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/install_util.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/logging_installer.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::win::RegKey;
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO: refactor this because it is only used once.
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UpOneDirectoryOrEmpty(std::wstring* dir) {
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath path = base::FilePath::FromWStringHack(*dir);
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath directory = path.DirName();
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there is no separator, we will get back kCurrentDirectory.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In this case, clear dir.
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (directory == path || directory.value() ==
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::FilePath::kCurrentDirectory)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dir->clear();
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *dir = directory.value();
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CreateRegKeyWorkItem::~CreateRegKeyWorkItem() {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CreateRegKeyWorkItem::CreateRegKeyWorkItem(HKEY predefined_root,
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const std::wstring& path)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : predefined_root_(predefined_root),
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path_(path),
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key_created_(false) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CreateRegKeyWorkItem::Do() {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!InitKeyList()) {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Nothing needs to be done here.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "no key to create";
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegKey key;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring key_path;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // To create keys, we iterate from back to front.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = key_list_.size(); i > 0; i--) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD disposition;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    key_path.assign(key_list_[i - 1]);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (key.CreateWithDisposition(predefined_root_, key_path.c_str(),
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  &disposition, KEY_READ) == ERROR_SUCCESS) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (disposition == REG_OPENED_EXISTING_KEY) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (key_created_) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // This should not happen. Someone created a subkey under the key
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // we just created?
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          LOG(ERROR) << key_path << " exists, this is not expected.";
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Remove the key path from list if it is already present.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        key_list_.pop_back();
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (disposition == REG_CREATED_NEW_KEY) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        VLOG(1) << "created " << key_path;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        key_created_ = true;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "unkown disposition";
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Failed to create " << key_path;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CreateRegKeyWorkItem::Rollback() {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!key_created_)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring key_path;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // To delete keys, we iterate from front to back.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::wstring>::iterator itr;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (itr = key_list_.begin(); itr != key_list_.end(); ++itr) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    key_path.assign(*itr);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (SHDeleteEmptyKey(predefined_root_, key_path.c_str()) ==
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ERROR_SUCCESS) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(1) << "rollback: delete " << key_path;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(1) << "rollback: can not delete " << key_path;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The key might have been deleted, but we don't reliably know what
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // error code(s) are returned in this case. So we just keep tring delete
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the rest.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_created_ = false;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_list_.clear();
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CreateRegKeyWorkItem::InitKeyList() {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (path_.empty())
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring key_path(path_);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    key_list_.push_back(key_path);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This is pure string operation so it does not matter whether the
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // path is file path or registry path.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpOneDirectoryOrEmpty(&key_path);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } while (!key_path.empty());
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
125