Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync_file_system / drive_backend / drive_backend_util.cc
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 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();
62        ++itr) {
63     details->add_parent_folder_ids((*itr)->file_id());
64   }
65   details->set_title(file_resource.title());
66
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);
72   else
73     details->set_file_kind(FILE_KIND_UNSUPPORTED);
74
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);
81 }
82
83 scoped_ptr<FileMetadata> CreateFileMetadataFromFileResource(
84     int64 change_id,
85     const google_apis::FileResource& resource) {
86   scoped_ptr<FileMetadata> file(new FileMetadata);
87   file->set_file_id(resource.file_id());
88
89   FileDetails* details = file->mutable_details();
90   details->set_change_id(change_id);
91
92   if (resource.labels().is_trashed()) {
93     details->set_missing(true);
94     return file.Pass();
95   }
96
97   PopulateFileDetailsByFileResource(resource, details);
98   return file.Pass();
99 }
100
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());
105
106   FileDetails* details = file->mutable_details();
107   details->set_change_id(change.change_id());
108
109   if (change.is_deleted()) {
110     details->set_missing(true);
111     return file.Pass();
112   }
113
114   PopulateFileDetailsByFileResource(*change.file(), details);
115   return file.Pass();
116 }
117
118 scoped_ptr<FileMetadata> CreateDeletedFileMetadata(
119     int64 change_id,
120     const std::string& file_id) {
121   scoped_ptr<FileMetadata> file(new FileMetadata);
122   file->set_file_id(file_id);
123
124   FileDetails* details = file->mutable_details();
125   details->set_change_id(change_id);
126   details->set_missing(true);
127   return file.Pass();
128 }
129
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();
135
136   return webkit_blob::ScopedFile(
137       temp_file_path,
138       webkit_blob::ScopedFile::DELETE_ON_SCOPE_OUT,
139       file_task_runner);
140 }
141
142 std::string FileKindToString(FileKind file_kind) {
143   switch (file_kind) {
144     case FILE_KIND_UNSUPPORTED:
145       return "unsupported";
146     case FILE_KIND_FILE:
147       return "file";
148     case FILE_KIND_FOLDER:
149       return "folder";
150   }
151
152   NOTREACHED();
153   return "unknown";
154 }
155
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)
159       return true;
160   }
161   return false;
162 }
163
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;
170   return mime_type;
171 }
172
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())
179       continue;
180
181     if (!oldest || oldest->published_time() > entry->published_time()) {
182       oldest.reset(entry);
183       candidates[i] = NULL;
184     }
185   }
186
187   return oldest.Pass();
188 }
189
190 SyncStatusCode GDataErrorCodeToSyncStatusCode(
191     google_apis::GDataErrorCode error) {
192   // NOTE: Please update DriveFileSyncService::UpdateServiceState when you add
193   // more error code mapping.
194   switch (error) {
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;
200
201     case google_apis::HTTP_NOT_MODIFIED:
202       return SYNC_STATUS_NOT_MODIFIED;
203
204     case google_apis::HTTP_CONFLICT:
205     case google_apis::HTTP_PRECONDITION:
206       return SYNC_STATUS_HAS_CONFLICT;
207
208     case google_apis::HTTP_UNAUTHORIZED:
209       return SYNC_STATUS_AUTHENTICATION_FAILED;
210
211     case google_apis::GDATA_NO_CONNECTION:
212       return SYNC_STATUS_NETWORK_ERROR;
213
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;
220
221     case google_apis::HTTP_NOT_FOUND:
222     case google_apis::HTTP_GONE:
223       return SYNC_FILE_ERROR_NOT_FOUND;
224
225     case google_apis::GDATA_FILE_ERROR:
226       return SYNC_FILE_ERROR_FAILED;
227
228     case google_apis::HTTP_FORBIDDEN:
229       return SYNC_STATUS_ACCESS_FORBIDDEN;
230
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;
238
239     case google_apis::GDATA_NO_SPACE:
240       return SYNC_FILE_ERROR_NO_SPACE;
241   }
242
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
246   // code is coming.
247   if (error == -1)
248     return SYNC_STATUS_NETWORK_ERROR;
249
250   util::Log(logging::LOG_WARNING,
251             FROM_HERE,
252             "Got unexpected error: %d",
253             static_cast<int>(error));
254   return SYNC_STATUS_FAILED;
255 }
256
257 }  // namespace drive_backend
258 }  // namespace sync_file_system