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

Side by Side Diff: chrome/browser/profiles/profile_shortcut_manager_win.cc

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

Powered by Google App Engine
This is Rietveld 408576698