This source file includes following definitions.
- PrepareUpdate
- FinishUpdate
- weak_ptr_factory_
- UpdateEntry
- UpdateEntryAfterPrepare
- UpdateEntryAfterUpdateResource
- UpdateEntryAfterFinish
#include "chrome/browser/chromeos/drive/sync/entry_update_performer.h"
#include "base/callback_helpers.h"
#include "base/file_util.h"
#include "chrome/browser/chromeos/drive/change_list_loader.h"
#include "chrome/browser/chromeos/drive/drive.pb.h"
#include "chrome/browser/chromeos/drive/file_cache.h"
#include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
#include "chrome/browser/chromeos/drive/file_system_util.h"
#include "chrome/browser/chromeos/drive/job_scheduler.h"
#include "chrome/browser/chromeos/drive/resource_metadata.h"
#include "chrome/browser/chromeos/drive/sync/entry_revert_performer.h"
#include "chrome/browser/chromeos/drive/sync/remove_performer.h"
#include "content/public/browser/browser_thread.h"
using content::BrowserThread;
namespace drive {
namespace internal {
struct EntryUpdatePerformer::LocalState {
LocalState() : should_content_update(false) {
}
ResourceEntry entry;
ResourceEntry parent_entry;
base::FilePath drive_file_path;
base::FilePath cache_file_path;
bool should_content_update;
};
namespace {
FileError PrepareUpdate(ResourceMetadata* metadata,
FileCache* cache,
const std::string& local_id,
EntryUpdatePerformer::LocalState* local_state) {
FileError error = metadata->GetResourceEntryById(local_id,
&local_state->entry);
if (error != FILE_ERROR_OK)
return error;
error = metadata->GetResourceEntryById(local_state->entry.parent_local_id(),
&local_state->parent_entry);
if (error != FILE_ERROR_OK)
return error;
local_state->drive_file_path = metadata->GetFilePath(local_id);
if (local_state->drive_file_path.empty())
return FILE_ERROR_NOT_FOUND;
FileCacheEntry cache_entry;
cache->GetCacheEntry(local_id, &cache_entry);
if (!local_state->entry.file_info().is_directory() &&
!cache_entry.is_present() && local_state->entry.resource_id().empty()) {
base::FilePath empty_file;
if (!base::CreateTemporaryFile(&empty_file))
return FILE_ERROR_FAILED;
error = cache->Store(local_id, std::string(), empty_file,
FileCache::FILE_OPERATION_MOVE);
if (error != FILE_ERROR_OK)
return error;
if (!cache->GetCacheEntry(local_id, &cache_entry))
return FILE_ERROR_NOT_FOUND;
}
if (cache_entry.is_dirty() && !cache->IsOpenedForWrite(local_id)) {
if (cache_entry.md5().empty()) {
error = cache->UpdateMd5(local_id);
if (error != FILE_ERROR_OK)
return error;
if (!cache->GetCacheEntry(local_id, &cache_entry))
return FILE_ERROR_NOT_FOUND;
}
if (cache_entry.md5() == local_state->entry.file_specific_info().md5()) {
error = cache->ClearDirty(local_id);
if (error != FILE_ERROR_OK)
return error;
} else {
error = cache->GetFile(local_id, &local_state->cache_file_path);
if (error != FILE_ERROR_OK)
return error;
local_state->should_content_update = true;
}
}
switch (local_state->entry.metadata_edit_state()) {
case ResourceEntry::CLEAN:
case ResourceEntry::SYNCING:
break;
case ResourceEntry::DIRTY:
local_state->entry.set_metadata_edit_state(ResourceEntry::SYNCING);
error = metadata->RefreshEntry(local_state->entry);
if (error != FILE_ERROR_OK)
return error;
break;
}
return FILE_ERROR_OK;
}
FileError FinishUpdate(ResourceMetadata* metadata,
FileCache* cache,
const std::string& local_id,
scoped_ptr<google_apis::ResourceEntry> resource_entry,
base::FilePath* changed_directory) {
std::string existing_local_id;
FileError error = metadata->GetIdByResourceId(
resource_entry->resource_id(), &existing_local_id);
switch (error) {
case FILE_ERROR_OK:
if (existing_local_id != local_id) {
base::FilePath existing_entry_path =
metadata->GetFilePath(existing_local_id);
error = metadata->RemoveEntry(existing_local_id);
if (error != FILE_ERROR_OK)
return error;
*changed_directory = existing_entry_path.DirName();
}
break;
case FILE_ERROR_NOT_FOUND:
break;
default:
return error;
}
ResourceEntry entry;
error = metadata->GetResourceEntryById(local_id, &entry);
if (error != FILE_ERROR_OK)
return error;
switch (entry.metadata_edit_state()) {
case ResourceEntry::CLEAN:
case ResourceEntry::DIRTY:
break;
case ResourceEntry::SYNCING:
entry.set_metadata_edit_state(ResourceEntry::CLEAN);
break;
}
if (!entry.file_info().is_directory())
entry.mutable_file_specific_info()->set_md5(resource_entry->file_md5());
entry.set_resource_id(resource_entry->resource_id());
error = metadata->RefreshEntry(entry);
if (error != FILE_ERROR_OK)
return error;
FileCacheEntry cache_entry;
if (cache->GetCacheEntry(local_id, &cache_entry) &&
cache_entry.md5() == entry.file_specific_info().md5()) {
error = cache->ClearDirty(local_id);
if (error != FILE_ERROR_OK)
return error;
}
return FILE_ERROR_OK;
}
}
EntryUpdatePerformer::EntryUpdatePerformer(
base::SequencedTaskRunner* blocking_task_runner,
file_system::OperationObserver* observer,
JobScheduler* scheduler,
ResourceMetadata* metadata,
FileCache* cache,
LoaderController* loader_controller)
: blocking_task_runner_(blocking_task_runner),
observer_(observer),
scheduler_(scheduler),
metadata_(metadata),
cache_(cache),
loader_controller_(loader_controller),
remove_performer_(new RemovePerformer(blocking_task_runner,
observer,
scheduler,
metadata)),
entry_revert_performer_(new EntryRevertPerformer(blocking_task_runner,
observer,
scheduler,
metadata)),
weak_ptr_factory_(this) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
EntryUpdatePerformer::~EntryUpdatePerformer() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
void EntryUpdatePerformer::UpdateEntry(const std::string& local_id,
const ClientContext& context,
const FileOperationCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!callback.is_null());
scoped_ptr<LocalState> local_state(new LocalState);
LocalState* local_state_ptr = local_state.get();
base::PostTaskAndReplyWithResult(
blocking_task_runner_.get(),
FROM_HERE,
base::Bind(&PrepareUpdate, metadata_, cache_, local_id, local_state_ptr),
base::Bind(&EntryUpdatePerformer::UpdateEntryAfterPrepare,
weak_ptr_factory_.GetWeakPtr(), context, callback,
base::Passed(&local_state)));
}
void EntryUpdatePerformer::UpdateEntryAfterPrepare(
const ClientContext& context,
const FileOperationCallback& callback,
scoped_ptr<LocalState> local_state,
FileError error) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!callback.is_null());
if (error != FILE_ERROR_OK) {
callback.Run(error);
return;
}
if (local_state->entry.parent_local_id() == util::kDriveTrashDirLocalId) {
remove_performer_->Remove(local_state->entry.local_id(), context, callback);
return;
}
if (local_state->parent_entry.resource_id().empty() &&
local_state->parent_entry.metadata_edit_state() != ResourceEntry::CLEAN) {
callback.Run(FILE_ERROR_OK);
return;
}
base::Time last_modified = base::Time::FromInternalValue(
local_state->entry.file_info().last_modified());
base::Time last_accessed = base::Time::FromInternalValue(
local_state->entry.file_info().last_accessed());
if (local_state->should_content_update) {
if (local_state->entry.resource_id().empty()) {
scoped_ptr<base::ScopedClosureRunner> null_loader_lock;
DriveUploader::UploadNewFileOptions options;
options.modified_date = last_modified;
options.last_viewed_by_me_date = last_accessed;
scheduler_->UploadNewFile(
local_state->parent_entry.resource_id(),
local_state->drive_file_path,
local_state->cache_file_path,
local_state->entry.title(),
local_state->entry.file_specific_info().content_mime_type(),
options,
context,
base::Bind(&EntryUpdatePerformer::UpdateEntryAfterUpdateResource,
weak_ptr_factory_.GetWeakPtr(),
context,
callback,
local_state->entry.local_id(),
base::Passed(&null_loader_lock)));
} else {
DriveUploader::UploadExistingFileOptions options;
options.title = local_state->entry.title();
options.parent_resource_id = local_state->parent_entry.resource_id();
options.modified_date = last_modified;
options.last_viewed_by_me_date = last_accessed;
scheduler_->UploadExistingFile(
local_state->entry.resource_id(),
local_state->drive_file_path,
local_state->cache_file_path,
local_state->entry.file_specific_info().content_mime_type(),
options,
context,
base::Bind(&EntryUpdatePerformer::UpdateEntryAfterUpdateResource,
weak_ptr_factory_.GetWeakPtr(),
context,
callback,
local_state->entry.local_id(),
base::Passed(scoped_ptr<base::ScopedClosureRunner>())));
}
return;
}
if (local_state->entry.file_info().is_directory() &&
local_state->entry.resource_id().empty()) {
scoped_ptr<base::ScopedClosureRunner> loader_lock =
loader_controller_->GetLock();
DriveServiceInterface::AddNewDirectoryOptions options;
options.modified_date = last_modified;
options.last_viewed_by_me_date = last_accessed;
scheduler_->AddNewDirectory(
local_state->parent_entry.resource_id(),
local_state->entry.title(),
options,
context,
base::Bind(&EntryUpdatePerformer::UpdateEntryAfterUpdateResource,
weak_ptr_factory_.GetWeakPtr(),
context,
callback,
local_state->entry.local_id(),
base::Passed(&loader_lock)));
return;
}
if (local_state->entry.metadata_edit_state() == ResourceEntry::CLEAN ||
local_state->entry.resource_id().empty()) {
callback.Run(FILE_ERROR_OK);
return;
}
scheduler_->UpdateResource(
local_state->entry.resource_id(), local_state->parent_entry.resource_id(),
local_state->entry.title(), last_modified, last_accessed,
context,
base::Bind(&EntryUpdatePerformer::UpdateEntryAfterUpdateResource,
weak_ptr_factory_.GetWeakPtr(),
context, callback, local_state->entry.local_id(),
base::Passed(scoped_ptr<base::ScopedClosureRunner>())));
}
void EntryUpdatePerformer::UpdateEntryAfterUpdateResource(
const ClientContext& context,
const FileOperationCallback& callback,
const std::string& local_id,
scoped_ptr<base::ScopedClosureRunner> loader_lock,
google_apis::GDataErrorCode status,
scoped_ptr<google_apis::ResourceEntry> resource_entry) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!callback.is_null());
if (status == google_apis::HTTP_FORBIDDEN) {
entry_revert_performer_->RevertEntry(local_id, context, callback);
return;
}
FileError error = GDataToFileError(status);
if (error != FILE_ERROR_OK) {
callback.Run(error);
return;
}
base::FilePath* changed_directory = new base::FilePath;
base::PostTaskAndReplyWithResult(
blocking_task_runner_.get(),
FROM_HERE,
base::Bind(&FinishUpdate,
metadata_, cache_, local_id, base::Passed(&resource_entry),
changed_directory),
base::Bind(&EntryUpdatePerformer::UpdateEntryAfterFinish,
weak_ptr_factory_.GetWeakPtr(), callback,
base::Owned(changed_directory)));
}
void EntryUpdatePerformer::UpdateEntryAfterFinish(
const FileOperationCallback& callback,
const base::FilePath* changed_directory,
FileError error) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!callback.is_null());
if (!changed_directory->empty())
observer_->OnDirectoryChangedByOperation(*changed_directory);
callback.Run(error);
}
}
}