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 "chrome/browser/sync_file_system/logger.h" 16 #include "google_apis/drive/drive_api_parser.h" 17 #include "google_apis/drive/gdata_wapi_parser.h" 18 #include "net/base/mime_util.h" 19 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 20 21 namespace sync_file_system { 22 namespace drive_backend { 23 24 void PutServiceMetadataToBatch(const ServiceMetadata& service_metadata, 25 leveldb::WriteBatch* batch) { 26 std::string value; 27 bool success = service_metadata.SerializeToString(&value); 28 DCHECK(success); 29 batch->Put(kServiceMetadataKey, value); 30 } 31 32 void PutFileMetadataToBatch(const FileMetadata& file, 33 leveldb::WriteBatch* batch) { 34 if (!batch) 35 return; 36 37 std::string value; 38 bool success = file.SerializeToString(&value); 39 DCHECK(success); 40 batch->Put(kFileMetadataKeyPrefix + file.file_id(), value); 41 } 42 43 void PutFileTrackerToBatch(const FileTracker& tracker, 44 leveldb::WriteBatch* batch) { 45 if (!batch) 46 return; 47 48 std::string value; 49 bool success = tracker.SerializeToString(&value); 50 DCHECK(success); 51 batch->Put(kFileTrackerKeyPrefix + base::Int64ToString(tracker.tracker_id()), 52 value); 53 } 54 55 void PutFileMetadataDeletionToBatch(const std::string& file_id, 56 leveldb::WriteBatch* batch) { 57 if (batch) 58 batch->Delete(kFileMetadataKeyPrefix + file_id); 59 } 60 61 void PutFileTrackerDeletionToBatch(int64 tracker_id, 62 leveldb::WriteBatch* batch) { 63 if (batch) 64 batch->Delete(kFileTrackerKeyPrefix + base::Int64ToString(tracker_id)); 65 } 66 67 void PopulateFileDetailsByFileResource( 68 const google_apis::FileResource& file_resource, 69 FileDetails* details) { 70 details->clear_parent_folder_ids(); 71 for (std::vector<google_apis::ParentReference>::const_iterator itr = 72 file_resource.parents().begin(); 73 itr != file_resource.parents().end(); 74 ++itr) { 75 details->add_parent_folder_ids(itr->file_id()); 76 } 77 details->set_title(file_resource.title()); 78 79 google_apis::DriveEntryKind kind = drive::util::GetKind(file_resource); 80 if (kind == google_apis::ENTRY_KIND_FILE) 81 details->set_file_kind(FILE_KIND_FILE); 82 else if (kind == google_apis::ENTRY_KIND_FOLDER) 83 details->set_file_kind(FILE_KIND_FOLDER); 84 else 85 details->set_file_kind(FILE_KIND_UNSUPPORTED); 86 87 details->set_md5(file_resource.md5_checksum()); 88 details->set_etag(file_resource.etag()); 89 details->set_creation_time(file_resource.created_date().ToInternalValue()); 90 details->set_modification_time( 91 file_resource.modified_date().ToInternalValue()); 92 details->set_missing(file_resource.labels().is_trashed()); 93 } 94 95 scoped_ptr<FileMetadata> CreateFileMetadataFromFileResource( 96 int64 change_id, 97 const google_apis::FileResource& resource) { 98 scoped_ptr<FileMetadata> file(new FileMetadata); 99 file->set_file_id(resource.file_id()); 100 101 FileDetails* details = file->mutable_details(); 102 details->set_change_id(change_id); 103 104 if (resource.labels().is_trashed()) { 105 details->set_missing(true); 106 return file.Pass(); 107 } 108 109 PopulateFileDetailsByFileResource(resource, details); 110 return file.Pass(); 111 } 112 113 scoped_ptr<FileMetadata> CreateFileMetadataFromChangeResource( 114 const google_apis::ChangeResource& change) { 115 scoped_ptr<FileMetadata> file(new FileMetadata); 116 file->set_file_id(change.file_id()); 117 118 FileDetails* details = file->mutable_details(); 119 details->set_change_id(change.change_id()); 120 121 if (change.is_deleted()) { 122 details->set_missing(true); 123 return file.Pass(); 124 } 125 126 PopulateFileDetailsByFileResource(*change.file(), details); 127 return file.Pass(); 128 } 129 130 scoped_ptr<FileMetadata> CreateDeletedFileMetadata( 131 int64 change_id, 132 const std::string& file_id) { 133 scoped_ptr<FileMetadata> file(new FileMetadata); 134 file->set_file_id(file_id); 135 136 FileDetails* details = file->mutable_details(); 137 details->set_change_id(change_id); 138 details->set_missing(true); 139 return file.Pass(); 140 } 141 142 webkit_blob::ScopedFile CreateTemporaryFile( 143 base::TaskRunner* file_task_runner) { 144 base::FilePath temp_file_path; 145 if (!base::CreateTemporaryFile(&temp_file_path)) 146 return webkit_blob::ScopedFile(); 147 148 return webkit_blob::ScopedFile( 149 temp_file_path, 150 webkit_blob::ScopedFile::DELETE_ON_SCOPE_OUT, 151 file_task_runner); 152 } 153 154 std::string FileKindToString(FileKind file_kind) { 155 switch (file_kind) { 156 case FILE_KIND_UNSUPPORTED: 157 return "unsupported"; 158 case FILE_KIND_FILE: 159 return "file"; 160 case FILE_KIND_FOLDER: 161 return "folder"; 162 } 163 164 NOTREACHED(); 165 return "unknown"; 166 } 167 168 bool HasFileAsParent(const FileDetails& details, const std::string& file_id) { 169 for (int i = 0; i < details.parent_folder_ids_size(); ++i) { 170 if (details.parent_folder_ids(i) == file_id) 171 return true; 172 } 173 return false; 174 } 175 176 std::string GetMimeTypeFromTitle(const base::FilePath& title) { 177 base::FilePath::StringType extension = title.Extension(); 178 std::string mime_type; 179 if (extension.empty() || 180 !net::GetWellKnownMimeTypeFromExtension(extension.substr(1), &mime_type)) 181 return kMimeTypeOctetStream; 182 return mime_type; 183 } 184 185 SyncStatusCode GDataErrorCodeToSyncStatusCode( 186 google_apis::GDataErrorCode error) { 187 // NOTE: Please update DriveFileSyncService::UpdateServiceState when you add 188 // more error code mapping. 189 switch (error) { 190 case google_apis::HTTP_SUCCESS: 191 case google_apis::HTTP_CREATED: 192 case google_apis::HTTP_NO_CONTENT: 193 case google_apis::HTTP_FOUND: 194 return SYNC_STATUS_OK; 195 196 case google_apis::HTTP_NOT_MODIFIED: 197 return SYNC_STATUS_NOT_MODIFIED; 198 199 case google_apis::HTTP_CONFLICT: 200 case google_apis::HTTP_PRECONDITION: 201 return SYNC_STATUS_HAS_CONFLICT; 202 203 case google_apis::HTTP_UNAUTHORIZED: 204 return SYNC_STATUS_AUTHENTICATION_FAILED; 205 206 case google_apis::GDATA_NO_CONNECTION: 207 return SYNC_STATUS_NETWORK_ERROR; 208 209 case google_apis::HTTP_INTERNAL_SERVER_ERROR: 210 case google_apis::HTTP_BAD_GATEWAY: 211 case google_apis::HTTP_SERVICE_UNAVAILABLE: 212 case google_apis::GDATA_CANCELLED: 213 case google_apis::GDATA_NOT_READY: 214 return SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE; 215 216 case google_apis::HTTP_NOT_FOUND: 217 case google_apis::HTTP_GONE: 218 return SYNC_FILE_ERROR_NOT_FOUND; 219 220 case google_apis::GDATA_FILE_ERROR: 221 return SYNC_FILE_ERROR_FAILED; 222 223 case google_apis::HTTP_FORBIDDEN: 224 return SYNC_STATUS_ACCESS_FORBIDDEN; 225 226 case google_apis::HTTP_RESUME_INCOMPLETE: 227 case google_apis::HTTP_BAD_REQUEST: 228 case google_apis::HTTP_LENGTH_REQUIRED: 229 case google_apis::HTTP_NOT_IMPLEMENTED: 230 case google_apis::GDATA_PARSE_ERROR: 231 case google_apis::GDATA_OTHER_ERROR: 232 return SYNC_STATUS_FAILED; 233 234 case google_apis::GDATA_NO_SPACE: 235 return SYNC_FILE_ERROR_NO_SPACE; 236 } 237 238 // There's a case where DriveService layer returns GDataErrorCode==-1 239 // when network is unavailable. (http://crbug.com/223042) 240 // TODO(kinuko,nhiroki): We should identify from where this undefined error 241 // code is coming. 242 if (error == -1) 243 return SYNC_STATUS_NETWORK_ERROR; 244 245 util::Log(logging::LOG_WARNING, 246 FROM_HERE, 247 "Got unexpected error: %d", 248 static_cast<int>(error)); 249 return SYNC_STATUS_FAILED; 250 } 251 252 scoped_ptr<FileTracker> CloneFileTracker(const FileTracker* obj) { 253 if (!obj) 254 return scoped_ptr<FileTracker>(); 255 return scoped_ptr<FileTracker>(new FileTracker(*obj)); 256 } 257 258 } // namespace drive_backend 259 } // namespace sync_file_system 260