#include "base/file_util.h"
#include "base/platform_file.h"
#include "base/prefs/pref_service.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/drive/change_list_loader.h"
-#include "chrome/browser/chromeos/drive/change_list_processor.h"
#include "chrome/browser/chromeos/drive/drive.pb.h"
#include "chrome/browser/chromeos/drive/file_cache.h"
#include "chrome/browser/chromeos/drive/file_system/copy_operation.h"
#include "chrome/browser/chromeos/drive/file_system/search_operation.h"
#include "chrome/browser/chromeos/drive/file_system/touch_operation.h"
#include "chrome/browser/chromeos/drive/file_system/truncate_operation.h"
-#include "chrome/browser/chromeos/drive/file_system/update_operation.h"
#include "chrome/browser/chromeos/drive/file_system_observer.h"
#include "chrome/browser/chromeos/drive/file_system_util.h"
#include "chrome/browser/chromeos/drive/job_scheduler.h"
-#include "chrome/browser/chromeos/drive/logging.h"
#include "chrome/browser/chromeos/drive/remove_stale_cache_files.h"
#include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
#include "chrome/browser/chromeos/drive/search_metadata.h"
#include "chrome/browser/chromeos/drive/sync_client.h"
#include "chrome/browser/drive/drive_service_interface.h"
-#include "chrome/browser/google_apis/drive_api_parser.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/browser_thread.h"
+#include "google_apis/drive/drive_api_parser.h"
using content::BrowserThread;
entry->file_specific_info().is_hosted_document())
return FILE_ERROR_OK;
- // When no dirty cache is found, use the original resource entry as is.
+ // When cache is not found, use the original resource entry as is.
FileCacheEntry cache_entry;
- if (!cache->GetCacheEntry(local_id, &cache_entry) || !cache_entry.is_dirty())
+ if (!cache->GetCacheEntry(local_id, &cache_entry))
return FILE_ERROR_OK;
- // If the cache is dirty, obtain the file info from the cache file itself.
+ // When cache is non-dirty and obsolete (old hash), use the original entry.
+ if (!cache_entry.is_dirty() &&
+ entry->file_specific_info().md5() != cache_entry.md5())
+ return FILE_ERROR_OK;
+
+ // If there's a valid cache, obtain the file info from the cache file itself.
base::FilePath local_cache_path;
error = cache->GetFile(local_id, &local_cache_path);
if (error != FILE_ERROR_OK)
return error;
- base::PlatformFileInfo file_info;
- if (!file_util::GetFileInfo(local_cache_path, &file_info))
+ base::File::Info file_info;
+ if (!base::GetFileInfo(local_cache_path, &file_info))
return FILE_ERROR_NOT_FOUND;
- SetPlatformFileInfoToResourceEntry(file_info, entry);
+ // TODO(hashimoto): crbug.com/346625. Also reflect timestamps.
+ entry->mutable_file_info()->set_size(file_info.size);
return FILE_ERROR_OK;
}
callback.Run(error, *cache_file_path);
}
-// Used to implement GetCacheEntryByPath.
-bool GetCacheEntryByPathInternal(internal::ResourceMetadata* resource_metadata,
+// Used to implement GetCacheEntry.
+bool GetCacheEntryInternal(internal::ResourceMetadata* resource_metadata,
internal::FileCache* cache,
const base::FilePath& drive_file_path,
FileCacheEntry* cache_entry) {
FileSystem::FileSystem(
PrefService* pref_service,
+ EventLogger* logger,
internal::FileCache* cache,
DriveServiceInterface* drive_service,
JobScheduler* scheduler,
base::SequencedTaskRunner* blocking_task_runner,
const base::FilePath& temporary_file_directory)
: pref_service_(pref_service),
+ logger_(logger),
cache_(cache),
drive_service_(drive_service),
scheduler_(scheduler),
change_list_loader_->RemoveObserver(this);
}
-void FileSystem::Reload(const FileOperationCallback& callback) {
+void FileSystem::Reset(const FileOperationCallback& callback) {
// Discard the current loader and operation objects and renew them. This is to
// avoid that changes initiated before the metadata reset is applied after the
// reset, which may cause an inconsistent state.
blocking_task_runner_,
FROM_HERE,
base::Bind(&ResetOnBlockingPool, resource_metadata_, cache_),
- base::Bind(&FileSystem::ReloadAfterReset,
- weak_ptr_factory_.GetWeakPtr(),
- callback));
-}
-
-void FileSystem::ReloadAfterReset(const FileOperationCallback& callback,
- FileError error) {
- if (error != FILE_ERROR_OK) {
- LOG(ERROR) << "Failed to reload Drive file system: "
- << FileErrorToString(error);
- callback.Run(error);
- return;
- }
-
- change_list_loader_->LoadIfNeeded(
- internal::DirectoryFetchInfo(),
- base::Bind(&FileSystem::OnUpdateChecked, weak_ptr_factory_.GetWeakPtr()));
- callback.Run(error);
+ callback);
}
void FileSystem::ResetComponents() {
file_system::OperationObserver* observer = this;
+
+ about_resource_loader_.reset(new internal::AboutResourceLoader(scheduler_));
+ loader_controller_.reset(new internal::LoaderController);
+ change_list_loader_.reset(new internal::ChangeListLoader(
+ logger_,
+ blocking_task_runner_.get(),
+ resource_metadata_,
+ scheduler_,
+ drive_service_,
+ about_resource_loader_.get(),
+ loader_controller_.get()));
+ change_list_loader_->AddObserver(this);
+
+ sync_client_.reset(new internal::SyncClient(blocking_task_runner_.get(),
+ observer,
+ scheduler_,
+ resource_metadata_,
+ cache_,
+ loader_controller_.get(),
+ temporary_file_directory_));
+
copy_operation_.reset(
- new file_system::CopyOperation(blocking_task_runner_.get(),
- observer,
- scheduler_,
- resource_metadata_,
- cache_,
- drive_service_,
- temporary_file_directory_));
+ new file_system::CopyOperation(
+ blocking_task_runner_.get(),
+ observer,
+ scheduler_,
+ resource_metadata_,
+ cache_,
+ drive_service_->GetResourceIdCanonicalizer()));
create_directory_operation_.reset(new file_system::CreateDirectoryOperation(
- blocking_task_runner_.get(), observer, scheduler_, resource_metadata_));
+ blocking_task_runner_.get(), observer, resource_metadata_));
create_file_operation_.reset(
new file_system::CreateFileOperation(blocking_task_runner_.get(),
observer,
- scheduler_,
- resource_metadata_,
- cache_));
+ resource_metadata_));
move_operation_.reset(
new file_system::MoveOperation(blocking_task_runner_.get(),
observer,
- scheduler_,
resource_metadata_));
open_file_operation_.reset(
new file_system::OpenFileOperation(blocking_task_runner_.get(),
remove_operation_.reset(
new file_system::RemoveOperation(blocking_task_runner_.get(),
observer,
- scheduler_,
resource_metadata_,
cache_));
touch_operation_.reset(new file_system::TouchOperation(
- blocking_task_runner_.get(), observer, scheduler_, resource_metadata_));
+ blocking_task_runner_.get(), observer, resource_metadata_));
truncate_operation_.reset(
new file_system::TruncateOperation(blocking_task_runner_.get(),
observer,
resource_metadata_,
cache_,
temporary_file_directory_));
- update_operation_.reset(
- new file_system::UpdateOperation(blocking_task_runner_.get(),
- observer,
- scheduler_,
- resource_metadata_,
- cache_));
search_operation_.reset(new file_system::SearchOperation(
- blocking_task_runner_.get(), scheduler_, resource_metadata_));
+ blocking_task_runner_.get(), scheduler_, resource_metadata_,
+ loader_controller_.get()));
get_file_for_saving_operation_.reset(
- new file_system::GetFileForSavingOperation(blocking_task_runner_.get(),
+ new file_system::GetFileForSavingOperation(logger_,
+ blocking_task_runner_.get(),
observer,
scheduler_,
resource_metadata_,
cache_,
temporary_file_directory_));
-
- sync_client_.reset(new internal::SyncClient(blocking_task_runner_.get(),
- observer,
- scheduler_,
- resource_metadata_,
- cache_,
- temporary_file_directory_));
-
- change_list_loader_.reset(new internal::ChangeListLoader(
- blocking_task_runner_.get(),
- resource_metadata_,
- scheduler_,
- drive_service_));
- change_list_loader_->AddObserver(this);
}
void FileSystem::CheckForUpdates() {
DCHECK(!callback.is_null());
// Ensure its parent directory is loaded to the local metadata.
- LoadDirectoryIfNeeded(
+ change_list_loader_->LoadDirectoryIfNeeded(
directory_path.DirName(),
base::Bind(&FileSystem::CreateDirectoryAfterLoad,
weak_ptr_factory_.GetWeakPtr(),
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!callback.is_null());
- if (load_error != FILE_ERROR_OK) {
- callback.Run(load_error);
- return;
- }
+ DVLOG_IF(1, load_error != FILE_ERROR_OK) << "LoadDirectoryIfNeeded failed. "
+ << FileErrorToString(load_error);
create_directory_operation_->CreateDirectory(
directory_path, is_exclusive, is_recursive, callback);
callback.Run(error);
}
-void FileSystem::GetFileByPath(const base::FilePath& file_path,
- const GetFileCallback& callback) {
+void FileSystem::GetFile(const base::FilePath& file_path,
+ const GetFileCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!callback.is_null());
callback);
}
-void FileSystem::GetFileByPathForSaving(const base::FilePath& file_path,
- const GetFileCallback& callback) {
+void FileSystem::GetFileForSaving(const base::FilePath& file_path,
+ const GetFileCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!callback.is_null());
get_file_for_saving_operation_->GetFileForSaving(file_path, callback);
}
-void FileSystem::GetFileContentByPath(
+void FileSystem::GetFileContent(
const base::FilePath& file_path,
const GetFileContentInitializedCallback& initialized_callback,
const google_apis::GetContentCallback& get_content_callback,
completion_callback));
}
-void FileSystem::GetResourceEntryByPath(
+void FileSystem::GetResourceEntry(
const base::FilePath& file_path,
const GetResourceEntryCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!callback.is_null());
- scoped_ptr<ResourceEntry> entry(new ResourceEntry);
- ResourceEntry* entry_ptr = entry.get();
- base::PostTaskAndReplyWithResult(
- blocking_task_runner_,
- FROM_HERE,
- base::Bind(&GetLocallyStoredResourceEntry,
- resource_metadata_,
- cache_,
- file_path,
- entry_ptr),
- base::Bind(&FileSystem::GetResourceEntryByPathAfterGetEntry,
+ change_list_loader_->LoadDirectoryIfNeeded(
+ file_path.DirName(),
+ base::Bind(&FileSystem::GetResourceEntryAfterLoad,
weak_ptr_factory_.GetWeakPtr(),
file_path,
- callback,
- base::Passed(&entry)));
-}
-
-void FileSystem::GetResourceEntryByPathAfterGetEntry(
- const base::FilePath& file_path,
- const GetResourceEntryCallback& callback,
- scoped_ptr<ResourceEntry> entry,
- FileError error) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(!callback.is_null());
-
- if (error == FILE_ERROR_NOT_FOUND) {
- // If the information about the path is not in the local ResourceMetadata,
- // try fetching information of the directory and retry.
- //
- // Note: this forms mutual recursion between GetResourceEntryByPath and
- // LoadDirectoryIfNeeded, because directory loading requires the existence
- // of directory entry itself. The recursion terminates because we always go
- // up the hierarchy by .DirName() bounded under the Drive root path.
- if (util::GetDriveGrandRootPath().IsParent(file_path)) {
- LoadDirectoryIfNeeded(
- file_path.DirName(),
- base::Bind(&FileSystem::GetResourceEntryByPathAfterLoad,
- weak_ptr_factory_.GetWeakPtr(),
- file_path,
- callback));
- return;
- }
- }
-
- callback.Run(error, entry.Pass());
+ callback));
}
-void FileSystem::GetResourceEntryByPathAfterLoad(
+void FileSystem::GetResourceEntryAfterLoad(
const base::FilePath& file_path,
const GetResourceEntryCallback& callback,
FileError error) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!callback.is_null());
- if (error != FILE_ERROR_OK) {
- callback.Run(error, scoped_ptr<ResourceEntry>());
- return;
- }
+ DVLOG_IF(1, error != FILE_ERROR_OK) << "LoadDirectoryIfNeeded failed. "
+ << FileErrorToString(error);
scoped_ptr<ResourceEntry> entry(new ResourceEntry);
ResourceEntry* entry_ptr = entry.get();
cache_,
file_path,
entry_ptr),
- base::Bind(&RunGetResourceEntryCallback,
- callback,
- base::Passed(&entry)));
+ base::Bind(&RunGetResourceEntryCallback, callback, base::Passed(&entry)));
}
-void FileSystem::ReadDirectoryByPath(
+void FileSystem::ReadDirectory(
const base::FilePath& directory_path,
const ReadDirectoryCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!callback.is_null());
- LoadDirectoryIfNeeded(
- directory_path,
- base::Bind(&FileSystem::ReadDirectoryByPathAfterLoad,
- weak_ptr_factory_.GetWeakPtr(),
- directory_path,
- callback));
-}
-
-void FileSystem::LoadDirectoryIfNeeded(const base::FilePath& directory_path,
- const FileOperationCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(!callback.is_null());
-
- GetResourceEntryByPath(
+ change_list_loader_->LoadDirectoryIfNeeded(
directory_path,
- base::Bind(&FileSystem::LoadDirectoryIfNeededAfterGetEntry,
+ base::Bind(&FileSystem::ReadDirectoryAfterLoad,
weak_ptr_factory_.GetWeakPtr(),
directory_path,
callback));
}
-void FileSystem::LoadDirectoryIfNeededAfterGetEntry(
- const base::FilePath& directory_path,
- const FileOperationCallback& callback,
- FileError error,
- scoped_ptr<ResourceEntry> entry) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(!callback.is_null());
-
- if (error != FILE_ERROR_OK) {
- callback.Run(error);
- return;
- }
-
- if (!entry->file_info().is_directory()) {
- callback.Run(FILE_ERROR_NOT_A_DIRECTORY);
- return;
- }
-
- // Pass the directory fetch info so we can fetch the contents of the
- // directory before loading change lists.
- internal::DirectoryFetchInfo directory_fetch_info(
- entry->resource_id(),
- entry->directory_specific_info().changestamp());
- change_list_loader_->LoadIfNeeded(directory_fetch_info, callback);
-}
-
-void FileSystem::ReadDirectoryByPathAfterLoad(
+void FileSystem::ReadDirectoryAfterLoad(
const base::FilePath& directory_path,
const ReadDirectoryCallback& callback,
FileError error) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!callback.is_null());
- DLOG_IF(INFO, error != FILE_ERROR_OK) << "LoadIfNeeded failed. "
- << FileErrorToString(error);
+ DVLOG_IF(1, error != FILE_ERROR_OK) << "LoadDirectoryIfNeeded failed. "
+ << FileErrorToString(error);
- resource_metadata_->ReadDirectoryByPathOnUIThread(
- directory_path,
- base::Bind(&FileSystem::ReadDirectoryByPathAfterRead,
+ ResourceEntryVector* entries = new ResourceEntryVector;
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner_.get(),
+ FROM_HERE,
+ base::Bind(&internal::ResourceMetadata::ReadDirectoryByPath,
+ base::Unretained(resource_metadata_),
+ directory_path,
+ entries),
+ base::Bind(&FileSystem::ReadDirectoryAfterRead,
weak_ptr_factory_.GetWeakPtr(),
directory_path,
- callback));
+ callback,
+ base::Owned(entries)));
}
-void FileSystem::ReadDirectoryByPathAfterRead(
- const base::FilePath& directory_path,
- const ReadDirectoryCallback& callback,
- FileError error,
- scoped_ptr<ResourceEntryVector> entries) {
+void FileSystem::ReadDirectoryAfterRead(const base::FilePath& directory_path,
+ const ReadDirectoryCallback& callback,
+ const ResourceEntryVector* entries,
+ FileError error) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!callback.is_null());
if (error != FILE_ERROR_OK) {
- callback.Run(error,
- scoped_ptr<ResourceEntryVector>());
+ callback.Run(error, scoped_ptr<ResourceEntryVector>(), false);
return;
}
- DCHECK(entries.get()); // This is valid for empty directories too.
// TODO(satorux): Stop handling hide_hosted_docs here. crbug.com/256520.
const bool hide_hosted_docs =
filtered->push_back(entries->at(i));
}
- callback.Run(FILE_ERROR_OK, filtered.Pass());
+ callback.Run(FILE_ERROR_OK, filtered.Pass(), false);
}
void FileSystem::GetAvailableSpace(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!callback.is_null());
- scheduler_->GetAboutResource(
+ about_resource_loader_->GetAboutResource(
base::Bind(&FileSystem::OnGetAboutResource,
weak_ptr_factory_.GetWeakPtr(),
callback));
callback.Run(error, GURL());
return;
}
- if (util::IsSpecialResourceId(entry->resource_id())) {
- // Do not load special directories. Just return.
+ if (entry->resource_id().empty()) {
+ // This entry does not exist on the server. Just return.
callback.Run(FILE_ERROR_FAILED, GURL());
return;
}
OnDirectoryChanged(directory_path);
}
-void FileSystem::OnCacheFileUploadNeededByOperation(
- const std::string& local_id) {
- sync_client_->AddUploadTask(local_id);
+void FileSystem::OnEntryUpdatedByOperation(const std::string& local_id) {
+ sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), local_id);
+}
+
+void FileSystem::OnDriveSyncError(file_system::DriveSyncErrorType type,
+ const std::string& local_id) {
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner_,
+ FROM_HERE,
+ base::Bind(&internal::ResourceMetadata::GetFilePath,
+ base::Unretained(resource_metadata_),
+ local_id),
+ base::Bind(&FileSystem::OnDriveSyncErrorAfterGetFilePath,
+ weak_ptr_factory_.GetWeakPtr(),
+ type));
+}
+
+void FileSystem::OnDriveSyncErrorAfterGetFilePath(
+ file_system::DriveSyncErrorType type,
+ const base::FilePath& path) {
+ if (path.empty())
+ return;
+ FOR_EACH_OBSERVER(FileSystemObserver,
+ observers_,
+ OnDriveSyncError(type, path));
}
void FileSystem::OnDirectoryChanged(const base::FilePath& directory_path) {
callback.Run(FILE_ERROR_FAILED);
return;
}
- cache_->MarkAsUnmountedOnUIThread(cache_file_path, callback);
+
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner_,
+ FROM_HERE,
+ base::Bind(&internal::FileCache::MarkAsUnmounted,
+ base::Unretained(cache_),
+ cache_file_path),
+ callback);
}
-void FileSystem::GetCacheEntryByPath(
+void FileSystem::GetCacheEntry(
const base::FilePath& drive_file_path,
const GetCacheEntryCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
base::PostTaskAndReplyWithResult(
blocking_task_runner_,
FROM_HERE,
- base::Bind(&GetCacheEntryByPathInternal,
+ base::Bind(&GetCacheEntryInternal,
resource_metadata_,
cache_,
drive_file_path,