| 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/sandbox_directory_database.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 #include <algorithm> | 8 #include <algorithm> |
| 9 #include <set> | 9 #include <set> |
| 10 #include <stack> | 10 #include <stack> |
| 11 | 11 |
| 12 #include "base/file_util.h" | 12 #include "base/file_util.h" |
| 13 #include "base/location.h" | 13 #include "base/location.h" |
| 14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 15 #include "base/pickle.h" | 15 #include "base/pickle.h" |
| 16 #include "base/string_util.h" | 16 #include "base/string_util.h" |
| 17 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
| 18 #include "third_party/leveldatabase/src/include/leveldb/db.h" | 18 #include "third_party/leveldatabase/src/include/leveldb/db.h" |
| 19 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" | 19 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" |
| 20 #include "webkit/fileapi/file_system_usage_cache.h" | 20 #include "webkit/fileapi/file_system_usage_cache.h" |
| 21 #include "webkit/fileapi/file_system_util.h" | 21 #include "webkit/fileapi/file_system_util.h" |
| 22 | 22 |
| 23 namespace { | 23 namespace { |
| 24 | 24 |
| 25 bool PickleFromFileInfo( | 25 bool PickleFromFileInfo( |
| 26 const fileapi::FileSystemDirectoryDatabase::FileInfo& info, | 26 const fileapi::SandboxDirectoryDatabase::FileInfo& info, |
| 27 Pickle* pickle) { | 27 Pickle* pickle) { |
| 28 DCHECK(pickle); | 28 DCHECK(pickle); |
| 29 std::string data_path; | 29 std::string data_path; |
| 30 // Round off here to match the behavior of the filesystem on real files. | 30 // Round off here to match the behavior of the filesystem on real files. |
| 31 base::Time time = | 31 base::Time time = |
| 32 base::Time::FromDoubleT(floor(info.modification_time.ToDoubleT())); | 32 base::Time::FromDoubleT(floor(info.modification_time.ToDoubleT())); |
| 33 std::string name; | 33 std::string name; |
| 34 | 34 |
| 35 data_path = fileapi::FilePathToString(info.data_path); | 35 data_path = fileapi::FilePathToString(info.data_path); |
| 36 name = fileapi::FilePathToString(base::FilePath(info.name)); | 36 name = fileapi::FilePathToString(base::FilePath(info.name)); |
| 37 | 37 |
| 38 if (pickle->WriteInt64(info.parent_id) && | 38 if (pickle->WriteInt64(info.parent_id) && |
| 39 pickle->WriteString(data_path) && | 39 pickle->WriteString(data_path) && |
| 40 pickle->WriteString(name) && | 40 pickle->WriteString(name) && |
| 41 pickle->WriteInt64(time.ToInternalValue())) | 41 pickle->WriteInt64(time.ToInternalValue())) |
| 42 return true; | 42 return true; |
| 43 | 43 |
| 44 NOTREACHED(); | 44 NOTREACHED(); |
| 45 return false; | 45 return false; |
| 46 } | 46 } |
| 47 | 47 |
| 48 bool FileInfoFromPickle( | 48 bool FileInfoFromPickle( |
| 49 const Pickle& pickle, | 49 const Pickle& pickle, |
| 50 fileapi::FileSystemDirectoryDatabase::FileInfo* info) { | 50 fileapi::SandboxDirectoryDatabase::FileInfo* info) { |
| 51 PickleIterator iter(pickle); | 51 PickleIterator iter(pickle); |
| 52 std::string data_path; | 52 std::string data_path; |
| 53 std::string name; | 53 std::string name; |
| 54 int64 internal_time; | 54 int64 internal_time; |
| 55 | 55 |
| 56 if (pickle.ReadInt64(&iter, &info->parent_id) && | 56 if (pickle.ReadInt64(&iter, &info->parent_id) && |
| 57 pickle.ReadString(&iter, &data_path) && | 57 pickle.ReadString(&iter, &data_path) && |
| 58 pickle.ReadString(&iter, &name) && | 58 pickle.ReadString(&iter, &name) && |
| 59 pickle.ReadInt64(&iter, &internal_time)) { | 59 pickle.ReadInt64(&iter, &internal_time)) { |
| 60 info->data_path = fileapi::StringToFilePath(data_path); | 60 info->data_path = fileapi::StringToFilePath(data_path); |
| 61 info->name = fileapi::StringToFilePath(name).value(); | 61 info->name = fileapi::StringToFilePath(name).value(); |
| 62 info->modification_time = base::Time::FromInternalValue(internal_time); | 62 info->modification_time = base::Time::FromInternalValue(internal_time); |
| 63 return true; | 63 return true; |
| 64 } | 64 } |
| 65 LOG(ERROR) << "Pickle could not be digested!"; | 65 LOG(ERROR) << "Pickle could not be digested!"; |
| 66 return false; | 66 return false; |
| 67 } | 67 } |
| 68 | 68 |
| 69 const base::FilePath::CharType kDirectoryDatabaseName[] = FILE_PATH_LITERAL("Pat
hs"); | 69 const base::FilePath::CharType kDirectoryDatabaseName[] = |
| 70 FILE_PATH_LITERAL("Paths"); |
| 70 const char kChildLookupPrefix[] = "CHILD_OF:"; | 71 const char kChildLookupPrefix[] = "CHILD_OF:"; |
| 71 const char kChildLookupSeparator[] = ":"; | 72 const char kChildLookupSeparator[] = ":"; |
| 72 const char kLastFileIdKey[] = "LAST_FILE_ID"; | 73 const char kLastFileIdKey[] = "LAST_FILE_ID"; |
| 73 const char kLastIntegerKey[] = "LAST_INTEGER"; | 74 const char kLastIntegerKey[] = "LAST_INTEGER"; |
| 74 const int64 kMinimumReportIntervalHours = 1; | 75 const int64 kMinimumReportIntervalHours = 1; |
| 75 const char kInitStatusHistogramLabel[] = "FileSystem.DirectoryDatabaseInit"; | 76 const char kInitStatusHistogramLabel[] = "FileSystem.DirectoryDatabaseInit"; |
| 76 const char kDatabaseRepairHistogramLabel[] = | 77 const char kDatabaseRepairHistogramLabel[] = |
| 77 "FileSystem.DirectoryDatabaseRepair"; | 78 "FileSystem.DirectoryDatabaseRepair"; |
| 78 | 79 |
| 79 enum InitStatus { | 80 enum InitStatus { |
| 80 INIT_STATUS_OK = 0, | 81 INIT_STATUS_OK = 0, |
| 81 INIT_STATUS_CORRUPTION, | 82 INIT_STATUS_CORRUPTION, |
| 82 INIT_STATUS_IO_ERROR, | 83 INIT_STATUS_IO_ERROR, |
| 83 INIT_STATUS_UNKNOWN_ERROR, | 84 INIT_STATUS_UNKNOWN_ERROR, |
| 84 INIT_STATUS_MAX | 85 INIT_STATUS_MAX |
| 85 }; | 86 }; |
| 86 | 87 |
| 87 enum RepairResult { | 88 enum RepairResult { |
| 88 DB_REPAIR_SUCCEEDED = 0, | 89 DB_REPAIR_SUCCEEDED = 0, |
| 89 DB_REPAIR_FAILED, | 90 DB_REPAIR_FAILED, |
| 90 DB_REPAIR_MAX | 91 DB_REPAIR_MAX |
| 91 }; | 92 }; |
| 92 | 93 |
| 93 std::string GetChildLookupKey( | 94 std::string GetChildLookupKey( |
| 94 fileapi::FileSystemDirectoryDatabase::FileId parent_id, | 95 fileapi::SandboxDirectoryDatabase::FileId parent_id, |
| 95 const base::FilePath::StringType& child_name) { | 96 const base::FilePath::StringType& child_name) { |
| 96 std::string name; | 97 std::string name; |
| 97 name = fileapi::FilePathToString(base::FilePath(child_name)); | 98 name = fileapi::FilePathToString(base::FilePath(child_name)); |
| 98 return std::string(kChildLookupPrefix) + base::Int64ToString(parent_id) + | 99 return std::string(kChildLookupPrefix) + base::Int64ToString(parent_id) + |
| 99 std::string(kChildLookupSeparator) + name; | 100 std::string(kChildLookupSeparator) + name; |
| 100 } | 101 } |
| 101 | 102 |
| 102 std::string GetChildListingKeyPrefix( | 103 std::string GetChildListingKeyPrefix( |
| 103 fileapi::FileSystemDirectoryDatabase::FileId parent_id) { | 104 fileapi::SandboxDirectoryDatabase::FileId parent_id) { |
| 104 return std::string(kChildLookupPrefix) + base::Int64ToString(parent_id) + | 105 return std::string(kChildLookupPrefix) + base::Int64ToString(parent_id) + |
| 105 std::string(kChildLookupSeparator); | 106 std::string(kChildLookupSeparator); |
| 106 } | 107 } |
| 107 | 108 |
| 108 const char* LastFileIdKey() { | 109 const char* LastFileIdKey() { |
| 109 return kLastFileIdKey; | 110 return kLastFileIdKey; |
| 110 } | 111 } |
| 111 | 112 |
| 112 const char* LastIntegerKey() { | 113 const char* LastIntegerKey() { |
| 113 return kLastIntegerKey; | 114 return kLastIntegerKey; |
| 114 } | 115 } |
| 115 | 116 |
| 116 std::string GetFileLookupKey( | 117 std::string GetFileLookupKey( |
| 117 fileapi::FileSystemDirectoryDatabase::FileId file_id) { | 118 fileapi::SandboxDirectoryDatabase::FileId file_id) { |
| 118 return base::Int64ToString(file_id); | 119 return base::Int64ToString(file_id); |
| 119 } | 120 } |
| 120 | 121 |
| 121 // Assumptions: | 122 // Assumptions: |
| 122 // - Any database entry is one of: | 123 // - Any database entry is one of: |
| 123 // - ("CHILD_OF:|parent_id|:<name>", "|file_id|"), | 124 // - ("CHILD_OF:|parent_id|:<name>", "|file_id|"), |
| 124 // - ("LAST_FILE_ID", "|last_file_id|"), | 125 // - ("LAST_FILE_ID", "|last_file_id|"), |
| 125 // - ("LAST_INTEGER", "|last_integer|"), | 126 // - ("LAST_INTEGER", "|last_integer|"), |
| 126 // - ("|file_id|", "pickled FileInfo") | 127 // - ("|file_id|", "pickled FileInfo") |
| 127 // where FileInfo has |parent_id|, |data_path|, |name| and | 128 // where FileInfo has |parent_id|, |data_path|, |name| and |
| 128 // |modification_time|, | 129 // |modification_time|, |
| 129 // Constraints: | 130 // Constraints: |
| 130 // - Each file in the database has unique backing file. | 131 // - Each file in the database has unique backing file. |
| 131 // - Each file in |filesystem_data_directory_| has a database entry. | 132 // - Each file in |filesystem_data_directory_| has a database entry. |
| 132 // - Directory structure is tree, i.e. connected and acyclic. | 133 // - Directory structure is tree, i.e. connected and acyclic. |
| 133 class DatabaseCheckHelper { | 134 class DatabaseCheckHelper { |
| 134 public: | 135 public: |
| 135 typedef fileapi::FileSystemDirectoryDatabase::FileId FileId; | 136 typedef fileapi::SandboxDirectoryDatabase::FileId FileId; |
| 136 typedef fileapi::FileSystemDirectoryDatabase::FileInfo FileInfo; | 137 typedef fileapi::SandboxDirectoryDatabase::FileInfo FileInfo; |
| 137 | 138 |
| 138 DatabaseCheckHelper(fileapi::FileSystemDirectoryDatabase* dir_db, | 139 DatabaseCheckHelper(fileapi::SandboxDirectoryDatabase* dir_db, |
| 139 leveldb::DB* db, | 140 leveldb::DB* db, |
| 140 const base::FilePath& path); | 141 const base::FilePath& path); |
| 141 | 142 |
| 142 bool IsFileSystemConsistent() { | 143 bool IsFileSystemConsistent() { |
| 143 return IsDatabaseEmpty() || | 144 return IsDatabaseEmpty() || |
| 144 (ScanDatabase() && ScanDirectory() && ScanHierarchy()); | 145 (ScanDatabase() && ScanDirectory() && ScanHierarchy()); |
| 145 } | 146 } |
| 146 | 147 |
| 147 private: | 148 private: |
| 148 bool IsDatabaseEmpty(); | 149 bool IsDatabaseEmpty(); |
| 149 // These 3 methods need to be called in the order. Each method requires its | 150 // These 3 methods need to be called in the order. Each method requires its |
| 150 // previous method finished successfully. They also require the database is | 151 // previous method finished successfully. They also require the database is |
| 151 // not empty. | 152 // not empty. |
| 152 bool ScanDatabase(); | 153 bool ScanDatabase(); |
| 153 bool ScanDirectory(); | 154 bool ScanDirectory(); |
| 154 bool ScanHierarchy(); | 155 bool ScanHierarchy(); |
| 155 | 156 |
| 156 fileapi::FileSystemDirectoryDatabase* dir_db_; | 157 fileapi::SandboxDirectoryDatabase* dir_db_; |
| 157 leveldb::DB* db_; | 158 leveldb::DB* db_; |
| 158 base::FilePath path_; | 159 base::FilePath path_; |
| 159 | 160 |
| 160 std::set<base::FilePath> files_in_db_; | 161 std::set<base::FilePath> files_in_db_; |
| 161 | 162 |
| 162 size_t num_directories_in_db_; | 163 size_t num_directories_in_db_; |
| 163 size_t num_files_in_db_; | 164 size_t num_files_in_db_; |
| 164 size_t num_hierarchy_links_in_db_; | 165 size_t num_hierarchy_links_in_db_; |
| 165 | 166 |
| 166 FileId last_file_id_; | 167 FileId last_file_id_; |
| 167 FileId last_integer_; | 168 FileId last_integer_; |
| 168 }; | 169 }; |
| 169 | 170 |
| 170 DatabaseCheckHelper::DatabaseCheckHelper( | 171 DatabaseCheckHelper::DatabaseCheckHelper( |
| 171 fileapi::FileSystemDirectoryDatabase* dir_db, | 172 fileapi::SandboxDirectoryDatabase* dir_db, |
| 172 leveldb::DB* db, | 173 leveldb::DB* db, |
| 173 const base::FilePath& path) | 174 const base::FilePath& path) |
| 174 : dir_db_(dir_db), db_(db), path_(path), | 175 : dir_db_(dir_db), db_(db), path_(path), |
| 175 num_directories_in_db_(0), | 176 num_directories_in_db_(0), |
| 176 num_files_in_db_(0), | 177 num_files_in_db_(0), |
| 177 num_hierarchy_links_in_db_(0), | 178 num_hierarchy_links_in_db_(0), |
| 178 last_file_id_(-1), last_integer_(-1) { | 179 last_file_id_(-1), last_integer_(-1) { |
| 179 DCHECK(dir_db_); | 180 DCHECK(dir_db_); |
| 180 DCHECK(db_); | 181 DCHECK(db_); |
| 181 DCHECK(!path_.empty() && file_util::DirectoryExists(path_)); | 182 DCHECK(!path_.empty() && file_util::DirectoryExists(path_)); |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 if (std::find(kExcludes, kExcludes + arraysize(kExcludes), | 300 if (std::find(kExcludes, kExcludes + arraysize(kExcludes), |
| 300 relative_file_path) != kExcludes + arraysize(kExcludes)) | 301 relative_file_path) != kExcludes + arraysize(kExcludes)) |
| 301 continue; | 302 continue; |
| 302 | 303 |
| 303 if (file_util::FileEnumerator::IsDirectory(find_info)) { | 304 if (file_util::FileEnumerator::IsDirectory(find_info)) { |
| 304 pending_directories.push(relative_file_path); | 305 pending_directories.push(relative_file_path); |
| 305 continue; | 306 continue; |
| 306 } | 307 } |
| 307 | 308 |
| 308 // Check if the file has a database entry. | 309 // Check if the file has a database entry. |
| 309 std::set<base::FilePath>::iterator itr = files_in_db_.find(relative_file_p
ath); | 310 std::set<base::FilePath>::iterator itr = |
| 311 files_in_db_.find(relative_file_path); |
| 310 if (itr == files_in_db_.end()) { | 312 if (itr == files_in_db_.end()) { |
| 311 if (!file_util::Delete(absolute_file_path, false)) | 313 if (!file_util::Delete(absolute_file_path, false)) |
| 312 return false; | 314 return false; |
| 313 } else { | 315 } else { |
| 314 files_in_db_.erase(itr); | 316 files_in_db_.erase(itr); |
| 315 } | 317 } |
| 316 } | 318 } |
| 317 } | 319 } |
| 318 | 320 |
| 319 return files_in_db_.empty(); | 321 return files_in_db_.empty(); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 if (data_path == kExcludes[i] || kExcludes[i].IsParent(data_path)) | 397 if (data_path == kExcludes[i] || kExcludes[i].IsParent(data_path)) |
| 396 return false; | 398 return false; |
| 397 } | 399 } |
| 398 return true; | 400 return true; |
| 399 } | 401 } |
| 400 | 402 |
| 401 } // namespace | 403 } // namespace |
| 402 | 404 |
| 403 namespace fileapi { | 405 namespace fileapi { |
| 404 | 406 |
| 405 FileSystemDirectoryDatabase::FileInfo::FileInfo() : parent_id(0) { | 407 SandboxDirectoryDatabase::FileInfo::FileInfo() : parent_id(0) { |
| 406 } | 408 } |
| 407 | 409 |
| 408 FileSystemDirectoryDatabase::FileInfo::~FileInfo() { | 410 SandboxDirectoryDatabase::FileInfo::~FileInfo() { |
| 409 } | 411 } |
| 410 | 412 |
| 411 FileSystemDirectoryDatabase::FileSystemDirectoryDatabase( | 413 SandboxDirectoryDatabase::SandboxDirectoryDatabase( |
| 412 const base::FilePath& filesystem_data_directory) | 414 const base::FilePath& filesystem_data_directory) |
| 413 : filesystem_data_directory_(filesystem_data_directory) { | 415 : filesystem_data_directory_(filesystem_data_directory) { |
| 414 } | 416 } |
| 415 | 417 |
| 416 FileSystemDirectoryDatabase::~FileSystemDirectoryDatabase() { | 418 SandboxDirectoryDatabase::~SandboxDirectoryDatabase() { |
| 417 } | 419 } |
| 418 | 420 |
| 419 bool FileSystemDirectoryDatabase::GetChildWithName( | 421 bool SandboxDirectoryDatabase::GetChildWithName( |
| 420 FileId parent_id, const base::FilePath::StringType& name, FileId* child_id)
{ | 422 FileId parent_id, |
| 423 const base::FilePath::StringType& name, |
| 424 FileId* child_id) { |
| 421 if (!Init(REPAIR_ON_CORRUPTION)) | 425 if (!Init(REPAIR_ON_CORRUPTION)) |
| 422 return false; | 426 return false; |
| 423 DCHECK(child_id); | 427 DCHECK(child_id); |
| 424 std::string child_key = GetChildLookupKey(parent_id, name); | 428 std::string child_key = GetChildLookupKey(parent_id, name); |
| 425 std::string child_id_string; | 429 std::string child_id_string; |
| 426 leveldb::Status status = | 430 leveldb::Status status = |
| 427 db_->Get(leveldb::ReadOptions(), child_key, &child_id_string); | 431 db_->Get(leveldb::ReadOptions(), child_key, &child_id_string); |
| 428 if (status.IsNotFound()) | 432 if (status.IsNotFound()) |
| 429 return false; | 433 return false; |
| 430 if (status.ok()) { | 434 if (status.ok()) { |
| 431 if (!base::StringToInt64(child_id_string, child_id)) { | 435 if (!base::StringToInt64(child_id_string, child_id)) { |
| 432 LOG(ERROR) << "Hit database corruption!"; | 436 LOG(ERROR) << "Hit database corruption!"; |
| 433 return false; | 437 return false; |
| 434 } | 438 } |
| 435 return true; | 439 return true; |
| 436 } | 440 } |
| 437 HandleError(FROM_HERE, status); | 441 HandleError(FROM_HERE, status); |
| 438 return false; | 442 return false; |
| 439 } | 443 } |
| 440 | 444 |
| 441 bool FileSystemDirectoryDatabase::GetFileWithPath( | 445 bool SandboxDirectoryDatabase::GetFileWithPath( |
| 442 const base::FilePath& path, FileId* file_id) { | 446 const base::FilePath& path, FileId* file_id) { |
| 443 std::vector<base::FilePath::StringType> components; | 447 std::vector<base::FilePath::StringType> components; |
| 444 VirtualPath::GetComponents(path, &components); | 448 VirtualPath::GetComponents(path, &components); |
| 445 FileId local_id = 0; | 449 FileId local_id = 0; |
| 446 std::vector<base::FilePath::StringType>::iterator iter; | 450 std::vector<base::FilePath::StringType>::iterator iter; |
| 447 for (iter = components.begin(); iter != components.end(); ++iter) { | 451 for (iter = components.begin(); iter != components.end(); ++iter) { |
| 448 base::FilePath::StringType name; | 452 base::FilePath::StringType name; |
| 449 name = *iter; | 453 name = *iter; |
| 450 if (name == FILE_PATH_LITERAL("/")) | 454 if (name == FILE_PATH_LITERAL("/")) |
| 451 continue; | 455 continue; |
| 452 if (!GetChildWithName(local_id, name, &local_id)) | 456 if (!GetChildWithName(local_id, name, &local_id)) |
| 453 return false; | 457 return false; |
| 454 } | 458 } |
| 455 *file_id = local_id; | 459 *file_id = local_id; |
| 456 return true; | 460 return true; |
| 457 } | 461 } |
| 458 | 462 |
| 459 bool FileSystemDirectoryDatabase::ListChildren( | 463 bool SandboxDirectoryDatabase::ListChildren( |
| 460 FileId parent_id, std::vector<FileId>* children) { | 464 FileId parent_id, std::vector<FileId>* children) { |
| 461 // Check to add later: fail if parent is a file, at least in debug builds. | 465 // Check to add later: fail if parent is a file, at least in debug builds. |
| 462 if (!Init(REPAIR_ON_CORRUPTION)) | 466 if (!Init(REPAIR_ON_CORRUPTION)) |
| 463 return false; | 467 return false; |
| 464 DCHECK(children); | 468 DCHECK(children); |
| 465 std::string child_key_prefix = GetChildListingKeyPrefix(parent_id); | 469 std::string child_key_prefix = GetChildListingKeyPrefix(parent_id); |
| 466 | 470 |
| 467 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions())); | 471 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions())); |
| 468 iter->Seek(child_key_prefix); | 472 iter->Seek(child_key_prefix); |
| 469 children->clear(); | 473 children->clear(); |
| 470 while (iter->Valid() && | 474 while (iter->Valid() && |
| 471 StartsWithASCII(iter->key().ToString(), child_key_prefix, true)) { | 475 StartsWithASCII(iter->key().ToString(), child_key_prefix, true)) { |
| 472 std::string child_id_string = iter->value().ToString(); | 476 std::string child_id_string = iter->value().ToString(); |
| 473 FileId child_id; | 477 FileId child_id; |
| 474 if (!base::StringToInt64(child_id_string, &child_id)) { | 478 if (!base::StringToInt64(child_id_string, &child_id)) { |
| 475 LOG(ERROR) << "Hit database corruption!"; | 479 LOG(ERROR) << "Hit database corruption!"; |
| 476 return false; | 480 return false; |
| 477 } | 481 } |
| 478 children->push_back(child_id); | 482 children->push_back(child_id); |
| 479 iter->Next(); | 483 iter->Next(); |
| 480 } | 484 } |
| 481 return true; | 485 return true; |
| 482 } | 486 } |
| 483 | 487 |
| 484 bool FileSystemDirectoryDatabase::GetFileInfo(FileId file_id, FileInfo* info) { | 488 bool SandboxDirectoryDatabase::GetFileInfo(FileId file_id, FileInfo* info) { |
| 485 if (!Init(REPAIR_ON_CORRUPTION)) | 489 if (!Init(REPAIR_ON_CORRUPTION)) |
| 486 return false; | 490 return false; |
| 487 DCHECK(info); | 491 DCHECK(info); |
| 488 std::string file_key = GetFileLookupKey(file_id); | 492 std::string file_key = GetFileLookupKey(file_id); |
| 489 std::string file_data_string; | 493 std::string file_data_string; |
| 490 leveldb::Status status = | 494 leveldb::Status status = |
| 491 db_->Get(leveldb::ReadOptions(), file_key, &file_data_string); | 495 db_->Get(leveldb::ReadOptions(), file_key, &file_data_string); |
| 492 if (status.ok()) { | 496 if (status.ok()) { |
| 493 bool success = FileInfoFromPickle( | 497 bool success = FileInfoFromPickle( |
| 494 Pickle(file_data_string.data(), file_data_string.length()), info); | 498 Pickle(file_data_string.data(), file_data_string.length()), info); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 508 info->name = base::FilePath::StringType(); | 512 info->name = base::FilePath::StringType(); |
| 509 info->data_path = base::FilePath(); | 513 info->data_path = base::FilePath(); |
| 510 info->modification_time = base::Time::Now(); | 514 info->modification_time = base::Time::Now(); |
| 511 info->parent_id = 0; | 515 info->parent_id = 0; |
| 512 return true; | 516 return true; |
| 513 } | 517 } |
| 514 HandleError(FROM_HERE, status); | 518 HandleError(FROM_HERE, status); |
| 515 return false; | 519 return false; |
| 516 } | 520 } |
| 517 | 521 |
| 518 bool FileSystemDirectoryDatabase::AddFileInfo( | 522 bool SandboxDirectoryDatabase::AddFileInfo( |
| 519 const FileInfo& info, FileId* file_id) { | 523 const FileInfo& info, FileId* file_id) { |
| 520 if (!Init(REPAIR_ON_CORRUPTION)) | 524 if (!Init(REPAIR_ON_CORRUPTION)) |
| 521 return false; | 525 return false; |
| 522 DCHECK(file_id); | 526 DCHECK(file_id); |
| 523 std::string child_key = GetChildLookupKey(info.parent_id, info.name); | 527 std::string child_key = GetChildLookupKey(info.parent_id, info.name); |
| 524 std::string child_id_string; | 528 std::string child_id_string; |
| 525 leveldb::Status status = | 529 leveldb::Status status = |
| 526 db_->Get(leveldb::ReadOptions(), child_key, &child_id_string); | 530 db_->Get(leveldb::ReadOptions(), child_key, &child_id_string); |
| 527 if (status.ok()) { | 531 if (status.ok()) { |
| 528 LOG(ERROR) << "File exists already!"; | 532 LOG(ERROR) << "File exists already!"; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 551 batch.Put(LastFileIdKey(), base::Int64ToString(temp_id)); | 555 batch.Put(LastFileIdKey(), base::Int64ToString(temp_id)); |
| 552 status = db_->Write(leveldb::WriteOptions(), &batch); | 556 status = db_->Write(leveldb::WriteOptions(), &batch); |
| 553 if (!status.ok()) { | 557 if (!status.ok()) { |
| 554 HandleError(FROM_HERE, status); | 558 HandleError(FROM_HERE, status); |
| 555 return false; | 559 return false; |
| 556 } | 560 } |
| 557 *file_id = temp_id; | 561 *file_id = temp_id; |
| 558 return true; | 562 return true; |
| 559 } | 563 } |
| 560 | 564 |
| 561 bool FileSystemDirectoryDatabase::RemoveFileInfo(FileId file_id) { | 565 bool SandboxDirectoryDatabase::RemoveFileInfo(FileId file_id) { |
| 562 if (!Init(REPAIR_ON_CORRUPTION)) | 566 if (!Init(REPAIR_ON_CORRUPTION)) |
| 563 return false; | 567 return false; |
| 564 leveldb::WriteBatch batch; | 568 leveldb::WriteBatch batch; |
| 565 if (!RemoveFileInfoHelper(file_id, &batch)) | 569 if (!RemoveFileInfoHelper(file_id, &batch)) |
| 566 return false; | 570 return false; |
| 567 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); | 571 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); |
| 568 if (!status.ok()) { | 572 if (!status.ok()) { |
| 569 HandleError(FROM_HERE, status); | 573 HandleError(FROM_HERE, status); |
| 570 return false; | 574 return false; |
| 571 } | 575 } |
| 572 return true; | 576 return true; |
| 573 } | 577 } |
| 574 | 578 |
| 575 bool FileSystemDirectoryDatabase::UpdateFileInfo( | 579 bool SandboxDirectoryDatabase::UpdateFileInfo( |
| 576 FileId file_id, const FileInfo& new_info) { | 580 FileId file_id, const FileInfo& new_info) { |
| 577 // TODO(ericu): We should also check to see that this doesn't create a loop, | 581 // TODO(ericu): We should also check to see that this doesn't create a loop, |
| 578 // but perhaps only in a debug build. | 582 // but perhaps only in a debug build. |
| 579 if (!Init(REPAIR_ON_CORRUPTION)) | 583 if (!Init(REPAIR_ON_CORRUPTION)) |
| 580 return false; | 584 return false; |
| 581 DCHECK(file_id); // You can't remove the root, ever. Just delete the DB. | 585 DCHECK(file_id); // You can't remove the root, ever. Just delete the DB. |
| 582 FileInfo old_info; | 586 FileInfo old_info; |
| 583 if (!GetFileInfo(file_id, &old_info)) | 587 if (!GetFileInfo(file_id, &old_info)) |
| 584 return false; | 588 return false; |
| 585 if (old_info.parent_id != new_info.parent_id && | 589 if (old_info.parent_id != new_info.parent_id && |
| (...skipping 13 matching lines...) Expand all Loading... |
| 599 !AddFileInfoHelper(new_info, file_id, &batch)) | 603 !AddFileInfoHelper(new_info, file_id, &batch)) |
| 600 return false; | 604 return false; |
| 601 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); | 605 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); |
| 602 if (!status.ok()) { | 606 if (!status.ok()) { |
| 603 HandleError(FROM_HERE, status); | 607 HandleError(FROM_HERE, status); |
| 604 return false; | 608 return false; |
| 605 } | 609 } |
| 606 return true; | 610 return true; |
| 607 } | 611 } |
| 608 | 612 |
| 609 bool FileSystemDirectoryDatabase::UpdateModificationTime( | 613 bool SandboxDirectoryDatabase::UpdateModificationTime( |
| 610 FileId file_id, const base::Time& modification_time) { | 614 FileId file_id, const base::Time& modification_time) { |
| 611 FileInfo info; | 615 FileInfo info; |
| 612 if (!GetFileInfo(file_id, &info)) | 616 if (!GetFileInfo(file_id, &info)) |
| 613 return false; | 617 return false; |
| 614 info.modification_time = modification_time; | 618 info.modification_time = modification_time; |
| 615 Pickle pickle; | 619 Pickle pickle; |
| 616 if (!PickleFromFileInfo(info, &pickle)) | 620 if (!PickleFromFileInfo(info, &pickle)) |
| 617 return false; | 621 return false; |
| 618 leveldb::Status status = db_->Put( | 622 leveldb::Status status = db_->Put( |
| 619 leveldb::WriteOptions(), | 623 leveldb::WriteOptions(), |
| 620 GetFileLookupKey(file_id), | 624 GetFileLookupKey(file_id), |
| 621 leveldb::Slice(reinterpret_cast<const char *>(pickle.data()), | 625 leveldb::Slice(reinterpret_cast<const char *>(pickle.data()), |
| 622 pickle.size())); | 626 pickle.size())); |
| 623 if (!status.ok()) { | 627 if (!status.ok()) { |
| 624 HandleError(FROM_HERE, status); | 628 HandleError(FROM_HERE, status); |
| 625 return false; | 629 return false; |
| 626 } | 630 } |
| 627 return true; | 631 return true; |
| 628 } | 632 } |
| 629 | 633 |
| 630 bool FileSystemDirectoryDatabase::OverwritingMoveFile( | 634 bool SandboxDirectoryDatabase::OverwritingMoveFile( |
| 631 FileId src_file_id, FileId dest_file_id) { | 635 FileId src_file_id, FileId dest_file_id) { |
| 632 FileInfo src_file_info; | 636 FileInfo src_file_info; |
| 633 FileInfo dest_file_info; | 637 FileInfo dest_file_info; |
| 634 | 638 |
| 635 if (!GetFileInfo(src_file_id, &src_file_info)) | 639 if (!GetFileInfo(src_file_id, &src_file_info)) |
| 636 return false; | 640 return false; |
| 637 if (!GetFileInfo(dest_file_id, &dest_file_info)) | 641 if (!GetFileInfo(dest_file_id, &dest_file_info)) |
| 638 return false; | 642 return false; |
| 639 if (src_file_info.is_directory() || dest_file_info.is_directory()) | 643 if (src_file_info.is_directory() || dest_file_info.is_directory()) |
| 640 return false; | 644 return false; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 652 leveldb::Slice(reinterpret_cast<const char *>(pickle.data()), | 656 leveldb::Slice(reinterpret_cast<const char *>(pickle.data()), |
| 653 pickle.size())); | 657 pickle.size())); |
| 654 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); | 658 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); |
| 655 if (!status.ok()) { | 659 if (!status.ok()) { |
| 656 HandleError(FROM_HERE, status); | 660 HandleError(FROM_HERE, status); |
| 657 return false; | 661 return false; |
| 658 } | 662 } |
| 659 return true; | 663 return true; |
| 660 } | 664 } |
| 661 | 665 |
| 662 bool FileSystemDirectoryDatabase::GetNextInteger(int64* next) { | 666 bool SandboxDirectoryDatabase::GetNextInteger(int64* next) { |
| 663 if (!Init(REPAIR_ON_CORRUPTION)) | 667 if (!Init(REPAIR_ON_CORRUPTION)) |
| 664 return false; | 668 return false; |
| 665 DCHECK(next); | 669 DCHECK(next); |
| 666 std::string int_string; | 670 std::string int_string; |
| 667 leveldb::Status status = | 671 leveldb::Status status = |
| 668 db_->Get(leveldb::ReadOptions(), LastIntegerKey(), &int_string); | 672 db_->Get(leveldb::ReadOptions(), LastIntegerKey(), &int_string); |
| 669 if (status.ok()) { | 673 if (status.ok()) { |
| 670 int64 temp; | 674 int64 temp; |
| 671 if (!base::StringToInt64(int_string, &temp)) { | 675 if (!base::StringToInt64(int_string, &temp)) { |
| 672 LOG(ERROR) << "Hit database corruption!"; | 676 LOG(ERROR) << "Hit database corruption!"; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 687 return false; | 691 return false; |
| 688 } | 692 } |
| 689 // The database must not yet exist; initialize it. | 693 // The database must not yet exist; initialize it. |
| 690 if (!StoreDefaultValues()) | 694 if (!StoreDefaultValues()) |
| 691 return false; | 695 return false; |
| 692 | 696 |
| 693 return GetNextInteger(next); | 697 return GetNextInteger(next); |
| 694 } | 698 } |
| 695 | 699 |
| 696 // static | 700 // static |
| 697 bool FileSystemDirectoryDatabase::DestroyDatabase(const base::FilePath& path) { | 701 bool SandboxDirectoryDatabase::DestroyDatabase(const base::FilePath& path) { |
| 698 std::string name = FilePathToString(path.Append(kDirectoryDatabaseName)); | 702 std::string name = FilePathToString(path.Append(kDirectoryDatabaseName)); |
| 699 leveldb::Status status = leveldb::DestroyDB(name, leveldb::Options()); | 703 leveldb::Status status = leveldb::DestroyDB(name, leveldb::Options()); |
| 700 if (status.ok()) | 704 if (status.ok()) |
| 701 return true; | 705 return true; |
| 702 LOG(WARNING) << "Failed to destroy a database with status " << | 706 LOG(WARNING) << "Failed to destroy a database with status " << |
| 703 status.ToString(); | 707 status.ToString(); |
| 704 return false; | 708 return false; |
| 705 } | 709 } |
| 706 | 710 |
| 707 bool FileSystemDirectoryDatabase::Init(RecoveryOption recovery_option) { | 711 bool SandboxDirectoryDatabase::Init(RecoveryOption recovery_option) { |
| 708 if (db_) | 712 if (db_) |
| 709 return true; | 713 return true; |
| 710 | 714 |
| 711 std::string path = | 715 std::string path = |
| 712 FilePathToString(filesystem_data_directory_.Append( | 716 FilePathToString(filesystem_data_directory_.Append( |
| 713 kDirectoryDatabaseName)); | 717 kDirectoryDatabaseName)); |
| 714 leveldb::Options options; | 718 leveldb::Options options; |
| 715 options.create_if_missing = true; | 719 options.create_if_missing = true; |
| 716 leveldb::DB* db; | 720 leveldb::DB* db; |
| 717 leveldb::Status status = leveldb::DB::Open(options, path, &db); | 721 leveldb::Status status = leveldb::DB::Open(options, path, &db); |
| 718 ReportInitStatus(status); | 722 ReportInitStatus(status); |
| 719 if (status.ok()) { | 723 if (status.ok()) { |
| 720 db_.reset(db); | 724 db_.reset(db); |
| 721 return true; | 725 return true; |
| 722 } | 726 } |
| 723 HandleError(FROM_HERE, status); | 727 HandleError(FROM_HERE, status); |
| 724 | 728 |
| 725 // Corruption due to missing necessary MANIFEST-* file causes IOError instead | 729 // Corruption due to missing necessary MANIFEST-* file causes IOError instead |
| 726 // of Corruption error. | 730 // of Corruption error. |
| 727 // Try to repair database even when IOError case. | 731 // Try to repair database even when IOError case. |
| 728 if (!status.IsCorruption() && !status.IsIOError()) | 732 if (!status.IsCorruption() && !status.IsIOError()) |
| 729 return false; | 733 return false; |
| 730 | 734 |
| 731 switch (recovery_option) { | 735 switch (recovery_option) { |
| 732 case FAIL_ON_CORRUPTION: | 736 case FAIL_ON_CORRUPTION: |
| 733 return false; | 737 return false; |
| 734 case REPAIR_ON_CORRUPTION: | 738 case REPAIR_ON_CORRUPTION: |
| 735 LOG(WARNING) << "Corrupted FileSystemDirectoryDatabase detected." | 739 LOG(WARNING) << "Corrupted SandboxDirectoryDatabase detected." |
| 736 << " Attempting to repair."; | 740 << " Attempting to repair."; |
| 737 if (RepairDatabase(path)) { | 741 if (RepairDatabase(path)) { |
| 738 UMA_HISTOGRAM_ENUMERATION(kDatabaseRepairHistogramLabel, | 742 UMA_HISTOGRAM_ENUMERATION(kDatabaseRepairHistogramLabel, |
| 739 DB_REPAIR_SUCCEEDED, DB_REPAIR_MAX); | 743 DB_REPAIR_SUCCEEDED, DB_REPAIR_MAX); |
| 740 return true; | 744 return true; |
| 741 } | 745 } |
| 742 UMA_HISTOGRAM_ENUMERATION(kDatabaseRepairHistogramLabel, | 746 UMA_HISTOGRAM_ENUMERATION(kDatabaseRepairHistogramLabel, |
| 743 DB_REPAIR_FAILED, DB_REPAIR_MAX); | 747 DB_REPAIR_FAILED, DB_REPAIR_MAX); |
| 744 LOG(WARNING) << "Failed to repair FileSystemDirectoryDatabase."; | 748 LOG(WARNING) << "Failed to repair SandboxDirectoryDatabase."; |
| 745 // fall through | 749 // fall through |
| 746 case DELETE_ON_CORRUPTION: | 750 case DELETE_ON_CORRUPTION: |
| 747 LOG(WARNING) << "Clearing FileSystemDirectoryDatabase."; | 751 LOG(WARNING) << "Clearing SandboxDirectoryDatabase."; |
| 748 if (!file_util::Delete(filesystem_data_directory_, true)) | 752 if (!file_util::Delete(filesystem_data_directory_, true)) |
| 749 return false; | 753 return false; |
| 750 if (!file_util::CreateDirectory(filesystem_data_directory_)) | 754 if (!file_util::CreateDirectory(filesystem_data_directory_)) |
| 751 return false; | 755 return false; |
| 752 return Init(FAIL_ON_CORRUPTION); | 756 return Init(FAIL_ON_CORRUPTION); |
| 753 } | 757 } |
| 754 | 758 |
| 755 NOTREACHED(); | 759 NOTREACHED(); |
| 756 return false; | 760 return false; |
| 757 } | 761 } |
| 758 | 762 |
| 759 bool FileSystemDirectoryDatabase::RepairDatabase(const std::string& db_path) { | 763 bool SandboxDirectoryDatabase::RepairDatabase(const std::string& db_path) { |
| 760 DCHECK(!db_.get()); | 764 DCHECK(!db_.get()); |
| 761 if (!leveldb::RepairDB(db_path, leveldb::Options()).ok()) | 765 if (!leveldb::RepairDB(db_path, leveldb::Options()).ok()) |
| 762 return false; | 766 return false; |
| 763 if (!Init(FAIL_ON_CORRUPTION)) | 767 if (!Init(FAIL_ON_CORRUPTION)) |
| 764 return false; | 768 return false; |
| 765 if (IsFileSystemConsistent()) | 769 if (IsFileSystemConsistent()) |
| 766 return true; | 770 return true; |
| 767 db_.reset(); | 771 db_.reset(); |
| 768 return false; | 772 return false; |
| 769 } | 773 } |
| 770 | 774 |
| 771 bool FileSystemDirectoryDatabase::IsFileSystemConsistent() { | 775 bool SandboxDirectoryDatabase::IsFileSystemConsistent() { |
| 772 if (!Init(FAIL_ON_CORRUPTION)) | 776 if (!Init(FAIL_ON_CORRUPTION)) |
| 773 return false; | 777 return false; |
| 774 DatabaseCheckHelper helper(this, db_.get(), filesystem_data_directory_); | 778 DatabaseCheckHelper helper(this, db_.get(), filesystem_data_directory_); |
| 775 return helper.IsFileSystemConsistent(); | 779 return helper.IsFileSystemConsistent(); |
| 776 } | 780 } |
| 777 | 781 |
| 778 void FileSystemDirectoryDatabase::ReportInitStatus( | 782 void SandboxDirectoryDatabase::ReportInitStatus( |
| 779 const leveldb::Status& status) { | 783 const leveldb::Status& status) { |
| 780 base::Time now = base::Time::Now(); | 784 base::Time now = base::Time::Now(); |
| 781 const base::TimeDelta minimum_interval = | 785 const base::TimeDelta minimum_interval = |
| 782 base::TimeDelta::FromHours(kMinimumReportIntervalHours); | 786 base::TimeDelta::FromHours(kMinimumReportIntervalHours); |
| 783 if (last_reported_time_ + minimum_interval >= now) | 787 if (last_reported_time_ + minimum_interval >= now) |
| 784 return; | 788 return; |
| 785 last_reported_time_ = now; | 789 last_reported_time_ = now; |
| 786 | 790 |
| 787 if (status.ok()) { | 791 if (status.ok()) { |
| 788 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel, | 792 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel, |
| 789 INIT_STATUS_OK, INIT_STATUS_MAX); | 793 INIT_STATUS_OK, INIT_STATUS_MAX); |
| 790 } else if (status.IsCorruption()) { | 794 } else if (status.IsCorruption()) { |
| 791 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel, | 795 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel, |
| 792 INIT_STATUS_CORRUPTION, INIT_STATUS_MAX); | 796 INIT_STATUS_CORRUPTION, INIT_STATUS_MAX); |
| 793 } else if (status.IsIOError()) { | 797 } else if (status.IsIOError()) { |
| 794 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel, | 798 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel, |
| 795 INIT_STATUS_IO_ERROR, INIT_STATUS_MAX); | 799 INIT_STATUS_IO_ERROR, INIT_STATUS_MAX); |
| 796 } else { | 800 } else { |
| 797 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel, | 801 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel, |
| 798 INIT_STATUS_UNKNOWN_ERROR, INIT_STATUS_MAX); | 802 INIT_STATUS_UNKNOWN_ERROR, INIT_STATUS_MAX); |
| 799 } | 803 } |
| 800 } | 804 } |
| 801 | 805 |
| 802 bool FileSystemDirectoryDatabase::StoreDefaultValues() { | 806 bool SandboxDirectoryDatabase::StoreDefaultValues() { |
| 803 // Verify that this is a totally new database, and initialize it. | 807 // Verify that this is a totally new database, and initialize it. |
| 804 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions())); | 808 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions())); |
| 805 iter->SeekToFirst(); | 809 iter->SeekToFirst(); |
| 806 if (iter->Valid()) { // DB was not empty--we shouldn't have been called. | 810 if (iter->Valid()) { // DB was not empty--we shouldn't have been called. |
| 807 LOG(ERROR) << "File system origin database is corrupt!"; | 811 LOG(ERROR) << "File system origin database is corrupt!"; |
| 808 return false; | 812 return false; |
| 809 } | 813 } |
| 810 // This is always the first write into the database. If we ever add a | 814 // This is always the first write into the database. If we ever add a |
| 811 // version number, it should go in this transaction too. | 815 // version number, it should go in this transaction too. |
| 812 FileInfo root; | 816 FileInfo root; |
| 813 root.parent_id = 0; | 817 root.parent_id = 0; |
| 814 root.modification_time = base::Time::Now(); | 818 root.modification_time = base::Time::Now(); |
| 815 leveldb::WriteBatch batch; | 819 leveldb::WriteBatch batch; |
| 816 if (!AddFileInfoHelper(root, 0, &batch)) | 820 if (!AddFileInfoHelper(root, 0, &batch)) |
| 817 return false; | 821 return false; |
| 818 batch.Put(LastFileIdKey(), base::Int64ToString(0)); | 822 batch.Put(LastFileIdKey(), base::Int64ToString(0)); |
| 819 batch.Put(LastIntegerKey(), base::Int64ToString(-1)); | 823 batch.Put(LastIntegerKey(), base::Int64ToString(-1)); |
| 820 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); | 824 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); |
| 821 if (!status.ok()) { | 825 if (!status.ok()) { |
| 822 HandleError(FROM_HERE, status); | 826 HandleError(FROM_HERE, status); |
| 823 return false; | 827 return false; |
| 824 } | 828 } |
| 825 return true; | 829 return true; |
| 826 } | 830 } |
| 827 | 831 |
| 828 bool FileSystemDirectoryDatabase::GetLastFileId(FileId* file_id) { | 832 bool SandboxDirectoryDatabase::GetLastFileId(FileId* file_id) { |
| 829 if (!Init(REPAIR_ON_CORRUPTION)) | 833 if (!Init(REPAIR_ON_CORRUPTION)) |
| 830 return false; | 834 return false; |
| 831 DCHECK(file_id); | 835 DCHECK(file_id); |
| 832 std::string id_string; | 836 std::string id_string; |
| 833 leveldb::Status status = | 837 leveldb::Status status = |
| 834 db_->Get(leveldb::ReadOptions(), LastFileIdKey(), &id_string); | 838 db_->Get(leveldb::ReadOptions(), LastFileIdKey(), &id_string); |
| 835 if (status.ok()) { | 839 if (status.ok()) { |
| 836 if (!base::StringToInt64(id_string, file_id)) { | 840 if (!base::StringToInt64(id_string, file_id)) { |
| 837 LOG(ERROR) << "Hit database corruption!"; | 841 LOG(ERROR) << "Hit database corruption!"; |
| 838 return false; | 842 return false; |
| 839 } | 843 } |
| 840 return true; | 844 return true; |
| 841 } | 845 } |
| 842 if (!status.IsNotFound()) { | 846 if (!status.IsNotFound()) { |
| 843 HandleError(FROM_HERE, status); | 847 HandleError(FROM_HERE, status); |
| 844 return false; | 848 return false; |
| 845 } | 849 } |
| 846 // The database must not yet exist; initialize it. | 850 // The database must not yet exist; initialize it. |
| 847 if (!StoreDefaultValues()) | 851 if (!StoreDefaultValues()) |
| 848 return false; | 852 return false; |
| 849 *file_id = 0; | 853 *file_id = 0; |
| 850 return true; | 854 return true; |
| 851 } | 855 } |
| 852 | 856 |
| 853 bool FileSystemDirectoryDatabase::VerifyIsDirectory(FileId file_id) { | 857 bool SandboxDirectoryDatabase::VerifyIsDirectory(FileId file_id) { |
| 854 FileInfo info; | 858 FileInfo info; |
| 855 if (!file_id) | 859 if (!file_id) |
| 856 return true; // The root is a directory. | 860 return true; // The root is a directory. |
| 857 if (!GetFileInfo(file_id, &info)) | 861 if (!GetFileInfo(file_id, &info)) |
| 858 return false; | 862 return false; |
| 859 if (!info.is_directory()) { | 863 if (!info.is_directory()) { |
| 860 LOG(ERROR) << "New parent directory is a file!"; | 864 LOG(ERROR) << "New parent directory is a file!"; |
| 861 return false; | 865 return false; |
| 862 } | 866 } |
| 863 return true; | 867 return true; |
| 864 } | 868 } |
| 865 | 869 |
| 866 // This does very few safety checks! | 870 // This does very few safety checks! |
| 867 bool FileSystemDirectoryDatabase::AddFileInfoHelper( | 871 bool SandboxDirectoryDatabase::AddFileInfoHelper( |
| 868 const FileInfo& info, FileId file_id, leveldb::WriteBatch* batch) { | 872 const FileInfo& info, FileId file_id, leveldb::WriteBatch* batch) { |
| 869 if (!VerifyDataPath(info.data_path)) { | 873 if (!VerifyDataPath(info.data_path)) { |
| 870 LOG(ERROR) << "Invalid data path is given: " << info.data_path.value(); | 874 LOG(ERROR) << "Invalid data path is given: " << info.data_path.value(); |
| 871 return false; | 875 return false; |
| 872 } | 876 } |
| 873 std::string id_string = GetFileLookupKey(file_id); | 877 std::string id_string = GetFileLookupKey(file_id); |
| 874 if (!file_id) { | 878 if (!file_id) { |
| 875 // The root directory doesn't need to be looked up by path from its parent. | 879 // The root directory doesn't need to be looked up by path from its parent. |
| 876 DCHECK(!info.parent_id); | 880 DCHECK(!info.parent_id); |
| 877 DCHECK(info.data_path.empty()); | 881 DCHECK(info.data_path.empty()); |
| 878 } else { | 882 } else { |
| 879 std::string child_key = GetChildLookupKey(info.parent_id, info.name); | 883 std::string child_key = GetChildLookupKey(info.parent_id, info.name); |
| 880 batch->Put(child_key, id_string); | 884 batch->Put(child_key, id_string); |
| 881 } | 885 } |
| 882 Pickle pickle; | 886 Pickle pickle; |
| 883 if (!PickleFromFileInfo(info, &pickle)) | 887 if (!PickleFromFileInfo(info, &pickle)) |
| 884 return false; | 888 return false; |
| 885 batch->Put( | 889 batch->Put( |
| 886 id_string, | 890 id_string, |
| 887 leveldb::Slice(reinterpret_cast<const char *>(pickle.data()), | 891 leveldb::Slice(reinterpret_cast<const char *>(pickle.data()), |
| 888 pickle.size())); | 892 pickle.size())); |
| 889 return true; | 893 return true; |
| 890 } | 894 } |
| 891 | 895 |
| 892 // This does very few safety checks! | 896 // This does very few safety checks! |
| 893 bool FileSystemDirectoryDatabase::RemoveFileInfoHelper( | 897 bool SandboxDirectoryDatabase::RemoveFileInfoHelper( |
| 894 FileId file_id, leveldb::WriteBatch* batch) { | 898 FileId file_id, leveldb::WriteBatch* batch) { |
| 895 DCHECK(file_id); // You can't remove the root, ever. Just delete the DB. | 899 DCHECK(file_id); // You can't remove the root, ever. Just delete the DB. |
| 896 FileInfo info; | 900 FileInfo info; |
| 897 if (!GetFileInfo(file_id, &info)) | 901 if (!GetFileInfo(file_id, &info)) |
| 898 return false; | 902 return false; |
| 899 if (info.data_path.empty()) { // It's a directory | 903 if (info.data_path.empty()) { // It's a directory |
| 900 std::vector<FileId> children; | 904 std::vector<FileId> children; |
| 901 // TODO(ericu): Make a faster is-the-directory-empty check. | 905 // TODO(ericu): Make a faster is-the-directory-empty check. |
| 902 if (!ListChildren(file_id, &children)) | 906 if (!ListChildren(file_id, &children)) |
| 903 return false; | 907 return false; |
| 904 if (children.size()) { | 908 if (children.size()) { |
| 905 LOG(ERROR) << "Can't remove a directory with children."; | 909 LOG(ERROR) << "Can't remove a directory with children."; |
| 906 return false; | 910 return false; |
| 907 } | 911 } |
| 908 } | 912 } |
| 909 batch->Delete(GetChildLookupKey(info.parent_id, info.name)); | 913 batch->Delete(GetChildLookupKey(info.parent_id, info.name)); |
| 910 batch->Delete(GetFileLookupKey(file_id)); | 914 batch->Delete(GetFileLookupKey(file_id)); |
| 911 return true; | 915 return true; |
| 912 } | 916 } |
| 913 | 917 |
| 914 void FileSystemDirectoryDatabase::HandleError( | 918 void SandboxDirectoryDatabase::HandleError( |
| 915 const tracked_objects::Location& from_here, | 919 const tracked_objects::Location& from_here, |
| 916 const leveldb::Status& status) { | 920 const leveldb::Status& status) { |
| 917 LOG(ERROR) << "FileSystemDirectoryDatabase failed at: " | 921 LOG(ERROR) << "SandboxDirectoryDatabase failed at: " |
| 918 << from_here.ToString() << " with error: " << status.ToString(); | 922 << from_here.ToString() << " with error: " << status.ToString(); |
| 919 db_.reset(); | 923 db_.reset(); |
| 920 } | 924 } |
| 921 | 925 |
| 922 } // namespace fileapi | 926 } // namespace fileapi |
| OLD | NEW |