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/chromeos/file_manager/open_util.h" | 5 #include "chrome/browser/chromeos/file_manager/open_util.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/files/file_path.h" | 8 #include "base/files/file_path.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
11 #include "chrome/browser/chromeos/drive/file_system_util.h" | 11 #include "chrome/browser/chromeos/drive/file_system_util.h" |
12 #include "chrome/browser/chromeos/file_manager/app_id.h" | 12 #include "chrome/browser/chromeos/file_manager/app_id.h" |
13 #include "chrome/browser/chromeos/file_manager/file_tasks.h" | 13 #include "chrome/browser/chromeos/file_manager/file_tasks.h" |
14 #include "chrome/browser/chromeos/file_manager/fileapi_util.h" | 14 #include "chrome/browser/chromeos/file_manager/fileapi_util.h" |
15 #include "chrome/browser/chromeos/file_manager/path_util.h" | 15 #include "chrome/browser/chromeos/file_manager/path_util.h" |
16 #include "chrome/browser/chromeos/file_manager/url_util.h" | 16 #include "chrome/browser/chromeos/file_manager/url_util.h" |
17 #include "chrome/browser/extensions/api/file_handlers/mime_util.h" | 17 #include "chrome/browser/extensions/api/file_handlers/mime_util.h" |
18 #include "chrome/browser/ui/browser.h" | |
19 #include "chrome/browser/ui/browser_finder.h" | |
20 #include "chrome/browser/ui/browser_window.h" | |
21 #include "chrome/browser/ui/simple_message_box.h" | |
22 #include "chrome/grit/generated_resources.h" | |
23 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
24 #include "content/public/browser/user_metrics.h" | 19 #include "content/public/browser/user_metrics.h" |
25 #include "storage/browser/fileapi/file_system_backend.h" | 20 #include "storage/browser/fileapi/file_system_backend.h" |
26 #include "storage/browser/fileapi/file_system_context.h" | 21 #include "storage/browser/fileapi/file_system_context.h" |
27 #include "storage/browser/fileapi/file_system_operation_runner.h" | 22 #include "storage/browser/fileapi/file_system_operation_runner.h" |
28 #include "storage/browser/fileapi/file_system_url.h" | 23 #include "storage/browser/fileapi/file_system_url.h" |
29 #include "ui/base/l10n/l10n_util.h" | |
30 | 24 |
31 using content::BrowserThread; | 25 using content::BrowserThread; |
32 using storage::FileSystemURL; | 26 using storage::FileSystemURL; |
33 | 27 |
34 namespace file_manager { | 28 namespace file_manager { |
35 namespace util { | 29 namespace util { |
36 namespace { | 30 namespace { |
37 | 31 |
38 // Shows a warning message box saying that the file could not be opened. | 32 bool shell_operations_allowed = true; |
39 void ShowWarningMessageBox(Profile* profile, | |
40 const base::FilePath& file_path, | |
41 int message_id) { | |
42 Browser* browser = chrome::FindTabbedBrowser( | |
43 profile, false, chrome::HOST_DESKTOP_TYPE_ASH); | |
44 chrome::ShowMessageBox( | |
45 browser ? browser->window()->GetNativeWindow() : NULL, | |
46 l10n_util::GetStringFUTF16( | |
47 IDS_FILE_BROWSER_ERROR_VIEWING_FILE_TITLE, | |
48 base::UTF8ToUTF16(file_path.BaseName().AsUTF8Unsafe())), | |
49 l10n_util::GetStringUTF16(message_id), | |
50 chrome::MESSAGE_BOX_TYPE_WARNING); | |
51 } | |
52 | 33 |
53 // Executes the |task| for the file specified by |url|. | 34 // Executes the |task| for the file specified by |url|. |
54 void ExecuteFileTaskForUrl(Profile* profile, | 35 void ExecuteFileTaskForUrl(Profile* profile, |
55 const file_tasks::TaskDescriptor& task, | 36 const file_tasks::TaskDescriptor& task, |
56 const GURL& url) { | 37 const GURL& url) { |
| 38 if (!shell_operations_allowed) |
| 39 return; |
57 storage::FileSystemContext* file_system_context = | 40 storage::FileSystemContext* file_system_context = |
58 GetFileSystemContextForExtensionId(profile, kFileManagerAppId); | 41 GetFileSystemContextForExtensionId(profile, kFileManagerAppId); |
59 | 42 |
60 file_tasks::ExecuteFileTask( | 43 file_tasks::ExecuteFileTask( |
61 profile, | 44 profile, |
62 GetFileManagerMainPageUrl(), // Executing the task on behalf of Files.app. | 45 GetFileManagerMainPageUrl(), // Executing the task on behalf of Files.app. |
63 task, | 46 task, |
64 std::vector<FileSystemURL>(1, file_system_context->CrackURL(url)), | 47 std::vector<FileSystemURL>(1, file_system_context->CrackURL(url)), |
65 file_tasks::FileTaskFinishedCallback()); | 48 file_tasks::FileTaskFinishedCallback()); |
66 } | 49 } |
67 | 50 |
68 // Opens the file manager for the specified |url|. Used to implement | 51 // Opens the file manager for the specified |url|. Used to implement |
69 // internal handlers of special action IDs: | 52 // internal handlers of special action IDs: |
70 // | 53 // |
71 // "open" - Open the file manager for the given folder. | 54 // "open" - Open the file manager for the given folder. |
72 // "select" - Open the file manager for the given file. The folder containing | 55 // "select" - Open the file manager for the given file. The folder containing |
73 // the file will be opened with the file selected. | 56 // the file will be opened with the file selected. |
74 void OpenFileManagerWithInternalActionId(Profile* profile, | 57 void OpenFileManagerWithInternalActionId(Profile* profile, |
75 const GURL& url, | 58 const GURL& url, |
76 const std::string& action_id) { | 59 const std::string& action_id) { |
77 DCHECK(action_id == "open" || action_id == "select"); | 60 DCHECK(action_id == "open" || action_id == "select"); |
| 61 if (!shell_operations_allowed) |
| 62 return; |
78 content::RecordAction(base::UserMetricsAction("ShowFileBrowserFullTab")); | 63 content::RecordAction(base::UserMetricsAction("ShowFileBrowserFullTab")); |
79 | 64 |
80 file_tasks::TaskDescriptor task(kFileManagerAppId, | 65 file_tasks::TaskDescriptor task(kFileManagerAppId, |
81 file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER, | 66 file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER, |
82 action_id); | 67 action_id); |
83 ExecuteFileTaskForUrl(profile, task, url); | 68 ExecuteFileTaskForUrl(profile, task, url); |
84 } | 69 } |
85 | 70 |
86 // Opens the file with fetched MIME type and calls the callback. | 71 // Opens the file with fetched MIME type and calls the callback. |
87 void OpenFileWithMimeType(Profile* profile, | 72 void OpenFileWithMimeType(Profile* profile, |
88 const base::FilePath& path, | 73 const base::FilePath& path, |
89 const GURL& url, | 74 const GURL& url, |
90 const base::Callback<void(bool)>& callback, | 75 const platform_util::OpenOperationCallback& callback, |
91 const std::string& mime_type) { | 76 const std::string& mime_type) { |
92 extensions::app_file_handler_util::PathAndMimeTypeSet path_mime_set; | 77 extensions::app_file_handler_util::PathAndMimeTypeSet path_mime_set; |
93 path_mime_set.insert(std::make_pair(path, mime_type)); | 78 path_mime_set.insert(std::make_pair(path, mime_type)); |
94 | 79 |
95 std::vector<GURL> file_urls; | 80 std::vector<GURL> file_urls; |
96 file_urls.push_back(url); | 81 file_urls.push_back(url); |
97 | 82 |
98 std::vector<file_tasks::FullTaskDescriptor> tasks; | 83 std::vector<file_tasks::FullTaskDescriptor> tasks; |
99 file_tasks::FindAllTypesOfTasks( | 84 file_tasks::FindAllTypesOfTasks( |
100 profile, | 85 profile, |
101 drive::util::GetDriveAppRegistryByProfile(profile), | 86 drive::util::GetDriveAppRegistryByProfile(profile), |
102 path_mime_set, | 87 path_mime_set, |
103 file_urls, | 88 file_urls, |
104 &tasks); | 89 &tasks); |
105 | 90 |
106 // Select a default handler. If a default handler is not available, select | 91 // Select a default handler. If a default handler is not available, select |
107 // a non-generic file handler. | 92 // a non-generic file handler. |
108 const file_tasks::FullTaskDescriptor* chosen_task = nullptr; | 93 const file_tasks::FullTaskDescriptor* chosen_task = nullptr; |
109 for (const auto& task : tasks) { | 94 for (const auto& task : tasks) { |
110 if (!task.is_generic_file_handler()) { | 95 if (!task.is_generic_file_handler()) { |
111 chosen_task = &task; | 96 chosen_task = &task; |
112 if (task.is_default()) | 97 if (task.is_default()) |
113 break; | 98 break; |
114 } | 99 } |
115 } | 100 } |
116 | 101 |
117 if (chosen_task != nullptr) { | 102 if (chosen_task != nullptr) { |
118 ExecuteFileTaskForUrl(profile, chosen_task->task_descriptor(), url); | 103 if (shell_operations_allowed) |
119 callback.Run(true); | 104 ExecuteFileTaskForUrl(profile, chosen_task->task_descriptor(), url); |
| 105 callback.Run(platform_util::OPEN_SUCCEEDED); |
120 } else { | 106 } else { |
121 callback.Run(false); | 107 callback.Run(platform_util::OPEN_FAILED_NO_HANLDER_FOR_FILE_TYPE); |
122 } | 108 } |
123 } | 109 } |
124 | 110 |
125 // Opens the file specified by |url| by finding and executing a file task for | 111 // Opens the file specified by |url| by finding and executing a file task for |
126 // the file. In case of success, calls |callback| with true. Otherwise the | 112 // the file. Calls |callback| with the result. |
127 // returned value is false. | |
128 void OpenFile(Profile* profile, | 113 void OpenFile(Profile* profile, |
129 const base::FilePath& path, | 114 const base::FilePath& path, |
130 const GURL& url, | 115 const GURL& url, |
131 const base::Callback<void(bool)>& callback) { | 116 const platform_util::OpenOperationCallback& callback) { |
132 extensions::app_file_handler_util::GetMimeTypeForLocalPath( | 117 extensions::app_file_handler_util::GetMimeTypeForLocalPath( |
133 profile, | 118 profile, path, |
134 path, | |
135 base::Bind(&OpenFileWithMimeType, profile, path, url, callback)); | 119 base::Bind(&OpenFileWithMimeType, profile, path, url, callback)); |
136 } | 120 } |
137 | 121 |
138 // Called when execution of ContinueOpenItem() is completed. | 122 void OpenItemWithMetadata(Profile* profile, |
139 void OnContinueOpenItemCompleted(Profile* profile, | 123 const base::FilePath& file_path, |
140 const base::FilePath& file_path, | 124 const GURL& url, |
141 bool result) { | 125 platform_util::OpenItemType expected_type, |
142 if (!result) { | 126 const platform_util::OpenOperationCallback& callback, |
143 int message; | 127 base::File::Error error, |
144 if (file_path.Extension() == FILE_PATH_LITERAL(".dmg")) | 128 const base::File::Info& file_info) { |
145 message = IDS_FILE_BROWSER_ERROR_VIEWING_FILE_FOR_DMG; | 129 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
146 else if (file_path.Extension() == FILE_PATH_LITERAL(".exe") || | 130 if (error != base::File::FILE_OK) { |
147 file_path.Extension() == FILE_PATH_LITERAL(".msi")) | 131 callback.Run(error == base::File::FILE_ERROR_NOT_FOUND |
148 message = IDS_FILE_BROWSER_ERROR_VIEWING_FILE_FOR_EXECUTABLE; | 132 ? platform_util::OPEN_FAILED_PATH_NOT_FOUND |
149 else | 133 : platform_util::OPEN_FAILED_FILE_ERROR); |
150 message = IDS_FILE_BROWSER_ERROR_VIEWING_FILE; | 134 return; |
151 ShowWarningMessageBox(profile, file_path, message); | |
152 } | 135 } |
153 } | |
154 | 136 |
155 // Used to implement OpenItem(). | 137 // Note that there exists a TOCTOU race between the time the metadata for |
156 void ContinueOpenItem(Profile* profile, | 138 // |file_path| was determined and when it is opened based on the metadata. |
157 const base::FilePath& file_path, | 139 if (expected_type == platform_util::OPEN_FOLDER && file_info.is_directory) { |
158 const GURL& url, | 140 OpenFileManagerWithInternalActionId(profile, url, "open"); |
159 base::File::Error error) { | 141 callback.Run(platform_util::OPEN_SUCCEEDED); |
160 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 142 return; |
| 143 } |
161 | 144 |
162 if (error == base::File::FILE_OK) { | 145 if (expected_type == platform_util::OPEN_FILE && !file_info.is_directory) { |
163 // A directory exists at |url|. Open it with the file manager. | 146 OpenFile(profile, file_path, url, callback); |
164 OpenFileManagerWithInternalActionId(profile, url, "open"); | 147 return; |
165 } else { | |
166 // |url| should be a file. Open it. | |
167 OpenFile(profile, | |
168 file_path, | |
169 url, | |
170 base::Bind(&OnContinueOpenItemCompleted, profile, file_path)); | |
171 } | 148 } |
172 } | |
173 | 149 |
174 // Converts the |path| passed from external callers to the filesystem URL | 150 callback.Run(platform_util::OPEN_FAILED_INVALID_TYPE); |
175 // that the file manager can correctly handle. | |
176 // | |
177 // When conversion fails, it shows a warning dialog UI and returns false. | |
178 bool ConvertPath(Profile* profile, const base::FilePath& path, GURL* url) { | |
179 if (!ConvertAbsoluteFilePathToFileSystemUrl( | |
180 profile, path, kFileManagerAppId, url)) { | |
181 ShowWarningMessageBox(profile, path, | |
182 IDS_FILE_BROWSER_ERROR_UNRESOLVABLE_FILE); | |
183 return false; | |
184 } | |
185 return true; | |
186 } | 151 } |
187 | 152 |
188 } // namespace | 153 } // namespace |
189 | 154 |
190 void OpenItem(Profile* profile, const base::FilePath& file_path) { | 155 void OpenItem(Profile* profile, |
| 156 const base::FilePath& file_path, |
| 157 platform_util::OpenItemType expected_type, |
| 158 const platform_util::OpenOperationCallback& callback) { |
191 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 159 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
192 | 160 |
193 GURL url; | 161 GURL url; |
194 if (!ConvertPath(profile, file_path, &url)) | 162 if (!ConvertAbsoluteFilePathToFileSystemUrl(profile, file_path, |
| 163 kFileManagerAppId, &url)) { |
| 164 callback.Run(platform_util::OPEN_FAILED_PATH_NOT_FOUND); |
195 return; | 165 return; |
| 166 } |
196 | 167 |
197 CheckIfDirectoryExists( | 168 GetMetadataForPath( |
198 GetFileSystemContextForExtensionId(profile, kFileManagerAppId), | 169 GetFileSystemContextForExtensionId(profile, kFileManagerAppId), url, |
199 url, | 170 base::Bind(&OpenItemWithMetadata, profile, file_path, url, expected_type, |
200 base::Bind(&ContinueOpenItem, profile, file_path, url)); | 171 callback)); |
201 } | 172 } |
202 | 173 |
203 void ShowItemInFolder(Profile* profile, const base::FilePath& file_path) { | 174 void ShowItemInFolder(Profile* profile, |
| 175 const base::FilePath& file_path, |
| 176 const platform_util::OpenOperationCallback& callback) { |
204 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 177 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
205 | 178 |
206 GURL url; | 179 GURL url; |
207 if (!ConvertPath(profile, file_path, &url)) | 180 if (!ConvertAbsoluteFilePathToFileSystemUrl(profile, file_path, |
| 181 kFileManagerAppId, &url)) { |
| 182 callback.Run(platform_util::OPEN_FAILED_PATH_NOT_FOUND); |
208 return; | 183 return; |
| 184 } |
209 | 185 |
210 // This action changes the selection so we do not reuse existing tabs. | 186 // This action changes the selection so we do not reuse existing tabs. |
211 OpenFileManagerWithInternalActionId(profile, url, "select"); | 187 OpenFileManagerWithInternalActionId(profile, url, "select"); |
| 188 callback.Run(platform_util::OPEN_SUCCEEDED); |
| 189 } |
| 190 |
| 191 void DisableShellOperationsForTesting() { |
| 192 shell_operations_allowed = false; |
212 } | 193 } |
213 | 194 |
214 } // namespace util | 195 } // namespace util |
215 } // namespace file_manager | 196 } // namespace file_manager |
OLD | NEW |