Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "storage/browser/fileapi/obfuscated_file_util.h" | 5 #include "storage/browser/fileapi/obfuscated_file_util.h" |
| 6 | 6 |
| 7 #include <queue> | 7 #include <queue> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
| 12 #include "base/format_macros.h" | 12 #include "base/format_macros.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/message_loop/message_loop.h" | 14 #include "base/message_loop/message_loop.h" |
| 15 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
| 16 #include "base/stl_util.h" | 16 #include "base/stl_util.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/stringprintf.h" | 19 #include "base/strings/stringprintf.h" |
| 19 #include "base/strings/sys_string_conversions.h" | 20 #include "base/strings/sys_string_conversions.h" |
| 20 #include "base/strings/utf_string_conversions.h" | 21 #include "base/strings/utf_string_conversions.h" |
| 21 #include "base/time/time.h" | 22 #include "base/time/time.h" |
| 22 #include "storage/browser/fileapi/file_observers.h" | 23 #include "storage/browser/fileapi/file_observers.h" |
| 23 #include "storage/browser/fileapi/file_system_context.h" | 24 #include "storage/browser/fileapi/file_system_context.h" |
| 24 #include "storage/browser/fileapi/file_system_operation_context.h" | 25 #include "storage/browser/fileapi/file_system_operation_context.h" |
| 25 #include "storage/browser/fileapi/file_system_url.h" | 26 #include "storage/browser/fileapi/file_system_url.h" |
| 26 #include "storage/browser/fileapi/native_file_util.h" | 27 #include "storage/browser/fileapi/native_file_util.h" |
| 27 #include "storage/browser/fileapi/sandbox_file_system_backend.h" | 28 #include "storage/browser/fileapi/sandbox_file_system_backend.h" |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 60 } | 61 } |
| 61 | 62 |
| 62 // Costs computed as per crbug.com/86114, based on the LevelDB implementation of | 63 // Costs computed as per crbug.com/86114, based on the LevelDB implementation of |
| 63 // path storage under Linux. It's not clear if that will differ on Windows, on | 64 // path storage under Linux. It's not clear if that will differ on Windows, on |
| 64 // which base::FilePath uses wide chars [since they're converted to UTF-8 for | 65 // which base::FilePath uses wide chars [since they're converted to UTF-8 for |
| 65 // storage anyway], but as long as the cost is high enough that one can't cheat | 66 // storage anyway], but as long as the cost is high enough that one can't cheat |
| 66 // on quota by storing data in paths, it doesn't need to be all that accurate. | 67 // on quota by storing data in paths, it doesn't need to be all that accurate. |
| 67 const int64 kPathCreationQuotaCost = 146; // Bytes per inode, basically. | 68 const int64 kPathCreationQuotaCost = 146; // Bytes per inode, basically. |
| 68 const int64 kPathByteQuotaCost = 2; // Bytes per byte of path length in UTF-8. | 69 const int64 kPathByteQuotaCost = 2; // Bytes per byte of path length in UTF-8. |
| 69 | 70 |
| 71 const char kDirectoryDatabaseKeySeparator = ' '; | |
| 72 | |
| 70 int64 UsageForPath(size_t length) { | 73 int64 UsageForPath(size_t length) { |
| 71 return kPathCreationQuotaCost + | 74 return kPathCreationQuotaCost + |
| 72 static_cast<int64>(length) * kPathByteQuotaCost; | 75 static_cast<int64>(length) * kPathByteQuotaCost; |
| 73 } | 76 } |
| 74 | 77 |
| 75 bool AllocateQuota(FileSystemOperationContext* context, int64 growth) { | 78 bool AllocateQuota(FileSystemOperationContext* context, int64 growth) { |
| 76 if (context->allowed_bytes_growth() == storage::QuotaManager::kNoLimit) | 79 if (context->allowed_bytes_growth() == storage::QuotaManager::kNoLimit) |
| 77 return true; | 80 return true; |
| 78 | 81 |
| 79 int64 new_quota = context->allowed_bytes_growth() - growth; | 82 int64 new_quota = context->allowed_bytes_growth() - growth; |
| (...skipping 770 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 850 } | 853 } |
| 851 | 854 |
| 852 if (error_code) | 855 if (error_code) |
| 853 *error_code = error; | 856 *error_code = error; |
| 854 return path; | 857 return path; |
| 855 } | 858 } |
| 856 | 859 |
| 857 bool ObfuscatedFileUtil::DeleteDirectoryForOriginAndType( | 860 bool ObfuscatedFileUtil::DeleteDirectoryForOriginAndType( |
| 858 const GURL& origin, | 861 const GURL& origin, |
| 859 const std::string& type_string) { | 862 const std::string& type_string) { |
| 860 base::File::Error error = base::File::FILE_OK; | 863 if (!DestroyDirectoryDatabase(origin, type_string)) |
| 861 base::FilePath origin_type_path = GetDirectoryForOriginAndType( | 864 return false; |
| 862 origin, type_string, false, &error); | 865 |
| 863 if (origin_type_path.empty()) | 866 const base::FilePath origin_path = GetDirectoryForOrigin(origin, false, NULL); |
| 864 return true; | 867 if (!type_string.empty()) { |
| 865 if (error != base::File::FILE_ERROR_NOT_FOUND) { | 868 // Delete the filesystem type directory. |
| 866 // TODO(dmikurube): Consider the return value of DestroyDirectoryDatabase. | 869 base::File::Error error = base::File::FILE_OK; |
| 867 // We ignore its error now since 1) it doesn't matter the final result, and | 870 const base::FilePath origin_type_path = |
| 868 // 2) it always returns false in Windows because of LevelDB's | 871 GetDirectoryForOriginAndType(origin, type_string, false, &error); |
| 869 // implementation. | 872 if (error == base::File::FILE_ERROR_FAILED) |
| 870 // Information about failure would be useful for debugging. | |
| 871 if (!type_string.empty()) | |
| 872 DestroyDirectoryDatabase(origin, type_string); | |
| 873 if (!base::DeleteFile(origin_type_path, true /* recursive */)) | |
| 874 return false; | 873 return false; |
| 875 } | 874 if (error == base::File::FILE_OK && |
| 875 !origin_type_path.empty() && | |
| 876 !base::DeleteFile(origin_type_path, true /* recursive */)) { | |
| 877 return false; | |
| 878 } | |
| 876 | 879 |
| 877 base::FilePath origin_path = VirtualPath::DirName(origin_type_path); | 880 DCHECK_EQ(origin_path.value(), |
| 878 DCHECK_EQ(origin_path.value(), | 881 GetDirectoryForOrigin(origin, false, NULL).value()); |
|
kinuko
2014/09/25 16:33:00
nit: This is checking the return val of GetDirecto
nhiroki
2014/11/07 08:15:42
Done.
| |
| 879 GetDirectoryForOrigin(origin, false, NULL).value()); | |
| 880 | 882 |
| 881 if (!type_string.empty()) { | |
| 882 // At this point we are sure we had successfully deleted the origin/type | 883 // At this point we are sure we had successfully deleted the origin/type |
| 883 // directory (i.e. we're ready to just return true). | 884 // directory (i.e. we're ready to just return true). |
| 884 // See if we have other directories in this origin directory. | 885 // See if we have other directories in this origin directory. |
| 885 for (std::set<std::string>::iterator iter = known_type_strings_.begin(); | 886 for (std::set<std::string>::iterator iter = known_type_strings_.begin(); |
| 886 iter != known_type_strings_.end(); | 887 iter != known_type_strings_.end(); |
| 887 ++iter) { | 888 ++iter) { |
| 888 if (*iter == type_string) | 889 if (*iter == type_string) |
| 889 continue; | 890 continue; |
| 890 if (base::DirectoryExists(origin_path.AppendASCII(*iter))) { | 891 if (base::DirectoryExists(origin_path.AppendASCII(*iter))) { |
| 891 // Other type's directory exists; just return true here. | 892 // Other type's directory exists; just return true here. |
| 892 return true; | 893 return true; |
| 893 } | 894 } |
| 894 } | 895 } |
| 895 } | 896 } |
| 896 | 897 |
| 897 // No other directories seem exist. Try deleting the entire origin directory. | 898 // No other directories seem exist. Try deleting the entire origin directory. |
| 898 InitOriginDatabase(origin, false); | 899 InitOriginDatabase(origin, false); |
| 899 if (origin_database_) { | 900 if (origin_database_) { |
| 900 origin_database_->RemovePathForOrigin( | 901 origin_database_->RemovePathForOrigin( |
| 901 storage::GetIdentifierFromOrigin(origin)); | 902 storage::GetIdentifierFromOrigin(origin)); |
| 902 } | 903 } |
| 903 if (!base::DeleteFile(origin_path, true /* recursive */)) | 904 return base::DeleteFile(origin_path, true /* recursive */); |
| 904 return false; | |
| 905 | |
| 906 return true; | |
| 907 } | 905 } |
| 908 | 906 |
| 909 ObfuscatedFileUtil::AbstractOriginEnumerator* | 907 ObfuscatedFileUtil::AbstractOriginEnumerator* |
| 910 ObfuscatedFileUtil::CreateOriginEnumerator() { | 908 ObfuscatedFileUtil::CreateOriginEnumerator() { |
| 911 std::vector<SandboxOriginDatabase::OriginRecord> origins; | 909 std::vector<SandboxOriginDatabase::OriginRecord> origins; |
| 912 | 910 |
| 913 InitOriginDatabase(GURL(), false); | 911 InitOriginDatabase(GURL(), false); |
| 914 return new ObfuscatedOriginEnumerator( | 912 return new ObfuscatedOriginEnumerator( |
| 915 origin_database_.get(), file_system_directory_); | 913 origin_database_.get(), file_system_directory_); |
| 916 } | 914 } |
| 917 | 915 |
| 918 bool ObfuscatedFileUtil::DestroyDirectoryDatabase( | 916 bool ObfuscatedFileUtil::DestroyDirectoryDatabase( |
| 919 const GURL& origin, | 917 const GURL& origin, |
| 920 const std::string& type_string) { | 918 const std::string& type_string) { |
| 921 std::string key = GetDirectoryDatabaseKey(origin, type_string); | 919 // If |type_string| is empty, delete all filesystem types under |origin|. |
|
kinuko
2014/09/25 16:33:00
Probably we could add a test to make sure this doe
nhiroki
2014/11/07 08:15:42
Added.
| |
| 922 if (key.empty()) | 920 const std::string key_prefix = GetDirectoryDatabaseKey(origin, type_string); |
| 923 return true; | 921 for (DirectoryMap::iterator iter = directories_.lower_bound(key_prefix); |
| 924 DirectoryMap::iterator iter = directories_.find(key); | 922 iter != directories_.end();) { |
| 925 if (iter == directories_.end()) | 923 if (!StartsWithASCII(iter->first, key_prefix, true)) |
| 926 return true; | 924 break; |
| 927 scoped_ptr<SandboxDirectoryDatabase> database(iter->second); | 925 DCHECK(type_string.empty() || iter->first == key_prefix); |
| 928 directories_.erase(iter); | 926 scoped_ptr<SandboxDirectoryDatabase> database(iter->second); |
| 929 return database->DestroyDatabase(); | 927 directories_.erase(iter++); |
| 928 if (!database->DestroyDatabase()) | |
| 929 return false; | |
|
kinuko
2014/09/25 16:33:00
It's a bit hard to say what we should do when we c
nhiroki
2014/11/07 08:15:42
I see... I made DestroyDatabase() ignore the failu
| |
| 930 } | |
| 931 return true; | |
| 930 } | 932 } |
| 931 | 933 |
| 932 // static | 934 // static |
| 933 int64 ObfuscatedFileUtil::ComputeFilePathCost(const base::FilePath& path) { | 935 int64 ObfuscatedFileUtil::ComputeFilePathCost(const base::FilePath& path) { |
| 934 return UsageForPath(VirtualPath::BaseName(path).value().size()); | 936 return UsageForPath(VirtualPath::BaseName(path).value().size()); |
| 935 } | 937 } |
| 936 | 938 |
| 937 void ObfuscatedFileUtil::MaybePrepopulateDatabase( | 939 void ObfuscatedFileUtil::MaybePrepopulateDatabase( |
| 938 const std::vector<std::string>& type_strings_to_prepopulate) { | 940 const std::vector<std::string>& type_strings_to_prepopulate) { |
| 939 SandboxPrioritizedOriginDatabase database(file_system_directory_, | 941 SandboxPrioritizedOriginDatabase database(file_system_directory_, |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1131 const FileSystemURL& url, const base::FilePath& data_path) { | 1133 const FileSystemURL& url, const base::FilePath& data_path) { |
| 1132 base::File::Error error = base::File::FILE_OK; | 1134 base::File::Error error = base::File::FILE_OK; |
| 1133 base::FilePath root = GetDirectoryForURL(url, false, &error); | 1135 base::FilePath root = GetDirectoryForURL(url, false, &error); |
| 1134 if (error != base::File::FILE_OK) | 1136 if (error != base::File::FILE_OK) |
| 1135 return base::FilePath(); | 1137 return base::FilePath(); |
| 1136 return root.Append(data_path); | 1138 return root.Append(data_path); |
| 1137 } | 1139 } |
| 1138 | 1140 |
| 1139 std::string ObfuscatedFileUtil::GetDirectoryDatabaseKey( | 1141 std::string ObfuscatedFileUtil::GetDirectoryDatabaseKey( |
| 1140 const GURL& origin, const std::string& type_string) { | 1142 const GURL& origin, const std::string& type_string) { |
| 1141 if (type_string.empty()) { | |
| 1142 LOG(WARNING) << "Unknown filesystem type requested:" << type_string; | |
| 1143 return std::string(); | |
| 1144 } | |
| 1145 // For isolated origin we just use a type string as a key. | 1143 // For isolated origin we just use a type string as a key. |
| 1146 return storage::GetIdentifierFromOrigin(origin) + type_string; | 1144 return storage::GetIdentifierFromOrigin(origin) + |
| 1145 kDirectoryDatabaseKeySeparator + type_string; | |
| 1147 } | 1146 } |
| 1148 | 1147 |
| 1149 // TODO(ericu): How to do the whole validation-without-creation thing? | 1148 // TODO(ericu): How to do the whole validation-without-creation thing? |
| 1150 // We may not have quota even to create the database. | 1149 // We may not have quota even to create the database. |
| 1151 // Ah, in that case don't even get here? | 1150 // Ah, in that case don't even get here? |
| 1152 // Still doesn't answer the quota issue, though. | 1151 // Still doesn't answer the quota issue, though. |
| 1153 SandboxDirectoryDatabase* ObfuscatedFileUtil::GetDirectoryDatabase( | 1152 SandboxDirectoryDatabase* ObfuscatedFileUtil::GetDirectoryDatabase( |
| 1154 const FileSystemURL& url, bool create) { | 1153 const FileSystemURL& url, bool create) { |
| 1155 std::string key = GetDirectoryDatabaseKey( | 1154 std::string key = GetDirectoryDatabaseKey( |
| 1156 url.origin(), CallGetTypeStringForURL(url)); | 1155 url.origin(), CallGetTypeStringForURL(url)); |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1408 } | 1407 } |
| 1409 return file.Pass(); | 1408 return file.Pass(); |
| 1410 } | 1409 } |
| 1411 | 1410 |
| 1412 bool ObfuscatedFileUtil::HasIsolatedStorage(const GURL& origin) { | 1411 bool ObfuscatedFileUtil::HasIsolatedStorage(const GURL& origin) { |
| 1413 return special_storage_policy_.get() && | 1412 return special_storage_policy_.get() && |
| 1414 special_storage_policy_->HasIsolatedStorage(origin); | 1413 special_storage_policy_->HasIsolatedStorage(origin); |
| 1415 } | 1414 } |
| 1416 | 1415 |
| 1417 } // namespace storage | 1416 } // namespace storage |
| OLD | NEW |