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/extensions/api/file_system/file_system_api.h" | 5 #include "chrome/browser/extensions/api/file_system/file_system_api.h" |
| 6 | 6 |
| 7 #include "apps/saved_files_service.h" | 7 #include "apps/saved_files_service.h" |
| 8 #include "apps/shell_window.h" | 8 #include "apps/shell_window.h" |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| 11 #include "base/files/file_path.h" | 11 #include "base/files/file_path.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/path_service.h" | 13 #include "base/path_service.h" |
| 14 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
| 15 #include "base/strings/stringprintf.h" | |
| 15 #include "base/strings/sys_string_conversions.h" | 16 #include "base/strings/sys_string_conversions.h" |
| 16 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
| 17 #include "base/value_conversions.h" | 18 #include "base/value_conversions.h" |
| 18 #include "base/values.h" | 19 #include "base/values.h" |
| 19 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h" | 20 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h" |
| 20 #include "chrome/browser/extensions/extension_service.h" | 21 #include "chrome/browser/extensions/extension_service.h" |
| 21 #include "chrome/browser/extensions/extension_system.h" | 22 #include "chrome/browser/extensions/extension_system.h" |
| 22 #include "chrome/browser/extensions/shell_window_registry.h" | 23 #include "chrome/browser/extensions/shell_window_registry.h" |
| 23 #include "chrome/browser/platform_util.h" | 24 #include "chrome/browser/platform_util.h" |
| 24 #include "chrome/browser/ui/chrome_select_file_policy.h" | 25 #include "chrome/browser/ui/chrome_select_file_policy.h" |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 53 using apps::SavedFileEntry; | 54 using apps::SavedFileEntry; |
| 54 using apps::SavedFilesService; | 55 using apps::SavedFilesService; |
| 55 using apps::ShellWindow; | 56 using apps::ShellWindow; |
| 56 using fileapi::IsolatedContext; | 57 using fileapi::IsolatedContext; |
| 57 | 58 |
| 58 const char kInvalidParameters[] = "Invalid parameters"; | 59 const char kInvalidParameters[] = "Invalid parameters"; |
| 59 const char kSecurityError[] = "Security error"; | 60 const char kSecurityError[] = "Security error"; |
| 60 const char kInvalidCallingPage[] = "Invalid calling page. This function can't " | 61 const char kInvalidCallingPage[] = "Invalid calling page. This function can't " |
| 61 "be called from a background page."; | 62 "be called from a background page."; |
| 62 const char kUserCancelled[] = "User cancelled"; | 63 const char kUserCancelled[] = "User cancelled"; |
| 63 const char kWritableFileError[] = | 64 const char kWritableFileRestrictedLocationError[] = |
| 64 "Cannot write to file in a restricted location"; | 65 "Cannot write to file in a restricted location"; |
| 66 const char kWritableFileErrorFormat[] = "Error opening %s"; | |
| 65 const char kRequiresFileSystemWriteError[] = | 67 const char kRequiresFileSystemWriteError[] = |
| 66 "Operation requires fileSystem.write permission"; | 68 "Operation requires fileSystem.write permission"; |
| 69 const char kMultipleUnsupportedError[] = | |
| 70 "acceptsMultiple: true is not supported for 'saveFile'"; | |
| 67 const char kUnknownIdError[] = "Unknown id"; | 71 const char kUnknownIdError[] = "Unknown id"; |
| 68 | 72 |
| 69 namespace file_system = extensions::api::file_system; | 73 namespace file_system = extensions::api::file_system; |
| 70 namespace ChooseEntry = file_system::ChooseEntry; | 74 namespace ChooseEntry = file_system::ChooseEntry; |
| 71 | 75 |
| 72 namespace { | 76 namespace { |
| 73 | 77 |
| 74 const int kBlacklistedPaths[] = { | 78 const int kBlacklistedPaths[] = { |
| 75 chrome::DIR_APP, | 79 chrome::DIR_APP, |
| 76 chrome::DIR_USER_DATA, | 80 chrome::DIR_USER_DATA, |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 149 && home_path.AppendRelativePath(source_path, &display_path)) | 153 && home_path.AppendRelativePath(source_path, &display_path)) |
| 150 return display_path; | 154 return display_path; |
| 151 #endif | 155 #endif |
| 152 return source_path; | 156 return source_path; |
| 153 } | 157 } |
| 154 #endif // defined(OS_MACOSX) | 158 #endif // defined(OS_MACOSX) |
| 155 | 159 |
| 156 bool g_skip_picker_for_test = false; | 160 bool g_skip_picker_for_test = false; |
| 157 bool g_use_suggested_path_for_test = false; | 161 bool g_use_suggested_path_for_test = false; |
| 158 base::FilePath* g_path_to_be_picked_for_test; | 162 base::FilePath* g_path_to_be_picked_for_test; |
| 163 std::vector<base::FilePath>* g_paths_to_be_picked_for_test; | |
| 159 | 164 |
| 160 bool GetFileSystemAndPathOfFileEntry( | 165 bool GetFileSystemAndPathOfFileEntry( |
| 161 const std::string& filesystem_name, | 166 const std::string& filesystem_name, |
| 162 const std::string& filesystem_path, | 167 const std::string& filesystem_path, |
| 163 const content::RenderViewHost* render_view_host, | 168 const content::RenderViewHost* render_view_host, |
| 164 std::string* filesystem_id, | 169 std::string* filesystem_id, |
| 165 base::FilePath* file_path, | 170 base::FilePath* file_path, |
| 166 std::string* error) { | 171 std::string* error) { |
| 167 if (!fileapi::CrackIsolatedFileSystemName(filesystem_name, filesystem_id)) { | 172 if (!fileapi::CrackIsolatedFileSystemName(filesystem_name, filesystem_id)) { |
| 168 *error = kInvalidParameters; | 173 *error = kInvalidParameters; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 203 std::string filesystem_id; | 208 std::string filesystem_id; |
| 204 return GetFileSystemAndPathOfFileEntry(filesystem_name, | 209 return GetFileSystemAndPathOfFileEntry(filesystem_name, |
| 205 filesystem_path, | 210 filesystem_path, |
| 206 render_view_host, | 211 render_view_host, |
| 207 &filesystem_id, | 212 &filesystem_id, |
| 208 file_path, | 213 file_path, |
| 209 error); | 214 error); |
| 210 } | 215 } |
| 211 | 216 |
| 212 bool DoCheckWritableFile(const base::FilePath& path, | 217 bool DoCheckWritableFile(const base::FilePath& path, |
| 213 const base::FilePath& extension_directory) { | 218 const base::FilePath& extension_directory, |
| 219 std::string* error_message) { | |
| 214 // Don't allow links. | 220 // Don't allow links. |
| 215 if (base::PathExists(path) && file_util::IsLink(path)) | 221 if (base::PathExists(path) && file_util::IsLink(path)) { |
| 222 *error_message = base::StringPrintf(kWritableFileErrorFormat, | |
| 223 path.BaseName().AsUTF8Unsafe().c_str()); | |
| 216 return false; | 224 return false; |
| 225 } | |
| 217 | 226 |
| 218 if (extension_directory == path || extension_directory.IsParent(path)) | 227 if (extension_directory == path || extension_directory.IsParent(path)) { |
| 228 *error_message = kWritableFileRestrictedLocationError; | |
| 219 return false; | 229 return false; |
| 230 } | |
| 220 | 231 |
| 221 bool is_whitelisted_path = false; | 232 bool is_whitelisted_path = false; |
| 222 | 233 |
| 223 #if defined(OS_CHROMEOS) | 234 #if defined(OS_CHROMEOS) |
| 224 for (size_t i = 0; i < arraysize(kWhitelistedPaths); i++) { | 235 for (size_t i = 0; i < arraysize(kWhitelistedPaths); i++) { |
| 225 base::FilePath whitelisted_path; | 236 base::FilePath whitelisted_path; |
| 226 if (PathService::Get(kWhitelistedPaths[i], &whitelisted_path) && | 237 if (PathService::Get(kWhitelistedPaths[i], &whitelisted_path) && |
| 227 (whitelisted_path == path || whitelisted_path.IsParent(path))) { | 238 (whitelisted_path == path || whitelisted_path.IsParent(path))) { |
| 228 is_whitelisted_path = true; | 239 is_whitelisted_path = true; |
| 229 break; | 240 break; |
| 230 } | 241 } |
| 231 } | 242 } |
| 232 #endif | 243 #endif |
| 233 | 244 |
| 234 if (!is_whitelisted_path) { | 245 if (!is_whitelisted_path) { |
| 235 for (size_t i = 0; i < arraysize(kBlacklistedPaths); i++) { | 246 for (size_t i = 0; i < arraysize(kBlacklistedPaths); i++) { |
| 236 base::FilePath blacklisted_path; | 247 base::FilePath blacklisted_path; |
| 237 if (PathService::Get(kBlacklistedPaths[i], &blacklisted_path) && | 248 if (PathService::Get(kBlacklistedPaths[i], &blacklisted_path) && |
| 238 (blacklisted_path == path || blacklisted_path.IsParent(path))) { | 249 (blacklisted_path == path || blacklisted_path.IsParent(path))) { |
| 250 *error_message = kWritableFileRestrictedLocationError; | |
| 239 return false; | 251 return false; |
| 240 } | 252 } |
| 241 } | 253 } |
| 242 } | 254 } |
| 243 | 255 |
| 244 // Create the file if it doesn't already exist. | 256 // Create the file if it doesn't already exist. |
| 245 base::PlatformFileError error = base::PLATFORM_FILE_OK; | 257 base::PlatformFileError error = base::PLATFORM_FILE_OK; |
| 246 int creation_flags = base::PLATFORM_FILE_CREATE | | 258 int creation_flags = base::PLATFORM_FILE_CREATE | |
| 247 base::PLATFORM_FILE_READ | | 259 base::PLATFORM_FILE_READ | |
| 248 base::PLATFORM_FILE_WRITE; | 260 base::PLATFORM_FILE_WRITE; |
| 249 base::PlatformFile file = base::CreatePlatformFile(path, creation_flags, | 261 base::PlatformFile file = base::CreatePlatformFile(path, creation_flags, |
| 250 NULL, &error); | 262 NULL, &error); |
| 251 // Close the file so we don't keep a lock open. | 263 // Close the file so we don't keep a lock open. |
| 252 if (file != base::kInvalidPlatformFileValue) | 264 if (file != base::kInvalidPlatformFileValue) |
| 253 base::ClosePlatformFile(file); | 265 base::ClosePlatformFile(file); |
| 254 return error == base::PLATFORM_FILE_OK || | 266 if (error != base::PLATFORM_FILE_OK && |
| 255 error == base::PLATFORM_FILE_ERROR_EXISTS; | 267 error != base::PLATFORM_FILE_ERROR_EXISTS) { |
| 268 *error_message = base::StringPrintf(kWritableFileErrorFormat, | |
| 269 path.BaseName().AsUTF8Unsafe().c_str()); | |
| 270 return false; | |
| 271 } | |
| 272 | |
| 273 return true; | |
| 256 } | 274 } |
| 257 | 275 |
| 258 void CheckLocalWritableFile(const base::FilePath& path, | 276 // Checks whether a list of paths are all OK for writing and calls a provided |
| 259 const base::FilePath& extension_directory, | 277 // on_success or on_failure callback when done. A file is OK for writing if it |
| 260 const base::Closure& on_success, | 278 // is not a symlink, is not in a blacklisted path and can be opened for writing; |
| 261 const base::Closure& on_failure) { | 279 // files are created if they do not exist. |
| 262 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | 280 class WritableFileChecker |
| 263 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | 281 : public base::RefCountedThreadSafe<WritableFileChecker> { |
| 264 DoCheckWritableFile(path, extension_directory) ? on_success : on_failure); | 282 public: |
| 265 } | 283 WritableFileChecker( |
| 284 const std::vector<base::FilePath>& paths, | |
| 285 Profile* profile, | |
| 286 const base::FilePath& extension_path, | |
| 287 const base::Closure& on_success, | |
| 288 const base::Callback<void(const std::string&)>& on_failure) | |
| 289 : outstanding_tasks_(1), | |
| 290 extension_path_(extension_path), | |
| 291 on_success_(on_success), | |
| 292 on_failure_(on_failure) { | |
| 293 #if defined(OS_CHROMEOS) | |
| 294 if (drive::util::IsUnderDriveMountPoint(paths[0])) { | |
| 295 outstanding_tasks_ = paths.size(); | |
| 296 for (std::vector<base::FilePath>::const_iterator it = paths.begin(); | |
| 297 it != paths.end(); ++it) { | |
| 298 DCHECK(drive::util::IsUnderDriveMountPoint(*it)); | |
| 299 drive::util::PrepareWritableFileAndRun( | |
| 300 profile, | |
| 301 *it, | |
| 302 base::Bind(&WritableFileChecker::CheckRemoteWritableFile, this)); | |
| 303 } | |
| 304 return; | |
| 305 } | |
| 306 #endif | |
| 307 content::BrowserThread::PostTask( | |
| 308 content::BrowserThread::FILE, | |
| 309 FROM_HERE, | |
| 310 base::Bind(&WritableFileChecker::CheckLocalWritableFiles, this, paths)); | |
| 311 } | |
| 312 | |
| 313 private: | |
| 314 friend class base::RefCountedThreadSafe<WritableFileChecker>; | |
| 315 virtual ~WritableFileChecker() {} | |
| 316 | |
| 317 // Called when a work item is completed. If all work items are done, this | |
| 318 // calls the success or failure callback. | |
| 319 void TaskDone() { | |
| 320 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 321 if (--outstanding_tasks_ == 0) { | |
| 322 if (error_.empty()) | |
| 323 on_success_.Run(); | |
| 324 else | |
| 325 on_failure_.Run(error_); | |
| 326 } | |
| 327 } | |
| 328 | |
| 329 // Reports an error in completing a work item. This may be called more than | |
| 330 // once, but only the last message will be retained. | |
| 331 void Error(const std::string& message) { | |
| 332 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
|
Matt Giuca
2013/08/01 00:02:24
Nit: Remove this DCHECK. There is nothing in this
Sam McNally
2013/08/01 00:08:39
Done.
| |
| 333 DCHECK(!message.empty()); | |
| 334 error_ = message; | |
| 335 TaskDone(); | |
| 336 } | |
| 337 | |
| 338 void CheckLocalWritableFiles(const std::vector<base::FilePath>& paths) { | |
| 339 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | |
| 340 std::string error; | |
| 341 for (std::vector<base::FilePath>::const_iterator it = paths.begin(); | |
| 342 it != paths.end(); ++it) { | |
| 343 if (!DoCheckWritableFile(*it, extension_path_, &error)) { | |
| 344 content::BrowserThread::PostTask( | |
| 345 content::BrowserThread::UI, | |
| 346 FROM_HERE, | |
| 347 base::Bind(&WritableFileChecker::Error, this, error)); | |
| 348 return; | |
| 349 } | |
| 350 } | |
| 351 content::BrowserThread::PostTask( | |
| 352 content::BrowserThread::UI, | |
| 353 FROM_HERE, | |
| 354 base::Bind(&WritableFileChecker::TaskDone, this)); | |
| 355 } | |
| 266 | 356 |
| 267 #if defined(OS_CHROMEOS) | 357 #if defined(OS_CHROMEOS) |
| 268 void CheckRemoteWritableFile(const base::Closure& on_success, | 358 void CheckRemoteWritableFile(drive::FileError error, |
| 269 const base::Closure& on_failure, | 359 const base::FilePath& path) { |
| 270 drive::FileError error, | 360 if (error == drive::FILE_ERROR_OK) { |
| 271 const base::FilePath& path) { | 361 content::BrowserThread::PostTask( |
| 272 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | 362 content::BrowserThread::UI, |
| 273 error == drive::FILE_ERROR_OK ? on_success : on_failure); | 363 FROM_HERE, |
| 274 } | 364 base::Bind(&WritableFileChecker::TaskDone, this)); |
| 365 } else { | |
| 366 content::BrowserThread::PostTask( | |
| 367 content::BrowserThread::UI, | |
| 368 FROM_HERE, | |
| 369 base::Bind( | |
| 370 &WritableFileChecker::Error, | |
| 371 this, | |
| 372 base::StringPrintf(kWritableFileErrorFormat, | |
| 373 path.BaseName().AsUTF8Unsafe().c_str()))); | |
| 374 } | |
| 375 } | |
| 275 #endif | 376 #endif |
| 276 | 377 |
| 378 int outstanding_tasks_; | |
| 379 const base::FilePath extension_path_; | |
| 380 std::string error_; | |
| 381 base::Closure on_success_; | |
| 382 base::Callback<void(const std::string&)> on_failure_; | |
| 383 }; | |
| 384 | |
| 277 // Expand the mime-types and extensions provided in an AcceptOption, returning | 385 // Expand the mime-types and extensions provided in an AcceptOption, returning |
| 278 // them within the passed extension vector. Returns false if no valid types | 386 // them within the passed extension vector. Returns false if no valid types |
| 279 // were found. | 387 // were found. |
| 280 bool GetFileTypesFromAcceptOption( | 388 bool GetFileTypesFromAcceptOption( |
| 281 const file_system::AcceptOption& accept_option, | 389 const file_system::AcceptOption& accept_option, |
| 282 std::vector<base::FilePath::StringType>* extensions, | 390 std::vector<base::FilePath::StringType>* extensions, |
| 283 string16* description) { | 391 string16* description) { |
| 284 std::set<base::FilePath::StringType> extension_set; | 392 std::set<base::FilePath::StringType> extension_set; |
| 285 int description_id = 0; | 393 int description_id = 0; |
| 286 | 394 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 389 | 497 |
| 390 bool FileSystemEntryFunction::HasFileSystemWritePermission() { | 498 bool FileSystemEntryFunction::HasFileSystemWritePermission() { |
| 391 const extensions::Extension* extension = GetExtension(); | 499 const extensions::Extension* extension = GetExtension(); |
| 392 if (!extension) | 500 if (!extension) |
| 393 return false; | 501 return false; |
| 394 | 502 |
| 395 return extension->HasAPIPermission(APIPermission::kFileSystemWrite); | 503 return extension->HasAPIPermission(APIPermission::kFileSystemWrite); |
| 396 } | 504 } |
| 397 | 505 |
| 398 void FileSystemEntryFunction::CheckWritableFile(const base::FilePath& path) { | 506 void FileSystemEntryFunction::CheckWritableFile(const base::FilePath& path) { |
| 399 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 507 std::vector<base::FilePath> paths; |
| 400 base::Closure on_success = | 508 paths.push_back(path); |
| 401 base::Bind(&FileSystemEntryFunction::RegisterFileSystemAndSendResponse, | 509 CheckWritableFiles(paths, false); |
| 402 this, path, WRITABLE); | |
| 403 base::Closure on_failure = | |
| 404 base::Bind(&FileSystemEntryFunction::HandleWritableFileError, this); | |
| 405 | |
| 406 #if defined(OS_CHROMEOS) | |
| 407 if (drive::util::IsUnderDriveMountPoint(path)) { | |
| 408 drive::util::PrepareWritableFileAndRun(profile_, path, | |
| 409 base::Bind(&CheckRemoteWritableFile, on_success, on_failure)); | |
| 410 return; | |
| 411 } | |
| 412 #endif | |
| 413 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, | |
| 414 base::Bind(&CheckLocalWritableFile, path, extension_->path(), on_success, | |
| 415 on_failure)); | |
| 416 } | 510 } |
| 417 | 511 |
| 418 void FileSystemEntryFunction::RegisterFileSystemAndSendResponse( | 512 void FileSystemEntryFunction::CheckWritableFiles( |
| 419 const base::FilePath& path, EntryType entry_type) { | 513 const std::vector<base::FilePath>& paths, bool multiple) { |
| 420 RegisterFileSystemAndSendResponseWithIdOverride(path, entry_type, ""); | 514 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 515 scoped_refptr<WritableFileChecker> helper = new WritableFileChecker( | |
| 516 paths, profile_, extension_->path(), | |
| 517 base::Bind( | |
| 518 &FileSystemEntryFunction::RegisterFileSystemsAndSendResponse, | |
| 519 this, paths, WRITABLE, multiple), | |
| 520 base::Bind(&FileSystemEntryFunction::HandleWritableFileError, this)); | |
| 521 } | |
| 522 | |
| 523 void FileSystemEntryFunction::RegisterFileSystemsAndSendResponse( | |
| 524 const std::vector<base::FilePath>& paths, | |
| 525 EntryType entry_type, | |
| 526 bool multiple) { | |
| 527 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 528 std::vector<std::pair<base::FilePath, std::string> > paths_and_overrides; | |
| 529 for (std::vector<base::FilePath>::const_iterator it = paths.begin(); | |
| 530 it != paths.end(); ++it) { | |
| 531 paths_and_overrides.push_back(std::make_pair(*it, "")); | |
| 532 } | |
| 533 RegisterFileSystemsAndSendResponseWithIdOverrides( | |
| 534 paths_and_overrides, entry_type, multiple); | |
| 535 } | |
| 536 | |
| 537 void FileSystemEntryFunction::RegisterFileSystemsAndSendResponseWithIdOverrides( | |
|
Matt Giuca
2013/08/01 00:02:24
Nit: Move this function below RegisterFileSystemAn
Sam McNally
2013/08/01 00:08:39
Done.
| |
| 538 const std::vector<std::pair<base::FilePath, std::string> >& | |
| 539 paths_and_overrides, | |
| 540 EntryType entry_type, | |
| 541 bool multiple) { | |
| 542 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 543 | |
| 544 base::DictionaryValue* response = new base::DictionaryValue(); | |
| 545 base::ListValue* list = new base::ListValue(); | |
| 546 response->Set("entries", list); | |
| 547 response->SetBoolean("multiple", multiple); | |
| 548 SetResult(response); | |
| 549 for (std::vector<std::pair<base::FilePath, std::string> >::const_iterator it = | |
| 550 paths_and_overrides.begin(); | |
| 551 it != paths_and_overrides.end(); ++it) { | |
| 552 list->Append(BuildEntryDict(it->first, entry_type, it->second)); | |
| 553 } | |
| 554 | |
| 555 SendResponse(true); | |
| 421 } | 556 } |
| 422 | 557 |
| 423 void FileSystemEntryFunction::RegisterFileSystemAndSendResponseWithIdOverride( | 558 void FileSystemEntryFunction::RegisterFileSystemAndSendResponseWithIdOverride( |
| 424 const base::FilePath& path, EntryType entry_type, const std::string& id) { | 559 const base::FilePath& path, EntryType entry_type, const std::string& id) { |
| 425 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 560 std::vector<std::pair<base::FilePath, std::string> > paths_and_overrides; |
| 561 paths_and_overrides.push_back(std::make_pair(path, id)); | |
| 562 RegisterFileSystemsAndSendResponseWithIdOverrides( | |
| 563 paths_and_overrides, entry_type, false); | |
| 564 } | |
| 426 | 565 |
| 427 fileapi::IsolatedContext* isolated_context = | 566 base::DictionaryValue* FileSystemEntryFunction::BuildEntryDict( |
| 428 fileapi::IsolatedContext::GetInstance(); | 567 const base::FilePath& path, EntryType entry_type, const std::string& id) { |
| 429 DCHECK(isolated_context); | |
| 430 | |
| 431 bool writable = entry_type == WRITABLE; | 568 bool writable = entry_type == WRITABLE; |
| 432 extensions::app_file_handler_util::GrantedFileEntry file_entry = | 569 extensions::app_file_handler_util::GrantedFileEntry file_entry = |
| 433 extensions::app_file_handler_util::CreateFileEntry(profile(), | 570 extensions::app_file_handler_util::CreateFileEntry(profile(), |
| 434 GetExtension()->id(), render_view_host_->GetProcess()->GetID(), path, | 571 GetExtension()->id(), render_view_host_->GetProcess()->GetID(), path, |
| 435 writable); | 572 writable); |
| 436 | 573 |
| 437 base::DictionaryValue* dict = new base::DictionaryValue(); | 574 base::DictionaryValue* dict = new base::DictionaryValue(); |
| 438 SetResult(dict); | |
| 439 dict->SetString("fileSystemId", file_entry.filesystem_id); | 575 dict->SetString("fileSystemId", file_entry.filesystem_id); |
| 440 dict->SetString("baseName", file_entry.registered_name); | 576 dict->SetString("baseName", file_entry.registered_name); |
| 441 if (id.empty()) | 577 if (id.empty()) |
| 442 dict->SetString("id", file_entry.id); | 578 dict->SetString("id", file_entry.id); |
| 443 else | 579 else |
| 444 dict->SetString("id", id); | 580 dict->SetString("id", id); |
| 445 | 581 return dict; |
| 446 SendResponse(true); | |
| 447 } | 582 } |
| 448 | 583 |
| 449 void FileSystemEntryFunction::HandleWritableFileError() { | 584 void FileSystemEntryFunction::HandleWritableFileError( |
| 585 const std::string& error) { | |
| 450 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 586 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 451 error_ = kWritableFileError; | 587 error_ = error; |
| 452 SendResponse(false); | 588 SendResponse(false); |
| 453 } | 589 } |
| 454 | 590 |
| 455 bool FileSystemGetWritableEntryFunction::RunImpl() { | 591 bool FileSystemGetWritableEntryFunction::RunImpl() { |
| 456 std::string filesystem_name; | 592 std::string filesystem_name; |
| 457 std::string filesystem_path; | 593 std::string filesystem_path; |
| 458 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); | 594 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); |
| 459 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); | 595 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); |
| 460 | 596 |
| 461 if (!HasFileSystemWritePermission()) { | 597 if (!HasFileSystemWritePermission()) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 497 // Handles showing a dialog to the user to ask for the filename for a file to | 633 // Handles showing a dialog to the user to ask for the filename for a file to |
| 498 // save or open. | 634 // save or open. |
| 499 class FileSystemChooseEntryFunction::FilePicker | 635 class FileSystemChooseEntryFunction::FilePicker |
| 500 : public ui::SelectFileDialog::Listener { | 636 : public ui::SelectFileDialog::Listener { |
| 501 public: | 637 public: |
| 502 FilePicker(FileSystemChooseEntryFunction* function, | 638 FilePicker(FileSystemChooseEntryFunction* function, |
| 503 content::WebContents* web_contents, | 639 content::WebContents* web_contents, |
| 504 const base::FilePath& suggested_name, | 640 const base::FilePath& suggested_name, |
| 505 const ui::SelectFileDialog::FileTypeInfo& file_type_info, | 641 const ui::SelectFileDialog::FileTypeInfo& file_type_info, |
| 506 ui::SelectFileDialog::Type picker_type, | 642 ui::SelectFileDialog::Type picker_type, |
| 507 EntryType entry_type) | 643 EntryType entry_type, |
| 644 bool multiple) | |
| 508 : entry_type_(entry_type), | 645 : entry_type_(entry_type), |
| 646 multiple_(multiple), | |
| 509 function_(function) { | 647 function_(function) { |
| 510 select_file_dialog_ = ui::SelectFileDialog::Create( | 648 select_file_dialog_ = ui::SelectFileDialog::Create( |
| 511 this, new ChromeSelectFilePolicy(web_contents)); | 649 this, new ChromeSelectFilePolicy(web_contents)); |
| 512 gfx::NativeWindow owning_window = web_contents ? | 650 gfx::NativeWindow owning_window = web_contents ? |
| 513 platform_util::GetTopLevel(web_contents->GetView()->GetNativeView()) : | 651 platform_util::GetTopLevel(web_contents->GetView()->GetNativeView()) : |
| 514 NULL; | 652 NULL; |
| 515 | 653 |
| 516 if (g_skip_picker_for_test) { | 654 if (g_skip_picker_for_test) { |
| 517 if (g_use_suggested_path_for_test) { | 655 if (g_use_suggested_path_for_test) { |
| 518 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | 656 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, |
| 519 base::Bind( | 657 base::Bind( |
| 520 &FileSystemChooseEntryFunction::FilePicker::FileSelected, | 658 &FileSystemChooseEntryFunction::FilePicker::FileSelected, |
| 521 base::Unretained(this), suggested_name, 1, | 659 base::Unretained(this), suggested_name, 1, |
| 522 static_cast<void*>(NULL))); | 660 static_cast<void*>(NULL))); |
| 523 } else if (g_path_to_be_picked_for_test) { | 661 } else if (g_path_to_be_picked_for_test) { |
| 524 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | 662 content::BrowserThread::PostTask( |
| 663 content::BrowserThread::UI, FROM_HERE, | |
| 525 base::Bind( | 664 base::Bind( |
| 526 &FileSystemChooseEntryFunction::FilePicker::FileSelected, | 665 &FileSystemChooseEntryFunction::FilePicker::FileSelected, |
| 527 base::Unretained(this), *g_path_to_be_picked_for_test, 1, | 666 base::Unretained(this), *g_path_to_be_picked_for_test, 1, |
| 528 static_cast<void*>(NULL))); | 667 static_cast<void*>(NULL))); |
| 668 } else if (g_paths_to_be_picked_for_test) { | |
| 669 content::BrowserThread::PostTask( | |
| 670 content::BrowserThread::UI, | |
| 671 FROM_HERE, | |
| 672 base::Bind( | |
| 673 &FileSystemChooseEntryFunction::FilePicker::MultiFilesSelected, | |
| 674 base::Unretained(this), | |
| 675 *g_paths_to_be_picked_for_test, | |
| 676 static_cast<void*>(NULL))); | |
| 529 } else { | 677 } else { |
| 530 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | 678 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, |
| 531 base::Bind( | 679 base::Bind( |
| 532 &FileSystemChooseEntryFunction::FilePicker:: | 680 &FileSystemChooseEntryFunction::FilePicker:: |
| 533 FileSelectionCanceled, | 681 FileSelectionCanceled, |
| 534 base::Unretained(this), static_cast<void*>(NULL))); | 682 base::Unretained(this), static_cast<void*>(NULL))); |
| 535 } | 683 } |
| 536 return; | 684 return; |
| 537 } | 685 } |
| 538 | 686 |
| 539 select_file_dialog_->SelectFile(picker_type, | 687 select_file_dialog_->SelectFile(picker_type, |
| 540 string16(), | 688 string16(), |
| 541 suggested_name, | 689 suggested_name, |
| 542 &file_type_info, | 690 &file_type_info, |
| 543 0, | 691 0, |
| 544 base::FilePath::StringType(), | 692 base::FilePath::StringType(), |
| 545 owning_window, | 693 owning_window, |
| 546 NULL); | 694 NULL); |
| 547 } | 695 } |
| 548 | 696 |
| 549 virtual ~FilePicker() {} | 697 virtual ~FilePicker() {} |
| 550 | 698 |
| 551 private: | 699 private: |
| 552 // ui::SelectFileDialog::Listener implementation. | 700 // ui::SelectFileDialog::Listener implementation. |
| 553 virtual void FileSelected(const base::FilePath& path, | 701 virtual void FileSelected(const base::FilePath& path, |
| 554 int index, | 702 int index, |
| 555 void* params) OVERRIDE { | 703 void* params) OVERRIDE { |
| 556 function_->FileSelected(path, entry_type_); | 704 std::vector<base::FilePath> paths; |
| 557 delete this; | 705 paths.push_back(path); |
| 706 MultiFilesSelected(paths, params); | |
| 558 } | 707 } |
| 559 | 708 |
| 560 virtual void FileSelectedWithExtraInfo(const ui::SelectedFileInfo& file, | 709 virtual void FileSelectedWithExtraInfo(const ui::SelectedFileInfo& file, |
| 561 int index, | 710 int index, |
| 562 void* params) OVERRIDE { | 711 void* params) OVERRIDE { |
| 563 // Normally, file.local_path is used because it is a native path to the | 712 // Normally, file.local_path is used because it is a native path to the |
| 564 // local read-only cached file in the case of remote file system like | 713 // local read-only cached file in the case of remote file system like |
| 565 // Chrome OS's Google Drive integration. Here, however, |file.file_path| is | 714 // Chrome OS's Google Drive integration. Here, however, |file.file_path| is |
| 566 // necessary because we need to create a FileEntry denoting the remote file, | 715 // necessary because we need to create a FileEntry denoting the remote file, |
| 567 // not its cache. On other platforms than Chrome OS, they are the same. | 716 // not its cache. On other platforms than Chrome OS, they are the same. |
| 568 // | 717 // |
| 569 // TODO(kinaba): remove this, once after the file picker implements proper | 718 // TODO(kinaba): remove this, once after the file picker implements proper |
| 570 // switch of the path treatment depending on the |support_drive| flag. | 719 // switch of the path treatment depending on the |support_drive| flag. |
| 571 function_->FileSelected(file.file_path, entry_type_); | 720 FileSelected(file.file_path, index, params); |
| 721 } | |
| 722 | |
| 723 virtual void MultiFilesSelected(const std::vector<base::FilePath>& files, | |
| 724 void* params) OVERRIDE { | |
| 725 function_->FilesSelected(files, entry_type_, multiple_); | |
| 572 delete this; | 726 delete this; |
| 573 } | 727 } |
| 574 | 728 |
| 729 virtual void MultiFilesSelectedWithExtraInfo( | |
| 730 const std::vector<ui::SelectedFileInfo>& files, | |
| 731 void* params) OVERRIDE { | |
| 732 std::vector<base::FilePath> paths; | |
| 733 for (std::vector<ui::SelectedFileInfo>::const_iterator it = files.begin(); | |
| 734 it != files.end(); ++it) { | |
| 735 paths.push_back(it->file_path); | |
| 736 } | |
| 737 MultiFilesSelected(paths, params); | |
| 738 } | |
| 739 | |
| 575 virtual void FileSelectionCanceled(void* params) OVERRIDE { | 740 virtual void FileSelectionCanceled(void* params) OVERRIDE { |
| 576 function_->FileSelectionCanceled(); | 741 function_->FileSelectionCanceled(); |
| 577 delete this; | 742 delete this; |
| 578 } | 743 } |
| 579 | 744 |
| 580 EntryType entry_type_; | 745 EntryType entry_type_; |
| 746 bool multiple_; | |
| 581 | 747 |
| 582 scoped_refptr<ui::SelectFileDialog> select_file_dialog_; | 748 scoped_refptr<ui::SelectFileDialog> select_file_dialog_; |
| 583 scoped_refptr<FileSystemChooseEntryFunction> function_; | 749 scoped_refptr<FileSystemChooseEntryFunction> function_; |
| 584 | 750 |
| 585 DISALLOW_COPY_AND_ASSIGN(FilePicker); | 751 DISALLOW_COPY_AND_ASSIGN(FilePicker); |
| 586 }; | 752 }; |
| 587 | 753 |
| 588 void FileSystemChooseEntryFunction::ShowPicker( | 754 void FileSystemChooseEntryFunction::ShowPicker( |
| 589 const ui::SelectFileDialog::FileTypeInfo& file_type_info, | 755 const ui::SelectFileDialog::FileTypeInfo& file_type_info, |
| 590 ui::SelectFileDialog::Type picker_type, | 756 ui::SelectFileDialog::Type picker_type, |
| 591 EntryType entry_type) { | 757 EntryType entry_type, |
| 758 bool multiple) { | |
| 592 // TODO(asargent/benwells) - As a short term remediation for crbug.com/179010 | 759 // TODO(asargent/benwells) - As a short term remediation for crbug.com/179010 |
| 593 // we're adding the ability for a whitelisted extension to use this API since | 760 // we're adding the ability for a whitelisted extension to use this API since |
| 594 // chrome.fileBrowserHandler.selectFile is ChromeOS-only. Eventually we'd | 761 // chrome.fileBrowserHandler.selectFile is ChromeOS-only. Eventually we'd |
| 595 // like a better solution and likely this code will go back to being | 762 // like a better solution and likely this code will go back to being |
| 596 // platform-app only. | 763 // platform-app only. |
| 597 content::WebContents* web_contents = NULL; | 764 content::WebContents* web_contents = NULL; |
| 598 if (extension_->is_platform_app()) { | 765 if (extension_->is_platform_app()) { |
| 599 ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile()); | 766 ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile()); |
| 600 DCHECK(registry); | 767 DCHECK(registry); |
| 601 ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost( | 768 ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost( |
| 602 render_view_host()); | 769 render_view_host()); |
| 603 if (!shell_window) { | 770 if (!shell_window) { |
| 604 error_ = kInvalidCallingPage; | 771 error_ = kInvalidCallingPage; |
| 605 SendResponse(false); | 772 SendResponse(false); |
| 606 return; | 773 return; |
| 607 } | 774 } |
| 608 web_contents = shell_window->web_contents(); | 775 web_contents = shell_window->web_contents(); |
| 609 } else { | 776 } else { |
| 610 web_contents = GetAssociatedWebContents(); | 777 web_contents = GetAssociatedWebContents(); |
| 611 } | 778 } |
| 612 // The file picker will hold a reference to this function instance, preventing | 779 // The file picker will hold a reference to this function instance, preventing |
| 613 // its destruction (and subsequent sending of the function response) until the | 780 // its destruction (and subsequent sending of the function response) until the |
| 614 // user has selected a file or cancelled the picker. At that point, the picker | 781 // user has selected a file or cancelled the picker. At that point, the picker |
| 615 // will delete itself, which will also free the function instance. | 782 // will delete itself, which will also free the function instance. |
| 616 new FilePicker(this, web_contents, initial_path_, file_type_info, | 783 new FilePicker(this, web_contents, initial_path_, file_type_info, |
| 617 picker_type, entry_type); | 784 picker_type, entry_type, multiple); |
| 618 } | 785 } |
| 619 | 786 |
| 620 // static | 787 // static |
| 621 void FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( | 788 void FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( |
| 622 base::FilePath* path) { | 789 base::FilePath* path) { |
| 623 g_skip_picker_for_test = true; | 790 g_skip_picker_for_test = true; |
| 624 g_use_suggested_path_for_test = false; | 791 g_use_suggested_path_for_test = false; |
| 625 g_path_to_be_picked_for_test = path; | 792 g_path_to_be_picked_for_test = path; |
| 793 g_paths_to_be_picked_for_test = NULL; | |
| 794 } | |
| 795 | |
| 796 void FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathsForTest( | |
| 797 std::vector<base::FilePath>* paths) { | |
| 798 g_skip_picker_for_test = true; | |
| 799 g_use_suggested_path_for_test = false; | |
| 800 g_paths_to_be_picked_for_test = paths; | |
| 626 } | 801 } |
| 627 | 802 |
| 628 // static | 803 // static |
| 629 void FileSystemChooseEntryFunction::SkipPickerAndSelectSuggestedPathForTest() { | 804 void FileSystemChooseEntryFunction::SkipPickerAndSelectSuggestedPathForTest() { |
| 630 g_skip_picker_for_test = true; | 805 g_skip_picker_for_test = true; |
| 631 g_use_suggested_path_for_test = true; | 806 g_use_suggested_path_for_test = true; |
| 632 g_path_to_be_picked_for_test = NULL; | 807 g_path_to_be_picked_for_test = NULL; |
| 808 g_paths_to_be_picked_for_test = NULL; | |
| 633 } | 809 } |
| 634 | 810 |
| 635 // static | 811 // static |
| 636 void FileSystemChooseEntryFunction::SkipPickerAndAlwaysCancelForTest() { | 812 void FileSystemChooseEntryFunction::SkipPickerAndAlwaysCancelForTest() { |
| 637 g_skip_picker_for_test = true; | 813 g_skip_picker_for_test = true; |
| 638 g_use_suggested_path_for_test = false; | 814 g_use_suggested_path_for_test = false; |
| 639 g_path_to_be_picked_for_test = NULL; | 815 g_path_to_be_picked_for_test = NULL; |
| 816 g_paths_to_be_picked_for_test = NULL; | |
| 640 } | 817 } |
| 641 | 818 |
| 642 // static | 819 // static |
| 643 void FileSystemChooseEntryFunction::StopSkippingPickerForTest() { | 820 void FileSystemChooseEntryFunction::StopSkippingPickerForTest() { |
| 644 g_skip_picker_for_test = false; | 821 g_skip_picker_for_test = false; |
| 645 } | 822 } |
| 646 | 823 |
| 647 // static | 824 // static |
| 648 void FileSystemChooseEntryFunction::RegisterTempExternalFileSystemForTest( | 825 void FileSystemChooseEntryFunction::RegisterTempExternalFileSystemForTest( |
| 649 const std::string& name, const base::FilePath& path) { | 826 const std::string& name, const base::FilePath& path) { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 663 } else { | 840 } else { |
| 664 base::FilePath documents_dir; | 841 base::FilePath documents_dir; |
| 665 if (PathService::Get(chrome::DIR_USER_DOCUMENTS, &documents_dir)) { | 842 if (PathService::Get(chrome::DIR_USER_DOCUMENTS, &documents_dir)) { |
| 666 initial_path_ = documents_dir.Append(suggested_name); | 843 initial_path_ = documents_dir.Append(suggested_name); |
| 667 } else { | 844 } else { |
| 668 initial_path_ = suggested_name; | 845 initial_path_ = suggested_name; |
| 669 } | 846 } |
| 670 } | 847 } |
| 671 } | 848 } |
| 672 | 849 |
| 673 void FileSystemChooseEntryFunction::FileSelected(const base::FilePath& path, | 850 void FileSystemChooseEntryFunction::FilesSelected( |
| 674 EntryType entry_type) { | 851 const std::vector<base::FilePath>& paths, |
| 852 EntryType entry_type, | |
| 853 bool multiple) { | |
| 675 file_system_api::SetLastChooseEntryDirectory( | 854 file_system_api::SetLastChooseEntryDirectory( |
| 676 ExtensionPrefs::Get(profile()), | 855 ExtensionPrefs::Get(profile()), GetExtension()->id(), paths[0].DirName()); |
| 677 GetExtension()->id(), | |
| 678 path.DirName()); | |
| 679 if (entry_type == WRITABLE) { | 856 if (entry_type == WRITABLE) { |
| 680 CheckWritableFile(path); | 857 CheckWritableFiles(paths, multiple); |
| 681 return; | 858 return; |
| 682 } | 859 } |
| 683 | 860 |
| 684 // Don't need to check the file, it's for reading. | 861 // Don't need to check the file, it's for reading. |
| 685 RegisterFileSystemAndSendResponse(path, READ_ONLY); | 862 RegisterFileSystemsAndSendResponse(paths, READ_ONLY, multiple); |
| 686 } | 863 } |
| 687 | 864 |
| 688 void FileSystemChooseEntryFunction::FileSelectionCanceled() { | 865 void FileSystemChooseEntryFunction::FileSelectionCanceled() { |
| 689 error_ = kUserCancelled; | 866 error_ = kUserCancelled; |
| 690 SendResponse(false); | 867 SendResponse(false); |
| 691 } | 868 } |
| 692 | 869 |
| 693 void FileSystemChooseEntryFunction::BuildFileTypeInfo( | 870 void FileSystemChooseEntryFunction::BuildFileTypeInfo( |
| 694 ui::SelectFileDialog::FileTypeInfo* file_type_info, | 871 ui::SelectFileDialog::FileTypeInfo* file_type_info, |
| 695 const base::FilePath::StringType& suggested_extension, | 872 const base::FilePath::StringType& suggested_extension, |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 754 scoped_ptr<ChooseEntry::Params> params(ChooseEntry::Params::Create(*args_)); | 931 scoped_ptr<ChooseEntry::Params> params(ChooseEntry::Params::Create(*args_)); |
| 755 EXTENSION_FUNCTION_VALIDATE(params.get()); | 932 EXTENSION_FUNCTION_VALIDATE(params.get()); |
| 756 | 933 |
| 757 base::FilePath suggested_name; | 934 base::FilePath suggested_name; |
| 758 ui::SelectFileDialog::FileTypeInfo file_type_info; | 935 ui::SelectFileDialog::FileTypeInfo file_type_info; |
| 759 EntryType entry_type = READ_ONLY; | 936 EntryType entry_type = READ_ONLY; |
| 760 ui::SelectFileDialog::Type picker_type = | 937 ui::SelectFileDialog::Type picker_type = |
| 761 ui::SelectFileDialog::SELECT_OPEN_FILE; | 938 ui::SelectFileDialog::SELECT_OPEN_FILE; |
| 762 | 939 |
| 763 file_system::ChooseEntryOptions* options = params->options.get(); | 940 file_system::ChooseEntryOptions* options = params->options.get(); |
| 941 bool multiple = false; | |
| 764 if (options) { | 942 if (options) { |
| 943 multiple = options->accepts_multiple; | |
| 944 if (multiple) | |
| 945 picker_type = ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE; | |
| 765 if (options->type == file_system::CHOOSE_ENTRY_TYPE_OPENWRITABLEFILE) { | 946 if (options->type == file_system::CHOOSE_ENTRY_TYPE_OPENWRITABLEFILE) { |
| 766 entry_type = WRITABLE; | 947 entry_type = WRITABLE; |
| 767 } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_SAVEFILE) { | 948 } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_SAVEFILE) { |
| 949 if (multiple) { | |
| 950 error_ = kMultipleUnsupportedError; | |
| 951 return false; | |
| 952 } | |
| 768 entry_type = WRITABLE; | 953 entry_type = WRITABLE; |
| 769 picker_type = ui::SelectFileDialog::SELECT_SAVEAS_FILE; | 954 picker_type = ui::SelectFileDialog::SELECT_SAVEAS_FILE; |
| 770 } | 955 } |
| 771 | 956 |
| 772 base::FilePath::StringType suggested_extension; | 957 base::FilePath::StringType suggested_extension; |
| 773 BuildSuggestion(options->suggested_name.get(), &suggested_name, | 958 BuildSuggestion(options->suggested_name.get(), &suggested_name, |
| 774 &suggested_extension); | 959 &suggested_extension); |
| 775 | 960 |
| 776 BuildFileTypeInfo(&file_type_info, suggested_extension, | 961 BuildFileTypeInfo(&file_type_info, suggested_extension, |
| 777 options->accepts.get(), options->accepts_all_types.get()); | 962 options->accepts.get(), options->accepts_all_types.get()); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 791 &previous_path); | 976 &previous_path); |
| 792 | 977 |
| 793 content::BrowserThread::PostTaskAndReply( | 978 content::BrowserThread::PostTaskAndReply( |
| 794 content::BrowserThread::FILE, | 979 content::BrowserThread::FILE, |
| 795 FROM_HERE, | 980 FROM_HERE, |
| 796 base::Bind( | 981 base::Bind( |
| 797 &FileSystemChooseEntryFunction::SetInitialPathOnFileThread, this, | 982 &FileSystemChooseEntryFunction::SetInitialPathOnFileThread, this, |
| 798 suggested_name, previous_path), | 983 suggested_name, previous_path), |
| 799 base::Bind( | 984 base::Bind( |
| 800 &FileSystemChooseEntryFunction::ShowPicker, this, file_type_info, | 985 &FileSystemChooseEntryFunction::ShowPicker, this, file_type_info, |
| 801 picker_type, entry_type)); | 986 picker_type, entry_type, multiple)); |
| 802 return true; | 987 return true; |
| 803 } | 988 } |
| 804 | 989 |
| 805 bool FileSystemRetainEntryFunction::RunImpl() { | 990 bool FileSystemRetainEntryFunction::RunImpl() { |
| 806 std::string entry_id; | 991 std::string entry_id; |
| 807 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); | 992 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); |
| 808 SavedFilesService* saved_files_service = SavedFilesService::Get(profile()); | 993 SavedFilesService* saved_files_service = SavedFilesService::Get(profile()); |
| 809 // Add the file to the retain list if it is not already on there. | 994 // Add the file to the retain list if it is not already on there. |
| 810 if (!saved_files_service->IsRegistered(extension_->id(), entry_id) && | 995 if (!saved_files_service->IsRegistered(extension_->id(), entry_id) && |
| 811 !RetainFileEntry(entry_id)) { | 996 !RetainFileEntry(entry_id)) { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 872 // ID that was passed to restoreEntry. | 1057 // ID that was passed to restoreEntry. |
| 873 RegisterFileSystemAndSendResponseWithIdOverride( | 1058 RegisterFileSystemAndSendResponseWithIdOverride( |
| 874 file_entry->path, | 1059 file_entry->path, |
| 875 file_entry->writable ? WRITABLE : READ_ONLY, | 1060 file_entry->writable ? WRITABLE : READ_ONLY, |
| 876 file_entry->id); | 1061 file_entry->id); |
| 877 } | 1062 } |
| 878 return true; | 1063 return true; |
| 879 } | 1064 } |
| 880 | 1065 |
| 881 } // namespace extensions | 1066 } // namespace extensions |
| OLD | NEW |