Home | History | Annotate | Download | only in drive_backend
      1 // Copyright 2013 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/sync_file_system/drive_backend/local_sync_delegate.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/callback.h"
      9 #include "chrome/browser/sync_file_system/conflict_resolution_resolver.h"
     10 #include "chrome/browser/sync_file_system/drive_backend/api_util.h"
     11 #include "chrome/browser/sync_file_system/drive_backend/drive_metadata_store.h"
     12 #include "chrome/browser/sync_file_system/logger.h"
     13 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
     14 
     15 namespace sync_file_system {
     16 namespace drive_backend {
     17 
     18 LocalSyncDelegate::LocalSyncDelegate(
     19     DriveFileSyncService* sync_service,
     20     const FileChange& local_change,
     21     const base::FilePath& local_path,
     22     const SyncFileMetadata& local_metadata,
     23     const fileapi::FileSystemURL& url)
     24     : sync_service_(sync_service),
     25       operation_(SYNC_OPERATION_NONE),
     26       url_(url),
     27       local_change_(local_change),
     28       local_path_(local_path),
     29       local_metadata_(local_metadata),
     30       has_drive_metadata_(false),
     31       has_remote_change_(false),
     32       weak_factory_(this) {}
     33 
     34 LocalSyncDelegate::~LocalSyncDelegate() {}
     35 
     36 void LocalSyncDelegate::Run(const SyncStatusCallback& callback) {
     37   // TODO(nhiroki): support directory operations (http://crbug.com/161442).
     38   DCHECK(IsSyncFSDirectoryOperationEnabled() || !local_change_.IsDirectory());
     39   operation_ = SYNC_OPERATION_NONE;
     40 
     41   has_drive_metadata_ =
     42       metadata_store()->ReadEntry(url_, &drive_metadata_) == SYNC_STATUS_OK;
     43 
     44   if (!has_drive_metadata_)
     45     drive_metadata_.set_md5_checksum(std::string());
     46 
     47   sync_service_->EnsureOriginRootDirectory(
     48       url_.origin(),
     49       base::Bind(&LocalSyncDelegate::DidGetOriginRoot,
     50                  weak_factory_.GetWeakPtr(),
     51                  callback));
     52 }
     53 
     54 void LocalSyncDelegate::DidGetOriginRoot(
     55     const SyncStatusCallback& callback,
     56     SyncStatusCode status,
     57     const std::string& origin_resource_id) {
     58   if (status != SYNC_STATUS_OK) {
     59     callback.Run(status);
     60     return;
     61   }
     62 
     63   origin_resource_id_ = origin_resource_id;
     64 
     65   has_remote_change_ =
     66       remote_change_handler()->GetChangeForURL(url_, &remote_change_);
     67   if (has_remote_change_ && drive_metadata_.resource_id().empty())
     68     drive_metadata_.set_resource_id(remote_change_.resource_id);
     69 
     70   SyncFileType remote_file_type =
     71       has_remote_change_ ? remote_change_.change.file_type() :
     72       has_drive_metadata_ ?
     73           DriveFileSyncService::DriveMetadataResourceTypeToSyncFileType(
     74               drive_metadata_.type())
     75       : SYNC_FILE_TYPE_UNKNOWN;
     76 
     77   DCHECK_EQ(SYNC_OPERATION_NONE, operation_);
     78   operation_ = LocalSyncOperationResolver::Resolve(
     79       local_change_,
     80       has_remote_change_ ? &remote_change_.change : NULL,
     81       has_drive_metadata_ ? &drive_metadata_ : NULL);
     82 
     83   util::Log(logging::LOG_VERBOSE, FROM_HERE,
     84             "ApplyLocalChange for %s local_change:%s ===> %s",
     85             url_.DebugString().c_str(),
     86             local_change_.DebugString().c_str(),
     87             SyncOperationTypeToString(operation_));
     88 
     89   switch (operation_) {
     90     case SYNC_OPERATION_ADD_FILE:
     91       UploadNewFile(callback);
     92       return;
     93     case SYNC_OPERATION_ADD_DIRECTORY:
     94       CreateDirectory(callback);
     95       return;
     96     case SYNC_OPERATION_UPDATE_FILE:
     97       UploadExistingFile(callback);
     98       return;
     99     case SYNC_OPERATION_DELETE:
    100       Delete(callback);
    101       return;
    102     case SYNC_OPERATION_NONE:
    103       callback.Run(SYNC_STATUS_OK);
    104       return;
    105     case SYNC_OPERATION_CONFLICT:
    106       HandleConflict(callback);
    107       return;
    108     case SYNC_OPERATION_RESOLVE_TO_LOCAL:
    109       ResolveToLocal(callback);
    110       return;
    111     case SYNC_OPERATION_RESOLVE_TO_REMOTE:
    112       ResolveToRemote(callback, remote_file_type);
    113       return;
    114     case SYNC_OPERATION_DELETE_METADATA:
    115       DeleteMetadata(base::Bind(
    116           &LocalSyncDelegate::DidApplyLocalChange,
    117           weak_factory_.GetWeakPtr(), callback, google_apis::HTTP_SUCCESS));
    118       return;
    119     case SYNC_OPERATION_FAIL: {
    120       callback.Run(SYNC_STATUS_FAILED);
    121       return;
    122     }
    123   }
    124   NOTREACHED();
    125   callback.Run(SYNC_STATUS_FAILED);
    126 }
    127 
    128 void LocalSyncDelegate::UploadNewFile(const SyncStatusCallback& callback) {
    129   api_util()->UploadNewFile(
    130       origin_resource_id_,
    131       local_path_,
    132       DriveFileSyncService::PathToTitle(url_.path()),
    133       base::Bind(&LocalSyncDelegate::DidUploadNewFile,
    134                  weak_factory_.GetWeakPtr(), callback));
    135 }
    136 
    137 void LocalSyncDelegate::DidUploadNewFile(
    138     const SyncStatusCallback& callback,
    139     google_apis::GDataErrorCode error,
    140     const std::string& resource_id,
    141     const std::string& md5) {
    142   switch (error) {
    143     case google_apis::HTTP_CREATED:
    144       UpdateMetadata(
    145           resource_id, md5, DriveMetadata::RESOURCE_TYPE_FILE,
    146           base::Bind(&LocalSyncDelegate::DidApplyLocalChange,
    147                      weak_factory_.GetWeakPtr(), callback, error));
    148       sync_service_->NotifyObserversFileStatusChanged(
    149           url_,
    150           SYNC_FILE_STATUS_SYNCED,
    151           SYNC_ACTION_ADDED,
    152           SYNC_DIRECTION_LOCAL_TO_REMOTE);
    153       return;
    154     case google_apis::HTTP_CONFLICT:
    155       HandleCreationConflict(resource_id, DriveMetadata::RESOURCE_TYPE_FILE,
    156                              callback);
    157       return;
    158     default:
    159       callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
    160   }
    161 }
    162 
    163 void LocalSyncDelegate::CreateDirectory(const SyncStatusCallback& callback) {
    164   DCHECK(IsSyncFSDirectoryOperationEnabled());
    165   api_util()->CreateDirectory(
    166       origin_resource_id_,
    167       DriveFileSyncService::PathToTitle(url_.path()),
    168       base::Bind(&LocalSyncDelegate::DidCreateDirectory,
    169                  weak_factory_.GetWeakPtr(), callback));
    170 }
    171 
    172 void LocalSyncDelegate::DidCreateDirectory(
    173     const SyncStatusCallback& callback,
    174     google_apis::GDataErrorCode error,
    175     const std::string& resource_id) {
    176   switch (error) {
    177     case google_apis::HTTP_SUCCESS:
    178     case google_apis::HTTP_CREATED: {
    179       UpdateMetadata(
    180           resource_id, std::string(), DriveMetadata::RESOURCE_TYPE_FOLDER,
    181           base::Bind(&LocalSyncDelegate::DidApplyLocalChange,
    182                      weak_factory_.GetWeakPtr(), callback, error));
    183       sync_service_->NotifyObserversFileStatusChanged(
    184           url_,
    185           SYNC_FILE_STATUS_SYNCED,
    186           SYNC_ACTION_ADDED,
    187           SYNC_DIRECTION_LOCAL_TO_REMOTE);
    188       return;
    189     }
    190 
    191     case google_apis::HTTP_CONFLICT:
    192       // There were conflicts and a file was left.
    193       // TODO(kinuko): Handle the latter case (http://crbug.com/237090).
    194       // Fall-through
    195 
    196     default:
    197       callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
    198   }
    199 }
    200 
    201 void LocalSyncDelegate::UploadExistingFile(const SyncStatusCallback& callback) {
    202   DCHECK(has_drive_metadata_);
    203   if (drive_metadata_.resource_id().empty()) {
    204     UploadNewFile(callback);
    205     return;
    206   }
    207 
    208   api_util()->UploadExistingFile(
    209       drive_metadata_.resource_id(),
    210       drive_metadata_.md5_checksum(),
    211       local_path_,
    212       base::Bind(&LocalSyncDelegate::DidUploadExistingFile,
    213                  weak_factory_.GetWeakPtr(), callback));
    214 }
    215 
    216 void LocalSyncDelegate::DidUploadExistingFile(
    217     const SyncStatusCallback& callback,
    218     google_apis::GDataErrorCode error,
    219     const std::string& resource_id,
    220     const std::string& md5) {
    221   DCHECK(has_drive_metadata_);
    222   switch (error) {
    223     case google_apis::HTTP_SUCCESS:
    224       UpdateMetadata(
    225           resource_id, md5, DriveMetadata::RESOURCE_TYPE_FILE,
    226           base::Bind(&LocalSyncDelegate::DidApplyLocalChange,
    227                      weak_factory_.GetWeakPtr(), callback, error));
    228       sync_service_->NotifyObserversFileStatusChanged(
    229           url_,
    230           SYNC_FILE_STATUS_SYNCED,
    231           SYNC_ACTION_UPDATED,
    232           SYNC_DIRECTION_LOCAL_TO_REMOTE);
    233       return;
    234     case google_apis::HTTP_CONFLICT:
    235       HandleConflict(callback);
    236       return;
    237     case google_apis::HTTP_NOT_MODIFIED:
    238       DidApplyLocalChange(callback,
    239                           google_apis::HTTP_SUCCESS, SYNC_STATUS_OK);
    240       return;
    241     case google_apis::HTTP_NOT_FOUND:
    242       UploadNewFile(callback);
    243       return;
    244     default: {
    245       const SyncStatusCode status =
    246           GDataErrorCodeToSyncStatusCodeWrapper(error);
    247       DCHECK_NE(SYNC_STATUS_OK, status);
    248       callback.Run(status);
    249       return;
    250     }
    251   }
    252 }
    253 
    254 void LocalSyncDelegate::Delete(const SyncStatusCallback& callback) {
    255   if (!has_drive_metadata_) {
    256     callback.Run(SYNC_STATUS_OK);
    257     return;
    258   }
    259 
    260   if (drive_metadata_.resource_id().empty()) {
    261     DidDelete(callback, google_apis::HTTP_NOT_FOUND);
    262     return;
    263   }
    264 
    265   api_util()->DeleteFile(
    266       drive_metadata_.resource_id(),
    267       drive_metadata_.md5_checksum(),
    268       base::Bind(&LocalSyncDelegate::DidDelete,
    269                  weak_factory_.GetWeakPtr(), callback));
    270 }
    271 
    272 void LocalSyncDelegate::DidDelete(
    273     const SyncStatusCallback& callback,
    274     google_apis::GDataErrorCode error) {
    275   DCHECK(has_drive_metadata_);
    276 
    277   switch (error) {
    278     case google_apis::HTTP_SUCCESS:
    279     case google_apis::HTTP_NOT_FOUND:
    280       DeleteMetadata(base::Bind(
    281           &LocalSyncDelegate::DidApplyLocalChange,
    282           weak_factory_.GetWeakPtr(), callback, google_apis::HTTP_SUCCESS));
    283       sync_service_->NotifyObserversFileStatusChanged(
    284           url_,
    285           SYNC_FILE_STATUS_SYNCED,
    286           SYNC_ACTION_DELETED,
    287           SYNC_DIRECTION_LOCAL_TO_REMOTE);
    288       return;
    289     case google_apis::HTTP_PRECONDITION:
    290     case google_apis::HTTP_CONFLICT:
    291       // Delete |drive_metadata| on the conflict case.
    292       // Conflicted remote change should be applied as a future remote change.
    293       DeleteMetadata(base::Bind(
    294           &LocalSyncDelegate::DidDeleteMetadataForDeletionConflict,
    295           weak_factory_.GetWeakPtr(), callback));
    296       sync_service_->NotifyObserversFileStatusChanged(
    297           url_,
    298           SYNC_FILE_STATUS_SYNCED,
    299           SYNC_ACTION_DELETED,
    300           SYNC_DIRECTION_LOCAL_TO_REMOTE);
    301       return;
    302     default: {
    303       const SyncStatusCode status =
    304           GDataErrorCodeToSyncStatusCodeWrapper(error);
    305       DCHECK_NE(SYNC_STATUS_OK, status);
    306       callback.Run(status);
    307       return;
    308     }
    309   }
    310 }
    311 
    312 void LocalSyncDelegate::DidDeleteMetadataForDeletionConflict(
    313     const SyncStatusCallback& callback,
    314     SyncStatusCode status) {
    315   callback.Run(SYNC_STATUS_OK);
    316 }
    317 
    318 void LocalSyncDelegate::ResolveToLocal(const SyncStatusCallback& callback) {
    319   if (drive_metadata_.resource_id().empty()) {
    320     DidDeleteFileToResolveToLocal(callback, google_apis::HTTP_NOT_FOUND);
    321     return;
    322   }
    323 
    324   api_util()->DeleteFile(
    325       drive_metadata_.resource_id(),
    326       drive_metadata_.md5_checksum(),
    327       base::Bind(
    328           &LocalSyncDelegate::DidDeleteFileToResolveToLocal,
    329           weak_factory_.GetWeakPtr(), callback));
    330 }
    331 
    332 void LocalSyncDelegate::DidDeleteFileToResolveToLocal(
    333     const SyncStatusCallback& callback,
    334     google_apis::GDataErrorCode error) {
    335   if (error != google_apis::HTTP_SUCCESS &&
    336       error != google_apis::HTTP_NOT_FOUND) {
    337     callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error));
    338     return;
    339   }
    340 
    341   DCHECK_NE(SYNC_FILE_TYPE_UNKNOWN, local_metadata_.file_type);
    342   if (local_metadata_.file_type == SYNC_FILE_TYPE_FILE) {
    343     UploadNewFile(callback);
    344     return;
    345   }
    346 
    347   DCHECK(IsSyncFSDirectoryOperationEnabled());
    348   DCHECK_EQ(SYNC_FILE_TYPE_DIRECTORY, local_metadata_.file_type);
    349   CreateDirectory(callback);
    350 }
    351 
    352 void LocalSyncDelegate::ResolveToRemote(
    353     const SyncStatusCallback& callback,
    354     SyncFileType remote_file_type) {
    355   // Mark the file as to-be-fetched.
    356   DCHECK(!drive_metadata_.resource_id().empty());
    357 
    358   SetMetadataToBeFetched(
    359       DriveFileSyncService::SyncFileTypeToDriveMetadataResourceType(
    360           remote_file_type),
    361       base::Bind(&LocalSyncDelegate::DidResolveToRemote,
    362                  weak_factory_.GetWeakPtr(), callback));
    363   // The synced notification will be dispatched when the remote file is
    364   // downloaded.
    365 }
    366 
    367 void LocalSyncDelegate::DidResolveToRemote(
    368     const SyncStatusCallback& callback,
    369     SyncStatusCode status) {
    370   DCHECK(has_drive_metadata_);
    371   if (status != SYNC_STATUS_OK) {
    372     callback.Run(status);
    373     return;
    374   }
    375 
    376   SyncFileType file_type = SYNC_FILE_TYPE_FILE;
    377   if (drive_metadata_.type() == DriveMetadata::RESOURCE_TYPE_FOLDER)
    378     file_type = SYNC_FILE_TYPE_DIRECTORY;
    379   sync_service_->AppendFetchChange(
    380       url_.origin(), url_.path(), drive_metadata_.resource_id(), file_type);
    381   callback.Run(status);
    382 }
    383 
    384 void LocalSyncDelegate::DidApplyLocalChange(
    385     const SyncStatusCallback& callback,
    386     const google_apis::GDataErrorCode error,
    387     SyncStatusCode status) {
    388   if ((operation_ == SYNC_OPERATION_DELETE ||
    389        operation_ == SYNC_OPERATION_DELETE_METADATA) &&
    390       (status == SYNC_FILE_ERROR_NOT_FOUND ||
    391        status == SYNC_DATABASE_ERROR_NOT_FOUND)) {
    392     status = SYNC_STATUS_OK;
    393   }
    394 
    395   if (status == SYNC_STATUS_OK) {
    396     remote_change_handler()->RemoveChangeForURL(url_);
    397     status = GDataErrorCodeToSyncStatusCodeWrapper(error);
    398   }
    399   callback.Run(status);
    400 }
    401 
    402 void LocalSyncDelegate::UpdateMetadata(
    403     const std::string& resource_id,
    404     const std::string& md5,
    405     DriveMetadata::ResourceType type,
    406     const SyncStatusCallback& callback) {
    407   has_drive_metadata_ = true;
    408   drive_metadata_.set_resource_id(resource_id);
    409   drive_metadata_.set_md5_checksum(md5);
    410   drive_metadata_.set_conflicted(false);
    411   drive_metadata_.set_to_be_fetched(false);
    412   drive_metadata_.set_type(type);
    413   metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
    414 }
    415 
    416 void LocalSyncDelegate::ResetMetadataMD5(const SyncStatusCallback& callback) {
    417   has_drive_metadata_ = true;
    418   drive_metadata_.set_md5_checksum(std::string());
    419   metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
    420 }
    421 
    422 void LocalSyncDelegate::SetMetadataToBeFetched(
    423     DriveMetadata::ResourceType type,
    424     const SyncStatusCallback& callback) {
    425   has_drive_metadata_ = true;
    426   drive_metadata_.set_md5_checksum(std::string());
    427   drive_metadata_.set_conflicted(false);
    428   drive_metadata_.set_to_be_fetched(true);
    429   drive_metadata_.set_type(type);
    430   metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
    431 }
    432 
    433 void LocalSyncDelegate::DeleteMetadata(const SyncStatusCallback& callback) {
    434   metadata_store()->DeleteEntry(url_, callback);
    435 }
    436 
    437 void LocalSyncDelegate::HandleCreationConflict(
    438     const std::string& resource_id,
    439     DriveMetadata::ResourceType type,
    440     const SyncStatusCallback& callback) {
    441   // File-file conflict is found.
    442   // Populates a fake drive_metadata and set has_drive_metadata = true.
    443   // In HandleConflictLocalSync:
    444   // - If conflict_resolution is manual, we'll change conflicted to true
    445   //   and save the metadata.
    446   // - Otherwise we'll save the metadata with empty md5 and will start
    447   //   over local sync as UploadExistingFile.
    448   drive_metadata_.set_resource_id(resource_id);
    449   drive_metadata_.set_md5_checksum(std::string());
    450   drive_metadata_.set_conflicted(false);
    451   drive_metadata_.set_to_be_fetched(false);
    452   drive_metadata_.set_type(type);
    453   has_drive_metadata_ = true;
    454   HandleConflict(callback);
    455 }
    456 
    457 void LocalSyncDelegate::HandleConflict(const SyncStatusCallback& callback) {
    458   DCHECK(!drive_metadata_.resource_id().empty());
    459   api_util()->GetResourceEntry(
    460       drive_metadata_.resource_id(),
    461       base::Bind(
    462           &LocalSyncDelegate::DidGetEntryForConflictResolution,
    463           weak_factory_.GetWeakPtr(), callback));
    464 }
    465 
    466 void LocalSyncDelegate::DidGetEntryForConflictResolution(
    467     const SyncStatusCallback& callback,
    468     google_apis::GDataErrorCode error,
    469     scoped_ptr<google_apis::ResourceEntry> entry) {
    470   SyncFileType remote_file_type = SYNC_FILE_TYPE_UNKNOWN;
    471   ConflictResolution resolution = CONFLICT_RESOLUTION_UNKNOWN;
    472 
    473   if (error != google_apis::HTTP_SUCCESS ||
    474       entry->updated_time().is_null()) {
    475     resolution = CONFLICT_RESOLUTION_LOCAL_WIN;
    476   } else {
    477     SyncFileType local_file_type = local_metadata_.file_type;
    478     base::Time local_modification_time = local_metadata_.last_modified;
    479     base::Time remote_modification_time = entry->updated_time();
    480     if (entry->is_file())
    481       remote_file_type = SYNC_FILE_TYPE_FILE;
    482     else if (entry->is_folder())
    483       remote_file_type = SYNC_FILE_TYPE_DIRECTORY;
    484     else
    485       remote_file_type = SYNC_FILE_TYPE_UNKNOWN;
    486 
    487     resolution = conflict_resolution_resolver()->Resolve(
    488         local_file_type, local_modification_time,
    489         remote_file_type, remote_modification_time);
    490   }
    491 
    492   switch (resolution) {
    493     case CONFLICT_RESOLUTION_MARK_CONFLICT:
    494       HandleManualResolutionCase(callback);
    495       return;
    496     case CONFLICT_RESOLUTION_LOCAL_WIN:
    497       HandleLocalWinCase(callback);
    498       return;
    499     case CONFLICT_RESOLUTION_REMOTE_WIN:
    500       HandleRemoteWinCase(callback, remote_file_type);
    501       return;
    502     case CONFLICT_RESOLUTION_UNKNOWN:
    503       NOTREACHED();
    504   }
    505   NOTREACHED();
    506   callback.Run(SYNC_STATUS_FAILED);
    507 }
    508 
    509 void LocalSyncDelegate::HandleManualResolutionCase(
    510     const SyncStatusCallback& callback) {
    511   if (drive_metadata_.conflicted()) {
    512     callback.Run(SYNC_STATUS_HAS_CONFLICT);
    513     return;
    514   }
    515 
    516   has_drive_metadata_ = true;
    517   sync_service_->MarkConflict(
    518       url_, &drive_metadata_,
    519       base::Bind(&LocalSyncDelegate::DidMarkConflict,
    520                  weak_factory_.GetWeakPtr(), callback));
    521 }
    522 
    523 void LocalSyncDelegate::DidMarkConflict(
    524     const SyncStatusCallback& callback,
    525     SyncStatusCode status) {
    526   DidApplyLocalChange(callback, google_apis::HTTP_CONFLICT, status);
    527 }
    528 
    529 void LocalSyncDelegate::HandleLocalWinCase(
    530     const SyncStatusCallback& callback) {
    531   util::Log(logging::LOG_VERBOSE, FROM_HERE,
    532             "Resolving conflict for local sync: %s: LOCAL WIN",
    533             url_.DebugString().c_str());
    534 
    535   DCHECK(!drive_metadata_.resource_id().empty());
    536   if (!has_drive_metadata_) {
    537     StartOver(callback, SYNC_STATUS_OK);
    538     return;
    539   }
    540 
    541   ResetMetadataMD5(base::Bind(&LocalSyncDelegate::StartOver,
    542                               weak_factory_.GetWeakPtr(), callback));
    543 }
    544 
    545 void LocalSyncDelegate::HandleRemoteWinCase(
    546     const SyncStatusCallback& callback,
    547     SyncFileType remote_file_type) {
    548   util::Log(logging::LOG_VERBOSE, FROM_HERE,
    549             "Resolving conflict for local sync: %s: REMOTE WIN",
    550             url_.DebugString().c_str());
    551   ResolveToRemote(callback, remote_file_type);
    552 }
    553 
    554 void LocalSyncDelegate::StartOver(const SyncStatusCallback& callback,
    555                                              SyncStatusCode status) {
    556   if (status != SYNC_STATUS_OK) {
    557     callback.Run(status);
    558     return;
    559   }
    560 
    561   remote_change_handler()->RemoveChangeForURL(url_);
    562   Run(callback);
    563 }
    564 
    565 SyncStatusCode
    566 LocalSyncDelegate::GDataErrorCodeToSyncStatusCodeWrapper(
    567     google_apis::GDataErrorCode error) {
    568   return sync_service_->GDataErrorCodeToSyncStatusCodeWrapper(error);
    569 }
    570 
    571 DriveMetadataStore* LocalSyncDelegate::metadata_store() {
    572   return sync_service_->metadata_store_.get();
    573 }
    574 
    575 APIUtilInterface* LocalSyncDelegate::api_util() {
    576   return sync_service_->api_util_.get();
    577 }
    578 
    579 RemoteChangeHandler* LocalSyncDelegate::remote_change_handler() {
    580   return &sync_service_->remote_change_handler_;
    581 }
    582 
    583 ConflictResolutionResolver* LocalSyncDelegate::conflict_resolution_resolver() {
    584   return &sync_service_->conflict_resolution_resolver_;
    585 }
    586 
    587 }  // namespace drive_backend
    588 }  // namespace sync_file_system
    589