| 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 "storage/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/files/file_enumerator.h" | 12 #include "base/files/file_enumerator.h" |
| 13 #include "base/files/file_util.h" | 13 #include "base/files/file_util.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 "storage/browser/fileapi/file_system_usage_cache.h" | 19 #include "storage/browser/fileapi/file_system_usage_cache.h" |
| 20 #include "storage/common/fileapi/file_system_util.h" | 20 #include "storage/common/fileapi/file_system_util.h" |
| 21 #include "third_party/leveldatabase/env_chromium.h" | 21 #include "third_party/leveldatabase/env_chromium.h" |
| 22 #include "third_party/leveldatabase/src/include/leveldb/db.h" | 22 #include "third_party/leveldatabase/src/include/leveldb/db.h" |
| 23 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" | 23 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" |
| 24 | 24 |
| 25 namespace { | 25 namespace { |
| 26 | 26 |
| 27 bool PickleFromFileInfo(const storage::SandboxDirectoryDatabase::FileInfo& info, | 27 bool PickleFromFileInfo(const storage::SandboxDirectoryDatabase::FileInfo& info, |
| 28 Pickle* pickle) { | 28 base::Pickle* pickle) { |
| 29 DCHECK(pickle); | 29 DCHECK(pickle); |
| 30 std::string data_path; | 30 std::string data_path; |
| 31 // Round off here to match the behavior of the filesystem on real files. | 31 // Round off here to match the behavior of the filesystem on real files. |
| 32 base::Time time = | 32 base::Time time = |
| 33 base::Time::FromDoubleT(floor(info.modification_time.ToDoubleT())); | 33 base::Time::FromDoubleT(floor(info.modification_time.ToDoubleT())); |
| 34 std::string name; | 34 std::string name; |
| 35 | 35 |
| 36 data_path = storage::FilePathToString(info.data_path); | 36 data_path = storage::FilePathToString(info.data_path); |
| 37 name = storage::FilePathToString(base::FilePath(info.name)); | 37 name = storage::FilePathToString(base::FilePath(info.name)); |
| 38 | 38 |
| 39 if (pickle->WriteInt64(info.parent_id) && | 39 if (pickle->WriteInt64(info.parent_id) && |
| 40 pickle->WriteString(data_path) && | 40 pickle->WriteString(data_path) && |
| 41 pickle->WriteString(name) && | 41 pickle->WriteString(name) && |
| 42 pickle->WriteInt64(time.ToInternalValue())) | 42 pickle->WriteInt64(time.ToInternalValue())) |
| 43 return true; | 43 return true; |
| 44 | 44 |
| 45 NOTREACHED(); | 45 NOTREACHED(); |
| 46 return false; | 46 return false; |
| 47 } | 47 } |
| 48 | 48 |
| 49 bool FileInfoFromPickle(const Pickle& pickle, | 49 bool FileInfoFromPickle(const base::Pickle& pickle, |
| 50 storage::SandboxDirectoryDatabase::FileInfo* info) { | 50 storage::SandboxDirectoryDatabase::FileInfo* info) { |
| 51 PickleIterator iter(pickle); | 51 base::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 (iter.ReadInt64(&info->parent_id) && | 56 if (iter.ReadInt64(&info->parent_id) && |
| 57 iter.ReadString(&data_path) && | 57 iter.ReadString(&data_path) && |
| 58 iter.ReadString(&name) && | 58 iter.ReadString(&name) && |
| 59 iter.ReadInt64(&internal_time)) { | 59 iter.ReadInt64(&internal_time)) { |
| 60 info->data_path = storage::StringToFilePath(data_path); | 60 info->data_path = storage::StringToFilePath(data_path); |
| 61 info->name = storage::StringToFilePath(name).value(); | 61 info->name = storage::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) << "base::Pickle could not be digested!"; |
| 66 return false; | 66 return false; |
| 67 } | 67 } |
| 68 | 68 |
| 69 const base::FilePath::CharType kDirectoryDatabaseName[] = | 69 const base::FilePath::CharType kDirectoryDatabaseName[] = |
| 70 FILE_PATH_LITERAL("Paths"); | 70 FILE_PATH_LITERAL("Paths"); |
| 71 const char kChildLookupPrefix[] = "CHILD_OF:"; | 71 const char kChildLookupPrefix[] = "CHILD_OF:"; |
| 72 const char kChildLookupSeparator[] = ":"; | 72 const char kChildLookupSeparator[] = ":"; |
| 73 const char kLastFileIdKey[] = "LAST_FILE_ID"; | 73 const char kLastFileIdKey[] = "LAST_FILE_ID"; |
| 74 const char kLastIntegerKey[] = "LAST_INTEGER"; | 74 const char kLastIntegerKey[] = "LAST_INTEGER"; |
| 75 const int64 kMinimumReportIntervalHours = 1; | 75 const int64 kMinimumReportIntervalHours = 1; |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 // key: "LAST_INTEGER" | 217 // key: "LAST_INTEGER" |
| 218 // value: "<last_integer>" | 218 // value: "<last_integer>" |
| 219 if (last_integer_ >= 0 || | 219 if (last_integer_ >= 0 || |
| 220 !base::StringToInt64(itr->value().ToString(), &last_integer_)) | 220 !base::StringToInt64(itr->value().ToString(), &last_integer_)) |
| 221 return false; | 221 return false; |
| 222 } else { | 222 } else { |
| 223 // key: "<entry_id>" | 223 // key: "<entry_id>" |
| 224 // value: "<pickled FileInfo>" | 224 // value: "<pickled FileInfo>" |
| 225 FileInfo file_info; | 225 FileInfo file_info; |
| 226 if (!FileInfoFromPickle( | 226 if (!FileInfoFromPickle( |
| 227 Pickle(itr->value().data(), itr->value().size()), &file_info)) | 227 base::Pickle(itr->value().data(), itr->value().size()), |
| 228 &file_info)) |
| 228 return false; | 229 return false; |
| 229 | 230 |
| 230 FileId file_id = -1; | 231 FileId file_id = -1; |
| 231 if (!base::StringToInt64(key, &file_id) || file_id < 0) | 232 if (!base::StringToInt64(key, &file_id) || file_id < 0) |
| 232 return false; | 233 return false; |
| 233 | 234 |
| 234 if (max_file_id < file_id) | 235 if (max_file_id < file_id) |
| 235 max_file_id = file_id; | 236 max_file_id = file_id; |
| 236 if (!file_ids.insert(file_id).second) | 237 if (!file_ids.insert(file_id).second) |
| 237 return false; | 238 return false; |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 bool SandboxDirectoryDatabase::GetFileInfo(FileId file_id, FileInfo* info) { | 492 bool SandboxDirectoryDatabase::GetFileInfo(FileId file_id, FileInfo* info) { |
| 492 if (!Init(REPAIR_ON_CORRUPTION)) | 493 if (!Init(REPAIR_ON_CORRUPTION)) |
| 493 return false; | 494 return false; |
| 494 DCHECK(info); | 495 DCHECK(info); |
| 495 std::string file_key = GetFileLookupKey(file_id); | 496 std::string file_key = GetFileLookupKey(file_id); |
| 496 std::string file_data_string; | 497 std::string file_data_string; |
| 497 leveldb::Status status = | 498 leveldb::Status status = |
| 498 db_->Get(leveldb::ReadOptions(), file_key, &file_data_string); | 499 db_->Get(leveldb::ReadOptions(), file_key, &file_data_string); |
| 499 if (status.ok()) { | 500 if (status.ok()) { |
| 500 bool success = FileInfoFromPickle( | 501 bool success = FileInfoFromPickle( |
| 501 Pickle(file_data_string.data(), file_data_string.length()), info); | 502 base::Pickle(file_data_string.data(), file_data_string.length()), info); |
| 502 if (!success) | 503 if (!success) |
| 503 return false; | 504 return false; |
| 504 if (!VerifyDataPath(info->data_path)) { | 505 if (!VerifyDataPath(info->data_path)) { |
| 505 LOG(ERROR) << "Resolved data path is invalid: " | 506 LOG(ERROR) << "Resolved data path is invalid: " |
| 506 << info->data_path.value(); | 507 << info->data_path.value(); |
| 507 return false; | 508 return false; |
| 508 } | 509 } |
| 509 return true; | 510 return true; |
| 510 } | 511 } |
| 511 // Special-case the root, for databases that haven't been initialized yet. | 512 // Special-case the root, for databases that haven't been initialized yet. |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 614 } | 615 } |
| 615 return true; | 616 return true; |
| 616 } | 617 } |
| 617 | 618 |
| 618 bool SandboxDirectoryDatabase::UpdateModificationTime( | 619 bool SandboxDirectoryDatabase::UpdateModificationTime( |
| 619 FileId file_id, const base::Time& modification_time) { | 620 FileId file_id, const base::Time& modification_time) { |
| 620 FileInfo info; | 621 FileInfo info; |
| 621 if (!GetFileInfo(file_id, &info)) | 622 if (!GetFileInfo(file_id, &info)) |
| 622 return false; | 623 return false; |
| 623 info.modification_time = modification_time; | 624 info.modification_time = modification_time; |
| 624 Pickle pickle; | 625 base::Pickle pickle; |
| 625 if (!PickleFromFileInfo(info, &pickle)) | 626 if (!PickleFromFileInfo(info, &pickle)) |
| 626 return false; | 627 return false; |
| 627 leveldb::Status status = db_->Put( | 628 leveldb::Status status = db_->Put( |
| 628 leveldb::WriteOptions(), | 629 leveldb::WriteOptions(), |
| 629 GetFileLookupKey(file_id), | 630 GetFileLookupKey(file_id), |
| 630 leveldb::Slice(reinterpret_cast<const char *>(pickle.data()), | 631 leveldb::Slice(reinterpret_cast<const char *>(pickle.data()), |
| 631 pickle.size())); | 632 pickle.size())); |
| 632 if (!status.ok()) { | 633 if (!status.ok()) { |
| 633 HandleError(FROM_HERE, status); | 634 HandleError(FROM_HERE, status); |
| 634 return false; | 635 return false; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 646 if (!GetFileInfo(dest_file_id, &dest_file_info)) | 647 if (!GetFileInfo(dest_file_id, &dest_file_info)) |
| 647 return false; | 648 return false; |
| 648 if (src_file_info.is_directory() || dest_file_info.is_directory()) | 649 if (src_file_info.is_directory() || dest_file_info.is_directory()) |
| 649 return false; | 650 return false; |
| 650 leveldb::WriteBatch batch; | 651 leveldb::WriteBatch batch; |
| 651 // This is the only field that really gets moved over; if you add fields to | 652 // This is the only field that really gets moved over; if you add fields to |
| 652 // FileInfo, e.g. ctime, they might need to be copied here. | 653 // FileInfo, e.g. ctime, they might need to be copied here. |
| 653 dest_file_info.data_path = src_file_info.data_path; | 654 dest_file_info.data_path = src_file_info.data_path; |
| 654 if (!RemoveFileInfoHelper(src_file_id, &batch)) | 655 if (!RemoveFileInfoHelper(src_file_id, &batch)) |
| 655 return false; | 656 return false; |
| 656 Pickle pickle; | 657 base::Pickle pickle; |
| 657 if (!PickleFromFileInfo(dest_file_info, &pickle)) | 658 if (!PickleFromFileInfo(dest_file_info, &pickle)) |
| 658 return false; | 659 return false; |
| 659 batch.Put( | 660 batch.Put( |
| 660 GetFileLookupKey(dest_file_id), | 661 GetFileLookupKey(dest_file_id), |
| 661 leveldb::Slice(reinterpret_cast<const char *>(pickle.data()), | 662 leveldb::Slice(reinterpret_cast<const char *>(pickle.data()), |
| 662 pickle.size())); | 663 pickle.size())); |
| 663 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); | 664 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); |
| 664 if (!status.ok()) { | 665 if (!status.ok()) { |
| 665 HandleError(FROM_HERE, status); | 666 HandleError(FROM_HERE, status); |
| 666 return false; | 667 return false; |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 892 } | 893 } |
| 893 std::string id_string = GetFileLookupKey(file_id); | 894 std::string id_string = GetFileLookupKey(file_id); |
| 894 if (!file_id) { | 895 if (!file_id) { |
| 895 // The root directory doesn't need to be looked up by path from its parent. | 896 // The root directory doesn't need to be looked up by path from its parent. |
| 896 DCHECK(!info.parent_id); | 897 DCHECK(!info.parent_id); |
| 897 DCHECK(info.data_path.empty()); | 898 DCHECK(info.data_path.empty()); |
| 898 } else { | 899 } else { |
| 899 std::string child_key = GetChildLookupKey(info.parent_id, info.name); | 900 std::string child_key = GetChildLookupKey(info.parent_id, info.name); |
| 900 batch->Put(child_key, id_string); | 901 batch->Put(child_key, id_string); |
| 901 } | 902 } |
| 902 Pickle pickle; | 903 base::Pickle pickle; |
| 903 if (!PickleFromFileInfo(info, &pickle)) | 904 if (!PickleFromFileInfo(info, &pickle)) |
| 904 return false; | 905 return false; |
| 905 batch->Put( | 906 batch->Put( |
| 906 id_string, | 907 id_string, |
| 907 leveldb::Slice(reinterpret_cast<const char *>(pickle.data()), | 908 leveldb::Slice(reinterpret_cast<const char *>(pickle.data()), |
| 908 pickle.size())); | 909 pickle.size())); |
| 909 return true; | 910 return true; |
| 910 } | 911 } |
| 911 | 912 |
| 912 // This does very few safety checks! | 913 // This does very few safety checks! |
| (...skipping 20 matching lines...) Expand all Loading... |
| 933 | 934 |
| 934 void SandboxDirectoryDatabase::HandleError( | 935 void SandboxDirectoryDatabase::HandleError( |
| 935 const tracked_objects::Location& from_here, | 936 const tracked_objects::Location& from_here, |
| 936 const leveldb::Status& status) { | 937 const leveldb::Status& status) { |
| 937 LOG(ERROR) << "SandboxDirectoryDatabase failed at: " | 938 LOG(ERROR) << "SandboxDirectoryDatabase failed at: " |
| 938 << from_here.ToString() << " with error: " << status.ToString(); | 939 << from_here.ToString() << " with error: " << status.ToString(); |
| 939 db_.reset(); | 940 db_.reset(); |
| 940 } | 941 } |
| 941 | 942 |
| 942 } // namespace storage | 943 } // namespace storage |
| OLD | NEW |