Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // | 4 // |
| 5 // This file contains the definitions of the installer functions that build | 5 // This file contains the definitions of the installer functions that build |
| 6 // the WorkItemList used to install the application. | 6 // the WorkItemList used to install the application. |
| 7 | 7 |
| 8 #include "chrome/installer/setup/install_worker.h" | 8 #include "chrome/installer/setup/install_worker.h" |
| 9 | 9 |
| 10 #include <oaidl.h> | 10 #include <oaidl.h> |
| 11 #include <shlobj.h> | 11 #include <shlobj.h> |
| 12 #include <time.h> | 12 #include <time.h> |
| 13 | 13 |
| 14 #include <algorithm> | |
| 14 #include <vector> | 15 #include <vector> |
| 15 | 16 |
| 16 #include "base/bind.h" | 17 #include "base/bind.h" |
| 17 #include "base/command_line.h" | 18 #include "base/command_line.h" |
| 18 #include "base/files/file_path.h" | 19 #include "base/files/file_path.h" |
| 19 #include "base/files/file_util.h" | 20 #include "base/files/file_util.h" |
| 20 #include "base/logging.h" | 21 #include "base/logging.h" |
| 21 #include "base/memory/scoped_ptr.h" | 22 #include "base/memory/scoped_ptr.h" |
| 22 #include "base/path_service.h" | 23 #include "base/path_service.h" |
| 24 #include "base/strings/string_tokenizer.h" | |
| 23 #include "base/strings/string_util.h" | 25 #include "base/strings/string_util.h" |
| 26 #include "base/strings/stringprintf.h" | |
| 24 #include "base/strings/utf_string_conversions.h" | 27 #include "base/strings/utf_string_conversions.h" |
| 25 #include "base/version.h" | 28 #include "base/version.h" |
| 26 #include "base/win/registry.h" | 29 #include "base/win/registry.h" |
| 27 #include "base/win/scoped_comptr.h" | 30 #include "base/win/scoped_comptr.h" |
| 28 #include "base/win/windows_version.h" | 31 #include "base/win/windows_version.h" |
| 29 #include "chrome/common/chrome_constants.h" | 32 #include "chrome/common/chrome_constants.h" |
| 30 #include "chrome/common/chrome_switches.h" | 33 #include "chrome/common/chrome_switches.h" |
| 31 #include "chrome/installer/setup/install.h" | 34 #include "chrome/installer/setup/install.h" |
| 32 #include "chrome/installer/setup/setup_constants.h" | 35 #include "chrome/installer/setup/setup_constants.h" |
| 33 #include "chrome/installer/setup/setup_util.h" | 36 #include "chrome/installer/setup/setup_util.h" |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 71 L"{6C288DD7-76FB-4721-B628-56FAC252E199}"; | 74 L"{6C288DD7-76FB-4721-B628-56FAC252E199}"; |
| 72 | 75 |
| 73 const wchar_t kElevationPolicyKeyPath[] = | 76 const wchar_t kElevationPolicyKeyPath[] = |
| 74 L"SOFTWARE\\Microsoft\\Internet Explorer\\Low Rights\\ElevationPolicy\\"; | 77 L"SOFTWARE\\Microsoft\\Internet Explorer\\Low Rights\\ElevationPolicy\\"; |
| 75 | 78 |
| 76 // The legacy command ids for installing an application or extension. These are | 79 // The legacy command ids for installing an application or extension. These are |
| 77 // only here so they can be removed from the registry. | 80 // only here so they can be removed from the registry. |
| 78 const wchar_t kLegacyCmdInstallApp[] = L"install-application"; | 81 const wchar_t kLegacyCmdInstallApp[] = L"install-application"; |
| 79 const wchar_t kLegacyCmdInstallExtension[] = L"install-extension"; | 82 const wchar_t kLegacyCmdInstallExtension[] = L"install-extension"; |
| 80 | 83 |
| 84 // The prefix of the ClientState value that contains the MSI product id in the | |
| 85 // format "<kMSIProductIdPrefix><PRODUCTID>". | |
| 86 const wchar_t kMSIProductIdPrefix[] = L"EnterpriseProduct"; | |
| 87 | |
| 88 // The common path for uninstall registry entries that show up in the | |
| 89 // "Add/Remove Programs" dialog and its later incarnations. | |
| 90 const wchar_t kUninstallRegPathRoot[] = | |
| 91 L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"; | |
| 92 | |
| 93 // This is the path to the MSI user data cache, which should probably never be | |
| 94 // tampered with but which we'll try tweaking anyway. This is used as a printf | |
| 95 // format string with the token to be replaced by an MSI user data id generated | |
| 96 // by ConvertGUIDToMSIUserDataFormat(). Other items of note here are that this | |
| 97 // hard-codes the Local System SID meaning that this is strictly only usable for | |
| 98 // system-level installs. This would need to change for http://crbug.com/111058 | |
| 99 // to be fixed. | |
| 100 const wchar_t kMSIUserDataCacheRoot[] = | |
| 101 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\" | |
| 102 L"S-1-5-18\\Products\\%ls\\InstallProperties"; | |
| 103 | |
| 81 void GetOldIELowRightsElevationPolicyKeyPath(base::string16* key_path) { | 104 void GetOldIELowRightsElevationPolicyKeyPath(base::string16* key_path) { |
| 82 key_path->assign(kElevationPolicyKeyPath, | 105 key_path->assign(kElevationPolicyKeyPath, |
| 83 arraysize(kElevationPolicyKeyPath) - 1); | 106 arraysize(kElevationPolicyKeyPath) - 1); |
| 84 key_path->append(kIELowRightsPolicyOldGuid, | 107 key_path->append(kIELowRightsPolicyOldGuid, |
| 85 arraysize(kIELowRightsPolicyOldGuid)- 1); | 108 arraysize(kIELowRightsPolicyOldGuid)- 1); |
| 86 } | 109 } |
| 87 | 110 |
| 88 // Local helper to call AddRegisterComDllWorkItems for all DLLs in a set of | 111 // Local helper to call AddRegisterComDllWorkItems for all DLLs in a set of |
| 89 // products managed by a given package. | 112 // products managed by a given package. |
| 90 // |old_version| can be NULL to indicate no Chrome is currently installed. | 113 // |old_version| can be NULL to indicate no Chrome is currently installed. |
| (...skipping 574 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 665 scoped_ptr<WorkItemList> no_rollback_list( | 688 scoped_ptr<WorkItemList> no_rollback_list( |
| 666 WorkItem::CreateNoRollbackWorkItemList()); | 689 WorkItem::CreateNoRollbackWorkItemList()); |
| 667 AddUninstallDelegateExecuteWorkItems( | 690 AddUninstallDelegateExecuteWorkItems( |
| 668 HKEY_CURRENT_USER, google_chrome_delegate_execute_path, | 691 HKEY_CURRENT_USER, google_chrome_delegate_execute_path, |
| 669 no_rollback_list.get()); | 692 no_rollback_list.get()); |
| 670 list->AddWorkItem(no_rollback_list.release()); | 693 list->AddWorkItem(no_rollback_list.release()); |
| 671 VLOG(1) << "Added deletion items for bad Canary registrations."; | 694 VLOG(1) << "Added deletion items for bad Canary registrations."; |
| 672 } | 695 } |
| 673 } | 696 } |
| 674 | 697 |
| 698 // Returns the MSI product ID from the ClientState key that is populated for MSI | |
| 699 // installs. This property is encoded in a value name whose format is | |
| 700 // "EnterpriseId<GUID>" where <GUID> is the MSI product id. <GUID> is in the | |
| 701 // format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. The id will be returned if found | |
| 702 // otherwise this method will return an empty string. | |
| 703 // | |
| 704 // This format is strange and its provenance is shrouded in mystery but it has | |
| 705 // the data we need, so use it. | |
| 706 base::string16 ExtractMSIProductId(const InstallerState& installer_state, | |
| 707 const Product& product) { | |
| 708 HKEY reg_root = installer_state.root_key(); | |
| 709 BrowserDistribution* dist = product.distribution(); | |
| 710 DCHECK(dist); | |
| 711 | |
| 712 base::win::RegistryValueIterator value_iter(reg_root, | |
| 713 dist->GetStateKey().c_str()); | |
| 714 for (; value_iter.Valid(); ++value_iter) { | |
| 715 base::string16 value_name(value_iter.Name()); | |
| 716 if (StartsWith(value_name, kMSIProductIdPrefix, false)) | |
|
grt (UTC plus 2)
2014/12/01 16:19:30
uber-nit: "false /* !case_sensitive */))"
| |
| 717 return value_name.substr(arraysize(kMSIProductIdPrefix) - 1); | |
| 718 } | |
| 719 return base::string16(); | |
| 720 } | |
| 721 | |
| 675 } // namespace | 722 } // namespace |
| 676 | 723 |
| 677 // This method adds work items to create (or update) Chrome uninstall entry in | 724 // This method adds work items to create (or update) Chrome uninstall entry in |
| 678 // either the Control Panel->Add/Remove Programs list or in the Omaha client | 725 // either the Control Panel->Add/Remove Programs list or in the Omaha client |
| 679 // state key if running under an MSI installer. | 726 // state key if running under an MSI installer. |
| 680 void AddUninstallShortcutWorkItems(const InstallerState& installer_state, | 727 void AddUninstallShortcutWorkItems(const InstallerState& installer_state, |
| 681 const base::FilePath& setup_path, | 728 const base::FilePath& setup_path, |
| 682 const Version& new_version, | 729 const Version& new_version, |
| 683 const Product& product, | 730 const Product& product, |
| 684 WorkItemList* install_list) { | 731 WorkItemList* install_list) { |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 714 true); | 761 true); |
| 715 install_list->AddSetRegValueWorkItem( | 762 install_list->AddSetRegValueWorkItem( |
| 716 reg_root, | 763 reg_root, |
| 717 update_state_key, | 764 update_state_key, |
| 718 KEY_WOW64_32KEY, | 765 KEY_WOW64_32KEY, |
| 719 installer::kUninstallArgumentsField, | 766 installer::kUninstallArgumentsField, |
| 720 uninstall_arguments.GetCommandLineString(), | 767 uninstall_arguments.GetCommandLineString(), |
| 721 true); | 768 true); |
| 722 | 769 |
| 723 // MSI installations will manage their own uninstall shortcuts. | 770 // MSI installations will manage their own uninstall shortcuts. |
| 724 if (!installer_state.is_msi() && product.ShouldCreateUninstallEntry()) { | 771 if (product.ShouldCreateUninstallEntry()) { |
| 725 // We need to quote the command line for the Add/Remove Programs dialog. | 772 if (!installer_state.is_msi()) { |
| 726 CommandLine quoted_uninstall_cmd(installer_path); | 773 // We need to quote the command line for the Add/Remove Programs dialog. |
| 727 DCHECK_EQ(quoted_uninstall_cmd.GetCommandLineString()[0], '"'); | 774 CommandLine quoted_uninstall_cmd(installer_path); |
| 728 quoted_uninstall_cmd.AppendArguments(uninstall_arguments, false); | 775 DCHECK_EQ(quoted_uninstall_cmd.GetCommandLineString()[0], '"'); |
| 776 quoted_uninstall_cmd.AppendArguments(uninstall_arguments, false); | |
| 729 | 777 |
| 730 base::string16 uninstall_reg = browser_dist->GetUninstallRegPath(); | 778 base::string16 uninstall_reg = browser_dist->GetUninstallRegPath(); |
| 731 install_list->AddCreateRegKeyWorkItem( | 779 install_list->AddCreateRegKeyWorkItem(reg_root, uninstall_reg, |
| 732 reg_root, uninstall_reg, KEY_WOW64_32KEY); | 780 KEY_WOW64_32KEY); |
| 733 install_list->AddSetRegValueWorkItem(reg_root, | |
| 734 uninstall_reg, | |
| 735 KEY_WOW64_32KEY, | |
| 736 installer::kUninstallDisplayNameField, | |
| 737 browser_dist->GetDisplayName(), | |
| 738 true); | |
| 739 install_list->AddSetRegValueWorkItem( | |
| 740 reg_root, | |
| 741 uninstall_reg, | |
| 742 KEY_WOW64_32KEY, | |
| 743 installer::kUninstallStringField, | |
| 744 quoted_uninstall_cmd.GetCommandLineString(), | |
| 745 true); | |
| 746 install_list->AddSetRegValueWorkItem(reg_root, | |
| 747 uninstall_reg, | |
| 748 KEY_WOW64_32KEY, | |
| 749 L"InstallLocation", | |
| 750 install_path.value(), | |
| 751 true); | |
| 752 | |
| 753 BrowserDistribution* dist = product.distribution(); | |
| 754 base::string16 chrome_icon = ShellUtil::FormatIconLocation( | |
| 755 install_path.Append(dist->GetIconFilename()).value(), | |
| 756 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)); | |
| 757 install_list->AddSetRegValueWorkItem(reg_root, | |
| 758 uninstall_reg, | |
| 759 KEY_WOW64_32KEY, | |
| 760 L"DisplayIcon", | |
| 761 chrome_icon, | |
| 762 true); | |
| 763 install_list->AddSetRegValueWorkItem(reg_root, | |
| 764 uninstall_reg, | |
| 765 KEY_WOW64_32KEY, | |
| 766 L"NoModify", | |
| 767 static_cast<DWORD>(1), | |
| 768 true); | |
| 769 install_list->AddSetRegValueWorkItem(reg_root, | |
| 770 uninstall_reg, | |
| 771 KEY_WOW64_32KEY, | |
| 772 L"NoRepair", | |
| 773 static_cast<DWORD>(1), | |
| 774 true); | |
| 775 | |
| 776 install_list->AddSetRegValueWorkItem(reg_root, | |
| 777 uninstall_reg, | |
| 778 KEY_WOW64_32KEY, | |
| 779 L"Publisher", | |
| 780 browser_dist->GetPublisherName(), | |
| 781 true); | |
| 782 install_list->AddSetRegValueWorkItem(reg_root, | |
| 783 uninstall_reg, | |
| 784 KEY_WOW64_32KEY, | |
| 785 L"Version", | |
| 786 ASCIIToUTF16(new_version.GetString()), | |
| 787 true); | |
| 788 install_list->AddSetRegValueWorkItem(reg_root, | |
| 789 uninstall_reg, | |
| 790 KEY_WOW64_32KEY, | |
| 791 L"DisplayVersion", | |
| 792 ASCIIToUTF16(new_version.GetString()), | |
| 793 true); | |
| 794 // TODO(wfh): Ensure that this value is preserved in the 64-bit hive when | |
| 795 // 64-bit installs place the uninstall information into the 64-bit registry. | |
| 796 install_list->AddSetRegValueWorkItem(reg_root, | |
| 797 uninstall_reg, | |
| 798 KEY_WOW64_32KEY, | |
| 799 L"InstallDate", | |
| 800 InstallUtil::GetCurrentDate(), | |
| 801 false); | |
| 802 | |
| 803 const std::vector<uint16>& version_components = new_version.components(); | |
| 804 if (version_components.size() == 4) { | |
| 805 // Our version should be in major.minor.build.rev. | |
| 806 install_list->AddSetRegValueWorkItem( | 781 install_list->AddSetRegValueWorkItem( |
| 807 reg_root, | 782 reg_root, uninstall_reg, KEY_WOW64_32KEY, |
| 808 uninstall_reg, | 783 installer::kUninstallDisplayNameField, browser_dist->GetDisplayName(), |
| 809 KEY_WOW64_32KEY, | |
| 810 L"VersionMajor", | |
| 811 static_cast<DWORD>(version_components[2]), | |
| 812 true); | 784 true); |
| 813 install_list->AddSetRegValueWorkItem( | 785 install_list->AddSetRegValueWorkItem( |
| 814 reg_root, | 786 reg_root, uninstall_reg, KEY_WOW64_32KEY, |
| 815 uninstall_reg, | 787 installer::kUninstallStringField, |
| 816 KEY_WOW64_32KEY, | 788 quoted_uninstall_cmd.GetCommandLineString(), true); |
| 817 L"VersionMinor", | 789 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, |
| 818 static_cast<DWORD>(version_components[3]), | 790 KEY_WOW64_32KEY, L"InstallLocation", |
| 819 true); | 791 install_path.value(), true); |
| 792 | |
| 793 BrowserDistribution* dist = product.distribution(); | |
| 794 base::string16 chrome_icon = ShellUtil::FormatIconLocation( | |
| 795 install_path.Append(dist->GetIconFilename()).value(), | |
| 796 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)); | |
| 797 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, | |
| 798 KEY_WOW64_32KEY, L"DisplayIcon", | |
| 799 chrome_icon, true); | |
| 800 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, | |
| 801 KEY_WOW64_32KEY, L"NoModify", | |
| 802 static_cast<DWORD>(1), true); | |
| 803 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, | |
| 804 KEY_WOW64_32KEY, L"NoRepair", | |
| 805 static_cast<DWORD>(1), true); | |
| 806 | |
| 807 install_list->AddSetRegValueWorkItem( | |
| 808 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"Publisher", | |
| 809 browser_dist->GetPublisherName(), true); | |
| 810 install_list->AddSetRegValueWorkItem( | |
| 811 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"Version", | |
| 812 ASCIIToUTF16(new_version.GetString()), true); | |
| 813 install_list->AddSetRegValueWorkItem( | |
| 814 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"DisplayVersion", | |
| 815 ASCIIToUTF16(new_version.GetString()), true); | |
| 816 // TODO(wfh): Ensure that this value is preserved in the 64-bit hive when | |
| 817 // 64-bit installs place the uninstall information into the 64-bit | |
| 818 // registry. | |
| 819 install_list->AddSetRegValueWorkItem( | |
| 820 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"InstallDate", | |
| 821 InstallUtil::GetCurrentDate(), false); | |
| 822 | |
| 823 const std::vector<uint16>& version_components = new_version.components(); | |
| 824 if (version_components.size() == 4) { | |
| 825 // Our version should be in major.minor.build.rev. | |
| 826 install_list->AddSetRegValueWorkItem( | |
| 827 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"VersionMajor", | |
| 828 static_cast<DWORD>(version_components[2]), true); | |
| 829 install_list->AddSetRegValueWorkItem( | |
| 830 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"VersionMinor", | |
| 831 static_cast<DWORD>(version_components[3]), true); | |
| 832 } | |
| 833 } else { | |
| 834 // This is an MSI install. Largely, leave all uninstall shortcuts and the | |
| 835 // like up to the MSI machinery EXCEPT for the DisplayVersion property. | |
| 836 // | |
| 837 // Due to reasons, the Chrome version number is wider than can fit inside | |
| 838 // the <8bits>.<16bits>.<8bits> allotted to MSI version numbers. To make | |
| 839 // things work the A.B.C.D Chrome version is lossily encoded into an X.Y.Z | |
| 840 // version, dropping the unneeded A and B terms. For full details, see | |
| 841 // https://code.google.com/p/chromium/issues/detail?id=67348#c62 | |
| 842 // | |
| 843 // The upshot of this is that Chrome MSIs have a different visible version | |
| 844 // than actual Chrome releases which causes trouble with some workflows. | |
| 845 // To help mitigate this, attempt to keep the DisplayVersion property in | |
| 846 // sync for MSI installs in both the Add/Remove Programs dialog and the | |
| 847 // corresponding MSI user data cache. | |
| 848 | |
| 849 // Figure out MSI ProductID by looking in ClientState. | |
| 850 // The ProductID is encoded as a key named "EnterpriseProduct<ProductID>". | |
| 851 base::string16 msi_product_id( | |
| 852 ExtractMSIProductId(installer_state, product)); | |
| 853 if (!msi_product_id.empty()) { | |
| 854 base::string16 uninstall_reg_path(kUninstallRegPathRoot); | |
| 855 uninstall_reg_path.append(L"{"); | |
| 856 uninstall_reg_path.append(msi_product_id); | |
| 857 uninstall_reg_path.append(L"}"); | |
| 858 | |
| 859 install_list->AddCreateRegKeyWorkItem(reg_root, uninstall_reg_path, | |
| 860 WorkItem::kWow64Default); | |
| 861 install_list->AddSetRegValueWorkItem( | |
| 862 reg_root, uninstall_reg_path, WorkItem::kWow64Default, | |
| 863 installer::kUninstallDisplayVersionField, | |
| 864 base::ASCIIToUTF16(new_version.GetString()), true)-> | |
| 865 set_ignore_failure(true); | |
| 866 | |
| 867 // Also fix up the MSI user data cache. This is a little hacky, there | |
| 868 // may be a better way and I am not certain this won't cause undesired | |
| 869 // side-effects. Note that the user data cache registry path includes | |
| 870 // the product id without dashes. Also note that the | |
| 871 // kMSIUserDataCacheRoot currently hardcodes the local system SID, which | |
| 872 // will need to be changed for user-level MSI installs to happen as | |
| 873 // tracked by http://crbug.com/111058. Leave a DCHECK here to warn those | |
| 874 // who next venture here to use a correct SID in kMSIUserDataCacheRoot. | |
| 875 DCHECK(installer_state.system_install()); | |
| 876 | |
| 877 base::string16 msi_user_data_product_id( | |
| 878 ConvertGUIDToMSIUserDataFormat(msi_product_id)); | |
| 879 if (!msi_user_data_product_id.empty()) { | |
| 880 base::string16 msi_cache_reg_path(base::StringPrintf( | |
| 881 kMSIUserDataCacheRoot, msi_user_data_product_id.c_str())); | |
| 882 | |
| 883 install_list->AddSetRegValueWorkItem( | |
| 884 reg_root, msi_cache_reg_path, KEY_WOW64_64KEY, | |
| 885 installer::kUninstallDisplayVersionField, | |
| 886 base::ASCIIToUTF16(new_version.GetString()), true)-> | |
| 887 set_ignore_failure(true); | |
| 888 } else { | |
| 889 VLOG(1) << "Failed to convert MSI user data id from product id: " | |
| 890 << msi_product_id; | |
| 891 } | |
| 892 } else { | |
| 893 VLOG(1) << "Failed to extract MSI product id."; | |
| 894 } | |
| 820 } | 895 } |
| 821 } | 896 } |
| 822 } | 897 } |
| 823 | 898 |
| 824 // Create Version key for a product (if not already present) and sets the new | 899 // Create Version key for a product (if not already present) and sets the new |
| 825 // product version as the last step. | 900 // product version as the last step. |
| 826 void AddVersionKeyWorkItems(HKEY root, | 901 void AddVersionKeyWorkItems(HKEY root, |
| 827 const base::string16& version_key, | 902 const base::string16& version_key, |
| 828 const base::string16& product_name, | 903 const base::string16& product_name, |
| 829 const Version& new_version, | 904 const Version& new_version, |
| (...skipping 833 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1663 | 1738 |
| 1664 // Unconditionally remove the legacy Quick Enable command from the binaries. | 1739 // Unconditionally remove the legacy Quick Enable command from the binaries. |
| 1665 // Do this even if multi-install Chrome isn't installed to ensure that it is | 1740 // Do this even if multi-install Chrome isn't installed to ensure that it is |
| 1666 // not left behind in any case. | 1741 // not left behind in any case. |
| 1667 work_item_list->AddDeleteRegKeyWorkItem( | 1742 work_item_list->AddDeleteRegKeyWorkItem( |
| 1668 installer_state.root_key(), cmd_key, KEY_WOW64_32KEY) | 1743 installer_state.root_key(), cmd_key, KEY_WOW64_32KEY) |
| 1669 ->set_log_message("removing " + base::UTF16ToASCII(kCmdQuickEnableCf) + | 1744 ->set_log_message("removing " + base::UTF16ToASCII(kCmdQuickEnableCf) + |
| 1670 " command"); | 1745 " command"); |
| 1671 } | 1746 } |
| 1672 | 1747 |
| 1748 // Converts a correctly formatted guid thusly: | |
| 1749 // 12345678-90ab-cdef-ghij-klmnopqrstuv -> 87654321ba09fedchgjilknmporqtsvu | |
| 1750 // This reverses the string of the first three terms and inverts the bytes of | |
| 1751 // the last two. It also removes the dashes. It expects the input to NOT be | |
| 1752 // wrapped in braces. | |
| 1753 // Returns an empty string on failure. | |
| 1754 base::string16 ConvertGUIDToMSIUserDataFormat(const base::string16& guid) { | |
| 1755 // Perform some very mild validation of the input. | |
| 1756 if (guid.size() != 36) | |
| 1757 return base::string16(); | |
| 1758 | |
| 1759 base::string16 msi_formatted_guid; | |
| 1760 int token_count = 0; | |
| 1761 base::WStringTokenizer tokenizer(guid, L"-"); | |
| 1762 while (tokenizer.GetNext()) { | |
| 1763 // There should be exactly five tokens, bail if not. | |
| 1764 if (token_count >= 5) | |
| 1765 return base::string16(); | |
| 1766 | |
| 1767 base::string16 token(tokenizer.token()); | |
| 1768 if (token_count < 3) { | |
| 1769 // For the first three tokens, just reverse the characters. | |
| 1770 std::reverse(token.begin(), token.end()); | |
| 1771 msi_formatted_guid += token; | |
| 1772 } else { | |
| 1773 // The last two tokens need to be of even length. | |
| 1774 if (token.size() % 2) | |
| 1775 return base::string16(); | |
| 1776 // Swap the halves of each byte (i.e. pair of chars). I don't even. | |
| 1777 for (size_t i = 0; i < token.size(); i += 2) { | |
| 1778 msi_formatted_guid += token[i+1]; | |
| 1779 msi_formatted_guid += token[i]; | |
| 1780 } | |
| 1781 } | |
| 1782 token_count++; | |
| 1783 } | |
| 1784 | |
| 1785 return (token_count == 5) ? msi_formatted_guid : base::string16(); | |
| 1786 } | |
| 1787 | |
| 1673 } // namespace installer | 1788 } // namespace installer |
| OLD | NEW |