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 // posts a task to run AllTasksDone on the UI thread. |
| 319 void TaskDone() { |
| 320 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
| 321 if (--outstanding_tasks_ == 0) { |
| 322 content::BrowserThread::PostTask( |
| 323 content::BrowserThread::UI, |
| 324 FROM_HERE, |
| 325 base::Bind(&WritableFileChecker::AllTasksDone, this)); |
| 326 } |
| 327 } |
| 328 |
| 329 // Called on the UI thread when all tasks are done. |
| 330 void AllTasksDone() { |
| 331 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 332 if (error_.empty()) |
| 333 on_success_.Run(); |
| 334 else |
| 335 on_failure_.Run(error_); |
| 336 } |
| 337 |
| 338 // Reports an error in completing a work item. This may be called more than |
| 339 // once, but only the last message will be retained. |
| 340 void Error(const std::string& message) { |
| 341 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
| 342 DCHECK(!message.empty()); |
| 343 error_ = message; |
| 344 TaskDone(); |
| 345 } |
| 346 |
| 347 void CheckLocalWritableFiles(const std::vector<base::FilePath>& paths) { |
| 348 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
| 349 std::string error; |
| 350 for (std::vector<base::FilePath>::const_iterator it = paths.begin(); |
| 351 it != paths.end(); ++it) { |
| 352 if (!DoCheckWritableFile(*it, extension_path_, &error)) { |
| 353 Error(error); |
| 354 return; |
| 355 } |
| 356 } |
| 357 TaskDone(); |
| 358 } |
266 | 359 |
267 #if defined(OS_CHROMEOS) | 360 #if defined(OS_CHROMEOS) |
268 void CheckRemoteWritableFile(const base::Closure& on_success, | 361 void CheckRemoteWritableFile(drive::FileError error, |
269 const base::Closure& on_failure, | 362 const base::FilePath& path) { |
270 drive::FileError error, | 363 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
271 const base::FilePath& path) { | 364 if (error == drive::FILE_ERROR_OK) { |
272 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | 365 TaskDone(); |
273 error == drive::FILE_ERROR_OK ? on_success : on_failure); | 366 } else { |
274 } | 367 Error(base::StringPrintf(kWritableFileErrorFormat, |
| 368 path.BaseName().AsUTF8Unsafe().c_str())); |
| 369 } |
| 370 } |
275 #endif | 371 #endif |
276 | 372 |
| 373 int outstanding_tasks_; |
| 374 const base::FilePath extension_path_; |
| 375 std::string error_; |
| 376 base::Closure on_success_; |
| 377 base::Callback<void(const std::string&)> on_failure_; |
| 378 }; |
| 379 |
277 // Expand the mime-types and extensions provided in an AcceptOption, returning | 380 // Expand the mime-types and extensions provided in an AcceptOption, returning |
278 // them within the passed extension vector. Returns false if no valid types | 381 // them within the passed extension vector. Returns false if no valid types |
279 // were found. | 382 // were found. |
280 bool GetFileTypesFromAcceptOption( | 383 bool GetFileTypesFromAcceptOption( |
281 const file_system::AcceptOption& accept_option, | 384 const file_system::AcceptOption& accept_option, |
282 std::vector<base::FilePath::StringType>* extensions, | 385 std::vector<base::FilePath::StringType>* extensions, |
283 string16* description) { | 386 string16* description) { |
284 std::set<base::FilePath::StringType> extension_set; | 387 std::set<base::FilePath::StringType> extension_set; |
285 int description_id = 0; | 388 int description_id = 0; |
286 | 389 |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 base::FilePath file_path; | 483 base::FilePath file_path; |
381 if (!GetFilePathOfFileEntry(filesystem_name, filesystem_path, | 484 if (!GetFilePathOfFileEntry(filesystem_name, filesystem_path, |
382 render_view_host_, &file_path, &error_)) | 485 render_view_host_, &file_path, &error_)) |
383 return false; | 486 return false; |
384 | 487 |
385 file_path = PrettifyPath(file_path); | 488 file_path = PrettifyPath(file_path); |
386 SetResult(base::Value::CreateStringValue(file_path.value())); | 489 SetResult(base::Value::CreateStringValue(file_path.value())); |
387 return true; | 490 return true; |
388 } | 491 } |
389 | 492 |
| 493 FileSystemEntryFunction::FileSystemEntryFunction() |
| 494 : multiple_(false), |
| 495 entry_type_(READ_ONLY), |
| 496 response_(NULL) {} |
| 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::CheckWritableFiles( |
| 507 const std::vector<base::FilePath>& paths) { |
399 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 508 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
400 base::Closure on_success = | 509 scoped_refptr<WritableFileChecker> helper = new WritableFileChecker( |
401 base::Bind(&FileSystemEntryFunction::RegisterFileSystemAndSendResponse, | 510 paths, profile_, extension_->path(), |
402 this, path, WRITABLE); | 511 base::Bind( |
403 base::Closure on_failure = | 512 &FileSystemEntryFunction::RegisterFileSystemsAndSendResponse, |
404 base::Bind(&FileSystemEntryFunction::HandleWritableFileError, this); | 513 this, paths), |
405 | 514 base::Bind(&FileSystemEntryFunction::HandleWritableFileError, this)); |
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 } | 515 } |
417 | 516 |
418 void FileSystemEntryFunction::RegisterFileSystemAndSendResponse( | 517 void FileSystemEntryFunction::RegisterFileSystemsAndSendResponse( |
419 const base::FilePath& path, EntryType entry_type) { | 518 const std::vector<base::FilePath>& paths) { |
420 RegisterFileSystemAndSendResponseWithIdOverride(path, entry_type, ""); | |
421 } | |
422 | |
423 void FileSystemEntryFunction::RegisterFileSystemAndSendResponseWithIdOverride( | |
424 const base::FilePath& path, EntryType entry_type, const std::string& id) { | |
425 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 519 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
426 | 520 |
427 fileapi::IsolatedContext* isolated_context = | 521 CreateResponse(); |
428 fileapi::IsolatedContext::GetInstance(); | 522 for (std::vector<base::FilePath>::const_iterator it = paths.begin(); |
429 DCHECK(isolated_context); | 523 it != paths.end(); ++it) { |
430 | 524 AddEntryToResponse(*it, ""); |
431 bool writable = entry_type == WRITABLE; | 525 } |
432 extensions::app_file_handler_util::GrantedFileEntry file_entry = | |
433 extensions::app_file_handler_util::CreateFileEntry(profile(), | |
434 GetExtension()->id(), render_view_host_->GetProcess()->GetID(), path, | |
435 writable); | |
436 | |
437 base::DictionaryValue* dict = new base::DictionaryValue(); | |
438 SetResult(dict); | |
439 dict->SetString("fileSystemId", file_entry.filesystem_id); | |
440 dict->SetString("baseName", file_entry.registered_name); | |
441 if (id.empty()) | |
442 dict->SetString("id", file_entry.id); | |
443 else | |
444 dict->SetString("id", id); | |
445 | |
446 SendResponse(true); | 526 SendResponse(true); |
447 } | 527 } |
448 | 528 |
449 void FileSystemEntryFunction::HandleWritableFileError() { | 529 void FileSystemEntryFunction::CreateResponse() { |
| 530 DCHECK(!response_); |
| 531 response_ = new base::DictionaryValue(); |
| 532 base::ListValue* list = new base::ListValue(); |
| 533 response_->Set("entries", list); |
| 534 response_->SetBoolean("multiple", multiple_); |
| 535 SetResult(response_); |
| 536 } |
| 537 |
| 538 void FileSystemEntryFunction::AddEntryToResponse( |
| 539 const base::FilePath& path, |
| 540 const std::string& id_override) { |
| 541 DCHECK(response_); |
| 542 bool writable = entry_type_ == WRITABLE; |
| 543 extensions::app_file_handler_util::GrantedFileEntry file_entry = |
| 544 extensions::app_file_handler_util::CreateFileEntry( |
| 545 profile(), |
| 546 GetExtension()->id(), |
| 547 render_view_host_->GetProcess()->GetID(), |
| 548 path, |
| 549 writable); |
| 550 base::ListValue* entries; |
| 551 bool success = response_->GetList("entries", &entries); |
| 552 DCHECK(success); |
| 553 |
| 554 base::DictionaryValue* entry = new base::DictionaryValue(); |
| 555 entry->SetString("fileSystemId", file_entry.filesystem_id); |
| 556 entry->SetString("baseName", file_entry.registered_name); |
| 557 if (id_override.empty()) |
| 558 entry->SetString("id", file_entry.id); |
| 559 else |
| 560 entry->SetString("id", id_override); |
| 561 entries->Append(entry); |
| 562 } |
| 563 |
| 564 void FileSystemEntryFunction::HandleWritableFileError( |
| 565 const std::string& error) { |
450 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 566 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
451 error_ = kWritableFileError; | 567 error_ = error; |
452 SendResponse(false); | 568 SendResponse(false); |
453 } | 569 } |
454 | 570 |
455 bool FileSystemGetWritableEntryFunction::RunImpl() { | 571 bool FileSystemGetWritableEntryFunction::RunImpl() { |
456 std::string filesystem_name; | 572 std::string filesystem_name; |
457 std::string filesystem_path; | 573 std::string filesystem_path; |
458 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); | 574 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); |
459 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); | 575 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); |
460 | 576 |
461 if (!HasFileSystemWritePermission()) { | 577 if (!HasFileSystemWritePermission()) { |
462 error_ = kRequiresFileSystemWriteError; | 578 error_ = kRequiresFileSystemWriteError; |
463 return false; | 579 return false; |
464 } | 580 } |
| 581 entry_type_ = WRITABLE; |
465 | 582 |
466 base::FilePath path; | 583 base::FilePath path; |
467 if (!GetFilePathOfFileEntry(filesystem_name, filesystem_path, | 584 if (!GetFilePathOfFileEntry(filesystem_name, filesystem_path, |
468 render_view_host_, &path, &error_)) | 585 render_view_host_, &path, &error_)) |
469 return false; | 586 return false; |
470 | 587 |
471 CheckWritableFile(path); | 588 std::vector<base::FilePath> paths; |
| 589 paths.push_back(path); |
| 590 CheckWritableFiles(paths); |
472 return true; | 591 return true; |
473 } | 592 } |
474 | 593 |
475 bool FileSystemIsWritableEntryFunction::RunImpl() { | 594 bool FileSystemIsWritableEntryFunction::RunImpl() { |
476 std::string filesystem_name; | 595 std::string filesystem_name; |
477 std::string filesystem_path; | 596 std::string filesystem_path; |
478 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); | 597 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); |
479 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); | 598 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); |
480 | 599 |
481 std::string filesystem_id; | 600 std::string filesystem_id; |
(...skipping 14 matching lines...) Expand all Loading... |
496 | 615 |
497 // Handles showing a dialog to the user to ask for the filename for a file to | 616 // Handles showing a dialog to the user to ask for the filename for a file to |
498 // save or open. | 617 // save or open. |
499 class FileSystemChooseEntryFunction::FilePicker | 618 class FileSystemChooseEntryFunction::FilePicker |
500 : public ui::SelectFileDialog::Listener { | 619 : public ui::SelectFileDialog::Listener { |
501 public: | 620 public: |
502 FilePicker(FileSystemChooseEntryFunction* function, | 621 FilePicker(FileSystemChooseEntryFunction* function, |
503 content::WebContents* web_contents, | 622 content::WebContents* web_contents, |
504 const base::FilePath& suggested_name, | 623 const base::FilePath& suggested_name, |
505 const ui::SelectFileDialog::FileTypeInfo& file_type_info, | 624 const ui::SelectFileDialog::FileTypeInfo& file_type_info, |
506 ui::SelectFileDialog::Type picker_type, | 625 ui::SelectFileDialog::Type picker_type) |
507 EntryType entry_type) | 626 : function_(function) { |
508 : entry_type_(entry_type), | |
509 function_(function) { | |
510 select_file_dialog_ = ui::SelectFileDialog::Create( | 627 select_file_dialog_ = ui::SelectFileDialog::Create( |
511 this, new ChromeSelectFilePolicy(web_contents)); | 628 this, new ChromeSelectFilePolicy(web_contents)); |
512 gfx::NativeWindow owning_window = web_contents ? | 629 gfx::NativeWindow owning_window = web_contents ? |
513 platform_util::GetTopLevel(web_contents->GetView()->GetNativeView()) : | 630 platform_util::GetTopLevel(web_contents->GetView()->GetNativeView()) : |
514 NULL; | 631 NULL; |
515 | 632 |
516 if (g_skip_picker_for_test) { | 633 if (g_skip_picker_for_test) { |
517 if (g_use_suggested_path_for_test) { | 634 if (g_use_suggested_path_for_test) { |
518 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | 635 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, |
519 base::Bind( | 636 base::Bind( |
520 &FileSystemChooseEntryFunction::FilePicker::FileSelected, | 637 &FileSystemChooseEntryFunction::FilePicker::FileSelected, |
521 base::Unretained(this), suggested_name, 1, | 638 base::Unretained(this), suggested_name, 1, |
522 static_cast<void*>(NULL))); | 639 static_cast<void*>(NULL))); |
523 } else if (g_path_to_be_picked_for_test) { | 640 } else if (g_path_to_be_picked_for_test) { |
524 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | 641 content::BrowserThread::PostTask( |
| 642 content::BrowserThread::UI, FROM_HERE, |
525 base::Bind( | 643 base::Bind( |
526 &FileSystemChooseEntryFunction::FilePicker::FileSelected, | 644 &FileSystemChooseEntryFunction::FilePicker::FileSelected, |
527 base::Unretained(this), *g_path_to_be_picked_for_test, 1, | 645 base::Unretained(this), *g_path_to_be_picked_for_test, 1, |
528 static_cast<void*>(NULL))); | 646 static_cast<void*>(NULL))); |
| 647 } else if (g_paths_to_be_picked_for_test) { |
| 648 content::BrowserThread::PostTask( |
| 649 content::BrowserThread::UI, |
| 650 FROM_HERE, |
| 651 base::Bind( |
| 652 &FileSystemChooseEntryFunction::FilePicker::MultiFilesSelected, |
| 653 base::Unretained(this), |
| 654 *g_paths_to_be_picked_for_test, |
| 655 static_cast<void*>(NULL))); |
529 } else { | 656 } else { |
530 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | 657 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, |
531 base::Bind( | 658 base::Bind( |
532 &FileSystemChooseEntryFunction::FilePicker:: | 659 &FileSystemChooseEntryFunction::FilePicker:: |
533 FileSelectionCanceled, | 660 FileSelectionCanceled, |
534 base::Unretained(this), static_cast<void*>(NULL))); | 661 base::Unretained(this), static_cast<void*>(NULL))); |
535 } | 662 } |
536 return; | 663 return; |
537 } | 664 } |
538 | 665 |
539 select_file_dialog_->SelectFile(picker_type, | 666 select_file_dialog_->SelectFile(picker_type, |
540 string16(), | 667 string16(), |
541 suggested_name, | 668 suggested_name, |
542 &file_type_info, | 669 &file_type_info, |
543 0, | 670 0, |
544 base::FilePath::StringType(), | 671 base::FilePath::StringType(), |
545 owning_window, | 672 owning_window, |
546 NULL); | 673 NULL); |
547 } | 674 } |
548 | 675 |
549 virtual ~FilePicker() {} | 676 virtual ~FilePicker() {} |
550 | 677 |
551 private: | 678 private: |
552 // ui::SelectFileDialog::Listener implementation. | 679 // ui::SelectFileDialog::Listener implementation. |
553 virtual void FileSelected(const base::FilePath& path, | 680 virtual void FileSelected(const base::FilePath& path, |
554 int index, | 681 int index, |
555 void* params) OVERRIDE { | 682 void* params) OVERRIDE { |
556 function_->FileSelected(path, entry_type_); | 683 std::vector<base::FilePath> paths; |
557 delete this; | 684 paths.push_back(path); |
| 685 MultiFilesSelected(paths, params); |
558 } | 686 } |
559 | 687 |
560 virtual void FileSelectedWithExtraInfo(const ui::SelectedFileInfo& file, | 688 virtual void FileSelectedWithExtraInfo(const ui::SelectedFileInfo& file, |
561 int index, | 689 int index, |
562 void* params) OVERRIDE { | 690 void* params) OVERRIDE { |
563 // Normally, file.local_path is used because it is a native path to the | 691 // 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 | 692 // 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 | 693 // 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, | 694 // 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. | 695 // not its cache. On other platforms than Chrome OS, they are the same. |
568 // | 696 // |
569 // TODO(kinaba): remove this, once after the file picker implements proper | 697 // TODO(kinaba): remove this, once after the file picker implements proper |
570 // switch of the path treatment depending on the |support_drive| flag. | 698 // switch of the path treatment depending on the |support_drive| flag. |
571 function_->FileSelected(file.file_path, entry_type_); | 699 FileSelected(file.file_path, index, params); |
| 700 } |
| 701 |
| 702 virtual void MultiFilesSelected(const std::vector<base::FilePath>& files, |
| 703 void* params) OVERRIDE { |
| 704 function_->FilesSelected(files); |
572 delete this; | 705 delete this; |
573 } | 706 } |
574 | 707 |
| 708 virtual void MultiFilesSelectedWithExtraInfo( |
| 709 const std::vector<ui::SelectedFileInfo>& files, |
| 710 void* params) OVERRIDE { |
| 711 std::vector<base::FilePath> paths; |
| 712 for (std::vector<ui::SelectedFileInfo>::const_iterator it = files.begin(); |
| 713 it != files.end(); ++it) { |
| 714 paths.push_back(it->file_path); |
| 715 } |
| 716 MultiFilesSelected(paths, params); |
| 717 } |
| 718 |
575 virtual void FileSelectionCanceled(void* params) OVERRIDE { | 719 virtual void FileSelectionCanceled(void* params) OVERRIDE { |
576 function_->FileSelectionCanceled(); | 720 function_->FileSelectionCanceled(); |
577 delete this; | 721 delete this; |
578 } | 722 } |
579 | 723 |
580 EntryType entry_type_; | |
581 | |
582 scoped_refptr<ui::SelectFileDialog> select_file_dialog_; | 724 scoped_refptr<ui::SelectFileDialog> select_file_dialog_; |
583 scoped_refptr<FileSystemChooseEntryFunction> function_; | 725 scoped_refptr<FileSystemChooseEntryFunction> function_; |
584 | 726 |
585 DISALLOW_COPY_AND_ASSIGN(FilePicker); | 727 DISALLOW_COPY_AND_ASSIGN(FilePicker); |
586 }; | 728 }; |
587 | 729 |
588 void FileSystemChooseEntryFunction::ShowPicker( | 730 void FileSystemChooseEntryFunction::ShowPicker( |
589 const ui::SelectFileDialog::FileTypeInfo& file_type_info, | 731 const ui::SelectFileDialog::FileTypeInfo& file_type_info, |
590 ui::SelectFileDialog::Type picker_type, | 732 ui::SelectFileDialog::Type picker_type) { |
591 EntryType entry_type) { | |
592 // TODO(asargent/benwells) - As a short term remediation for crbug.com/179010 | 733 // 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 | 734 // we're adding the ability for a whitelisted extension to use this API since |
594 // chrome.fileBrowserHandler.selectFile is ChromeOS-only. Eventually we'd | 735 // chrome.fileBrowserHandler.selectFile is ChromeOS-only. Eventually we'd |
595 // like a better solution and likely this code will go back to being | 736 // like a better solution and likely this code will go back to being |
596 // platform-app only. | 737 // platform-app only. |
597 content::WebContents* web_contents = NULL; | 738 content::WebContents* web_contents = NULL; |
598 if (extension_->is_platform_app()) { | 739 if (extension_->is_platform_app()) { |
599 ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile()); | 740 ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile()); |
600 DCHECK(registry); | 741 DCHECK(registry); |
601 ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost( | 742 ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost( |
602 render_view_host()); | 743 render_view_host()); |
603 if (!shell_window) { | 744 if (!shell_window) { |
604 error_ = kInvalidCallingPage; | 745 error_ = kInvalidCallingPage; |
605 SendResponse(false); | 746 SendResponse(false); |
606 return; | 747 return; |
607 } | 748 } |
608 web_contents = shell_window->web_contents(); | 749 web_contents = shell_window->web_contents(); |
609 } else { | 750 } else { |
610 web_contents = GetAssociatedWebContents(); | 751 web_contents = GetAssociatedWebContents(); |
611 } | 752 } |
612 // The file picker will hold a reference to this function instance, preventing | 753 // The file picker will hold a reference to this function instance, preventing |
613 // its destruction (and subsequent sending of the function response) until the | 754 // 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 | 755 // 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. | 756 // will delete itself, which will also free the function instance. |
616 new FilePicker(this, web_contents, initial_path_, file_type_info, | 757 new FilePicker( |
617 picker_type, entry_type); | 758 this, web_contents, initial_path_, file_type_info, picker_type); |
618 } | 759 } |
619 | 760 |
620 // static | 761 // static |
621 void FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( | 762 void FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( |
622 base::FilePath* path) { | 763 base::FilePath* path) { |
623 g_skip_picker_for_test = true; | 764 g_skip_picker_for_test = true; |
624 g_use_suggested_path_for_test = false; | 765 g_use_suggested_path_for_test = false; |
625 g_path_to_be_picked_for_test = path; | 766 g_path_to_be_picked_for_test = path; |
| 767 g_paths_to_be_picked_for_test = NULL; |
| 768 } |
| 769 |
| 770 void FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathsForTest( |
| 771 std::vector<base::FilePath>* paths) { |
| 772 g_skip_picker_for_test = true; |
| 773 g_use_suggested_path_for_test = false; |
| 774 g_paths_to_be_picked_for_test = paths; |
626 } | 775 } |
627 | 776 |
628 // static | 777 // static |
629 void FileSystemChooseEntryFunction::SkipPickerAndSelectSuggestedPathForTest() { | 778 void FileSystemChooseEntryFunction::SkipPickerAndSelectSuggestedPathForTest() { |
630 g_skip_picker_for_test = true; | 779 g_skip_picker_for_test = true; |
631 g_use_suggested_path_for_test = true; | 780 g_use_suggested_path_for_test = true; |
632 g_path_to_be_picked_for_test = NULL; | 781 g_path_to_be_picked_for_test = NULL; |
| 782 g_paths_to_be_picked_for_test = NULL; |
633 } | 783 } |
634 | 784 |
635 // static | 785 // static |
636 void FileSystemChooseEntryFunction::SkipPickerAndAlwaysCancelForTest() { | 786 void FileSystemChooseEntryFunction::SkipPickerAndAlwaysCancelForTest() { |
637 g_skip_picker_for_test = true; | 787 g_skip_picker_for_test = true; |
638 g_use_suggested_path_for_test = false; | 788 g_use_suggested_path_for_test = false; |
639 g_path_to_be_picked_for_test = NULL; | 789 g_path_to_be_picked_for_test = NULL; |
| 790 g_paths_to_be_picked_for_test = NULL; |
640 } | 791 } |
641 | 792 |
642 // static | 793 // static |
643 void FileSystemChooseEntryFunction::StopSkippingPickerForTest() { | 794 void FileSystemChooseEntryFunction::StopSkippingPickerForTest() { |
644 g_skip_picker_for_test = false; | 795 g_skip_picker_for_test = false; |
645 } | 796 } |
646 | 797 |
647 // static | 798 // static |
648 void FileSystemChooseEntryFunction::RegisterTempExternalFileSystemForTest( | 799 void FileSystemChooseEntryFunction::RegisterTempExternalFileSystemForTest( |
649 const std::string& name, const base::FilePath& path) { | 800 const std::string& name, const base::FilePath& path) { |
(...skipping 13 matching lines...) Expand all Loading... |
663 } else { | 814 } else { |
664 base::FilePath documents_dir; | 815 base::FilePath documents_dir; |
665 if (PathService::Get(chrome::DIR_USER_DOCUMENTS, &documents_dir)) { | 816 if (PathService::Get(chrome::DIR_USER_DOCUMENTS, &documents_dir)) { |
666 initial_path_ = documents_dir.Append(suggested_name); | 817 initial_path_ = documents_dir.Append(suggested_name); |
667 } else { | 818 } else { |
668 initial_path_ = suggested_name; | 819 initial_path_ = suggested_name; |
669 } | 820 } |
670 } | 821 } |
671 } | 822 } |
672 | 823 |
673 void FileSystemChooseEntryFunction::FileSelected(const base::FilePath& path, | 824 void FileSystemChooseEntryFunction::FilesSelected( |
674 EntryType entry_type) { | 825 const std::vector<base::FilePath>& paths) { |
| 826 DCHECK(!paths.empty()); |
675 file_system_api::SetLastChooseEntryDirectory( | 827 file_system_api::SetLastChooseEntryDirectory( |
676 ExtensionPrefs::Get(profile()), | 828 ExtensionPrefs::Get(profile()), GetExtension()->id(), paths[0].DirName()); |
677 GetExtension()->id(), | 829 if (entry_type_ == WRITABLE) { |
678 path.DirName()); | 830 CheckWritableFiles(paths); |
679 if (entry_type == WRITABLE) { | |
680 CheckWritableFile(path); | |
681 return; | 831 return; |
682 } | 832 } |
683 | 833 |
684 // Don't need to check the file, it's for reading. | 834 // Don't need to check the file, it's for reading. |
685 RegisterFileSystemAndSendResponse(path, READ_ONLY); | 835 RegisterFileSystemsAndSendResponse(paths); |
686 } | 836 } |
687 | 837 |
688 void FileSystemChooseEntryFunction::FileSelectionCanceled() { | 838 void FileSystemChooseEntryFunction::FileSelectionCanceled() { |
689 error_ = kUserCancelled; | 839 error_ = kUserCancelled; |
690 SendResponse(false); | 840 SendResponse(false); |
691 } | 841 } |
692 | 842 |
693 void FileSystemChooseEntryFunction::BuildFileTypeInfo( | 843 void FileSystemChooseEntryFunction::BuildFileTypeInfo( |
694 ui::SelectFileDialog::FileTypeInfo* file_type_info, | 844 ui::SelectFileDialog::FileTypeInfo* file_type_info, |
695 const base::FilePath::StringType& suggested_extension, | 845 const base::FilePath::StringType& suggested_extension, |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
749 suggested_extension->erase(suggested_extension->begin()); // drop the . | 899 suggested_extension->erase(suggested_extension->begin()); // drop the . |
750 } | 900 } |
751 } | 901 } |
752 | 902 |
753 bool FileSystemChooseEntryFunction::RunImpl() { | 903 bool FileSystemChooseEntryFunction::RunImpl() { |
754 scoped_ptr<ChooseEntry::Params> params(ChooseEntry::Params::Create(*args_)); | 904 scoped_ptr<ChooseEntry::Params> params(ChooseEntry::Params::Create(*args_)); |
755 EXTENSION_FUNCTION_VALIDATE(params.get()); | 905 EXTENSION_FUNCTION_VALIDATE(params.get()); |
756 | 906 |
757 base::FilePath suggested_name; | 907 base::FilePath suggested_name; |
758 ui::SelectFileDialog::FileTypeInfo file_type_info; | 908 ui::SelectFileDialog::FileTypeInfo file_type_info; |
759 EntryType entry_type = READ_ONLY; | |
760 ui::SelectFileDialog::Type picker_type = | 909 ui::SelectFileDialog::Type picker_type = |
761 ui::SelectFileDialog::SELECT_OPEN_FILE; | 910 ui::SelectFileDialog::SELECT_OPEN_FILE; |
762 | 911 |
763 file_system::ChooseEntryOptions* options = params->options.get(); | 912 file_system::ChooseEntryOptions* options = params->options.get(); |
764 if (options) { | 913 if (options) { |
| 914 multiple_ = options->accepts_multiple; |
| 915 if (multiple_) |
| 916 picker_type = ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE; |
765 if (options->type == file_system::CHOOSE_ENTRY_TYPE_OPENWRITABLEFILE) { | 917 if (options->type == file_system::CHOOSE_ENTRY_TYPE_OPENWRITABLEFILE) { |
766 entry_type = WRITABLE; | 918 entry_type_ = WRITABLE; |
767 } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_SAVEFILE) { | 919 } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_SAVEFILE) { |
768 entry_type = WRITABLE; | 920 if (multiple_) { |
| 921 error_ = kMultipleUnsupportedError; |
| 922 return false; |
| 923 } |
| 924 entry_type_ = WRITABLE; |
769 picker_type = ui::SelectFileDialog::SELECT_SAVEAS_FILE; | 925 picker_type = ui::SelectFileDialog::SELECT_SAVEAS_FILE; |
770 } | 926 } |
771 | 927 |
772 base::FilePath::StringType suggested_extension; | 928 base::FilePath::StringType suggested_extension; |
773 BuildSuggestion(options->suggested_name.get(), &suggested_name, | 929 BuildSuggestion(options->suggested_name.get(), &suggested_name, |
774 &suggested_extension); | 930 &suggested_extension); |
775 | 931 |
776 BuildFileTypeInfo(&file_type_info, suggested_extension, | 932 BuildFileTypeInfo(&file_type_info, suggested_extension, |
777 options->accepts.get(), options->accepts_all_types.get()); | 933 options->accepts.get(), options->accepts_all_types.get()); |
778 } | 934 } |
779 | 935 |
780 if (entry_type == WRITABLE && !HasFileSystemWritePermission()) { | 936 if (entry_type_ == WRITABLE && !HasFileSystemWritePermission()) { |
781 error_ = kRequiresFileSystemWriteError; | 937 error_ = kRequiresFileSystemWriteError; |
782 return false; | 938 return false; |
783 } | 939 } |
784 | 940 |
785 file_type_info.support_drive = true; | 941 file_type_info.support_drive = true; |
786 | 942 |
787 base::FilePath previous_path; | 943 base::FilePath previous_path; |
788 file_system_api::GetLastChooseEntryDirectory( | 944 file_system_api::GetLastChooseEntryDirectory( |
789 ExtensionPrefs::Get(profile()), | 945 ExtensionPrefs::Get(profile()), |
790 GetExtension()->id(), | 946 GetExtension()->id(), |
791 &previous_path); | 947 &previous_path); |
792 | 948 |
793 content::BrowserThread::PostTaskAndReply( | 949 content::BrowserThread::PostTaskAndReply( |
794 content::BrowserThread::FILE, | 950 content::BrowserThread::FILE, |
795 FROM_HERE, | 951 FROM_HERE, |
796 base::Bind( | 952 base::Bind( |
797 &FileSystemChooseEntryFunction::SetInitialPathOnFileThread, this, | 953 &FileSystemChooseEntryFunction::SetInitialPathOnFileThread, this, |
798 suggested_name, previous_path), | 954 suggested_name, previous_path), |
799 base::Bind( | 955 base::Bind( |
800 &FileSystemChooseEntryFunction::ShowPicker, this, file_type_info, | 956 &FileSystemChooseEntryFunction::ShowPicker, this, file_type_info, |
801 picker_type, entry_type)); | 957 picker_type)); |
802 return true; | 958 return true; |
803 } | 959 } |
804 | 960 |
805 bool FileSystemRetainEntryFunction::RunImpl() { | 961 bool FileSystemRetainEntryFunction::RunImpl() { |
806 std::string entry_id; | 962 std::string entry_id; |
807 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); | 963 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); |
808 SavedFilesService* saved_files_service = SavedFilesService::Get(profile()); | 964 SavedFilesService* saved_files_service = SavedFilesService::Get(profile()); |
809 // Add the file to the retain list if it is not already on there. | 965 // Add the file to the retain list if it is not already on there. |
810 if (!saved_files_service->IsRegistered(extension_->id(), entry_id) && | 966 if (!saved_files_service->IsRegistered(extension_->id(), entry_id) && |
811 !RetainFileEntry(entry_id)) { | 967 !RetainFileEntry(entry_id)) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
861 return false; | 1017 return false; |
862 } | 1018 } |
863 | 1019 |
864 SavedFilesService::Get(profile())->EnqueueFileEntry( | 1020 SavedFilesService::Get(profile())->EnqueueFileEntry( |
865 extension_->id(), entry_id); | 1021 extension_->id(), entry_id); |
866 | 1022 |
867 // Only create a new file entry if the renderer requests one. | 1023 // Only create a new file entry if the renderer requests one. |
868 // |needs_new_entry| will be false if the renderer already has an Entry for | 1024 // |needs_new_entry| will be false if the renderer already has an Entry for |
869 // |entry_id|. | 1025 // |entry_id|. |
870 if (needs_new_entry) { | 1026 if (needs_new_entry) { |
871 // Reuse the ID of the retained file entry so retainEntry returns the same | 1027 entry_type_ = file_entry->writable ? WRITABLE : READ_ONLY; |
872 // ID that was passed to restoreEntry. | 1028 CreateResponse(); |
873 RegisterFileSystemAndSendResponseWithIdOverride( | 1029 AddEntryToResponse(file_entry->path, file_entry->id); |
874 file_entry->path, | |
875 file_entry->writable ? WRITABLE : READ_ONLY, | |
876 file_entry->id); | |
877 } | 1030 } |
| 1031 SendResponse(true); |
878 return true; | 1032 return true; |
879 } | 1033 } |
880 | 1034 |
881 } // namespace extensions | 1035 } // namespace extensions |
OLD | NEW |