| 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 52113d695ba4d74d0c4793872fc833600f0b8615..dc6b70e80461d2299a24a73e14a8aae02f51cbcc 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,52 @@ 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 growth_in_number_of_paths,
|
| + int64 growth_in_bytes_of_path_length) {
|
| + return growth_in_number_of_paths * kPathCreationQuotaCost +
|
| + growth_in_bytes_of_path_length * kPathByteQuotaCost;
|
| +}
|
| +
|
| +bool AllocateQuotaForPath(
|
| + fileapi::FileSystemOperationContext* context,
|
| + int growth_in_number_of_paths,
|
| + int64 growth_in_bytes_of_path_length) {
|
| + int64 growth = GetPathQuotaUsage(growth_in_number_of_paths,
|
| + growth_in_bytes_of_path_length);
|
| + int64 new_quota = context->allowed_bytes_growth() - growth;
|
| +
|
| + if (growth <= 0 || new_quota >= 0) {
|
| + context->set_allowed_bytes_growth(new_quota);
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +void UpdatePathQuotaUsage(
|
| + fileapi::FileSystemOperationContext* context,
|
| + const GURL& origin_url,
|
| + fileapi::FileSystemType type,
|
| + int growth_in_number_of_paths, // -1, 0, or 1
|
| + int64 growth_in_bytes_of_path_length) {
|
| + int64 growth = GetPathQuotaUsage(growth_in_number_of_paths,
|
| + growth_in_bytes_of_path_length);
|
| + fileapi::FileSystemQuotaUtil* quota_util =
|
| + context->file_system_context()->GetQuotaUtil(type);
|
| + quota::QuotaManagerProxy* quota_manager_proxy =
|
| + context->file_system_context()->quota_manager_proxy();
|
| + 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 +136,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 +188,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 +317,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 +324,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 +341,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 +398,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 +415,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 +425,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 +474,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 +501,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 +529,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 +570,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 +848,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 +897,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 +1137,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 =
|
|
|