| Index: chrome/browser/profiles/profile_shortcut_manager_win.cc
|
| diff --git a/chrome/browser/profiles/profile_shortcut_manager_win.cc b/chrome/browser/profiles/profile_shortcut_manager_win.cc
|
| index dcd69f59f97968b2b2f34f4c5af396d6d3c5a48a..0061b4cfcd4938ccc2b9094afd2968fd3708fe0a 100644
|
| --- a/chrome/browser/profiles/profile_shortcut_manager_win.cc
|
| +++ b/chrome/browser/profiles/profile_shortcut_manager_win.cc
|
| @@ -6,8 +6,6 @@
|
|
|
| #include <shlobj.h> // For SHChangeNotify().
|
|
|
| -#include <algorithm>
|
| -#include <set>
|
| #include <string>
|
| #include <vector>
|
|
|
| @@ -291,56 +289,33 @@
|
| return ConvertToLongPath(target_path) == ConvertToLongPath(chrome_exe);
|
| }
|
|
|
| -// A functor checks if |path| is the Chrome desktop shortcut (|chrome_exe|)
|
| -// that have the specified |command_line|. If |include_empty_command_lines| is
|
| -// true Chrome desktop shortcuts with empty command lines will also be included.
|
| -struct ChromeCommandLineFilter {
|
| - const base::FilePath& chrome_exe;
|
| - const base::string16& command_line;
|
| - bool include_empty_command_lines;
|
| -
|
| - ChromeCommandLineFilter(const base::FilePath& chrome_exe,
|
| - const base::string16& command_line,
|
| - bool include_empty_command_lines)
|
| - : chrome_exe(chrome_exe),
|
| - command_line(command_line),
|
| - include_empty_command_lines(include_empty_command_lines) {}
|
| -
|
| - bool operator()(const base::FilePath& path) const {
|
| +// Populates |paths| with the file paths of Chrome desktop shortcuts that have
|
| +// the specified |command_line|. If |include_empty_command_lines| is true,
|
| +// Chrome desktop shortcuts with empty command lines will also be included.
|
| +void ListDesktopShortcutsWithCommandLine(const base::FilePath& chrome_exe,
|
| + const base::string16& command_line,
|
| + bool include_empty_command_lines,
|
| + std::vector<base::FilePath>* paths) {
|
| + base::FilePath user_shortcuts_directory;
|
| + if (!GetDesktopShortcutsDirectories(&user_shortcuts_directory, NULL))
|
| + return;
|
| +
|
| + base::FileEnumerator enumerator(user_shortcuts_directory, false,
|
| + base::FileEnumerator::FILES);
|
| + for (base::FilePath path = enumerator.Next(); !path.empty();
|
| + path = enumerator.Next()) {
|
| base::string16 shortcut_command_line;
|
| if (!IsChromeShortcut(path, chrome_exe, &shortcut_command_line))
|
| - return false;
|
| + continue;
|
|
|
| // TODO(asvitkine): Change this to build a CommandLine object and ensure all
|
| // args from |command_line| are present in the shortcut's CommandLine. This
|
| // will be more robust when |command_line| contains multiple args.
|
| if ((shortcut_command_line.empty() && include_empty_command_lines) ||
|
| (shortcut_command_line.find(command_line) != base::string16::npos)) {
|
| - return true;
|
| + paths->push_back(path);
|
| }
|
| - return false;
|
| - }
|
| -};
|
| -
|
| -// Get the file paths of desktop files and folders optionally filtered
|
| -// by |filter|.
|
| -std::set<base::FilePath> ListUserDesktopContents(
|
| - const ChromeCommandLineFilter* filter) {
|
| - std::set<base::FilePath> result;
|
| -
|
| - base::FilePath user_shortcuts_directory;
|
| - if (!GetDesktopShortcutsDirectories(&user_shortcuts_directory, nullptr))
|
| - return result;
|
| -
|
| - base::FileEnumerator enumerator(
|
| - user_shortcuts_directory, false,
|
| - base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
|
| - for (base::FilePath path = enumerator.Next(); !path.empty();
|
| - path = enumerator.Next()) {
|
| - if (!filter || (*filter)(path))
|
| - result.insert(path);
|
| - }
|
| - return result;
|
| + }
|
| }
|
|
|
| // Renames the given desktop shortcut and informs the shell of this change.
|
| @@ -360,20 +335,9 @@
|
|
|
| // Renames an existing Chrome desktop profile shortcut. Must be called on the
|
| // FILE thread.
|
| -// |profile_shortcuts| are Chrome desktop shortcuts for the profile (there can
|
| -// be several).
|
| -// |desktop_contents| is the collection of all user desktop shortcuts
|
| -// (not only Chrome). It is used to make an unique shortcut for the
|
| -// |new_profile_name| among all shortcuts.
|
| -// This function updates |profile_shortcuts| and |desktop_contents| respectively
|
| -// when renaming occurs.
|
| void RenameChromeDesktopShortcutForProfile(
|
| - const base::string16& old_profile_name,
|
| - const base::string16& new_profile_name,
|
| - std::set<base::FilePath>* profile_shortcuts,
|
| - std::set<base::FilePath>* desktop_contents) {
|
| - DCHECK(profile_shortcuts);
|
| - DCHECK(desktop_contents);
|
| + const base::string16& old_shortcut_filename,
|
| + const base::string16& new_shortcut_filename) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::FILE);
|
|
|
| base::FilePath user_shortcuts_directory;
|
| @@ -383,70 +347,32 @@
|
| return;
|
| }
|
|
|
| - BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
|
| -
|
| - // Get a new unique shortcut name.
|
| - const base::string16 new_shortcut_filename =
|
| - profiles::internal::GetUniqueShortcutFilenameForProfile(
|
| - new_profile_name, *desktop_contents, distribution);
|
| + const base::FilePath old_shortcut_path =
|
| + user_shortcuts_directory.Append(old_shortcut_filename);
|
| const base::FilePath new_shortcut_path =
|
| user_shortcuts_directory.Append(new_shortcut_filename);
|
|
|
| - if (!profile_shortcuts->empty()) {
|
| - // From all profile_shortcuts choose the one with a known (canonical) name.
|
| - profiles::internal::ShortcutFilenameMatcher matcher(old_profile_name,
|
| - distribution);
|
| - auto it = std::find_if(profile_shortcuts->begin(), profile_shortcuts->end(),
|
| - [&matcher](const base::FilePath& p) {
|
| - return matcher.IsCanonical(p.BaseName().value());
|
| - });
|
| - // If all profile_shortcuts were renamed by user, respect it and do not
|
| - // rename.
|
| - if (it == profile_shortcuts->end())
|
| - return;
|
| - const base::FilePath old_shortcut_path = *it;
|
| -
|
| + if (base::PathExists(old_shortcut_path)) {
|
| // Rename the old shortcut unless a system-level shortcut exists at the
|
| // destination, in which case the old shortcut is simply deleted.
|
| const base::FilePath possible_new_system_shortcut =
|
| system_shortcuts_directory.Append(new_shortcut_filename);
|
| - if (base::PathExists(possible_new_system_shortcut)) {
|
| - if (base::DeleteFile(old_shortcut_path, false)) {
|
| - profile_shortcuts->erase(old_shortcut_path);
|
| - desktop_contents->erase(old_shortcut_path);
|
| - } else {
|
| - DLOG(ERROR) << "Could not delete Windows profile desktop shortcut.";
|
| - }
|
| - } else {
|
| - if (RenameDesktopShortcut(old_shortcut_path, new_shortcut_path)) {
|
| - profile_shortcuts->erase(old_shortcut_path);
|
| - desktop_contents->erase(old_shortcut_path);
|
| - profile_shortcuts->insert(new_shortcut_path);
|
| - desktop_contents->insert(new_shortcut_path);
|
| - } else {
|
| - DLOG(ERROR) << "Could not rename Windows profile desktop shortcut.";
|
| - }
|
| - }
|
| + if (base::PathExists(possible_new_system_shortcut))
|
| + base::DeleteFile(old_shortcut_path, false);
|
| + else if (!RenameDesktopShortcut(old_shortcut_path, new_shortcut_path))
|
| + DLOG(ERROR) << "Could not rename Windows profile desktop shortcut.";
|
| } else {
|
| - // If the shortcut does not exist, it may have been deleted by the user.
|
| + // If the shortcut does not exist, it may have been renamed by the user. In
|
| + // that case, its name should not be changed.
|
| // It's also possible that a system-level shortcut exists instead - this
|
| // should only be the case for the original Chrome shortcut from an
|
| // installation. If that's the case, copy that one over - it will get its
|
| // properties updated by
|
| // |CreateOrUpdateDesktopShortcutsAndIconForProfile()|.
|
| - const auto old_shortcut_filename =
|
| - profiles::internal::GetShortcutFilenameForProfile(old_profile_name,
|
| - distribution);
|
| const base::FilePath possible_old_system_shortcut =
|
| system_shortcuts_directory.Append(old_shortcut_filename);
|
| - if (base::PathExists(possible_old_system_shortcut)) {
|
| - if (base::CopyFile(possible_old_system_shortcut, new_shortcut_path)) {
|
| - profile_shortcuts->insert(new_shortcut_path);
|
| - desktop_contents->insert(new_shortcut_path);
|
| - } else {
|
| - DLOG(ERROR) << "Could not copy Windows profile desktop shortcut.";
|
| - }
|
| - }
|
| + if (base::PathExists(possible_old_system_shortcut))
|
| + base::CopyFile(possible_old_system_shortcut, new_shortcut_path);
|
| }
|
| }
|
|
|
| @@ -502,31 +428,24 @@
|
| // the following code may result in NOTREACHED() being hit.
|
| DCHECK(distribution->CanCreateDesktopShortcuts());
|
|
|
| - std::set<base::FilePath> desktop_contents = ListUserDesktopContents(nullptr);
|
| -
|
| - const base::string16 command_line =
|
| - profiles::internal::CreateProfileShortcutFlags(params.profile_path);
|
| - ChromeCommandLineFilter filter(
|
| - chrome_exe, command_line,
|
| - params.action == ProfileShortcutManagerWin::UPDATE_NON_PROFILE_SHORTCUTS);
|
| -
|
| - std::set<base::FilePath> shortcuts;
|
| - // Do not call ListUserDesktopContents again (but with filter) to avoid
|
| - // excess work inside it. Just reuse non-filtered desktop_contents.
|
| - // We need both of them (desktop_contents and shortcuts) later.
|
| - std::copy_if(desktop_contents.begin(), desktop_contents.end(),
|
| - std::inserter(shortcuts, shortcuts.begin()), filter);
|
| -
|
| if (params.old_profile_name != params.profile_name) {
|
| - RenameChromeDesktopShortcutForProfile(params.old_profile_name,
|
| - params.profile_name, &shortcuts,
|
| - &desktop_contents);
|
| + const base::string16 old_shortcut_filename =
|
| + profiles::internal::GetShortcutFilenameForProfile(
|
| + params.old_profile_name,
|
| + distribution);
|
| + const base::string16 new_shortcut_filename =
|
| + profiles::internal::GetShortcutFilenameForProfile(params.profile_name,
|
| + distribution);
|
| + RenameChromeDesktopShortcutForProfile(old_shortcut_filename,
|
| + new_shortcut_filename);
|
| }
|
|
|
| ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER);
|
| installer::Product product(distribution);
|
| product.AddDefaultShortcutProperties(chrome_exe, &properties);
|
|
|
| + const base::string16 command_line =
|
| + profiles::internal::CreateProfileShortcutFlags(params.profile_path);
|
|
|
| // Only set the profile-specific properties when |profile_name| is non empty.
|
| // If it is empty, it means the shortcut being created should be a regular,
|
| @@ -546,17 +465,22 @@
|
| ShellUtil::ShortcutOperation operation =
|
| ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING;
|
|
|
| + std::vector<base::FilePath> shortcuts;
|
| + ListDesktopShortcutsWithCommandLine(chrome_exe, command_line,
|
| + params.action == ProfileShortcutManagerWin::UPDATE_NON_PROFILE_SHORTCUTS,
|
| + &shortcuts);
|
| if (params.create_mode == ProfileShortcutManagerWin::CREATE_WHEN_NONE_FOUND &&
|
| shortcuts.empty()) {
|
| const base::string16 shortcut_name =
|
| - profiles::internal::GetUniqueShortcutFilenameForProfile(
|
| - params.profile_name, desktop_contents, distribution);
|
| - shortcuts.insert(base::FilePath(shortcut_name));
|
| + profiles::internal::GetShortcutFilenameForProfile(params.profile_name,
|
| + distribution);
|
| + shortcuts.push_back(base::FilePath(shortcut_name));
|
| operation = ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL;
|
| }
|
|
|
| - for (const auto& shortcut : shortcuts) {
|
| - const base::FilePath shortcut_name = shortcut.BaseName().RemoveExtension();
|
| + for (size_t i = 0; i < shortcuts.size(); ++i) {
|
| + const base::FilePath shortcut_name =
|
| + shortcuts[i].BaseName().RemoveExtension();
|
| properties.set_shortcut_name(shortcut_name.value());
|
| ShellUtil::CreateOrUpdateShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
|
| distribution, properties, operation);
|
| @@ -597,18 +521,20 @@
|
|
|
| const base::string16 command_line =
|
| profiles::internal::CreateProfileShortcutFlags(profile_path);
|
| - ChromeCommandLineFilter filter(chrome_exe, command_line, false);
|
| - const std::set<base::FilePath> shortcuts = ListUserDesktopContents(&filter);
|
| -
|
| - for (const auto& shortcut : shortcuts) {
|
| + std::vector<base::FilePath> shortcuts;
|
| + ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, false,
|
| + &shortcuts);
|
| +
|
| + for (size_t i = 0; i < shortcuts.size(); ++i) {
|
| // Use base::DeleteFile() instead of ShellUtil::RemoveShortcuts(), as the
|
| // latter causes non-profile taskbar shortcuts to be removed since it
|
| // doesn't consider the command-line of the shortcuts it deletes.
|
| // TODO(huangs): Refactor with ShellUtil::RemoveShortcuts().
|
| - base::win::UnpinShortcutFromTaskbar(shortcut);
|
| - base::DeleteFile(shortcut, false);
|
| + base::win::UnpinShortcutFromTaskbar(shortcuts[i]);
|
| + base::DeleteFile(shortcuts[i], false);
|
| // Notify the shell that the shortcut was deleted to ensure desktop refresh.
|
| - SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, shortcut.value().c_str(), nullptr);
|
| + SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, shortcuts[i].value().c_str(),
|
| + NULL);
|
| }
|
|
|
| // If |ensure_shortcuts_remain| is true and deleting this profile caused the
|
| @@ -646,8 +572,10 @@
|
|
|
| const base::string16 command_line =
|
| profiles::internal::CreateProfileShortcutFlags(profile_path);
|
| - ChromeCommandLineFilter filter(chrome_exe, command_line, false);
|
| - return !ListUserDesktopContents(&filter).empty();
|
| + std::vector<base::FilePath> shortcuts;
|
| + ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, false,
|
| + &shortcuts);
|
| + return !shortcuts.empty();
|
| }
|
|
|
| // Replaces any reserved characters with spaces, and trims the resulting string
|
| @@ -713,60 +641,6 @@
|
| distribution->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME));
|
| }
|
| return shortcut_name + installer::kLnkExt;
|
| -}
|
| -
|
| -base::string16 GetUniqueShortcutFilenameForProfile(
|
| - const base::string16& profile_name,
|
| - const std::set<base::FilePath>& excludes,
|
| - BrowserDistribution* distribution) {
|
| - std::set<base::string16> excludes_names;
|
| - std::transform(excludes.begin(), excludes.end(),
|
| - std::inserter(excludes_names, excludes_names.begin()),
|
| - [](const base::FilePath& e) { return e.BaseName().value(); });
|
| -
|
| - const auto base_name =
|
| - GetShortcutFilenameForProfile(profile_name, distribution);
|
| - auto name = base_name;
|
| - const base::FilePath base_path(base_name);
|
| - for (int uniquifier = 1; excludes_names.count(name) > 0; ++uniquifier) {
|
| - const auto suffix = base::StringPrintf(" (%d)", uniquifier);
|
| - name = base_path.InsertBeforeExtensionASCII(suffix).value();
|
| - }
|
| - return name;
|
| -}
|
| -
|
| -// Corresponds to GetUniqueShortcutFilenameForProfile.
|
| -ShortcutFilenameMatcher::ShortcutFilenameMatcher(
|
| - const base::string16& profile_name,
|
| - BrowserDistribution* distribution)
|
| - : profile_shortcut_filename_(
|
| - GetShortcutFilenameForProfile(profile_name, distribution)),
|
| - lnk_ext_(installer::kLnkExt),
|
| - profile_shortcut_name_(profile_shortcut_filename_) {
|
| - DCHECK(profile_shortcut_name_.ends_with(lnk_ext_));
|
| - profile_shortcut_name_.remove_suffix(lnk_ext_.size());
|
| -}
|
| -
|
| -bool ShortcutFilenameMatcher::IsCanonical(
|
| - const base::string16& filename) const {
|
| - if (filename == profile_shortcut_filename_)
|
| - return true;
|
| -
|
| - base::StringPiece16 shortcut_suffix(filename);
|
| - if (!shortcut_suffix.starts_with(profile_shortcut_name_))
|
| - return false;
|
| - shortcut_suffix.remove_prefix(profile_shortcut_name_.size());
|
| -
|
| - if (!shortcut_suffix.ends_with(lnk_ext_))
|
| - return false;
|
| - shortcut_suffix.remove_suffix(lnk_ext_.size());
|
| -
|
| - if (shortcut_suffix.size() < 4 || !shortcut_suffix.starts_with(L" (") ||
|
| - !shortcut_suffix.ends_with(L")")) {
|
| - return false;
|
| - }
|
| - return std::all_of(shortcut_suffix.begin() + 2, shortcut_suffix.end() - 1,
|
| - iswdigit);
|
| }
|
|
|
| base::string16 CreateProfileShortcutFlags(const base::FilePath& profile_path) {
|
|
|