Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(12)

Unified Diff: chrome/browser/sync_file_system/drive/apply_local_change_delegate.cc

Issue 14977008: [SyncFileSystem] Separate out ApplyLocalChange from DriveFileSyncService. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: drop extra empty line Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/sync_file_system/drive/apply_local_change_delegate.cc
diff --git a/chrome/browser/sync_file_system/drive/apply_local_change_delegate.cc b/chrome/browser/sync_file_system/drive/apply_local_change_delegate.cc
new file mode 100644
index 0000000000000000000000000000000000000000..183177e4c460828a4a1ec131d2e8b9337bc83f8b
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive/apply_local_change_delegate.cc
@@ -0,0 +1,612 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sync_file_system/drive/apply_local_change_delegate.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "chrome/browser/sync_file_system/drive/api_util.h"
+#include "chrome/browser/sync_file_system/drive_file_sync_service.h"
+#include "chrome/browser/sync_file_system/drive_metadata_store.h"
+#include "webkit/fileapi/syncable/syncable_file_system_util.h"
+
+namespace sync_file_system {
+namespace drive {
+
+namespace {
+
+void OwnDelegateInstance(ApplyLocalChangeDelegate* delegate,
+ const SyncStatusCallback& callback,
+ SyncStatusCode status) {
+ callback.Run(status);
+}
+
+} // namespace
+
+ApplyLocalChangeDelegate::~ApplyLocalChangeDelegate() {}
+
+ApplyLocalChangeDelegate::ApplyLocalChangeDelegate(
kinuko 2013/05/16 06:57:49 nit: method order different from .h
tzik 2013/05/16 11:06:14 Done.
+ base::WeakPtr<DriveFileSyncService> sync_service,
+ const FileChange& local_change,
+ const base::FilePath& local_path,
+ const SyncFileMetadata& local_metadata,
+ const fileapi::FileSystemURL& url)
+ : sync_service_(sync_service),
+ url_(url),
+ local_change_(local_change),
+ local_path_(local_path),
+ local_metadata_(local_metadata),
+ has_drive_metadata_(false),
+ has_remote_change_(false),
+ weak_factory_(this) {}
+
+void ApplyLocalChangeDelegate::ApplyLocalChange(
+ base::WeakPtr<DriveFileSyncService> sync_service,
+ const FileChange& local_change,
+ const base::FilePath& local_path,
+ const SyncFileMetadata& local_metadata,
+ const fileapi::FileSystemURL& url,
+ const SyncStatusCallback& callback) {
+ if (!sync_service)
+ return;
+
+ ApplyLocalChangeDelegate* delegate = new ApplyLocalChangeDelegate(
+ sync_service, local_change, local_path, local_metadata, url);
+ SyncStatusCallback completion_callback =
+ base::Bind(&OwnDelegateInstance, base::Owned(delegate), callback);
kinuko 2013/05/16 06:57:49 I understand this class's very self-contained and
tzik 2013/05/16 11:06:14 Done. I added |running_local_sync_task_| to DriveF
+ delegate->Run(completion_callback);
+}
+
+void ApplyLocalChangeDelegate::Run(const SyncStatusCallback& callback) {
+ if (!sync_service_)
+ return;
+
+ // TODO(nhiroki): support directory operations (http://crbug.com/161442).
+ DCHECK(IsSyncDirectoryOperationEnabled() || !local_change_.IsDirectory());
+
+ has_drive_metadata_ =
+ metadata_store()->ReadEntry(url_, &drive_metadata_) == SYNC_STATUS_OK;
+
+ if (!has_drive_metadata_)
+ drive_metadata_.set_md5_checksum(std::string());
+
+ sync_service_->EnsureOriginRootDirectory(
+ url_.origin(),
+ base::Bind(&ApplyLocalChangeDelegate::DidGetOriginRoot,
+ weak_factory_.GetWeakPtr(),
+ callback));
+}
+
+void ApplyLocalChangeDelegate::DidGetOriginRoot(
+ const SyncStatusCallback& callback,
+ SyncStatusCode status,
+ const std::string& origin_resource_id) {
+ if (!sync_service_)
+ return;
+
+ if (status != SYNC_STATUS_OK) {
+ callback.Run(status);
+ return;
+ }
+
+ origin_resource_id_ = origin_resource_id;
+
+ has_remote_change_ =
+ remote_change_handler()->GetChangeForURL(url_, &remote_change_);
+ if (has_remote_change_ && drive_metadata_.resource_id().empty())
+ drive_metadata_.set_resource_id(remote_change_.resource_id);
+
+ LocalSyncOperationType operation = LocalSyncOperationResolver::Resolve(
+ local_change_,
+ has_remote_change_ ? &remote_change_.change : NULL,
+ has_drive_metadata_ ? &drive_metadata_ : NULL);
+
+ DVLOG(1) << "ApplyLocalChange for " << url_.DebugString()
+ << " local_change:" << local_change_.DebugString()
+ << " ==> operation:" << operation;
+
+ switch (operation) {
+ case LOCAL_SYNC_OPERATION_ADD_FILE:
+ UploadNewFile(callback);
+ return;
+ case LOCAL_SYNC_OPERATION_ADD_DIRECTORY:
+ CreateDirectory(callback);
+ return;
+ case LOCAL_SYNC_OPERATION_UPDATE_FILE:
+ UploadExistingFile(callback);
+ return;
+ case LOCAL_SYNC_OPERATION_DELETE_FILE:
+ DeleteFile(callback);
+ return;
+ case LOCAL_SYNC_OPERATION_DELETE_DIRECTORY:
+ DeleteDirectory(callback);
+ return;
+ case LOCAL_SYNC_OPERATION_NONE:
+ callback.Run(SYNC_STATUS_OK);
+ return;
+ case LOCAL_SYNC_OPERATION_CONFLICT:
+ HandleConflict(callback);
+ return;
+ case LOCAL_SYNC_OPERATION_RESOLVE_TO_LOCAL:
+ ResolveToLocal(callback);
+ return;
+ case LOCAL_SYNC_OPERATION_RESOLVE_TO_REMOTE:
+ ResolveToRemote(callback);
+ return;
+ case LOCAL_SYNC_OPERATION_DELETE_METADATA:
+ DeleteMetadata(base::Bind(
+ &ApplyLocalChangeDelegate::DidApplyLocalChange,
+ weak_factory_.GetWeakPtr(), callback, google_apis::HTTP_SUCCESS));
+ return;
+ case LOCAL_SYNC_OPERATION_FAIL: {
+ callback.Run(SYNC_STATUS_FAILED);
+ return;
+ }
+ }
+ NOTREACHED();
+ callback.Run(SYNC_STATUS_FAILED);
+}
+
+void ApplyLocalChangeDelegate::UploadNewFile(
+ const SyncStatusCallback& callback) {
+ if (!sync_service_)
+ return;
+
+ api_util()->UploadNewFile(
+ origin_resource_id_,
+ local_path_,
+ DriveFileSyncService::PathToTitle(url_.path()),
+ base::Bind(&ApplyLocalChangeDelegate::DidUploadNewFile,
+ weak_factory_.GetWeakPtr(), callback));
+}
+
+void ApplyLocalChangeDelegate::DidUploadNewFile(
+ const SyncStatusCallback& callback,
+ google_apis::GDataErrorCode error,
+ const std::string& resource_id,
+ const std::string& md5) {
+ if (!sync_service_)
+ return;
+
+ switch (error) {
+ case google_apis::HTTP_CREATED:
+ UpdateMetadata(
+ resource_id, md5, DriveMetadata::RESOURCE_TYPE_FILE,
+ base::Bind(&ApplyLocalChangeDelegate::DidApplyLocalChange,
+ weak_factory_.GetWeakPtr(), callback, error));
+ sync_service_->NotifyObserversFileStatusChanged(
+ url_,
+ SYNC_FILE_STATUS_SYNCED,
+ SYNC_ACTION_ADDED,
+ SYNC_DIRECTION_LOCAL_TO_REMOTE);
+ return;
+ case google_apis::HTTP_CONFLICT:
+ HandleCreationConflict(resource_id, DriveMetadata::RESOURCE_TYPE_FILE,
+ callback);
+ return;
+ default:
+ callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
+ }
+}
+
+void ApplyLocalChangeDelegate::CreateDirectory(
+ const SyncStatusCallback& callback) {
+ if (!sync_service_)
+ return;
+
+ DCHECK(IsSyncDirectoryOperationEnabled());
+ api_util()->CreateDirectory(
+ origin_resource_id_,
+ DriveFileSyncService::PathToTitle(url_.path()),
+ base::Bind(&ApplyLocalChangeDelegate::DidCreateDirectory,
+ weak_factory_.GetWeakPtr(), callback));
+}
+
+void ApplyLocalChangeDelegate::DidCreateDirectory(
+ const SyncStatusCallback& callback,
+ google_apis::GDataErrorCode error,
+ const std::string& resource_id) {
+ if (!sync_service_)
+ return;
+
+ switch (error) {
+ case google_apis::HTTP_SUCCESS:
+ case google_apis::HTTP_CREATED: {
+ UpdateMetadata(
+ resource_id, std::string(), DriveMetadata::RESOURCE_TYPE_FOLDER,
+ base::Bind(&ApplyLocalChangeDelegate::DidApplyLocalChange,
+ weak_factory_.GetWeakPtr(), callback, error));
+ sync_service_->NotifyObserversFileStatusChanged(
+ url_,
+ SYNC_FILE_STATUS_SYNCED,
+ SYNC_ACTION_ADDED,
+ SYNC_DIRECTION_LOCAL_TO_REMOTE);
+ return;
+ }
+
+ case google_apis::HTTP_CONFLICT:
+ // There were conflicts and a file was left.
+ // TODO(kinuko): Handle the latter case (http://crbug.com/237090).
+ // Fall-through
+
+ default:
+ callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
+ }
+}
+
+void ApplyLocalChangeDelegate::UploadExistingFile(
+ const SyncStatusCallback& callback) {
+ if (!sync_service_)
+ return;
+
+ DCHECK(has_drive_metadata_);
+ api_util()->UploadExistingFile(
+ drive_metadata_.resource_id(),
+ drive_metadata_.md5_checksum(),
+ local_path_,
+ base::Bind(&ApplyLocalChangeDelegate::DidUploadExistingFile,
+ weak_factory_.GetWeakPtr(), callback));
+}
+
+void ApplyLocalChangeDelegate::DidUploadExistingFile(
+ const SyncStatusCallback& callback,
+ google_apis::GDataErrorCode error,
+ const std::string& resource_id,
+ const std::string& md5) {
+ if (!sync_service_)
+ return;
+
+ DCHECK(has_drive_metadata_);
+ switch (error) {
+ case google_apis::HTTP_SUCCESS:
+ UpdateMetadata(
+ resource_id, md5, DriveMetadata::RESOURCE_TYPE_FILE,
+ base::Bind(&ApplyLocalChangeDelegate::DidApplyLocalChange,
+ weak_factory_.GetWeakPtr(), callback, error));
+ sync_service_->NotifyObserversFileStatusChanged(
+ url_,
+ SYNC_FILE_STATUS_SYNCED,
+ SYNC_ACTION_UPDATED,
+ SYNC_DIRECTION_LOCAL_TO_REMOTE);
+ return;
+ case google_apis::HTTP_CONFLICT: {
+ HandleConflict(callback);
+ return;
+ }
+ case google_apis::HTTP_NOT_MODIFIED: {
+ DidApplyLocalChange(callback,
+ google_apis::HTTP_SUCCESS, SYNC_STATUS_OK);
+ return;
+ }
+ case google_apis::HTTP_NOT_FOUND: {
+ UploadNewFile(callback);
+ return;
+ }
+ default: {
+ const SyncStatusCode status =
+ GDataErrorCodeToSyncStatusCodeWrapper(error);
+ DCHECK_NE(SYNC_STATUS_OK, status);
+ callback.Run(status);
+ return;
+ }
+ }
+}
+
+void ApplyLocalChangeDelegate::DeleteFile(
+ const SyncStatusCallback& callback) {
+ if (!sync_service_)
+ return;
+
+ DCHECK(has_drive_metadata_);
+ api_util()->DeleteFile(
+ drive_metadata_.resource_id(),
+ drive_metadata_.md5_checksum(),
+ base::Bind(&ApplyLocalChangeDelegate::DidDeleteFile,
+ weak_factory_.GetWeakPtr(), callback));
+}
+
+void ApplyLocalChangeDelegate::DeleteDirectory(
+ const SyncStatusCallback& callback) {
+ if (!sync_service_)
+ return;
+
+ DCHECK(IsSyncDirectoryOperationEnabled());
+ DCHECK(has_drive_metadata_);
+ // This does not handle recursive directory deletion
+ // (which should not happen other than after a restart).
+ api_util()->DeleteFile(
+ drive_metadata_.resource_id(),
+ std::string(), // empty md5
+ base::Bind(&ApplyLocalChangeDelegate::DidDeleteFile,
+ weak_factory_.GetWeakPtr(), callback));
+}
+
+void ApplyLocalChangeDelegate::DidDeleteFile(
+ const SyncStatusCallback& callback,
+ google_apis::GDataErrorCode error) {
+ if (!sync_service_)
+ return;
+
+ DCHECK(has_drive_metadata_);
+
+ switch (error) {
+ // Regardless of whether the deletion has succeeded (HTTP_SUCCESS) or
+ // has failed with ETag conflict error (HTTP_PRECONDITION or HTTP_CONFLICT)
+ // we should just delete the drive_metadata.
+ // In the former case the file should be just gone now, and
+ // in the latter case the remote change will be applied in a future
+ // remote sync.
+ case google_apis::HTTP_SUCCESS:
+ case google_apis::HTTP_PRECONDITION:
+ case google_apis::HTTP_CONFLICT:
+ DeleteMetadata(base::Bind(&ApplyLocalChangeDelegate::DidApplyLocalChange,
+ weak_factory_.GetWeakPtr(), callback, error));
+ sync_service_->NotifyObserversFileStatusChanged(
+ url_,
+ SYNC_FILE_STATUS_SYNCED,
+ SYNC_ACTION_DELETED,
+ SYNC_DIRECTION_LOCAL_TO_REMOTE);
+ return;
+ case google_apis::HTTP_NOT_FOUND:
+ DidApplyLocalChange(callback,
+ google_apis::HTTP_SUCCESS, SYNC_STATUS_OK);
+ return;
+ default: {
+ const SyncStatusCode status =
+ GDataErrorCodeToSyncStatusCodeWrapper(error);
+ DCHECK_NE(SYNC_STATUS_OK, status);
+ callback.Run(status);
+ return;
+ }
+ }
+}
+
+void ApplyLocalChangeDelegate::ResolveToLocal(
+ const SyncStatusCallback& callback) {
+ if (!sync_service_)
+ return;
+
+ api_util()->DeleteFile(
+ drive_metadata_.resource_id(),
+ drive_metadata_.md5_checksum(),
+ base::Bind(
+ &ApplyLocalChangeDelegate::DidDeleteFileToResolveToLocal,
+ weak_factory_.GetWeakPtr(), callback));
+}
+
+void ApplyLocalChangeDelegate::DidDeleteFileToResolveToLocal(
+ const SyncStatusCallback& callback,
+ google_apis::GDataErrorCode error) {
+ if (!sync_service_)
+ return;
+
+ if (error != google_apis::HTTP_SUCCESS &&
+ error != google_apis::HTTP_NOT_FOUND) {
+ remote_change_handler()->RemoveChangeForURL(url_);
+ callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
+ return;
+ }
+
+ DCHECK_NE(SYNC_FILE_TYPE_UNKNOWN, local_metadata_.file_type);
+ if (local_metadata_.file_type == SYNC_FILE_TYPE_FILE) {
+ UploadNewFile(callback);
+ return;
+ }
+
+ DCHECK(IsSyncDirectoryOperationEnabled());
+ DCHECK_EQ(SYNC_FILE_TYPE_DIRECTORY, local_metadata_.file_type);
+ CreateDirectory(callback);
+}
+
+void ApplyLocalChangeDelegate::ResolveToRemote(
+ const SyncStatusCallback& callback) {
+ if (!sync_service_)
+ return;
+
+ // Mark the file as to-be-fetched.
+ DCHECK(!drive_metadata_.resource_id().empty());
+
+ SyncFileType type = remote_change_.change.file_type();
+ SetToBeFetched(
+ drive_metadata_.resource_id(),
+ DriveFileSyncService::SyncFileTypeToDriveMetadataResourceType(type),
+ base::Bind(&ApplyLocalChangeDelegate::DidResolveToRemote,
+ weak_factory_.GetWeakPtr(), callback));
+ // The synced notification will be dispatched when the remote file is
+ // downloaded.
+}
+
+void ApplyLocalChangeDelegate::DidResolveToRemote(
+ const SyncStatusCallback& callback,
+ SyncStatusCode status) {
+ if (!sync_service_)
+ return;
+
+ DCHECK(has_drive_metadata_);
+ if (status != SYNC_STATUS_OK) {
+ callback.Run(status);
+ return;
+ }
+
+ SyncFileType file_type = SYNC_FILE_TYPE_FILE;
+ if (drive_metadata_.type() == DriveMetadata::RESOURCE_TYPE_FOLDER)
+ file_type = SYNC_FILE_TYPE_DIRECTORY;
+ sync_service_->AppendFetchChange(
+ url_.origin(), url_.path(), drive_metadata_.resource_id(), file_type);
+ callback.Run(status);
+}
+
+void ApplyLocalChangeDelegate::DidApplyLocalChange(
+ const SyncStatusCallback& callback,
+ const google_apis::GDataErrorCode error,
+ SyncStatusCode status) {
+ if (!sync_service_)
+ return;
+
+ if (status == SYNC_STATUS_OK) {
+ remote_change_handler()->RemoveChangeForURL(url_);
+ status = GDataErrorCodeToSyncStatusCodeWrapper(error);
+ }
+ callback.Run(status);
+}
+
+void ApplyLocalChangeDelegate::UpdateMetadata(
+ const std::string& resource_id,
+ const std::string& md5,
+ DriveMetadata::ResourceType type,
+ const SyncStatusCallback& callback) {
+ if (!sync_service_)
+ return;
+
+ drive_metadata_.set_resource_id(resource_id);
+ drive_metadata_.set_md5_checksum(md5);
+ drive_metadata_.set_conflicted(false);
+ drive_metadata_.set_to_be_fetched(false);
+ drive_metadata_.set_type(type);
+ metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
+}
+
+void ApplyLocalChangeDelegate::SetToBeFetched(
+ const std::string& resource_id,
+ DriveMetadata::ResourceType type,
+ const SyncStatusCallback& callback) {
+ if (!sync_service_)
+ return;
+
+ drive_metadata_.set_resource_id(resource_id);
+ drive_metadata_.set_md5_checksum(std::string());
+ drive_metadata_.set_conflicted(false);
+ drive_metadata_.set_to_be_fetched(true);
+ drive_metadata_.set_type(type);
+ metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
+}
+
+void ApplyLocalChangeDelegate::SetConflict(
+ const std::string& resource_id,
+ const std::string& md5,
+ DriveMetadata::ResourceType type,
+ const SyncStatusCallback& callback) {
+ if (!sync_service_)
+ return;
+
+ drive_metadata_.set_resource_id(resource_id);
+ drive_metadata_.set_md5_checksum(md5);
+ drive_metadata_.set_conflicted(true);
+ drive_metadata_.set_to_be_fetched(false);
+ drive_metadata_.set_type(type);
+ metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
+}
+
+void ApplyLocalChangeDelegate::DeleteMetadata(
+ const SyncStatusCallback& callback) {
+ metadata_store()->DeleteEntry(url_, callback);
+}
+
+void ApplyLocalChangeDelegate::HandleCreationConflict(
+ const std::string& resource_id,
+ DriveMetadata::ResourceType type,
+ const SyncStatusCallback& callback) {
+ if (!sync_service_)
+ return;
+
+ // File-file conflict is found.
+ // Populates a fake drive_metadata and set has_drive_metadata = true.
+ // In HandleConflictLocalSync:
+ // - If conflict_resolution is manual, we'll change conflicted to true
+ // and save the metadata.
+ // - Otherwise we'll save the metadata with empty md5 and will start
+ // over local sync as UploadExistingFile.
+ drive_metadata_.set_resource_id(resource_id);
+ drive_metadata_.set_md5_checksum(std::string());
+ drive_metadata_.set_conflicted(false);
+ drive_metadata_.set_to_be_fetched(false);
+ drive_metadata_.set_type(type);
+ has_drive_metadata_ = true;
+ HandleConflict(callback);
+}
+
+void ApplyLocalChangeDelegate::HandleConflict(
+ const SyncStatusCallback& callback) {
+ if (!sync_service_)
+ return;
+
+ DCHECK(!drive_metadata_.resource_id().empty());
+
+ api_util()->GetResourceEntry(
+ drive_metadata_.resource_id(),
+ base::Bind(
+ &ApplyLocalChangeDelegate::DidGetEntryForConflictResolution,
+ weak_factory_.GetWeakPtr(), callback));
+}
+
+void ApplyLocalChangeDelegate::DidGetEntryForConflictResolution(
+ const SyncStatusCallback& callback,
+ google_apis::GDataErrorCode error,
+ scoped_ptr<google_apis::ResourceEntry> entry) {
+ if (!sync_service_)
+ return;
+
+ SyncFileType local_file_type = local_metadata_.file_type;
+ base::Time local_modification_time = local_metadata_.last_modified;
+
+ SyncFileType remote_file_type;
+ base::Time remote_modification_time = entry->updated_time();
+ if (entry->is_file())
+ remote_file_type = SYNC_FILE_TYPE_FILE;
+ else if (entry->is_folder())
+ remote_file_type = SYNC_FILE_TYPE_DIRECTORY;
+ else
+ remote_file_type = SYNC_FILE_TYPE_UNKNOWN;
+
+ switch (sync_service_->ResolveConflictForLocalSync(
+ local_file_type, local_modification_time,
+ remote_file_type, remote_modification_time)) {
+ case DriveFileSyncService::CONFLICT_RESOLUTION_MARK_CONFLICT:
+ if (drive_metadata_.conflicted()) {
+ callback.Run(SYNC_STATUS_HAS_CONFLICT);
+ return;
+ }
+
+ SetConflict(drive_metadata_.resource_id(),
+ drive_metadata_.md5_checksum(),
+ DriveFileSyncService::SyncFileTypeToDriveMetadataResourceType(
+ local_file_type),
+ base::Bind(&ApplyLocalChangeDelegate::DidApplyLocalChange,
+ weak_factory_.GetWeakPtr(), callback,
+ google_apis::HTTP_SUCCESS));
+ return;
+ case DriveFileSyncService::CONFLICT_RESOLUTION_LOCAL_WIN:
+ DVLOG(1) << "Resolving conflict for local sync:"
+ << url_.DebugString() << ": LOCAL WIN";
+ ResolveToLocal(callback);
+ return;
+ case DriveFileSyncService::CONFLICT_RESOLUTION_REMOTE_WIN:
+ DVLOG(1) << "Resolving conflict for local sync:"
+ << url_.DebugString() << ": REMOTE WIN";
+ ResolveToRemote(callback);
+ return;
+ }
+ NOTREACHED();
+ callback.Run(SYNC_STATUS_FAILED);
+}
+
+SyncStatusCode ApplyLocalChangeDelegate::GDataErrorCodeToSyncStatusCodeWrapper(
+ google_apis::GDataErrorCode error) {
+ return sync_service_->GDataErrorCodeToSyncStatusCodeWrapper(error);
+}
+
+DriveMetadataStore* ApplyLocalChangeDelegate::metadata_store() {
+ return sync_service_->metadata_store_.get();
+}
+
+APIUtilInterface* ApplyLocalChangeDelegate::api_util() {
+ return sync_service_->api_util_.get();
+}
+
+RemoteChangeHandler* ApplyLocalChangeDelegate::remote_change_handler() {
+ return &sync_service_->remote_change_handler_;
+}
+
+} // drive
+} // namespace sync_file_system

Powered by Google App Engine
This is Rietveld 408576698