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/metadata_db_migration_util.h"
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"
12 #include "webkit/browser/fileapi/file_system_url.h"
13 #include "webkit/common/fileapi/file_system_types.h"
15 namespace sync_file_system
{
16 namespace drive_backend
{
20 const base::FilePath::CharType kV0FormatPathPrefix
[] =
21 FILE_PATH_LITERAL("drive/");
22 const char kWapiFileIdPrefix
[] = "file:";
23 const char kWapiFolderIdPrefix
[] = "folder:";
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());
33 bool ParseV0FormatFileSystemURL(const GURL
& url
,
35 base::FilePath
* path
) {
36 fileapi::FileSystemType mount_type
;
37 base::FilePath virtual_path
;
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();
46 base::FilePath::StringType prefix
=
47 base::FilePath(kV0FormatPathPrefix
).NormalizePathSeparators().value();
48 if (virtual_path
.value().substr(0, prefix
.size()) != prefix
)
51 *path
= base::FilePath(virtual_path
.value().substr(prefix
.size()));
55 std::string
AddWapiFilePrefix(const std::string
& resource_id
) {
56 DCHECK(!StartsWithASCII(resource_id
, kWapiFileIdPrefix
, true));
57 DCHECK(!StartsWithASCII(resource_id
, kWapiFolderIdPrefix
, true));
59 if (resource_id
.empty() ||
60 StartsWithASCII(resource_id
, kWapiFileIdPrefix
, true) ||
61 StartsWithASCII(resource_id
, kWapiFolderIdPrefix
, true))
63 return kWapiFileIdPrefix
+ resource_id
;
66 std::string
AddWapiFolderPrefix(const std::string
& resource_id
) {
67 DCHECK(!StartsWithASCII(resource_id
, kWapiFileIdPrefix
, true));
68 DCHECK(!StartsWithASCII(resource_id
, kWapiFolderIdPrefix
, true));
70 if (resource_id
.empty() ||
71 StartsWithASCII(resource_id
, kWapiFileIdPrefix
, true) ||
72 StartsWithASCII(resource_id
, kWapiFolderIdPrefix
, true))
74 return kWapiFolderIdPrefix
+ resource_id
;
77 std::string
AddWapiIdPrefix(const std::string
& resource_id
,
78 DriveMetadata_ResourceType 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
);
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
);
97 SyncStatusCode
MigrateDatabaseFromV0ToV1(leveldb::DB
* db
) {
98 // Version 0 database format:
99 // key: "CHANGE_STAMP"
100 // value: <Largest Changestamp>
102 // key: "SYNC_ROOT_DIR"
103 // value: <Resource ID of the sync root directory>
105 // key: "METADATA: " +
106 // <FileSystemURL serialized by SerializeSyncableFileSystemURL>
107 // value: <Serialized DriveMetadata>
109 // key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin>
110 // value: <Resource ID of the drive directory for the origin>
112 // key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin>
113 // value: <Resource ID of the drive directory for the origin>
115 // Version 1 database format (changed keys/fields are marked with '*'):
116 // * key: "VERSION" (new)
119 // key: "CHANGE_STAMP"
120 // value: <Largest Changestamp>
122 // key: "SYNC_ROOT_DIR"
123 // value: <Resource ID of the sync root directory>
125 // * key: "METADATA: " + <Origin and URL> (changed)
126 // * value: <Serialized DriveMetadata>
128 // key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin>
129 // value: <Resource ID of the drive directory for the origin>
131 // key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin>
132 // value: <Resource ID of the drive directory for the origin>
134 // key: "DISABLED_ORIGIN: " + <URL string of a disabled origin>
135 // value: <Resource ID of the drive directory for the origin>
137 const char kDatabaseVersionKey
[] = "VERSION";
138 const char kDriveMetadataKeyPrefix
[] = "METADATA: ";
139 const char kMetadataKeySeparator
= ' ';
141 leveldb::WriteBatch write_batch
;
142 write_batch
.Put(kDatabaseVersionKey
, "1");
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))
149 std::string
serialized_url(RemovePrefix(key
, kDriveMetadataKeyPrefix
));
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();
159 write_batch
.Put(new_key
, itr
->value());
160 write_batch
.Delete(key
);
163 return LevelDBStatusToSyncStatusCode(
164 db
->Write(leveldb::WriteOptions(), &write_batch
));
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")
171 // Version 2 database format (changed keys/fields are marked with '*'):
175 // key: "CHANGE_STAMP"
176 // value: <Largest Changestamp>
178 // key: "SYNC_ROOT_DIR"
179 // * value: <Resource ID of the sync root directory> (striped)
181 // key: "METADATA: " + <Origin and URL>
182 // * value: <Serialized DriveMetadata> (stripped)
184 // * key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin> (deleted)
185 // * value: <Resource ID of the drive directory for the origin> (deleted)
187 // key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin>
188 // * value: <Resource ID of the drive directory for the origin> (stripped)
190 // key: "DISABLED_ORIGIN: " + <URL string of a disabled origin>
191 // * value: <Resource ID of the drive directory for the origin> (stripped)
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: ";
200 leveldb::WriteBatch write_batch
;
201 write_batch
.Put(kDatabaseVersionKey
, "2");
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();
207 // Strip resource id for the sync root directory.
208 if (StartsWithASCII(key
, kSyncRootDirectoryKey
, true)) {
209 write_batch
.Put(key
, RemoveWapiIdPrefix(itr
->value().ToString()));
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());
219 metadata
.set_resource_id(RemoveWapiIdPrefix(metadata
.resource_id()));
220 std::string metadata_string
;
221 metadata
.SerializeToString(&metadata_string
);
223 write_batch
.Put(key
, metadata_string
);
227 // Deprecate legacy batch sync origin entries that are no longer needed.
228 if (StartsWithASCII(key
, kDriveBatchSyncOriginKeyPrefix
, true)) {
229 write_batch
.Delete(key
);
233 // Strip resource ids of the incremental sync origins.
234 if (StartsWithASCII(key
, kDriveIncrementalSyncOriginKeyPrefix
, true)) {
235 write_batch
.Put(key
, RemoveWapiIdPrefix(itr
->value().ToString()));
239 // Strip resource ids of the disabled sync origins.
240 if (StartsWithASCII(key
, kDriveDisabledOriginKeyPrefix
, true)) {
241 write_batch
.Put(key
, RemoveWapiIdPrefix(itr
->value().ToString()));
246 return LevelDBStatusToSyncStatusCode(
247 db
->Write(leveldb::WriteOptions(), &write_batch
));
250 } // namespace drive_backend
251 } // namespace sync_file_system