| 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 |