OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/sync/internal_api/sync_manager.h" | 5 #include "chrome/browser/sync/internal_api/sync_manager.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/base64.h" | 9 #include "base/base64.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 1062 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1073 done_callback.Run(); // Should only happen during first time sync. | 1073 done_callback.Run(); // Should only happen during first time sync. |
1074 return; | 1074 return; |
1075 } | 1075 } |
1076 | 1076 |
1077 bool success = false; | 1077 bool success = false; |
1078 { | 1078 { |
1079 WriteTransaction trans(FROM_HERE, GetUserShare()); | 1079 WriteTransaction trans(FROM_HERE, GetUserShare()); |
1080 Cryptographer* cryptographer = trans.GetCryptographer(); | 1080 Cryptographer* cryptographer = trans.GetCryptographer(); |
1081 WriteNode node(&trans); | 1081 WriteNode node(&trans); |
1082 | 1082 |
1083 if (node.InitByTagLookup(kNigoriTag)) { | 1083 if (node.InitByTagLookup(kNigoriTag) == sync_api::BaseNode::INIT_OK) { |
1084 sync_pb::NigoriSpecifics nigori(node.GetNigoriSpecifics()); | 1084 sync_pb::NigoriSpecifics nigori(node.GetNigoriSpecifics()); |
1085 Cryptographer::UpdateResult result = cryptographer->Update(nigori); | 1085 Cryptographer::UpdateResult result = cryptographer->Update(nigori); |
1086 if (result == Cryptographer::NEEDS_PASSPHRASE) { | 1086 if (result == Cryptographer::NEEDS_PASSPHRASE) { |
1087 sync_pb::EncryptedData pending_keys; | 1087 sync_pb::EncryptedData pending_keys; |
1088 if (cryptographer->has_pending_keys()) | 1088 if (cryptographer->has_pending_keys()) |
1089 pending_keys = cryptographer->GetPendingKeys(); | 1089 pending_keys = cryptographer->GetPendingKeys(); |
1090 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | 1090 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, |
1091 OnPassphraseRequired(sync_api::REASON_DECRYPTION, | 1091 OnPassphraseRequired(sync_api::REASON_DECRYPTION, |
1092 pending_keys)); | 1092 pending_keys)); |
1093 } | 1093 } |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1246 } | 1246 } |
1247 | 1247 |
1248 void SyncManager::SyncInternal::MaybeSetSyncTabsInNigoriNode( | 1248 void SyncManager::SyncInternal::MaybeSetSyncTabsInNigoriNode( |
1249 const ModelTypeSet enabled_types) { | 1249 const ModelTypeSet enabled_types) { |
1250 // The initialized_ check is to ensure that we don't CHECK in GetUserShare | 1250 // The initialized_ check is to ensure that we don't CHECK in GetUserShare |
1251 // when this is called on start-up. It's ok to ignore that case, since | 1251 // when this is called on start-up. It's ok to ignore that case, since |
1252 // presumably this would've run when the user originally enabled sessions. | 1252 // presumably this would've run when the user originally enabled sessions. |
1253 if (initialized_ && enabled_types.Has(syncable::SESSIONS)) { | 1253 if (initialized_ && enabled_types.Has(syncable::SESSIONS)) { |
1254 WriteTransaction trans(FROM_HERE, GetUserShare()); | 1254 WriteTransaction trans(FROM_HERE, GetUserShare()); |
1255 WriteNode node(&trans); | 1255 WriteNode node(&trans); |
1256 if (!node.InitByTagLookup(kNigoriTag)) { | 1256 if (node.InitByTagLookup(kNigoriTag) != sync_api::BaseNode::INIT_OK) { |
1257 LOG(WARNING) << "Unable to set 'sync_tabs' bit because Nigori node not " | 1257 LOG(WARNING) << "Unable to set 'sync_tabs' bit because Nigori node not " |
1258 << "found."; | 1258 << "found."; |
1259 return; | 1259 return; |
1260 } | 1260 } |
1261 | 1261 |
1262 sync_pb::NigoriSpecifics specifics(node.GetNigoriSpecifics()); | 1262 sync_pb::NigoriSpecifics specifics(node.GetNigoriSpecifics()); |
1263 specifics.set_sync_tabs(true); | 1263 specifics.set_sync_tabs(true); |
1264 node.SetNigoriSpecifics(specifics); | 1264 node.SetNigoriSpecifics(specifics); |
1265 } | 1265 } |
1266 } | 1266 } |
1267 | 1267 |
1268 void SyncManager::SyncInternal::SetEncryptionPassphrase( | 1268 void SyncManager::SyncInternal::SetEncryptionPassphrase( |
1269 const std::string& passphrase, | 1269 const std::string& passphrase, |
1270 bool is_explicit) { | 1270 bool is_explicit) { |
1271 // We do not accept empty passphrases. | 1271 // We do not accept empty passphrases. |
1272 if (passphrase.empty()) { | 1272 if (passphrase.empty()) { |
1273 NOTREACHED() << "Cannot encrypt with an empty passphrase."; | 1273 NOTREACHED() << "Cannot encrypt with an empty passphrase."; |
1274 return; | 1274 return; |
1275 } | 1275 } |
1276 | 1276 |
1277 // All accesses to the cryptographer are protected by a transaction. | 1277 // All accesses to the cryptographer are protected by a transaction. |
1278 WriteTransaction trans(FROM_HERE, GetUserShare()); | 1278 WriteTransaction trans(FROM_HERE, GetUserShare()); |
1279 Cryptographer* cryptographer = trans.GetCryptographer(); | 1279 Cryptographer* cryptographer = trans.GetCryptographer(); |
1280 KeyParams key_params = {"localhost", "dummy", passphrase}; | 1280 KeyParams key_params = {"localhost", "dummy", passphrase}; |
1281 WriteNode node(&trans); | 1281 WriteNode node(&trans); |
1282 if (!node.InitByTagLookup(kNigoriTag)) { | 1282 if (node.InitByTagLookup(kNigoriTag) != sync_api::BaseNode::INIT_OK) { |
1283 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS. | 1283 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS. |
1284 NOTREACHED(); | 1284 NOTREACHED(); |
1285 return; | 1285 return; |
1286 } | 1286 } |
1287 | 1287 |
1288 bool nigori_has_explicit_passphrase = | 1288 bool nigori_has_explicit_passphrase = |
1289 node.GetNigoriSpecifics().using_explicit_passphrase(); | 1289 node.GetNigoriSpecifics().using_explicit_passphrase(); |
1290 std::string bootstrap_token; | 1290 std::string bootstrap_token; |
1291 sync_pb::EncryptedData pending_keys; | 1291 sync_pb::EncryptedData pending_keys; |
1292 if (cryptographer->has_pending_keys()) | 1292 if (cryptographer->has_pending_keys()) |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1386 if (passphrase.empty()) { | 1386 if (passphrase.empty()) { |
1387 NOTREACHED() << "Cannot decrypt with an empty passphrase."; | 1387 NOTREACHED() << "Cannot decrypt with an empty passphrase."; |
1388 return; | 1388 return; |
1389 } | 1389 } |
1390 | 1390 |
1391 // All accesses to the cryptographer are protected by a transaction. | 1391 // All accesses to the cryptographer are protected by a transaction. |
1392 WriteTransaction trans(FROM_HERE, GetUserShare()); | 1392 WriteTransaction trans(FROM_HERE, GetUserShare()); |
1393 Cryptographer* cryptographer = trans.GetCryptographer(); | 1393 Cryptographer* cryptographer = trans.GetCryptographer(); |
1394 KeyParams key_params = {"localhost", "dummy", passphrase}; | 1394 KeyParams key_params = {"localhost", "dummy", passphrase}; |
1395 WriteNode node(&trans); | 1395 WriteNode node(&trans); |
1396 if (!node.InitByTagLookup(kNigoriTag)) { | 1396 if (node.InitByTagLookup(kNigoriTag) != sync_api::BaseNode::INIT_OK) { |
1397 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS. | 1397 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS. |
1398 NOTREACHED(); | 1398 NOTREACHED(); |
1399 return; | 1399 return; |
1400 } | 1400 } |
1401 | 1401 |
1402 if (!cryptographer->has_pending_keys()) { | 1402 if (!cryptographer->has_pending_keys()) { |
1403 // Note that this *can* happen in a rare situation where data is | 1403 // Note that this *can* happen in a rare situation where data is |
1404 // re-encrypted on another client while a SetDecryptionPassphrase() call is | 1404 // re-encrypted on another client while a SetDecryptionPassphrase() call is |
1405 // in-flight on this client. It is rare enough that we choose to do nothing. | 1405 // in-flight on this client. It is rare enough that we choose to do nothing. |
1406 NOTREACHED() << "Attempt to set decryption passphrase failed because there " | 1406 NOTREACHED() << "Attempt to set decryption passphrase failed because there " |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1575 nigori_node->SetNigoriSpecifics(specifics); | 1575 nigori_node->SetNigoriSpecifics(specifics); |
1576 | 1576 |
1577 // Does nothing if everything is already encrypted or the cryptographer has | 1577 // Does nothing if everything is already encrypted or the cryptographer has |
1578 // pending keys. | 1578 // pending keys. |
1579 ReEncryptEverything(trans); | 1579 ReEncryptEverything(trans); |
1580 } | 1580 } |
1581 | 1581 |
1582 bool SyncManager::SyncInternal::IsUsingExplicitPassphrase() { | 1582 bool SyncManager::SyncInternal::IsUsingExplicitPassphrase() { |
1583 ReadTransaction trans(FROM_HERE, &share_); | 1583 ReadTransaction trans(FROM_HERE, &share_); |
1584 ReadNode node(&trans); | 1584 ReadNode node(&trans); |
1585 if (!node.InitByTagLookup(kNigoriTag)) { | 1585 if (node.InitByTagLookup(kNigoriTag) != sync_api::BaseNode::INIT_OK) { |
1586 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS. | 1586 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS. |
1587 NOTREACHED(); | 1587 NOTREACHED(); |
1588 return false; | 1588 return false; |
1589 } | 1589 } |
1590 | 1590 |
1591 return node.GetNigoriSpecifics().using_explicit_passphrase(); | 1591 return node.GetNigoriSpecifics().using_explicit_passphrase(); |
1592 } | 1592 } |
1593 | 1593 |
1594 void SyncManager::SyncInternal::RefreshEncryption() { | 1594 void SyncManager::SyncInternal::RefreshEncryption() { |
1595 DCHECK(initialized_); | 1595 DCHECK(initialized_); |
1596 | 1596 |
1597 WriteTransaction trans(FROM_HERE, GetUserShare()); | 1597 WriteTransaction trans(FROM_HERE, GetUserShare()); |
1598 WriteNode node(&trans); | 1598 WriteNode node(&trans); |
1599 if (!node.InitByTagLookup(kNigoriTag)) { | 1599 if (node.InitByTagLookup(kNigoriTag) != sync_api::BaseNode::INIT_OK) { |
1600 NOTREACHED() << "Unable to set encrypted datatypes because Nigori node not " | 1600 NOTREACHED() << "Unable to set encrypted datatypes because Nigori node not " |
1601 << "found."; | 1601 << "found."; |
1602 return; | 1602 return; |
1603 } | 1603 } |
1604 | 1604 |
1605 Cryptographer* cryptographer = trans.GetCryptographer(); | 1605 Cryptographer* cryptographer = trans.GetCryptographer(); |
1606 | 1606 |
1607 if (!cryptographer->is_ready()) { | 1607 if (!cryptographer->is_ready()) { |
1608 DVLOG(1) << "Attempting to encrypt datatypes when cryptographer not " | 1608 DVLOG(1) << "Attempting to encrypt datatypes when cryptographer not " |
1609 << "initialized, prompting for passphrase."; | 1609 << "initialized, prompting for passphrase."; |
(...skipping 26 matching lines...) Expand all Loading... |
1636 registrar_->GetModelSafeRoutingInfo(&routes); | 1636 registrar_->GetModelSafeRoutingInfo(&routes); |
1637 std::string tag; | 1637 std::string tag; |
1638 for (syncable::ModelTypeSet::Iterator iter = encrypted_types.First(); | 1638 for (syncable::ModelTypeSet::Iterator iter = encrypted_types.First(); |
1639 iter.Good(); iter.Inc()) { | 1639 iter.Good(); iter.Inc()) { |
1640 if (iter.Get() == syncable::PASSWORDS || | 1640 if (iter.Get() == syncable::PASSWORDS || |
1641 iter.Get() == syncable::NIGORI || | 1641 iter.Get() == syncable::NIGORI || |
1642 routes.count(iter.Get()) == 0) | 1642 routes.count(iter.Get()) == 0) |
1643 continue; | 1643 continue; |
1644 ReadNode type_root(trans); | 1644 ReadNode type_root(trans); |
1645 tag = syncable::ModelTypeToRootTag(iter.Get()); | 1645 tag = syncable::ModelTypeToRootTag(iter.Get()); |
1646 if (!type_root.InitByTagLookup(tag)) { | 1646 if (type_root.InitByTagLookup(tag) != sync_api::BaseNode::INIT_OK) { |
1647 // This can happen when we enable a datatype for the first time on restart | 1647 // This can happen when we enable a datatype for the first time on restart |
1648 // (for example when we upgrade) and therefore haven't done the initial | 1648 // (for example when we upgrade) and therefore haven't done the initial |
1649 // download for that type at the time we RefreshEncryption. There's | 1649 // download for that type at the time we RefreshEncryption. There's |
1650 // nothing we can do for now, so just move on to the next type. | 1650 // nothing we can do for now, so just move on to the next type. |
1651 continue; | 1651 continue; |
1652 } | 1652 } |
1653 | 1653 |
1654 // Iterate through all children of this datatype. | 1654 // Iterate through all children of this datatype. |
1655 std::queue<int64> to_visit; | 1655 std::queue<int64> to_visit; |
1656 int64 child_id = type_root.GetFirstChildId(); | 1656 int64 child_id = type_root.GetFirstChildId(); |
1657 to_visit.push(child_id); | 1657 to_visit.push(child_id); |
1658 while (!to_visit.empty()) { | 1658 while (!to_visit.empty()) { |
1659 child_id = to_visit.front(); | 1659 child_id = to_visit.front(); |
1660 to_visit.pop(); | 1660 to_visit.pop(); |
1661 if (child_id == kInvalidId) | 1661 if (child_id == kInvalidId) |
1662 continue; | 1662 continue; |
1663 | 1663 |
1664 WriteNode child(trans); | 1664 WriteNode child(trans); |
1665 if (!child.InitByIdLookup(child_id)) { | 1665 if (child.InitByIdLookup(child_id) != sync_api::BaseNode::INIT_OK) { |
1666 NOTREACHED(); | 1666 NOTREACHED(); |
1667 continue; | 1667 continue; |
1668 } | 1668 } |
1669 if (child.GetIsFolder()) { | 1669 if (child.GetIsFolder()) { |
1670 to_visit.push(child.GetFirstChildId()); | 1670 to_visit.push(child.GetFirstChildId()); |
1671 } | 1671 } |
1672 if (child.GetEntry()->Get(syncable::UNIQUE_SERVER_TAG).empty()) { | 1672 if (child.GetEntry()->Get(syncable::UNIQUE_SERVER_TAG).empty()) { |
1673 // Rewrite the specifics of the node with encrypted data if necessary | 1673 // Rewrite the specifics of the node with encrypted data if necessary |
1674 // (only rewrite the non-unique folders). | 1674 // (only rewrite the non-unique folders). |
1675 child.ResetFromSpecifics(); | 1675 child.ResetFromSpecifics(); |
1676 } | 1676 } |
1677 to_visit.push(child.GetSuccessorId()); | 1677 to_visit.push(child.GetSuccessorId()); |
1678 } | 1678 } |
1679 } | 1679 } |
1680 | 1680 |
1681 if (routes.count(syncable::PASSWORDS) > 0) { | 1681 if (routes.count(syncable::PASSWORDS) > 0) { |
1682 // Passwords are encrypted with their own legacy scheme. | 1682 // Passwords are encrypted with their own legacy scheme. |
1683 ReadNode passwords_root(trans); | 1683 ReadNode passwords_root(trans); |
1684 std::string passwords_tag = | 1684 std::string passwords_tag = |
1685 syncable::ModelTypeToRootTag(syncable::PASSWORDS); | 1685 syncable::ModelTypeToRootTag(syncable::PASSWORDS); |
1686 // It's possible we'll have the password routing info and not the password | 1686 // It's possible we'll have the password routing info and not the password |
1687 // root if we attempted to set a passphrase before passwords was enabled. | 1687 // root if we attempted to set a passphrase before passwords was enabled. |
1688 if (passwords_root.InitByTagLookup(passwords_tag)) { | 1688 if (passwords_root.InitByTagLookup(passwords_tag) == |
| 1689 sync_api::BaseNode::INIT_OK) { |
1689 int64 child_id = passwords_root.GetFirstChildId(); | 1690 int64 child_id = passwords_root.GetFirstChildId(); |
1690 while (child_id != kInvalidId) { | 1691 while (child_id != kInvalidId) { |
1691 WriteNode child(trans); | 1692 WriteNode child(trans); |
1692 if (!child.InitByIdLookup(child_id)) { | 1693 if (child.InitByIdLookup(child_id) != sync_api::BaseNode::INIT_OK) { |
1693 NOTREACHED(); | 1694 NOTREACHED(); |
1694 return; | 1695 return; |
1695 } | 1696 } |
1696 child.SetPasswordSpecifics(child.GetPasswordSpecifics()); | 1697 child.SetPasswordSpecifics(child.GetPasswordSpecifics()); |
1697 child_id = child.GetSuccessorId(); | 1698 child_id = child.GetSuccessorId(); |
1698 } | 1699 } |
1699 } | 1700 } |
1700 } | 1701 } |
1701 | 1702 |
1702 // NOTE: We notify from within a transaction. | 1703 // NOTE: We notify from within a transaction. |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2085 LOG(INFO) << "OnSyncCycleCompleted not sent because sync api is not " | 2086 LOG(INFO) << "OnSyncCycleCompleted not sent because sync api is not " |
2086 << "initialized"; | 2087 << "initialized"; |
2087 return; | 2088 return; |
2088 } | 2089 } |
2089 | 2090 |
2090 if (!event.snapshot->has_more_to_sync) { | 2091 if (!event.snapshot->has_more_to_sync) { |
2091 // To account for a nigori node arriving with stale/bad data, we ensure | 2092 // To account for a nigori node arriving with stale/bad data, we ensure |
2092 // that the nigori node is up to date at the end of each cycle. | 2093 // that the nigori node is up to date at the end of each cycle. |
2093 WriteTransaction trans(FROM_HERE, GetUserShare()); | 2094 WriteTransaction trans(FROM_HERE, GetUserShare()); |
2094 WriteNode nigori_node(&trans); | 2095 WriteNode nigori_node(&trans); |
2095 if (nigori_node.InitByTagLookup(kNigoriTag)) { | 2096 if (nigori_node.InitByTagLookup(kNigoriTag) == |
| 2097 sync_api::BaseNode::INIT_OK) { |
2096 Cryptographer* cryptographer = trans.GetCryptographer(); | 2098 Cryptographer* cryptographer = trans.GetCryptographer(); |
2097 UpdateNigoriEncryptionState(cryptographer, &nigori_node); | 2099 UpdateNigoriEncryptionState(cryptographer, &nigori_node); |
2098 } | 2100 } |
2099 | 2101 |
2100 DVLOG(1) << "Sending OnSyncCycleCompleted"; | 2102 DVLOG(1) << "Sending OnSyncCycleCompleted"; |
2101 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, | 2103 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, |
2102 OnSyncCycleCompleted(event.snapshot)); | 2104 OnSyncCycleCompleted(event.snapshot)); |
2103 } | 2105 } |
2104 | 2106 |
2105 // This is here for tests, which are still using p2p notifications. | 2107 // This is here for tests, which are still using p2p notifications. |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2265 ListValue* id_list = NULL; | 2267 ListValue* id_list = NULL; |
2266 ReadTransaction trans(FROM_HERE, user_share); | 2268 ReadTransaction trans(FROM_HERE, user_share); |
2267 if (args.Get().GetList(0, &id_list)) { | 2269 if (args.Get().GetList(0, &id_list)) { |
2268 CHECK(id_list); | 2270 CHECK(id_list); |
2269 for (size_t i = 0; i < id_list->GetSize(); ++i) { | 2271 for (size_t i = 0; i < id_list->GetSize(); ++i) { |
2270 int64 id = GetId(*id_list, i); | 2272 int64 id = GetId(*id_list, i); |
2271 if (id == kInvalidId) { | 2273 if (id == kInvalidId) { |
2272 continue; | 2274 continue; |
2273 } | 2275 } |
2274 ReadNode node(&trans); | 2276 ReadNode node(&trans); |
2275 if (!node.InitByIdLookup(id)) { | 2277 if (node.InitByIdLookup(id) != sync_api::BaseNode::INIT_OK) { |
2276 continue; | 2278 continue; |
2277 } | 2279 } |
2278 node_summaries->Append((node.*info_getter)()); | 2280 node_summaries->Append((node.*info_getter)()); |
2279 } | 2281 } |
2280 } | 2282 } |
2281 return JsArgList(&return_args); | 2283 return JsArgList(&return_args); |
2282 } | 2284 } |
2283 | 2285 |
2284 } // namespace | 2286 } // namespace |
2285 | 2287 |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2473 | 2475 |
2474 syncable::ModelTypeSet SyncManager::GetEncryptedDataTypesForTest() const { | 2476 syncable::ModelTypeSet SyncManager::GetEncryptedDataTypesForTest() const { |
2475 ReadTransaction trans(FROM_HERE, GetUserShare()); | 2477 ReadTransaction trans(FROM_HERE, GetUserShare()); |
2476 return GetEncryptedTypes(&trans); | 2478 return GetEncryptedTypes(&trans); |
2477 } | 2479 } |
2478 | 2480 |
2479 bool SyncManager::ReceivedExperimentalTypes(syncable::ModelTypeSet* to_add) | 2481 bool SyncManager::ReceivedExperimentalTypes(syncable::ModelTypeSet* to_add) |
2480 const { | 2482 const { |
2481 ReadTransaction trans(FROM_HERE, GetUserShare()); | 2483 ReadTransaction trans(FROM_HERE, GetUserShare()); |
2482 ReadNode node(&trans); | 2484 ReadNode node(&trans); |
2483 if (!node.InitByTagLookup(kNigoriTag)) { | 2485 if (node.InitByTagLookup(kNigoriTag) != sync_api::BaseNode::INIT_OK) { |
2484 DVLOG(1) << "Couldn't find Nigori node."; | 2486 DVLOG(1) << "Couldn't find Nigori node."; |
2485 return false; | 2487 return false; |
2486 } | 2488 } |
2487 if (node.GetNigoriSpecifics().sync_tabs()) { | 2489 if (node.GetNigoriSpecifics().sync_tabs()) { |
2488 to_add->Put(syncable::SESSIONS); | 2490 to_add->Put(syncable::SESSIONS); |
2489 return true; | 2491 return true; |
2490 } | 2492 } |
2491 return false; | 2493 return false; |
2492 } | 2494 } |
2493 | 2495 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2564 share->directory->GetDownloadProgress(i.Get(), &marker); | 2566 share->directory->GetDownloadProgress(i.Get(), &marker); |
2565 | 2567 |
2566 if (marker.token().empty()) | 2568 if (marker.token().empty()) |
2567 result.Put(i.Get()); | 2569 result.Put(i.Get()); |
2568 | 2570 |
2569 } | 2571 } |
2570 return result; | 2572 return result; |
2571 } | 2573 } |
2572 | 2574 |
2573 } // namespace sync_api | 2575 } // namespace sync_api |
OLD | NEW |