Chromium Code Reviews| 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 if (expected_type == platform_util::OPEN_FOLDER && file_info.is_directory) { |
| 156 void ContinueOpenItem(Profile* profile, | 138 OpenFileManagerWithInternalActionId(profile, url, "open"); |
| 157 const base::FilePath& file_path, | 139 callback.Run(platform_util::OPEN_SUCCEEDED); |
| 158 const GURL& url, | 140 return; |
| 159 base::File::Error error) { | 141 } |
| 160 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 161 | 142 |
| 162 if (error == base::File::FILE_OK) { | 143 if (expected_type == platform_util::OPEN_FILE && !file_info.is_directory) { |
| 163 // A directory exists at |url|. Open it with the file manager. | 144 OpenFile(profile, file_path, url, callback); |
|
mtomasz
2015/03/06 07:05:49
nit: TOCTOU race here as well. Can we add a commen
asanka
2015/03/06 21:09:40
Right. Added a comment above.
Although the "open"
| |
| 164 OpenFileManagerWithInternalActionId(profile, url, "open"); | 145 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 } | 146 } |
| 172 } | |
| 173 | 147 |
| 174 // Converts the |path| passed from external callers to the filesystem URL | 148 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 } | 149 } |
| 187 | 150 |
| 188 } // namespace | 151 } // namespace |
| 189 | 152 |
| 190 void OpenItem(Profile* profile, const base::FilePath& file_path) { | 153 void OpenItem(Profile* profile, |
| 154 const base::FilePath& file_path, | |
| 155 platform_util::OpenItemType expected_type, | |
| 156 const platform_util::OpenOperationCallback& callback) { | |
| 191 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 157 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 192 | 158 |
| 193 GURL url; | 159 GURL url; |
| 194 if (!ConvertPath(profile, file_path, &url)) | 160 if (!ConvertAbsoluteFilePathToFileSystemUrl(profile, file_path, |
| 161 kFileManagerAppId, &url)) { | |
| 162 callback.Run(platform_util::OPEN_FAILED_PATH_NOT_FOUND); | |
| 195 return; | 163 return; |
| 164 } | |
| 196 | 165 |
| 197 CheckIfDirectoryExists( | 166 GetMetadataForPath( |
| 198 GetFileSystemContextForExtensionId(profile, kFileManagerAppId), | 167 GetFileSystemContextForExtensionId(profile, kFileManagerAppId), url, |
| 199 url, | 168 base::Bind(&OpenItemWithMetadata, profile, file_path, url, expected_type, |
| 200 base::Bind(&ContinueOpenItem, profile, file_path, url)); | 169 callback)); |
| 201 } | 170 } |
| 202 | 171 |
| 203 void ShowItemInFolder(Profile* profile, const base::FilePath& file_path) { | 172 void ShowItemInFolder(Profile* profile, |
| 173 const base::FilePath& file_path, | |
| 174 const platform_util::OpenOperationCallback& callback) { | |
| 204 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 175 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 205 | 176 |
| 206 GURL url; | 177 GURL url; |
| 207 if (!ConvertPath(profile, file_path, &url)) | 178 if (!ConvertAbsoluteFilePathToFileSystemUrl(profile, file_path, |
| 179 kFileManagerAppId, &url)) { | |
| 180 callback.Run(platform_util::OPEN_FAILED_PATH_NOT_FOUND); | |
| 208 return; | 181 return; |
| 182 } | |
| 209 | 183 |
| 210 // This action changes the selection so we do not reuse existing tabs. | 184 // This action changes the selection so we do not reuse existing tabs. |
| 211 OpenFileManagerWithInternalActionId(profile, url, "select"); | 185 OpenFileManagerWithInternalActionId(profile, url, "select"); |
| 186 callback.Run(platform_util::OPEN_SUCCEEDED); | |
| 187 } | |
| 188 | |
| 189 void DisableShellOperationsForTesting() { | |
| 190 shell_operations_allowed = false; | |
| 212 } | 191 } |
| 213 | 192 |
| 214 } // namespace util | 193 } // namespace util |
| 215 } // namespace file_manager | 194 } // namespace file_manager |
| OLD | NEW |