| 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 = | |
| 43 chrome::FindTabbedBrowser(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), chrome::MESSAGE_BOX_TYPE_WARNING); | |
| 50 } | |
| 51 | 33 |
| 52 // Executes the |task| for the file specified by |url|. | 34 // Executes the |task| for the file specified by |url|. |
| 53 void ExecuteFileTaskForUrl(Profile* profile, | 35 void ExecuteFileTaskForUrl(Profile* profile, |
| 54 const file_tasks::TaskDescriptor& task, | 36 const file_tasks::TaskDescriptor& task, |
| 55 const GURL& url) { | 37 const GURL& url) { |
| 38 if (!shell_operations_allowed) |
| 39 return; |
| 56 storage::FileSystemContext* file_system_context = | 40 storage::FileSystemContext* file_system_context = |
| 57 GetFileSystemContextForExtensionId(profile, kFileManagerAppId); | 41 GetFileSystemContextForExtensionId(profile, kFileManagerAppId); |
| 58 | 42 |
| 59 file_tasks::ExecuteFileTask( | 43 file_tasks::ExecuteFileTask( |
| 60 profile, | 44 profile, |
| 61 GetFileManagerMainPageUrl(), // Executing the task on behalf of Files.app. | 45 GetFileManagerMainPageUrl(), // Executing the task on behalf of Files.app. |
| 62 task, | 46 task, |
| 63 std::vector<FileSystemURL>(1, file_system_context->CrackURL(url)), | 47 std::vector<FileSystemURL>(1, file_system_context->CrackURL(url)), |
| 64 file_tasks::FileTaskFinishedCallback()); | 48 file_tasks::FileTaskFinishedCallback()); |
| 65 } | 49 } |
| 66 | 50 |
| 67 // Opens the file manager for the specified |url|. Used to implement | 51 // Opens the file manager for the specified |url|. Used to implement |
| 68 // internal handlers of special action IDs: | 52 // internal handlers of special action IDs: |
| 69 // | 53 // |
| 70 // "open" - Open the file manager for the given folder. | 54 // "open" - Open the file manager for the given folder. |
| 71 // "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 |
| 72 // the file will be opened with the file selected. | 56 // the file will be opened with the file selected. |
| 73 void OpenFileManagerWithInternalActionId(Profile* profile, | 57 void OpenFileManagerWithInternalActionId(Profile* profile, |
| 74 const GURL& url, | 58 const GURL& url, |
| 75 const std::string& action_id) { | 59 const std::string& action_id) { |
| 76 DCHECK(action_id == "open" || action_id == "select"); | 60 DCHECK(action_id == "open" || action_id == "select"); |
| 61 if (!shell_operations_allowed) |
| 62 return; |
| 77 content::RecordAction(base::UserMetricsAction("ShowFileBrowserFullTab")); | 63 content::RecordAction(base::UserMetricsAction("ShowFileBrowserFullTab")); |
| 78 | 64 |
| 79 file_tasks::TaskDescriptor task(kFileManagerAppId, | 65 file_tasks::TaskDescriptor task(kFileManagerAppId, |
| 80 file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER, | 66 file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER, |
| 81 action_id); | 67 action_id); |
| 82 ExecuteFileTaskForUrl(profile, task, url); | 68 ExecuteFileTaskForUrl(profile, task, url); |
| 83 } | 69 } |
| 84 | 70 |
| 85 // Opens the file with fetched MIME type and calls the callback. | 71 // Opens the file with fetched MIME type and calls the callback. |
| 86 void OpenFileWithMimeType(Profile* profile, | 72 void OpenFileWithMimeType(Profile* profile, |
| 87 const base::FilePath& path, | 73 const base::FilePath& path, |
| 88 const GURL& url, | 74 const GURL& url, |
| 89 const base::Callback<void(bool)>& callback, | 75 const platform_util::OpenOperationCallback& callback, |
| 90 const std::string& mime_type) { | 76 const std::string& mime_type) { |
| 91 extensions::app_file_handler_util::PathAndMimeTypeSet path_mime_set; | 77 extensions::app_file_handler_util::PathAndMimeTypeSet path_mime_set; |
| 92 path_mime_set.insert(std::make_pair(path, mime_type)); | 78 path_mime_set.insert(std::make_pair(path, mime_type)); |
| 93 | 79 |
| 94 std::vector<GURL> file_urls; | 80 std::vector<GURL> file_urls; |
| 95 file_urls.push_back(url); | 81 file_urls.push_back(url); |
| 96 | 82 |
| 97 std::vector<file_tasks::FullTaskDescriptor> tasks; | 83 std::vector<file_tasks::FullTaskDescriptor> tasks; |
| 98 file_tasks::FindAllTypesOfTasks( | 84 file_tasks::FindAllTypesOfTasks( |
| 99 profile, | 85 profile, |
| 100 drive::util::GetDriveAppRegistryByProfile(profile), | 86 drive::util::GetDriveAppRegistryByProfile(profile), |
| 101 path_mime_set, | 87 path_mime_set, |
| 102 file_urls, | 88 file_urls, |
| 103 &tasks); | 89 &tasks); |
| 104 | 90 |
| 105 // 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 |
| 106 // a non-generic file handler. | 92 // a non-generic file handler. |
| 107 const file_tasks::FullTaskDescriptor* chosen_task = nullptr; | 93 const file_tasks::FullTaskDescriptor* chosen_task = nullptr; |
| 108 for (const auto& task : tasks) { | 94 for (const auto& task : tasks) { |
| 109 if (!task.is_generic_file_handler()) { | 95 if (!task.is_generic_file_handler()) { |
| 110 chosen_task = &task; | 96 chosen_task = &task; |
| 111 if (task.is_default()) | 97 if (task.is_default()) |
| 112 break; | 98 break; |
| 113 } | 99 } |
| 114 } | 100 } |
| 115 | 101 |
| 116 if (chosen_task != nullptr) { | 102 if (chosen_task != nullptr) { |
| 117 ExecuteFileTaskForUrl(profile, chosen_task->task_descriptor(), url); | 103 if (shell_operations_allowed) |
| 118 callback.Run(true); | 104 ExecuteFileTaskForUrl(profile, chosen_task->task_descriptor(), url); |
| 105 callback.Run(platform_util::OPEN_SUCCEEDED); |
| 119 } else { | 106 } else { |
| 120 callback.Run(false); | 107 callback.Run(platform_util::OPEN_FAILED_NO_HANLDER_FOR_FILE_TYPE); |
| 121 } | 108 } |
| 122 } | 109 } |
| 123 | 110 |
| 124 // 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 |
| 125 // the file. In case of success, calls |callback| with true. Otherwise the | 112 // the file. Calls |callback| with the result. |
| 126 // returned value is false. | |
| 127 void OpenFile(Profile* profile, | 113 void OpenFile(Profile* profile, |
| 128 const base::FilePath& path, | 114 const base::FilePath& path, |
| 129 const GURL& url, | 115 const GURL& url, |
| 130 const base::Callback<void(bool)>& callback) { | 116 const platform_util::OpenOperationCallback& callback) { |
| 131 extensions::app_file_handler_util::GetMimeTypeForLocalPath( | 117 extensions::app_file_handler_util::GetMimeTypeForLocalPath( |
| 132 profile, path, | 118 profile, path, |
| 133 base::Bind(&OpenFileWithMimeType, profile, path, url, callback)); | 119 base::Bind(&OpenFileWithMimeType, profile, path, url, callback)); |
| 134 } | 120 } |
| 135 | 121 |
| 136 // Called when execution of ContinueOpenItem() is completed. | 122 void OpenItemWithMetadata(Profile* profile, |
| 137 void OnContinueOpenItemCompleted(Profile* profile, | 123 const base::FilePath& file_path, |
| 138 const base::FilePath& file_path, | 124 const GURL& url, |
| 139 bool result) { | 125 platform_util::OpenItemType expected_type, |
| 140 if (!result) { | 126 const platform_util::OpenOperationCallback& callback, |
| 141 int message; | 127 base::File::Error error, |
| 142 if (file_path.Extension() == FILE_PATH_LITERAL(".dmg")) | 128 const base::File::Info& file_info) { |
| 143 message = IDS_FILE_BROWSER_ERROR_VIEWING_FILE_FOR_DMG; | 129 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 144 else if (file_path.Extension() == FILE_PATH_LITERAL(".exe") || | 130 if (error != base::File::FILE_OK) { |
| 145 file_path.Extension() == FILE_PATH_LITERAL(".msi")) | 131 callback.Run(error == base::File::FILE_ERROR_NOT_FOUND |
| 146 message = IDS_FILE_BROWSER_ERROR_VIEWING_FILE_FOR_EXECUTABLE; | 132 ? platform_util::OPEN_FAILED_PATH_NOT_FOUND |
| 147 else | 133 : platform_util::OPEN_FAILED_FILE_ERROR); |
| 148 message = IDS_FILE_BROWSER_ERROR_VIEWING_FILE; | 134 return; |
| 149 ShowWarningMessageBox(profile, file_path, message); | |
| 150 } | 135 } |
| 151 } | |
| 152 | 136 |
| 153 // Used to implement OpenItem(). | 137 // Note that there exists a TOCTOU race between the time the metadata for |
| 154 void ContinueOpenItem(Profile* profile, | 138 // |file_path| was determined and when it is opened based on the metadata. |
| 155 const base::FilePath& file_path, | 139 if (expected_type == platform_util::OPEN_FOLDER && file_info.is_directory) { |
| 156 const GURL& url, | 140 OpenFileManagerWithInternalActionId(profile, url, "open"); |
| 157 base::File::Error error) { | 141 callback.Run(platform_util::OPEN_SUCCEEDED); |
| 158 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 142 return; |
| 143 } |
| 159 | 144 |
| 160 if (error == base::File::FILE_OK) { | 145 if (expected_type == platform_util::OPEN_FILE && !file_info.is_directory) { |
| 161 // A directory exists at |url|. Open it with the file manager. | 146 OpenFile(profile, file_path, url, callback); |
| 162 OpenFileManagerWithInternalActionId(profile, url, "open"); | 147 return; |
| 163 } else { | |
| 164 // |url| should be a file. Open it. | |
| 165 OpenFile(profile, file_path, url, | |
| 166 base::Bind(&OnContinueOpenItemCompleted, profile, file_path)); | |
| 167 } | 148 } |
| 168 } | |
| 169 | 149 |
| 170 // Converts the |path| passed from external callers to the filesystem URL | 150 callback.Run(platform_util::OPEN_FAILED_INVALID_TYPE); |
| 171 // that the file manager can correctly handle. | |
| 172 // | |
| 173 // When conversion fails, it shows a warning dialog UI and returns false. | |
| 174 bool ConvertPath(Profile* profile, const base::FilePath& path, GURL* url) { | |
| 175 if (!ConvertAbsoluteFilePathToFileSystemUrl(profile, path, kFileManagerAppId, | |
| 176 url)) { | |
| 177 ShowWarningMessageBox(profile, path, | |
| 178 IDS_FILE_BROWSER_ERROR_UNRESOLVABLE_FILE); | |
| 179 return false; | |
| 180 } | |
| 181 return true; | |
| 182 } | 151 } |
| 183 | 152 |
| 184 } // namespace | 153 } // namespace |
| 185 | 154 |
| 186 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) { |
| 187 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 159 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 188 | 160 |
| 189 GURL url; | 161 GURL url; |
| 190 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); |
| 191 return; | 165 return; |
| 166 } |
| 192 | 167 |
| 193 CheckIfDirectoryExists( | 168 GetMetadataForPath( |
| 194 GetFileSystemContextForExtensionId(profile, kFileManagerAppId), url, | 169 GetFileSystemContextForExtensionId(profile, kFileManagerAppId), url, |
| 195 base::Bind(&ContinueOpenItem, profile, file_path, url)); | 170 base::Bind(&OpenItemWithMetadata, profile, file_path, url, expected_type, |
| 171 callback)); |
| 196 } | 172 } |
| 197 | 173 |
| 198 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) { |
| 199 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 177 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 200 | 178 |
| 201 GURL url; | 179 GURL url; |
| 202 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); |
| 203 return; | 183 return; |
| 184 } |
| 204 | 185 |
| 205 // 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. |
| 206 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; |
| 207 } | 193 } |
| 208 | 194 |
| 209 } // namespace util | 195 } // namespace util |
| 210 } // namespace file_manager | 196 } // namespace file_manager |
| OLD | NEW |