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.
5 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
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"
21 namespace sync_file_system {
22 namespace drive_backend {
24 void PutServiceMetadataToBatch(const ServiceMetadata& service_metadata,
25 leveldb::WriteBatch* batch) {
27 bool success = service_metadata.SerializeToString(&value);
29 batch->Put(kServiceMetadataKey, value);
32 void PutFileMetadataToBatch(const FileMetadata& file,
33 leveldb::WriteBatch* batch) {
38 bool success = file.SerializeToString(&value);
40 batch->Put(kFileMetadataKeyPrefix + file.file_id(), value);
43 void PutFileTrackerToBatch(const FileTracker& tracker,
44 leveldb::WriteBatch* batch) {
49 bool success = tracker.SerializeToString(&value);
51 batch->Put(kFileTrackerKeyPrefix + base::Int64ToString(tracker.tracker_id()),
55 void PopulateFileDetailsByFileResource(
56 const google_apis::FileResource& file_resource,
57 FileDetails* details) {
58 details->clear_parent_folder_ids();
59 for (ScopedVector<google_apis::ParentReference>::const_iterator itr =
60 file_resource.parents().begin();
61 itr != file_resource.parents().end();
63 details->add_parent_folder_ids((*itr)->file_id());
65 details->set_title(file_resource.title());
67 google_apis::DriveEntryKind kind = drive::util::GetKind(file_resource);
68 if (kind == google_apis::ENTRY_KIND_FILE)
69 details->set_file_kind(FILE_KIND_FILE);
70 else if (kind == google_apis::ENTRY_KIND_FOLDER)
71 details->set_file_kind(FILE_KIND_FOLDER);
73 details->set_file_kind(FILE_KIND_UNSUPPORTED);
75 details->set_md5(file_resource.md5_checksum());
76 details->set_etag(file_resource.etag());
77 details->set_creation_time(file_resource.created_date().ToInternalValue());
78 details->set_modification_time(
79 file_resource.modified_date().ToInternalValue());
80 details->set_missing(false);
83 scoped_ptr<FileMetadata> CreateFileMetadataFromFileResource(
85 const google_apis::FileResource& resource) {
86 scoped_ptr<FileMetadata> file(new FileMetadata);
87 file->set_file_id(resource.file_id());
89 FileDetails* details = file->mutable_details();
90 details->set_change_id(change_id);
92 if (resource.labels().is_trashed()) {
93 details->set_missing(true);
97 PopulateFileDetailsByFileResource(resource, details);
101 scoped_ptr<FileMetadata> CreateFileMetadataFromChangeResource(
102 const google_apis::ChangeResource& change) {
103 scoped_ptr<FileMetadata> file(new FileMetadata);
104 file->set_file_id(change.file_id());
106 FileDetails* details = file->mutable_details();
107 details->set_change_id(change.change_id());
109 if (change.is_deleted()) {
110 details->set_missing(true);
114 PopulateFileDetailsByFileResource(*change.file(), details);
118 scoped_ptr<FileMetadata> CreateDeletedFileMetadata(
120 const std::string& file_id) {
121 scoped_ptr<FileMetadata> file(new FileMetadata);
122 file->set_file_id(file_id);
124 FileDetails* details = file->mutable_details();
125 details->set_change_id(change_id);
126 details->set_missing(true);
130 webkit_blob::ScopedFile CreateTemporaryFile(
131 base::TaskRunner* file_task_runner) {
132 base::FilePath temp_file_path;
133 if (!base::CreateTemporaryFile(&temp_file_path))
134 return webkit_blob::ScopedFile();
136 return webkit_blob::ScopedFile(
138 webkit_blob::ScopedFile::DELETE_ON_SCOPE_OUT,
142 std::string FileKindToString(FileKind file_kind) {
144 case FILE_KIND_UNSUPPORTED:
145 return "unsupported";
148 case FILE_KIND_FOLDER:
156 bool HasFileAsParent(const FileDetails& details, const std::string& file_id) {
157 for (int i = 0; i < details.parent_folder_ids_size(); ++i) {
158 if (details.parent_folder_ids(i) == file_id)
164 std::string GetMimeTypeFromTitle(const base::FilePath& title) {
165 base::FilePath::StringType extension = title.Extension();
166 std::string mime_type;
167 if (extension.empty() ||
168 !net::GetWellKnownMimeTypeFromExtension(extension.substr(1), &mime_type))
169 return kMimeTypeOctetStream;
173 scoped_ptr<google_apis::ResourceEntry> GetOldestCreatedFolderResource(
174 ScopedVector<google_apis::ResourceEntry> candidates) {
175 scoped_ptr<google_apis::ResourceEntry> oldest;
176 for (size_t i = 0; i < candidates.size(); ++i) {
177 google_apis::ResourceEntry* entry = candidates[i];
178 if (!entry->is_folder() || entry->deleted())
181 if (!oldest || oldest->published_time() > entry->published_time()) {
183 candidates[i] = NULL;
187 return oldest.Pass();
190 SyncStatusCode GDataErrorCodeToSyncStatusCode(
191 google_apis::GDataErrorCode error) {
192 // NOTE: Please update DriveFileSyncService::UpdateServiceState when you add
193 // more error code mapping.
195 case google_apis::HTTP_SUCCESS:
196 case google_apis::HTTP_CREATED:
197 case google_apis::HTTP_NO_CONTENT:
198 case google_apis::HTTP_FOUND:
199 return SYNC_STATUS_OK;
201 case google_apis::HTTP_NOT_MODIFIED:
202 return SYNC_STATUS_NOT_MODIFIED;
204 case google_apis::HTTP_CONFLICT:
205 case google_apis::HTTP_PRECONDITION:
206 return SYNC_STATUS_HAS_CONFLICT;
208 case google_apis::HTTP_UNAUTHORIZED:
209 return SYNC_STATUS_AUTHENTICATION_FAILED;
211 case google_apis::GDATA_NO_CONNECTION:
212 return SYNC_STATUS_NETWORK_ERROR;
214 case google_apis::HTTP_INTERNAL_SERVER_ERROR:
215 case google_apis::HTTP_BAD_GATEWAY:
216 case google_apis::HTTP_SERVICE_UNAVAILABLE:
217 case google_apis::GDATA_CANCELLED:
218 case google_apis::GDATA_NOT_READY:
219 return SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE;
221 case google_apis::HTTP_NOT_FOUND:
222 case google_apis::HTTP_GONE:
223 return SYNC_FILE_ERROR_NOT_FOUND;
225 case google_apis::GDATA_FILE_ERROR:
226 return SYNC_FILE_ERROR_FAILED;
228 case google_apis::HTTP_FORBIDDEN:
229 return SYNC_STATUS_ACCESS_FORBIDDEN;
231 case google_apis::HTTP_RESUME_INCOMPLETE:
232 case google_apis::HTTP_BAD_REQUEST:
233 case google_apis::HTTP_LENGTH_REQUIRED:
234 case google_apis::HTTP_NOT_IMPLEMENTED:
235 case google_apis::GDATA_PARSE_ERROR:
236 case google_apis::GDATA_OTHER_ERROR:
237 return SYNC_STATUS_FAILED;
239 case google_apis::GDATA_NO_SPACE:
240 return SYNC_FILE_ERROR_NO_SPACE;
243 // There's a case where DriveService layer returns GDataErrorCode==-1
244 // when network is unavailable. (http://crbug.com/223042)
245 // TODO(kinuko,nhiroki): We should identify from where this undefined error
248 return SYNC_STATUS_NETWORK_ERROR;
250 util::Log(logging::LOG_WARNING,
252 "Got unexpected error: %d",
253 static_cast<int>(error));
254 return SYNC_STATUS_FAILED;
257 } // namespace drive_backend
258 } // namespace sync_file_system