Chromium Code Reviews| Index: webkit/fileapi/obfuscated_file_system_file_util.cc |
| diff --git a/webkit/fileapi/obfuscated_file_system_file_util.cc b/webkit/fileapi/obfuscated_file_system_file_util.cc |
| index abff6cb5845cc1796b351e12cf90c7df23f2c4b8..65bb00b79b1709edd1cb8c694962727466e01267 100644 |
| --- a/webkit/fileapi/obfuscated_file_system_file_util.cc |
| +++ b/webkit/fileapi/obfuscated_file_system_file_util.cc |
| @@ -19,8 +19,10 @@ |
| #include "webkit/fileapi/file_system_context.h" |
| #include "webkit/fileapi/file_system_operation_context.h" |
| #include "webkit/fileapi/file_system_path_manager.h" |
| +#include "webkit/fileapi/file_system_quota_util.h" |
| #include "webkit/fileapi/file_system_util.h" |
| #include "webkit/fileapi/sandbox_mount_point_provider.h" |
| +#include "webkit/quota/quota_manager.h" |
| namespace { |
| @@ -43,6 +45,49 @@ bool IsRootDirectory(const FilePath& virtual_path) { |
| virtual_path.value() == FILE_PATH_LITERAL("/")); |
| } |
| +// Costs computed as per crbug.com/86114, based on the LevelDB implementation of |
| +// path storage under Linux. It's not clear if that will differ on Windows, on |
| +// which FilePath uses wide chars [since they're converted to UTF-8 for storage |
| +// anyway], but as long as the cost is high enough that one can't cheat on quota |
| +// by storing data in paths, it doesn't need to be all that accurate. |
| +const int64 kPathCreationQuotaCost = 146; // Bytes per inode, basically. |
| +const int64 kPathByteQuotaCost = 2; // Bytes per byte of path length in UTF-8. |
| + |
| +int64 GetPathQuotaUsage( |
| + int growthInNumberOfPaths, |
|
kinuko
2011/08/15 03:42:34
growth_in_number_of_paths?
You seem to be followi
ericu
2011/08/15 23:47:10
Oops! Thanks--I often do that. It doesn't help t
|
| + int64 growthInBytesOfPathLength) { |
| + return growthInNumberOfPaths * kPathCreationQuotaCost + |
| + growthInBytesOfPathLength * kPathByteQuotaCost; |
| +} |
| + |
| +bool AllocateQuotaForPath( |
| + fileapi::FileSystemOperationContext* context, |
| + int growthInNumberOfPaths, |
| + int64 growthInBytesOfPathLength) { |
| + int64 growth = GetPathQuotaUsage(growthInNumberOfPaths, |
| + growthInBytesOfPathLength); |
| + int64 new_quota = context->allowed_bytes_growth() - growth; |
| + context->set_allowed_bytes_growth(new_quota); |
| + |
| + return new_quota >= 0; |
| +} |
| + |
| +void UpdatePathQuotaUsage( |
| + fileapi::FileSystemOperationContext* context, |
| + const GURL& origin_url, |
| + fileapi::FileSystemType type, |
| + int growthInNumberOfPaths, // -1, 0, or 1 |
| + int64 growthInBytesOfPathLength) { |
| + int64 growth = GetPathQuotaUsage(growthInNumberOfPaths, |
| + growthInBytesOfPathLength); |
| + fileapi::FileSystemQuotaUtil* quota_util = |
| + context->file_system_context()->GetQuotaUtil(type); |
| + quota::QuotaManagerProxy* quota_manager_proxy = |
| + context->file_system_context()->quota_manager_proxy(); |
|
kinuko
2011/08/15 03:42:34
nit: weird indent
ericu
2011/08/15 23:47:10
Done.
|
| + quota_util->UpdateOriginUsageOnFileThread(quota_manager_proxy, origin_url, |
| + type, growth); |
| +} |
| + |
| const FilePath::CharType kLegacyDataDirectory[] = FILE_PATH_LITERAL("Legacy"); |
| const FilePath::CharType kTemporaryDirectoryName[] = FILE_PATH_LITERAL("t"); |
| @@ -88,6 +133,8 @@ PlatformFileError ObfuscatedFileSystemFileUtil::CreateOrOpen( |
| return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| FileInfo file_info; |
| InitFileInfo(&file_info, parent_id, virtual_path.BaseName().value()); |
| + if (!AllocateQuotaForPath(context, 1, file_info.name.size())) |
| + return base::PLATFORM_FILE_ERROR_NO_SPACE; |
| PlatformFileError error = CreateFile( |
| context, context->src_origin_url(), context->src_type(), FilePath(), |
| &file_info, file_flags, file_handle); |
| @@ -138,6 +185,8 @@ PlatformFileError ObfuscatedFileSystemFileUtil::EnsureFileExists( |
| FileInfo file_info; |
| InitFileInfo(&file_info, parent_id, virtual_path.BaseName().value()); |
| + if (!AllocateQuotaForPath(context, 1, file_info.name.size())) |
| + return base::PLATFORM_FILE_ERROR_NO_SPACE; |
| PlatformFileError error = CreateFile(context, context->src_origin_url(), |
| context->src_type(), FilePath(), &file_info, 0, NULL); |
| if (created && base::PLATFORM_FILE_OK == error) |
| @@ -265,12 +314,6 @@ PlatformFileError ObfuscatedFileSystemFileUtil::CreateDirectory( |
| } |
| if (!recursive && components.size() - index > 1) |
| return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| - // TODO(dmikurube): Eliminate do_not_write_actually in future. |
| - bool do_not_write_actually = context->do_not_write_actually(); |
| - context->set_do_not_write_actually(true); |
| - underlying_file_util_->CreateDirectory(context, |
| - FilePath(), exclusive, recursive); |
| - context->set_do_not_write_actually(do_not_write_actually); |
| for (; index < components.size(); ++index) { |
| FileInfo file_info; |
| file_info.name = components[index]; |
| @@ -278,10 +321,14 @@ PlatformFileError ObfuscatedFileSystemFileUtil::CreateDirectory( |
| continue; |
| file_info.modification_time = base::Time::Now(); |
| file_info.parent_id = parent_id; |
| + if (!AllocateQuotaForPath(context, 1, file_info.name.size())) |
| + return base::PLATFORM_FILE_ERROR_NO_SPACE; |
| if (!db->AddFileInfo(file_info, &parent_id)) { |
| NOTREACHED(); |
| return base::PLATFORM_FILE_ERROR_FAILED; |
| } |
| + UpdatePathQuotaUsage(context, context->src_origin_url(), |
| + context->src_type(), 1, file_info.name.size()); |
| } |
| return base::PLATFORM_FILE_OK; |
| } |
| @@ -291,6 +338,10 @@ PlatformFileError ObfuscatedFileSystemFileUtil::CopyOrMoveFile( |
| const FilePath& src_file_path, |
| const FilePath& dest_file_path, |
| bool copy) { |
| + // Cross-filesystem copies and moves should be handled via CopyInForeignFile. |
| + DCHECK(context->src_origin_url() == context->dest_origin_url()); |
| + DCHECK(context->src_type() == context->dest_type()); |
| + |
| FileSystemDirectoryDatabase* db = GetDirectoryDatabase( |
| context->src_origin_url(), context->src_type(), true); |
| if (!db) |
| @@ -344,12 +395,16 @@ PlatformFileError ObfuscatedFileSystemFileUtil::CopyOrMoveFile( |
| } |
| InitFileInfo(&dest_file_info, dest_parent_id, |
| dest_file_path.BaseName().value()); |
| + if (!AllocateQuotaForPath(context, 1, dest_file_info.name.size())) |
| + return base::PLATFORM_FILE_ERROR_NO_SPACE; |
| return CreateFile(context, context->dest_origin_url(), |
| context->dest_type(), src_data_path, &dest_file_info, 0, |
| NULL); |
| } |
| } else { // It's a move. |
| if (overwrite) { |
| + AllocateQuotaForPath(context, -1, |
| + -static_cast<int64>(src_file_info.name.size())); |
| if (!db->OverwritingMoveFile(src_file_id, dest_file_id)) |
| return base::PLATFORM_FILE_ERROR_FAILED; |
| FilePath dest_data_path = DataPathToLocalPath(context->src_origin_url(), |
| @@ -357,6 +412,9 @@ PlatformFileError ObfuscatedFileSystemFileUtil::CopyOrMoveFile( |
| if (base::PLATFORM_FILE_OK != |
| underlying_file_util_->DeleteFile(context, dest_data_path)) |
| LOG(WARNING) << "Leaked a backing file."; |
| + UpdatePathQuotaUsage(context, context->src_origin_url(), |
| + context->src_type(), -1, |
| + -static_cast<int64>(src_file_info.name.size())); |
| return base::PLATFORM_FILE_OK; |
| } else { |
| FileId dest_parent_id; |
| @@ -364,10 +422,19 @@ PlatformFileError ObfuscatedFileSystemFileUtil::CopyOrMoveFile( |
| NOTREACHED(); |
| return base::PLATFORM_FILE_ERROR_FAILED; |
| } |
| + if (!AllocateQuotaForPath( |
| + context, 0, |
| + static_cast<int64>(dest_file_path.BaseName().value().size()) |
| + - static_cast<int64>(src_file_info.name.size()))) |
| + return base::PLATFORM_FILE_ERROR_NO_SPACE; |
| src_file_info.parent_id = dest_parent_id; |
| src_file_info.name = dest_file_path.BaseName().value(); |
| if (!db->UpdateFileInfo(src_file_id, src_file_info)) |
| return base::PLATFORM_FILE_ERROR_FAILED; |
| + UpdatePathQuotaUsage( |
| + context, context->src_origin_url(), context->src_type(), 0, |
| + static_cast<int64>(dest_file_path.BaseName().value().size()) - |
| + static_cast<int64>(src_file_path.BaseName().value().size())); |
| return base::PLATFORM_FILE_OK; |
| } |
| } |
| @@ -404,6 +471,8 @@ PlatformFileError ObfuscatedFileSystemFileUtil::CopyInForeignFile( |
| } |
| InitFileInfo(&dest_file_info, dest_parent_id, |
| dest_file_path.BaseName().value()); |
| + if (!AllocateQuotaForPath(context, 1, dest_file_info.name.size())) |
| + return base::PLATFORM_FILE_ERROR_NO_SPACE; |
| return CreateFile(context, context->dest_origin_url(), |
| context->dest_type(), src_file_path, &dest_file_info, 0, NULL); |
| } |
| @@ -429,6 +498,9 @@ PlatformFileError ObfuscatedFileSystemFileUtil::DeleteFile( |
| NOTREACHED(); |
| return base::PLATFORM_FILE_ERROR_FAILED; |
| } |
| + AllocateQuotaForPath(context, -1, -static_cast<int64>(file_info.name.size())); |
| + UpdatePathQuotaUsage(context, context->src_origin_url(), context->src_type(), |
| + -1, -static_cast<int64>(file_info.name.size())); |
| FilePath data_path = DataPathToLocalPath(context->src_origin_url(), |
| context->src_type(), file_info.data_path); |
| if (base::PLATFORM_FILE_OK != |
| @@ -454,6 +526,9 @@ PlatformFileError ObfuscatedFileSystemFileUtil::DeleteSingleDirectory( |
| } |
| if (!db->RemoveFileInfo(file_id)) |
| return base::PLATFORM_FILE_ERROR_NOT_EMPTY; |
| + AllocateQuotaForPath(context, -1, -static_cast<int64>(file_info.name.size())); |
| + UpdatePathQuotaUsage(context, context->src_origin_url(), context->src_type(), |
| + -1, -static_cast<int64>(file_info.name.size())); |
| return base::PLATFORM_FILE_OK; |
| } |
| @@ -492,6 +567,8 @@ PlatformFileError ObfuscatedFileSystemFileUtil::Touch( |
| InitFileInfo(&file_info, parent_id, virtual_path.BaseName().value()); |
| // In the event of a sporadic underlying failure, we might create a new file, |
| // but fail to update its mtime + atime. |
| + if (!AllocateQuotaForPath(context, 1, file_info.name.size())) |
| + return base::PLATFORM_FILE_ERROR_NO_SPACE; |
| PlatformFileError error = CreateFile(context, context->src_origin_url(), |
| context->src_type(), FilePath(), &file_info, 0, NULL); |
| if (base::PLATFORM_FILE_OK != error) |
| @@ -768,17 +845,15 @@ PlatformFileError ObfuscatedFileSystemFileUtil::CreateFile( |
| return base::PLATFORM_FILE_ERROR_FAILED; |
| path = path.AppendASCII(StringPrintf("%02" PRIu64, directory_number)); |
| - if (file_util::DirectoryExists(path.DirName())) { |
| - if (!file_util::DirectoryExists(path) && !file_util::CreateDirectory(path)) |
| - return base::PLATFORM_FILE_ERROR_FAILED; |
| - } else { |
| - return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| - } |
| + PlatformFileError error; |
| + error = underlying_file_util_->CreateDirectory( |
| + context, path, false /* exclusive */, false /* recursive */); |
| + if (base::PLATFORM_FILE_OK != error) |
| + return error; |
| path = path.AppendASCII(StringPrintf("%08" PRIu64, number)); |
| FilePath data_path = LocalPathToDataPath(origin_url, type, path); |
| if (data_path.empty()) |
| return base::PLATFORM_FILE_ERROR_FAILED; |
| - PlatformFileError error; |
| bool created = false; |
| if (!source_path.empty()) { |
| DCHECK(!file_flags); |
| @@ -819,6 +894,7 @@ PlatformFileError ObfuscatedFileSystemFileUtil::CreateFile( |
| underlying_file_util_->DeleteFile(context, path); |
| return base::PLATFORM_FILE_ERROR_FAILED; |
| } |
| + UpdatePathQuotaUsage(context, origin_url, type, 1, file_info->name.size()); |
| return base::PLATFORM_FILE_OK; |
| } |
| @@ -1058,6 +1134,11 @@ void ObfuscatedFileSystemFileUtil::DropDatabases() { |
| directories_.clear(); |
| } |
| +// static |
| +int64 ObfuscatedFileSystemFileUtil::ComputeFilePathCost(const FilePath& path) { |
| + return GetPathQuotaUsage(1, path.BaseName().value().size()); |
| +} |
| + |
| bool ObfuscatedFileSystemFileUtil::DestroyDirectoryDatabase( |
| const GURL& origin, FileSystemType type) { |
| std::string type_string = |