190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/sync_file_system/local/local_file_sync_context.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/platform_file.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/single_thread_task_runner.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/task_runner_util.h"
132385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/sync_file_system/file_change.h"
142385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/sync_file_system/local/local_file_change_tracker.h"
152385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/sync_file_system/local/local_origin_change_observer.h"
162385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
172385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/sync_file_system/local/syncable_file_operation_runner.h"
182385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/sync_file_system/sync_file_metadata.h"
192385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "webkit/browser/fileapi/file_system_context.h"
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "webkit/browser/fileapi/file_system_file_util.h"
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "webkit/browser/fileapi/file_system_operation_context.h"
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "webkit/browser/fileapi/file_system_operation_runner.h"
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "webkit/common/fileapi/file_system_util.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using fileapi::FileSystemContext;
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using fileapi::FileSystemFileUtil;
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using fileapi::FileSystemOperation;
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using fileapi::FileSystemOperationContext;
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using fileapi::FileSystemURL;
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace sync_file_system {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMaxConcurrentSyncableOperation = 3;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kNotifyChangesDurationInSec = 1;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMaxURLsToFetchForLocalSync = 5;
39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LocalFileSyncContext::LocalFileSyncContext(
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::SingleThreadTaskRunner* ui_task_runner,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::SingleThreadTaskRunner* io_task_runner)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : ui_task_runner_(ui_task_runner),
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      io_task_runner_(io_task_runner),
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shutdown_on_ui_(false),
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mock_notify_changes_duration_in_sec_(-1) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::MaybeInitializeFileSystemContext(
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& source_url,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileSystemContext* file_system_context,
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SyncStatusCallback& callback) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ContainsKey(file_system_contexts_, file_system_context)) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The context has been already initialized. Just dispatch the callback
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // with SYNC_STATUS_OK.
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui_task_runner_->PostTask(FROM_HERE,
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              base::Bind(callback,
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         SYNC_STATUS_OK));
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StatusCallbackQueue& callback_queue =
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pending_initialize_callbacks_[file_system_context];
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback_queue.push_back(callback);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (callback_queue.size() > 1)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io_task_runner_->PostTask(
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&LocalFileSyncContext::InitializeFileSystemContextOnIOThread,
75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 this, source_url,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 make_scoped_refptr(file_system_context)));
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::ShutdownOnUIThread() {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shutdown_on_ui_ = true;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io_task_runner_->PostTask(
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&LocalFileSyncContext::ShutdownOnIOThread,
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 this));
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::GetFileForLocalSync(
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileSystemContext* file_system_context,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const LocalFileSyncInfoCallback& callback) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(file_system_context);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::deque<FileSystemURL>* urls = new std::deque<FileSystemURL>;
95a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  file_system_context->default_file_task_runner()->PostTaskAndReply(
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&LocalFileSyncContext::GetNextURLsForSyncOnFileThread,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 this, make_scoped_refptr(file_system_context),
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Unretained(urls)),
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&LocalFileSyncContext::TryPrepareForLocalSync,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 this, make_scoped_refptr(file_system_context),
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Owned(urls), callback));
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void LocalFileSyncContext::ClearChangesForURL(
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileSystemContext* file_system_context,
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const FileSystemURL& url,
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Closure& done_callback) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is initially called on UI thread and to be relayed to FILE thread.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(file_system_context);
111a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!file_system_context->default_file_task_runner()->
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          RunsTasksOnCurrentThread()) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
114a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    file_system_context->default_file_task_runner()->PostTask(
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&LocalFileSyncContext::ClearChangesForURL,
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   this, make_scoped_refptr(file_system_context),
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   url, done_callback));
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
121a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
122a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SyncFileSystemBackend* backend =
123a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      SyncFileSystemBackend::GetBackend(file_system_context);
124a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(backend);
125a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(backend->change_tracker());
126a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  backend->change_tracker()->ClearChangesForURL(url);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Call the completion callback on UI thread.
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui_task_runner_->PostTask(FROM_HERE, done_callback);
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void LocalFileSyncContext::ClearSyncFlagForURL(const FileSystemURL& url) {
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This is initially called on UI thread and to be relayed to IO thread.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io_task_runner_->PostTask(
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&LocalFileSyncContext::EnableWritingOnIOThread,
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 this, url));
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::PrepareForSync(
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileSystemContext* file_system_context,
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FileSystemURL& url,
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const LocalFileSyncInfoCallback& callback) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is initially called on UI thread and to be relayed to IO thread.
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!io_task_runner_->RunsTasksOnCurrentThread()) {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    io_task_runner_->PostTask(
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&LocalFileSyncContext::PrepareForSync, this,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   make_scoped_refptr(file_system_context), url, callback));
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const bool syncable = sync_status()->IsSyncable(url);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Disable writing if it's ready to be synced.
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (syncable)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sync_status()->StartSyncing(url);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui_task_runner_->PostTask(
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&LocalFileSyncContext::DidGetWritingStatusForSync,
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 this, make_scoped_refptr(file_system_context),
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 syncable ? SYNC_STATUS_OK :
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            SYNC_STATUS_FILE_BUSY,
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 url, callback));
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::RegisterURLForWaitingSync(
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FileSystemURL& url,
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Closure& on_syncable_callback) {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is initially called on UI thread and to be relayed to IO thread.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!io_task_runner_->RunsTasksOnCurrentThread()) {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    io_task_runner_->PostTask(
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&LocalFileSyncContext::RegisterURLForWaitingSync,
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   this, url, on_syncable_callback));
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (sync_status()->IsSyncable(url)) {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No need to register; fire the callback now.
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ui_task_runner_->PostTask(FROM_HERE, on_syncable_callback);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_waiting_sync_on_io_ = url;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_syncable_callback_ = on_syncable_callback;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::ApplyRemoteChange(
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileSystemContext* file_system_context,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FileChange& change,
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& local_path,
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FileSystemURL& url,
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SyncStatusCallback& callback) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!io_task_runner_->RunsTasksOnCurrentThread()) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    io_task_runner_->PostTask(
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&LocalFileSyncContext::ApplyRemoteChange, this,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   make_scoped_refptr(file_system_context),
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   change, local_path, url, callback));
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!sync_status()->IsWritable(url));
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!sync_status()->IsWriting(url));
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  FileSystemOperation::StatusCallback operation_callback;
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (change.change() == FileChange::FILE_CHANGE_ADD_OR_UPDATE) {
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    operation_callback = base::Bind(
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        &LocalFileSyncContext::DidRemoveExistingEntryForApplyRemoteChange,
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        this,
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        make_scoped_refptr(file_system_context),
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        change,
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        local_path,
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        url,
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        callback);
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK_EQ(FileChange::FILE_CHANGE_DELETE, change.change());
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    operation_callback = base::Bind(
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        &LocalFileSyncContext::DidApplyRemoteChange, this, url, callback);
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
223868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  FileSystemURL url_for_sync = CreateSyncableFileSystemURLForSync(
224868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      file_system_context, url);
225868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  file_system_context->operation_runner()->Remove(
226868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      url_for_sync, true /* recursive */, operation_callback);
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void LocalFileSyncContext::DidRemoveExistingEntryForApplyRemoteChange(
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    FileSystemContext* file_system_context,
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const FileChange& change,
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::FilePath& local_path,
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const FileSystemURL& url,
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const SyncStatusCallback& callback,
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::PlatformFileError error) {
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Remove() may fail if the target entry does not exist (which is ok),
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // so we ignore |error| here.
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!sync_status()) {
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    callback.Run(SYNC_FILE_ERROR_ABORT);
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!sync_status()->IsWritable(url));
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!sync_status()->IsWriting(url));
247868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  FileSystemURL url_for_sync = CreateSyncableFileSystemURLForSync(
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      file_system_context, url);
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  FileSystemOperation::StatusCallback operation_callback = base::Bind(
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      &LocalFileSyncContext::DidApplyRemoteChange, this, url, callback);
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(FileChange::FILE_CHANGE_ADD_OR_UPDATE, change.change());
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  switch (change.file_type()) {
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case SYNC_FILE_TYPE_FILE: {
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      DCHECK(!local_path.empty());
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::FilePath dir_path = fileapi::VirtualPath::DirName(url.path());
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (dir_path.empty() ||
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          fileapi::VirtualPath::DirName(dir_path) == dir_path) {
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Copying into the root directory.
261868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        file_system_context->operation_runner()->CopyInForeignFile(
262868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            local_path, url_for_sync, operation_callback);
263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else {
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        FileSystemURL dir_url = file_system_context->CreateCrackedFileSystemURL(
265868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            url_for_sync.origin(),
266868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            url_for_sync.mount_type(),
267868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            fileapi::VirtualPath::DirName(url_for_sync.virtual_path()));
268868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        file_system_context->operation_runner()->CreateDirectory(
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            dir_url,
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            false /* exclusive */,
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            true /* recursive */,
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            base::Bind(&LocalFileSyncContext::DidCreateDirectoryForCopyIn,
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       this,
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       make_scoped_refptr(file_system_context),
275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       local_path,
276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       url,
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       operation_callback));
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case SYNC_FILE_TYPE_DIRECTORY:
282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      file_system_context->operation_runner()->CreateDirectory(
283868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          url_for_sync, false /* exclusive */, true /* recursive */,
284868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          operation_callback);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case SYNC_FILE_TYPE_UNKNOWN:
287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      NOTREACHED() << "File type unknown for ADD_OR_UPDATE change";
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void LocalFileSyncContext::RecordFakeLocalChange(
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FileSystemContext* file_system_context,
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const FileSystemURL& url,
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const FileChange& change,
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const SyncStatusCallback& callback) {
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This is called on UI thread and to be relayed to FILE thread.
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(file_system_context);
298a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!file_system_context->default_file_task_runner()->
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          RunsTasksOnCurrentThread()) {
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
301a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    file_system_context->default_file_task_runner()->PostTask(
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&LocalFileSyncContext::RecordFakeLocalChange,
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   this, make_scoped_refptr(file_system_context),
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   url, change, callback));
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
309a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SyncFileSystemBackend* backend =
310a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      SyncFileSystemBackend::GetBackend(file_system_context);
311a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(backend);
312a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(backend->change_tracker());
313a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  backend->change_tracker()->MarkDirtyOnDatabase(url);
314a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  backend->change_tracker()->RecordChange(url, change);
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Fire the callback on UI thread.
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui_task_runner_->PostTask(FROM_HERE,
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            base::Bind(callback,
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       SYNC_STATUS_OK));
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::GetFileMetadata(
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileSystemContext* file_system_context,
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FileSystemURL& url,
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SyncFileMetadataCallback& callback) {
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is initially called on UI thread and to be relayed to IO thread.
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!io_task_runner_->RunsTasksOnCurrentThread()) {
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    io_task_runner_->PostTask(
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&LocalFileSyncContext::GetFileMetadata, this,
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   make_scoped_refptr(file_system_context), url, callback));
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
336868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
337868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  FileSystemURL url_for_sync = CreateSyncableFileSystemURLForSync(
338868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      file_system_context, url);
339868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  file_system_context->operation_runner()->GetMetadata(
340868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      url_for_sync, base::Bind(&LocalFileSyncContext::DidGetFileMetadata,
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      this, callback));
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void LocalFileSyncContext::HasPendingLocalChanges(
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FileSystemContext* file_system_context,
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const FileSystemURL& url,
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const HasPendingLocalChangeCallback& callback) {
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This gets called on UI thread and relays the task on FILE thread.
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(file_system_context);
350a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!file_system_context->default_file_task_runner()->
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          RunsTasksOnCurrentThread()) {
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
353a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    file_system_context->default_file_task_runner()->PostTask(
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&LocalFileSyncContext::HasPendingLocalChanges,
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   this, make_scoped_refptr(file_system_context),
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   url, callback));
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
361a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SyncFileSystemBackend* backend =
362a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      SyncFileSystemBackend::GetBackend(file_system_context);
363a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(backend);
364a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(backend->change_tracker());
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FileChangeList changes;
366a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  backend->change_tracker()->GetChangesForURL(url, &changes);
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Fire the callback on UI thread.
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui_task_runner_->PostTask(FROM_HERE,
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            base::Bind(callback,
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       SYNC_STATUS_OK,
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       !changes.empty()));
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::AddOriginChangeObserver(
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LocalOriginChangeObserver* observer) {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  origin_change_observers_.AddObserver(observer);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::RemoveOriginChangeObserver(
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LocalOriginChangeObserver* observer) {
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  origin_change_observers_.RemoveObserver(observer);
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::WeakPtr<SyncableFileOperationRunner>
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LocalFileSyncContext::operation_runner() const {
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
388b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (operation_runner_)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return operation_runner_->AsWeakPtr();
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::WeakPtr<SyncableFileOperationRunner>();
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LocalFileSyncStatus* LocalFileSyncContext::sync_status() const {
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return sync_status_.get();
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::OnSyncEnabled(const FileSystemURL& url) {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  origins_with_pending_changes_.insert(url.origin());
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleNotifyChangesUpdatedOnIOThread();
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_syncable_callback_.is_null() ||
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sync_status()->IsWriting(url_waiting_sync_on_io_)) {
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(kinuko): may want to check how many pending tasks we have.
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui_task_runner_->PostTask(FROM_HERE, url_syncable_callback_);
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_syncable_callback_.Reset();
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::OnWriteEnabled(const FileSystemURL& url) {
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Nothing to do for now.
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LocalFileSyncContext::~LocalFileSyncContext() {
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void LocalFileSyncContext::ScheduleNotifyChangesUpdatedOnIOThread() {
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::Time::Now() > last_notified_changes_ + NotifyChangesDuration()) {
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NotifyAvailableChangesOnIOThread();
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (!timer_on_io_->IsRunning()) {
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timer_on_io_->Start(
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE, NotifyChangesDuration(), this,
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &LocalFileSyncContext::NotifyAvailableChangesOnIOThread);
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::NotifyAvailableChangesOnIOThread() {
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui_task_runner_->PostTask(
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&LocalFileSyncContext::NotifyAvailableChanges,
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 this, origins_with_pending_changes_));
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_notified_changes_ = base::Time::Now();
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  origins_with_pending_changes_.clear();
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::NotifyAvailableChanges(
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::set<GURL>& origins) {
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(LocalOriginChangeObserver, origin_change_observers_,
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    OnChangesAvailableInOrigins(origins));
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::ShutdownOnIOThread() {
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  operation_runner_.reset();
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_status_.reset();
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_on_io_.reset();
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::InitializeFileSystemContextOnIOThread(
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& source_url,
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileSystemContext* file_system_context) {
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(file_system_context);
458a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SyncFileSystemBackend* backend =
459a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      SyncFileSystemBackend::GetBackend(file_system_context);
460a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(backend);
461a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!backend->change_tracker()) {
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // First registers the service name.
463868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    RegisterSyncableFileSystem();
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Create and initialize LocalFileChangeTracker and call back this method
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // later again.
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::set<GURL>* origins_with_changes = new std::set<GURL>;
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<LocalFileChangeTracker>* tracker_ptr(
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new scoped_ptr<LocalFileChangeTracker>);
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::PostTaskAndReplyWithResult(
470a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        file_system_context->default_file_task_runner(),
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&LocalFileSyncContext::InitializeChangeTrackerOnFileThread,
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   this, tracker_ptr,
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   make_scoped_refptr(file_system_context),
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   origins_with_changes),
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&LocalFileSyncContext::DidInitializeChangeTrackerOnIOThread,
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   this, base::Owned(tracker_ptr),
478868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                   source_url,
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   make_scoped_refptr(file_system_context),
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Owned(origins_with_changes)));
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
483b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!operation_runner_) {
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!sync_status_);
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!timer_on_io_);
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sync_status_.reset(new LocalFileSyncStatus);
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timer_on_io_.reset(new base::OneShotTimer<LocalFileSyncContext>);
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    operation_runner_.reset(new SyncableFileOperationRunner(
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            kMaxConcurrentSyncableOperation,
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sync_status_.get()));
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sync_status_->AddObserver(this);
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
493a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  backend->set_sync_context(this);
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DidInitialize(source_url, file_system_context,
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                SYNC_STATUS_OK);
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyncStatusCode LocalFileSyncContext::InitializeChangeTrackerOnFileThread(
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<LocalFileChangeTracker>* tracker_ptr,
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FileSystemContext* file_system_context,
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::set<GURL>* origins_with_changes) {
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(file_system_context);
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(tracker_ptr);
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(origins_with_changes);
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tracker_ptr->reset(new LocalFileChangeTracker(
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          file_system_context->partition_path(),
507a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          file_system_context->default_file_task_runner()));
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const SyncStatusCode status = (*tracker_ptr)->Initialize(file_system_context);
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (status != SYNC_STATUS_OK)
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return status;
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Get all origins that have pending changes.
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::deque<FileSystemURL> urls;
5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  (*tracker_ptr)->GetNextChangedURLs(&urls, 0);
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::deque<FileSystemURL>::iterator iter = urls.begin();
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       iter != urls.end(); ++iter) {
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    origins_with_changes->insert(iter->origin());
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return status;
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::DidInitializeChangeTrackerOnIOThread(
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<LocalFileChangeTracker>* tracker_ptr,
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& source_url,
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileSystemContext* file_system_context,
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::set<GURL>* origins_with_changes,
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SyncStatusCode status) {
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(file_system_context);
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(origins_with_changes);
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status != SYNC_STATUS_OK) {
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DidInitialize(source_url, file_system_context, status);
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
535a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
536a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SyncFileSystemBackend* backend =
537a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      SyncFileSystemBackend::GetBackend(file_system_context);
538a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(backend);
539a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  backend->SetLocalFileChangeTracker(tracker_ptr->Pass());
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  origins_with_pending_changes_.insert(origins_with_changes->begin(),
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       origins_with_changes->end());
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleNotifyChangesUpdatedOnIOThread();
5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
545868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  InitializeFileSystemContextOnIOThread(source_url, file_system_context);
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::DidInitialize(
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& source_url,
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileSystemContext* file_system_context,
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SyncStatusCode status) {
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ui_task_runner_->RunsTasksOnCurrentThread()) {
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ui_task_runner_->PostTask(
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&LocalFileSyncContext::DidInitialize,
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   this, source_url,
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   make_scoped_refptr(file_system_context), status));
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!ContainsKey(file_system_contexts_, file_system_context));
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsKey(pending_initialize_callbacks_, file_system_context));
563a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
564a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SyncFileSystemBackend* backend =
565a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      SyncFileSystemBackend::GetBackend(file_system_context);
566a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(backend);
567a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(backend->change_tracker());
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_system_contexts_.insert(file_system_context);
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StatusCallbackQueue& callback_queue =
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pending_initialize_callbacks_[file_system_context];
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (StatusCallbackQueue::iterator iter = callback_queue.begin();
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter != callback_queue.end(); ++iter) {
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ui_task_runner_->PostTask(FROM_HERE, base::Bind(*iter, status));
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_initialize_callbacks_.erase(file_system_context);
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::GetNextURLsForSyncOnFileThread(
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileSystemContext* file_system_context,
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::deque<FileSystemURL>* urls) {
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(file_system_context);
584a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(file_system_context->default_file_task_runner()->
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             RunsTasksOnCurrentThread());
586a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SyncFileSystemBackend* backend =
587a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      SyncFileSystemBackend::GetBackend(file_system_context);
588a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(backend);
589a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(backend->change_tracker());
590a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  backend->change_tracker()->GetNextChangedURLs(
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      urls, kMaxURLsToFetchForLocalSync);
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::TryPrepareForLocalSync(
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileSystemContext* file_system_context,
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::deque<FileSystemURL>* urls,
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const LocalFileSyncInfoCallback& callback) {
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(urls);
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
601c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (shutdown_on_ui_) {
602c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    callback.Run(SYNC_STATUS_ABORT, LocalFileSyncInfo());
603c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
604c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
605c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (urls->empty()) {
6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback.Run(SYNC_STATUS_NO_CHANGE_TO_SYNC,
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 LocalFileSyncInfo());
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const FileSystemURL url = urls->front();
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  urls->pop_front();
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::deque<FileSystemURL>* remaining = new std::deque<FileSystemURL>;
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  remaining->swap(*urls);
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrepareForSync(
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_system_context, url,
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&LocalFileSyncContext::DidTryPrepareForLocalSync,
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 this, make_scoped_refptr(file_system_context),
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Owned(remaining), callback));
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::DidTryPrepareForLocalSync(
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileSystemContext* file_system_context,
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::deque<FileSystemURL>* remaining_urls,
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const LocalFileSyncInfoCallback& callback,
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SyncStatusCode status,
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const LocalFileSyncInfo& sync_file_info) {
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status != SYNC_STATUS_FILE_BUSY) {
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback.Run(status, sync_file_info);
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Recursively call TryPrepareForLocalSync with remaining_urls.
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TryPrepareForLocalSync(file_system_context, remaining_urls, callback);
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::DidGetWritingStatusForSync(
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileSystemContext* file_system_context,
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SyncStatusCode status,
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FileSystemURL& url,
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const LocalFileSyncInfoCallback& callback) {
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This gets called on UI thread and relays the task on FILE thread.
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(file_system_context);
646a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!file_system_context->default_file_task_runner()->
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          RunsTasksOnCurrentThread()) {
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (shutdown_on_ui_) {
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      callback.Run(SYNC_STATUS_ABORT, LocalFileSyncInfo());
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
653a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    file_system_context->default_file_task_runner()->PostTask(
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&LocalFileSyncContext::DidGetWritingStatusForSync,
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   this, make_scoped_refptr(file_system_context),
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   status, url, callback));
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
661a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  SyncFileSystemBackend* backend =
662a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      SyncFileSystemBackend::GetBackend(file_system_context);
663a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(backend);
664a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(backend->change_tracker());
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FileChangeList changes;
666a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  backend->change_tracker()->GetChangesForURL(url, &changes);
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath platform_path;
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PlatformFileInfo file_info;
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FileSystemFileUtil* file_util = file_system_context->GetFileUtil(url.type());
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(file_util);
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PlatformFileError file_error = file_util->GetFileInfo(
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      make_scoped_ptr(
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          new FileSystemOperationContext(file_system_context)).get(),
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url,
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &file_info,
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &platform_path);
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status == SYNC_STATUS_OK &&
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_error != base::PLATFORM_FILE_OK &&
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_error != base::PLATFORM_FILE_ERROR_NOT_FOUND)
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    status = PlatformFileErrorToSyncStatusCode(file_error);
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!file_info.is_symbolic_link);
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SyncFileType file_type = SYNC_FILE_TYPE_FILE;
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (file_error == base::PLATFORM_FILE_ERROR_NOT_FOUND)
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_type = SYNC_FILE_TYPE_UNKNOWN;
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if (file_info.is_directory)
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_type = SYNC_FILE_TYPE_DIRECTORY;
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LocalFileSyncInfo sync_file_info;
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_file_info.url = url;
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_file_info.local_file_path = platform_path;
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_file_info.metadata.file_type = file_type;
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_file_info.metadata.size = file_info.size;
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_file_info.metadata.last_modified = file_info.last_modified;
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_file_info.changes = changes;
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui_task_runner_->PostTask(FROM_HERE,
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            base::Bind(callback, status, sync_file_info));
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::EnableWritingOnIOThread(
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FileSystemURL& url) {
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
706c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!sync_status()) {
707c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // The service might have been shut down.
708c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
709c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_status()->EndSyncing(url);
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since a sync has finished the number of changes must have been updated.
7122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  origins_with_pending_changes_.insert(url.origin());
7132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScheduleNotifyChangesUpdatedOnIOThread();
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::DidApplyRemoteChange(
7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const FileSystemURL& url,
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SyncStatusCallback& callback_on_ui,
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::PlatformFileError file_error) {
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui_task_runner_->PostTask(
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(callback_on_ui,
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 PlatformFileErrorToSyncStatusCode(file_error)));
7252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EnableWritingOnIOThread(url);
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LocalFileSyncContext::DidGetFileMetadata(
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SyncFileMetadataCallback& callback,
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::PlatformFileError file_error,
7317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const base::PlatformFileInfo& file_info) {
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SyncFileMetadata metadata;
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (file_error == base::PLATFORM_FILE_OK) {
7352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    metadata.file_type = file_info.is_directory ?
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        SYNC_FILE_TYPE_DIRECTORY : SYNC_FILE_TYPE_FILE;
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    metadata.size = file_info.size;
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    metadata.last_modified = file_info.last_modified;
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui_task_runner_->PostTask(
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(callback,
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 PlatformFileErrorToSyncStatusCode(file_error),
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 metadata));
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::TimeDelta LocalFileSyncContext::NotifyChangesDuration() {
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (mock_notify_changes_duration_in_sec_ >= 0)
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return base::TimeDelta::FromSeconds(mock_notify_changes_duration_in_sec_);
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::TimeDelta::FromSeconds(kNotifyChangesDurationInSec);
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
753c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void LocalFileSyncContext::DidCreateDirectoryForCopyIn(
754c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    FileSystemContext* file_system_context,
755c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::FilePath& local_path,
756c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const FileSystemURL& dest_url,
757c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const StatusCallback& callback,
758c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::PlatformFileError error) {
759c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (error != base::PLATFORM_FILE_OK) {
760c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    callback.Run(error);
761c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
762c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
763c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
764868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  FileSystemURL url_for_sync = CreateSyncableFileSystemURLForSync(
765868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      file_system_context, dest_url);
766868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  file_system_context->operation_runner()->CopyInForeignFile(
767868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      local_path, url_for_sync, callback);
768c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
769c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace sync_file_system
771