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 "storage/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 "storage/browser/fileapi/file_system_usage_cache.h" |
22 #include "webkit/common/fileapi/file_system_util.h" | 22 #include "storage/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) && pickle->WriteString(data_path) && |
40 pickle->WriteString(data_path) && | 39 pickle->WriteString(name) && pickle->WriteInt64(time.ToInternalValue())) |
41 pickle->WriteString(name) && | |
42 pickle->WriteInt64(time.ToInternalValue())) | |
43 return true; | 40 return true; |
44 | 41 |
45 NOTREACHED(); | 42 NOTREACHED(); |
46 return false; | 43 return false; |
47 } | 44 } |
48 | 45 |
49 bool FileInfoFromPickle( | 46 bool FileInfoFromPickle(const Pickle& pickle, |
50 const Pickle& pickle, | 47 storage::SandboxDirectoryDatabase::FileInfo* info) { |
51 fileapi::SandboxDirectoryDatabase::FileInfo* info) { | |
52 PickleIterator iter(pickle); | 48 PickleIterator iter(pickle); |
53 std::string data_path; | 49 std::string data_path; |
54 std::string name; | 50 std::string name; |
55 int64 internal_time; | 51 int64 internal_time; |
56 | 52 |
57 if (pickle.ReadInt64(&iter, &info->parent_id) && | 53 if (pickle.ReadInt64(&iter, &info->parent_id) && |
58 pickle.ReadString(&iter, &data_path) && | 54 pickle.ReadString(&iter, &data_path) && pickle.ReadString(&iter, &name) && |
59 pickle.ReadString(&iter, &name) && | |
60 pickle.ReadInt64(&iter, &internal_time)) { | 55 pickle.ReadInt64(&iter, &internal_time)) { |
61 info->data_path = fileapi::StringToFilePath(data_path); | 56 info->data_path = storage::StringToFilePath(data_path); |
62 info->name = fileapi::StringToFilePath(name).value(); | 57 info->name = storage::StringToFilePath(name).value(); |
63 info->modification_time = base::Time::FromInternalValue(internal_time); | 58 info->modification_time = base::Time::FromInternalValue(internal_time); |
64 return true; | 59 return true; |
65 } | 60 } |
66 LOG(ERROR) << "Pickle could not be digested!"; | 61 LOG(ERROR) << "Pickle could not be digested!"; |
67 return false; | 62 return false; |
68 } | 63 } |
69 | 64 |
70 const base::FilePath::CharType kDirectoryDatabaseName[] = | 65 const base::FilePath::CharType kDirectoryDatabaseName[] = |
71 FILE_PATH_LITERAL("Paths"); | 66 FILE_PATH_LITERAL("Paths"); |
72 const char kChildLookupPrefix[] = "CHILD_OF:"; | 67 const char kChildLookupPrefix[] = "CHILD_OF:"; |
73 const char kChildLookupSeparator[] = ":"; | 68 const char kChildLookupSeparator[] = ":"; |
74 const char kLastFileIdKey[] = "LAST_FILE_ID"; | 69 const char kLastFileIdKey[] = "LAST_FILE_ID"; |
75 const char kLastIntegerKey[] = "LAST_INTEGER"; | 70 const char kLastIntegerKey[] = "LAST_INTEGER"; |
76 const int64 kMinimumReportIntervalHours = 1; | 71 const int64 kMinimumReportIntervalHours = 1; |
77 const char kInitStatusHistogramLabel[] = "FileSystem.DirectoryDatabaseInit"; | 72 const char kInitStatusHistogramLabel[] = "FileSystem.DirectoryDatabaseInit"; |
78 const char kDatabaseRepairHistogramLabel[] = | 73 const char kDatabaseRepairHistogramLabel[] = |
79 "FileSystem.DirectoryDatabaseRepair"; | 74 "FileSystem.DirectoryDatabaseRepair"; |
80 | 75 |
81 enum InitStatus { | 76 enum InitStatus { |
82 INIT_STATUS_OK = 0, | 77 INIT_STATUS_OK = 0, |
83 INIT_STATUS_CORRUPTION, | 78 INIT_STATUS_CORRUPTION, |
84 INIT_STATUS_IO_ERROR, | 79 INIT_STATUS_IO_ERROR, |
85 INIT_STATUS_UNKNOWN_ERROR, | 80 INIT_STATUS_UNKNOWN_ERROR, |
86 INIT_STATUS_MAX | 81 INIT_STATUS_MAX |
87 }; | 82 }; |
88 | 83 |
89 enum RepairResult { | 84 enum RepairResult { DB_REPAIR_SUCCEEDED = 0, DB_REPAIR_FAILED, DB_REPAIR_MAX }; |
90 DB_REPAIR_SUCCEEDED = 0, | |
91 DB_REPAIR_FAILED, | |
92 DB_REPAIR_MAX | |
93 }; | |
94 | 85 |
95 std::string GetChildLookupKey( | 86 std::string GetChildLookupKey( |
96 fileapi::SandboxDirectoryDatabase::FileId parent_id, | 87 storage::SandboxDirectoryDatabase::FileId parent_id, |
97 const base::FilePath::StringType& child_name) { | 88 const base::FilePath::StringType& child_name) { |
98 std::string name; | 89 std::string name; |
99 name = fileapi::FilePathToString(base::FilePath(child_name)); | 90 name = storage::FilePathToString(base::FilePath(child_name)); |
100 return std::string(kChildLookupPrefix) + base::Int64ToString(parent_id) + | 91 return std::string(kChildLookupPrefix) + base::Int64ToString(parent_id) + |
101 std::string(kChildLookupSeparator) + name; | 92 std::string(kChildLookupSeparator) + name; |
102 } | 93 } |
103 | 94 |
104 std::string GetChildListingKeyPrefix( | 95 std::string GetChildListingKeyPrefix( |
105 fileapi::SandboxDirectoryDatabase::FileId parent_id) { | 96 storage::SandboxDirectoryDatabase::FileId parent_id) { |
106 return std::string(kChildLookupPrefix) + base::Int64ToString(parent_id) + | 97 return std::string(kChildLookupPrefix) + base::Int64ToString(parent_id) + |
107 std::string(kChildLookupSeparator); | 98 std::string(kChildLookupSeparator); |
108 } | 99 } |
109 | 100 |
110 const char* LastFileIdKey() { | 101 const char* LastFileIdKey() { |
111 return kLastFileIdKey; | 102 return kLastFileIdKey; |
112 } | 103 } |
113 | 104 |
114 const char* LastIntegerKey() { | 105 const char* LastIntegerKey() { |
115 return kLastIntegerKey; | 106 return kLastIntegerKey; |
116 } | 107 } |
117 | 108 |
118 std::string GetFileLookupKey( | 109 std::string GetFileLookupKey( |
119 fileapi::SandboxDirectoryDatabase::FileId file_id) { | 110 storage::SandboxDirectoryDatabase::FileId file_id) { |
120 return base::Int64ToString(file_id); | 111 return base::Int64ToString(file_id); |
121 } | 112 } |
122 | 113 |
123 // Assumptions: | 114 // Assumptions: |
124 // - Any database entry is one of: | 115 // - Any database entry is one of: |
125 // - ("CHILD_OF:|parent_id|:<name>", "|file_id|"), | 116 // - ("CHILD_OF:|parent_id|:<name>", "|file_id|"), |
126 // - ("LAST_FILE_ID", "|last_file_id|"), | 117 // - ("LAST_FILE_ID", "|last_file_id|"), |
127 // - ("LAST_INTEGER", "|last_integer|"), | 118 // - ("LAST_INTEGER", "|last_integer|"), |
128 // - ("|file_id|", "pickled FileInfo") | 119 // - ("|file_id|", "pickled FileInfo") |
129 // where FileInfo has |parent_id|, |data_path|, |name| and | 120 // where FileInfo has |parent_id|, |data_path|, |name| and |
130 // |modification_time|, | 121 // |modification_time|, |
131 // Constraints: | 122 // Constraints: |
132 // - Each file in the database has unique backing file. | 123 // - Each file in the database has unique backing file. |
133 // - Each file in |filesystem_data_directory_| has a database entry. | 124 // - Each file in |filesystem_data_directory_| has a database entry. |
134 // - Directory structure is tree, i.e. connected and acyclic. | 125 // - Directory structure is tree, i.e. connected and acyclic. |
135 class DatabaseCheckHelper { | 126 class DatabaseCheckHelper { |
136 public: | 127 public: |
137 typedef fileapi::SandboxDirectoryDatabase::FileId FileId; | 128 typedef storage::SandboxDirectoryDatabase::FileId FileId; |
138 typedef fileapi::SandboxDirectoryDatabase::FileInfo FileInfo; | 129 typedef storage::SandboxDirectoryDatabase::FileInfo FileInfo; |
139 | 130 |
140 DatabaseCheckHelper(fileapi::SandboxDirectoryDatabase* dir_db, | 131 DatabaseCheckHelper(storage::SandboxDirectoryDatabase* dir_db, |
141 leveldb::DB* db, | 132 leveldb::DB* db, |
142 const base::FilePath& path); | 133 const base::FilePath& path); |
143 | 134 |
144 bool IsFileSystemConsistent() { | 135 bool IsFileSystemConsistent() { |
145 return IsDatabaseEmpty() || | 136 return IsDatabaseEmpty() || |
146 (ScanDatabase() && ScanDirectory() && ScanHierarchy()); | 137 (ScanDatabase() && ScanDirectory() && ScanHierarchy()); |
147 } | 138 } |
148 | 139 |
149 private: | 140 private: |
150 bool IsDatabaseEmpty(); | 141 bool IsDatabaseEmpty(); |
151 // These 3 methods need to be called in the order. Each method requires its | 142 // 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 | 143 // previous method finished successfully. They also require the database is |
153 // not empty. | 144 // not empty. |
154 bool ScanDatabase(); | 145 bool ScanDatabase(); |
155 bool ScanDirectory(); | 146 bool ScanDirectory(); |
156 bool ScanHierarchy(); | 147 bool ScanHierarchy(); |
157 | 148 |
158 fileapi::SandboxDirectoryDatabase* dir_db_; | 149 storage::SandboxDirectoryDatabase* dir_db_; |
159 leveldb::DB* db_; | 150 leveldb::DB* db_; |
160 base::FilePath path_; | 151 base::FilePath path_; |
161 | 152 |
162 std::set<base::FilePath> files_in_db_; | 153 std::set<base::FilePath> files_in_db_; |
163 | 154 |
164 size_t num_directories_in_db_; | 155 size_t num_directories_in_db_; |
165 size_t num_files_in_db_; | 156 size_t num_files_in_db_; |
166 size_t num_hierarchy_links_in_db_; | 157 size_t num_hierarchy_links_in_db_; |
167 | 158 |
168 FileId last_file_id_; | 159 FileId last_file_id_; |
169 FileId last_integer_; | 160 FileId last_integer_; |
170 }; | 161 }; |
171 | 162 |
172 DatabaseCheckHelper::DatabaseCheckHelper( | 163 DatabaseCheckHelper::DatabaseCheckHelper( |
173 fileapi::SandboxDirectoryDatabase* dir_db, | 164 storage::SandboxDirectoryDatabase* dir_db, |
174 leveldb::DB* db, | 165 leveldb::DB* db, |
175 const base::FilePath& path) | 166 const base::FilePath& path) |
176 : dir_db_(dir_db), db_(db), path_(path), | 167 : dir_db_(dir_db), |
| 168 db_(db), |
| 169 path_(path), |
177 num_directories_in_db_(0), | 170 num_directories_in_db_(0), |
178 num_files_in_db_(0), | 171 num_files_in_db_(0), |
179 num_hierarchy_links_in_db_(0), | 172 num_hierarchy_links_in_db_(0), |
180 last_file_id_(-1), last_integer_(-1) { | 173 last_file_id_(-1), |
| 174 last_integer_(-1) { |
181 DCHECK(dir_db_); | 175 DCHECK(dir_db_); |
182 DCHECK(db_); | 176 DCHECK(db_); |
183 DCHECK(!path_.empty() && base::DirectoryExists(path_)); | 177 DCHECK(!path_.empty() && base::DirectoryExists(path_)); |
184 } | 178 } |
185 | 179 |
186 bool DatabaseCheckHelper::IsDatabaseEmpty() { | 180 bool DatabaseCheckHelper::IsDatabaseEmpty() { |
187 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); | 181 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); |
188 itr->SeekToFirst(); | 182 itr->SeekToFirst(); |
189 return !itr->Valid(); | 183 return !itr->Valid(); |
190 } | 184 } |
(...skipping 23 matching lines...) Expand all Loading... |
214 } else if (key == kLastIntegerKey) { | 208 } else if (key == kLastIntegerKey) { |
215 // key: "LAST_INTEGER" | 209 // key: "LAST_INTEGER" |
216 // value: "<last_integer>" | 210 // value: "<last_integer>" |
217 if (last_integer_ >= 0 || | 211 if (last_integer_ >= 0 || |
218 !base::StringToInt64(itr->value().ToString(), &last_integer_)) | 212 !base::StringToInt64(itr->value().ToString(), &last_integer_)) |
219 return false; | 213 return false; |
220 } else { | 214 } else { |
221 // key: "<entry_id>" | 215 // key: "<entry_id>" |
222 // value: "<pickled FileInfo>" | 216 // value: "<pickled FileInfo>" |
223 FileInfo file_info; | 217 FileInfo file_info; |
224 if (!FileInfoFromPickle( | 218 if (!FileInfoFromPickle(Pickle(itr->value().data(), itr->value().size()), |
225 Pickle(itr->value().data(), itr->value().size()), &file_info)) | 219 &file_info)) |
226 return false; | 220 return false; |
227 | 221 |
228 FileId file_id = -1; | 222 FileId file_id = -1; |
229 if (!base::StringToInt64(key, &file_id) || file_id < 0) | 223 if (!base::StringToInt64(key, &file_id) || file_id < 0) |
230 return false; | 224 return false; |
231 | 225 |
232 if (max_file_id < file_id) | 226 if (max_file_id < file_id) |
233 max_file_id = file_id; | 227 max_file_id = file_id; |
234 if (!file_ids.insert(file_id).second) | 228 if (!file_ids.insert(file_id).second) |
235 return false; | 229 return false; |
236 | 230 |
237 if (file_info.is_directory()) { | 231 if (file_info.is_directory()) { |
238 ++num_directories_in_db_; | 232 ++num_directories_in_db_; |
239 DCHECK(file_info.data_path.empty()); | 233 DCHECK(file_info.data_path.empty()); |
240 } else { | 234 } else { |
241 // Ensure any pair of file entry don't share their data_path. | 235 // Ensure any pair of file entry don't share their data_path. |
242 if (!files_in_db_.insert(file_info.data_path).second) | 236 if (!files_in_db_.insert(file_info.data_path).second) |
243 return false; | 237 return false; |
244 | 238 |
245 // Ensure the backing file exists as a normal file. | 239 // Ensure the backing file exists as a normal file. |
246 base::File::Info platform_file_info; | 240 base::File::Info platform_file_info; |
247 if (!base::GetFileInfo( | 241 if (!base::GetFileInfo(path_.Append(file_info.data_path), |
248 path_.Append(file_info.data_path), &platform_file_info) || | 242 &platform_file_info) || |
249 platform_file_info.is_directory || | 243 platform_file_info.is_directory || |
250 platform_file_info.is_symbolic_link) { | 244 platform_file_info.is_symbolic_link) { |
251 // leveldb::Iterator iterates a snapshot of the database. | 245 // leveldb::Iterator iterates a snapshot of the database. |
252 // So even after RemoveFileInfo() call, we'll visit hierarchy link | 246 // So even after RemoveFileInfo() call, we'll visit hierarchy link |
253 // from |parent_id| to |file_id|. | 247 // from |parent_id| to |file_id|. |
254 if (!dir_db_->RemoveFileInfo(file_id)) | 248 if (!dir_db_->RemoveFileInfo(file_id)) |
255 return false; | 249 return false; |
256 --num_hierarchy_links_in_db_; | 250 --num_hierarchy_links_in_db_; |
257 files_in_db_.erase(file_info.data_path); | 251 files_in_db_.erase(file_info.data_path); |
258 } else { | 252 } else { |
259 ++num_files_in_db_; | 253 ++num_files_in_db_; |
260 } | 254 } |
261 } | 255 } |
262 } | 256 } |
263 } | 257 } |
264 | 258 |
265 // TODO(tzik): Add constraint for |last_integer_| to avoid possible | 259 // TODO(tzik): Add constraint for |last_integer_| to avoid possible |
266 // data path confliction on ObfuscatedFileUtil. | 260 // data path confliction on ObfuscatedFileUtil. |
267 return max_file_id <= last_file_id_; | 261 return max_file_id <= last_file_id_; |
268 } | 262 } |
269 | 263 |
270 bool DatabaseCheckHelper::ScanDirectory() { | 264 bool DatabaseCheckHelper::ScanDirectory() { |
271 // TODO(kinuko): Scans all local file system entries to verify each of them | 265 // TODO(kinuko): Scans all local file system entries to verify each of them |
272 // has a database entry. | 266 // has a database entry. |
273 const base::FilePath kExcludes[] = { | 267 const base::FilePath kExcludes[] = { |
274 base::FilePath(kDirectoryDatabaseName), | 268 base::FilePath(kDirectoryDatabaseName), |
275 base::FilePath(fileapi::FileSystemUsageCache::kUsageFileName), | 269 base::FilePath(storage::FileSystemUsageCache::kUsageFileName), |
276 }; | 270 }; |
277 | 271 |
278 // Any path in |pending_directories| is relative to |path_|. | 272 // Any path in |pending_directories| is relative to |path_|. |
279 std::stack<base::FilePath> pending_directories; | 273 std::stack<base::FilePath> pending_directories; |
280 pending_directories.push(base::FilePath()); | 274 pending_directories.push(base::FilePath()); |
281 | 275 |
282 while (!pending_directories.empty()) { | 276 while (!pending_directories.empty()) { |
283 base::FilePath dir_path = pending_directories.top(); | 277 base::FilePath dir_path = pending_directories.top(); |
284 pending_directories.pop(); | 278 pending_directories.pop(); |
285 | 279 |
286 base::FileEnumerator file_enum( | 280 base::FileEnumerator file_enum( |
287 dir_path.empty() ? path_ : path_.Append(dir_path), | 281 dir_path.empty() ? path_ : path_.Append(dir_path), |
288 false /* not recursive */, | 282 false /* not recursive */, |
289 base::FileEnumerator::DIRECTORIES | base::FileEnumerator::FILES); | 283 base::FileEnumerator::DIRECTORIES | base::FileEnumerator::FILES); |
290 | 284 |
291 base::FilePath absolute_file_path; | 285 base::FilePath absolute_file_path; |
292 while (!(absolute_file_path = file_enum.Next()).empty()) { | 286 while (!(absolute_file_path = file_enum.Next()).empty()) { |
293 base::FileEnumerator::FileInfo find_info = file_enum.GetInfo(); | 287 base::FileEnumerator::FileInfo find_info = file_enum.GetInfo(); |
294 | 288 |
295 base::FilePath relative_file_path; | 289 base::FilePath relative_file_path; |
296 if (!path_.AppendRelativePath(absolute_file_path, &relative_file_path)) | 290 if (!path_.AppendRelativePath(absolute_file_path, &relative_file_path)) |
297 return false; | 291 return false; |
298 | 292 |
299 if (std::find(kExcludes, kExcludes + arraysize(kExcludes), | 293 if (std::find(kExcludes, |
| 294 kExcludes + arraysize(kExcludes), |
300 relative_file_path) != kExcludes + arraysize(kExcludes)) | 295 relative_file_path) != kExcludes + arraysize(kExcludes)) |
301 continue; | 296 continue; |
302 | 297 |
303 if (find_info.IsDirectory()) { | 298 if (find_info.IsDirectory()) { |
304 pending_directories.push(relative_file_path); | 299 pending_directories.push(relative_file_path); |
305 continue; | 300 continue; |
306 } | 301 } |
307 | 302 |
308 // Check if the file has a database entry. | 303 // Check if the file has a database entry. |
309 std::set<base::FilePath>::iterator itr = | 304 std::set<base::FilePath>::iterator itr = |
(...skipping 15 matching lines...) Expand all Loading... |
325 size_t visited_files = 0; | 320 size_t visited_files = 0; |
326 size_t visited_links = 0; | 321 size_t visited_links = 0; |
327 | 322 |
328 std::stack<FileId> directories; | 323 std::stack<FileId> directories; |
329 directories.push(0); | 324 directories.push(0); |
330 | 325 |
331 // Check if the root directory exists as a directory. | 326 // Check if the root directory exists as a directory. |
332 FileInfo file_info; | 327 FileInfo file_info; |
333 if (!dir_db_->GetFileInfo(0, &file_info)) | 328 if (!dir_db_->GetFileInfo(0, &file_info)) |
334 return false; | 329 return false; |
335 if (file_info.parent_id != 0 || | 330 if (file_info.parent_id != 0 || !file_info.is_directory()) |
336 !file_info.is_directory()) | |
337 return false; | 331 return false; |
338 | 332 |
339 while (!directories.empty()) { | 333 while (!directories.empty()) { |
340 ++visited_directories; | 334 ++visited_directories; |
341 FileId dir_id = directories.top(); | 335 FileId dir_id = directories.top(); |
342 directories.pop(); | 336 directories.pop(); |
343 | 337 |
344 std::vector<FileId> children; | 338 std::vector<FileId> children; |
345 if (!dir_db_->ListChildren(dir_id, &children)) | 339 if (!dir_db_->ListChildren(dir_id, &children)) |
346 return false; | 340 return false; |
(...skipping 20 matching lines...) Expand all Loading... |
367 if (file_info.is_directory()) | 361 if (file_info.is_directory()) |
368 directories.push(*itr); | 362 directories.push(*itr); |
369 else | 363 else |
370 ++visited_files; | 364 ++visited_files; |
371 ++visited_links; | 365 ++visited_links; |
372 } | 366 } |
373 } | 367 } |
374 | 368 |
375 // Check if we've visited all database entries. | 369 // Check if we've visited all database entries. |
376 return num_directories_in_db_ == visited_directories && | 370 return num_directories_in_db_ == visited_directories && |
377 num_files_in_db_ == visited_files && | 371 num_files_in_db_ == visited_files && |
378 num_hierarchy_links_in_db_ == visited_links; | 372 num_hierarchy_links_in_db_ == visited_links; |
379 } | 373 } |
380 | 374 |
381 // Returns true if the given |data_path| contains no parent references ("..") | 375 // Returns true if the given |data_path| contains no parent references ("..") |
382 // and does not refer to special system files. | 376 // and does not refer to special system files. |
383 // This is called in GetFileInfo, AddFileInfo and UpdateFileInfo to | 377 // This is called in GetFileInfo, AddFileInfo and UpdateFileInfo to |
384 // ensure we're only dealing with valid data paths. | 378 // ensure we're only dealing with valid data paths. |
385 bool VerifyDataPath(const base::FilePath& data_path) { | 379 bool VerifyDataPath(const base::FilePath& data_path) { |
386 // |data_path| should not contain any ".." and should be a relative path | 380 // |data_path| should not contain any ".." and should be a relative path |
387 // (to the filesystem_data_directory_). | 381 // (to the filesystem_data_directory_). |
388 if (data_path.ReferencesParent() || data_path.IsAbsolute()) | 382 if (data_path.ReferencesParent() || data_path.IsAbsolute()) |
389 return false; | 383 return false; |
390 // See if it's not pointing to the special system paths. | 384 // See if it's not pointing to the special system paths. |
391 const base::FilePath kExcludes[] = { | 385 const base::FilePath kExcludes[] = { |
392 base::FilePath(kDirectoryDatabaseName), | 386 base::FilePath(kDirectoryDatabaseName), |
393 base::FilePath(fileapi::FileSystemUsageCache::kUsageFileName), | 387 base::FilePath(storage::FileSystemUsageCache::kUsageFileName), |
394 }; | 388 }; |
395 for (size_t i = 0; i < arraysize(kExcludes); ++i) { | 389 for (size_t i = 0; i < arraysize(kExcludes); ++i) { |
396 if (data_path == kExcludes[i] || kExcludes[i].IsParent(data_path)) | 390 if (data_path == kExcludes[i] || kExcludes[i].IsParent(data_path)) |
397 return false; | 391 return false; |
398 } | 392 } |
399 return true; | 393 return true; |
400 } | 394 } |
401 | 395 |
402 } // namespace | 396 } // namespace |
403 | 397 |
404 namespace fileapi { | 398 namespace storage { |
405 | 399 |
406 SandboxDirectoryDatabase::FileInfo::FileInfo() : parent_id(0) { | 400 SandboxDirectoryDatabase::FileInfo::FileInfo() : parent_id(0) { |
407 } | 401 } |
408 | 402 |
409 SandboxDirectoryDatabase::FileInfo::~FileInfo() { | 403 SandboxDirectoryDatabase::FileInfo::~FileInfo() { |
410 } | 404 } |
411 | 405 |
412 SandboxDirectoryDatabase::SandboxDirectoryDatabase( | 406 SandboxDirectoryDatabase::SandboxDirectoryDatabase( |
413 const base::FilePath& filesystem_data_directory, | 407 const base::FilePath& filesystem_data_directory, |
414 leveldb::Env* env_override) | 408 leveldb::Env* env_override) |
(...skipping 21 matching lines...) Expand all Loading... |
436 if (!base::StringToInt64(child_id_string, child_id)) { | 430 if (!base::StringToInt64(child_id_string, child_id)) { |
437 LOG(ERROR) << "Hit database corruption!"; | 431 LOG(ERROR) << "Hit database corruption!"; |
438 return false; | 432 return false; |
439 } | 433 } |
440 return true; | 434 return true; |
441 } | 435 } |
442 HandleError(FROM_HERE, status); | 436 HandleError(FROM_HERE, status); |
443 return false; | 437 return false; |
444 } | 438 } |
445 | 439 |
446 bool SandboxDirectoryDatabase::GetFileWithPath( | 440 bool SandboxDirectoryDatabase::GetFileWithPath(const base::FilePath& path, |
447 const base::FilePath& path, FileId* file_id) { | 441 FileId* file_id) { |
448 std::vector<base::FilePath::StringType> components; | 442 std::vector<base::FilePath::StringType> components; |
449 VirtualPath::GetComponents(path, &components); | 443 VirtualPath::GetComponents(path, &components); |
450 FileId local_id = 0; | 444 FileId local_id = 0; |
451 std::vector<base::FilePath::StringType>::iterator iter; | 445 std::vector<base::FilePath::StringType>::iterator iter; |
452 for (iter = components.begin(); iter != components.end(); ++iter) { | 446 for (iter = components.begin(); iter != components.end(); ++iter) { |
453 base::FilePath::StringType name; | 447 base::FilePath::StringType name; |
454 name = *iter; | 448 name = *iter; |
455 if (name == FILE_PATH_LITERAL("/")) | 449 if (name == FILE_PATH_LITERAL("/")) |
456 continue; | 450 continue; |
457 if (!GetChildWithName(local_id, name, &local_id)) | 451 if (!GetChildWithName(local_id, name, &local_id)) |
458 return false; | 452 return false; |
459 } | 453 } |
460 *file_id = local_id; | 454 *file_id = local_id; |
461 return true; | 455 return true; |
462 } | 456 } |
463 | 457 |
464 bool SandboxDirectoryDatabase::ListChildren( | 458 bool SandboxDirectoryDatabase::ListChildren(FileId parent_id, |
465 FileId parent_id, std::vector<FileId>* children) { | 459 std::vector<FileId>* children) { |
466 // Check to add later: fail if parent is a file, at least in debug builds. | 460 // Check to add later: fail if parent is a file, at least in debug builds. |
467 if (!Init(REPAIR_ON_CORRUPTION)) | 461 if (!Init(REPAIR_ON_CORRUPTION)) |
468 return false; | 462 return false; |
469 DCHECK(children); | 463 DCHECK(children); |
470 std::string child_key_prefix = GetChildListingKeyPrefix(parent_id); | 464 std::string child_key_prefix = GetChildListingKeyPrefix(parent_id); |
471 | 465 |
472 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions())); | 466 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions())); |
473 iter->Seek(child_key_prefix); | 467 iter->Seek(child_key_prefix); |
474 children->clear(); | 468 children->clear(); |
475 while (iter->Valid() && | 469 while (iter->Valid() && |
476 StartsWithASCII(iter->key().ToString(), child_key_prefix, true)) { | 470 StartsWithASCII(iter->key().ToString(), child_key_prefix, true)) { |
477 std::string child_id_string = iter->value().ToString(); | 471 std::string child_id_string = iter->value().ToString(); |
478 FileId child_id; | 472 FileId child_id; |
479 if (!base::StringToInt64(child_id_string, &child_id)) { | 473 if (!base::StringToInt64(child_id_string, &child_id)) { |
480 LOG(ERROR) << "Hit database corruption!"; | 474 LOG(ERROR) << "Hit database corruption!"; |
481 return false; | 475 return false; |
482 } | 476 } |
483 children->push_back(child_id); | 477 children->push_back(child_id); |
484 iter->Next(); | 478 iter->Next(); |
485 } | 479 } |
486 return true; | 480 return true; |
(...skipping 26 matching lines...) Expand all Loading... |
513 info->name = base::FilePath::StringType(); | 507 info->name = base::FilePath::StringType(); |
514 info->data_path = base::FilePath(); | 508 info->data_path = base::FilePath(); |
515 info->modification_time = base::Time::Now(); | 509 info->modification_time = base::Time::Now(); |
516 info->parent_id = 0; | 510 info->parent_id = 0; |
517 return true; | 511 return true; |
518 } | 512 } |
519 HandleError(FROM_HERE, status); | 513 HandleError(FROM_HERE, status); |
520 return false; | 514 return false; |
521 } | 515 } |
522 | 516 |
523 base::File::Error SandboxDirectoryDatabase::AddFileInfo( | 517 base::File::Error SandboxDirectoryDatabase::AddFileInfo(const FileInfo& info, |
524 const FileInfo& info, FileId* file_id) { | 518 FileId* file_id) { |
525 if (!Init(REPAIR_ON_CORRUPTION)) | 519 if (!Init(REPAIR_ON_CORRUPTION)) |
526 return base::File::FILE_ERROR_FAILED; | 520 return base::File::FILE_ERROR_FAILED; |
527 DCHECK(file_id); | 521 DCHECK(file_id); |
528 std::string child_key = GetChildLookupKey(info.parent_id, info.name); | 522 std::string child_key = GetChildLookupKey(info.parent_id, info.name); |
529 std::string child_id_string; | 523 std::string child_id_string; |
530 leveldb::Status status = | 524 leveldb::Status status = |
531 db_->Get(leveldb::ReadOptions(), child_key, &child_id_string); | 525 db_->Get(leveldb::ReadOptions(), child_key, &child_id_string); |
532 if (status.ok()) { | 526 if (status.ok()) { |
533 LOG(ERROR) << "File exists already!"; | 527 LOG(ERROR) << "File exists already!"; |
534 return base::File::FILE_ERROR_EXISTS; | 528 return base::File::FILE_ERROR_EXISTS; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
572 if (!RemoveFileInfoHelper(file_id, &batch)) | 566 if (!RemoveFileInfoHelper(file_id, &batch)) |
573 return false; | 567 return false; |
574 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); | 568 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); |
575 if (!status.ok()) { | 569 if (!status.ok()) { |
576 HandleError(FROM_HERE, status); | 570 HandleError(FROM_HERE, status); |
577 return false; | 571 return false; |
578 } | 572 } |
579 return true; | 573 return true; |
580 } | 574 } |
581 | 575 |
582 bool SandboxDirectoryDatabase::UpdateFileInfo( | 576 bool SandboxDirectoryDatabase::UpdateFileInfo(FileId file_id, |
583 FileId file_id, const FileInfo& new_info) { | 577 const FileInfo& new_info) { |
584 // TODO(ericu): We should also check to see that this doesn't create a loop, | 578 // TODO(ericu): We should also check to see that this doesn't create a loop, |
585 // but perhaps only in a debug build. | 579 // but perhaps only in a debug build. |
586 if (!Init(REPAIR_ON_CORRUPTION)) | 580 if (!Init(REPAIR_ON_CORRUPTION)) |
587 return false; | 581 return false; |
588 DCHECK(file_id); // You can't remove the root, ever. Just delete the DB. | 582 DCHECK(file_id); // You can't remove the root, ever. Just delete the DB. |
589 FileInfo old_info; | 583 FileInfo old_info; |
590 if (!GetFileInfo(file_id, &old_info)) | 584 if (!GetFileInfo(file_id, &old_info)) |
591 return false; | 585 return false; |
592 if (old_info.parent_id != new_info.parent_id && | 586 if (old_info.parent_id != new_info.parent_id && |
593 !IsDirectory(new_info.parent_id)) | 587 !IsDirectory(new_info.parent_id)) |
(...skipping 13 matching lines...) Expand all Loading... |
607 return false; | 601 return false; |
608 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); | 602 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); |
609 if (!status.ok()) { | 603 if (!status.ok()) { |
610 HandleError(FROM_HERE, status); | 604 HandleError(FROM_HERE, status); |
611 return false; | 605 return false; |
612 } | 606 } |
613 return true; | 607 return true; |
614 } | 608 } |
615 | 609 |
616 bool SandboxDirectoryDatabase::UpdateModificationTime( | 610 bool SandboxDirectoryDatabase::UpdateModificationTime( |
617 FileId file_id, const base::Time& modification_time) { | 611 FileId file_id, |
| 612 const base::Time& modification_time) { |
618 FileInfo info; | 613 FileInfo info; |
619 if (!GetFileInfo(file_id, &info)) | 614 if (!GetFileInfo(file_id, &info)) |
620 return false; | 615 return false; |
621 info.modification_time = modification_time; | 616 info.modification_time = modification_time; |
622 Pickle pickle; | 617 Pickle pickle; |
623 if (!PickleFromFileInfo(info, &pickle)) | 618 if (!PickleFromFileInfo(info, &pickle)) |
624 return false; | 619 return false; |
625 leveldb::Status status = db_->Put( | 620 leveldb::Status status = |
626 leveldb::WriteOptions(), | 621 db_->Put(leveldb::WriteOptions(), |
627 GetFileLookupKey(file_id), | 622 GetFileLookupKey(file_id), |
628 leveldb::Slice(reinterpret_cast<const char *>(pickle.data()), | 623 leveldb::Slice(reinterpret_cast<const char*>(pickle.data()), |
629 pickle.size())); | 624 pickle.size())); |
630 if (!status.ok()) { | 625 if (!status.ok()) { |
631 HandleError(FROM_HERE, status); | 626 HandleError(FROM_HERE, status); |
632 return false; | 627 return false; |
633 } | 628 } |
634 return true; | 629 return true; |
635 } | 630 } |
636 | 631 |
637 bool SandboxDirectoryDatabase::OverwritingMoveFile( | 632 bool SandboxDirectoryDatabase::OverwritingMoveFile(FileId src_file_id, |
638 FileId src_file_id, FileId dest_file_id) { | 633 FileId dest_file_id) { |
639 FileInfo src_file_info; | 634 FileInfo src_file_info; |
640 FileInfo dest_file_info; | 635 FileInfo dest_file_info; |
641 | 636 |
642 if (!GetFileInfo(src_file_id, &src_file_info)) | 637 if (!GetFileInfo(src_file_id, &src_file_info)) |
643 return false; | 638 return false; |
644 if (!GetFileInfo(dest_file_id, &dest_file_info)) | 639 if (!GetFileInfo(dest_file_id, &dest_file_info)) |
645 return false; | 640 return false; |
646 if (src_file_info.is_directory() || dest_file_info.is_directory()) | 641 if (src_file_info.is_directory() || dest_file_info.is_directory()) |
647 return false; | 642 return false; |
648 leveldb::WriteBatch batch; | 643 leveldb::WriteBatch batch; |
649 // This is the only field that really gets moved over; if you add fields to | 644 // This is the only field that really gets moved over; if you add fields to |
650 // FileInfo, e.g. ctime, they might need to be copied here. | 645 // FileInfo, e.g. ctime, they might need to be copied here. |
651 dest_file_info.data_path = src_file_info.data_path; | 646 dest_file_info.data_path = src_file_info.data_path; |
652 if (!RemoveFileInfoHelper(src_file_id, &batch)) | 647 if (!RemoveFileInfoHelper(src_file_id, &batch)) |
653 return false; | 648 return false; |
654 Pickle pickle; | 649 Pickle pickle; |
655 if (!PickleFromFileInfo(dest_file_info, &pickle)) | 650 if (!PickleFromFileInfo(dest_file_info, &pickle)) |
656 return false; | 651 return false; |
657 batch.Put( | 652 batch.Put(GetFileLookupKey(dest_file_id), |
658 GetFileLookupKey(dest_file_id), | 653 leveldb::Slice(reinterpret_cast<const char*>(pickle.data()), |
659 leveldb::Slice(reinterpret_cast<const char *>(pickle.data()), | 654 pickle.size())); |
660 pickle.size())); | |
661 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); | 655 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); |
662 if (!status.ok()) { | 656 if (!status.ok()) { |
663 HandleError(FROM_HERE, status); | 657 HandleError(FROM_HERE, status); |
664 return false; | 658 return false; |
665 } | 659 } |
666 return true; | 660 return true; |
667 } | 661 } |
668 | 662 |
669 bool SandboxDirectoryDatabase::GetNextInteger(int64* next) { | 663 bool SandboxDirectoryDatabase::GetNextInteger(int64* next) { |
670 if (!Init(REPAIR_ON_CORRUPTION)) | 664 if (!Init(REPAIR_ON_CORRUPTION)) |
671 return false; | 665 return false; |
672 DCHECK(next); | 666 DCHECK(next); |
673 std::string int_string; | 667 std::string int_string; |
674 leveldb::Status status = | 668 leveldb::Status status = |
675 db_->Get(leveldb::ReadOptions(), LastIntegerKey(), &int_string); | 669 db_->Get(leveldb::ReadOptions(), LastIntegerKey(), &int_string); |
676 if (status.ok()) { | 670 if (status.ok()) { |
677 int64 temp; | 671 int64 temp; |
678 if (!base::StringToInt64(int_string, &temp)) { | 672 if (!base::StringToInt64(int_string, &temp)) { |
679 LOG(ERROR) << "Hit database corruption!"; | 673 LOG(ERROR) << "Hit database corruption!"; |
680 return false; | 674 return false; |
681 } | 675 } |
682 ++temp; | 676 ++temp; |
683 status = db_->Put(leveldb::WriteOptions(), LastIntegerKey(), | 677 status = db_->Put( |
684 base::Int64ToString(temp)); | 678 leveldb::WriteOptions(), LastIntegerKey(), base::Int64ToString(temp)); |
685 if (!status.ok()) { | 679 if (!status.ok()) { |
686 HandleError(FROM_HERE, status); | 680 HandleError(FROM_HERE, status); |
687 return false; | 681 return false; |
688 } | 682 } |
689 *next = temp; | 683 *next = temp; |
690 return true; | 684 return true; |
691 } | 685 } |
692 if (!status.IsNotFound()) { | 686 if (!status.IsNotFound()) { |
693 HandleError(FROM_HERE, status); | 687 HandleError(FROM_HERE, status); |
694 return false; | 688 return false; |
695 } | 689 } |
696 // The database must not yet exist; initialize it. | 690 // The database must not yet exist; initialize it. |
697 if (!StoreDefaultValues()) | 691 if (!StoreDefaultValues()) |
698 return false; | 692 return false; |
699 | 693 |
700 return GetNextInteger(next); | 694 return GetNextInteger(next); |
701 } | 695 } |
702 | 696 |
703 // static | 697 // static |
704 bool SandboxDirectoryDatabase::DestroyDatabase(const base::FilePath& path, | 698 bool SandboxDirectoryDatabase::DestroyDatabase(const base::FilePath& path, |
705 leveldb::Env* env_override) { | 699 leveldb::Env* env_override) { |
706 std::string name = FilePathToString(path.Append(kDirectoryDatabaseName)); | 700 std::string name = FilePathToString(path.Append(kDirectoryDatabaseName)); |
707 leveldb::Options options; | 701 leveldb::Options options; |
708 if (env_override) | 702 if (env_override) |
709 options.env = env_override; | 703 options.env = env_override; |
710 leveldb::Status status = leveldb::DestroyDB(name, options); | 704 leveldb::Status status = leveldb::DestroyDB(name, options); |
711 if (status.ok()) | 705 if (status.ok()) |
712 return true; | 706 return true; |
713 LOG(WARNING) << "Failed to destroy a database with status " << | 707 LOG(WARNING) << "Failed to destroy a database with status " |
714 status.ToString(); | 708 << status.ToString(); |
715 return false; | 709 return false; |
716 } | 710 } |
717 | 711 |
718 bool SandboxDirectoryDatabase::Init(RecoveryOption recovery_option) { | 712 bool SandboxDirectoryDatabase::Init(RecoveryOption recovery_option) { |
719 if (db_) | 713 if (db_) |
720 return true; | 714 return true; |
721 | 715 |
722 std::string path = | 716 std::string path = FilePathToString( |
723 FilePathToString(filesystem_data_directory_.Append( | 717 filesystem_data_directory_.Append(kDirectoryDatabaseName)); |
724 kDirectoryDatabaseName)); | |
725 leveldb::Options options; | 718 leveldb::Options options; |
726 options.max_open_files = 0; // Use minimum. | 719 options.max_open_files = 0; // Use minimum. |
727 options.create_if_missing = true; | 720 options.create_if_missing = true; |
728 if (env_override_) | 721 if (env_override_) |
729 options.env = env_override_; | 722 options.env = env_override_; |
730 leveldb::DB* db; | 723 leveldb::DB* db; |
731 leveldb::Status status = leveldb::DB::Open(options, path, &db); | 724 leveldb::Status status = leveldb::DB::Open(options, path, &db); |
732 ReportInitStatus(status); | 725 ReportInitStatus(status); |
733 if (status.ok()) { | 726 if (status.ok()) { |
734 db_.reset(db); | 727 db_.reset(db); |
735 return true; | 728 return true; |
736 } | 729 } |
737 HandleError(FROM_HERE, status); | 730 HandleError(FROM_HERE, status); |
738 | 731 |
739 // Corruption due to missing necessary MANIFEST-* file causes IOError instead | 732 // Corruption due to missing necessary MANIFEST-* file causes IOError instead |
740 // of Corruption error. | 733 // of Corruption error. |
741 // Try to repair database even when IOError case. | 734 // Try to repair database even when IOError case. |
742 if (!status.IsCorruption() && !status.IsIOError()) | 735 if (!status.IsCorruption() && !status.IsIOError()) |
743 return false; | 736 return false; |
744 | 737 |
745 switch (recovery_option) { | 738 switch (recovery_option) { |
746 case FAIL_ON_CORRUPTION: | 739 case FAIL_ON_CORRUPTION: |
747 return false; | 740 return false; |
748 case REPAIR_ON_CORRUPTION: | 741 case REPAIR_ON_CORRUPTION: |
749 LOG(WARNING) << "Corrupted SandboxDirectoryDatabase detected." | 742 LOG(WARNING) << "Corrupted SandboxDirectoryDatabase detected." |
750 << " Attempting to repair."; | 743 << " Attempting to repair."; |
751 if (RepairDatabase(path)) { | 744 if (RepairDatabase(path)) { |
752 UMA_HISTOGRAM_ENUMERATION(kDatabaseRepairHistogramLabel, | 745 UMA_HISTOGRAM_ENUMERATION( |
753 DB_REPAIR_SUCCEEDED, DB_REPAIR_MAX); | 746 kDatabaseRepairHistogramLabel, DB_REPAIR_SUCCEEDED, DB_REPAIR_MAX); |
754 return true; | 747 return true; |
755 } | 748 } |
756 UMA_HISTOGRAM_ENUMERATION(kDatabaseRepairHistogramLabel, | 749 UMA_HISTOGRAM_ENUMERATION( |
757 DB_REPAIR_FAILED, DB_REPAIR_MAX); | 750 kDatabaseRepairHistogramLabel, DB_REPAIR_FAILED, DB_REPAIR_MAX); |
758 LOG(WARNING) << "Failed to repair SandboxDirectoryDatabase."; | 751 LOG(WARNING) << "Failed to repair SandboxDirectoryDatabase."; |
759 // fall through | 752 // fall through |
760 case DELETE_ON_CORRUPTION: | 753 case DELETE_ON_CORRUPTION: |
761 LOG(WARNING) << "Clearing SandboxDirectoryDatabase."; | 754 LOG(WARNING) << "Clearing SandboxDirectoryDatabase."; |
762 if (!base::DeleteFile(filesystem_data_directory_, true)) | 755 if (!base::DeleteFile(filesystem_data_directory_, true)) |
763 return false; | 756 return false; |
764 if (!base::CreateDirectory(filesystem_data_directory_)) | 757 if (!base::CreateDirectory(filesystem_data_directory_)) |
765 return false; | 758 return false; |
766 return Init(FAIL_ON_CORRUPTION); | 759 return Init(FAIL_ON_CORRUPTION); |
767 } | 760 } |
768 | 761 |
769 NOTREACHED(); | 762 NOTREACHED(); |
(...skipping 27 matching lines...) Expand all Loading... |
797 return true; | 790 return true; |
798 } | 791 } |
799 | 792 |
800 bool SandboxDirectoryDatabase::IsFileSystemConsistent() { | 793 bool SandboxDirectoryDatabase::IsFileSystemConsistent() { |
801 if (!Init(FAIL_ON_CORRUPTION)) | 794 if (!Init(FAIL_ON_CORRUPTION)) |
802 return false; | 795 return false; |
803 DatabaseCheckHelper helper(this, db_.get(), filesystem_data_directory_); | 796 DatabaseCheckHelper helper(this, db_.get(), filesystem_data_directory_); |
804 return helper.IsFileSystemConsistent(); | 797 return helper.IsFileSystemConsistent(); |
805 } | 798 } |
806 | 799 |
807 void SandboxDirectoryDatabase::ReportInitStatus( | 800 void SandboxDirectoryDatabase::ReportInitStatus(const leveldb::Status& status) { |
808 const leveldb::Status& status) { | |
809 base::Time now = base::Time::Now(); | 801 base::Time now = base::Time::Now(); |
810 const base::TimeDelta minimum_interval = | 802 const base::TimeDelta minimum_interval = |
811 base::TimeDelta::FromHours(kMinimumReportIntervalHours); | 803 base::TimeDelta::FromHours(kMinimumReportIntervalHours); |
812 if (last_reported_time_ + minimum_interval >= now) | 804 if (last_reported_time_ + minimum_interval >= now) |
813 return; | 805 return; |
814 last_reported_time_ = now; | 806 last_reported_time_ = now; |
815 | 807 |
816 if (status.ok()) { | 808 if (status.ok()) { |
817 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel, | 809 UMA_HISTOGRAM_ENUMERATION( |
818 INIT_STATUS_OK, INIT_STATUS_MAX); | 810 kInitStatusHistogramLabel, INIT_STATUS_OK, INIT_STATUS_MAX); |
819 } else if (status.IsCorruption()) { | 811 } else if (status.IsCorruption()) { |
820 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel, | 812 UMA_HISTOGRAM_ENUMERATION( |
821 INIT_STATUS_CORRUPTION, INIT_STATUS_MAX); | 813 kInitStatusHistogramLabel, INIT_STATUS_CORRUPTION, INIT_STATUS_MAX); |
822 } else if (status.IsIOError()) { | 814 } else if (status.IsIOError()) { |
823 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel, | 815 UMA_HISTOGRAM_ENUMERATION( |
824 INIT_STATUS_IO_ERROR, INIT_STATUS_MAX); | 816 kInitStatusHistogramLabel, INIT_STATUS_IO_ERROR, INIT_STATUS_MAX); |
825 } else { | 817 } else { |
826 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel, | 818 UMA_HISTOGRAM_ENUMERATION( |
827 INIT_STATUS_UNKNOWN_ERROR, INIT_STATUS_MAX); | 819 kInitStatusHistogramLabel, INIT_STATUS_UNKNOWN_ERROR, INIT_STATUS_MAX); |
828 } | 820 } |
829 } | 821 } |
830 | 822 |
831 bool SandboxDirectoryDatabase::StoreDefaultValues() { | 823 bool SandboxDirectoryDatabase::StoreDefaultValues() { |
832 // Verify that this is a totally new database, and initialize it. | 824 // Verify that this is a totally new database, and initialize it. |
833 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions())); | 825 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions())); |
834 iter->SeekToFirst(); | 826 iter->SeekToFirst(); |
835 if (iter->Valid()) { // DB was not empty--we shouldn't have been called. | 827 if (iter->Valid()) { // DB was not empty--we shouldn't have been called. |
836 LOG(ERROR) << "File system origin database is corrupt!"; | 828 LOG(ERROR) << "File system origin database is corrupt!"; |
837 return false; | 829 return false; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
873 return false; | 865 return false; |
874 } | 866 } |
875 // The database must not yet exist; initialize it. | 867 // The database must not yet exist; initialize it. |
876 if (!StoreDefaultValues()) | 868 if (!StoreDefaultValues()) |
877 return false; | 869 return false; |
878 *file_id = 0; | 870 *file_id = 0; |
879 return true; | 871 return true; |
880 } | 872 } |
881 | 873 |
882 // This does very few safety checks! | 874 // This does very few safety checks! |
883 bool SandboxDirectoryDatabase::AddFileInfoHelper( | 875 bool SandboxDirectoryDatabase::AddFileInfoHelper(const FileInfo& info, |
884 const FileInfo& info, FileId file_id, leveldb::WriteBatch* batch) { | 876 FileId file_id, |
| 877 leveldb::WriteBatch* batch) { |
885 if (!VerifyDataPath(info.data_path)) { | 878 if (!VerifyDataPath(info.data_path)) { |
886 LOG(ERROR) << "Invalid data path is given: " << info.data_path.value(); | 879 LOG(ERROR) << "Invalid data path is given: " << info.data_path.value(); |
887 return false; | 880 return false; |
888 } | 881 } |
889 std::string id_string = GetFileLookupKey(file_id); | 882 std::string id_string = GetFileLookupKey(file_id); |
890 if (!file_id) { | 883 if (!file_id) { |
891 // The root directory doesn't need to be looked up by path from its parent. | 884 // The root directory doesn't need to be looked up by path from its parent. |
892 DCHECK(!info.parent_id); | 885 DCHECK(!info.parent_id); |
893 DCHECK(info.data_path.empty()); | 886 DCHECK(info.data_path.empty()); |
894 } else { | 887 } else { |
895 std::string child_key = GetChildLookupKey(info.parent_id, info.name); | 888 std::string child_key = GetChildLookupKey(info.parent_id, info.name); |
896 batch->Put(child_key, id_string); | 889 batch->Put(child_key, id_string); |
897 } | 890 } |
898 Pickle pickle; | 891 Pickle pickle; |
899 if (!PickleFromFileInfo(info, &pickle)) | 892 if (!PickleFromFileInfo(info, &pickle)) |
900 return false; | 893 return false; |
901 batch->Put( | 894 batch->Put(id_string, |
902 id_string, | 895 leveldb::Slice(reinterpret_cast<const char*>(pickle.data()), |
903 leveldb::Slice(reinterpret_cast<const char *>(pickle.data()), | 896 pickle.size())); |
904 pickle.size())); | |
905 return true; | 897 return true; |
906 } | 898 } |
907 | 899 |
908 // This does very few safety checks! | 900 // This does very few safety checks! |
909 bool SandboxDirectoryDatabase::RemoveFileInfoHelper( | 901 bool SandboxDirectoryDatabase::RemoveFileInfoHelper( |
910 FileId file_id, leveldb::WriteBatch* batch) { | 902 FileId file_id, |
| 903 leveldb::WriteBatch* batch) { |
911 DCHECK(file_id); // You can't remove the root, ever. Just delete the DB. | 904 DCHECK(file_id); // You can't remove the root, ever. Just delete the DB. |
912 FileInfo info; | 905 FileInfo info; |
913 if (!GetFileInfo(file_id, &info)) | 906 if (!GetFileInfo(file_id, &info)) |
914 return false; | 907 return false; |
915 if (info.data_path.empty()) { // It's a directory | 908 if (info.data_path.empty()) { // It's a directory |
916 std::vector<FileId> children; | 909 std::vector<FileId> children; |
917 // TODO(ericu): Make a faster is-the-directory-empty check. | 910 // TODO(ericu): Make a faster is-the-directory-empty check. |
918 if (!ListChildren(file_id, &children)) | 911 if (!ListChildren(file_id, &children)) |
919 return false; | 912 return false; |
920 if (children.size()) { | 913 if (children.size()) { |
921 LOG(ERROR) << "Can't remove a directory with children."; | 914 LOG(ERROR) << "Can't remove a directory with children."; |
922 return false; | 915 return false; |
923 } | 916 } |
924 } | 917 } |
925 batch->Delete(GetChildLookupKey(info.parent_id, info.name)); | 918 batch->Delete(GetChildLookupKey(info.parent_id, info.name)); |
926 batch->Delete(GetFileLookupKey(file_id)); | 919 batch->Delete(GetFileLookupKey(file_id)); |
927 return true; | 920 return true; |
928 } | 921 } |
929 | 922 |
930 void SandboxDirectoryDatabase::HandleError( | 923 void SandboxDirectoryDatabase::HandleError( |
931 const tracked_objects::Location& from_here, | 924 const tracked_objects::Location& from_here, |
932 const leveldb::Status& status) { | 925 const leveldb::Status& status) { |
933 LOG(ERROR) << "SandboxDirectoryDatabase failed at: " | 926 LOG(ERROR) << "SandboxDirectoryDatabase failed at: " << from_here.ToString() |
934 << from_here.ToString() << " with error: " << status.ToString(); | 927 << " with error: " << status.ToString(); |
935 db_.reset(); | 928 db_.reset(); |
936 } | 929 } |
937 | 930 |
938 } // namespace fileapi | 931 } // namespace storage |
OLD | NEW |