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/logging.h"
8#include "base/memory/scoped_vector.h"
9#include "base/strings/string_number_conversions.h"
10#include "base/strings/string_util.h"
11#include "base/threading/thread_restrictions.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/leveldb_wrapper.h"
15#include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
16#include "chrome/browser/sync_file_system/logger.h"
17#include "google_apis/drive/drive_api_parser.h"
18#include "google_apis/drive/gdata_wapi_parser.h"
19#include "third_party/leveldatabase/src/include/leveldb/status.h"
20
21namespace sync_file_system {
22namespace drive_backend {
23
24void PutVersionToDB(int64 version, LevelDBWrapper* db) {
25  DCHECK(db);
26  db->Put(kDatabaseVersionKey, base::Int64ToString(version));
27}
28
29void PutServiceMetadataToDB(const ServiceMetadata& service_metadata,
30                            LevelDBWrapper* db) {
31  DCHECK(db);
32
33  std::string value;
34  bool success = service_metadata.SerializeToString(&value);
35  DCHECK(success);
36  db->Put(kServiceMetadataKey, value);
37}
38
39void PutFileMetadataToDB(const FileMetadata& file, LevelDBWrapper* db) {
40  DCHECK(db);
41
42  std::string value;
43  bool success = file.SerializeToString(&value);
44  DCHECK(success);
45  db->Put(kFileMetadataKeyPrefix + file.file_id(), value);
46}
47
48void PutFileTrackerToDB(const FileTracker& tracker, LevelDBWrapper* db) {
49  DCHECK(db);
50
51  std::string value;
52  bool success = tracker.SerializeToString(&value);
53  DCHECK(success);
54  db->Put(kFileTrackerKeyPrefix + base::Int64ToString(tracker.tracker_id()),
55          value);
56}
57
58void PutFileMetadataDeletionToDB(const std::string& file_id,
59                                 LevelDBWrapper* db) {
60  DCHECK(db);
61  db->Delete(kFileMetadataKeyPrefix + file_id);
62}
63
64void PutFileTrackerDeletionToDB(int64 tracker_id, LevelDBWrapper* db) {
65  DCHECK(db);
66  db->Delete(kFileTrackerKeyPrefix + base::Int64ToString(tracker_id));
67}
68
69bool HasFileAsParent(const FileDetails& details, const std::string& file_id) {
70  for (int i = 0; i < details.parent_folder_ids_size(); ++i) {
71    if (details.parent_folder_ids(i) == file_id)
72      return true;
73  }
74  return false;
75}
76
77bool IsAppRoot(const FileTracker& tracker) {
78  return tracker.tracker_kind() == TRACKER_KIND_APP_ROOT ||
79      tracker.tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT;
80}
81
82std::string GetTrackerTitle(const FileTracker& tracker) {
83  if (tracker.has_synced_details())
84    return tracker.synced_details().title();
85  return std::string();
86}
87
88SyncStatusCode GDataErrorCodeToSyncStatusCode(
89    google_apis::GDataErrorCode error) {
90  // NOTE: Please update DriveFileSyncService::UpdateServiceState when you add
91  // more error code mapping.
92  switch (error) {
93    case google_apis::HTTP_SUCCESS:
94    case google_apis::HTTP_CREATED:
95    case google_apis::HTTP_NO_CONTENT:
96    case google_apis::HTTP_FOUND:
97      return SYNC_STATUS_OK;
98
99    case google_apis::HTTP_NOT_MODIFIED:
100      return SYNC_STATUS_NOT_MODIFIED;
101
102    case google_apis::HTTP_CONFLICT:
103    case google_apis::HTTP_PRECONDITION:
104      return SYNC_STATUS_HAS_CONFLICT;
105
106    case google_apis::HTTP_UNAUTHORIZED:
107      return SYNC_STATUS_AUTHENTICATION_FAILED;
108
109    case google_apis::GDATA_NO_CONNECTION:
110      return SYNC_STATUS_NETWORK_ERROR;
111
112    case google_apis::HTTP_INTERNAL_SERVER_ERROR:
113    case google_apis::HTTP_BAD_GATEWAY:
114    case google_apis::HTTP_SERVICE_UNAVAILABLE:
115    case google_apis::GDATA_CANCELLED:
116    case google_apis::GDATA_NOT_READY:
117      return SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE;
118
119    case google_apis::HTTP_NOT_FOUND:
120    case google_apis::HTTP_GONE:
121      return SYNC_FILE_ERROR_NOT_FOUND;
122
123    case google_apis::GDATA_FILE_ERROR:
124      return SYNC_FILE_ERROR_FAILED;
125
126    case google_apis::HTTP_FORBIDDEN:
127      return SYNC_STATUS_ACCESS_FORBIDDEN;
128
129    case google_apis::HTTP_RESUME_INCOMPLETE:
130    case google_apis::HTTP_BAD_REQUEST:
131    case google_apis::HTTP_LENGTH_REQUIRED:
132    case google_apis::HTTP_NOT_IMPLEMENTED:
133    case google_apis::GDATA_PARSE_ERROR:
134    case google_apis::GDATA_OTHER_ERROR:
135      return SYNC_STATUS_FAILED;
136
137    case google_apis::GDATA_NO_SPACE:
138      return SYNC_FILE_ERROR_NO_SPACE;
139  }
140
141  // There's a case where DriveService layer returns GDataErrorCode==-1
142  // when network is unavailable. (http://crbug.com/223042)
143  // TODO(kinuko,nhiroki): We should identify from where this undefined error
144  // code is coming.
145  if (error == -1)
146    return SYNC_STATUS_NETWORK_ERROR;
147
148  util::Log(logging::LOG_WARNING,
149            FROM_HERE,
150            "Got unexpected error: %d",
151            static_cast<int>(error));
152  return SYNC_STATUS_FAILED;
153}
154
155bool RemovePrefix(const std::string& str, const std::string& prefix,
156                  std::string* out) {
157  if (!StartsWithASCII(str, prefix, true)) {
158    if (out)
159      *out = str;
160    return false;
161  }
162
163  if (out)
164    *out = str.substr(prefix.size());
165  return true;
166}
167
168scoped_ptr<ServiceMetadata> InitializeServiceMetadata(LevelDBWrapper* db) {
169  base::ThreadRestrictions::AssertIOAllowed();
170  DCHECK(db);
171
172  scoped_ptr<ServiceMetadata> service_metadata;
173
174  std::string value;
175  leveldb::Status status = db->Get(kServiceMetadataKey, &value);
176  if (status.ok()) {
177    service_metadata.reset(new ServiceMetadata);
178    if (!service_metadata->ParseFromString(value))
179      service_metadata.reset();
180  } else if (status.IsNotFound()) {
181    service_metadata.reset(new ServiceMetadata);
182    service_metadata->set_next_tracker_id(1);
183  }
184
185  return service_metadata.Pass();
186}
187
188}  // namespace drive_backend
189}  // namespace sync_file_system
190