- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync_file_system / drive_backend / metadata_db_migration_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/metadata_db_migration_util.h"
6
7 #include "base/files/file_path.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/string_util.h"
10 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
11 #include "url/gurl.h"
12 #include "webkit/browser/fileapi/file_system_url.h"
13 #include "webkit/common/fileapi/file_system_types.h"
14
15 namespace sync_file_system {
16 namespace drive_backend {
17
18 namespace {
19
20 const base::FilePath::CharType kV0FormatPathPrefix[] =
21     FILE_PATH_LITERAL("drive/");
22 const char kWapiFileIdPrefix[] = "file:";
23 const char kWapiFolderIdPrefix[] = "folder:";
24
25 std::string RemovePrefix(const std::string& str, const std::string& prefix) {
26   if (StartsWithASCII(str, prefix, true))
27     return std::string(str.begin() + prefix.size(), str.end());
28   return str;
29 }
30
31 }  // namespace
32
33 bool ParseV0FormatFileSystemURL(const GURL& url,
34                                 GURL* origin,
35                                 base::FilePath* path) {
36   fileapi::FileSystemType mount_type;
37   base::FilePath virtual_path;
38
39   if (!fileapi::FileSystemURL::ParseFileSystemSchemeURL(
40           url, origin, &mount_type, &virtual_path) ||
41       mount_type != fileapi::kFileSystemTypeExternal) {
42     NOTREACHED() << "Failed to parse filesystem scheme URL " << url.spec();
43     return false;
44   }
45
46   base::FilePath::StringType prefix =
47       base::FilePath(kV0FormatPathPrefix).NormalizePathSeparators().value();
48   if (virtual_path.value().substr(0, prefix.size()) != prefix)
49     return false;
50
51   *path = base::FilePath(virtual_path.value().substr(prefix.size()));
52   return true;
53 }
54
55 std::string AddWapiFilePrefix(const std::string& resource_id) {
56   DCHECK(!StartsWithASCII(resource_id, kWapiFileIdPrefix, true));
57   DCHECK(!StartsWithASCII(resource_id, kWapiFolderIdPrefix, true));
58
59   if (resource_id.empty() ||
60       StartsWithASCII(resource_id, kWapiFileIdPrefix, true) ||
61       StartsWithASCII(resource_id, kWapiFolderIdPrefix, true))
62     return resource_id;
63   return kWapiFileIdPrefix + resource_id;
64 }
65
66 std::string AddWapiFolderPrefix(const std::string& resource_id) {
67   DCHECK(!StartsWithASCII(resource_id, kWapiFileIdPrefix, true));
68   DCHECK(!StartsWithASCII(resource_id, kWapiFolderIdPrefix, true));
69
70   if (resource_id.empty() ||
71       StartsWithASCII(resource_id, kWapiFileIdPrefix, true) ||
72       StartsWithASCII(resource_id, kWapiFolderIdPrefix, true))
73     return resource_id;
74   return kWapiFolderIdPrefix + resource_id;
75 }
76
77 std::string AddWapiIdPrefix(const std::string& resource_id,
78                             DriveMetadata_ResourceType type) {
79   switch (type) {
80     case DriveMetadata_ResourceType_RESOURCE_TYPE_FILE:
81       return AddWapiFilePrefix(resource_id);
82     case DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER:
83       return AddWapiFolderPrefix(resource_id);
84   }
85   NOTREACHED();
86   return resource_id;
87 }
88
89 std::string RemoveWapiIdPrefix(const std::string& resource_id) {
90   if (StartsWithASCII(resource_id, kWapiFileIdPrefix, true))
91     return RemovePrefix(resource_id, kWapiFileIdPrefix);
92   if (StartsWithASCII(resource_id, kWapiFolderIdPrefix, true))
93     return RemovePrefix(resource_id, kWapiFolderIdPrefix);
94   return resource_id;
95 }
96
97 SyncStatusCode MigrateDatabaseFromV0ToV1(leveldb::DB* db) {
98   // Version 0 database format:
99   //   key: "CHANGE_STAMP"
100   //   value: <Largest Changestamp>
101   //
102   //   key: "SYNC_ROOT_DIR"
103   //   value: <Resource ID of the sync root directory>
104   //
105   //   key: "METADATA: " +
106   //        <FileSystemURL serialized by SerializeSyncableFileSystemURL>
107   //   value: <Serialized DriveMetadata>
108   //
109   //   key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin>
110   //   value: <Resource ID of the drive directory for the origin>
111   //
112   //   key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin>
113   //   value: <Resource ID of the drive directory for the origin>
114   //
115   // Version 1 database format (changed keys/fields are marked with '*'):
116   // * key: "VERSION" (new)
117   // * value: 1
118   //
119   //   key: "CHANGE_STAMP"
120   //   value: <Largest Changestamp>
121   //
122   //   key: "SYNC_ROOT_DIR"
123   //   value: <Resource ID of the sync root directory>
124   //
125   // * key: "METADATA: " + <Origin and URL> (changed)
126   // * value: <Serialized DriveMetadata>
127   //
128   //   key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin>
129   //   value: <Resource ID of the drive directory for the origin>
130   //
131   //   key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin>
132   //   value: <Resource ID of the drive directory for the origin>
133   //
134   //   key: "DISABLED_ORIGIN: " + <URL string of a disabled origin>
135   //   value: <Resource ID of the drive directory for the origin>
136
137   const char kDatabaseVersionKey[] = "VERSION";
138   const char kDriveMetadataKeyPrefix[] = "METADATA: ";
139   const char kMetadataKeySeparator = ' ';
140
141   leveldb::WriteBatch write_batch;
142   write_batch.Put(kDatabaseVersionKey, "1");
143
144   scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions()));
145   for (itr->Seek(kDriveMetadataKeyPrefix); itr->Valid(); itr->Next()) {
146     std::string key = itr->key().ToString();
147     if (!StartsWithASCII(key, kDriveMetadataKeyPrefix, true))
148       break;
149     std::string serialized_url(RemovePrefix(key, kDriveMetadataKeyPrefix));
150
151     GURL origin;
152     base::FilePath path;
153     bool success = ParseV0FormatFileSystemURL(
154         GURL(serialized_url), &origin, &path);
155     DCHECK(success) << serialized_url;
156     std::string new_key = kDriveMetadataKeyPrefix + origin.spec() +
157         kMetadataKeySeparator + path.AsUTF8Unsafe();
158
159     write_batch.Put(new_key, itr->value());
160     write_batch.Delete(key);
161   }
162
163   return LevelDBStatusToSyncStatusCode(
164       db->Write(leveldb::WriteOptions(), &write_batch));
165 }
166
167 SyncStatusCode MigrateDatabaseFromV1ToV2(leveldb::DB* db) {
168   // Strips prefix of WAPI resource ID, and discards batch sync origins.
169   // (i.e. "file:xxxx" => "xxxx", "folder:yyyy" => "yyyy")
170   //
171   // Version 2 database format (changed keys/fields are marked with '*'):
172   //   key: "VERSION"
173   // * value: 2
174   //
175   //   key: "CHANGE_STAMP"
176   //   value: <Largest Changestamp>
177   //
178   //   key: "SYNC_ROOT_DIR"
179   // * value: <Resource ID of the sync root directory> (striped)
180   //
181   //   key: "METADATA: " + <Origin and URL>
182   // * value: <Serialized DriveMetadata> (stripped)
183   //
184   // * key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin> (deleted)
185   // * value: <Resource ID of the drive directory for the origin> (deleted)
186   //
187   //   key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin>
188   // * value: <Resource ID of the drive directory for the origin> (stripped)
189   //
190   //   key: "DISABLED_ORIGIN: " + <URL string of a disabled origin>
191   // * value: <Resource ID of the drive directory for the origin> (stripped)
192
193   const char kDatabaseVersionKey[] = "VERSION";
194   const char kSyncRootDirectoryKey[] = "SYNC_ROOT_DIR";
195   const char kDriveMetadataKeyPrefix[] = "METADATA: ";
196   const char kDriveBatchSyncOriginKeyPrefix[] = "BSYNC_ORIGIN: ";
197   const char kDriveIncrementalSyncOriginKeyPrefix[] = "ISYNC_ORIGIN: ";
198   const char kDriveDisabledOriginKeyPrefix[] = "DISABLED_ORIGIN: ";
199
200   leveldb::WriteBatch write_batch;
201   write_batch.Put(kDatabaseVersionKey, "2");
202
203   scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions()));
204   for (itr->SeekToFirst(); itr->Valid(); itr->Next()) {
205     std::string key = itr->key().ToString();
206
207     // Strip resource id for the sync root directory.
208     if (StartsWithASCII(key, kSyncRootDirectoryKey, true)) {
209       write_batch.Put(key, RemoveWapiIdPrefix(itr->value().ToString()));
210       continue;
211     }
212
213     // Strip resource ids in the drive metadata.
214     if (StartsWithASCII(key, kDriveMetadataKeyPrefix, true)) {
215       DriveMetadata metadata;
216       bool success = metadata.ParseFromString(itr->value().ToString());
217       DCHECK(success);
218
219       metadata.set_resource_id(RemoveWapiIdPrefix(metadata.resource_id()));
220       std::string metadata_string;
221       metadata.SerializeToString(&metadata_string);
222
223       write_batch.Put(key, metadata_string);
224       continue;
225     }
226
227     // Deprecate legacy batch sync origin entries that are no longer needed.
228     if (StartsWithASCII(key, kDriveBatchSyncOriginKeyPrefix, true)) {
229       write_batch.Delete(key);
230       continue;
231     }
232
233     // Strip resource ids of the incremental sync origins.
234     if (StartsWithASCII(key, kDriveIncrementalSyncOriginKeyPrefix, true)) {
235       write_batch.Put(key, RemoveWapiIdPrefix(itr->value().ToString()));
236       continue;
237     }
238
239     // Strip resource ids of the disabled sync origins.
240     if (StartsWithASCII(key, kDriveDisabledOriginKeyPrefix, true)) {
241       write_batch.Put(key, RemoveWapiIdPrefix(itr->value().ToString()));
242       continue;
243     }
244   }
245
246   return LevelDBStatusToSyncStatusCode(
247       db->Write(leveldb::WriteOptions(), &write_batch));
248 }
249
250 }  // namespace drive_backend
251 }  // namespace sync_file_system