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
PutServiceMetadataToBatch(const ServiceMetadata & service_metadata,leveldb::WriteBatch * batch)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
PutFileToBatch(const FileMetadata & file,leveldb::WriteBatch * batch)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
PutTrackerToBatch(const FileTracker & tracker,leveldb::WriteBatch * batch)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
PopulateFileDetailsByFileResource(const google_apis::FileResource & file_resource,FileDetails * details)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
CreateFileMetadataFromFileResource(int64 change_id,const google_apis::FileResource & resource)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
CreateFileMetadataFromChangeResource(const google_apis::ChangeResource & change)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
CreateDeletedFileMetadata(int64 change_id,const std::string & file_id)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
CreateTemporaryFile(base::TaskRunner * file_task_runner)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
FileKindToString(FileKind file_kind)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
HasFileAsParent(const FileDetails & details,const std::string & file_id)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
GetMimeTypeFromTitle(const base::FilePath & title)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
GetOldestCreatedFolderResource(ScopedVector<google_apis::ResourceEntry> candidates)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