Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "webkit/fileapi/file_system_directory_database.h" | 5 #include "webkit/fileapi/file_system_directory_database.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 | 8 |
| 9 #include "base/file_util.h" | |
| 9 #include "base/location.h" | 10 #include "base/location.h" |
| 10 #include "base/pickle.h" | 11 #include "base/pickle.h" |
| 11 #include "base/string_number_conversions.h" | 12 #include "base/string_number_conversions.h" |
| 12 #include "base/string_util.h" | 13 #include "base/string_util.h" |
| 13 #include "base/sys_string_conversions.h" | 14 #include "base/utf_string_conversions.h" |
| 14 #include "third_party/leveldatabase/src/include/leveldb/iterator.h" | 15 #include "third_party/leveldatabase/src/include/leveldb/iterator.h" |
| 16 #include "third_party/leveldatabase/src/include/leveldb/status.h" | |
| 15 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" | 17 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" |
| 16 #include "webkit/fileapi/file_system_util.h" | 18 #include "webkit/fileapi/file_system_util.h" |
| 17 | 19 |
| 18 namespace { | 20 namespace { |
| 19 | 21 |
| 22 std::string FilePathStringToString(const FilePath::StringType& path) { | |
|
kinuko
2012/03/26 05:25:09
Hmm. Could we move this into file_system_util.h o
tzik
2012/03/26 08:04:56
Done.
| |
| 23 // TODO(tzik): Unify this to FilePathToString in | |
| 24 // third_party/leveldatabase/env_chromium.cc. | |
| 25 #if defined(OS_WIN) | |
| 26 return UTF16ToUTF8(path); | |
| 27 #elif defined(OS_POSIX) | |
| 28 return path; | |
| 29 #endif | |
| 30 } | |
| 31 | |
| 32 std::string FilePathToString(const FilePath& path) { | |
| 33 return FilePathStringToString(path.value()); | |
| 34 } | |
| 35 | |
| 36 FilePath::StringType StringToFilePathString(const std::string& path_string) { | |
| 37 // TODO(tzik): Unify this to CreateFilePath in | |
| 38 // third_party/leveldatabase/env_chromium.cc. | |
| 39 #if defined(OS_WIN) | |
| 40 return UTF8ToUTF16(path_string); | |
| 41 #elif defined(OS_POSIX) | |
| 42 return path_string; | |
| 43 #endif | |
| 44 } | |
| 45 | |
| 46 FilePath StringToFilePath(const std::string& path_string) { | |
| 47 return FilePath(StringToFilePathString(path_string)); | |
| 48 } | |
| 49 | |
| 20 bool PickleFromFileInfo( | 50 bool PickleFromFileInfo( |
| 21 const fileapi::FileSystemDirectoryDatabase::FileInfo& info, | 51 const fileapi::FileSystemDirectoryDatabase::FileInfo& info, |
| 22 Pickle* pickle) { | 52 Pickle* pickle) { |
| 23 DCHECK(pickle); | 53 DCHECK(pickle); |
| 24 std::string data_path; | 54 std::string data_path; |
| 25 // Round off here to match the behavior of the filesystem on real files. | 55 // Round off here to match the behavior of the filesystem on real files. |
| 26 base::Time time = | 56 base::Time time = |
| 27 base::Time::FromDoubleT(floor(info.modification_time.ToDoubleT())); | 57 base::Time::FromDoubleT(floor(info.modification_time.ToDoubleT())); |
| 28 std::string name; | 58 std::string name; |
| 29 | 59 |
| 30 #if defined(OS_POSIX) | 60 data_path = FilePathToString(info.data_path); |
| 31 data_path = info.data_path.value(); | 61 name = FilePathStringToString(info.name); |
| 32 name = info.name; | 62 |
| 33 #elif defined(OS_WIN) | |
| 34 data_path = base::SysWideToUTF8(info.data_path.value()); | |
| 35 name = base::SysWideToUTF8(info.name); | |
| 36 #endif | |
| 37 if (pickle->WriteInt64(info.parent_id) && | 63 if (pickle->WriteInt64(info.parent_id) && |
| 38 pickle->WriteString(data_path) && | 64 pickle->WriteString(data_path) && |
| 39 pickle->WriteString(name) && | 65 pickle->WriteString(name) && |
| 40 pickle->WriteInt64(time.ToInternalValue())) | 66 pickle->WriteInt64(time.ToInternalValue())) |
| 41 return true; | 67 return true; |
| 42 | 68 |
| 43 NOTREACHED(); | 69 NOTREACHED(); |
| 44 return false; | 70 return false; |
| 45 } | 71 } |
| 46 | 72 |
| 47 bool FileInfoFromPickle( | 73 bool FileInfoFromPickle( |
| 48 const Pickle& pickle, | 74 const Pickle& pickle, |
| 49 fileapi::FileSystemDirectoryDatabase::FileInfo* info) { | 75 fileapi::FileSystemDirectoryDatabase::FileInfo* info) { |
| 50 PickleIterator iter(pickle); | 76 PickleIterator iter(pickle); |
| 51 std::string data_path; | 77 std::string data_path; |
| 52 std::string name; | 78 std::string name; |
| 53 int64 internal_time; | 79 int64 internal_time; |
| 54 | 80 |
| 55 if (pickle.ReadInt64(&iter, &info->parent_id) && | 81 if (pickle.ReadInt64(&iter, &info->parent_id) && |
| 56 pickle.ReadString(&iter, &data_path) && | 82 pickle.ReadString(&iter, &data_path) && |
| 57 pickle.ReadString(&iter, &name) && | 83 pickle.ReadString(&iter, &name) && |
| 58 pickle.ReadInt64(&iter, &internal_time)) { | 84 pickle.ReadInt64(&iter, &internal_time)) { |
| 59 #if defined(OS_POSIX) | 85 |
| 60 info->data_path = FilePath(data_path); | 86 info->data_path = FilePath(StringToFilePath(data_path)); |
| 61 info->name = name; | 87 info->name = StringToFilePathString(name); |
| 62 #elif defined(OS_WIN) | |
| 63 info->data_path = FilePath(base::SysUTF8ToWide(data_path)); | |
| 64 info->name = base::SysUTF8ToWide(name); | |
| 65 #endif | |
| 66 info->modification_time = base::Time::FromInternalValue(internal_time); | 88 info->modification_time = base::Time::FromInternalValue(internal_time); |
| 67 return true; | 89 return true; |
| 68 } | 90 } |
| 69 LOG(ERROR) << "Pickle could not be digested!"; | 91 LOG(ERROR) << "Pickle could not be digested!"; |
| 70 return false; | 92 return false; |
| 71 } | 93 } |
| 72 | 94 |
| 95 const FilePath::CharType kDirectoryDatabaseName[] = FILE_PATH_LITERAL("Paths"); | |
| 73 const char kChildLookupPrefix[] = "CHILD_OF:"; | 96 const char kChildLookupPrefix[] = "CHILD_OF:"; |
| 74 const char kChildLookupSeparator[] = ":"; | 97 const char kChildLookupSeparator[] = ":"; |
| 75 const char kLastFileIdKey[] = "LAST_FILE_ID"; | 98 const char kLastFileIdKey[] = "LAST_FILE_ID"; |
| 76 const char kLastIntegerKey[] = "LAST_INTEGER"; | 99 const char kLastIntegerKey[] = "LAST_INTEGER"; |
| 77 | 100 |
| 78 std::string GetChildLookupKey( | 101 std::string GetChildLookupKey( |
| 79 fileapi::FileSystemDirectoryDatabase::FileId parent_id, | 102 fileapi::FileSystemDirectoryDatabase::FileId parent_id, |
| 80 const FilePath::StringType& child_name) { | 103 const FilePath::StringType& child_name) { |
| 81 std::string name; | 104 std::string name; |
| 82 #if defined(OS_POSIX) | 105 name = FilePathStringToString(child_name); |
| 83 name = child_name; | |
| 84 #elif defined(OS_WIN) | |
| 85 name = base::SysWideToUTF8(child_name); | |
| 86 #endif | |
| 87 return std::string(kChildLookupPrefix) + base::Int64ToString(parent_id) + | 106 return std::string(kChildLookupPrefix) + base::Int64ToString(parent_id) + |
| 88 std::string(kChildLookupSeparator) + name; | 107 std::string(kChildLookupSeparator) + name; |
| 89 } | 108 } |
| 90 | 109 |
| 91 std::string GetChildListingKeyPrefix( | 110 std::string GetChildListingKeyPrefix( |
| 92 fileapi::FileSystemDirectoryDatabase::FileId parent_id) { | 111 fileapi::FileSystemDirectoryDatabase::FileId parent_id) { |
| 93 return std::string(kChildLookupPrefix) + base::Int64ToString(parent_id) + | 112 return std::string(kChildLookupPrefix) + base::Int64ToString(parent_id) + |
| 94 std::string(kChildLookupSeparator); | 113 std::string(kChildLookupSeparator); |
| 95 } | 114 } |
| 96 | 115 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 110 } // namespace | 129 } // namespace |
| 111 | 130 |
| 112 namespace fileapi { | 131 namespace fileapi { |
| 113 | 132 |
| 114 FileSystemDirectoryDatabase::FileInfo::FileInfo() : parent_id(0) { | 133 FileSystemDirectoryDatabase::FileInfo::FileInfo() : parent_id(0) { |
| 115 } | 134 } |
| 116 | 135 |
| 117 FileSystemDirectoryDatabase::FileInfo::~FileInfo() { | 136 FileSystemDirectoryDatabase::FileInfo::~FileInfo() { |
| 118 } | 137 } |
| 119 | 138 |
| 120 FileSystemDirectoryDatabase::FileSystemDirectoryDatabase(const FilePath& path) { | 139 FileSystemDirectoryDatabase::FileSystemDirectoryDatabase( |
| 121 #if defined(OS_POSIX) | 140 const FilePath& sandbox_directory) |
| 122 path_ = path.value(); | 141 : sandbox_directory_(sandbox_directory) { |
| 123 #elif defined(OS_WIN) | |
| 124 path_ = base::SysWideToUTF8(path.value()); | |
| 125 #endif | |
| 126 } | 142 } |
| 127 | 143 |
| 128 FileSystemDirectoryDatabase::~FileSystemDirectoryDatabase() { | 144 FileSystemDirectoryDatabase::~FileSystemDirectoryDatabase() { |
| 129 } | 145 } |
| 130 | 146 |
| 131 bool FileSystemDirectoryDatabase::GetChildWithName( | 147 bool FileSystemDirectoryDatabase::GetChildWithName( |
| 132 FileId parent_id, const FilePath::StringType& name, FileId* child_id) { | 148 FileId parent_id, const FilePath::StringType& name, FileId* child_id) { |
| 133 if (!Init()) | 149 if (!Init(FAIL_ON_CORRUPTION)) |
| 134 return false; | 150 return false; |
| 135 DCHECK(child_id); | 151 DCHECK(child_id); |
| 136 std::string child_key = GetChildLookupKey(parent_id, name); | 152 std::string child_key = GetChildLookupKey(parent_id, name); |
| 137 std::string child_id_string; | 153 std::string child_id_string; |
| 138 leveldb::Status status = | 154 leveldb::Status status = |
| 139 db_->Get(leveldb::ReadOptions(), child_key, &child_id_string); | 155 db_->Get(leveldb::ReadOptions(), child_key, &child_id_string); |
| 140 if (status.IsNotFound()) | 156 if (status.IsNotFound()) |
| 141 return false; | 157 return false; |
| 142 if (status.ok()) { | 158 if (status.ok()) { |
| 143 if (!base::StringToInt64(child_id_string, child_id)) { | 159 if (!base::StringToInt64(child_id_string, child_id)) { |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 164 if (!GetChildWithName(local_id, name, &local_id)) | 180 if (!GetChildWithName(local_id, name, &local_id)) |
| 165 return false; | 181 return false; |
| 166 } | 182 } |
| 167 *file_id = local_id; | 183 *file_id = local_id; |
| 168 return true; | 184 return true; |
| 169 } | 185 } |
| 170 | 186 |
| 171 bool FileSystemDirectoryDatabase::ListChildren( | 187 bool FileSystemDirectoryDatabase::ListChildren( |
| 172 FileId parent_id, std::vector<FileId>* children) { | 188 FileId parent_id, std::vector<FileId>* children) { |
| 173 // Check to add later: fail if parent is a file, at least in debug builds. | 189 // Check to add later: fail if parent is a file, at least in debug builds. |
| 174 if (!Init()) | 190 if (!Init(FAIL_ON_CORRUPTION)) |
| 175 return false; | 191 return false; |
| 176 DCHECK(children); | 192 DCHECK(children); |
| 177 std::string child_key_prefix = GetChildListingKeyPrefix(parent_id); | 193 std::string child_key_prefix = GetChildListingKeyPrefix(parent_id); |
| 178 | 194 |
| 179 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions())); | 195 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions())); |
| 180 iter->Seek(child_key_prefix); | 196 iter->Seek(child_key_prefix); |
| 181 children->clear(); | 197 children->clear(); |
| 182 while (iter->Valid() && | 198 while (iter->Valid() && |
| 183 StartsWithASCII(iter->key().ToString(), child_key_prefix, true)) { | 199 StartsWithASCII(iter->key().ToString(), child_key_prefix, true)) { |
| 184 std::string child_id_string = iter->value().ToString(); | 200 std::string child_id_string = iter->value().ToString(); |
| 185 FileId child_id; | 201 FileId child_id; |
| 186 if (!base::StringToInt64(child_id_string, &child_id)) { | 202 if (!base::StringToInt64(child_id_string, &child_id)) { |
| 187 LOG(ERROR) << "Hit database corruption!"; | 203 LOG(ERROR) << "Hit database corruption!"; |
| 188 return false; | 204 return false; |
| 189 } | 205 } |
| 190 children->push_back(child_id); | 206 children->push_back(child_id); |
| 191 iter->Next(); | 207 iter->Next(); |
| 192 } | 208 } |
| 193 return true; | 209 return true; |
| 194 } | 210 } |
| 195 | 211 |
| 196 bool FileSystemDirectoryDatabase::GetFileInfo(FileId file_id, FileInfo* info) { | 212 bool FileSystemDirectoryDatabase::GetFileInfo(FileId file_id, FileInfo* info) { |
| 197 if (!Init()) | 213 if (!Init(FAIL_ON_CORRUPTION)) |
| 198 return false; | 214 return false; |
| 199 DCHECK(info); | 215 DCHECK(info); |
| 200 std::string file_key = GetFileLookupKey(file_id); | 216 std::string file_key = GetFileLookupKey(file_id); |
| 201 std::string file_data_string; | 217 std::string file_data_string; |
| 202 leveldb::Status status = | 218 leveldb::Status status = |
| 203 db_->Get(leveldb::ReadOptions(), file_key, &file_data_string); | 219 db_->Get(leveldb::ReadOptions(), file_key, &file_data_string); |
| 204 if (status.ok()) { | 220 if (status.ok()) { |
| 205 return FileInfoFromPickle( | 221 return FileInfoFromPickle( |
| 206 Pickle(file_data_string.data(), file_data_string.length()), info); | 222 Pickle(file_data_string.data(), file_data_string.length()), info); |
| 207 } | 223 } |
| 208 // Special-case the root, for databases that haven't been initialized yet. | 224 // Special-case the root, for databases that haven't been initialized yet. |
| 209 // Without this, a query for the root's file info, made before creating the | 225 // Without this, a query for the root's file info, made before creating the |
| 210 // first file in the database, will fail and confuse callers. | 226 // first file in the database, will fail and confuse callers. |
| 211 if (status.IsNotFound() && !file_id) { | 227 if (status.IsNotFound() && !file_id) { |
| 212 info->name = FilePath::StringType(); | 228 info->name = FilePath::StringType(); |
| 213 info->data_path = FilePath(); | 229 info->data_path = FilePath(); |
| 214 info->modification_time = base::Time::Now(); | 230 info->modification_time = base::Time::Now(); |
| 215 info->parent_id = 0; | 231 info->parent_id = 0; |
| 216 return true; | 232 return true; |
| 217 } | 233 } |
| 218 HandleError(FROM_HERE, status); | 234 HandleError(FROM_HERE, status); |
| 219 return false; | 235 return false; |
| 220 } | 236 } |
| 221 | 237 |
| 222 bool FileSystemDirectoryDatabase::AddFileInfo( | 238 bool FileSystemDirectoryDatabase::AddFileInfo( |
| 223 const FileInfo& info, FileId* file_id) { | 239 const FileInfo& info, FileId* file_id) { |
| 224 if (!Init()) | 240 if (!Init(FAIL_ON_CORRUPTION)) |
| 225 return false; | 241 return false; |
| 226 DCHECK(file_id); | 242 DCHECK(file_id); |
| 227 std::string child_key = GetChildLookupKey(info.parent_id, info.name); | 243 std::string child_key = GetChildLookupKey(info.parent_id, info.name); |
| 228 std::string child_id_string; | 244 std::string child_id_string; |
| 229 leveldb::Status status = | 245 leveldb::Status status = |
| 230 db_->Get(leveldb::ReadOptions(), child_key, &child_id_string); | 246 db_->Get(leveldb::ReadOptions(), child_key, &child_id_string); |
| 231 if (status.ok()) { | 247 if (status.ok()) { |
| 232 LOG(ERROR) << "File exists already!"; | 248 LOG(ERROR) << "File exists already!"; |
| 233 return false; | 249 return false; |
| 234 } | 250 } |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 256 status = db_->Write(leveldb::WriteOptions(), &batch); | 272 status = db_->Write(leveldb::WriteOptions(), &batch); |
| 257 if (!status.ok()) { | 273 if (!status.ok()) { |
| 258 HandleError(FROM_HERE, status); | 274 HandleError(FROM_HERE, status); |
| 259 return false; | 275 return false; |
| 260 } | 276 } |
| 261 *file_id = temp_id; | 277 *file_id = temp_id; |
| 262 return true; | 278 return true; |
| 263 } | 279 } |
| 264 | 280 |
| 265 bool FileSystemDirectoryDatabase::RemoveFileInfo(FileId file_id) { | 281 bool FileSystemDirectoryDatabase::RemoveFileInfo(FileId file_id) { |
| 266 if (!Init()) | 282 if (!Init(FAIL_ON_CORRUPTION)) |
| 267 return false; | 283 return false; |
| 268 leveldb::WriteBatch batch; | 284 leveldb::WriteBatch batch; |
| 269 if (!RemoveFileInfoHelper(file_id, &batch)) | 285 if (!RemoveFileInfoHelper(file_id, &batch)) |
| 270 return false; | 286 return false; |
| 271 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); | 287 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); |
| 272 if (!status.ok()) { | 288 if (!status.ok()) { |
| 273 HandleError(FROM_HERE, status); | 289 HandleError(FROM_HERE, status); |
| 274 return false; | 290 return false; |
| 275 } | 291 } |
| 276 return true; | 292 return true; |
| 277 } | 293 } |
| 278 | 294 |
| 279 bool FileSystemDirectoryDatabase::UpdateFileInfo( | 295 bool FileSystemDirectoryDatabase::UpdateFileInfo( |
| 280 FileId file_id, const FileInfo& new_info) { | 296 FileId file_id, const FileInfo& new_info) { |
| 281 // TODO: We should also check to see that this doesn't create a loop, but | 297 // TODO: We should also check to see that this doesn't create a loop, but |
| 282 // perhaps only in a debug build. | 298 // perhaps only in a debug build. |
| 283 if (!Init()) | 299 if (!Init(FAIL_ON_CORRUPTION)) |
| 284 return false; | 300 return false; |
| 285 DCHECK(file_id); // You can't remove the root, ever. Just delete the DB. | 301 DCHECK(file_id); // You can't remove the root, ever. Just delete the DB. |
| 286 FileInfo old_info; | 302 FileInfo old_info; |
| 287 if (!GetFileInfo(file_id, &old_info)) | 303 if (!GetFileInfo(file_id, &old_info)) |
| 288 return false; | 304 return false; |
| 289 if (old_info.parent_id != new_info.parent_id && | 305 if (old_info.parent_id != new_info.parent_id && |
| 290 !VerifyIsDirectory(new_info.parent_id)) | 306 !VerifyIsDirectory(new_info.parent_id)) |
| 291 return false; | 307 return false; |
| 292 if (old_info.parent_id != new_info.parent_id || | 308 if (old_info.parent_id != new_info.parent_id || |
| 293 old_info.name != new_info.name) { | 309 old_info.name != new_info.name) { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 357 pickle.size())); | 373 pickle.size())); |
| 358 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); | 374 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); |
| 359 if (!status.ok()) { | 375 if (!status.ok()) { |
| 360 HandleError(FROM_HERE, status); | 376 HandleError(FROM_HERE, status); |
| 361 return false; | 377 return false; |
| 362 } | 378 } |
| 363 return true; | 379 return true; |
| 364 } | 380 } |
| 365 | 381 |
| 366 bool FileSystemDirectoryDatabase::GetNextInteger(int64* next) { | 382 bool FileSystemDirectoryDatabase::GetNextInteger(int64* next) { |
| 367 if (!Init()) | 383 if (!Init(FAIL_ON_CORRUPTION)) |
| 368 return false; | 384 return false; |
| 369 DCHECK(next); | 385 DCHECK(next); |
| 370 std::string int_string; | 386 std::string int_string; |
| 371 leveldb::Status status = | 387 leveldb::Status status = |
| 372 db_->Get(leveldb::ReadOptions(), LastIntegerKey(), &int_string); | 388 db_->Get(leveldb::ReadOptions(), LastIntegerKey(), &int_string); |
| 373 if (status.ok()) { | 389 if (status.ok()) { |
| 374 int64 temp; | 390 int64 temp; |
| 375 if (!base::StringToInt64(int_string, &temp)) { | 391 if (!base::StringToInt64(int_string, &temp)) { |
| 376 LOG(ERROR) << "Hit database corruption!"; | 392 LOG(ERROR) << "Hit database corruption!"; |
| 377 return false; | 393 return false; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 392 } | 408 } |
| 393 // The database must not yet exist; initialize it. | 409 // The database must not yet exist; initialize it. |
| 394 if (!StoreDefaultValues()) | 410 if (!StoreDefaultValues()) |
| 395 return false; | 411 return false; |
| 396 | 412 |
| 397 return GetNextInteger(next); | 413 return GetNextInteger(next); |
| 398 } | 414 } |
| 399 | 415 |
| 400 // static | 416 // static |
| 401 bool FileSystemDirectoryDatabase::DestroyDatabase(const FilePath& path) { | 417 bool FileSystemDirectoryDatabase::DestroyDatabase(const FilePath& path) { |
| 402 std::string name; | 418 std::string name = FilePathToString(path.Append(kDirectoryDatabaseName)); |
| 403 #if defined(OS_POSIX) | |
| 404 name = path.value(); | |
| 405 #elif defined(OS_WIN) | |
| 406 name = base::SysWideToUTF8(path.value()); | |
| 407 #endif | |
| 408 leveldb::Status status = leveldb::DestroyDB(name, leveldb::Options()); | 419 leveldb::Status status = leveldb::DestroyDB(name, leveldb::Options()); |
| 409 if (status.ok()) | 420 if (status.ok()) |
| 410 return true; | 421 return true; |
| 411 LOG(WARNING) << "Failed to destroy a database with status " << | 422 LOG(WARNING) << "Failed to destroy a database with status " << |
| 412 status.ToString(); | 423 status.ToString(); |
| 413 return false; | 424 return false; |
| 414 } | 425 } |
| 415 | 426 |
| 416 bool FileSystemDirectoryDatabase::Init() { | 427 bool FileSystemDirectoryDatabase::Init(RecoveryOption recovery_option) { |
| 417 if (db_.get()) | 428 if (db_.get()) |
| 418 return true; | 429 return true; |
| 419 | 430 |
| 420 leveldb::Options options; | 431 std::string path = |
| 421 options.create_if_missing = true; | 432 FilePathToString(sandbox_directory_.Append(kDirectoryDatabaseName)); |
| 422 leveldb::DB* db; | 433 leveldb::Options options; |
| 423 leveldb::Status status = leveldb::DB::Open(options, path_, &db); | 434 options.create_if_missing = true; |
| 424 if (status.ok()) { | 435 leveldb::DB* db; |
| 425 db_.reset(db); | 436 leveldb::Status status = leveldb::DB::Open(options, path, &db); |
| 426 return true; | 437 // TODO(tzik): Collect status metrics here. |
| 427 } | 438 if (status.ok()) { |
| 428 HandleError(FROM_HERE, status); | 439 db_.reset(db); |
| 429 return false; | 440 return true; |
| 441 } | |
| 442 HandleError(FROM_HERE, status); | |
| 443 | |
| 444 if (recovery_option == FAIL_ON_CORRUPTION) | |
| 445 return false; | |
| 446 | |
| 447 DCHECK_EQ(DELETE_ON_CORRUPTION, recovery_option); | |
| 448 if (!file_util::Delete(sandbox_directory_, true)) | |
| 449 return false; | |
| 450 if (!file_util::CreateDirectory(sandbox_directory_)) | |
| 451 return false; | |
| 452 return Init(FAIL_ON_CORRUPTION); | |
| 430 } | 453 } |
| 431 | 454 |
| 432 bool FileSystemDirectoryDatabase::StoreDefaultValues() { | 455 bool FileSystemDirectoryDatabase::StoreDefaultValues() { |
| 433 // Verify that this is a totally new database, and initialize it. | 456 // Verify that this is a totally new database, and initialize it. |
| 434 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions())); | 457 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions())); |
| 435 iter->SeekToFirst(); | 458 iter->SeekToFirst(); |
| 436 if (iter->Valid()) { // DB was not empty--we shouldn't have been called. | 459 if (iter->Valid()) { // DB was not empty--we shouldn't have been called. |
| 437 LOG(ERROR) << "File system origin database is corrupt!"; | 460 LOG(ERROR) << "File system origin database is corrupt!"; |
| 438 return false; | 461 return false; |
| 439 } | 462 } |
| 440 // This is always the first write into the database. If we ever add a | 463 // This is always the first write into the database. If we ever add a |
| 441 // version number, it should go in this transaction too. | 464 // version number, it should go in this transaction too. |
| 442 FileInfo root; | 465 FileInfo root; |
| 443 root.parent_id = 0; | 466 root.parent_id = 0; |
| 444 root.modification_time = base::Time::Now(); | 467 root.modification_time = base::Time::Now(); |
| 445 leveldb::WriteBatch batch; | 468 leveldb::WriteBatch batch; |
| 446 if (!AddFileInfoHelper(root, 0, &batch)) | 469 if (!AddFileInfoHelper(root, 0, &batch)) |
| 447 return false; | 470 return false; |
| 448 batch.Put(LastFileIdKey(), base::Int64ToString(0)); | 471 batch.Put(LastFileIdKey(), base::Int64ToString(0)); |
| 449 batch.Put(LastIntegerKey(), base::Int64ToString(-1)); | 472 batch.Put(LastIntegerKey(), base::Int64ToString(-1)); |
| 450 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); | 473 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); |
| 451 if (!status.ok()) { | 474 if (!status.ok()) { |
| 452 HandleError(FROM_HERE, status); | 475 HandleError(FROM_HERE, status); |
| 453 return false; | 476 return false; |
| 454 } | 477 } |
| 455 return true; | 478 return true; |
| 456 } | 479 } |
| 457 | 480 |
| 458 bool FileSystemDirectoryDatabase::GetLastFileId(FileId* file_id) { | 481 bool FileSystemDirectoryDatabase::GetLastFileId(FileId* file_id) { |
| 459 if (!Init()) | 482 if (!Init(FAIL_ON_CORRUPTION)) |
| 460 return false; | 483 return false; |
| 461 DCHECK(file_id); | 484 DCHECK(file_id); |
| 462 std::string id_string; | 485 std::string id_string; |
| 463 leveldb::Status status = | 486 leveldb::Status status = |
| 464 db_->Get(leveldb::ReadOptions(), LastFileIdKey(), &id_string); | 487 db_->Get(leveldb::ReadOptions(), LastFileIdKey(), &id_string); |
| 465 if (status.ok()) { | 488 if (status.ok()) { |
| 466 if (!base::StringToInt64(id_string, file_id)) { | 489 if (!base::StringToInt64(id_string, file_id)) { |
| 467 LOG(ERROR) << "Hit database corruption!"; | 490 LOG(ERROR) << "Hit database corruption!"; |
| 468 return false; | 491 return false; |
| 469 } | 492 } |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 539 | 562 |
| 540 void FileSystemDirectoryDatabase::HandleError( | 563 void FileSystemDirectoryDatabase::HandleError( |
| 541 const tracked_objects::Location& from_here, | 564 const tracked_objects::Location& from_here, |
| 542 leveldb::Status status) { | 565 leveldb::Status status) { |
| 543 LOG(ERROR) << "FileSystemDirectoryDatabase failed at: " | 566 LOG(ERROR) << "FileSystemDirectoryDatabase failed at: " |
| 544 << from_here.ToString() << " with error: " << status.ToString(); | 567 << from_here.ToString() << " with error: " << status.ToString(); |
| 545 db_.reset(); | 568 db_.reset(); |
| 546 } | 569 } |
| 547 | 570 |
| 548 } // namespace fileapi | 571 } // namespace fileapi |
| OLD | NEW |