| 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/extensions/api/file_handlers/app_file_handler_util.h" | 5 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h" |
| 6 | 6 |
| 7 #include "base/files/file.h" | 7 #include "base/files/file.h" |
| 8 #include "base/files/file_path.h" | 8 #include "base/files/file_path.h" |
| 9 #include "base/files/file_util.h" | 9 #include "base/files/file_util.h" |
| 10 #include "build/build_config.h" | 10 #include "build/build_config.h" |
| 11 #include "chrome/browser/profiles/profile.h" |
| 11 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
| 12 #include "content/public/browser/child_process_security_policy.h" | 13 #include "content/public/browser/child_process_security_policy.h" |
| 14 #include "extensions/browser/api/extensions_api_client.h" |
| 13 #include "extensions/browser/entry_info.h" | 15 #include "extensions/browser/entry_info.h" |
| 14 #include "extensions/browser/extension_prefs.h" | 16 #include "extensions/browser/extension_prefs.h" |
| 15 #include "extensions/browser/granted_file_entry.h" | 17 #include "extensions/browser/granted_file_entry.h" |
| 16 #include "extensions/common/permissions/permissions_data.h" | 18 #include "extensions/common/permissions/permissions_data.h" |
| 17 #include "net/base/mime_util.h" | 19 #include "net/base/mime_util.h" |
| 18 #include "storage/browser/fileapi/isolated_context.h" | 20 #include "storage/browser/fileapi/isolated_context.h" |
| 19 #include "storage/common/fileapi/file_system_mount_option.h" | 21 #include "storage/common/fileapi/file_system_mount_option.h" |
| 20 #include "storage/common/fileapi/file_system_types.h" | 22 #include "storage/common/fileapi/file_system_types.h" |
| 21 | 23 |
| 22 #if defined(OS_CHROMEOS) | 24 #if defined(OS_CHROMEOS) |
| 23 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h" | 25 #include "extensions/browser/api/file_handlers/non_native_file_system_delegate.h
" |
| 24 #endif | 26 #endif |
| 25 | 27 |
| 26 namespace extensions { | 28 namespace extensions { |
| 27 | 29 |
| 28 namespace app_file_handler_util { | 30 namespace app_file_handler_util { |
| 29 | 31 |
| 30 const char kInvalidParameters[] = "Invalid parameters"; | 32 const char kInvalidParameters[] = "Invalid parameters"; |
| 31 const char kSecurityError[] = "Security error"; | 33 const char kSecurityError[] = "Security error"; |
| 32 | 34 |
| 33 namespace { | 35 namespace { |
| 34 | 36 |
| 35 bool FileHandlerCanHandleFileWithExtension( | 37 bool FileHandlerCanHandleFileWithExtension(const FileHandlerInfo& handler, |
| 36 const FileHandlerInfo& handler, | 38 const base::FilePath& path) { |
| 37 const base::FilePath& path) { | |
| 38 for (std::set<std::string>::const_iterator extension = | 39 for (std::set<std::string>::const_iterator extension = |
| 39 handler.extensions.begin(); | 40 handler.extensions.begin(); |
| 40 extension != handler.extensions.end(); ++extension) { | 41 extension != handler.extensions.end(); ++extension) { |
| 41 if (*extension == "*") | 42 if (*extension == "*") |
| 42 return true; | 43 return true; |
| 43 | 44 |
| 44 // Accept files whose extension or combined extension (e.g. ".tar.gz") | 45 // Accept files whose extension or combined extension (e.g. ".tar.gz") |
| 45 // match the supported extensions of file handler. | 46 // match the supported extensions of file handler. |
| 46 base::FilePath::StringType handler_extention( | 47 base::FilePath::StringType handler_extention( |
| 47 base::FilePath::kExtensionSeparator + | 48 base::FilePath::kExtensionSeparator + |
| 48 base::FilePath::FromUTF8Unsafe(*extension).value()); | 49 base::FilePath::FromUTF8Unsafe(*extension).value()); |
| 49 if (base::FilePath::CompareEqualIgnoreCase( | 50 if (base::FilePath::CompareEqualIgnoreCase(handler_extention, |
| 50 handler_extention, path.Extension()) || | 51 path.Extension()) || |
| 51 base::FilePath::CompareEqualIgnoreCase( | 52 base::FilePath::CompareEqualIgnoreCase(handler_extention, |
| 52 handler_extention, path.FinalExtension())) { | 53 path.FinalExtension())) { |
| 53 return true; | 54 return true; |
| 54 } | 55 } |
| 55 | 56 |
| 56 // Also accept files with no extension for handlers that support an | 57 // Also accept files with no extension for handlers that support an |
| 57 // empty extension, i.e. both "foo" and "foo." match. | 58 // empty extension, i.e. both "foo" and "foo." match. |
| 58 if (extension->empty() && | 59 if (extension->empty() && |
| 59 path.MatchesExtension(base::FilePath::StringType())) { | 60 path.MatchesExtension(base::FilePath::StringType())) { |
| 60 return true; | 61 return true; |
| 61 } | 62 } |
| 62 } | 63 } |
| 63 return false; | 64 return false; |
| 64 } | 65 } |
| 65 | 66 |
| 66 bool FileHandlerCanHandleFileWithMimeType( | 67 bool FileHandlerCanHandleFileWithMimeType(const FileHandlerInfo& handler, |
| 67 const FileHandlerInfo& handler, | 68 const std::string& mime_type) { |
| 68 const std::string& mime_type) { | |
| 69 for (std::set<std::string>::const_iterator type = handler.types.begin(); | 69 for (std::set<std::string>::const_iterator type = handler.types.begin(); |
| 70 type != handler.types.end(); ++type) { | 70 type != handler.types.end(); ++type) { |
| 71 if (net::MatchesMimeType(*type, mime_type)) | 71 if (net::MatchesMimeType(*type, mime_type)) |
| 72 return true; | 72 return true; |
| 73 } | 73 } |
| 74 return false; | 74 return false; |
| 75 } | 75 } |
| 76 | 76 |
| 77 bool PrepareNativeLocalFileForWritableApp(const base::FilePath& path, | 77 bool PrepareNativeLocalFileForWritableApp(const base::FilePath& path, |
| 78 bool is_directory) { | 78 bool is_directory) { |
| 79 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); | 79 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); |
| 80 | 80 |
| 81 // Don't allow links. | 81 // Don't allow links. |
| 82 if (base::PathExists(path) && base::IsLink(path)) | 82 if (base::PathExists(path) && base::IsLink(path)) |
| 83 return false; | 83 return false; |
| 84 | 84 |
| 85 if (is_directory) | 85 if (is_directory) |
| 86 return base::DirectoryExists(path); | 86 return base::DirectoryExists(path); |
| 87 | 87 |
| 88 // Create the file if it doesn't already exist. | 88 // Create the file if it doesn't already exist. |
| 89 int creation_flags = base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ; | 89 int creation_flags = base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ; |
| 90 base::File file(path, creation_flags); | 90 base::File file(path, creation_flags); |
| 91 | 91 |
| 92 return file.IsValid(); | 92 return file.IsValid(); |
| 93 } | 93 } |
| 94 | 94 |
| 95 // Checks whether a list of paths are all OK for writing and calls a provided | 95 // Checks whether a list of paths are all OK for writing and calls a provided |
| 96 // on_success or on_failure callback when done. A file is OK for writing if it | 96 // on_success or on_failure callback when done. A path is OK for writing if it |
| 97 // is not a symlink, is not in a blacklisted path and can be opened for writing; | 97 // is not a symlink, is not in a blacklisted path and can be opened for writing. |
| 98 // files are created if they do not exist. | 98 // Creates files if they do not exist, but fails for non-existent directory |
| 99 // paths. On Chrome OS, also fails for non-local files that don't already exist. |
| 99 class WritableFileChecker | 100 class WritableFileChecker |
| 100 : public base::RefCountedThreadSafe<WritableFileChecker> { | 101 : public base::RefCountedThreadSafe<WritableFileChecker> { |
| 101 public: | 102 public: |
| 102 WritableFileChecker( | 103 WritableFileChecker( |
| 103 const std::vector<base::FilePath>& paths, | 104 const std::vector<base::FilePath>& paths, |
| 104 Profile* profile, | 105 Profile* profile, |
| 105 const std::set<base::FilePath>& directory_paths, | 106 const std::set<base::FilePath>& directory_paths, |
| 106 const base::Closure& on_success, | 107 const base::Closure& on_success, |
| 107 const base::Callback<void(const base::FilePath&)>& on_failure); | 108 const base::Callback<void(const base::FilePath&)>& on_failure); |
| 108 | 109 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 const base::Closure& on_success, | 143 const base::Closure& on_success, |
| 143 const base::Callback<void(const base::FilePath&)>& on_failure) | 144 const base::Callback<void(const base::FilePath&)>& on_failure) |
| 144 : paths_(paths), | 145 : paths_(paths), |
| 145 profile_(profile), | 146 profile_(profile), |
| 146 directory_paths_(directory_paths), | 147 directory_paths_(directory_paths), |
| 147 outstanding_tasks_(1), | 148 outstanding_tasks_(1), |
| 148 on_success_(on_success), | 149 on_success_(on_success), |
| 149 on_failure_(on_failure) {} | 150 on_failure_(on_failure) {} |
| 150 | 151 |
| 151 void WritableFileChecker::Check() { | 152 void WritableFileChecker::Check() { |
| 152 outstanding_tasks_ = paths_.size(); | 153 outstanding_tasks_ = paths_.size(); |
| 153 for (const auto& path : paths_) { | 154 for (const auto& path : paths_) { |
| 154 bool is_directory = directory_paths_.find(path) != directory_paths_.end(); | 155 bool is_directory = directory_paths_.find(path) != directory_paths_.end(); |
| 155 #if defined(OS_CHROMEOS) | 156 #if defined(OS_CHROMEOS) |
| 156 if (file_manager::util::IsUnderNonNativeLocalPath(profile_, path)) { | 157 NonNativeFileSystemDelegate* delegate = |
| 157 if (is_directory) { | 158 ExtensionsAPIClient::Get()->GetNonNativeFileSystemDelegate(); |
| 158 file_manager::util::IsNonNativeLocalPathDirectory( | 159 if (delegate && delegate->IsUnderNonNativeLocalPath(profile_, path)) { |
| 159 profile_, path, | 160 if (is_directory) { |
| 160 base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path)); | 161 delegate->IsNonNativeLocalPathDirectory( |
| 161 } else { | 162 profile_, |
| 162 file_manager::util::PrepareNonNativeLocalFileForWritableApp( | 163 path, |
| 163 profile_, path, | 164 base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path)); |
| 164 base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path)); | 165 } else { |
| 165 } | 166 delegate->PrepareNonNativeLocalFileForWritableApp( |
| 166 continue; | 167 profile_, |
| 168 path, |
| 169 base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path)); |
| 167 } | 170 } |
| 171 continue; |
| 172 } |
| 168 #endif | 173 #endif |
| 169 content::BrowserThread::PostTaskAndReplyWithResult( | 174 content::BrowserThread::PostTaskAndReplyWithResult( |
| 170 content::BrowserThread::FILE, FROM_HERE, | 175 content::BrowserThread::FILE, FROM_HERE, |
| 171 base::Bind(&PrepareNativeLocalFileForWritableApp, path, is_directory), | 176 base::Bind(&PrepareNativeLocalFileForWritableApp, path, is_directory), |
| 172 base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path)); | 177 base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path)); |
| 173 } | 178 } |
| 174 } | 179 } |
| 175 | 180 |
| 176 WritableFileChecker::~WritableFileChecker() {} | 181 WritableFileChecker::~WritableFileChecker() {} |
| 177 | 182 |
| 178 void WritableFileChecker::TaskDone() { | 183 void WritableFileChecker::TaskDone() { |
| 179 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 184 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 180 if (--outstanding_tasks_ == 0) { | 185 if (--outstanding_tasks_ == 0) { |
| 181 if (error_path_.empty()) | 186 if (error_path_.empty()) |
| 182 on_success_.Run(); | 187 on_success_.Run(); |
| 183 else | 188 else |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 | 252 |
| 248 bool FileHandlerCanHandleEntry(const FileHandlerInfo& handler, | 253 bool FileHandlerCanHandleEntry(const FileHandlerInfo& handler, |
| 249 const EntryInfo& entry) { | 254 const EntryInfo& entry) { |
| 250 if (entry.is_directory) | 255 if (entry.is_directory) |
| 251 return handler.include_directories; | 256 return handler.include_directories; |
| 252 | 257 |
| 253 return FileHandlerCanHandleFileWithMimeType(handler, entry.mime_type) || | 258 return FileHandlerCanHandleFileWithMimeType(handler, entry.mime_type) || |
| 254 FileHandlerCanHandleFileWithExtension(handler, entry.path); | 259 FileHandlerCanHandleFileWithExtension(handler, entry.path); |
| 255 } | 260 } |
| 256 | 261 |
| 257 GrantedFileEntry CreateFileEntry( | 262 GrantedFileEntry CreateFileEntry(Profile* profile, |
| 258 Profile* profile, | 263 const Extension* extension, |
| 259 const Extension* extension, | 264 int renderer_id, |
| 260 int renderer_id, | 265 const base::FilePath& path, |
| 261 const base::FilePath& path, | 266 bool is_directory) { |
| 262 bool is_directory) { | |
| 263 GrantedFileEntry result; | 267 GrantedFileEntry result; |
| 264 storage::IsolatedContext* isolated_context = | 268 storage::IsolatedContext* isolated_context = |
| 265 storage::IsolatedContext::GetInstance(); | 269 storage::IsolatedContext::GetInstance(); |
| 266 DCHECK(isolated_context); | 270 DCHECK(isolated_context); |
| 267 | 271 |
| 268 result.filesystem_id = isolated_context->RegisterFileSystemForPath( | 272 result.filesystem_id = isolated_context->RegisterFileSystemForPath( |
| 269 storage::kFileSystemTypeNativeForPlatformApp, | 273 storage::kFileSystemTypeNativeForPlatformApp, std::string(), path, |
| 270 std::string(), | |
| 271 path, | |
| 272 &result.registered_name); | 274 &result.registered_name); |
| 273 | 275 |
| 274 content::ChildProcessSecurityPolicy* policy = | 276 content::ChildProcessSecurityPolicy* policy = |
| 275 content::ChildProcessSecurityPolicy::GetInstance(); | 277 content::ChildProcessSecurityPolicy::GetInstance(); |
| 276 policy->GrantReadFileSystem(renderer_id, result.filesystem_id); | 278 policy->GrantReadFileSystem(renderer_id, result.filesystem_id); |
| 277 if (HasFileSystemWritePermission(extension)) { | 279 if (HasFileSystemWritePermission(extension)) { |
| 278 if (is_directory) { | 280 if (is_directory) { |
| 279 policy->GrantCreateReadWriteFileSystem(renderer_id, result.filesystem_id); | 281 policy->GrantCreateReadWriteFileSystem(renderer_id, result.filesystem_id); |
| 280 } else { | 282 } else { |
| 281 policy->GrantWriteFileSystem(renderer_id, result.filesystem_id); | 283 policy->GrantWriteFileSystem(renderer_id, result.filesystem_id); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 324 content::ChildProcessSecurityPolicy* policy = | 326 content::ChildProcessSecurityPolicy* policy = |
| 325 content::ChildProcessSecurityPolicy::GetInstance(); | 327 content::ChildProcessSecurityPolicy::GetInstance(); |
| 326 if (!policy->CanReadFileSystem(render_process_id, filesystem_id)) { | 328 if (!policy->CanReadFileSystem(render_process_id, filesystem_id)) { |
| 327 *error = kSecurityError; | 329 *error = kSecurityError; |
| 328 return false; | 330 return false; |
| 329 } | 331 } |
| 330 | 332 |
| 331 storage::IsolatedContext* context = storage::IsolatedContext::GetInstance(); | 333 storage::IsolatedContext* context = storage::IsolatedContext::GetInstance(); |
| 332 base::FilePath relative_path = | 334 base::FilePath relative_path = |
| 333 base::FilePath::FromUTF8Unsafe(filesystem_path); | 335 base::FilePath::FromUTF8Unsafe(filesystem_path); |
| 334 base::FilePath virtual_path = context->CreateVirtualRootPath(filesystem_id) | 336 base::FilePath virtual_path = |
| 335 .Append(relative_path); | 337 context->CreateVirtualRootPath(filesystem_id).Append(relative_path); |
| 336 storage::FileSystemType type; | 338 storage::FileSystemType type; |
| 337 storage::FileSystemMountOption mount_option; | 339 storage::FileSystemMountOption mount_option; |
| 338 std::string cracked_id; | 340 std::string cracked_id; |
| 339 if (!context->CrackVirtualPath( | 341 if (!context->CrackVirtualPath(virtual_path, &filesystem_id, &type, |
| 340 virtual_path, &filesystem_id, &type, &cracked_id, file_path, | 342 &cracked_id, file_path, &mount_option)) { |
| 341 &mount_option)) { | |
| 342 *error = kInvalidParameters; | 343 *error = kInvalidParameters; |
| 343 return false; | 344 return false; |
| 344 } | 345 } |
| 345 | 346 |
| 346 // The file system API is only intended to operate on file entries that | 347 // The file system API is only intended to operate on file entries that |
| 347 // correspond to a native file, selected by the user so only allow file | 348 // correspond to a native file, selected by the user so only allow file |
| 348 // systems returned by the file system API or from a drag and drop operation. | 349 // systems returned by the file system API or from a drag and drop operation. |
| 349 if (type != storage::kFileSystemTypeNativeForPlatformApp && | 350 if (type != storage::kFileSystemTypeNativeForPlatformApp && |
| 350 type != storage::kFileSystemTypeDragged) { | 351 type != storage::kFileSystemTypeDragged) { |
| 351 *error = kInvalidParameters; | 352 *error = kInvalidParameters; |
| 352 return false; | 353 return false; |
| 353 } | 354 } |
| 354 | 355 |
| 355 return true; | 356 return true; |
| 356 } | 357 } |
| 357 | 358 |
| 358 } // namespace app_file_handler_util | 359 } // namespace app_file_handler_util |
| 359 | 360 |
| 360 } // namespace extensions | 361 } // namespace extensions |
| OLD | NEW |