Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5840)

Unified Diff: chrome/installer/util/shell_util.cc

Issue 14287008: Refactoring installer shortcut deletion; adding dedicated shortcut update feature. (Closed) Base URL: http://chromium.googlesource.com/chromium/src.git@master
Patch Set: Adding tests for cookie migration code; using SHORTCUT_REPLACE_EXISTING now. Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/installer/util/shell_util.cc
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index 4a60171174d5526e3b21bab49799e9406b19f4c5..a00d96b09ea07a6da10b21ca2ec2048562910c05 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -15,6 +15,7 @@
#include <limits>
#include <string>
+#include "base/bind.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
@@ -1159,33 +1160,133 @@ ShellUtil::DefaultState ProbeProtocolHandlers(
return ProbeOpenCommandHandlers(protocols, num_protocols);
}
-// Removes shortcut at |shortcut_path| if it is a shortcut that points to
-// |target_exe|. If |delete_folder| is true, deletes the parent folder of
-// the shortcut completely. Returns true if either the shortcut was deleted
-// successfully or if the shortcut did not point to |target_exe|.
-bool MaybeRemoveShortcutAtPath(const base::FilePath& shortcut_path,
- const base::FilePath& target_exe,
- bool delete_folder) {
- base::FilePath target_path;
- if (!base::win::ResolveShortcut(shortcut_path, &target_path, NULL))
+// (Windows 8+) Returns the folder for app shortcuts, or empty if none found.
+base::FilePath GetAppShortcutsFolder(BrowserDistribution* dist,
gab 2013/04/29 19:06:36 I feel it would be better to have GetAppShortcutsF
huangs 2013/04/30 03:04:16 Done.
+ bool is_user_level) {
+ if (base::win::GetVersion() < base::win::VERSION_WIN8)
+ return base::FilePath();
+
+ base::FilePath folder;
+ if (!PathService::Get(base::DIR_APP_SHORTCUTS, &folder)) {
+ LOG(ERROR) << "Could not get application shortcuts location.";
+ return base::FilePath();
+ }
+
+ folder = folder.Append(ShellUtil::GetBrowserModelId(dist, is_user_level));
+ if (!file_util::DirectoryExists(folder)) {
+ VLOG(1) << "No start screen shortcuts.";
+ return base::FilePath();
+ }
+
+ return folder;
+}
+
+const wchar_t kAllFiles[] = L"*";
gab 2013/04/29 19:06:36 Rename kAllShortcuts and add the extension (if you
huangs 2013/04/30 03:04:16 Done.
+
+typedef base::Callback<bool(const base::FilePath&)> FileOperationCallback;
+
+// Shortcut operations for BatchShortcutAction().
+
+bool ShortcutOpNone(const base::FilePath& shortcut_path) {
+ return true;
+}
+
+bool ShortcutOpUnpin(const base::FilePath& shortcut_path) {
+ VLOG(1) << "Trying to unpin " << shortcut_path.value();
+ if (!base::win::TaskbarUnpinShortcutLink(shortcut_path.value().c_str())) {
+ VLOG(1) << shortcut_path.value() << " wasn't pinned (or the unpin failed).";
+ // No error, since shortcut might not be pinned.
+ }
+ return true;
+}
+
+bool ShortcutOpDelete(const base::FilePath& shortcut_path) {
+ return file_util::Delete(shortcut_path, false);
+}
+
+bool ShortcutOpUnpinAndDelete(const base::FilePath& shortcut_path) {
+ // Want to try both, without short-circuiting.
+ bool ret1 = ShortcutOpUnpin(shortcut_path);
+ bool ret2 = ShortcutOpDelete(shortcut_path);
+ return ret1 && ret2;
+}
+
+bool ShortcutOpSetTarget(const base::FilePath& target_path,
+ const base::FilePath& shortcut_path) {
+ base::win::ShortcutProperties shortcut_properties;
+ shortcut_properties.set_target(target_path);
+ shortcut_properties.set_working_dir(target_path.DirName());
+ return base::win::CreateOrUpdateShortcutLink(
+ shortcut_path, shortcut_properties, base::win::SHORTCUT_REPLACE_EXISTING);
+}
+
+// Folder operations for BatchShortcutAction().
+
+bool FolderOpNone(const base::FilePath& folder_path) {
+ return true;
+}
+
+bool FolderOpDelete(const base::FilePath& folder_path) {
+ return file_util::Delete(folder_path, true);
+}
+
+// {|location|, |dist|, |level|} determine |shortcut_folder| to operate in.
+// In |shortcut_folder|, iterate over shortcuts that have names matching
+// |name_filter|, and have |target_exe| as the target.
gab 2013/04/29 19:06:36 Remove comma (it is only an enumeration of 2 thing
huangs 2013/04/30 03:04:16 Rephrased.
+// Applies |opShortcut| on each matching shortcuts, then at the end, applies
+// |opFolder| on |shortcut_folder|.
gab 2013/04/29 19:06:36 What about: // Applies |shortcut_operation| on ea
huangs 2013/04/30 03:04:16 Done.
+// If |name_filter| is empty, then ignores |opShortcut|; otherwise iterate
+// with implicitly ".lnk" suffix. |kAllFiles| is used to specify all shortcuts.
+// Returns true iff all operations are successful.
+bool BatchShortcutAction(const FileOperationCallback& opShortcut,
gab 2013/04/29 19:06:36 Use underscore casing for variable names, not Came
huangs 2013/04/30 03:04:16 Done (language mix-up :).
+ const FileOperationCallback& opFolder,
+ ShellUtil::ShortcutLocation location,
+ BrowserDistribution* dist,
+ ShellUtil::ShellChange level,
+ const base::FilePath& target_exe,
+ const string16& name_filter) {
+ base::FilePath shortcut_folder;
+ if (!ShellUtil::GetShortcutPath(location, dist, level, &shortcut_folder) ||
+ !file_util::PathExists(shortcut_folder)) {
+ LOG(ERROR) << "Cannot find path at location " << location;
gab 2013/04/29 19:06:36 This is more an WARNING, then an ERROR imo.
huangs 2013/04/30 03:04:16 Done.
return false;
+ }
- if (InstallUtil::ProgramCompare(target_exe).EvaluatePath(target_path)) {
- // Unpin the shortcut if it was ever pinned by the user or the installer.
- VLOG(1) << "Trying to unpin " << shortcut_path.value();
- if (!base::win::TaskbarUnpinShortcutLink(shortcut_path.value().c_str())) {
- VLOG(1) << shortcut_path.value()
- << " wasn't pinned (or the unpin failed).";
+ // Operate on specified shortcuts in the folder.
+ InstallUtil::ProgramCompare target_compare(target_exe);
+ bool success = true;
+ if (!name_filter.empty()) {
+ // Ensure ".lnk" extension.
+ string16 pattern = name_filter + installer::kLnkExt;
+ if (!EndsWith(pattern, installer::kLnkExt, false))
gab 2013/04/29 19:06:36 You just added installer::kLnkExt above so it will
huangs 2013/04/30 03:04:16 Ah, good catch! Done.
+ pattern.append(installer::kLnkExt);
+ file_util::FileEnumerator enumerator(shortcut_folder, false,
+ file_util::FileEnumerator::FILES, pattern);
gab 2013/04/29 19:06:36 either indent parameters at the paranthesis or 4 s
huangs 2013/04/30 03:04:16 Done.
+ for (base::FilePath shortcut_path = enumerator.Next();
+ !shortcut_path.empty();
+ shortcut_path = enumerator.Next()) {
+ base::FilePath target_path;
+ if (base::win::ResolveShortcut(shortcut_path, &target_path, NULL)) {
+ if (target_compare.EvaluatePath(target_path)) {
+ if (!opShortcut.Run(shortcut_path)) {
gab 2013/04/29 19:06:36 Merge this if with the previous one via "&&" (sinc
huangs 2013/04/30 03:04:16 Done.
+ LOG(ERROR) << "Failed shortcut operation on "
+ << shortcut_path.value();
+ success = false;
+ }
+ }
+ } else {
+ LOG(ERROR) << "Cannot resolve shortcut at " << shortcut_path.value();
+ success = false;
+ }
}
- if (delete_folder)
- return file_util::Delete(shortcut_path.DirName(), true);
- else
- return file_util::Delete(shortcut_path, false);
}
- // The shortcut at |shortcut_path| doesn't point to |target_exe|, act as if
- // our shortcut had been deleted.
- return true;
+ // Operate on shortcut folder itself.
+ if (!opFolder.Run(shortcut_folder)) {
+ LOG(ERROR) << "Failed folder operation on " << shortcut_folder.value();
+ success = false;
+ }
+ return success;
}
} // namespace
@@ -1270,6 +1371,15 @@ bool ShellUtil::GetShortcutPath(ShellUtil::ShortcutLocation location,
base::DIR_COMMON_START_MENU;
add_folder_for_dist = true;
break;
+ case SHORTCUT_LOCATION_TASKBAR_PINS:
gab 2013/04/29 19:06:36 I feel this should fail if (base::win::GetVersion(
huangs 2013/04/30 03:04:16 You mean, fail if (base::win::GetVersion() < base:
+ dir_key = base::DIR_TASKBAR_PINS;
+ break;
+ case SHORTCUT_LOCATION_APP_SHORTCUTS: {
+ base::FilePath ret(GetAppShortcutsFolder(dist, level == CURRENT_USER));
+ if (!ret.empty())
+ *path = ret;
+ return !ret.empty();
+ }
default:
NOTREACHED();
return false;
@@ -1299,8 +1409,7 @@ bool ShellUtil::CreateOrUpdateShortcut(
base::FilePath user_shortcut_path;
base::FilePath system_shortcut_path;
- if (!GetShortcutPath(location, dist, SYSTEM_LEVEL, &system_shortcut_path) ||
- system_shortcut_path.empty()) {
gab 2013/04/29 19:06:36 GetShortcutPath() is already designed to only retu
huangs 2013/04/30 03:04:16 This IS the original code; my CL already removes t
+ if (!GetShortcutPath(location, dist, SYSTEM_LEVEL, &system_shortcut_path)) {
NOTREACHED();
return false;
}
@@ -1318,8 +1427,7 @@ bool ShellUtil::CreateOrUpdateShortcut(
// Otherwise install the user-level shortcut, unless the system-level
// variant of this shortcut is present on the machine and |operation| states
// not to create a user-level shortcut in that case.
- if (!GetShortcutPath(location, dist, CURRENT_USER, &user_shortcut_path) ||
- user_shortcut_path.empty()) {
+ if (!GetShortcutPath(location, dist, CURRENT_USER, &user_shortcut_path)) {
NOTREACHED();
return false;
}
@@ -1858,104 +1966,102 @@ bool ShellUtil::RegisterChromeForProtocol(BrowserDistribution* dist,
}
}
+// static
+bool ShellUtil::RemoveShortcutWithName(ShellUtil::ShortcutLocation location,
+ BrowserDistribution* dist,
+ ShellChange level,
+ const base::FilePath& target_path,
+ const string16& name_filter) {
+ bool delete_folder = (location == SHORTCUT_LOCATION_START_MENU);
+ return BatchShortcutAction(
+ base::Bind(&ShortcutOpUnpinAndDelete),
+ base::Bind(delete_folder ? &FolderOpDelete : &FolderOpNone),
+ location, dist, level, target_path, name_filter);
+}
+
+// static
bool ShellUtil::RemoveShortcut(ShellUtil::ShortcutLocation location,
gab 2013/04/29 19:06:36 Consider renaming to RemoveShortcutsAtLocation now
huangs 2013/04/30 03:04:16 Moot; removed routine.
BrowserDistribution* dist,
- const base::FilePath& target_exe,
ShellChange level,
- const string16* shortcut_name) {
- const bool delete_folder = (location == SHORTCUT_LOCATION_START_MENU);
-
- base::FilePath shortcut_folder;
- if (!GetShortcutPath(location, dist, level, &shortcut_folder) ||
- shortcut_folder.empty()) {
- NOTREACHED();
- return false;
- }
-
- if (!delete_folder && !shortcut_name) {
- file_util::FileEnumerator enumerator(shortcut_folder, false,
- file_util::FileEnumerator::FILES);
- bool had_failures = false;
- for (base::FilePath path = enumerator.Next(); !path.empty();
- path = enumerator.Next()) {
- if (path.Extension() != installer::kLnkExt)
- continue;
-
- if (!MaybeRemoveShortcutAtPath(path, target_exe, delete_folder))
- had_failures = true;
- }
- return !had_failures;
- }
-
- const string16 shortcut_base_name(
- (shortcut_name ? *shortcut_name : dist->GetAppShortCutName()) +
- installer::kLnkExt);
- const base::FilePath shortcut_path(
- shortcut_folder.Append(shortcut_base_name));
- if (!file_util::PathExists(shortcut_path))
- return true;
-
- return MaybeRemoveShortcutAtPath(shortcut_path, target_exe, delete_folder);
+ const base::FilePath& target_path) {
+ return ShellUtil::RemoveShortcutWithName(
+ location, dist, level, target_path, kAllFiles);
}
+// static
void ShellUtil::RemoveTaskbarShortcuts(const string16& target_exe) {
gab 2013/04/29 19:06:36 This call and RemoveStartScreenShortcuts() below d
huangs 2013/04/30 03:04:16 Changed routine and the caller. To maintain behavi
if (base::win::GetVersion() < base::win::VERSION_WIN7)
return;
- base::FilePath taskbar_pins_path;
- if (!PathService::Get(base::DIR_TASKBAR_PINS, &taskbar_pins_path) ||
- !file_util::PathExists(taskbar_pins_path)) {
- LOG(ERROR) << "Couldn't find path to taskbar pins.";
- return;
- }
-
- file_util::FileEnumerator shortcuts_enum(
- taskbar_pins_path, false,
- file_util::FileEnumerator::FILES, FILE_PATH_LITERAL("*.lnk"));
-
- base::FilePath target_path(target_exe);
- InstallUtil::ProgramCompare target_compare(target_path);
- for (base::FilePath shortcut_path = shortcuts_enum.Next();
- !shortcut_path.empty();
- shortcut_path = shortcuts_enum.Next()) {
- base::FilePath read_target;
- if (!base::win::ResolveShortcut(shortcut_path, &read_target, NULL)) {
- LOG(ERROR) << "Couldn't resolve shortcut at " << shortcut_path.value();
- continue;
- }
- if (target_compare.EvaluatePath(read_target)) {
- // Unpin this shortcut if it points to |target_exe|.
- base::win::TaskbarUnpinShortcutLink(shortcut_path.value().c_str());
- }
- }
+ ShortcutLocation location = SHORTCUT_LOCATION_TASKBAR_PINS;
+ ShellChange level = ShellUtil::CURRENT_USER;
+ BatchShortcutAction(base::Bind(&ShortcutOpUnpin), base::Bind(&FolderOpNone),
+ location, NULL, level, base::FilePath(target_exe),
+ kAllFiles);
}
+// static
void ShellUtil::RemoveStartScreenShortcuts(BrowserDistribution* dist,
const string16& target_exe) {
if (base::win::GetVersion() < base::win::VERSION_WIN8)
return;
- base::FilePath app_shortcuts_path;
- if (!PathService::Get(base::DIR_APP_SHORTCUTS, &app_shortcuts_path)) {
- LOG(ERROR) << "Could not get application shortcuts location to delete"
- << " start screen shortcuts.";
- return;
+ ShortcutLocation location = SHORTCUT_LOCATION_APP_SHORTCUTS;
+ ShellChange level = InstallUtil::IsPerUserInstall(target_exe.c_str()) ?
+ ShellUtil::CURRENT_USER : ShellUtil::SYSTEM_LEVEL;
+ VLOG(1) << "Removing start screen shortcuts.";
+ if (!BatchShortcutAction(base::Bind(&ShortcutOpNone),
gab 2013/04/29 19:06:36 This will still unnecessarily iterate over all sho
huangs 2013/04/30 03:04:16 This won't do useless cycles because |name_filter|
+ base::Bind(&FolderOpDelete),
+ location, dist, level, base::FilePath(target_exe),
+ L"")) {
+ LOG(ERROR) << "Failed to remove start screen shortcuts.";
}
+}
+
+// static
+bool ShellUtil::MigrateShortcut(ShellUtil::ShortcutLocation location,
+ BrowserDistribution* dist,
+ ShellChange level,
+ const base::FilePath& old_target_path,
+ const base::FilePath& new_target_path) {
gab 2013/04/29 19:06:36 A per above comment, change _path to _exe when ref
huangs 2013/04/30 03:04:16 Done.
+ return BatchShortcutAction(base::Bind(&ShortcutOpSetTarget, new_target_path),
+ base::Bind(&FolderOpNone),
+ location, dist, level, old_target_path, kAllFiles);
+}
- app_shortcuts_path = app_shortcuts_path.Append(
- GetBrowserModelId(dist,
- InstallUtil::IsPerUserInstall(target_exe.c_str())));
- if (!file_util::DirectoryExists(app_shortcuts_path)) {
- VLOG(1) << "No start screen shortcuts to delete.";
+// static
+void ShellUtil::MigrateTaskbarShortcuts(const string16& old_target_exe,
+ const string16& new_target_exe) {
+ if (base::win::GetVersion() < base::win::VERSION_WIN7)
return;
- }
- VLOG(1) << "Removing start screen shortcuts from "
- << app_shortcuts_path.value();
- if (!file_util::Delete(app_shortcuts_path, true)) {
- LOG(ERROR) << "Failed to remove start screen shortcuts from "
- << app_shortcuts_path.value();
+ base::FilePath new_target_path(new_target_exe);
+ ShortcutLocation location = SHORTCUT_LOCATION_TASKBAR_PINS;
+ ShellChange level = ShellUtil::CURRENT_USER;
+ BatchShortcutAction(base::Bind(&ShortcutOpSetTarget, new_target_path),
+ base::Bind(&FolderOpNone),
+ location, NULL, level, base::FilePath(old_target_exe),
+ kAllFiles);
+}
+
+// static
+void ShellUtil::MigrateStartScreenShortcuts(BrowserDistribution* dist,
+ const string16& old_target_exe,
+ const string16& new_target_exe) {
+ if (base::win::GetVersion() < base::win::VERSION_WIN8)
+ return;
+
+ base::FilePath new_target_path(new_target_exe);
+ ShortcutLocation location = SHORTCUT_LOCATION_APP_SHORTCUTS;
+ ShellChange level = InstallUtil::IsPerUserInstall(old_target_exe.c_str()) ?
+ ShellUtil::CURRENT_USER : ShellUtil::SYSTEM_LEVEL;
+ VLOG(1) << "Migrating start screen shortcuts.";
+ if (!BatchShortcutAction(base::Bind(&ShortcutOpSetTarget, new_target_path),
+ base::Bind(&FolderOpNone), location, dist, level,
+ base::FilePath(old_target_exe), kAllFiles)) {
+ LOG(ERROR) << "Failed to migrate start screen shortcuts.";
}
+
}
bool ShellUtil::GetUserSpecificRegistrySuffix(string16* suffix) {

Powered by Google App Engine
This is Rietveld 408576698