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/browser/fileapi/sandbox_directory_database.h" | 5 #include "webkit/browser/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/files/file_enumerator.h" | 13 #include "base/files/file_enumerator.h" |
14 #include "base/location.h" | 14 #include "base/location.h" |
15 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
16 #include "base/pickle.h" | 16 #include "base/pickle.h" |
17 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
18 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
19 #include "third_party/leveldatabase/src/include/leveldb/db.h" | 19 #include "third_party/leveldatabase/src/include/leveldb/db.h" |
20 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" | 20 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" |
21 #include "webkit/browser/fileapi/file_system_usage_cache.h" | 21 #include "webkit/browser/fileapi/file_system_usage_cache.h" |
22 #include "webkit/common/fileapi/file_system_util.h" | 22 #include "webkit/common/fileapi/file_system_util.h" |
23 | 23 |
24 namespace { | 24 namespace { |
25 | 25 |
26 bool PickleFromFileInfo( | 26 bool PickleFromFileInfo(const storage::SandboxDirectoryDatabase::FileInfo& info, |
27 const fileapi::SandboxDirectoryDatabase::FileInfo& info, | 27 Pickle* pickle) { |
28 Pickle* pickle) { | |
29 DCHECK(pickle); | 28 DCHECK(pickle); |
30 std::string data_path; | 29 std::string data_path; |
31 // 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. |
32 base::Time time = | 31 base::Time time = |
33 base::Time::FromDoubleT(floor(info.modification_time.ToDoubleT())); | 32 base::Time::FromDoubleT(floor(info.modification_time.ToDoubleT())); |
34 std::string name; | 33 std::string name; |
35 | 34 |
36 data_path = fileapi::FilePathToString(info.data_path); | 35 data_path = storage::FilePathToString(info.data_path); |
37 name = fileapi::FilePathToString(base::FilePath(info.name)); | 36 name = storage::FilePathToString(base::FilePath(info.name)); |
38 | 37 |
39 if (pickle->WriteInt64(info.parent_id) && | 38 if (pickle->WriteInt64(info.parent_id) && |
40 pickle->WriteString(data_path) && | 39 pickle->WriteString(data_path) && |
41 pickle->WriteString(name) && | 40 pickle->WriteString(name) && |
42 pickle->WriteInt64(time.ToInternalValue())) | 41 pickle->WriteInt64(time.ToInternalValue())) |
43 return true; | 42 return true; |
44 | 43 |
45 NOTREACHED(); | 44 NOTREACHED(); |
46 return false; | 45 return false; |
47 } | 46 } |
48 | 47 |
49 bool FileInfoFromPickle( | 48 bool FileInfoFromPickle(const Pickle& pickle, |
50 const Pickle& pickle, | 49 storage::SandboxDirectoryDatabase::FileInfo* info) { |
51 fileapi::SandboxDirectoryDatabase::FileInfo* info) { | |
52 PickleIterator iter(pickle); | 50 PickleIterator iter(pickle); |
53 std::string data_path; | 51 std::string data_path; |
54 std::string name; | 52 std::string name; |
55 int64 internal_time; | 53 int64 internal_time; |
56 | 54 |
57 if (pickle.ReadInt64(&iter, &info->parent_id) && | 55 if (pickle.ReadInt64(&iter, &info->parent_id) && |
58 pickle.ReadString(&iter, &data_path) && | 56 pickle.ReadString(&iter, &data_path) && |
59 pickle.ReadString(&iter, &name) && | 57 pickle.ReadString(&iter, &name) && |
60 pickle.ReadInt64(&iter, &internal_time)) { | 58 pickle.ReadInt64(&iter, &internal_time)) { |
61 info->data_path = fileapi::StringToFilePath(data_path); | 59 info->data_path = storage::StringToFilePath(data_path); |
62 info->name = fileapi::StringToFilePath(name).value(); | 60 info->name = storage::StringToFilePath(name).value(); |
63 info->modification_time = base::Time::FromInternalValue(internal_time); | 61 info->modification_time = base::Time::FromInternalValue(internal_time); |
64 return true; | 62 return true; |
65 } | 63 } |
66 LOG(ERROR) << "Pickle could not be digested!"; | 64 LOG(ERROR) << "Pickle could not be digested!"; |
67 return false; | 65 return false; |
68 } | 66 } |
69 | 67 |
70 const base::FilePath::CharType kDirectoryDatabaseName[] = | 68 const base::FilePath::CharType kDirectoryDatabaseName[] = |
71 FILE_PATH_LITERAL("Paths"); | 69 FILE_PATH_LITERAL("Paths"); |
72 const char kChildLookupPrefix[] = "CHILD_OF:"; | 70 const char kChildLookupPrefix[] = "CHILD_OF:"; |
(...skipping 13 matching lines...) Expand all Loading... |
86 INIT_STATUS_MAX | 84 INIT_STATUS_MAX |
87 }; | 85 }; |
88 | 86 |
89 enum RepairResult { | 87 enum RepairResult { |
90 DB_REPAIR_SUCCEEDED = 0, | 88 DB_REPAIR_SUCCEEDED = 0, |
91 DB_REPAIR_FAILED, | 89 DB_REPAIR_FAILED, |
92 DB_REPAIR_MAX | 90 DB_REPAIR_MAX |
93 }; | 91 }; |
94 | 92 |
95 std::string GetChildLookupKey( | 93 std::string GetChildLookupKey( |
96 fileapi::SandboxDirectoryDatabase::FileId parent_id, | 94 storage::SandboxDirectoryDatabase::FileId parent_id, |
97 const base::FilePath::StringType& child_name) { | 95 const base::FilePath::StringType& child_name) { |
98 std::string name; | 96 std::string name; |
99 name = fileapi::FilePathToString(base::FilePath(child_name)); | 97 name = storage::FilePathToString(base::FilePath(child_name)); |
100 return std::string(kChildLookupPrefix) + base::Int64ToString(parent_id) + | 98 return std::string(kChildLookupPrefix) + base::Int64ToString(parent_id) + |
101 std::string(kChildLookupSeparator) + name; | 99 std::string(kChildLookupSeparator) + name; |
102 } | 100 } |
103 | 101 |
104 std::string GetChildListingKeyPrefix( | 102 std::string GetChildListingKeyPrefix( |
105 fileapi::SandboxDirectoryDatabase::FileId parent_id) { | 103 storage::SandboxDirectoryDatabase::FileId parent_id) { |
106 return std::string(kChildLookupPrefix) + base::Int64ToString(parent_id) + | 104 return std::string(kChildLookupPrefix) + base::Int64ToString(parent_id) + |
107 std::string(kChildLookupSeparator); | 105 std::string(kChildLookupSeparator); |
108 } | 106 } |
109 | 107 |
110 const char* LastFileIdKey() { | 108 const char* LastFileIdKey() { |
111 return kLastFileIdKey; | 109 return kLastFileIdKey; |
112 } | 110 } |
113 | 111 |
114 const char* LastIntegerKey() { | 112 const char* LastIntegerKey() { |
115 return kLastIntegerKey; | 113 return kLastIntegerKey; |
116 } | 114 } |
117 | 115 |
118 std::string GetFileLookupKey( | 116 std::string GetFileLookupKey( |
119 fileapi::SandboxDirectoryDatabase::FileId file_id) { | 117 storage::SandboxDirectoryDatabase::FileId file_id) { |
120 return base::Int64ToString(file_id); | 118 return base::Int64ToString(file_id); |
121 } | 119 } |
122 | 120 |
123 // Assumptions: | 121 // Assumptions: |
124 // - Any database entry is one of: | 122 // - Any database entry is one of: |
125 // - ("CHILD_OF:|parent_id|:<name>", "|file_id|"), | 123 // - ("CHILD_OF:|parent_id|:<name>", "|file_id|"), |
126 // - ("LAST_FILE_ID", "|last_file_id|"), | 124 // - ("LAST_FILE_ID", "|last_file_id|"), |
127 // - ("LAST_INTEGER", "|last_integer|"), | 125 // - ("LAST_INTEGER", "|last_integer|"), |
128 // - ("|file_id|", "pickled FileInfo") | 126 // - ("|file_id|", "pickled FileInfo") |
129 // where FileInfo has |parent_id|, |data_path|, |name| and | 127 // where FileInfo has |parent_id|, |data_path|, |name| and |
130 // |modification_time|, | 128 // |modification_time|, |
131 // Constraints: | 129 // Constraints: |
132 // - Each file in the database has unique backing file. | 130 // - Each file in the database has unique backing file. |
133 // - Each file in |filesystem_data_directory_| has a database entry. | 131 // - Each file in |filesystem_data_directory_| has a database entry. |
134 // - Directory structure is tree, i.e. connected and acyclic. | 132 // - Directory structure is tree, i.e. connected and acyclic. |
135 class DatabaseCheckHelper { | 133 class DatabaseCheckHelper { |
136 public: | 134 public: |
137 typedef fileapi::SandboxDirectoryDatabase::FileId FileId; | 135 typedef storage::SandboxDirectoryDatabase::FileId FileId; |
138 typedef fileapi::SandboxDirectoryDatabase::FileInfo FileInfo; | 136 typedef storage::SandboxDirectoryDatabase::FileInfo FileInfo; |
139 | 137 |
140 DatabaseCheckHelper(fileapi::SandboxDirectoryDatabase* dir_db, | 138 DatabaseCheckHelper(storage::SandboxDirectoryDatabase* dir_db, |
141 leveldb::DB* db, | 139 leveldb::DB* db, |
142 const base::FilePath& path); | 140 const base::FilePath& path); |
143 | 141 |
144 bool IsFileSystemConsistent() { | 142 bool IsFileSystemConsistent() { |
145 return IsDatabaseEmpty() || | 143 return IsDatabaseEmpty() || |
146 (ScanDatabase() && ScanDirectory() && ScanHierarchy()); | 144 (ScanDatabase() && ScanDirectory() && ScanHierarchy()); |
147 } | 145 } |
148 | 146 |
149 private: | 147 private: |
150 bool IsDatabaseEmpty(); | 148 bool IsDatabaseEmpty(); |
151 // These 3 methods need to be called in the order. Each method requires its | 149 // These 3 methods need to be called in the order. Each method requires its |
152 // previous method finished successfully. They also require the database is | 150 // previous method finished successfully. They also require the database is |
153 // not empty. | 151 // not empty. |
154 bool ScanDatabase(); | 152 bool ScanDatabase(); |
155 bool ScanDirectory(); | 153 bool ScanDirectory(); |
156 bool ScanHierarchy(); | 154 bool ScanHierarchy(); |
157 | 155 |
158 fileapi::SandboxDirectoryDatabase* dir_db_; | 156 storage::SandboxDirectoryDatabase* dir_db_; |
159 leveldb::DB* db_; | 157 leveldb::DB* db_; |
160 base::FilePath path_; | 158 base::FilePath path_; |
161 | 159 |
162 std::set<base::FilePath> files_in_db_; | 160 std::set<base::FilePath> files_in_db_; |
163 | 161 |
164 size_t num_directories_in_db_; | 162 size_t num_directories_in_db_; |
165 size_t num_files_in_db_; | 163 size_t num_files_in_db_; |
166 size_t num_hierarchy_links_in_db_; | 164 size_t num_hierarchy_links_in_db_; |
167 | 165 |
168 FileId last_file_id_; | 166 FileId last_file_id_; |
169 FileId last_integer_; | 167 FileId last_integer_; |
170 }; | 168 }; |
171 | 169 |
172 DatabaseCheckHelper::DatabaseCheckHelper( | 170 DatabaseCheckHelper::DatabaseCheckHelper( |
173 fileapi::SandboxDirectoryDatabase* dir_db, | 171 storage::SandboxDirectoryDatabase* dir_db, |
174 leveldb::DB* db, | 172 leveldb::DB* db, |
175 const base::FilePath& path) | 173 const base::FilePath& path) |
176 : dir_db_(dir_db), db_(db), path_(path), | 174 : dir_db_(dir_db), |
| 175 db_(db), |
| 176 path_(path), |
177 num_directories_in_db_(0), | 177 num_directories_in_db_(0), |
178 num_files_in_db_(0), | 178 num_files_in_db_(0), |
179 num_hierarchy_links_in_db_(0), | 179 num_hierarchy_links_in_db_(0), |
180 last_file_id_(-1), last_integer_(-1) { | 180 last_file_id_(-1), |
| 181 last_integer_(-1) { |
181 DCHECK(dir_db_); | 182 DCHECK(dir_db_); |
182 DCHECK(db_); | 183 DCHECK(db_); |
183 DCHECK(!path_.empty() && base::DirectoryExists(path_)); | 184 DCHECK(!path_.empty() && base::DirectoryExists(path_)); |
184 } | 185 } |
185 | 186 |
186 bool DatabaseCheckHelper::IsDatabaseEmpty() { | 187 bool DatabaseCheckHelper::IsDatabaseEmpty() { |
187 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); | 188 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); |
188 itr->SeekToFirst(); | 189 itr->SeekToFirst(); |
189 return !itr->Valid(); | 190 return !itr->Valid(); |
190 } | 191 } |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 | 265 |
265 // TODO(tzik): Add constraint for |last_integer_| to avoid possible | 266 // TODO(tzik): Add constraint for |last_integer_| to avoid possible |
266 // data path confliction on ObfuscatedFileUtil. | 267 // data path confliction on ObfuscatedFileUtil. |
267 return max_file_id <= last_file_id_; | 268 return max_file_id <= last_file_id_; |
268 } | 269 } |
269 | 270 |
270 bool DatabaseCheckHelper::ScanDirectory() { | 271 bool DatabaseCheckHelper::ScanDirectory() { |
271 // TODO(kinuko): Scans all local file system entries to verify each of them | 272 // TODO(kinuko): Scans all local file system entries to verify each of them |
272 // has a database entry. | 273 // has a database entry. |
273 const base::FilePath kExcludes[] = { | 274 const base::FilePath kExcludes[] = { |
274 base::FilePath(kDirectoryDatabaseName), | 275 base::FilePath(kDirectoryDatabaseName), |
275 base::FilePath(fileapi::FileSystemUsageCache::kUsageFileName), | 276 base::FilePath(storage::FileSystemUsageCache::kUsageFileName), |
276 }; | 277 }; |
277 | 278 |
278 // Any path in |pending_directories| is relative to |path_|. | 279 // Any path in |pending_directories| is relative to |path_|. |
279 std::stack<base::FilePath> pending_directories; | 280 std::stack<base::FilePath> pending_directories; |
280 pending_directories.push(base::FilePath()); | 281 pending_directories.push(base::FilePath()); |
281 | 282 |
282 while (!pending_directories.empty()) { | 283 while (!pending_directories.empty()) { |
283 base::FilePath dir_path = pending_directories.top(); | 284 base::FilePath dir_path = pending_directories.top(); |
284 pending_directories.pop(); | 285 pending_directories.pop(); |
285 | 286 |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 // and does not refer to special system files. | 383 // and does not refer to special system files. |
383 // This is called in GetFileInfo, AddFileInfo and UpdateFileInfo to | 384 // This is called in GetFileInfo, AddFileInfo and UpdateFileInfo to |
384 // ensure we're only dealing with valid data paths. | 385 // ensure we're only dealing with valid data paths. |
385 bool VerifyDataPath(const base::FilePath& data_path) { | 386 bool VerifyDataPath(const base::FilePath& data_path) { |
386 // |data_path| should not contain any ".." and should be a relative path | 387 // |data_path| should not contain any ".." and should be a relative path |
387 // (to the filesystem_data_directory_). | 388 // (to the filesystem_data_directory_). |
388 if (data_path.ReferencesParent() || data_path.IsAbsolute()) | 389 if (data_path.ReferencesParent() || data_path.IsAbsolute()) |
389 return false; | 390 return false; |
390 // See if it's not pointing to the special system paths. | 391 // See if it's not pointing to the special system paths. |
391 const base::FilePath kExcludes[] = { | 392 const base::FilePath kExcludes[] = { |
392 base::FilePath(kDirectoryDatabaseName), | 393 base::FilePath(kDirectoryDatabaseName), |
393 base::FilePath(fileapi::FileSystemUsageCache::kUsageFileName), | 394 base::FilePath(storage::FileSystemUsageCache::kUsageFileName), |
394 }; | 395 }; |
395 for (size_t i = 0; i < arraysize(kExcludes); ++i) { | 396 for (size_t i = 0; i < arraysize(kExcludes); ++i) { |
396 if (data_path == kExcludes[i] || kExcludes[i].IsParent(data_path)) | 397 if (data_path == kExcludes[i] || kExcludes[i].IsParent(data_path)) |
397 return false; | 398 return false; |
398 } | 399 } |
399 return true; | 400 return true; |
400 } | 401 } |
401 | 402 |
402 } // namespace | 403 } // namespace |
403 | 404 |
404 namespace fileapi { | 405 namespace storage { |
405 | 406 |
406 SandboxDirectoryDatabase::FileInfo::FileInfo() : parent_id(0) { | 407 SandboxDirectoryDatabase::FileInfo::FileInfo() : parent_id(0) { |
407 } | 408 } |
408 | 409 |
409 SandboxDirectoryDatabase::FileInfo::~FileInfo() { | 410 SandboxDirectoryDatabase::FileInfo::~FileInfo() { |
410 } | 411 } |
411 | 412 |
412 SandboxDirectoryDatabase::SandboxDirectoryDatabase( | 413 SandboxDirectoryDatabase::SandboxDirectoryDatabase( |
413 const base::FilePath& filesystem_data_directory, | 414 const base::FilePath& filesystem_data_directory, |
414 leveldb::Env* env_override) | 415 leveldb::Env* env_override) |
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
928 } | 929 } |
929 | 930 |
930 void SandboxDirectoryDatabase::HandleError( | 931 void SandboxDirectoryDatabase::HandleError( |
931 const tracked_objects::Location& from_here, | 932 const tracked_objects::Location& from_here, |
932 const leveldb::Status& status) { | 933 const leveldb::Status& status) { |
933 LOG(ERROR) << "SandboxDirectoryDatabase failed at: " | 934 LOG(ERROR) << "SandboxDirectoryDatabase failed at: " |
934 << from_here.ToString() << " with error: " << status.ToString(); | 935 << from_here.ToString() << " with error: " << status.ToString(); |
935 db_.reset(); | 936 db_.reset(); |
936 } | 937 } |
937 | 938 |
938 } // namespace fileapi | 939 } // namespace storage |
OLD | NEW |