Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / chromeos / file_manager / open_util.cc
blob9eeb9cc4938db112970e55b9fecb927ef2e67265
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
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/file_manager/open_util.h"
7 #include "base/bind.h"
8 #include "base/files/file_path.h"
9 #include "base/logging.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/chromeos/drive/file_system_util.h"
12 #include "chrome/browser/chromeos/file_manager/app_id.h"
13 #include "chrome/browser/chromeos/file_manager/file_tasks.h"
14 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
15 #include "chrome/browser/chromeos/file_manager/path_util.h"
16 #include "chrome/browser/chromeos/file_manager/url_util.h"
17 #include "chrome/browser/extensions/api/file_handlers/mime_util.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/user_metrics.h"
20 #include "storage/browser/fileapi/file_system_backend.h"
21 #include "storage/browser/fileapi/file_system_context.h"
22 #include "storage/browser/fileapi/file_system_operation_runner.h"
23 #include "storage/browser/fileapi/file_system_url.h"
25 using content::BrowserThread;
26 using storage::FileSystemURL;
28 namespace file_manager {
29 namespace util {
30 namespace {
32 bool shell_operations_allowed = true;
34 // Executes the |task| for the file specified by |url|.
35 void ExecuteFileTaskForUrl(Profile* profile,
36 const file_tasks::TaskDescriptor& task,
37 const GURL& url) {
38 if (!shell_operations_allowed)
39 return;
40 storage::FileSystemContext* file_system_context =
41 GetFileSystemContextForExtensionId(profile, kFileManagerAppId);
43 file_tasks::ExecuteFileTask(
44 profile,
45 GetFileManagerMainPageUrl(), // Executing the task on behalf of Files.app.
46 task,
47 std::vector<FileSystemURL>(1, file_system_context->CrackURL(url)),
48 file_tasks::FileTaskFinishedCallback());
51 // Opens the file manager for the specified |url|. Used to implement
52 // internal handlers of special action IDs:
54 // "open" - Open the file manager for the given folder.
55 // "select" - Open the file manager for the given file. The folder containing
56 // the file will be opened with the file selected.
57 void OpenFileManagerWithInternalActionId(Profile* profile,
58 const GURL& url,
59 const std::string& action_id) {
60 DCHECK(action_id == "open" || action_id == "select");
61 if (!shell_operations_allowed)
62 return;
63 content::RecordAction(base::UserMetricsAction("ShowFileBrowserFullTab"));
65 file_tasks::TaskDescriptor task(kFileManagerAppId,
66 file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER,
67 action_id);
68 ExecuteFileTaskForUrl(profile, task, url);
71 // Opens the file with fetched MIME type and calls the callback.
72 void OpenFileWithMimeType(Profile* profile,
73 const base::FilePath& path,
74 const GURL& url,
75 const platform_util::OpenOperationCallback& callback,
76 const std::string& mime_type) {
77 extensions::app_file_handler_util::PathAndMimeTypeSet path_mime_set;
78 path_mime_set.insert(std::make_pair(path, mime_type));
80 std::vector<GURL> file_urls;
81 file_urls.push_back(url);
83 std::vector<file_tasks::FullTaskDescriptor> tasks;
84 file_tasks::FindAllTypesOfTasks(
85 profile,
86 drive::util::GetDriveAppRegistryByProfile(profile),
87 path_mime_set,
88 file_urls,
89 &tasks);
91 // Select a default handler. If a default handler is not available, select
92 // a non-generic file handler.
93 const file_tasks::FullTaskDescriptor* chosen_task = nullptr;
94 for (const auto& task : tasks) {
95 if (!task.is_generic_file_handler()) {
96 chosen_task = &task;
97 if (task.is_default())
98 break;
102 if (chosen_task != nullptr) {
103 if (shell_operations_allowed)
104 ExecuteFileTaskForUrl(profile, chosen_task->task_descriptor(), url);
105 callback.Run(platform_util::OPEN_SUCCEEDED);
106 } else {
107 callback.Run(platform_util::OPEN_FAILED_NO_HANLDER_FOR_FILE_TYPE);
111 // Opens the file specified by |url| by finding and executing a file task for
112 // the file. Calls |callback| with the result.
113 void OpenFile(Profile* profile,
114 const base::FilePath& path,
115 const GURL& url,
116 const platform_util::OpenOperationCallback& callback) {
117 extensions::app_file_handler_util::GetMimeTypeForLocalPath(
118 profile, path,
119 base::Bind(&OpenFileWithMimeType, profile, path, url, callback));
122 void OpenItemWithMetadata(Profile* profile,
123 const base::FilePath& file_path,
124 const GURL& url,
125 platform_util::OpenItemType expected_type,
126 const platform_util::OpenOperationCallback& callback,
127 base::File::Error error,
128 const base::File::Info& file_info) {
129 DCHECK_CURRENTLY_ON(BrowserThread::UI);
130 if (error != base::File::FILE_OK) {
131 callback.Run(error == base::File::FILE_ERROR_NOT_FOUND
132 ? platform_util::OPEN_FAILED_PATH_NOT_FOUND
133 : platform_util::OPEN_FAILED_FILE_ERROR);
134 return;
137 // Note that there exists a TOCTOU race between the time the metadata for
138 // |file_path| was determined and when it is opened based on the metadata.
139 if (expected_type == platform_util::OPEN_FOLDER && file_info.is_directory) {
140 OpenFileManagerWithInternalActionId(profile, url, "open");
141 callback.Run(platform_util::OPEN_SUCCEEDED);
142 return;
145 if (expected_type == platform_util::OPEN_FILE && !file_info.is_directory) {
146 OpenFile(profile, file_path, url, callback);
147 return;
150 callback.Run(platform_util::OPEN_FAILED_INVALID_TYPE);
153 } // namespace
155 void OpenItem(Profile* profile,
156 const base::FilePath& file_path,
157 platform_util::OpenItemType expected_type,
158 const platform_util::OpenOperationCallback& callback) {
159 DCHECK_CURRENTLY_ON(BrowserThread::UI);
161 // This is unfortunately necessary as file browser handlers operate on URLs.
162 GURL url;
163 if (!ConvertAbsoluteFilePathToFileSystemUrl(profile, file_path,
164 kFileManagerAppId, &url)) {
165 callback.Run(platform_util::OPEN_FAILED_PATH_NOT_FOUND);
166 return;
169 GetMetadataForPath(
170 GetFileSystemContextForExtensionId(profile, kFileManagerAppId), file_path,
171 base::Bind(&OpenItemWithMetadata, profile, file_path, url, expected_type,
172 callback));
175 void ShowItemInFolder(Profile* profile,
176 const base::FilePath& file_path,
177 const platform_util::OpenOperationCallback& callback) {
178 DCHECK_CURRENTLY_ON(BrowserThread::UI);
180 GURL url;
181 if (!ConvertAbsoluteFilePathToFileSystemUrl(profile, file_path,
182 kFileManagerAppId, &url)) {
183 callback.Run(platform_util::OPEN_FAILED_PATH_NOT_FOUND);
184 return;
187 // This action changes the selection so we do not reuse existing tabs.
188 OpenFileManagerWithInternalActionId(profile, url, "select");
189 callback.Run(platform_util::OPEN_SUCCEEDED);
192 void DisableShellOperationsForTesting() {
193 shell_operations_allowed = false;
196 } // namespace util
197 } // namespace file_manager