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

Side by Side Diff: chrome/browser/shell_integration_linux.cc

Issue 9958006: Create Linux platform app shortcuts to run in their own process. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Moved new function into shell_integration_linux.h Created 8 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 unified diff | Download patch
« no previous file with comments | « chrome/browser/shell_integration_linux.h ('k') | chrome/browser/shell_integration_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/shell_integration.h" 5 #include "chrome/browser/shell_integration_linux.h"
6 6
7 #include <fcntl.h> 7 #include <fcntl.h>
8 #include <glib.h> 8 #include <glib.h>
9 #include <stdlib.h> 9 #include <stdlib.h>
10 #include <sys/stat.h> 10 #include <sys/stat.h>
11 #include <sys/types.h> 11 #include <sys/types.h>
12 #include <unistd.h> 12 #include <unistd.h>
13 13
14 #include <string> 14 #include <string>
15 #include <vector> 15 #include <vector>
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
106 argv.push_back(base::IntToString(bitmap->width())); 106 argv.push_back(base::IntToString(bitmap->width()));
107 107
108 argv.push_back(temp_file_path.value()); 108 argv.push_back(temp_file_path.value());
109 std::string icon_name = temp_file_path.BaseName().RemoveExtension().value(); 109 std::string icon_name = temp_file_path.BaseName().RemoveExtension().value();
110 argv.push_back(icon_name); 110 argv.push_back(icon_name);
111 int exit_code; 111 int exit_code;
112 LaunchXdgUtility(argv, &exit_code); 112 LaunchXdgUtility(argv, &exit_code);
113 return icon_name; 113 return icon_name;
114 } 114 }
115 115
116 void CreateShortcutOnDesktop(const FilePath& shortcut_filename, 116 bool CreateShortcutOnDesktop(const FilePath& shortcut_filename,
117 const std::string& contents) { 117 const std::string& contents) {
118 // TODO(phajdan.jr): Report errors from this function, possibly as infobars.
119
120 // Make sure that we will later call openat in a secure way. 118 // Make sure that we will later call openat in a secure way.
121 DCHECK_EQ(shortcut_filename.BaseName().value(), shortcut_filename.value()); 119 DCHECK_EQ(shortcut_filename.BaseName().value(), shortcut_filename.value());
122 120
123 FilePath desktop_path; 121 FilePath desktop_path;
124 if (!PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_path)) 122 if (!PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_path))
125 return; 123 return false;
126 124
127 int desktop_fd = open(desktop_path.value().c_str(), O_RDONLY | O_DIRECTORY); 125 int desktop_fd = open(desktop_path.value().c_str(), O_RDONLY | O_DIRECTORY);
128 if (desktop_fd < 0) 126 if (desktop_fd < 0)
129 return; 127 return false;
130 128
131 int fd = openat(desktop_fd, shortcut_filename.value().c_str(), 129 int fd = openat(desktop_fd, shortcut_filename.value().c_str(),
132 O_CREAT | O_EXCL | O_WRONLY, 130 O_CREAT | O_EXCL | O_WRONLY,
133 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 131 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
134 if (fd < 0) { 132 if (fd < 0) {
135 if (HANDLE_EINTR(close(desktop_fd)) < 0) 133 if (HANDLE_EINTR(close(desktop_fd)) < 0)
136 PLOG(ERROR) << "close"; 134 PLOG(ERROR) << "close";
137 return; 135 return false;
138 } 136 }
139 137
140 ssize_t bytes_written = file_util::WriteFileDescriptor(fd, contents.data(), 138 ssize_t bytes_written = file_util::WriteFileDescriptor(fd, contents.data(),
141 contents.length()); 139 contents.length());
142 if (HANDLE_EINTR(close(fd)) < 0) 140 if (HANDLE_EINTR(close(fd)) < 0)
143 PLOG(ERROR) << "close"; 141 PLOG(ERROR) << "close";
144 142
145 if (bytes_written != static_cast<ssize_t>(contents.length())) { 143 if (bytes_written != static_cast<ssize_t>(contents.length())) {
146 // Delete the file. No shortuct is better than corrupted one. Use unlinkat 144 // Delete the file. No shortuct is better than corrupted one. Use unlinkat
147 // to make sure we're deleting the file in the directory we think we are. 145 // to make sure we're deleting the file in the directory we think we are.
148 // Even if an attacker manager to put something other at 146 // Even if an attacker manager to put something other at
149 // |shortcut_filename| we'll just undo his action. 147 // |shortcut_filename| we'll just undo his action.
150 unlinkat(desktop_fd, shortcut_filename.value().c_str(), 0); 148 unlinkat(desktop_fd, shortcut_filename.value().c_str(), 0);
151 } 149 }
152 150
153 if (HANDLE_EINTR(close(desktop_fd)) < 0) 151 if (HANDLE_EINTR(close(desktop_fd)) < 0)
154 PLOG(ERROR) << "close"; 152 PLOG(ERROR) << "close";
153
154 return true;
155 } 155 }
156 156
157 void CreateShortcutInApplicationsMenu(const FilePath& shortcut_filename, 157 bool CreateShortcutInApplicationsMenu(const FilePath& shortcut_filename,
158 const std::string& contents) { 158 const std::string& contents) {
159 // TODO(phajdan.jr): Report errors from this function, possibly as infobars.
160 ScopedTempDir temp_dir; 159 ScopedTempDir temp_dir;
161 if (!temp_dir.CreateUniqueTempDir()) 160 if (!temp_dir.CreateUniqueTempDir())
162 return; 161 return false;
163 162
164 FilePath temp_file_path = temp_dir.path().Append(shortcut_filename); 163 FilePath temp_file_path = temp_dir.path().Append(shortcut_filename);
165 164
166 int bytes_written = file_util::WriteFile(temp_file_path, contents.data(), 165 int bytes_written = file_util::WriteFile(temp_file_path, contents.data(),
167 contents.length()); 166 contents.length());
168 167
169 if (bytes_written != static_cast<int>(contents.length())) 168 if (bytes_written != static_cast<int>(contents.length()))
170 return; 169 return false;
171 170
172 std::vector<std::string> argv; 171 std::vector<std::string> argv;
173 argv.push_back("xdg-desktop-menu"); 172 argv.push_back("xdg-desktop-menu");
174 argv.push_back("install"); 173 argv.push_back("install");
175 174
176 // Always install in user mode, even if someone runs the browser as root 175 // Always install in user mode, even if someone runs the browser as root
177 // (people do that). 176 // (people do that).
178 argv.push_back("--mode"); 177 argv.push_back("--mode");
179 argv.push_back("user"); 178 argv.push_back("user");
180 179
181 argv.push_back(temp_file_path.value()); 180 argv.push_back(temp_file_path.value());
182 int exit_code; 181 int exit_code;
183 LaunchXdgUtility(argv, &exit_code); 182 LaunchXdgUtility(argv, &exit_code);
183 return exit_code == 0;
184 } 184 }
185 185
186 // Quote a string such that it appears as one verbatim argument for the Exec 186 // Quote a string such that it appears as one verbatim argument for the Exec
187 // key in a desktop file. 187 // key in a desktop file.
188 std::string QuoteArgForDesktopFileExec(const std::string& arg) { 188 std::string QuoteArgForDesktopFileExec(const std::string& arg) {
189 // http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s06.html 189 // http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s06.html
190 190
191 // Quoting is only necessary if the argument has a reserved character. 191 // Quoting is only necessary if the argument has a reserved character.
192 if (arg.find_first_of(" \t\n\"'\\><~|&;$*?#()`") == std::string::npos) 192 if (arg.find_first_of(" \t\n\"'\\><~|&;$*?#()`") == std::string::npos)
193 return arg; // No quoting necessary. 193 return arg; // No quoting necessary.
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 470
471 return FilePath(); 471 return FilePath();
472 } 472 }
473 473
474 // static 474 // static
475 std::string ShellIntegration::GetDesktopFileContents( 475 std::string ShellIntegration::GetDesktopFileContents(
476 const std::string& template_contents, 476 const std::string& template_contents,
477 const std::string& app_name, 477 const std::string& app_name,
478 const GURL& url, 478 const GURL& url,
479 const std::string& extension_id, 479 const std::string& extension_id,
480 const bool is_platform_app,
481 const FilePath& web_app_path,
482 const FilePath& extension_path,
480 const string16& title, 483 const string16& title,
481 const std::string& icon_name) { 484 const std::string& icon_name) {
482 if (template_contents.empty()) 485 if (template_contents.empty())
483 return std::string(kXdgOpenShebang) + "\n"; 486 return std::string(kXdgOpenShebang) + "\n";
484 487
485 // See http://standards.freedesktop.org/desktop-entry-spec/latest/ 488 // See http://standards.freedesktop.org/desktop-entry-spec/latest/
486 // http://developer.gnome.org/glib/unstable/glib-Key-value-file-parser.html 489 // http://developer.gnome.org/glib/unstable/glib-Key-value-file-parser.html
487 GKeyFile* key_file = g_key_file_new(); 490 GKeyFile* key_file = g_key_file_new();
488 GError* err = NULL; 491 GError* err = NULL;
489 // Loading the data will strip translations and comments from the desktop 492 // Loading the data will strip translations and comments from the desktop
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 std::string exec_string(exec_c_string); 537 std::string exec_string(exec_c_string);
535 g_free(exec_c_string); 538 g_free(exec_c_string);
536 StringTokenizer exec_tokenizer(exec_string, " "); 539 StringTokenizer exec_tokenizer(exec_string, " ");
537 540
538 std::string final_path; 541 std::string final_path;
539 while (exec_tokenizer.GetNext() && exec_tokenizer.token() != "%U") { 542 while (exec_tokenizer.GetNext() && exec_tokenizer.token() != "%U") {
540 if (!final_path.empty()) 543 if (!final_path.empty())
541 final_path += " "; 544 final_path += " ";
542 final_path += exec_tokenizer.token(); 545 final_path += exec_tokenizer.token();
543 } 546 }
544 CommandLine cmd_line = 547 CommandLine cmd_line(CommandLine::NO_PROGRAM);
545 ShellIntegration::CommandLineArgsForLauncher(url, extension_id); 548 if (is_platform_app) {
549 cmd_line = ShellIntegration::CommandLineArgsForPlatformApp(
550 extension_id, web_app_path, extension_path);
551 } else {
552 cmd_line = ShellIntegration::CommandLineArgsForLauncher(
553 url, extension_id);
554 }
546 const CommandLine::SwitchMap& switch_map = cmd_line.GetSwitches(); 555 const CommandLine::SwitchMap& switch_map = cmd_line.GetSwitches();
547 for (CommandLine::SwitchMap::const_iterator i = switch_map.begin(); 556 for (CommandLine::SwitchMap::const_iterator i = switch_map.begin();
548 i != switch_map.end(); ++i) { 557 i != switch_map.end(); ++i) {
549 if (i->second.empty()) { 558 if (i->second.empty()) {
550 final_path += " --" + i->first; 559 final_path += " --" + i->first;
551 } else { 560 } else {
552 final_path += " " + QuoteArgForDesktopFileExec("--" + i->first + 561 final_path += " " + QuoteArgForDesktopFileExec("--" + i->first +
553 "=" + i->second); 562 "=" + i->second);
554 } 563 }
555 } 564 }
(...skipping 19 matching lines...) Expand all
575 if (data_dump) { 584 if (data_dump) {
576 output_buffer += data_dump; 585 output_buffer += data_dump;
577 g_free(data_dump); 586 g_free(data_dump);
578 } 587 }
579 588
580 g_key_file_free(key_file); 589 g_key_file_free(key_file);
581 return output_buffer; 590 return output_buffer;
582 } 591 }
583 592
584 // static 593 // static
585 void ShellIntegration::CreateDesktopShortcut( 594 bool ShellIntegration::CreateDesktopShortcut(
586 const ShortcutInfo& shortcut_info, const std::string& shortcut_template) { 595 const ShortcutInfo& shortcut_info,
587 // TODO(phajdan.jr): Report errors from this function, possibly as infobars. 596 const std::string& shortcut_template) {
597 DCHECK(!shortcut_info.is_platform_app);
598 DCHECK(shortcut_info.extension_id.empty());
588 599
600 return ShellIntegrationLinux::CreateDesktopShortcutForChromeApp(
601 shortcut_info, FilePath(), shortcut_template);
602 }
603
604 namespace ShellIntegrationLinux {
605
606 bool CreateDesktopShortcutForChromeApp(
607 const ShellIntegration::ShortcutInfo& shortcut_info,
608 const FilePath& web_app_path,
609 const std::string& shortcut_template) {
589 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 610 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
590 611
591 FilePath shortcut_filename = GetDesktopShortcutFilename(shortcut_info.url); 612 FilePath shortcut_filename = ShellIntegration::GetDesktopShortcutFilename(
613 shortcut_info.url);
592 if (shortcut_filename.empty()) 614 if (shortcut_filename.empty())
593 return; 615 return false;
594 616
595 std::string icon_name = CreateShortcutIcon(shortcut_info, shortcut_filename); 617 std::string icon_name = CreateShortcutIcon(shortcut_info, shortcut_filename);
596 618
597 std::string app_name = 619 std::string app_name =
598 web_app::GenerateApplicationNameFromInfo(shortcut_info); 620 web_app::GenerateApplicationNameFromInfo(shortcut_info);
599 std::string contents = GetDesktopFileContents( 621 std::string contents = ShellIntegration::GetDesktopFileContents(
600 shortcut_template, 622 shortcut_template,
601 app_name, 623 app_name,
602 shortcut_info.url, 624 shortcut_info.url,
603 shortcut_info.extension_id, 625 shortcut_info.extension_id,
626 shortcut_info.is_platform_app,
627 web_app_path,
628 shortcut_info.extension_path,
604 shortcut_info.title, 629 shortcut_info.title,
605 icon_name); 630 icon_name);
606 631
632 bool success = true;
633
607 if (shortcut_info.create_on_desktop) 634 if (shortcut_info.create_on_desktop)
608 CreateShortcutOnDesktop(shortcut_filename, contents); 635 success = CreateShortcutOnDesktop(shortcut_filename, contents);
609 636
610 if (shortcut_info.create_in_applications_menu) 637 if (shortcut_info.create_in_applications_menu)
611 CreateShortcutInApplicationsMenu(shortcut_filename, contents); 638 success = CreateShortcutInApplicationsMenu(shortcut_filename, contents) &&
639 success;
640
641 return success;
612 } 642 }
643
644 } // namespace ShellIntegrationLinux
OLDNEW
« no previous file with comments | « chrome/browser/shell_integration_linux.h ('k') | chrome/browser/shell_integration_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698