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

Side by Side Diff: chrome/browser/chromeos/gdata/gdata_file_system.cc

Issue 10829118: gdata: Move GDataWapiFeedParser to a set of new files (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix clang build for sure... Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 <set> 7 #include <set>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 return GDATA_FILE_ERROR_ABORT; 130 return GDATA_FILE_ERROR_ABORT;
131 case GDATA_NO_CONNECTION: 131 case GDATA_NO_CONNECTION:
132 return GDATA_FILE_ERROR_NO_CONNECTION; 132 return GDATA_FILE_ERROR_NO_CONNECTION;
133 default: 133 default:
134 return GDATA_FILE_ERROR_FAILED; 134 return GDATA_FILE_ERROR_FAILED;
135 } 135 }
136 } 136 }
137 137
138 //================================ Helper functions ============================ 138 //================================ Helper functions ============================
139 139
140 // Recursively extracts the paths set of all sub-directories of |entry|.
141 void GetChildDirectoryPaths(GDataEntry* entry,
142 std::set<FilePath>* changed_dirs) {
143 GDataDirectory* dir = entry->AsGDataDirectory();
144 if (!dir)
145 return;
146
147 for (GDataDirectoryCollection::const_iterator it =
148 dir->child_directories().begin();
149 it != dir->child_directories().end(); ++it) {
150 GDataDirectory* child_dir = it->second;
151 changed_dirs->insert(child_dir->GetFilePath());
152 GetChildDirectoryPaths(child_dir, changed_dirs);
153 }
154 }
155
156
157 // Invoked upon completion of TransferRegularFile initiated by Copy. 140 // Invoked upon completion of TransferRegularFile initiated by Copy.
158 // 141 //
159 // |callback| is run on the thread represented by |relay_proxy|. 142 // |callback| is run on the thread represented by |relay_proxy|.
160 void OnTransferRegularFileCompleteForCopy( 143 void OnTransferRegularFileCompleteForCopy(
161 const FileOperationCallback& callback, 144 const FileOperationCallback& callback,
162 scoped_refptr<base::MessageLoopProxy> relay_proxy, 145 scoped_refptr<base::MessageLoopProxy> relay_proxy,
163 GDataFileError error) { 146 GDataFileError error) {
164 if (!callback.is_null()) 147 if (!callback.is_null())
165 relay_proxy->PostTask(FROM_HERE, base::Bind(callback, error)); 148 relay_proxy->PostTask(FROM_HERE, base::Bind(callback, error));
166 } 149 }
(...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 const GetEntryInfoWithFilePathCallback& callback, 551 const GetEntryInfoWithFilePathCallback& callback,
569 const FilePath& path, 552 const FilePath& path,
570 GDataFileError error, 553 GDataFileError error,
571 scoped_ptr<GDataEntryProto> entry_proto) { 554 scoped_ptr<GDataEntryProto> entry_proto) {
572 if (!callback.is_null()) 555 if (!callback.is_null())
573 callback.Run(error, path, entry_proto.Pass()); 556 callback.Run(error, path, entry_proto.Pass());
574 } 557 }
575 558
576 } // namespace 559 } // namespace
577 560
578 // Struct used to record UMA stats with FeedToFileResourceMap().
579 //
580 // TODO(satorux): Move this to a new file. crbug.com/130669
581 struct FeedToFileResourceMapUmaStats {
582 FeedToFileResourceMapUmaStats()
583 : num_regular_files(0),
584 num_hosted_documents(0) {}
585
586 typedef std::map<DocumentEntry::EntryKind, int> EntryKindToCountMap;
587 int num_regular_files;
588 int num_hosted_documents;
589 EntryKindToCountMap num_files_with_entry_kind;
590 };
591
592 // GDataWapiFeedProcessor is used to process feeds from WAPI (codename for
593 // Documents List API).
594 //
595 // TODO(satorux): Move this into a new file. crbug.com/130669
596 class GDataWapiFeedProcessor {
597 public:
598 explicit GDataWapiFeedProcessor(GDataDirectoryService* directory_service)
599 : directory_service_(directory_service) {
600 }
601
602 // Applies the documents feeds to the file system using |directory_service_|.
603 //
604 // |start_changestamp| determines the type of feed to process. The value is
605 // set to zero for the root feeds, every other value is for the delta feeds.
606 //
607 // In the case of processing the root feeds |root_feed_changestamp| is used
608 // as its initial changestamp value. The value comes from
609 // AccountMetadataFeed.
610 GDataFileError ApplyFeeds(const std::vector<DocumentFeed*>& feed_list,
611 int start_changestamp,
612 int root_feed_changestamp,
613 std::set<FilePath>* changed_dirs);
614
615 // Converts list of document feeds from collected feeds into
616 // FileResourceIdMap.
617 GDataFileError FeedToFileResourceMap(
618 const std::vector<DocumentFeed*>& feed_list,
619 FileResourceIdMap* file_map,
620 int* feed_changestamp,
621 FeedToFileResourceMapUmaStats* uma_stats);
622
623 private:
624 // Updates UMA histograms about file counts.
625 void UpdateFileCountUmaHistograms(
626 const FeedToFileResourceMapUmaStats& uma_stats) const;
627
628 // Applies the pre-processed feed from |file_map| map onto the file system.
629 // All entries in |file_map| will be erased (i.e. the map becomes empty),
630 // and values are deleted.
631 void ApplyFeedFromFileUrlMap(bool is_delta_feed,
632 int feed_changestamp,
633 FileResourceIdMap* file_map,
634 std::set<FilePath>* changed_dirs);
635
636 // Helper function for adding new |file| from the feed into |directory|. It
637 // checks the type of file and updates |changed_dirs| if this file adding
638 // operation needs to raise directory notification update. If file is being
639 // added to |orphaned_dir_service| such notifications are not raised since
640 // we ignore such files and don't add them to the file system now.
641 static void AddEntryToDirectoryAndCollectChangedDirectories(
642 GDataEntry* entry,
643 GDataDirectory* directory,
644 GDataDirectoryService* orphaned_dir_service,
645 std::set<FilePath>* changed_dirs);
646
647 // Helper function for removing |entry| from |directory|. If |entry| is a
648 // directory too, it will collect all its children file paths into
649 // |changed_dirs| as well.
650 static void RemoveEntryFromDirectoryAndCollectChangedDirectories(
651 GDataDirectory* directory,
652 GDataEntry* entry,
653 std::set<FilePath>* changed_dirs);
654
655 // Finds directory where new |file| should be added to during feed processing.
656 // |orphaned_entries_dir| collects files/dirs that don't have a parent in
657 // either locally cached file system or in this new feed.
658 GDataDirectory* FindDirectoryForNewEntry(
659 GDataEntry* new_entry,
660 const FileResourceIdMap& file_map,
661 GDataDirectoryService* orphaned_dir_service);
662
663 GDataDirectoryService* directory_service_;
664 DISALLOW_COPY_AND_ASSIGN(GDataWapiFeedProcessor);
665 };
666
667 // GDataFileSystem::GetDocumentsParams struct implementation. 561 // GDataFileSystem::GetDocumentsParams struct implementation.
668 struct GDataFileSystem::GetDocumentsParams { 562 struct GDataFileSystem::GetDocumentsParams {
669 GetDocumentsParams(int start_changestamp, 563 GetDocumentsParams(int start_changestamp,
670 int root_feed_changestamp, 564 int root_feed_changestamp,
671 std::vector<DocumentFeed*>* feed_list, 565 std::vector<DocumentFeed*>* feed_list,
672 bool should_fetch_multiple_feeds, 566 bool should_fetch_multiple_feeds,
673 const FilePath& search_file_path, 567 const FilePath& search_file_path,
674 const std::string& search_query, 568 const std::string& search_query,
675 const std::string& directory_resource_id, 569 const std::string& directory_resource_id,
676 const FindEntryCallback& callback); 570 const FindEntryCallback& callback);
(...skipping 2707 matching lines...) Expand 10 before | Expand all | Expand 10 after
3384 if (should_notify_directory_changed) { 3278 if (should_notify_directory_changed) {
3385 for (std::set<FilePath>::iterator dir_iter = changed_dirs.begin(); 3279 for (std::set<FilePath>::iterator dir_iter = changed_dirs.begin();
3386 dir_iter != changed_dirs.end(); ++dir_iter) { 3280 dir_iter != changed_dirs.end(); ++dir_iter) {
3387 NotifyDirectoryChanged(*dir_iter); 3281 NotifyDirectoryChanged(*dir_iter);
3388 } 3282 }
3389 } 3283 }
3390 3284
3391 return error; 3285 return error;
3392 } 3286 }
3393 3287
3394 GDataFileError GDataWapiFeedProcessor::ApplyFeeds(
3395 const std::vector<DocumentFeed*>& feed_list,
3396 int start_changestamp,
3397 int root_feed_changestamp,
3398 std::set<FilePath>* changed_dirs) {
3399 bool is_delta_feed = start_changestamp != 0;
3400
3401 directory_service_->set_origin(FROM_SERVER);
3402
3403 int delta_feed_changestamp = 0;
3404 FeedToFileResourceMapUmaStats uma_stats;
3405 FileResourceIdMap file_map;
3406 GDataFileError error = FeedToFileResourceMap(feed_list,
3407 &file_map,
3408 &delta_feed_changestamp,
3409 &uma_stats);
3410 if (error != GDATA_FILE_OK)
3411 return error;
3412
3413 ApplyFeedFromFileUrlMap(
3414 is_delta_feed,
3415 is_delta_feed ? delta_feed_changestamp : root_feed_changestamp,
3416 &file_map,
3417 changed_dirs);
3418
3419 // Shouldn't record histograms when processing delta feeds.
3420 if (!is_delta_feed)
3421 UpdateFileCountUmaHistograms(uma_stats);
3422
3423 return GDATA_FILE_OK;
3424 }
3425
3426 void GDataWapiFeedProcessor::UpdateFileCountUmaHistograms(
3427 const FeedToFileResourceMapUmaStats& uma_stats) const {
3428 const int num_total_files =
3429 uma_stats.num_hosted_documents + uma_stats.num_regular_files;
3430 UMA_HISTOGRAM_COUNTS("GData.NumberOfRegularFiles",
3431 uma_stats.num_regular_files);
3432 UMA_HISTOGRAM_COUNTS("GData.NumberOfHostedDocuments",
3433 uma_stats.num_hosted_documents);
3434 UMA_HISTOGRAM_COUNTS("GData.NumberOfTotalFiles", num_total_files);
3435 const std::vector<int> all_entry_kinds = DocumentEntry::GetAllEntryKinds();
3436 for (FeedToFileResourceMapUmaStats::EntryKindToCountMap::const_iterator iter =
3437 uma_stats.num_files_with_entry_kind.begin();
3438 iter != uma_stats.num_files_with_entry_kind.end();
3439 ++iter) {
3440 const DocumentEntry::EntryKind kind = iter->first;
3441 const int count = iter->second;
3442 for (int i = 0; i < count; ++i) {
3443 UMA_HISTOGRAM_CUSTOM_ENUMERATION(
3444 "GData.EntryKind", kind, all_entry_kinds);
3445 }
3446 }
3447 }
3448
3449 void GDataWapiFeedProcessor::ApplyFeedFromFileUrlMap(
3450 bool is_delta_feed,
3451 int feed_changestamp,
3452 FileResourceIdMap* file_map,
3453 std::set<FilePath>* changed_dirs) {
3454 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3455 DCHECK(changed_dirs);
3456
3457 if (!is_delta_feed) { // Full update.
3458 directory_service_->root()->RemoveChildren();
3459 changed_dirs->insert(directory_service_->root()->GetFilePath());
3460 }
3461 directory_service_->set_largest_changestamp(feed_changestamp);
3462
3463 scoped_ptr<GDataDirectoryService> orphaned_dir_service(
3464 new GDataDirectoryService);
3465 // Go through all entries generated by the feed and apply them to the local
3466 // snapshot of the file system.
3467 for (FileResourceIdMap::iterator it = file_map->begin();
3468 it != file_map->end();) {
3469 // Ensure that the entry is deleted, unless the ownership is explicitly
3470 // transferred by entry.release().
3471 scoped_ptr<GDataEntry> entry(it->second);
3472 DCHECK_EQ(it->first, entry->resource_id());
3473 // Erase the entry so the deleted entry won't be referenced.
3474 file_map->erase(it++);
3475
3476 GDataEntry* old_entry =
3477 directory_service_->GetEntryByResourceId(entry->resource_id());
3478 GDataDirectory* dest_dir = NULL;
3479 if (entry->is_deleted()) { // Deleted file/directory.
3480 DVLOG(1) << "Removing file " << entry->base_name();
3481 if (!old_entry)
3482 continue;
3483
3484 dest_dir = old_entry->parent();
3485 if (!dest_dir) {
3486 NOTREACHED();
3487 continue;
3488 }
3489 RemoveEntryFromDirectoryAndCollectChangedDirectories(
3490 dest_dir, old_entry, changed_dirs);
3491 } else if (old_entry) { // Change or move of existing entry.
3492 // Please note that entry rename is just a special case of change here
3493 // since name is just one of the properties that can change.
3494 DVLOG(1) << "Changed file " << entry->base_name();
3495 dest_dir = old_entry->parent();
3496 if (!dest_dir) {
3497 NOTREACHED();
3498 continue;
3499 }
3500 // Move children files over if we are dealing with directories.
3501 if (old_entry->AsGDataDirectory() && entry->AsGDataDirectory()) {
3502 entry->AsGDataDirectory()->TakeOverEntries(
3503 old_entry->AsGDataDirectory());
3504 }
3505 // Remove the old instance of this entry.
3506 RemoveEntryFromDirectoryAndCollectChangedDirectories(
3507 dest_dir, old_entry, changed_dirs);
3508 // Did we actually move the new file to another directory?
3509 if (dest_dir->resource_id() != entry->parent_resource_id()) {
3510 changed_dirs->insert(dest_dir->GetFilePath());
3511 dest_dir = FindDirectoryForNewEntry(entry.get(),
3512 *file_map,
3513 orphaned_dir_service.get());
3514 }
3515 DCHECK(dest_dir);
3516 AddEntryToDirectoryAndCollectChangedDirectories(
3517 entry.release(),
3518 dest_dir,
3519 orphaned_dir_service.get(),
3520 changed_dirs);
3521 } else { // Adding a new file.
3522 dest_dir = FindDirectoryForNewEntry(entry.get(),
3523 *file_map,
3524 orphaned_dir_service.get());
3525 DCHECK(dest_dir);
3526 AddEntryToDirectoryAndCollectChangedDirectories(
3527 entry.release(),
3528 dest_dir,
3529 orphaned_dir_service.get(),
3530 changed_dirs);
3531 }
3532
3533 // Record changed directory if this was a delta feed and the parent
3534 // directory is already properly rooted within its parent.
3535 if (dest_dir && (dest_dir->parent() ||
3536 dest_dir == directory_service_->root()) &&
3537 dest_dir != orphaned_dir_service->root() && is_delta_feed) {
3538 changed_dirs->insert(dest_dir->GetFilePath());
3539 }
3540 }
3541 // All entry must be erased from the map.
3542 DCHECK(file_map->empty());
3543 }
3544
3545 // static
3546 void GDataWapiFeedProcessor::AddEntryToDirectoryAndCollectChangedDirectories(
3547 GDataEntry* entry,
3548 GDataDirectory* directory,
3549 GDataDirectoryService* orphaned_dir_service,
3550 std::set<FilePath>* changed_dirs) {
3551 directory->AddEntry(entry);
3552 if (entry->AsGDataDirectory() && directory != orphaned_dir_service->root())
3553 changed_dirs->insert(entry->GetFilePath());
3554 }
3555
3556 // static
3557 void GDataWapiFeedProcessor::
3558 RemoveEntryFromDirectoryAndCollectChangedDirectories(
3559 GDataDirectory* directory,
3560 GDataEntry* entry,
3561 std::set<FilePath>* changed_dirs) {
3562 // Get the list of all sub-directory paths, so we can notify their listeners
3563 // that they are smoked.
3564 GetChildDirectoryPaths(entry, changed_dirs);
3565 directory->RemoveEntry(entry);
3566 }
3567 3288
3568 // static 3289 // static
3569 void GDataFileSystem::RemoveStaleEntryOnUpload(const std::string& resource_id, 3290 void GDataFileSystem::RemoveStaleEntryOnUpload(const std::string& resource_id,
3570 GDataDirectory* parent_dir, 3291 GDataDirectory* parent_dir,
3571 GDataEntry* existing_entry) { 3292 GDataEntry* existing_entry) {
3572 if (existing_entry && 3293 if (existing_entry &&
3573 // This should always match, but just in case. 3294 // This should always match, but just in case.
3574 existing_entry->parent() == parent_dir) { 3295 existing_entry->parent() == parent_dir) {
3575 parent_dir->RemoveEntry(existing_entry); 3296 parent_dir->RemoveEntry(existing_entry);
3576 } else { 3297 } else {
3577 LOG(ERROR) << "Entry for the existing file not found: " << resource_id; 3298 LOG(ERROR) << "Entry for the existing file not found: " << resource_id;
3578 } 3299 }
3579 } 3300 }
3580 3301
3581 GDataDirectory* GDataWapiFeedProcessor::FindDirectoryForNewEntry(
3582 GDataEntry* new_entry,
3583 const FileResourceIdMap& file_map,
3584 GDataDirectoryService* orphaned_dir_service) {
3585 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3586 GDataDirectory* dir = NULL;
3587 // Added file.
3588 const std::string& parent_id = new_entry->parent_resource_id();
3589 if (parent_id.empty()) {
3590 dir = directory_service_->root();
3591 DVLOG(1) << "Root parent for " << new_entry->base_name();
3592 } else {
3593 GDataEntry* entry = directory_service_->GetEntryByResourceId(parent_id);
3594 dir = entry ? entry->AsGDataDirectory() : NULL;
3595 if (!dir) {
3596 // The parent directory was also added with this set of feeds.
3597 FileResourceIdMap::const_iterator find_iter =
3598 file_map.find(parent_id);
3599 dir = (find_iter != file_map.end() &&
3600 find_iter->second) ?
3601 find_iter->second->AsGDataDirectory() : NULL;
3602 if (dir) {
3603 DVLOG(1) << "Found parent for " << new_entry->base_name()
3604 << " in file_map " << parent_id;
3605 } else {
3606 DVLOG(1) << "Adding orphan " << new_entry->GetFilePath().value();
3607 dir = orphaned_dir_service->root();
3608 }
3609 }
3610 }
3611 return dir;
3612 }
3613
3614 GDataFileError GDataWapiFeedProcessor::FeedToFileResourceMap(
3615 const std::vector<DocumentFeed*>& feed_list,
3616 FileResourceIdMap* file_map,
3617 int* feed_changestamp,
3618 FeedToFileResourceMapUmaStats* uma_stats) {
3619 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3620 DCHECK(uma_stats);
3621
3622 GDataFileError error = GDATA_FILE_OK;
3623 uma_stats->num_regular_files = 0;
3624 uma_stats->num_hosted_documents = 0;
3625 uma_stats->num_files_with_entry_kind.clear();
3626 for (size_t i = 0; i < feed_list.size(); ++i) {
3627 const DocumentFeed* feed = feed_list[i];
3628
3629 // Get upload url from the root feed. Links for all other collections will
3630 // be handled in GDatadirectory::FromDocumentEntry();
3631 if (i == 0) {
3632 const Link* root_feed_upload_link =
3633 feed->GetLinkByType(Link::RESUMABLE_CREATE_MEDIA);
3634 if (root_feed_upload_link)
3635 directory_service_->root()->set_upload_url(
3636 root_feed_upload_link->href());
3637 *feed_changestamp = feed->largest_changestamp();
3638 DCHECK_GE(*feed_changestamp, 0);
3639 }
3640
3641 for (ScopedVector<DocumentEntry>::const_iterator iter =
3642 feed->entries().begin();
3643 iter != feed->entries().end(); ++iter) {
3644 DocumentEntry* doc = *iter;
3645 GDataEntry* entry = GDataEntry::FromDocumentEntry(
3646 NULL, doc, directory_service_);
3647 // Some document entries don't map into files (i.e. sites).
3648 if (!entry)
3649 continue;
3650 // Count the number of files.
3651 GDataFile* as_file = entry->AsGDataFile();
3652 if (as_file) {
3653 if (as_file->is_hosted_document())
3654 ++uma_stats->num_hosted_documents;
3655 else
3656 ++uma_stats->num_regular_files;
3657 ++uma_stats->num_files_with_entry_kind[as_file->kind()];
3658 }
3659
3660 FileResourceIdMap::iterator map_entry =
3661 file_map->find(entry->resource_id());
3662
3663 // An entry with the same self link may already exist, so we need to
3664 // release the existing GDataEntry instance before overwriting the
3665 // entry with another GDataEntry instance.
3666 if (map_entry != file_map->end()) {
3667 LOG(WARNING) << "Found duplicate file "
3668 << map_entry->second->base_name();
3669
3670 delete map_entry->second;
3671 file_map->erase(map_entry);
3672 }
3673 file_map->insert(
3674 std::pair<std::string, GDataEntry*>(entry->resource_id(), entry));
3675 }
3676 }
3677
3678 if (error != GDATA_FILE_OK) {
3679 // If the code above fails to parse a feed, any GDataEntry instance
3680 // added to |file_by_url| is not managed by a GDataDirectory instance,
3681 // so we need to explicitly release them here.
3682 STLDeleteValues(file_map);
3683 }
3684
3685 return error;
3686 }
3687
3688 void GDataFileSystem::NotifyDirectoryChanged(const FilePath& directory_path) { 3302 void GDataFileSystem::NotifyDirectoryChanged(const FilePath& directory_path) {
3689 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3303 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3690 3304
3691 DVLOG(1) << "Content changed of " << directory_path.value(); 3305 DVLOG(1) << "Content changed of " << directory_path.value();
3692 // Notify the observers that content of |directory_path| has been changed. 3306 // Notify the observers that content of |directory_path| has been changed.
3693 FOR_EACH_OBSERVER(Observer, observers_, OnDirectoryChanged(directory_path)); 3307 FOR_EACH_OBSERVER(Observer, observers_, OnDirectoryChanged(directory_path));
3694 } 3308 }
3695 3309
3696 void GDataFileSystem::NotifyDocumentFeedFetched(int num_accumulated_entries) { 3310 void GDataFileSystem::NotifyDocumentFeedFetched(int num_accumulated_entries) {
3697 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
(...skipping 668 matching lines...) Expand 10 before | Expand all | Expand 10 after
4366 } 3980 }
4367 3981
4368 PlatformFileInfoProto entry_file_info; 3982 PlatformFileInfoProto entry_file_info;
4369 GDataEntry::ConvertPlatformFileInfoToProto(*file_info, &entry_file_info); 3983 GDataEntry::ConvertPlatformFileInfoToProto(*file_info, &entry_file_info);
4370 *entry_proto->mutable_file_info() = entry_file_info; 3984 *entry_proto->mutable_file_info() = entry_file_info;
4371 if (!callback.is_null()) 3985 if (!callback.is_null())
4372 callback.Run(GDATA_FILE_OK, entry_proto.Pass()); 3986 callback.Run(GDATA_FILE_OK, entry_proto.Pass());
4373 } 3987 }
4374 3988
4375 } // namespace gdata 3989 } // namespace gdata
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/gdata/gdata_file_system.h ('k') | chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698