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/chromeos/gdata/gdata_file_system.h" | 5 #include "chrome/browser/chromeos/gdata/gdata_file_system.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <sys/stat.h> | 8 #include <sys/stat.h> |
9 | 9 |
10 #include <set> | 10 #include <set> |
(...skipping 725 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
736 *error = base::PLATFORM_FILE_OK; | 736 *error = base::PLATFORM_FILE_OK; |
737 } | 737 } |
738 } | 738 } |
739 | 739 |
740 *mime_type = kMimeTypeJson; | 740 *mime_type = kMimeTypeJson; |
741 *file_type = HOSTED_DOCUMENT; | 741 *file_type = HOSTED_DOCUMENT; |
742 if (*error != base::PLATFORM_FILE_OK) | 742 if (*error != base::PLATFORM_FILE_OK) |
743 temp_file_path->clear(); | 743 temp_file_path->clear(); |
744 } | 744 } |
745 | 745 |
| 746 // Tests if we are allowed to create new directory in the provided directory. |
| 747 bool ShouldCreateDirectory(const FilePath& directory_path) { |
| 748 // We allow directory creation for paths that are on gdata file system |
| 749 // (GDATA_SEARCH_PATH_INVALID) and paths that reference actual gdata file |
| 750 // system path (GDATA_SEARCH_PATH_RESULT_CHILD). |
| 751 util::GDataSearchPathType path_type = |
| 752 util::GetSearchPathStatus(directory_path); |
| 753 return path_type == util::GDATA_SEARCH_PATH_INVALID || |
| 754 path_type == util::GDATA_SEARCH_PATH_RESULT_CHILD; |
| 755 } |
| 756 |
746 // Relays the given FindEntryCallback to another thread via |replay_proxy|. | 757 // Relays the given FindEntryCallback to another thread via |replay_proxy|. |
747 void RelayFindEntryCallback(scoped_refptr<base::MessageLoopProxy> relay_proxy, | 758 void RelayFindEntryCallback(scoped_refptr<base::MessageLoopProxy> relay_proxy, |
748 const FindEntryCallback& callback, | 759 const FindEntryCallback& callback, |
749 base::PlatformFileError error, | 760 base::PlatformFileError error, |
750 const FilePath& directory_path, | 761 const FilePath& directory_path, |
751 GDataEntry* entry) { | 762 GDataEntry* entry) { |
752 relay_proxy->PostTask(FROM_HERE, | 763 relay_proxy->PostTask(FROM_HERE, |
753 base::Bind(callback, error, directory_path, entry)); | 764 base::Bind(callback, error, directory_path, entry)); |
754 } | 765 } |
755 | 766 |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
862 | 873 |
863 GDataFileProperties::~GDataFileProperties() { | 874 GDataFileProperties::~GDataFileProperties() { |
864 } | 875 } |
865 | 876 |
866 // GDataFileSystem::GetDocumentsParams struct implementation. | 877 // GDataFileSystem::GetDocumentsParams struct implementation. |
867 | 878 |
868 GDataFileSystem::GetDocumentsParams::GetDocumentsParams( | 879 GDataFileSystem::GetDocumentsParams::GetDocumentsParams( |
869 int start_changestamp, | 880 int start_changestamp, |
870 int root_feed_changestamp, | 881 int root_feed_changestamp, |
871 std::vector<DocumentFeed*>* feed_list, | 882 std::vector<DocumentFeed*>* feed_list, |
| 883 bool should_fetch_multiple_feeds, |
872 const FilePath& search_file_path, | 884 const FilePath& search_file_path, |
| 885 const std::string& search_query, |
873 const FindEntryCallback& callback) | 886 const FindEntryCallback& callback) |
874 : start_changestamp(start_changestamp), | 887 : start_changestamp(start_changestamp), |
875 root_feed_changestamp(root_feed_changestamp), | 888 root_feed_changestamp(root_feed_changestamp), |
876 feed_list(feed_list), | 889 feed_list(feed_list), |
| 890 should_fetch_multiple_feeds(should_fetch_multiple_feeds), |
877 search_file_path(search_file_path), | 891 search_file_path(search_file_path), |
| 892 search_query(search_query), |
878 callback(callback) { | 893 callback(callback) { |
879 } | 894 } |
880 | 895 |
881 GDataFileSystem::GetDocumentsParams::~GetDocumentsParams() { | 896 GDataFileSystem::GetDocumentsParams::~GetDocumentsParams() { |
882 STLDeleteElements(feed_list.get()); | 897 STLDeleteElements(feed_list.get()); |
883 } | 898 } |
884 | 899 |
885 // GDataFileSystem::CreateDirectoryParams struct implementation. | 900 // GDataFileSystem::CreateDirectoryParams struct implementation. |
886 | 901 |
887 GDataFileSystem::CreateDirectoryParams::CreateDirectoryParams( | 902 GDataFileSystem::CreateDirectoryParams::CreateDirectoryParams( |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1140 int local_changestamp, | 1155 int local_changestamp, |
1141 const FilePath& search_file_path, | 1156 const FilePath& search_file_path, |
1142 const FindEntryCallback& callback, | 1157 const FindEntryCallback& callback, |
1143 GDataErrorCode status, | 1158 GDataErrorCode status, |
1144 scoped_ptr<base::Value> feed_data) { | 1159 scoped_ptr<base::Value> feed_data) { |
1145 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1146 | 1161 |
1147 base::PlatformFileError error = GDataToPlatformError(status); | 1162 base::PlatformFileError error = GDataToPlatformError(status); |
1148 if (error != base::PLATFORM_FILE_OK) { | 1163 if (error != base::PLATFORM_FILE_OK) { |
1149 // Get changes starting from the next changestamp from what we have locally. | 1164 // Get changes starting from the next changestamp from what we have locally. |
1150 LoadFeedFromServer(local_changestamp + 1, 0, search_file_path, callback); | 1165 LoadFeedFromServer(local_changestamp + 1, 0, |
| 1166 true, /* should_fetch_multiple_feeds */ |
| 1167 search_file_path, |
| 1168 std::string() /* no search query */, |
| 1169 callback, |
| 1170 base::Bind(&GDataFileSystem::OnFeedFromServerLoaded, |
| 1171 ui_weak_ptr_)); |
1151 return; | 1172 return; |
1152 } | 1173 } |
1153 | 1174 |
1154 scoped_ptr<AccountMetadataFeed> feed; | 1175 scoped_ptr<AccountMetadataFeed> feed; |
1155 if (feed_data.get()) | 1176 if (feed_data.get()) |
1156 feed = AccountMetadataFeed::CreateFrom(*feed_data); | 1177 feed = AccountMetadataFeed::CreateFrom(*feed_data); |
1157 if (!feed.get()) { | 1178 if (!feed.get()) { |
1158 LoadFeedFromServer(local_changestamp + 1, 0, search_file_path, callback); | 1179 LoadFeedFromServer(local_changestamp + 1, 0, |
| 1180 true, /* should_fetch_multiple_feeds */ |
| 1181 search_file_path, |
| 1182 std::string() /* no search query */, |
| 1183 callback, |
| 1184 base::Bind(&GDataFileSystem::OnFeedFromServerLoaded, |
| 1185 ui_weak_ptr_)); |
1159 return; | 1186 return; |
1160 } | 1187 } |
1161 | 1188 |
1162 bool changes_detected = true; | 1189 bool changes_detected = true; |
1163 if (local_changestamp >= feed->largest_changestamp()) { | 1190 if (local_changestamp >= feed->largest_changestamp()) { |
1164 if (local_changestamp > feed->largest_changestamp()) { | 1191 if (local_changestamp > feed->largest_changestamp()) { |
1165 LOG(WARNING) << "Cached client feed is fresher than server, client = " | 1192 LOG(WARNING) << "Cached client feed is fresher than server, client = " |
1166 << local_changestamp | 1193 << local_changestamp |
1167 << ", server = " | 1194 << ", server = " |
1168 << feed->largest_changestamp(); | 1195 << feed->largest_changestamp(); |
(...skipping 13 matching lines...) Expand all Loading... |
1182 | 1209 |
1183 NotifyInitialLoadFinished(); | 1210 NotifyInitialLoadFinished(); |
1184 return; | 1211 return; |
1185 } | 1212 } |
1186 | 1213 |
1187 SaveFeed(feed_data.Pass(), FilePath(kAccountMetadataFile)); | 1214 SaveFeed(feed_data.Pass(), FilePath(kAccountMetadataFile)); |
1188 | 1215 |
1189 // Load changes from the server. | 1216 // Load changes from the server. |
1190 LoadFeedFromServer(local_changestamp > 0 ? local_changestamp + 1 : 0, | 1217 LoadFeedFromServer(local_changestamp > 0 ? local_changestamp + 1 : 0, |
1191 feed->largest_changestamp(), | 1218 feed->largest_changestamp(), |
| 1219 true, /* should_fetch_multiple_feeds */ |
1192 search_file_path, | 1220 search_file_path, |
1193 callback); | 1221 std::string() /* no search query */, |
| 1222 callback, |
| 1223 base::Bind(&GDataFileSystem::OnFeedFromServerLoaded, |
| 1224 ui_weak_ptr_)); |
1194 } | 1225 } |
1195 | 1226 |
1196 void GDataFileSystem::LoadFeedFromServer( | 1227 void GDataFileSystem::LoadFeedFromServer( |
1197 int start_changestamp, | 1228 int start_changestamp, |
1198 int root_feed_changestamp, | 1229 int root_feed_changestamp, |
| 1230 bool should_fetch_multiple_feeds, |
1199 const FilePath& search_file_path, | 1231 const FilePath& search_file_path, |
1200 const FindEntryCallback& callback) { | 1232 const std::string& search_query, |
| 1233 const FindEntryCallback& entry_found_callback, |
| 1234 const LoadDocumentFeedCallback& feed_load_callback) { |
1201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1202 | 1236 |
1203 // ...then also kick off document feed fetching from the server as well. | 1237 // ...then also kick off document feed fetching from the server as well. |
1204 // |feed_list| will contain the list of all collected feed updates that | 1238 // |feed_list| will contain the list of all collected feed updates that |
1205 // we will receive through calls of DocumentsService::GetDocuments(). | 1239 // we will receive through calls of DocumentsService::GetDocuments(). |
1206 scoped_ptr<std::vector<DocumentFeed*> > feed_list( | 1240 scoped_ptr<std::vector<DocumentFeed*> > feed_list( |
1207 new std::vector<DocumentFeed*>); | 1241 new std::vector<DocumentFeed*>); |
1208 // Kick off document feed fetching here if we don't have complete data | 1242 // Kick off document feed fetching here if we don't have complete data |
1209 // to finish this call. | 1243 // to finish this call. |
1210 documents_service_->GetDocuments( | 1244 documents_service_->GetDocuments( |
1211 GURL(), // root feed start. | 1245 GURL(), // root feed start. |
1212 start_changestamp, | 1246 start_changestamp, |
| 1247 search_query, |
1213 base::Bind(&GDataFileSystem::OnGetDocuments, | 1248 base::Bind(&GDataFileSystem::OnGetDocuments, |
1214 ui_weak_ptr_, | 1249 ui_weak_ptr_, |
| 1250 feed_load_callback, |
1215 base::Owned(new GetDocumentsParams(start_changestamp, | 1251 base::Owned(new GetDocumentsParams(start_changestamp, |
1216 root_feed_changestamp, | 1252 root_feed_changestamp, |
1217 feed_list.release(), | 1253 feed_list.release(), |
| 1254 should_fetch_multiple_feeds, |
1218 search_file_path, | 1255 search_file_path, |
1219 callback)))); | 1256 search_query, |
| 1257 entry_found_callback)))); |
| 1258 } |
| 1259 |
| 1260 void GDataFileSystem::OnFeedFromServerLoaded(GetDocumentsParams* params, |
| 1261 base::PlatformFileError error) { |
| 1262 if (error != base::PLATFORM_FILE_OK) { |
| 1263 params->callback.Run(error, FilePath(), |
| 1264 reinterpret_cast<GDataEntry*>(NULL)); |
| 1265 return; |
| 1266 } |
| 1267 |
| 1268 error = UpdateFromFeed(*params->feed_list, |
| 1269 FROM_SERVER, |
| 1270 params->start_changestamp, |
| 1271 params->root_feed_changestamp); |
| 1272 |
| 1273 if (error != base::PLATFORM_FILE_OK) { |
| 1274 if (!params->callback.is_null()) { |
| 1275 params->callback.Run(error, FilePath(), |
| 1276 reinterpret_cast<GDataEntry*>(NULL)); |
| 1277 } |
| 1278 |
| 1279 return; |
| 1280 } |
| 1281 |
| 1282 // Save file system metadata to disk. |
| 1283 SaveFileSystemAsProto(); |
| 1284 |
| 1285 // If we had someone to report this too, then this retrieval was done in a |
| 1286 // context of search... so continue search. |
| 1287 if (!params->callback.is_null()) { |
| 1288 FindEntryByPathSyncOnUIThread(params->search_file_path, params->callback); |
| 1289 } |
1220 } | 1290 } |
1221 | 1291 |
1222 void GDataFileSystem::TransferFile(const FilePath& local_file_path, | 1292 void GDataFileSystem::TransferFile(const FilePath& local_file_path, |
1223 const FilePath& remote_dest_file_path, | 1293 const FilePath& remote_dest_file_path, |
1224 const FileOperationCallback& callback) { | 1294 const FileOperationCallback& callback) { |
1225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1295 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1226 | 1296 |
1227 base::AutoLock lock(lock_); | 1297 base::AutoLock lock(lock_); |
1228 // Make sure the destination directory exists | 1298 // Make sure the destination directory exists |
1229 GDataEntry* dest_dir = GetGDataEntryByPath( | 1299 GDataEntry* dest_dir = GetGDataEntryByPath( |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1370 base::Bind(&RelayFileOperationCallback, | 1440 base::Bind(&RelayFileOperationCallback, |
1371 base::MessageLoopProxy::current(), | 1441 base::MessageLoopProxy::current(), |
1372 callback))); | 1442 callback))); |
1373 DCHECK(posted); | 1443 DCHECK(posted); |
1374 return; | 1444 return; |
1375 } | 1445 } |
1376 | 1446 |
1377 CopyOnUIThread(src_file_path, dest_file_path, callback); | 1447 CopyOnUIThread(src_file_path, dest_file_path, callback); |
1378 } | 1448 } |
1379 | 1449 |
1380 void GDataFileSystem::CopyOnUIThread(const FilePath& src_file_path, | 1450 void GDataFileSystem::CopyOnUIThread(const FilePath& original_src_file_path, |
1381 const FilePath& dest_file_path, | 1451 const FilePath& original_dest_file_path, |
1382 const FileOperationCallback& callback) { | 1452 const FileOperationCallback& callback) { |
1383 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1453 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1384 | 1454 |
1385 base::PlatformFileError error = base::PLATFORM_FILE_OK; | 1455 base::PlatformFileError error = base::PLATFORM_FILE_OK; |
1386 FilePath dest_parent_path = dest_file_path.DirName(); | 1456 FilePath dest_parent_path = original_dest_file_path.DirName(); |
| 1457 |
| 1458 FilePath src_file_path; |
| 1459 FilePath dest_file_path; |
1387 | 1460 |
1388 std::string src_file_resource_id; | 1461 std::string src_file_resource_id; |
1389 bool src_file_is_hosted_document = false; | 1462 bool src_file_is_hosted_document = false; |
1390 { | 1463 { |
1391 base::AutoLock lock(lock_); | 1464 base::AutoLock lock(lock_); |
1392 GDataEntry* src_entry = GetGDataEntryByPath(src_file_path); | 1465 GDataEntry* src_entry = GetGDataEntryByPath(original_src_file_path); |
1393 GDataEntry* dest_parent = GetGDataEntryByPath(dest_parent_path); | 1466 GDataEntry* dest_parent = GetGDataEntryByPath(dest_parent_path); |
1394 if (!src_entry || !dest_parent) { | 1467 if (!src_entry || !dest_parent) { |
1395 error = base::PLATFORM_FILE_ERROR_NOT_FOUND; | 1468 error = base::PLATFORM_FILE_ERROR_NOT_FOUND; |
1396 } else if (!dest_parent->AsGDataDirectory()) { | 1469 } else if (!dest_parent->AsGDataDirectory()) { |
1397 error = base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; | 1470 error = base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; |
1398 } else if (!src_entry->AsGDataFile()) { | 1471 } else if (!src_entry->AsGDataFile() || dest_parent->is_detached()) { |
1399 // TODO(benchan): Implement copy for directories. In the interim, | 1472 // TODO(benchan): Implement copy for directories. In the interim, |
1400 // we handle recursive directory copy in the file manager. | 1473 // we handle recursive directory copy in the file manager. |
1401 error = base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | 1474 error = base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
1402 } else { | 1475 } else { |
1403 src_file_resource_id = src_entry->resource_id(); | 1476 src_file_resource_id = src_entry->resource_id(); |
1404 src_file_is_hosted_document = | 1477 src_file_is_hosted_document = |
1405 src_entry->AsGDataFile()->is_hosted_document(); | 1478 src_entry->AsGDataFile()->is_hosted_document(); |
| 1479 // |original_src_file_path| and |original_dest_file_path| don't have to |
| 1480 // necessary be equal to |src_entry|'s or |dest_entry|'s file path (e.g. |
| 1481 // paths used to display gdata content search results). |
| 1482 // That's why, instead of using |original_src_file_path| and |
| 1483 // |original_dest_file_path|, we will get file paths to use in copy |
| 1484 // operation from the entries. |
| 1485 src_file_path = src_entry->GetFilePath(); |
| 1486 dest_parent_path = dest_parent->GetFilePath(); |
| 1487 dest_file_path = dest_parent_path.Append( |
| 1488 original_dest_file_path.BaseName()); |
1406 } | 1489 } |
1407 } | 1490 } |
1408 | 1491 |
1409 if (error != base::PLATFORM_FILE_OK) { | 1492 if (error != base::PLATFORM_FILE_OK) { |
1410 if (!callback.is_null()) | 1493 if (!callback.is_null()) |
1411 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, error)); | 1494 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, error)); |
1412 | 1495 |
1413 return; | 1496 return; |
1414 } | 1497 } |
1415 | 1498 |
| 1499 DCHECK(!src_file_path.empty()); |
| 1500 DCHECK(!dest_file_path.empty()); |
| 1501 |
1416 if (src_file_is_hosted_document) { | 1502 if (src_file_is_hosted_document) { |
1417 CopyDocumentToDirectory(dest_parent_path, | 1503 CopyDocumentToDirectory(dest_parent_path, |
1418 src_file_resource_id, | 1504 src_file_resource_id, |
1419 // Drop the document extension, which should not be | 1505 // Drop the document extension, which should not be |
1420 // in the document title. | 1506 // in the document title. |
1421 dest_file_path.BaseName().RemoveExtension().value(), | 1507 dest_file_path.BaseName().RemoveExtension().value(), |
1422 callback); | 1508 callback); |
1423 return; | 1509 return; |
1424 } | 1510 } |
1425 | 1511 |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1546 base::Bind(&RelayFileOperationCallback, | 1632 base::Bind(&RelayFileOperationCallback, |
1547 base::MessageLoopProxy::current(), | 1633 base::MessageLoopProxy::current(), |
1548 callback))); | 1634 callback))); |
1549 DCHECK(posted); | 1635 DCHECK(posted); |
1550 return; | 1636 return; |
1551 } | 1637 } |
1552 | 1638 |
1553 MoveOnUIThread(src_file_path, dest_file_path, callback); | 1639 MoveOnUIThread(src_file_path, dest_file_path, callback); |
1554 } | 1640 } |
1555 | 1641 |
1556 void GDataFileSystem::MoveOnUIThread(const FilePath& src_file_path, | 1642 void GDataFileSystem::MoveOnUIThread(const FilePath& original_src_file_path, |
1557 const FilePath& dest_file_path, | 1643 const FilePath& original_dest_file_path, |
1558 const FileOperationCallback& callback) { | 1644 const FileOperationCallback& callback) { |
1559 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1645 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1560 | 1646 |
1561 base::PlatformFileError error = base::PLATFORM_FILE_OK; | 1647 base::PlatformFileError error = base::PLATFORM_FILE_OK; |
1562 FilePath dest_parent_path = dest_file_path.DirName(); | 1648 FilePath dest_parent_path = original_dest_file_path.DirName(); |
| 1649 |
| 1650 FilePath src_file_path; |
| 1651 FilePath dest_file_path; |
| 1652 FilePath dest_name = original_dest_file_path.BaseName(); |
1563 | 1653 |
1564 { | 1654 { |
1565 // This scoped lock needs to be released before calling Rename() below. | 1655 // This scoped lock needs to be released before calling Rename() below. |
1566 base::AutoLock lock(lock_); | 1656 base::AutoLock lock(lock_); |
1567 GDataEntry* src_entry = GetGDataEntryByPath(src_file_path); | 1657 GDataEntry* src_entry = GetGDataEntryByPath(original_src_file_path); |
1568 GDataEntry* dest_parent = GetGDataEntryByPath(dest_parent_path); | 1658 GDataEntry* dest_parent = GetGDataEntryByPath(dest_parent_path); |
1569 if (!src_entry || !dest_parent) { | 1659 if (!src_entry || !dest_parent) { |
1570 error = base::PLATFORM_FILE_ERROR_NOT_FOUND; | 1660 error = base::PLATFORM_FILE_ERROR_NOT_FOUND; |
1571 } else { | 1661 } else if (!dest_parent->AsGDataDirectory()) { |
1572 if (!dest_parent->AsGDataDirectory()) | |
1573 error = base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; | 1662 error = base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; |
| 1663 } else if (dest_parent->is_detached()) { |
| 1664 // We allow moving to a directory without file system root only if it's |
| 1665 // done as part of renaming (i.e. source and destination parent paths are |
| 1666 // the same). |
| 1667 if (original_src_file_path.DirName() != dest_parent_path) { |
| 1668 error = base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
| 1669 } else { |
| 1670 // If we are indeed renaming, we have to strip resource id from the file |
| 1671 // name. |
| 1672 std::string resource_id; |
| 1673 std::string file_name; |
| 1674 util::ParseSearchFileName(dest_name.value(), &resource_id, &file_name); |
| 1675 if (!file_name.empty()) |
| 1676 dest_name = FilePath(file_name); |
| 1677 } |
1574 } | 1678 } |
1575 | 1679 |
1576 if (error != base::PLATFORM_FILE_OK) { | 1680 if (error != base::PLATFORM_FILE_OK) { |
1577 if (!callback.is_null()) { | 1681 if (!callback.is_null()) { |
1578 MessageLoop::current()->PostTask(FROM_HERE, | 1682 MessageLoop::current()->PostTask(FROM_HERE, |
1579 base::Bind(callback, error)); | 1683 base::Bind(callback, error)); |
1580 } | 1684 } |
1581 return; | 1685 return; |
1582 } | 1686 } |
| 1687 // |original_src_file_path| and |original_dest_file_path| don't have to |
| 1688 // necessary be equal to |src_entry|'s or |dest_entry|'s file path (e.g. |
| 1689 // paths used to display gdata content search results). |
| 1690 // That's why, instead of using |original_src_file_path| and |
| 1691 // |original_dest_file_path|, we will get file paths to use in move |
| 1692 // operation from the entries. |
| 1693 src_file_path = src_entry->GetFilePath(); |
| 1694 if (!dest_parent->is_detached()) |
| 1695 dest_parent_path = dest_parent->GetFilePath(); |
| 1696 dest_file_path = dest_parent_path.Append(dest_name); |
1583 } | 1697 } |
1584 | 1698 |
| 1699 DCHECK(!src_file_path.empty()); |
| 1700 DCHECK(!dest_file_path.empty()); |
| 1701 |
1585 // If the file/directory is moved to the same directory, just rename it. | 1702 // If the file/directory is moved to the same directory, just rename it. |
1586 if (src_file_path.DirName() == dest_parent_path) { | 1703 if (original_src_file_path.DirName() == dest_parent_path) { |
1587 FilePathUpdateCallback final_file_path_update_callback = | 1704 FilePathUpdateCallback final_file_path_update_callback = |
1588 base::Bind(&GDataFileSystem::OnFilePathUpdated, | 1705 base::Bind(&GDataFileSystem::OnFilePathUpdated, |
1589 ui_weak_ptr_, | 1706 ui_weak_ptr_, |
1590 callback); | 1707 callback); |
1591 | 1708 |
1592 Rename(src_file_path, dest_file_path.BaseName().value(), | 1709 Rename(original_src_file_path, dest_name.value(), |
1593 final_file_path_update_callback); | 1710 final_file_path_update_callback); |
1594 return; | 1711 return; |
1595 } | 1712 } |
1596 | 1713 |
1597 // Otherwise, the move operation involves three steps: | 1714 // Otherwise, the move operation involves three steps: |
1598 // 1. Renames the file at |src_file_path| to basename(|dest_file_path|) | 1715 // 1. Renames the file at |src_file_path| to basename(|dest_file_path|) |
1599 // within the same directory. The rename operation is a no-op if | 1716 // within the same directory. The rename operation is a no-op if |
1600 // basename(|src_file_path|) equals to basename(|dest_file_path|). | 1717 // basename(|src_file_path|) equals to basename(|dest_file_path|). |
1601 // 2. Removes the file from its parent directory (the file is not deleted), | 1718 // 2. Removes the file from its parent directory (the file is not deleted), |
1602 // which effectively moves the file to the root directory. | 1719 // which effectively moves the file to the root directory. |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1732 base::Bind(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND)); | 1849 base::Bind(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND)); |
1733 } | 1850 } |
1734 return; | 1851 return; |
1735 } | 1852 } |
1736 | 1853 |
1737 documents_service_->DeleteDocument( | 1854 documents_service_->DeleteDocument( |
1738 entry->edit_url(), | 1855 entry->edit_url(), |
1739 base::Bind(&GDataFileSystem::OnRemovedDocument, | 1856 base::Bind(&GDataFileSystem::OnRemovedDocument, |
1740 ui_weak_ptr_, | 1857 ui_weak_ptr_, |
1741 callback, | 1858 callback, |
1742 file_path)); | 1859 entry->GetFilePath())); |
1743 } | 1860 } |
1744 | 1861 |
1745 void GDataFileSystem::CreateDirectory( | 1862 void GDataFileSystem::CreateDirectory( |
1746 const FilePath& directory_path, | 1863 const FilePath& directory_path, |
1747 bool is_exclusive, | 1864 bool is_exclusive, |
1748 bool is_recursive, | 1865 bool is_recursive, |
1749 const FileOperationCallback& callback) { | 1866 const FileOperationCallback& callback) { |
1750 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 1867 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
1751 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 1868 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
1752 const bool posted = BrowserThread::PostTask( | 1869 const bool posted = BrowserThread::PostTask( |
(...skipping 15 matching lines...) Expand all Loading... |
1768 directory_path, is_exclusive, is_recursive, callback); | 1885 directory_path, is_exclusive, is_recursive, callback); |
1769 } | 1886 } |
1770 | 1887 |
1771 void GDataFileSystem::CreateDirectoryOnUIThread( | 1888 void GDataFileSystem::CreateDirectoryOnUIThread( |
1772 const FilePath& directory_path, | 1889 const FilePath& directory_path, |
1773 bool is_exclusive, | 1890 bool is_exclusive, |
1774 bool is_recursive, | 1891 bool is_recursive, |
1775 const FileOperationCallback& callback) { | 1892 const FileOperationCallback& callback) { |
1776 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1893 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1777 | 1894 |
| 1895 if (!ShouldCreateDirectory(directory_path)) { |
| 1896 if (!callback.is_null()) { |
| 1897 MessageLoop::current()->PostTask(FROM_HERE, |
| 1898 base::Bind(callback, base::PLATFORM_FILE_ERROR_INVALID_OPERATION)); |
| 1899 } |
| 1900 return; |
| 1901 } |
| 1902 |
1778 FilePath last_parent_dir_path; | 1903 FilePath last_parent_dir_path; |
1779 FilePath first_missing_path; | 1904 FilePath first_missing_path; |
1780 GURL last_parent_dir_url; | 1905 GURL last_parent_dir_url; |
1781 FindMissingDirectoryResult result = | 1906 FindMissingDirectoryResult result = |
1782 FindFirstMissingParentDirectory(directory_path, | 1907 FindFirstMissingParentDirectory(directory_path, |
1783 &last_parent_dir_url, | 1908 &last_parent_dir_url, |
1784 &first_missing_path); | 1909 &first_missing_path); |
1785 switch (result) { | 1910 switch (result) { |
1786 case FOUND_INVALID: { | 1911 case FOUND_INVALID: { |
1787 if (!callback.is_null()) { | 1912 if (!callback.is_null()) { |
(...skipping 894 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2682 params.callback); | 2807 params.callback); |
2683 return; | 2808 return; |
2684 } | 2809 } |
2685 | 2810 |
2686 if (!params.callback.is_null()) { | 2811 if (!params.callback.is_null()) { |
2687 // Finally done with the create request. | 2812 // Finally done with the create request. |
2688 params.callback.Run(base::PLATFORM_FILE_OK); | 2813 params.callback.Run(base::PLATFORM_FILE_OK); |
2689 } | 2814 } |
2690 } | 2815 } |
2691 | 2816 |
2692 void GDataFileSystem::OnGetDocuments(GetDocumentsParams* params, | 2817 void GDataFileSystem::OnSearch(const ReadDirectoryCallback& callback, |
| 2818 GetDocumentsParams* params, |
| 2819 base::PlatformFileError error) { |
| 2820 // The search results will be returned using virtual directory. |
| 2821 // The directory is not really part of the file system, so it has no parent or |
| 2822 // root. |
| 2823 scoped_ptr<GDataDirectory> search_dir(new GDataDirectory(NULL, NULL)); |
| 2824 |
| 2825 base::AutoLock lock(lock_); |
| 2826 |
| 2827 int delta_feed_changestamp = 0; |
| 2828 int num_regular_files = 0; |
| 2829 int num_hosted_documents = 0; |
| 2830 FileResourceIdMap file_map; |
| 2831 if (error == base::PLATFORM_FILE_OK) { |
| 2832 error = FeedToFileResourceMap(*params->feed_list, |
| 2833 &file_map, |
| 2834 &delta_feed_changestamp, |
| 2835 &num_regular_files, |
| 2836 &num_hosted_documents); |
| 2837 } |
| 2838 |
| 2839 if (error == base::PLATFORM_FILE_OK) { |
| 2840 std::set<FilePath> ignored; |
| 2841 |
| 2842 // Go through all entires generated by the feed and add them to the search |
| 2843 // result directory. |
| 2844 for (FileResourceIdMap::const_iterator it = file_map.begin(); |
| 2845 it != file_map.end(); ++it) { |
| 2846 scoped_ptr<GDataEntry> entry(it->second); |
| 2847 DCHECK_EQ(it->first, entry->resource_id()); |
| 2848 DCHECK(!entry->is_deleted()); |
| 2849 |
| 2850 entry->set_title(entry->resource_id() + "." + entry->title()); |
| 2851 |
| 2852 search_dir->AddEntry(entry.release()); |
| 2853 } |
| 2854 } |
| 2855 |
| 2856 scoped_ptr<GDataDirectoryProto> directory_proto(new GDataDirectoryProto); |
| 2857 search_dir->ToProto(directory_proto.get()); |
| 2858 |
| 2859 if (!callback.is_null()) { |
| 2860 callback.Run(error, directory_proto.Pass()); |
| 2861 } |
| 2862 } |
| 2863 |
| 2864 void GDataFileSystem::SearchAsync(const std::string& search_query, |
| 2865 const ReadDirectoryCallback& callback) { |
| 2866 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 2867 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 2868 const bool posted = BrowserThread::PostTask( |
| 2869 BrowserThread::UI, |
| 2870 FROM_HERE, |
| 2871 base::Bind(&GDataFileSystem::SearchAsyncOnUIThread, |
| 2872 ui_weak_ptr_, |
| 2873 search_query, |
| 2874 base::Bind(&RelayReadDirectoryCallback, |
| 2875 base::MessageLoopProxy::current(), |
| 2876 callback))); |
| 2877 DCHECK(posted); |
| 2878 return; |
| 2879 } |
| 2880 |
| 2881 SearchAsyncOnUIThread(search_query, callback); |
| 2882 } |
| 2883 |
| 2884 void GDataFileSystem::SearchAsyncOnUIThread( |
| 2885 const std::string& search_query, |
| 2886 const ReadDirectoryCallback& callback) { |
| 2887 scoped_ptr<std::vector<DocumentFeed*> > feed_list( |
| 2888 new std::vector<DocumentFeed*>); |
| 2889 |
| 2890 LoadFeedFromServer(0, 0, // We don't use change stamps when fetching search |
| 2891 // data; we always fetch the whole result feed. |
| 2892 false, // Stop fetching search results after first feed |
| 2893 // chunk to avoid displaying huge number of search |
| 2894 // results (especially since we don't cache them). |
| 2895 FilePath(), // Not used. |
| 2896 search_query, |
| 2897 FindEntryCallback(), // Not used. |
| 2898 base::Bind(&GDataFileSystem::OnSearch, |
| 2899 ui_weak_ptr_, callback)); |
| 2900 } |
| 2901 |
| 2902 void GDataFileSystem::OnGetDocuments(const LoadDocumentFeedCallback& callback, |
| 2903 GetDocumentsParams* params, |
2693 GDataErrorCode status, | 2904 GDataErrorCode status, |
2694 scoped_ptr<base::Value> data) { | 2905 scoped_ptr<base::Value> data) { |
2695 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 2906 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
2696 | 2907 |
2697 base::PlatformFileError error = GDataToPlatformError(status); | 2908 base::PlatformFileError error = GDataToPlatformError(status); |
2698 if (error == base::PLATFORM_FILE_OK && | 2909 if (error == base::PLATFORM_FILE_OK && |
2699 (!data.get() || data->GetType() != Value::TYPE_DICTIONARY)) { | 2910 (!data.get() || data->GetType() != Value::TYPE_DICTIONARY)) { |
2700 LOG(WARNING) << "No feed content!"; | |
2701 error = base::PLATFORM_FILE_ERROR_FAILED; | 2911 error = base::PLATFORM_FILE_ERROR_FAILED; |
2702 } | 2912 } |
2703 | 2913 |
2704 if (error != base::PLATFORM_FILE_OK) { | 2914 if (error != base::PLATFORM_FILE_OK) { |
2705 if (!params->callback.is_null()) { | 2915 if (!callback.is_null()) { |
2706 params->callback.Run(error, FilePath(), | 2916 callback.Run(params, error); |
2707 reinterpret_cast<GDataEntry*>(NULL)); | |
2708 } | 2917 } |
2709 | 2918 |
2710 return; | 2919 return; |
2711 } | 2920 } |
2712 | 2921 |
2713 // TODO(zelidrag): Find a faster way to get next url rather than parsing | 2922 // TODO(zelidrag): Find a faster way to get next url rather than parsing |
2714 // the entire feed. | 2923 // the entire feed. |
2715 GURL next_feed_url; | 2924 GURL next_feed_url; |
2716 scoped_ptr<DocumentFeed> current_feed(DocumentFeed::ExtractAndParse(*data)); | 2925 scoped_ptr<DocumentFeed> current_feed(DocumentFeed::ExtractAndParse(*data)); |
2717 if (!current_feed.get()) { | 2926 if (!current_feed.get()) { |
2718 if (!params->callback.is_null()) { | 2927 if (!callback.is_null()) { |
2719 params->callback.Run(base::PLATFORM_FILE_ERROR_FAILED, FilePath(), | 2928 callback.Run(params, base::PLATFORM_FILE_ERROR_FAILED); |
2720 reinterpret_cast<GDataEntry*>(NULL)); | |
2721 } | 2929 } |
2722 | 2930 |
2723 return; | 2931 return; |
2724 } | 2932 } |
2725 const bool has_next_feed_url = current_feed->GetNextFeedURL(&next_feed_url); | 2933 const bool has_next_feed_url = current_feed->GetNextFeedURL(&next_feed_url); |
2726 | 2934 |
2727 // Add the current feed to the list of collected feeds for this directory. | 2935 // Add the current feed to the list of collected feeds for this directory. |
2728 params->feed_list->push_back(current_feed.release()); | 2936 params->feed_list->push_back(current_feed.release()); |
2729 | 2937 |
2730 // Check if we need to collect more data to complete the directory list. | 2938 // Check if we need to collect more data to complete the directory list. |
2731 if (has_next_feed_url && !next_feed_url.is_empty()) { | 2939 if (params->should_fetch_multiple_feeds && has_next_feed_url && |
| 2940 !next_feed_url.is_empty()) { |
2732 // Kick of the remaining part of the feeds. | 2941 // Kick of the remaining part of the feeds. |
2733 documents_service_->GetDocuments( | 2942 documents_service_->GetDocuments( |
2734 next_feed_url, | 2943 next_feed_url, |
2735 params->start_changestamp, | 2944 params->start_changestamp, |
| 2945 params->search_query, |
2736 base::Bind(&GDataFileSystem::OnGetDocuments, | 2946 base::Bind(&GDataFileSystem::OnGetDocuments, |
2737 ui_weak_ptr_, | 2947 ui_weak_ptr_, |
| 2948 callback, |
2738 base::Owned( | 2949 base::Owned( |
2739 new GetDocumentsParams(params->start_changestamp, | 2950 new GetDocumentsParams( |
2740 params->root_feed_changestamp, | 2951 params->start_changestamp, |
2741 params->feed_list.release(), | 2952 params->root_feed_changestamp, |
2742 params->search_file_path, | 2953 params->feed_list.release(), |
2743 params->callback)))); | 2954 params->should_fetch_multiple_feeds, |
| 2955 params->search_file_path, |
| 2956 params->search_query, |
| 2957 params->callback)))); |
2744 return; | 2958 return; |
2745 } | 2959 } |
2746 | 2960 |
2747 error = UpdateFromFeed(*params->feed_list, | 2961 if (!callback.is_null()) |
2748 FROM_SERVER, | 2962 callback.Run(params, error); |
2749 params->start_changestamp, | |
2750 params->root_feed_changestamp); | |
2751 | |
2752 if (error != base::PLATFORM_FILE_OK) { | |
2753 if (!params->callback.is_null()) { | |
2754 params->callback.Run(error, FilePath(), | |
2755 reinterpret_cast<GDataEntry*>(NULL)); | |
2756 } | |
2757 | |
2758 return; | |
2759 } | |
2760 | |
2761 // Save file system metadata to disk. | |
2762 SaveFileSystemAsProto(); | |
2763 | |
2764 // If we had someone to report this too, then this retrieval was done in a | |
2765 // context of search... so continue search. | |
2766 if (!params->callback.is_null()) { | |
2767 FindEntryByPathSyncOnUIThread(params->search_file_path, params->callback); | |
2768 } | |
2769 } | 2963 } |
2770 | 2964 |
2771 void GDataFileSystem::LoadRootFeedFromCache( | 2965 void GDataFileSystem::LoadRootFeedFromCache( |
2772 bool should_load_from_server, | 2966 bool should_load_from_server, |
2773 const FilePath& search_file_path, | 2967 const FilePath& search_file_path, |
2774 const FindEntryCallback& callback) { | 2968 const FindEntryCallback& callback) { |
2775 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 2969 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
2776 | 2970 |
2777 const FilePath path = | 2971 const FilePath path = |
2778 GetCacheDirectoryPath(GDataRootDirectory::CACHE_TYPE_META).Append( | 2972 GetCacheDirectoryPath(GDataRootDirectory::CACHE_TYPE_META).Append( |
(...skipping 743 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3522 return base::PLATFORM_FILE_ERROR_FAILED; | 3716 return base::PLATFORM_FILE_ERROR_FAILED; |
3523 | 3717 |
3524 GDataEntry* new_entry = GDataEntry::FromDocumentEntry(parent_dir, | 3718 GDataEntry* new_entry = GDataEntry::FromDocumentEntry(parent_dir, |
3525 doc_entry.get(), | 3719 doc_entry.get(), |
3526 root_.get()); | 3720 root_.get()); |
3527 if (!new_entry) | 3721 if (!new_entry) |
3528 return base::PLATFORM_FILE_ERROR_FAILED; | 3722 return base::PLATFORM_FILE_ERROR_FAILED; |
3529 | 3723 |
3530 parent_dir->AddEntry(new_entry); | 3724 parent_dir->AddEntry(new_entry); |
3531 | 3725 |
3532 NotifyDirectoryChanged(directory_path); | 3726 // |directory_path| is not necessary same as |entry->GetFilePath()|. It may be |
| 3727 // virtual path that references the entry (e.g. path under which content |
| 3728 // search result is shown). |
| 3729 // We want to dispatch directory changed with the actual entry's path. |
| 3730 NotifyDirectoryChanged(entry->GetFilePath()); |
3533 return base::PLATFORM_FILE_OK; | 3731 return base::PLATFORM_FILE_OK; |
3534 } | 3732 } |
3535 | 3733 |
3536 GDataFileSystem::FindMissingDirectoryResult | 3734 GDataFileSystem::FindMissingDirectoryResult |
3537 GDataFileSystem::FindFirstMissingParentDirectory( | 3735 GDataFileSystem::FindFirstMissingParentDirectory( |
3538 const FilePath& directory_path, | 3736 const FilePath& directory_path, |
3539 GURL* last_dir_content_url, | 3737 GURL* last_dir_content_url, |
3540 FilePath* first_missing_parent_path) { | 3738 FilePath* first_missing_parent_path) { |
3541 // Let's find which how deep is the existing directory structure and | 3739 // Let's find which how deep is the existing directory structure and |
3542 // get the first element that's missing. | 3740 // get the first element that's missing. |
(...skipping 1247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4790 pref_registrar_->Init(profile_->GetPrefs()); | 4988 pref_registrar_->Init(profile_->GetPrefs()); |
4791 pref_registrar_->Add(prefs::kDisableGDataHostedFiles, this); | 4989 pref_registrar_->Add(prefs::kDisableGDataHostedFiles, this); |
4792 } | 4990 } |
4793 | 4991 |
4794 void SetFreeDiskSpaceGetterForTesting(FreeDiskSpaceGetterInterface* getter) { | 4992 void SetFreeDiskSpaceGetterForTesting(FreeDiskSpaceGetterInterface* getter) { |
4795 delete global_free_disk_getter_for_testing; // Safe to delete NULL; | 4993 delete global_free_disk_getter_for_testing; // Safe to delete NULL; |
4796 global_free_disk_getter_for_testing = getter; | 4994 global_free_disk_getter_for_testing = getter; |
4797 } | 4995 } |
4798 | 4996 |
4799 } // namespace gdata | 4997 } // namespace gdata |
OLD | NEW |