file_system.cc revision 58e6fbe4ee35d65e14b626c557d37565bf8ad179
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 3// found in the LICENSE file. 4 5#include "chrome/browser/chromeos/drive/file_system.h" 6 7#include "base/bind.h" 8#include "base/file_util.h" 9#include "base/message_loop/message_loop_proxy.h" 10#include "base/platform_file.h" 11#include "base/prefs/pref_change_registrar.h" 12#include "base/prefs/pref_service.h" 13#include "base/strings/stringprintf.h" 14#include "base/threading/sequenced_worker_pool.h" 15#include "chrome/browser/chromeos/drive/change_list_loader.h" 16#include "chrome/browser/chromeos/drive/change_list_processor.h" 17#include "chrome/browser/chromeos/drive/drive.pb.h" 18#include "chrome/browser/chromeos/drive/file_cache.h" 19#include "chrome/browser/chromeos/drive/file_system/copy_operation.h" 20#include "chrome/browser/chromeos/drive/file_system/create_directory_operation.h" 21#include "chrome/browser/chromeos/drive/file_system/create_file_operation.h" 22#include "chrome/browser/chromeos/drive/file_system/download_operation.h" 23#include "chrome/browser/chromeos/drive/file_system/move_operation.h" 24#include "chrome/browser/chromeos/drive/file_system/open_file_operation.h" 25#include "chrome/browser/chromeos/drive/file_system/remove_operation.h" 26#include "chrome/browser/chromeos/drive/file_system/search_operation.h" 27#include "chrome/browser/chromeos/drive/file_system/touch_operation.h" 28#include "chrome/browser/chromeos/drive/file_system/truncate_operation.h" 29#include "chrome/browser/chromeos/drive/file_system/update_operation.h" 30#include "chrome/browser/chromeos/drive/file_system_observer.h" 31#include "chrome/browser/chromeos/drive/file_system_util.h" 32#include "chrome/browser/chromeos/drive/job_scheduler.h" 33#include "chrome/browser/chromeos/drive/remove_stale_cache_files.h" 34#include "chrome/browser/chromeos/drive/search_metadata.h" 35#include "chrome/browser/chromeos/drive/sync_client.h" 36#include "chrome/browser/drive/drive_api_util.h" 37#include "chrome/browser/drive/drive_service_interface.h" 38#include "chrome/browser/google_apis/drive_api_parser.h" 39#include "chrome/common/pref_names.h" 40#include "content/public/browser/browser_thread.h" 41 42using content::BrowserThread; 43 44namespace drive { 45namespace { 46 47//================================ Helper functions ============================ 48 49// Callback for ResourceMetadata::GetLargestChangestamp. 50// |callback| must not be null. 51void OnGetLargestChangestamp( 52 FileSystemMetadata metadata, // Will be modified. 53 const GetFilesystemMetadataCallback& callback, 54 int64 largest_changestamp) { 55 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 56 DCHECK(!callback.is_null()); 57 58 metadata.largest_changestamp = largest_changestamp; 59 callback.Run(metadata); 60} 61 62// Thin adapter to map GetFileCallback to FileOperationCallback. 63void GetFileCallbackToFileOperationCallbackAdapter( 64 const FileOperationCallback& callback, 65 FileError error, 66 const base::FilePath& unused_file_path, 67 scoped_ptr<ResourceEntry> unused_entry) { 68 callback.Run(error); 69} 70 71} // namespace 72 73FileSystem::FileSystem( 74 PrefService* pref_service, 75 internal::FileCache* cache, 76 DriveServiceInterface* drive_service, 77 JobScheduler* scheduler, 78 internal::ResourceMetadata* resource_metadata, 79 base::SequencedTaskRunner* blocking_task_runner, 80 const base::FilePath& temporary_file_directory) 81 : pref_service_(pref_service), 82 cache_(cache), 83 drive_service_(drive_service), 84 scheduler_(scheduler), 85 resource_metadata_(resource_metadata), 86 last_update_check_error_(FILE_ERROR_OK), 87 hide_hosted_docs_(false), 88 blocking_task_runner_(blocking_task_runner), 89 temporary_file_directory_(temporary_file_directory), 90 weak_ptr_factory_(this) { 91 // Should be created from the file browser extension API on UI thread. 92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 93} 94 95void FileSystem::Reload() { 96 resource_metadata_->ResetOnUIThread(base::Bind( 97 &FileSystem::ReloadAfterReset, 98 weak_ptr_factory_.GetWeakPtr())); 99} 100 101void FileSystem::Initialize() { 102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 103 104 SetupChangeListLoader(); 105 106 file_system::OperationObserver* observer = this; 107 copy_operation_.reset( 108 new file_system::CopyOperation(blocking_task_runner_.get(), 109 observer, 110 scheduler_, 111 resource_metadata_, 112 cache_, 113 drive_service_, 114 temporary_file_directory_)); 115 create_directory_operation_.reset(new file_system::CreateDirectoryOperation( 116 blocking_task_runner_.get(), observer, scheduler_, resource_metadata_)); 117 create_file_operation_.reset( 118 new file_system::CreateFileOperation(blocking_task_runner_.get(), 119 observer, 120 scheduler_, 121 resource_metadata_, 122 cache_)); 123 move_operation_.reset( 124 new file_system::MoveOperation(observer, scheduler_, resource_metadata_)); 125 open_file_operation_.reset( 126 new file_system::OpenFileOperation(blocking_task_runner_.get(), 127 observer, 128 scheduler_, 129 resource_metadata_, 130 cache_, 131 temporary_file_directory_)); 132 remove_operation_.reset( 133 new file_system::RemoveOperation(blocking_task_runner_.get(), 134 observer, 135 scheduler_, 136 resource_metadata_, 137 cache_)); 138 touch_operation_.reset(new file_system::TouchOperation( 139 blocking_task_runner_.get(), observer, scheduler_, resource_metadata_)); 140 truncate_operation_.reset( 141 new file_system::TruncateOperation(blocking_task_runner_.get(), 142 observer, 143 scheduler_, 144 resource_metadata_, 145 cache_, 146 temporary_file_directory_)); 147 download_operation_.reset( 148 new file_system::DownloadOperation(blocking_task_runner_.get(), 149 observer, 150 scheduler_, 151 resource_metadata_, 152 cache_, 153 temporary_file_directory_)); 154 update_operation_.reset( 155 new file_system::UpdateOperation(blocking_task_runner_.get(), 156 observer, 157 scheduler_, 158 resource_metadata_, 159 cache_)); 160 search_operation_.reset(new file_system::SearchOperation( 161 blocking_task_runner_.get(), scheduler_, resource_metadata_)); 162 sync_client_.reset(new internal::SyncClient(blocking_task_runner_.get(), 163 observer, 164 scheduler_, 165 resource_metadata_, 166 cache_, 167 temporary_file_directory_)); 168 169 hide_hosted_docs_ = 170 pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles); 171 172 InitializePreferenceObserver(); 173} 174 175void FileSystem::ReloadAfterReset(FileError error) { 176 if (error != FILE_ERROR_OK) { 177 LOG(ERROR) << "Failed to reset the resource metadata: " 178 << FileErrorToString(error); 179 return; 180 } 181 182 SetupChangeListLoader(); 183 184 change_list_loader_->LoadIfNeeded( 185 DirectoryFetchInfo(), 186 base::Bind(&FileSystem::OnUpdateChecked, 187 weak_ptr_factory_.GetWeakPtr())); 188} 189 190void FileSystem::SetupChangeListLoader() { 191 change_list_loader_.reset(new internal::ChangeListLoader( 192 blocking_task_runner_.get(), resource_metadata_, scheduler_)); 193 change_list_loader_->AddObserver(this); 194} 195 196void FileSystem::CheckForUpdates() { 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 198 DVLOG(1) << "CheckForUpdates"; 199 200 if (change_list_loader_) { 201 change_list_loader_->CheckForUpdates( 202 base::Bind(&FileSystem::OnUpdateChecked, 203 weak_ptr_factory_.GetWeakPtr())); 204 } 205} 206 207void FileSystem::OnUpdateChecked(FileError error) { 208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 209 DVLOG(1) << "CheckForUpdates finished: " << FileErrorToString(error); 210 last_update_check_time_ = base::Time::Now(); 211 last_update_check_error_ = error; 212} 213 214FileSystem::~FileSystem() { 215 // This should be called from UI thread, from DriveIntegrationService 216 // shutdown. 217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 218 219 change_list_loader_->RemoveObserver(this); 220} 221 222void FileSystem::AddObserver(FileSystemObserver* observer) { 223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 224 observers_.AddObserver(observer); 225} 226 227void FileSystem::RemoveObserver(FileSystemObserver* observer) { 228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 229 observers_.RemoveObserver(observer); 230} 231 232void FileSystem::TransferFileFromRemoteToLocal( 233 const base::FilePath& remote_src_file_path, 234 const base::FilePath& local_dest_file_path, 235 const FileOperationCallback& callback) { 236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 237 DCHECK(!callback.is_null()); 238 copy_operation_->TransferFileFromRemoteToLocal(remote_src_file_path, 239 local_dest_file_path, 240 callback); 241} 242 243void FileSystem::TransferFileFromLocalToRemote( 244 const base::FilePath& local_src_file_path, 245 const base::FilePath& remote_dest_file_path, 246 const FileOperationCallback& callback) { 247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 248 DCHECK(!callback.is_null()); 249 copy_operation_->TransferFileFromLocalToRemote(local_src_file_path, 250 remote_dest_file_path, 251 callback); 252} 253 254void FileSystem::Copy(const base::FilePath& src_file_path, 255 const base::FilePath& dest_file_path, 256 const FileOperationCallback& callback) { 257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 258 DCHECK(!callback.is_null()); 259 copy_operation_->Copy(src_file_path, dest_file_path, callback); 260} 261 262void FileSystem::Move(const base::FilePath& src_file_path, 263 const base::FilePath& dest_file_path, 264 const FileOperationCallback& callback) { 265 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 266 DCHECK(!callback.is_null()); 267 move_operation_->Move(src_file_path, dest_file_path, callback); 268} 269 270void FileSystem::Remove(const base::FilePath& file_path, 271 bool is_recursive, 272 const FileOperationCallback& callback) { 273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 274 DCHECK(!callback.is_null()); 275 remove_operation_->Remove(file_path, is_recursive, callback); 276} 277 278void FileSystem::CreateDirectory( 279 const base::FilePath& directory_path, 280 bool is_exclusive, 281 bool is_recursive, 282 const FileOperationCallback& callback) { 283 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 284 DCHECK(!callback.is_null()); 285 286 change_list_loader_->LoadIfNeeded( 287 DirectoryFetchInfo(), 288 base::Bind(&FileSystem::CreateDirectoryAfterLoad, 289 weak_ptr_factory_.GetWeakPtr(), 290 directory_path, is_exclusive, is_recursive, callback)); 291} 292 293void FileSystem::CreateDirectoryAfterLoad( 294 const base::FilePath& directory_path, 295 bool is_exclusive, 296 bool is_recursive, 297 const FileOperationCallback& callback, 298 FileError load_error) { 299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 300 DCHECK(!callback.is_null()); 301 302 if (load_error != FILE_ERROR_OK) { 303 callback.Run(load_error); 304 return; 305 } 306 307 create_directory_operation_->CreateDirectory( 308 directory_path, is_exclusive, is_recursive, callback); 309} 310 311void FileSystem::CreateFile(const base::FilePath& file_path, 312 bool is_exclusive, 313 const FileOperationCallback& callback) { 314 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 315 DCHECK(!callback.is_null()); 316 create_file_operation_->CreateFile(file_path, is_exclusive, callback); 317} 318 319void FileSystem::TouchFile(const base::FilePath& file_path, 320 const base::Time& last_access_time, 321 const base::Time& last_modified_time, 322 const FileOperationCallback& callback) { 323 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 324 DCHECK(!last_access_time.is_null()); 325 DCHECK(!last_modified_time.is_null()); 326 DCHECK(!callback.is_null()); 327 touch_operation_->TouchFile( 328 file_path, last_access_time, last_modified_time, callback); 329} 330 331void FileSystem::TruncateFile(const base::FilePath& file_path, 332 int64 length, 333 const FileOperationCallback& callback) { 334 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 335 DCHECK(!callback.is_null()); 336 truncate_operation_->Truncate(file_path, length, callback); 337} 338 339void FileSystem::Pin(const base::FilePath& file_path, 340 const FileOperationCallback& callback) { 341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 342 DCHECK(!callback.is_null()); 343 344 GetResourceEntryByPath(file_path, 345 base::Bind(&FileSystem::PinAfterGetResourceEntryByPath, 346 weak_ptr_factory_.GetWeakPtr(), 347 callback)); 348} 349 350void FileSystem::PinAfterGetResourceEntryByPath( 351 const FileOperationCallback& callback, 352 FileError error, 353 scoped_ptr<ResourceEntry> entry) { 354 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 355 DCHECK(!callback.is_null()); 356 357 // TODO(hashimoto): Support pinning directories. crbug.com/127831 358 if (entry && entry->file_info().is_directory()) 359 error = FILE_ERROR_NOT_A_FILE; 360 361 if (error != FILE_ERROR_OK) { 362 callback.Run(error); 363 return; 364 } 365 DCHECK(entry); 366 367 cache_->PinOnUIThread(entry->resource_id(), 368 base::Bind(&FileSystem::FinishPin, 369 weak_ptr_factory_.GetWeakPtr(), 370 callback, 371 entry->resource_id())); 372} 373 374void FileSystem::FinishPin(const FileOperationCallback& callback, 375 const std::string& resource_id, 376 FileError error) { 377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 378 DCHECK(!callback.is_null()); 379 380 if (error == FILE_ERROR_OK) 381 sync_client_->AddFetchTask(resource_id); 382 callback.Run(error); 383} 384 385void FileSystem::Unpin(const base::FilePath& file_path, 386 const FileOperationCallback& callback) { 387 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 388 DCHECK(!callback.is_null()); 389 390 GetResourceEntryByPath( 391 file_path, 392 base::Bind(&FileSystem::UnpinAfterGetResourceEntryByPath, 393 weak_ptr_factory_.GetWeakPtr(), 394 callback)); 395} 396 397void FileSystem::UnpinAfterGetResourceEntryByPath( 398 const FileOperationCallback& callback, 399 FileError error, 400 scoped_ptr<ResourceEntry> entry) { 401 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 402 DCHECK(!callback.is_null()); 403 404 // TODO(hashimoto): Support pinning directories. crbug.com/127831 405 if (entry && entry->file_info().is_directory()) 406 error = FILE_ERROR_NOT_A_FILE; 407 408 if (error != FILE_ERROR_OK) { 409 callback.Run(error); 410 return; 411 } 412 DCHECK(entry); 413 414 cache_->UnpinOnUIThread(entry->resource_id(), 415 base::Bind(&FileSystem::FinishUnpin, 416 weak_ptr_factory_.GetWeakPtr(), 417 callback, 418 entry->resource_id())); 419} 420 421void FileSystem::FinishUnpin(const FileOperationCallback& callback, 422 const std::string& resource_id, 423 FileError error) { 424 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 425 DCHECK(!callback.is_null()); 426 427 if (error == FILE_ERROR_OK) 428 sync_client_->RemoveFetchTask(resource_id); 429 callback.Run(error); 430} 431 432void FileSystem::GetFileByPath(const base::FilePath& file_path, 433 const GetFileCallback& callback) { 434 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 435 DCHECK(!callback.is_null()); 436 437 download_operation_->EnsureFileDownloadedByPath( 438 file_path, 439 ClientContext(USER_INITIATED), 440 GetFileContentInitializedCallback(), 441 google_apis::GetContentCallback(), 442 callback); 443} 444 445void FileSystem::GetFileContentByPath( 446 const base::FilePath& file_path, 447 const GetFileContentInitializedCallback& initialized_callback, 448 const google_apis::GetContentCallback& get_content_callback, 449 const FileOperationCallback& completion_callback) { 450 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 451 DCHECK(!initialized_callback.is_null()); 452 DCHECK(!get_content_callback.is_null()); 453 DCHECK(!completion_callback.is_null()); 454 455 download_operation_->EnsureFileDownloadedByPath( 456 file_path, 457 ClientContext(USER_INITIATED), 458 initialized_callback, 459 get_content_callback, 460 base::Bind(&GetFileCallbackToFileOperationCallbackAdapter, 461 completion_callback)); 462} 463 464void FileSystem::GetResourceEntryByPath( 465 const base::FilePath& file_path, 466 const GetResourceEntryCallback& callback) { 467 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 468 DCHECK(!callback.is_null()); 469 470 // ResourceMetadata may know about the entry even if the resource 471 // metadata is not yet fully loaded. For instance, ResourceMetadata() 472 // always knows about the root directory. For "fast fetch" 473 // (crbug.com/178348) to work, it's needed to delay the resource metadata 474 // loading until the first call to ReadDirectoryByPath(). 475 resource_metadata_->GetResourceEntryByPathOnUIThread( 476 file_path, 477 base::Bind(&FileSystem::GetResourceEntryByPathAfterGetEntry1, 478 weak_ptr_factory_.GetWeakPtr(), 479 file_path, 480 callback)); 481} 482 483void FileSystem::GetResourceEntryByPathAfterGetEntry1( 484 const base::FilePath& file_path, 485 const GetResourceEntryCallback& callback, 486 FileError error, 487 scoped_ptr<ResourceEntry> entry) { 488 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 489 DCHECK(!callback.is_null()); 490 491 if (error == FILE_ERROR_OK) { 492 CheckLocalModificationAndRun(entry.Pass(), callback); 493 return; 494 } 495 496 // If the information about the path is not in the local ResourceMetadata, 497 // try fetching information of the directory and retry. 498 LoadDirectoryIfNeeded( 499 file_path.DirName(), 500 base::Bind(&FileSystem::GetResourceEntryByPathAfterLoad, 501 weak_ptr_factory_.GetWeakPtr(), 502 file_path, 503 callback)); 504} 505 506void FileSystem::GetResourceEntryByPathAfterLoad( 507 const base::FilePath& file_path, 508 const GetResourceEntryCallback& callback, 509 FileError error) { 510 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 511 DCHECK(!callback.is_null()); 512 513 if (error != FILE_ERROR_OK) { 514 callback.Run(error, scoped_ptr<ResourceEntry>()); 515 return; 516 } 517 518 resource_metadata_->GetResourceEntryByPathOnUIThread( 519 file_path, 520 base::Bind(&FileSystem::GetResourceEntryByPathAfterGetEntry2, 521 weak_ptr_factory_.GetWeakPtr(), 522 callback)); 523} 524 525void FileSystem::GetResourceEntryByPathAfterGetEntry2( 526 const GetResourceEntryCallback& callback, 527 FileError error, 528 scoped_ptr<ResourceEntry> entry) { 529 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 530 DCHECK(!callback.is_null()); 531 532 if (error != FILE_ERROR_OK) { 533 callback.Run(error, scoped_ptr<ResourceEntry>()); 534 return; 535 } 536 DCHECK(entry.get()); 537 538 CheckLocalModificationAndRun(entry.Pass(), callback); 539} 540 541void FileSystem::ReadDirectoryByPath( 542 const base::FilePath& directory_path, 543 const ReadDirectoryCallback& callback) { 544 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 545 DCHECK(!callback.is_null()); 546 547 LoadDirectoryIfNeeded( 548 directory_path, 549 base::Bind(&FileSystem::ReadDirectoryByPathAfterLoad, 550 weak_ptr_factory_.GetWeakPtr(), 551 directory_path, 552 callback)); 553} 554 555void FileSystem::LoadDirectoryIfNeeded(const base::FilePath& directory_path, 556 const FileOperationCallback& callback) { 557 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 558 DCHECK(!callback.is_null()); 559 560 // As described in GetResourceEntryByPath(), ResourceMetadata may know 561 // about the entry even if the file system is not yet fully loaded, hence we 562 // should just ask ResourceMetadata first. 563 resource_metadata_->GetResourceEntryByPathOnUIThread( 564 directory_path, 565 base::Bind(&FileSystem::LoadDirectoryIfNeededAfterGetEntry, 566 weak_ptr_factory_.GetWeakPtr(), 567 directory_path, 568 callback)); 569} 570 571void FileSystem::LoadDirectoryIfNeededAfterGetEntry( 572 const base::FilePath& directory_path, 573 const FileOperationCallback& callback, 574 FileError error, 575 scoped_ptr<ResourceEntry> entry) { 576 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 577 DCHECK(!callback.is_null()); 578 579 if (error != FILE_ERROR_OK || 580 entry->resource_id() == util::kDriveOtherDirSpecialResourceId) { 581 // If we don't know about the directory, or it is the "drive/other" 582 // directory that has to gather all orphan entries, start loading full 583 // resource list. 584 change_list_loader_->LoadIfNeeded(DirectoryFetchInfo(), callback); 585 return; 586 } 587 588 if (!entry->file_info().is_directory()) { 589 callback.Run(FILE_ERROR_NOT_A_DIRECTORY); 590 return; 591 } 592 593 // Pass the directory fetch info so we can fetch the contents of the 594 // directory before loading change lists. 595 DirectoryFetchInfo directory_fetch_info( 596 entry->resource_id(), 597 entry->directory_specific_info().changestamp()); 598 change_list_loader_->LoadIfNeeded(directory_fetch_info, callback); 599} 600 601void FileSystem::ReadDirectoryByPathAfterLoad( 602 const base::FilePath& directory_path, 603 const ReadDirectoryCallback& callback, 604 FileError error) { 605 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 606 DCHECK(!callback.is_null()); 607 608 DLOG_IF(INFO, error != FILE_ERROR_OK) << "LoadIfNeeded failed. " 609 << FileErrorToString(error); 610 611 resource_metadata_->ReadDirectoryByPathOnUIThread( 612 directory_path, 613 base::Bind(&FileSystem::ReadDirectoryByPathAfterRead, 614 weak_ptr_factory_.GetWeakPtr(), 615 callback)); 616} 617 618void FileSystem::ReadDirectoryByPathAfterRead( 619 const ReadDirectoryCallback& callback, 620 FileError error, 621 scoped_ptr<ResourceEntryVector> entries) { 622 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 623 DCHECK(!callback.is_null()); 624 625 if (error != FILE_ERROR_OK) { 626 callback.Run(error, 627 scoped_ptr<ResourceEntryVector>()); 628 return; 629 } 630 DCHECK(entries.get()); // This is valid for empty directories too. 631 632 // TODO(satorux): Stop handling hide_hosted_docs_ here. crbug.com/256520. 633 scoped_ptr<ResourceEntryVector> filtered(new ResourceEntryVector); 634 for (size_t i = 0; i < entries->size(); ++i) { 635 if (hide_hosted_docs_ && 636 entries->at(i).file_specific_info().is_hosted_document()) { 637 continue; 638 } 639 filtered->push_back(entries->at(i)); 640 } 641 callback.Run(FILE_ERROR_OK, filtered.Pass()); 642} 643 644void FileSystem::GetAvailableSpace( 645 const GetAvailableSpaceCallback& callback) { 646 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 647 DCHECK(!callback.is_null()); 648 649 scheduler_->GetAboutResource( 650 base::Bind(&FileSystem::OnGetAboutResource, 651 weak_ptr_factory_.GetWeakPtr(), 652 callback)); 653} 654 655void FileSystem::OnGetAboutResource( 656 const GetAvailableSpaceCallback& callback, 657 google_apis::GDataErrorCode status, 658 scoped_ptr<google_apis::AboutResource> about_resource) { 659 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 660 DCHECK(!callback.is_null()); 661 662 FileError error = util::GDataToFileError(status); 663 if (error != FILE_ERROR_OK) { 664 callback.Run(error, -1, -1); 665 return; 666 } 667 DCHECK(about_resource); 668 669 callback.Run(FILE_ERROR_OK, 670 about_resource->quota_bytes_total(), 671 about_resource->quota_bytes_used()); 672} 673 674void FileSystem::GetShareUrl( 675 const base::FilePath& file_path, 676 const GURL& embed_origin, 677 const GetShareUrlCallback& callback) { 678 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 679 DCHECK(!callback.is_null()); 680 681 // Resolve the resource id. 682 resource_metadata_->GetResourceEntryByPathOnUIThread( 683 file_path, 684 base::Bind(&FileSystem::GetShareUrlAfterGetResourceEntry, 685 weak_ptr_factory_.GetWeakPtr(), 686 file_path, 687 embed_origin, 688 callback)); 689} 690 691void FileSystem::GetShareUrlAfterGetResourceEntry( 692 const base::FilePath& file_path, 693 const GURL& embed_origin, 694 const GetShareUrlCallback& callback, 695 FileError error, 696 scoped_ptr<ResourceEntry> entry) { 697 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 698 DCHECK(!callback.is_null()); 699 700 if (error != FILE_ERROR_OK) { 701 callback.Run(error, GURL()); 702 return; 703 } 704 if (util::IsSpecialResourceId(entry->resource_id())) { 705 // Do not load special directories. Just return. 706 callback.Run(FILE_ERROR_FAILED, GURL()); 707 return; 708 } 709 710 scheduler_->GetShareUrl( 711 entry->resource_id(), 712 embed_origin, 713 ClientContext(USER_INITIATED), 714 base::Bind(&FileSystem::OnGetResourceEntryForGetShareUrl, 715 weak_ptr_factory_.GetWeakPtr(), 716 callback)); 717} 718 719void FileSystem::OnGetResourceEntryForGetShareUrl( 720 const GetShareUrlCallback& callback, 721 google_apis::GDataErrorCode status, 722 const GURL& share_url) { 723 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 724 DCHECK(!callback.is_null()); 725 726 FileError error = util::GDataToFileError(status); 727 if (error != FILE_ERROR_OK) { 728 callback.Run(error, GURL()); 729 return; 730 } 731 732 if (share_url.is_empty()) { 733 callback.Run(FILE_ERROR_FAILED, GURL()); 734 return; 735 } 736 737 callback.Run(FILE_ERROR_OK, share_url); 738} 739 740void FileSystem::Search(const std::string& search_query, 741 const GURL& next_url, 742 const SearchCallback& callback) { 743 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 744 DCHECK(!callback.is_null()); 745 search_operation_->Search(search_query, next_url, callback); 746} 747 748void FileSystem::SearchMetadata(const std::string& query, 749 int options, 750 int at_most_num_matches, 751 const SearchMetadataCallback& callback) { 752 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 753 754 if (hide_hosted_docs_) 755 options |= SEARCH_METADATA_EXCLUDE_HOSTED_DOCUMENTS; 756 757 drive::internal::SearchMetadata(blocking_task_runner_, 758 resource_metadata_, 759 query, 760 options, 761 at_most_num_matches, 762 callback); 763} 764 765void FileSystem::OnDirectoryChangedByOperation( 766 const base::FilePath& directory_path) { 767 OnDirectoryChanged(directory_path); 768} 769 770void FileSystem::OnCacheFileUploadNeededByOperation( 771 const std::string& resource_id) { 772 sync_client_->AddUploadTask(resource_id); 773} 774 775void FileSystem::OnDirectoryChanged(const base::FilePath& directory_path) { 776 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 777 778 FOR_EACH_OBSERVER(FileSystemObserver, observers_, 779 OnDirectoryChanged(directory_path)); 780} 781 782void FileSystem::OnLoadFromServerComplete() { 783 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 784 785 sync_client_->StartCheckingExistingPinnedFiles(); 786} 787 788void FileSystem::OnInitialLoadComplete() { 789 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 790 791 blocking_task_runner_->PostTask(FROM_HERE, 792 base::Bind(&internal::RemoveStaleCacheFiles, 793 cache_, 794 resource_metadata_)); 795 sync_client_->StartProcessingBacklog(); 796} 797 798void FileSystem::GetMetadata( 799 const GetFilesystemMetadataCallback& callback) { 800 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 801 DCHECK(!callback.is_null()); 802 803 FileSystemMetadata metadata; 804 metadata.refreshing = change_list_loader_->IsRefreshing(); 805 806 // Metadata related to delta update. 807 metadata.last_update_check_time = last_update_check_time_; 808 metadata.last_update_check_error = last_update_check_error_; 809 810 resource_metadata_->GetLargestChangestampOnUIThread( 811 base::Bind(&OnGetLargestChangestamp, metadata, callback)); 812} 813 814void FileSystem::MarkCacheFileAsMounted( 815 const base::FilePath& drive_file_path, 816 const MarkMountedCallback& callback) { 817 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 818 DCHECK(!callback.is_null()); 819 820 GetResourceEntryByPath( 821 drive_file_path, 822 base::Bind(&FileSystem::MarkCacheFileAsMountedAfterGetResourceEntry, 823 weak_ptr_factory_.GetWeakPtr(), callback)); 824} 825 826void FileSystem::MarkCacheFileAsMountedAfterGetResourceEntry( 827 const MarkMountedCallback& callback, 828 FileError error, 829 scoped_ptr<ResourceEntry> entry) { 830 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 831 DCHECK(!callback.is_null()); 832 833 if (error != FILE_ERROR_OK) { 834 callback.Run(error, base::FilePath()); 835 return; 836 } 837 838 DCHECK(entry); 839 cache_->MarkAsMountedOnUIThread(entry->resource_id(), callback); 840} 841 842void FileSystem::MarkCacheFileAsUnmounted( 843 const base::FilePath& cache_file_path, 844 const FileOperationCallback& callback) { 845 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 846 DCHECK(!callback.is_null()); 847 848 if (!cache_->IsUnderFileCacheDirectory(cache_file_path)) { 849 callback.Run(FILE_ERROR_FAILED); 850 return; 851 } 852 cache_->MarkAsUnmountedOnUIThread(cache_file_path, callback); 853} 854 855void FileSystem::GetCacheEntryByResourceId( 856 const std::string& resource_id, 857 const std::string& md5, 858 const GetCacheEntryCallback& callback) { 859 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 860 DCHECK(!resource_id.empty()); 861 DCHECK(!callback.is_null()); 862 863 cache_->GetCacheEntryOnUIThread(resource_id, md5, callback); 864} 865 866void FileSystem::OnDisableDriveHostedFilesChanged() { 867 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 868 SetHideHostedDocuments( 869 pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles)); 870} 871 872void FileSystem::SetHideHostedDocuments(bool hide) { 873 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 874 875 if (hide == hide_hosted_docs_) 876 return; 877 878 hide_hosted_docs_ = hide; 879 880 // Kick off directory refresh when this setting changes. 881 FOR_EACH_OBSERVER(FileSystemObserver, observers_, 882 OnDirectoryChanged(util::GetDriveGrandRootPath())); 883} 884 885//============= FileSystem: internal helper functions ===================== 886 887void FileSystem::InitializePreferenceObserver() { 888 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 889 890 pref_registrar_.reset(new PrefChangeRegistrar()); 891 pref_registrar_->Init(pref_service_); 892 pref_registrar_->Add( 893 prefs::kDisableDriveHostedFiles, 894 base::Bind(&FileSystem::OnDisableDriveHostedFilesChanged, 895 base::Unretained(this))); 896} 897 898void FileSystem::OpenFile(const base::FilePath& file_path, 899 OpenMode open_mode, 900 const OpenFileCallback& callback) { 901 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 902 DCHECK(!callback.is_null()); 903 904 open_file_operation_->OpenFile(file_path, open_mode, callback); 905} 906 907void FileSystem::CheckLocalModificationAndRun( 908 scoped_ptr<ResourceEntry> entry, 909 const GetResourceEntryCallback& callback) { 910 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 911 DCHECK(entry.get()); 912 DCHECK(!callback.is_null()); 913 914 // For entries that will never be cached, use the original resource entry 915 // as is. 916 if (!entry->has_file_specific_info() || 917 entry->file_specific_info().is_hosted_document()) { 918 callback.Run(FILE_ERROR_OK, entry.Pass()); 919 return; 920 } 921 922 // Checks if the file is cached and modified locally. 923 const std::string resource_id = entry->resource_id(); 924 const std::string md5 = entry->file_specific_info().md5(); 925 cache_->GetCacheEntryOnUIThread( 926 resource_id, 927 md5, 928 base::Bind( 929 &FileSystem::CheckLocalModificationAndRunAfterGetCacheEntry, 930 weak_ptr_factory_.GetWeakPtr(), 931 base::Passed(&entry), 932 callback)); 933} 934 935void FileSystem::CheckLocalModificationAndRunAfterGetCacheEntry( 936 scoped_ptr<ResourceEntry> entry, 937 const GetResourceEntryCallback& callback, 938 bool success, 939 const FileCacheEntry& cache_entry) { 940 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 941 DCHECK(!callback.is_null()); 942 943 // When no dirty cache is found, use the original resource entry as is. 944 if (!success || !cache_entry.is_dirty()) { 945 callback.Run(FILE_ERROR_OK, entry.Pass()); 946 return; 947 } 948 949 // Gets the cache file path. 950 const std::string& resource_id = entry->resource_id(); 951 cache_->GetFileOnUIThread( 952 resource_id, 953 base::Bind( 954 &FileSystem::CheckLocalModificationAndRunAfterGetCacheFile, 955 weak_ptr_factory_.GetWeakPtr(), 956 base::Passed(&entry), 957 callback)); 958} 959 960void FileSystem::CheckLocalModificationAndRunAfterGetCacheFile( 961 scoped_ptr<ResourceEntry> entry, 962 const GetResourceEntryCallback& callback, 963 FileError error, 964 const base::FilePath& local_cache_path) { 965 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 966 DCHECK(!callback.is_null()); 967 968 // When no dirty cache is found, use the original resource entry as is. 969 if (error != FILE_ERROR_OK) { 970 callback.Run(FILE_ERROR_OK, entry.Pass()); 971 return; 972 } 973 974 // If the cache is dirty, obtain the file info from the cache file itself. 975 base::PlatformFileInfo* file_info = new base::PlatformFileInfo; 976 base::PostTaskAndReplyWithResult( 977 blocking_task_runner_.get(), 978 FROM_HERE, 979 base::Bind(&file_util::GetFileInfo, 980 local_cache_path, 981 base::Unretained(file_info)), 982 base::Bind(&FileSystem::CheckLocalModificationAndRunAfterGetFileInfo, 983 weak_ptr_factory_.GetWeakPtr(), 984 base::Passed(&entry), 985 callback, 986 base::Owned(file_info))); 987} 988 989void FileSystem::CheckLocalModificationAndRunAfterGetFileInfo( 990 scoped_ptr<ResourceEntry> entry, 991 const GetResourceEntryCallback& callback, 992 base::PlatformFileInfo* file_info, 993 bool get_file_info_result) { 994 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 995 DCHECK(!callback.is_null()); 996 997 if (!get_file_info_result) { 998 callback.Run(FILE_ERROR_NOT_FOUND, scoped_ptr<ResourceEntry>()); 999 return; 1000 } 1001 1002 PlatformFileInfoProto entry_file_info; 1003 util::ConvertPlatformFileInfoToResourceEntry(*file_info, &entry_file_info); 1004 *entry->mutable_file_info() = entry_file_info; 1005 callback.Run(FILE_ERROR_OK, entry.Pass()); 1006} 1007 1008} // namespace drive 1009