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 #include "chrome/browser/profiles/profile_shortcut_manager_win.h" | 5 #include "chrome/browser/profiles/profile_shortcut_manager_win.h" |
6 | 6 |
7 #include <shlobj.h> // For SHChangeNotify(). | 7 #include <shlobj.h> // For SHChangeNotify(). |
8 | 8 |
9 #include <algorithm> | |
10 #include <set> | |
11 #include <string> | 9 #include <string> |
12 #include <vector> | 10 #include <vector> |
13 | 11 |
14 #include "base/bind.h" | 12 #include "base/bind.h" |
15 #include "base/command_line.h" | 13 #include "base/command_line.h" |
16 #include "base/files/file_enumerator.h" | 14 #include "base/files/file_enumerator.h" |
17 #include "base/files/file_util.h" | 15 #include "base/files/file_util.h" |
18 #include "base/path_service.h" | 16 #include "base/path_service.h" |
19 #include "base/prefs/pref_service.h" | 17 #include "base/prefs/pref_service.h" |
20 #include "base/strings/string16.h" | 18 #include "base/strings/string16.h" |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
284 return false; | 282 return false; |
285 | 283 |
286 base::FilePath target_path; | 284 base::FilePath target_path; |
287 if (!base::win::ResolveShortcut(path, &target_path, command_line)) | 285 if (!base::win::ResolveShortcut(path, &target_path, command_line)) |
288 return false; | 286 return false; |
289 // One of the paths may be in short (elided) form. Compare long paths to | 287 // One of the paths may be in short (elided) form. Compare long paths to |
290 // ensure these are still properly matched. | 288 // ensure these are still properly matched. |
291 return ConvertToLongPath(target_path) == ConvertToLongPath(chrome_exe); | 289 return ConvertToLongPath(target_path) == ConvertToLongPath(chrome_exe); |
292 } | 290 } |
293 | 291 |
294 // A functor checks if |path| is the Chrome desktop shortcut (|chrome_exe|) | 292 // Populates |paths| with the file paths of Chrome desktop shortcuts that have |
295 // that have the specified |command_line|. If |include_empty_command_lines| is | 293 // the specified |command_line|. If |include_empty_command_lines| is true, |
296 // true Chrome desktop shortcuts with empty command lines will also be included. | 294 // Chrome desktop shortcuts with empty command lines will also be included. |
297 struct ChromeCommandLineFilter { | 295 void ListDesktopShortcutsWithCommandLine(const base::FilePath& chrome_exe, |
298 const base::FilePath& chrome_exe; | 296 const base::string16& command_line, |
299 const base::string16& command_line; | 297 bool include_empty_command_lines, |
300 bool include_empty_command_lines; | 298 std::vector<base::FilePath>* paths) { |
| 299 base::FilePath user_shortcuts_directory; |
| 300 if (!GetDesktopShortcutsDirectories(&user_shortcuts_directory, NULL)) |
| 301 return; |
301 | 302 |
302 ChromeCommandLineFilter(const base::FilePath& chrome_exe, | 303 base::FileEnumerator enumerator(user_shortcuts_directory, false, |
303 const base::string16& command_line, | 304 base::FileEnumerator::FILES); |
304 bool include_empty_command_lines) | 305 for (base::FilePath path = enumerator.Next(); !path.empty(); |
305 : chrome_exe(chrome_exe), | 306 path = enumerator.Next()) { |
306 command_line(command_line), | |
307 include_empty_command_lines(include_empty_command_lines) {} | |
308 | |
309 bool operator()(const base::FilePath& path) const { | |
310 base::string16 shortcut_command_line; | 307 base::string16 shortcut_command_line; |
311 if (!IsChromeShortcut(path, chrome_exe, &shortcut_command_line)) | 308 if (!IsChromeShortcut(path, chrome_exe, &shortcut_command_line)) |
312 return false; | 309 continue; |
313 | 310 |
314 // TODO(asvitkine): Change this to build a CommandLine object and ensure all | 311 // TODO(asvitkine): Change this to build a CommandLine object and ensure all |
315 // args from |command_line| are present in the shortcut's CommandLine. This | 312 // args from |command_line| are present in the shortcut's CommandLine. This |
316 // will be more robust when |command_line| contains multiple args. | 313 // will be more robust when |command_line| contains multiple args. |
317 if ((shortcut_command_line.empty() && include_empty_command_lines) || | 314 if ((shortcut_command_line.empty() && include_empty_command_lines) || |
318 (shortcut_command_line.find(command_line) != base::string16::npos)) { | 315 (shortcut_command_line.find(command_line) != base::string16::npos)) { |
319 return true; | 316 paths->push_back(path); |
320 } | 317 } |
321 return false; | |
322 } | 318 } |
323 }; | |
324 | |
325 // Get the file paths of desktop files and folders optionally filtered | |
326 // by |filter|. | |
327 std::set<base::FilePath> ListUserDesktopContents( | |
328 const ChromeCommandLineFilter* filter) { | |
329 std::set<base::FilePath> result; | |
330 | |
331 base::FilePath user_shortcuts_directory; | |
332 if (!GetDesktopShortcutsDirectories(&user_shortcuts_directory, nullptr)) | |
333 return result; | |
334 | |
335 base::FileEnumerator enumerator( | |
336 user_shortcuts_directory, false, | |
337 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); | |
338 for (base::FilePath path = enumerator.Next(); !path.empty(); | |
339 path = enumerator.Next()) { | |
340 if (!filter || (*filter)(path)) | |
341 result.insert(path); | |
342 } | |
343 return result; | |
344 } | 319 } |
345 | 320 |
346 // Renames the given desktop shortcut and informs the shell of this change. | 321 // Renames the given desktop shortcut and informs the shell of this change. |
347 bool RenameDesktopShortcut(const base::FilePath& old_shortcut_path, | 322 bool RenameDesktopShortcut(const base::FilePath& old_shortcut_path, |
348 const base::FilePath& new_shortcut_path) { | 323 const base::FilePath& new_shortcut_path) { |
349 if (!base::Move(old_shortcut_path, new_shortcut_path)) | 324 if (!base::Move(old_shortcut_path, new_shortcut_path)) |
350 return false; | 325 return false; |
351 | 326 |
352 // Notify the shell of the rename, which allows the icon to keep its position | 327 // Notify the shell of the rename, which allows the icon to keep its position |
353 // on the desktop when renamed. Note: This only works if either SHCNF_FLUSH or | 328 // on the desktop when renamed. Note: This only works if either SHCNF_FLUSH or |
354 // SHCNF_FLUSHNOWAIT is specified as a flag. | 329 // SHCNF_FLUSHNOWAIT is specified as a flag. |
355 SHChangeNotify(SHCNE_RENAMEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, | 330 SHChangeNotify(SHCNE_RENAMEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, |
356 old_shortcut_path.value().c_str(), | 331 old_shortcut_path.value().c_str(), |
357 new_shortcut_path.value().c_str()); | 332 new_shortcut_path.value().c_str()); |
358 return true; | 333 return true; |
359 } | 334 } |
360 | 335 |
361 // Renames an existing Chrome desktop profile shortcut. Must be called on the | 336 // Renames an existing Chrome desktop profile shortcut. Must be called on the |
362 // FILE thread. | 337 // FILE thread. |
363 // |profile_shortcuts| are Chrome desktop shortcuts for the profile (there can | |
364 // be several). | |
365 // |desktop_contents| is the collection of all user desktop shortcuts | |
366 // (not only Chrome). It is used to make an unique shortcut for the | |
367 // |new_profile_name| among all shortcuts. | |
368 // This function updates |profile_shortcuts| and |desktop_contents| respectively | |
369 // when renaming occurs. | |
370 void RenameChromeDesktopShortcutForProfile( | 338 void RenameChromeDesktopShortcutForProfile( |
371 const base::string16& old_profile_name, | 339 const base::string16& old_shortcut_filename, |
372 const base::string16& new_profile_name, | 340 const base::string16& new_shortcut_filename) { |
373 std::set<base::FilePath>* profile_shortcuts, | |
374 std::set<base::FilePath>* desktop_contents) { | |
375 DCHECK(profile_shortcuts); | |
376 DCHECK(desktop_contents); | |
377 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 341 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
378 | 342 |
379 base::FilePath user_shortcuts_directory; | 343 base::FilePath user_shortcuts_directory; |
380 base::FilePath system_shortcuts_directory; | 344 base::FilePath system_shortcuts_directory; |
381 if (!GetDesktopShortcutsDirectories(&user_shortcuts_directory, | 345 if (!GetDesktopShortcutsDirectories(&user_shortcuts_directory, |
382 &system_shortcuts_directory)) { | 346 &system_shortcuts_directory)) { |
383 return; | 347 return; |
384 } | 348 } |
385 | 349 |
386 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 350 const base::FilePath old_shortcut_path = |
387 | 351 user_shortcuts_directory.Append(old_shortcut_filename); |
388 // Get a new unique shortcut name. | |
389 const base::string16 new_shortcut_filename = | |
390 profiles::internal::GetUniqueShortcutFilenameForProfile( | |
391 new_profile_name, *desktop_contents, distribution); | |
392 const base::FilePath new_shortcut_path = | 352 const base::FilePath new_shortcut_path = |
393 user_shortcuts_directory.Append(new_shortcut_filename); | 353 user_shortcuts_directory.Append(new_shortcut_filename); |
394 | 354 |
395 if (!profile_shortcuts->empty()) { | 355 if (base::PathExists(old_shortcut_path)) { |
396 // From all profile_shortcuts choose the one with a known (canonical) name. | |
397 profiles::internal::ShortcutFilenameMatcher matcher(old_profile_name, | |
398 distribution); | |
399 auto it = std::find_if(profile_shortcuts->begin(), profile_shortcuts->end(), | |
400 [&matcher](const base::FilePath& p) { | |
401 return matcher.IsCanonical(p.BaseName().value()); | |
402 }); | |
403 // If all profile_shortcuts were renamed by user, respect it and do not | |
404 // rename. | |
405 if (it == profile_shortcuts->end()) | |
406 return; | |
407 const base::FilePath old_shortcut_path = *it; | |
408 | |
409 // Rename the old shortcut unless a system-level shortcut exists at the | 356 // Rename the old shortcut unless a system-level shortcut exists at the |
410 // destination, in which case the old shortcut is simply deleted. | 357 // destination, in which case the old shortcut is simply deleted. |
411 const base::FilePath possible_new_system_shortcut = | 358 const base::FilePath possible_new_system_shortcut = |
412 system_shortcuts_directory.Append(new_shortcut_filename); | 359 system_shortcuts_directory.Append(new_shortcut_filename); |
413 if (base::PathExists(possible_new_system_shortcut)) { | 360 if (base::PathExists(possible_new_system_shortcut)) |
414 if (base::DeleteFile(old_shortcut_path, false)) { | 361 base::DeleteFile(old_shortcut_path, false); |
415 profile_shortcuts->erase(old_shortcut_path); | 362 else if (!RenameDesktopShortcut(old_shortcut_path, new_shortcut_path)) |
416 desktop_contents->erase(old_shortcut_path); | 363 DLOG(ERROR) << "Could not rename Windows profile desktop shortcut."; |
417 } else { | |
418 DLOG(ERROR) << "Could not delete Windows profile desktop shortcut."; | |
419 } | |
420 } else { | |
421 if (RenameDesktopShortcut(old_shortcut_path, new_shortcut_path)) { | |
422 profile_shortcuts->erase(old_shortcut_path); | |
423 desktop_contents->erase(old_shortcut_path); | |
424 profile_shortcuts->insert(new_shortcut_path); | |
425 desktop_contents->insert(new_shortcut_path); | |
426 } else { | |
427 DLOG(ERROR) << "Could not rename Windows profile desktop shortcut."; | |
428 } | |
429 } | |
430 } else { | 364 } else { |
431 // If the shortcut does not exist, it may have been deleted by the user. | 365 // If the shortcut does not exist, it may have been renamed by the user. In |
| 366 // that case, its name should not be changed. |
432 // It's also possible that a system-level shortcut exists instead - this | 367 // It's also possible that a system-level shortcut exists instead - this |
433 // should only be the case for the original Chrome shortcut from an | 368 // should only be the case for the original Chrome shortcut from an |
434 // installation. If that's the case, copy that one over - it will get its | 369 // installation. If that's the case, copy that one over - it will get its |
435 // properties updated by | 370 // properties updated by |
436 // |CreateOrUpdateDesktopShortcutsAndIconForProfile()|. | 371 // |CreateOrUpdateDesktopShortcutsAndIconForProfile()|. |
437 const auto old_shortcut_filename = | |
438 profiles::internal::GetShortcutFilenameForProfile(old_profile_name, | |
439 distribution); | |
440 const base::FilePath possible_old_system_shortcut = | 372 const base::FilePath possible_old_system_shortcut = |
441 system_shortcuts_directory.Append(old_shortcut_filename); | 373 system_shortcuts_directory.Append(old_shortcut_filename); |
442 if (base::PathExists(possible_old_system_shortcut)) { | 374 if (base::PathExists(possible_old_system_shortcut)) |
443 if (base::CopyFile(possible_old_system_shortcut, new_shortcut_path)) { | 375 base::CopyFile(possible_old_system_shortcut, new_shortcut_path); |
444 profile_shortcuts->insert(new_shortcut_path); | |
445 desktop_contents->insert(new_shortcut_path); | |
446 } else { | |
447 DLOG(ERROR) << "Could not copy Windows profile desktop shortcut."; | |
448 } | |
449 } | |
450 } | 376 } |
451 } | 377 } |
452 | 378 |
453 struct CreateOrUpdateShortcutsParams { | 379 struct CreateOrUpdateShortcutsParams { |
454 CreateOrUpdateShortcutsParams( | 380 CreateOrUpdateShortcutsParams( |
455 base::FilePath profile_path, | 381 base::FilePath profile_path, |
456 ProfileShortcutManagerWin::CreateOrUpdateMode create_mode, | 382 ProfileShortcutManagerWin::CreateOrUpdateMode create_mode, |
457 ProfileShortcutManagerWin::NonProfileShortcutAction action) | 383 ProfileShortcutManagerWin::NonProfileShortcutAction action) |
458 : create_mode(create_mode), action(action), profile_path(profile_path) {} | 384 : create_mode(create_mode), action(action), profile_path(profile_path) {} |
459 ~CreateOrUpdateShortcutsParams() {} | 385 ~CreateOrUpdateShortcutsParams() {} |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
495 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 421 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { |
496 NOTREACHED(); | 422 NOTREACHED(); |
497 return; | 423 return; |
498 } | 424 } |
499 | 425 |
500 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 426 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); |
501 // Ensure that the distribution supports creating shortcuts. If it doesn't, | 427 // Ensure that the distribution supports creating shortcuts. If it doesn't, |
502 // the following code may result in NOTREACHED() being hit. | 428 // the following code may result in NOTREACHED() being hit. |
503 DCHECK(distribution->CanCreateDesktopShortcuts()); | 429 DCHECK(distribution->CanCreateDesktopShortcuts()); |
504 | 430 |
505 std::set<base::FilePath> desktop_contents = ListUserDesktopContents(nullptr); | |
506 | |
507 const base::string16 command_line = | |
508 profiles::internal::CreateProfileShortcutFlags(params.profile_path); | |
509 ChromeCommandLineFilter filter( | |
510 chrome_exe, command_line, | |
511 params.action == ProfileShortcutManagerWin::UPDATE_NON_PROFILE_SHORTCUTS); | |
512 | |
513 std::set<base::FilePath> shortcuts; | |
514 // Do not call ListUserDesktopContents again (but with filter) to avoid | |
515 // excess work inside it. Just reuse non-filtered desktop_contents. | |
516 // We need both of them (desktop_contents and shortcuts) later. | |
517 std::copy_if(desktop_contents.begin(), desktop_contents.end(), | |
518 std::inserter(shortcuts, shortcuts.begin()), filter); | |
519 | |
520 if (params.old_profile_name != params.profile_name) { | 431 if (params.old_profile_name != params.profile_name) { |
521 RenameChromeDesktopShortcutForProfile(params.old_profile_name, | 432 const base::string16 old_shortcut_filename = |
522 params.profile_name, &shortcuts, | 433 profiles::internal::GetShortcutFilenameForProfile( |
523 &desktop_contents); | 434 params.old_profile_name, |
| 435 distribution); |
| 436 const base::string16 new_shortcut_filename = |
| 437 profiles::internal::GetShortcutFilenameForProfile(params.profile_name, |
| 438 distribution); |
| 439 RenameChromeDesktopShortcutForProfile(old_shortcut_filename, |
| 440 new_shortcut_filename); |
524 } | 441 } |
525 | 442 |
526 ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER); | 443 ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER); |
527 installer::Product product(distribution); | 444 installer::Product product(distribution); |
528 product.AddDefaultShortcutProperties(chrome_exe, &properties); | 445 product.AddDefaultShortcutProperties(chrome_exe, &properties); |
529 | 446 |
| 447 const base::string16 command_line = |
| 448 profiles::internal::CreateProfileShortcutFlags(params.profile_path); |
530 | 449 |
531 // Only set the profile-specific properties when |profile_name| is non empty. | 450 // Only set the profile-specific properties when |profile_name| is non empty. |
532 // If it is empty, it means the shortcut being created should be a regular, | 451 // If it is empty, it means the shortcut being created should be a regular, |
533 // non-profile Chrome shortcut. | 452 // non-profile Chrome shortcut. |
534 if (!params.profile_name.empty()) { | 453 if (!params.profile_name.empty()) { |
535 properties.set_arguments(command_line); | 454 properties.set_arguments(command_line); |
536 properties.set_icon(shortcut_icon, 0); | 455 properties.set_icon(shortcut_icon, 0); |
537 } else { | 456 } else { |
538 // Set the arguments explicitly to the empty string to ensure that | 457 // Set the arguments explicitly to the empty string to ensure that |
539 // |ShellUtil::CreateOrUpdateShortcut| updates that part of the shortcut. | 458 // |ShellUtil::CreateOrUpdateShortcut| updates that part of the shortcut. |
540 properties.set_arguments(base::string16()); | 459 properties.set_arguments(base::string16()); |
541 } | 460 } |
542 | 461 |
543 properties.set_app_id( | 462 properties.set_app_id( |
544 ShellIntegration::GetChromiumModelIdForProfile(params.profile_path)); | 463 ShellIntegration::GetChromiumModelIdForProfile(params.profile_path)); |
545 | 464 |
546 ShellUtil::ShortcutOperation operation = | 465 ShellUtil::ShortcutOperation operation = |
547 ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING; | 466 ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING; |
548 | 467 |
| 468 std::vector<base::FilePath> shortcuts; |
| 469 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, |
| 470 params.action == ProfileShortcutManagerWin::UPDATE_NON_PROFILE_SHORTCUTS, |
| 471 &shortcuts); |
549 if (params.create_mode == ProfileShortcutManagerWin::CREATE_WHEN_NONE_FOUND && | 472 if (params.create_mode == ProfileShortcutManagerWin::CREATE_WHEN_NONE_FOUND && |
550 shortcuts.empty()) { | 473 shortcuts.empty()) { |
551 const base::string16 shortcut_name = | 474 const base::string16 shortcut_name = |
552 profiles::internal::GetUniqueShortcutFilenameForProfile( | 475 profiles::internal::GetShortcutFilenameForProfile(params.profile_name, |
553 params.profile_name, desktop_contents, distribution); | 476 distribution); |
554 shortcuts.insert(base::FilePath(shortcut_name)); | 477 shortcuts.push_back(base::FilePath(shortcut_name)); |
555 operation = ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL; | 478 operation = ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL; |
556 } | 479 } |
557 | 480 |
558 for (const auto& shortcut : shortcuts) { | 481 for (size_t i = 0; i < shortcuts.size(); ++i) { |
559 const base::FilePath shortcut_name = shortcut.BaseName().RemoveExtension(); | 482 const base::FilePath shortcut_name = |
| 483 shortcuts[i].BaseName().RemoveExtension(); |
560 properties.set_shortcut_name(shortcut_name.value()); | 484 properties.set_shortcut_name(shortcut_name.value()); |
561 ShellUtil::CreateOrUpdateShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, | 485 ShellUtil::CreateOrUpdateShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, |
562 distribution, properties, operation); | 486 distribution, properties, operation); |
563 } | 487 } |
564 } | 488 } |
565 | 489 |
566 // Returns true if any desktop shortcuts exist with target |chrome_exe|, | 490 // Returns true if any desktop shortcuts exist with target |chrome_exe|, |
567 // regardless of their command line arguments. | 491 // regardless of their command line arguments. |
568 bool ChromeDesktopShortcutsExist(const base::FilePath& chrome_exe) { | 492 bool ChromeDesktopShortcutsExist(const base::FilePath& chrome_exe) { |
569 base::FilePath user_shortcuts_directory; | 493 base::FilePath user_shortcuts_directory; |
(...skipping 20 matching lines...) Expand all Loading... |
590 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 514 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
591 | 515 |
592 base::FilePath chrome_exe; | 516 base::FilePath chrome_exe; |
593 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 517 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { |
594 NOTREACHED(); | 518 NOTREACHED(); |
595 return; | 519 return; |
596 } | 520 } |
597 | 521 |
598 const base::string16 command_line = | 522 const base::string16 command_line = |
599 profiles::internal::CreateProfileShortcutFlags(profile_path); | 523 profiles::internal::CreateProfileShortcutFlags(profile_path); |
600 ChromeCommandLineFilter filter(chrome_exe, command_line, false); | 524 std::vector<base::FilePath> shortcuts; |
601 const std::set<base::FilePath> shortcuts = ListUserDesktopContents(&filter); | 525 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, false, |
| 526 &shortcuts); |
602 | 527 |
603 for (const auto& shortcut : shortcuts) { | 528 for (size_t i = 0; i < shortcuts.size(); ++i) { |
604 // Use base::DeleteFile() instead of ShellUtil::RemoveShortcuts(), as the | 529 // Use base::DeleteFile() instead of ShellUtil::RemoveShortcuts(), as the |
605 // latter causes non-profile taskbar shortcuts to be removed since it | 530 // latter causes non-profile taskbar shortcuts to be removed since it |
606 // doesn't consider the command-line of the shortcuts it deletes. | 531 // doesn't consider the command-line of the shortcuts it deletes. |
607 // TODO(huangs): Refactor with ShellUtil::RemoveShortcuts(). | 532 // TODO(huangs): Refactor with ShellUtil::RemoveShortcuts(). |
608 base::win::UnpinShortcutFromTaskbar(shortcut); | 533 base::win::UnpinShortcutFromTaskbar(shortcuts[i]); |
609 base::DeleteFile(shortcut, false); | 534 base::DeleteFile(shortcuts[i], false); |
610 // Notify the shell that the shortcut was deleted to ensure desktop refresh. | 535 // Notify the shell that the shortcut was deleted to ensure desktop refresh. |
611 SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, shortcut.value().c_str(), nullptr); | 536 SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, shortcuts[i].value().c_str(), |
| 537 NULL); |
612 } | 538 } |
613 | 539 |
614 // If |ensure_shortcuts_remain| is true and deleting this profile caused the | 540 // If |ensure_shortcuts_remain| is true and deleting this profile caused the |
615 // last shortcuts to be removed, re-create a regular non-profile shortcut. | 541 // last shortcuts to be removed, re-create a regular non-profile shortcut. |
616 const bool had_shortcuts = !shortcuts.empty(); | 542 const bool had_shortcuts = !shortcuts.empty(); |
617 if (ensure_shortcuts_remain && had_shortcuts && | 543 if (ensure_shortcuts_remain && had_shortcuts && |
618 !ChromeDesktopShortcutsExist(chrome_exe)) { | 544 !ChromeDesktopShortcutsExist(chrome_exe)) { |
619 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); | 545 BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); |
620 // Ensure that the distribution supports creating shortcuts. If it doesn't, | 546 // Ensure that the distribution supports creating shortcuts. If it doesn't, |
621 // the following code may result in NOTREACHED() being hit. | 547 // the following code may result in NOTREACHED() being hit. |
(...skipping 17 matching lines...) Expand all Loading... |
639 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 565 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
640 | 566 |
641 base::FilePath chrome_exe; | 567 base::FilePath chrome_exe; |
642 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 568 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { |
643 NOTREACHED(); | 569 NOTREACHED(); |
644 return false; | 570 return false; |
645 } | 571 } |
646 | 572 |
647 const base::string16 command_line = | 573 const base::string16 command_line = |
648 profiles::internal::CreateProfileShortcutFlags(profile_path); | 574 profiles::internal::CreateProfileShortcutFlags(profile_path); |
649 ChromeCommandLineFilter filter(chrome_exe, command_line, false); | 575 std::vector<base::FilePath> shortcuts; |
650 return !ListUserDesktopContents(&filter).empty(); | 576 ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, false, |
| 577 &shortcuts); |
| 578 return !shortcuts.empty(); |
651 } | 579 } |
652 | 580 |
653 // Replaces any reserved characters with spaces, and trims the resulting string | 581 // Replaces any reserved characters with spaces, and trims the resulting string |
654 // to prevent any leading and trailing spaces. Also makes sure that the | 582 // to prevent any leading and trailing spaces. Also makes sure that the |
655 // resulting filename doesn't exceed |kMaxProfileShortcutFileNameLength|. | 583 // resulting filename doesn't exceed |kMaxProfileShortcutFileNameLength|. |
656 // TODO(macourteau): find a way to limit the total path's length to MAX_PATH | 584 // TODO(macourteau): find a way to limit the total path's length to MAX_PATH |
657 // instead of limiting the profile's name to |kMaxProfileShortcutFileNameLength| | 585 // instead of limiting the profile's name to |kMaxProfileShortcutFileNameLength| |
658 // characters. | 586 // characters. |
659 base::string16 SanitizeShortcutProfileNameString( | 587 base::string16 SanitizeShortcutProfileNameString( |
660 const base::string16& profile_name) { | 588 const base::string16& profile_name) { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
708 shortcut_name.append(SanitizeShortcutProfileNameString(profile_name)); | 636 shortcut_name.append(SanitizeShortcutProfileNameString(profile_name)); |
709 shortcut_name.append(L" - "); | 637 shortcut_name.append(L" - "); |
710 shortcut_name.append(l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); | 638 shortcut_name.append(l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); |
711 } else { | 639 } else { |
712 shortcut_name.append( | 640 shortcut_name.append( |
713 distribution->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME)); | 641 distribution->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME)); |
714 } | 642 } |
715 return shortcut_name + installer::kLnkExt; | 643 return shortcut_name + installer::kLnkExt; |
716 } | 644 } |
717 | 645 |
718 base::string16 GetUniqueShortcutFilenameForProfile( | |
719 const base::string16& profile_name, | |
720 const std::set<base::FilePath>& excludes, | |
721 BrowserDistribution* distribution) { | |
722 std::set<base::string16> excludes_names; | |
723 std::transform(excludes.begin(), excludes.end(), | |
724 std::inserter(excludes_names, excludes_names.begin()), | |
725 [](const base::FilePath& e) { return e.BaseName().value(); }); | |
726 | |
727 const auto base_name = | |
728 GetShortcutFilenameForProfile(profile_name, distribution); | |
729 auto name = base_name; | |
730 const base::FilePath base_path(base_name); | |
731 for (int uniquifier = 1; excludes_names.count(name) > 0; ++uniquifier) { | |
732 const auto suffix = base::StringPrintf(" (%d)", uniquifier); | |
733 name = base_path.InsertBeforeExtensionASCII(suffix).value(); | |
734 } | |
735 return name; | |
736 } | |
737 | |
738 // Corresponds to GetUniqueShortcutFilenameForProfile. | |
739 ShortcutFilenameMatcher::ShortcutFilenameMatcher( | |
740 const base::string16& profile_name, | |
741 BrowserDistribution* distribution) | |
742 : profile_shortcut_filename_( | |
743 GetShortcutFilenameForProfile(profile_name, distribution)), | |
744 lnk_ext_(installer::kLnkExt), | |
745 profile_shortcut_name_(profile_shortcut_filename_) { | |
746 DCHECK(profile_shortcut_name_.ends_with(lnk_ext_)); | |
747 profile_shortcut_name_.remove_suffix(lnk_ext_.size()); | |
748 } | |
749 | |
750 bool ShortcutFilenameMatcher::IsCanonical( | |
751 const base::string16& filename) const { | |
752 if (filename == profile_shortcut_filename_) | |
753 return true; | |
754 | |
755 base::StringPiece16 shortcut_suffix(filename); | |
756 if (!shortcut_suffix.starts_with(profile_shortcut_name_)) | |
757 return false; | |
758 shortcut_suffix.remove_prefix(profile_shortcut_name_.size()); | |
759 | |
760 if (!shortcut_suffix.ends_with(lnk_ext_)) | |
761 return false; | |
762 shortcut_suffix.remove_suffix(lnk_ext_.size()); | |
763 | |
764 if (shortcut_suffix.size() < 4 || !shortcut_suffix.starts_with(L" (") || | |
765 !shortcut_suffix.ends_with(L")")) { | |
766 return false; | |
767 } | |
768 return std::all_of(shortcut_suffix.begin() + 2, shortcut_suffix.end() - 1, | |
769 iswdigit); | |
770 } | |
771 | |
772 base::string16 CreateProfileShortcutFlags(const base::FilePath& profile_path) { | 646 base::string16 CreateProfileShortcutFlags(const base::FilePath& profile_path) { |
773 return base::StringPrintf(L"--%ls=\"%ls\"", | 647 return base::StringPrintf(L"--%ls=\"%ls\"", |
774 base::ASCIIToUTF16( | 648 base::ASCIIToUTF16( |
775 switches::kProfileDirectory).c_str(), | 649 switches::kProfileDirectory).c_str(), |
776 profile_path.BaseName().value().c_str()); | 650 profile_path.BaseName().value().c_str()); |
777 } | 651 } |
778 | 652 |
779 } // namespace internal | 653 } // namespace internal |
780 } // namespace profiles | 654 } // namespace profiles |
781 | 655 |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1003 // Ensure the profile's icon file has been created. | 877 // Ensure the profile's icon file has been created. |
1004 CreateOrUpdateProfileIcon(profile->GetPath()); | 878 CreateOrUpdateProfileIcon(profile->GetPath()); |
1005 } | 879 } |
1006 break; | 880 break; |
1007 } | 881 } |
1008 default: | 882 default: |
1009 NOTREACHED(); | 883 NOTREACHED(); |
1010 break; | 884 break; |
1011 } | 885 } |
1012 } | 886 } |
OLD | NEW |