1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h" 6 7 #include "base/file_util.h" 8 #include "base/logging.h" 9 #include "base/memory/scoped_vector.h" 10 #include "base/message_loop/message_loop_proxy.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "chrome/browser/drive/drive_api_util.h" 13 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h" 14 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h" 15 #include "google_apis/drive/drive_api_parser.h" 16 #include "google_apis/drive/gdata_wapi_parser.h" 17 #include "net/base/mime_util.h" 18 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 19 20 namespace sync_file_system { 21 namespace drive_backend { 22 23 namespace { 24 25 const char kMimeTypeOctetStream[] = "application/octet-stream"; 26 27 } // namespace 28 29 void PutServiceMetadataToBatch(const ServiceMetadata& service_metadata, 30 leveldb::WriteBatch* batch) { 31 std::string value; 32 bool success = service_metadata.SerializeToString(&value); 33 DCHECK(success); 34 batch->Put(kServiceMetadataKey, value); 35 } 36 37 void PutFileToBatch(const FileMetadata& file, leveldb::WriteBatch* batch) { 38 std::string value; 39 bool success = file.SerializeToString(&value); 40 DCHECK(success); 41 batch->Put(kFileMetadataKeyPrefix + file.file_id(), value); 42 } 43 44 void PutTrackerToBatch(const FileTracker& tracker, leveldb::WriteBatch* batch) { 45 std::string value; 46 bool success = tracker.SerializeToString(&value); 47 DCHECK(success); 48 batch->Put(kFileTrackerKeyPrefix + base::Int64ToString(tracker.tracker_id()), 49 value); 50 } 51 52 void PopulateFileDetailsByFileResource( 53 const google_apis::FileResource& file_resource, 54 FileDetails* details) { 55 details->clear_parent_folder_ids(); 56 for (ScopedVector<google_apis::ParentReference>::const_iterator itr = 57 file_resource.parents().begin(); 58 itr != file_resource.parents().end(); 59 ++itr) { 60 details->add_parent_folder_ids((*itr)->file_id()); 61 } 62 details->set_title(file_resource.title()); 63 64 google_apis::DriveEntryKind kind = drive::util::GetKind(file_resource); 65 if (kind == google_apis::ENTRY_KIND_FILE) 66 details->set_file_kind(FILE_KIND_FILE); 67 else if (kind == google_apis::ENTRY_KIND_FOLDER) 68 details->set_file_kind(FILE_KIND_FOLDER); 69 else 70 details->set_file_kind(FILE_KIND_UNSUPPORTED); 71 72 details->set_md5(file_resource.md5_checksum()); 73 details->set_etag(file_resource.etag()); 74 details->set_creation_time(file_resource.created_date().ToInternalValue()); 75 details->set_modification_time( 76 file_resource.modified_date().ToInternalValue()); 77 details->set_missing(false); 78 } 79 80 scoped_ptr<FileMetadata> CreateFileMetadataFromFileResource( 81 int64 change_id, 82 const google_apis::FileResource& resource) { 83 scoped_ptr<FileMetadata> file(new FileMetadata); 84 file->set_file_id(resource.file_id()); 85 86 FileDetails* details = file->mutable_details(); 87 details->set_change_id(change_id); 88 89 if (resource.labels().is_trashed()) { 90 details->set_missing(true); 91 return file.Pass(); 92 } 93 94 PopulateFileDetailsByFileResource(resource, details); 95 return file.Pass(); 96 } 97 98 scoped_ptr<FileMetadata> CreateFileMetadataFromChangeResource( 99 const google_apis::ChangeResource& change) { 100 scoped_ptr<FileMetadata> file(new FileMetadata); 101 file->set_file_id(change.file_id()); 102 103 FileDetails* details = file->mutable_details(); 104 details->set_change_id(change.change_id()); 105 106 if (change.is_deleted()) { 107 details->set_missing(true); 108 return file.Pass(); 109 } 110 111 PopulateFileDetailsByFileResource(*change.file(), details); 112 return file.Pass(); 113 } 114 115 scoped_ptr<FileMetadata> CreateDeletedFileMetadata( 116 int64 change_id, 117 const std::string& file_id) { 118 scoped_ptr<FileMetadata> file(new FileMetadata); 119 file->set_file_id(file_id); 120 121 FileDetails* details = file->mutable_details(); 122 details->set_change_id(change_id); 123 details->set_missing(true); 124 return file.Pass(); 125 } 126 127 webkit_blob::ScopedFile CreateTemporaryFile( 128 base::TaskRunner* file_task_runner) { 129 base::FilePath temp_file_path; 130 if (!base::CreateTemporaryFile(&temp_file_path)) 131 return webkit_blob::ScopedFile(); 132 133 return webkit_blob::ScopedFile( 134 temp_file_path, 135 webkit_blob::ScopedFile::DELETE_ON_SCOPE_OUT, 136 file_task_runner); 137 } 138 139 std::string FileKindToString(FileKind file_kind) { 140 switch (file_kind) { 141 case FILE_KIND_UNSUPPORTED: 142 return "unsupported"; 143 case FILE_KIND_FILE: 144 return "file"; 145 case FILE_KIND_FOLDER: 146 return "folder"; 147 } 148 149 NOTREACHED(); 150 return "unknown"; 151 } 152 153 bool HasFileAsParent(const FileDetails& details, const std::string& file_id) { 154 for (int i = 0; i < details.parent_folder_ids_size(); ++i) { 155 if (details.parent_folder_ids(i) == file_id) 156 return true; 157 } 158 return false; 159 } 160 161 std::string GetMimeTypeFromTitle(const base::FilePath& title) { 162 base::FilePath::StringType extension = title.Extension(); 163 std::string mime_type; 164 if (extension.empty() || 165 !net::GetWellKnownMimeTypeFromExtension(extension.substr(1), &mime_type)) 166 return kMimeTypeOctetStream; 167 return mime_type; 168 } 169 170 scoped_ptr<google_apis::ResourceEntry> GetOldestCreatedFolderResource( 171 ScopedVector<google_apis::ResourceEntry> candidates) { 172 scoped_ptr<google_apis::ResourceEntry> oldest; 173 for (size_t i = 0; i < candidates.size(); ++i) { 174 google_apis::ResourceEntry* entry = candidates[i]; 175 if (!entry->is_folder() || entry->deleted()) 176 continue; 177 178 if (!oldest || oldest->published_time() > entry->published_time()) { 179 oldest.reset(entry); 180 candidates[i] = NULL; 181 } 182 } 183 184 return oldest.Pass(); 185 } 186 187 } // namespace drive_backend 188 } // namespace sync_file_system 189