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

Side by Side Diff: chrome/browser/sync_file_system/drive_backend/local_sync_delegate.cc

Issue 23787003: [SyncFS] Move SyncFS V1 files from drive_backend to drive_backend_v1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: move back metadata_db_migration_util* Created 7 years, 3 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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::ResetMetadataForStartOver(
417 const SyncStatusCallback& callback) {
418 has_drive_metadata_ = true;
419 DCHECK(!drive_metadata_.resource_id().empty());
420 drive_metadata_.set_md5_checksum(std::string());
421 drive_metadata_.set_conflicted(false);
422 drive_metadata_.set_to_be_fetched(false);
423 metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
424 }
425
426 void LocalSyncDelegate::SetMetadataToBeFetched(
427 DriveMetadata::ResourceType type,
428 const SyncStatusCallback& callback) {
429 has_drive_metadata_ = true;
430 drive_metadata_.set_md5_checksum(std::string());
431 drive_metadata_.set_conflicted(false);
432 drive_metadata_.set_to_be_fetched(true);
433 drive_metadata_.set_type(type);
434 metadata_store()->UpdateEntry(url_, drive_metadata_, callback);
435 }
436
437 void LocalSyncDelegate::DeleteMetadata(const SyncStatusCallback& callback) {
438 metadata_store()->DeleteEntry(url_, callback);
439 }
440
441 void LocalSyncDelegate::HandleCreationConflict(
442 const std::string& resource_id,
443 DriveMetadata::ResourceType type,
444 const SyncStatusCallback& callback) {
445 // File-file conflict is found.
446 // Populates a fake drive_metadata and set has_drive_metadata = true.
447 // In HandleConflictLocalSync:
448 // - If conflict_resolution is manual, we'll change conflicted to true
449 // and save the metadata.
450 // - Otherwise we'll save the metadata with empty md5 and will start
451 // over local sync as UploadExistingFile.
452 drive_metadata_.set_resource_id(resource_id);
453 drive_metadata_.set_md5_checksum(std::string());
454 drive_metadata_.set_conflicted(false);
455 drive_metadata_.set_to_be_fetched(false);
456 drive_metadata_.set_type(type);
457 has_drive_metadata_ = true;
458 HandleConflict(callback);
459 }
460
461 void LocalSyncDelegate::HandleConflict(const SyncStatusCallback& callback) {
462 DCHECK(!drive_metadata_.resource_id().empty());
463 api_util()->GetResourceEntry(
464 drive_metadata_.resource_id(),
465 base::Bind(
466 &LocalSyncDelegate::DidGetEntryForConflictResolution,
467 weak_factory_.GetWeakPtr(), callback));
468 }
469
470 void LocalSyncDelegate::DidGetEntryForConflictResolution(
471 const SyncStatusCallback& callback,
472 google_apis::GDataErrorCode error,
473 scoped_ptr<google_apis::ResourceEntry> entry) {
474 SyncFileType remote_file_type = SYNC_FILE_TYPE_UNKNOWN;
475 ConflictResolution resolution = CONFLICT_RESOLUTION_UNKNOWN;
476
477 if (error != google_apis::HTTP_SUCCESS ||
478 entry->updated_time().is_null()) {
479 resolution = CONFLICT_RESOLUTION_LOCAL_WIN;
480 } else {
481 SyncFileType local_file_type = local_metadata_.file_type;
482 base::Time local_modification_time = local_metadata_.last_modified;
483 base::Time remote_modification_time = entry->updated_time();
484 if (entry->is_file())
485 remote_file_type = SYNC_FILE_TYPE_FILE;
486 else if (entry->is_folder())
487 remote_file_type = SYNC_FILE_TYPE_DIRECTORY;
488 else
489 remote_file_type = SYNC_FILE_TYPE_UNKNOWN;
490
491 resolution = conflict_resolution_resolver()->Resolve(
492 local_file_type, local_modification_time,
493 remote_file_type, remote_modification_time);
494 }
495
496 switch (resolution) {
497 case CONFLICT_RESOLUTION_MARK_CONFLICT:
498 HandleManualResolutionCase(callback);
499 return;
500 case CONFLICT_RESOLUTION_LOCAL_WIN:
501 HandleLocalWinCase(callback);
502 return;
503 case CONFLICT_RESOLUTION_REMOTE_WIN:
504 HandleRemoteWinCase(callback, remote_file_type);
505 return;
506 case CONFLICT_RESOLUTION_UNKNOWN:
507 NOTREACHED();
508 }
509 NOTREACHED();
510 callback.Run(SYNC_STATUS_FAILED);
511 }
512
513 void LocalSyncDelegate::HandleManualResolutionCase(
514 const SyncStatusCallback& callback) {
515 if (drive_metadata_.conflicted()) {
516 callback.Run(SYNC_STATUS_HAS_CONFLICT);
517 return;
518 }
519
520 has_drive_metadata_ = true;
521 sync_service_->MarkConflict(
522 url_, &drive_metadata_,
523 base::Bind(&LocalSyncDelegate::DidMarkConflict,
524 weak_factory_.GetWeakPtr(), callback));
525 }
526
527 void LocalSyncDelegate::DidMarkConflict(
528 const SyncStatusCallback& callback,
529 SyncStatusCode status) {
530 DidApplyLocalChange(callback, google_apis::HTTP_CONFLICT, status);
531 }
532
533 void LocalSyncDelegate::HandleLocalWinCase(
534 const SyncStatusCallback& callback) {
535 util::Log(logging::LOG_VERBOSE, FROM_HERE,
536 "Resolving conflict for local sync: %s: LOCAL WIN",
537 url_.DebugString().c_str());
538
539 DCHECK(!drive_metadata_.resource_id().empty());
540 if (!has_drive_metadata_) {
541 StartOver(callback, SYNC_STATUS_OK);
542 return;
543 }
544
545 ResetMetadataForStartOver(base::Bind(&LocalSyncDelegate::StartOver,
546 weak_factory_.GetWeakPtr(), callback));
547 }
548
549 void LocalSyncDelegate::HandleRemoteWinCase(
550 const SyncStatusCallback& callback,
551 SyncFileType remote_file_type) {
552 util::Log(logging::LOG_VERBOSE, FROM_HERE,
553 "Resolving conflict for local sync: %s: REMOTE WIN",
554 url_.DebugString().c_str());
555 ResolveToRemote(callback, remote_file_type);
556 }
557
558 void LocalSyncDelegate::StartOver(const SyncStatusCallback& callback,
559 SyncStatusCode status) {
560 if (status != SYNC_STATUS_OK) {
561 callback.Run(status);
562 return;
563 }
564
565 remote_change_handler()->RemoveChangeForURL(url_);
566 Run(callback);
567 }
568
569 SyncStatusCode
570 LocalSyncDelegate::GDataErrorCodeToSyncStatusCodeWrapper(
571 google_apis::GDataErrorCode error) {
572 return sync_service_->GDataErrorCodeToSyncStatusCodeWrapper(error);
573 }
574
575 DriveMetadataStore* LocalSyncDelegate::metadata_store() {
576 return sync_service_->metadata_store_.get();
577 }
578
579 APIUtilInterface* LocalSyncDelegate::api_util() {
580 return sync_service_->api_util_.get();
581 }
582
583 RemoteChangeHandler* LocalSyncDelegate::remote_change_handler() {
584 return &sync_service_->remote_change_handler_;
585 }
586
587 ConflictResolutionResolver* LocalSyncDelegate::conflict_resolution_resolver() {
588 return &sync_service_->conflict_resolution_resolver_;
589 }
590
591 } // namespace drive_backend
592 } // namespace sync_file_system
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698