|  | // Copyright 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include <stddef.h> | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include <limits> | 
|  | #include <memory> | 
|  | #include <set> | 
|  | #include <string> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/files/file.h" | 
|  | #include "base/files/file_path.h" | 
|  | #include "base/files/file_util.h" | 
|  | #include "base/files/scoped_temp_dir.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/message_loop/message_loop.h" | 
|  | #include "base/run_loop.h" | 
|  | #include "base/test/scoped_task_environment.h" | 
|  | #include "base/threading/thread_task_runner_handle.h" | 
|  | #include "build/build_config.h" | 
|  | #include "storage/browser/fileapi/external_mount_points.h" | 
|  | #include "storage/browser/fileapi/file_system_backend.h" | 
|  | #include "storage/browser/fileapi/file_system_context.h" | 
|  | #include "storage/browser/fileapi/file_system_operation_context.h" | 
|  | #include "storage/browser/fileapi/file_system_usage_cache.h" | 
|  | #include "storage/browser/fileapi/obfuscated_file_util.h" | 
|  | #include "storage/browser/fileapi/sandbox_directory_database.h" | 
|  | #include "storage/browser/fileapi/sandbox_file_system_backend_delegate.h" | 
|  | #include "storage/browser/fileapi/sandbox_isolated_origin_database.h" | 
|  | #include "storage/browser/fileapi/sandbox_origin_database.h" | 
|  | #include "storage/browser/quota/quota_manager.h" | 
|  | #include "storage/browser/test/async_file_test_helper.h" | 
|  | #include "storage/browser/test/fileapi_test_file_set.h" | 
|  | #include "storage/browser/test/mock_file_change_observer.h" | 
|  | #include "storage/browser/test/mock_special_storage_policy.h" | 
|  | #include "storage/browser/test/sandbox_file_system_test_helper.h" | 
|  | #include "storage/browser/test/test_file_system_context.h" | 
|  | #include "storage/common/database/database_identifier.h" | 
|  | #include "storage/common/quota/quota_types.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | using content::AsyncFileTestHelper; | 
|  | using storage::FileSystemContext; | 
|  | using storage::FileSystemOperation; | 
|  | using storage::FileSystemOperationContext; | 
|  | using storage::FileSystemURL; | 
|  | using storage::ObfuscatedFileUtil; | 
|  | using storage::SandboxDirectoryDatabase; | 
|  | using storage::SandboxIsolatedOriginDatabase; | 
|  | using storage::kFileSystemTypeTemporary; | 
|  | using storage::kFileSystemTypePersistent; | 
|  |  | 
|  | namespace content { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | bool FileExists(const base::FilePath& path) { | 
|  | return base::PathExists(path) && !base::DirectoryExists(path); | 
|  | } | 
|  |  | 
|  | int64_t GetSize(const base::FilePath& path) { | 
|  | int64_t size; | 
|  | EXPECT_TRUE(base::GetFileSize(path, &size)); | 
|  | return size; | 
|  | } | 
|  |  | 
|  | // After a move, the dest exists and the source doesn't. | 
|  | // After a copy, both source and dest exist. | 
|  | struct CopyMoveTestCaseRecord { | 
|  | bool is_copy_not_move; | 
|  | const char source_path[64]; | 
|  | const char dest_path[64]; | 
|  | bool cause_overwrite; | 
|  | }; | 
|  |  | 
|  | const CopyMoveTestCaseRecord kCopyMoveTestCases[] = { | 
|  | // This is the combinatoric set of: | 
|  | //  rename vs. same-name | 
|  | //  different directory vs. same directory | 
|  | //  overwrite vs. no-overwrite | 
|  | //  copy vs. move | 
|  | //  We can never be called with source and destination paths identical, so | 
|  | //  those cases are omitted. | 
|  | {true, "dir0/file0", "dir0/file1", false}, | 
|  | {false, "dir0/file0", "dir0/file1", false}, | 
|  | {true, "dir0/file0", "dir0/file1", true}, | 
|  | {false, "dir0/file0", "dir0/file1", true}, | 
|  |  | 
|  | {true, "dir0/file0", "dir1/file0", false}, | 
|  | {false, "dir0/file0", "dir1/file0", false}, | 
|  | {true, "dir0/file0", "dir1/file0", true}, | 
|  | {false, "dir0/file0", "dir1/file0", true}, | 
|  | {true, "dir0/file0", "dir1/file1", false}, | 
|  | {false, "dir0/file0", "dir1/file1", false}, | 
|  | {true, "dir0/file0", "dir1/file1", true}, | 
|  | {false, "dir0/file0", "dir1/file1", true}, | 
|  | }; | 
|  |  | 
|  | struct OriginEnumerationTestRecord { | 
|  | std::string origin_url; | 
|  | bool has_temporary; | 
|  | bool has_persistent; | 
|  | }; | 
|  |  | 
|  | const OriginEnumerationTestRecord kOriginEnumerationTestRecords[] = { | 
|  | {"http://example.com/", false, true}, | 
|  | {"http://example1.com/", true, false}, | 
|  | {"https://example1.com/", true, true}, | 
|  | {"file:///", false, true}, | 
|  | {"http://example.com:8000/", false, true}, | 
|  | }; | 
|  |  | 
|  | FileSystemURL FileSystemURLAppend( | 
|  | const FileSystemURL& url, const base::FilePath::StringType& child) { | 
|  | return FileSystemURL::CreateForTest( | 
|  | url.origin(), url.mount_type(), url.virtual_path().Append(child)); | 
|  | } | 
|  |  | 
|  | FileSystemURL FileSystemURLAppendUTF8( | 
|  | const FileSystemURL& url, const std::string& child) { | 
|  | return FileSystemURL::CreateForTest( | 
|  | url.origin(), | 
|  | url.mount_type(), | 
|  | url.virtual_path().Append(base::FilePath::FromUTF8Unsafe(child))); | 
|  | } | 
|  |  | 
|  | FileSystemURL FileSystemURLDirName(const FileSystemURL& url) { | 
|  | return FileSystemURL::CreateForTest( | 
|  | url.origin(), | 
|  | url.mount_type(), | 
|  | storage::VirtualPath::DirName(url.virtual_path())); | 
|  | } | 
|  |  | 
|  | std::string GetTypeString(storage::FileSystemType type) { | 
|  | return storage::SandboxFileSystemBackendDelegate::GetTypeString(type); | 
|  | } | 
|  |  | 
|  | bool HasFileSystemType(ObfuscatedFileUtil::AbstractOriginEnumerator* enumerator, | 
|  | storage::FileSystemType type) { | 
|  | return enumerator->HasTypeDirectory(GetTypeString(type)); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | // TODO(ericu): The vast majority of this and the other FSFU subclass tests | 
|  | // could theoretically be shared.  It would basically be a FSFU interface | 
|  | // compliance test, and only the subclass-specific bits that look into the | 
|  | // implementation would need to be written per-subclass. | 
|  | class ObfuscatedFileUtilTest : public testing::Test { | 
|  | public: | 
|  | ObfuscatedFileUtilTest() | 
|  | : scoped_task_environment_( | 
|  | base::test::ScopedTaskEnvironment::MainThreadType::IO), | 
|  | origin_(GURL("http://www.example.com")), | 
|  | type_(storage::kFileSystemTypeTemporary), | 
|  | sandbox_file_system_(origin_, type_), | 
|  | quota_status_(storage::kQuotaStatusUnknown), | 
|  | usage_(-1), | 
|  | weak_factory_(this) {} | 
|  |  | 
|  | void SetUp() override { | 
|  | ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); | 
|  |  | 
|  | storage_policy_ = new MockSpecialStoragePolicy(); | 
|  |  | 
|  | quota_manager_ = new storage::QuotaManager( | 
|  | false /* is_incognito */, data_dir_.GetPath(), | 
|  | base::ThreadTaskRunnerHandle::Get().get(), storage_policy_.get(), | 
|  | storage::GetQuotaSettingsFunc()); | 
|  | storage::QuotaSettings settings; | 
|  | settings.per_host_quota = 25 * 1024 * 1024; | 
|  | settings.pool_size = settings.per_host_quota * 5; | 
|  | settings.must_remain_available = 10 * 1024 * 1024; | 
|  | settings.refresh_interval = base::TimeDelta::Max(); | 
|  | quota_manager_->SetQuotaSettings(settings); | 
|  |  | 
|  | // Every time we create a new sandbox_file_system helper, | 
|  | // it creates another context, which creates another path manager, | 
|  | // another sandbox_backend, and another OFU. | 
|  | // We need to pass in the context to skip all that. | 
|  | file_system_context_ = CreateFileSystemContextForTesting( | 
|  | quota_manager_->proxy(), data_dir_.GetPath()); | 
|  |  | 
|  | sandbox_file_system_.SetUp(file_system_context_.get()); | 
|  |  | 
|  | change_observers_ = | 
|  | storage::MockFileChangeObserver::CreateList(&change_observer_); | 
|  | } | 
|  |  | 
|  | void TearDown() override { | 
|  | quota_manager_ = NULL; | 
|  | scoped_task_environment_.RunUntilIdle(); | 
|  | sandbox_file_system_.TearDown(); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<FileSystemOperationContext> LimitedContext( | 
|  | int64_t allowed_bytes_growth) { | 
|  | std::unique_ptr<FileSystemOperationContext> context( | 
|  | sandbox_file_system_.NewOperationContext()); | 
|  | context->set_allowed_bytes_growth(allowed_bytes_growth); | 
|  | return context; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<FileSystemOperationContext> UnlimitedContext() { | 
|  | return LimitedContext(std::numeric_limits<int64_t>::max()); | 
|  | } | 
|  |  | 
|  | FileSystemOperationContext* NewContext( | 
|  | SandboxFileSystemTestHelper* file_system) { | 
|  | change_observer()->ResetCount(); | 
|  | FileSystemOperationContext* context; | 
|  | if (file_system) | 
|  | context = file_system->NewOperationContext(); | 
|  | else | 
|  | context = sandbox_file_system_.NewOperationContext(); | 
|  | // Setting allowed_bytes_growth big enough for all tests. | 
|  | context->set_allowed_bytes_growth(1024 * 1024); | 
|  | context->set_change_observers(change_observers()); | 
|  | return context; | 
|  | } | 
|  |  | 
|  | const storage::ChangeObserverList& change_observers() const { | 
|  | return change_observers_; | 
|  | } | 
|  |  | 
|  | storage::MockFileChangeObserver* change_observer() { | 
|  | return &change_observer_; | 
|  | } | 
|  |  | 
|  | // This can only be used after SetUp has run and created file_system_context_ | 
|  | // and obfuscated_file_util_. | 
|  | // Use this for tests which need to run in multiple origins; we need a test | 
|  | // helper per origin. | 
|  | SandboxFileSystemTestHelper* NewFileSystem(const GURL& origin, | 
|  | storage::FileSystemType type) { | 
|  | SandboxFileSystemTestHelper* file_system = | 
|  | new SandboxFileSystemTestHelper(origin, type); | 
|  |  | 
|  | file_system->SetUp(file_system_context_.get()); | 
|  | return file_system; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<ObfuscatedFileUtil> CreateObfuscatedFileUtil( | 
|  | storage::SpecialStoragePolicy* storage_policy) { | 
|  | return std::unique_ptr<ObfuscatedFileUtil>( | 
|  | ObfuscatedFileUtil::CreateForTesting( | 
|  | storage_policy, data_dir_path(), NULL, | 
|  | base::ThreadTaskRunnerHandle::Get().get())); | 
|  | } | 
|  |  | 
|  | ObfuscatedFileUtil* ofu() { | 
|  | return static_cast<ObfuscatedFileUtil*>(sandbox_file_system_.file_util()); | 
|  | } | 
|  |  | 
|  | const base::FilePath& test_directory() const { return data_dir_.GetPath(); } | 
|  |  | 
|  | const GURL& origin() const { | 
|  | return origin_; | 
|  | } | 
|  |  | 
|  | storage::FileSystemType type() const { return type_; } | 
|  |  | 
|  | std::string type_string() const { | 
|  | return GetTypeString(type_); | 
|  | } | 
|  |  | 
|  | int64_t ComputeTotalFileSize() { | 
|  | return sandbox_file_system_.ComputeCurrentOriginUsage() - | 
|  | sandbox_file_system_.ComputeCurrentDirectoryDatabaseUsage(); | 
|  | } | 
|  |  | 
|  | void GetUsageFromQuotaManager() { | 
|  | int64_t quota = -1; | 
|  | quota_status_ = | 
|  | AsyncFileTestHelper::GetUsageAndQuota(quota_manager_.get(), | 
|  | origin(), | 
|  | sandbox_file_system_.type(), | 
|  | &usage_, | 
|  | "a); | 
|  | EXPECT_EQ(storage::kQuotaStatusOk, quota_status_); | 
|  | } | 
|  |  | 
|  | void RevokeUsageCache() { | 
|  | quota_manager_->ResetUsageTracker(sandbox_file_system_.storage_type()); | 
|  | usage_cache()->Delete(sandbox_file_system_.GetUsageCachePath()); | 
|  | } | 
|  |  | 
|  | int64_t SizeByQuotaUtil() { | 
|  | return sandbox_file_system_.GetCachedOriginUsage(); | 
|  | } | 
|  |  | 
|  | int64_t SizeInUsageFile() { | 
|  | scoped_task_environment_.RunUntilIdle(); | 
|  | int64_t usage = 0; | 
|  | return usage_cache()->GetUsage( | 
|  | sandbox_file_system_.GetUsageCachePath(), &usage) ? usage : -1; | 
|  | } | 
|  |  | 
|  | bool PathExists(const FileSystemURL& url) { | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  | base::File::Info file_info; | 
|  | base::FilePath platform_path; | 
|  | base::File::Error error = ofu()->GetFileInfo( | 
|  | context.get(), url, &file_info, &platform_path); | 
|  | return error == base::File::FILE_OK; | 
|  | } | 
|  |  | 
|  | bool DirectoryExists(const FileSystemURL& url) { | 
|  | return AsyncFileTestHelper::DirectoryExists(file_system_context(), url); | 
|  | } | 
|  |  | 
|  | int64_t usage() const { return usage_; } | 
|  | storage::FileSystemUsageCache* usage_cache() { | 
|  | return sandbox_file_system_.usage_cache(); | 
|  | } | 
|  |  | 
|  | FileSystemURL CreateURLFromUTF8(const std::string& path) { | 
|  | return sandbox_file_system_.CreateURLFromUTF8(path); | 
|  | } | 
|  |  | 
|  | int64_t PathCost(const FileSystemURL& url) { | 
|  | return ObfuscatedFileUtil::ComputeFilePathCost(url.path()); | 
|  | } | 
|  |  | 
|  | FileSystemURL CreateURL(const base::FilePath& path) { | 
|  | return sandbox_file_system_.CreateURL(path); | 
|  | } | 
|  |  | 
|  | void CheckFileAndCloseHandle(const FileSystemURL& url, base::File file) { | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  | base::FilePath local_path; | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetLocalFilePath(context.get(), url, &local_path)); | 
|  |  | 
|  | base::File::Info file_info0; | 
|  | base::FilePath data_path; | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetFileInfo(context.get(), url, &file_info0, &data_path)); | 
|  | EXPECT_EQ(data_path, local_path); | 
|  | EXPECT_TRUE(FileExists(data_path)); | 
|  | EXPECT_EQ(0, GetSize(data_path)); | 
|  |  | 
|  | const char data[] = "test data"; | 
|  | const int length = arraysize(data) - 1; | 
|  |  | 
|  | if (!file.IsValid()) { | 
|  | file.Initialize(data_path, | 
|  | base::File::FLAG_OPEN | base::File::FLAG_WRITE); | 
|  | ASSERT_TRUE(file.IsValid()); | 
|  | EXPECT_FALSE(file.created()); | 
|  | } | 
|  | ASSERT_EQ(length, file.Write(0, data, length)); | 
|  | file.Close(); | 
|  |  | 
|  | base::File::Info file_info1; | 
|  | EXPECT_EQ(length, GetSize(data_path)); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetFileInfo(context.get(), url, &file_info1, &data_path)); | 
|  | EXPECT_EQ(data_path, local_path); | 
|  |  | 
|  | EXPECT_FALSE(file_info0.is_directory); | 
|  | EXPECT_FALSE(file_info1.is_directory); | 
|  | EXPECT_FALSE(file_info0.is_symbolic_link); | 
|  | EXPECT_FALSE(file_info1.is_symbolic_link); | 
|  | EXPECT_EQ(0, file_info0.size); | 
|  | EXPECT_EQ(length, file_info1.size); | 
|  | EXPECT_LE(file_info0.last_modified, file_info1.last_modified); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate(context.get(), url, length * 2)); | 
|  | EXPECT_EQ(length * 2, GetSize(data_path)); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate(context.get(), url, 0)); | 
|  | EXPECT_EQ(0, GetSize(data_path)); | 
|  | } | 
|  |  | 
|  | void ValidateTestDirectory( | 
|  | const FileSystemURL& root_url, | 
|  | const std::set<base::FilePath::StringType>& files, | 
|  | const std::set<base::FilePath::StringType>& directories) { | 
|  | std::unique_ptr<FileSystemOperationContext> context; | 
|  | std::set<base::FilePath::StringType>::const_iterator iter; | 
|  | for (iter = files.begin(); iter != files.end(); ++iter) { | 
|  | bool created = true; | 
|  | context.reset(NewContext(NULL)); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), | 
|  | FileSystemURLAppend(root_url, *iter), | 
|  | &created)); | 
|  | ASSERT_FALSE(created); | 
|  | } | 
|  | for (iter = directories.begin(); iter != directories.end(); ++iter) { | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_TRUE(DirectoryExists( | 
|  | FileSystemURLAppend(root_url, *iter))); | 
|  | } | 
|  | } | 
|  |  | 
|  | class UsageVerifyHelper { | 
|  | public: | 
|  | UsageVerifyHelper(std::unique_ptr<FileSystemOperationContext> context, | 
|  | SandboxFileSystemTestHelper* file_system, | 
|  | int64_t expected_usage, | 
|  | ObfuscatedFileUtilTest* test) | 
|  | : context_(std::move(context)), | 
|  | sandbox_file_system_(file_system), | 
|  | expected_usage_(expected_usage), | 
|  | test_(test) {} | 
|  |  | 
|  | ~UsageVerifyHelper() { | 
|  | test_->scoped_task_environment_.RunUntilIdle(); | 
|  | Check(); | 
|  | } | 
|  |  | 
|  | FileSystemOperationContext* context() { | 
|  | return context_.get(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | void Check() { | 
|  | ASSERT_EQ(expected_usage_, | 
|  | sandbox_file_system_->GetCachedOriginUsage()); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<FileSystemOperationContext> context_; | 
|  | SandboxFileSystemTestHelper* sandbox_file_system_; | 
|  | int64_t expected_usage_; | 
|  | ObfuscatedFileUtilTest* const test_; | 
|  | }; | 
|  |  | 
|  | std::unique_ptr<UsageVerifyHelper> AllowUsageIncrease( | 
|  | int64_t requested_growth) { | 
|  | int64_t usage = sandbox_file_system_.GetCachedOriginUsage(); | 
|  | return std::unique_ptr<UsageVerifyHelper>(new UsageVerifyHelper( | 
|  | LimitedContext(requested_growth), &sandbox_file_system_, | 
|  | usage + requested_growth, this)); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<UsageVerifyHelper> DisallowUsageIncrease( | 
|  | int64_t requested_growth) { | 
|  | int64_t usage = sandbox_file_system_.GetCachedOriginUsage(); | 
|  | return std::unique_ptr<UsageVerifyHelper>( | 
|  | new UsageVerifyHelper(LimitedContext(requested_growth - 1), | 
|  | &sandbox_file_system_, usage, this)); | 
|  | } | 
|  |  | 
|  | void FillTestDirectory( | 
|  | const FileSystemURL& root_url, | 
|  | std::set<base::FilePath::StringType>* files, | 
|  | std::set<base::FilePath::StringType>* directories) { | 
|  | std::unique_ptr<FileSystemOperationContext> context; | 
|  | std::vector<storage::DirectoryEntry> entries; | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | AsyncFileTestHelper::ReadDirectory(file_system_context(), | 
|  | root_url, &entries)); | 
|  | EXPECT_EQ(0UL, entries.size()); | 
|  |  | 
|  | files->clear(); | 
|  | files->insert(FILE_PATH_LITERAL("first")); | 
|  | files->insert(FILE_PATH_LITERAL("second")); | 
|  | files->insert(FILE_PATH_LITERAL("third")); | 
|  | directories->clear(); | 
|  | directories->insert(FILE_PATH_LITERAL("fourth")); | 
|  | directories->insert(FILE_PATH_LITERAL("fifth")); | 
|  | directories->insert(FILE_PATH_LITERAL("sixth")); | 
|  | std::set<base::FilePath::StringType>::iterator iter; | 
|  | for (iter = files->begin(); iter != files->end(); ++iter) { | 
|  | bool created = false; | 
|  | context.reset(NewContext(NULL)); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), | 
|  | FileSystemURLAppend(root_url, *iter), | 
|  | &created)); | 
|  | ASSERT_TRUE(created); | 
|  | } | 
|  | for (iter = directories->begin(); iter != directories->end(); ++iter) { | 
|  | bool exclusive = true; | 
|  | bool recursive = false; | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), | 
|  | FileSystemURLAppend(root_url, *iter), | 
|  | exclusive, recursive)); | 
|  | } | 
|  | ValidateTestDirectory(root_url, *files, *directories); | 
|  | } | 
|  |  | 
|  | void TestReadDirectoryHelper(const FileSystemURL& root_url) { | 
|  | std::set<base::FilePath::StringType> files; | 
|  | std::set<base::FilePath::StringType> directories; | 
|  | FillTestDirectory(root_url, &files, &directories); | 
|  |  | 
|  | std::unique_ptr<FileSystemOperationContext> context; | 
|  | std::vector<storage::DirectoryEntry> entries; | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | AsyncFileTestHelper::ReadDirectory( | 
|  | file_system_context(), root_url, &entries)); | 
|  | std::vector<storage::DirectoryEntry>::iterator entry_iter; | 
|  | EXPECT_EQ(files.size() + directories.size(), entries.size()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | for (entry_iter = entries.begin(); entry_iter != entries.end(); | 
|  | ++entry_iter) { | 
|  | const storage::DirectoryEntry& entry = *entry_iter; | 
|  | std::set<base::FilePath::StringType>::iterator iter = | 
|  | files.find(entry.name); | 
|  | if (iter != files.end()) { | 
|  | EXPECT_FALSE(entry.is_directory); | 
|  | files.erase(iter); | 
|  | continue; | 
|  | } | 
|  | iter = directories.find(entry.name); | 
|  | EXPECT_FALSE(directories.end() == iter); | 
|  | EXPECT_TRUE(entry.is_directory); | 
|  | directories.erase(iter); | 
|  | } | 
|  | } | 
|  |  | 
|  | void TestTouchHelper(const FileSystemURL& url, bool is_file) { | 
|  | base::Time last_access_time = base::Time::Now(); | 
|  | base::Time last_modified_time = base::Time::Now(); | 
|  |  | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->Touch(context.get(), url, last_access_time, | 
|  | last_modified_time)); | 
|  | // Currently we fire no change notifications for Touch. | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | base::FilePath local_path; | 
|  | base::File::Info file_info; | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, ofu()->GetFileInfo( | 
|  | context.get(), url, &file_info, &local_path)); | 
|  | // We compare as time_t here to lower our resolution, to avoid false | 
|  | // negatives caused by conversion to the local filesystem's native | 
|  | // representation and back. | 
|  | EXPECT_EQ(file_info.last_modified.ToTimeT(), last_modified_time.ToTimeT()); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | last_modified_time += base::TimeDelta::FromHours(1); | 
|  | last_access_time += base::TimeDelta::FromHours(14); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->Touch(context.get(), url, last_access_time, | 
|  | last_modified_time)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetFileInfo(context.get(), url, &file_info, &local_path)); | 
|  | EXPECT_EQ(file_info.last_modified.ToTimeT(), last_modified_time.ToTimeT()); | 
|  | if (is_file)  // Directories in OFU don't support atime. | 
|  | EXPECT_EQ(file_info.last_accessed.ToTimeT(), last_access_time.ToTimeT()); | 
|  | } | 
|  |  | 
|  | void TestCopyInForeignFileHelper(bool overwrite) { | 
|  | base::ScopedTempDir source_dir; | 
|  | ASSERT_TRUE(source_dir.CreateUniqueTempDir()); | 
|  | base::FilePath root_file_path = source_dir.GetPath(); | 
|  | base::FilePath src_file_path = root_file_path.AppendASCII("file_name"); | 
|  | FileSystemURL dest_url = CreateURLFromUTF8("new file"); | 
|  | int64_t src_file_length = 87; | 
|  |  | 
|  | base::File file(src_file_path, | 
|  | base::File::FLAG_CREATE | base::File::FLAG_WRITE); | 
|  | ASSERT_TRUE(file.IsValid()); | 
|  | EXPECT_TRUE(file.created()); | 
|  | ASSERT_TRUE(file.SetLength(src_file_length)); | 
|  | file.Close(); | 
|  |  | 
|  | std::unique_ptr<FileSystemOperationContext> context; | 
|  |  | 
|  | if (overwrite) { | 
|  | context.reset(NewContext(NULL)); | 
|  | bool created = false; | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), dest_url, &created)); | 
|  | EXPECT_TRUE(created); | 
|  |  | 
|  | // We must have observed one (and only one) create_file_count. | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count()); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | const int64_t path_cost = | 
|  | ObfuscatedFileUtil::ComputeFilePathCost(dest_url.path()); | 
|  | if (!overwrite) { | 
|  | // Verify that file creation requires sufficient quota for the path. | 
|  | context.reset(NewContext(NULL)); | 
|  | context->set_allowed_bytes_growth(path_cost + src_file_length - 1); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE, | 
|  | ofu()->CopyInForeignFile(context.get(), | 
|  | src_file_path, dest_url)); | 
|  | } | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | context->set_allowed_bytes_growth(path_cost + src_file_length); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CopyInForeignFile(context.get(), | 
|  | src_file_path, dest_url)); | 
|  |  | 
|  | EXPECT_TRUE(PathExists(dest_url)); | 
|  | EXPECT_FALSE(DirectoryExists(dest_url)); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | base::File::Info file_info; | 
|  | base::FilePath data_path; | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetFileInfo(context.get(), dest_url, &file_info, | 
|  | &data_path)); | 
|  | EXPECT_NE(data_path, src_file_path); | 
|  | EXPECT_TRUE(FileExists(data_path)); | 
|  | EXPECT_EQ(src_file_length, GetSize(data_path)); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->DeleteFile(context.get(), dest_url)); | 
|  | } | 
|  |  | 
|  | void ClearTimestamp(const FileSystemURL& url) { | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->Touch(context.get(), url, base::Time(), base::Time())); | 
|  | EXPECT_EQ(base::Time(), GetModifiedTime(url)); | 
|  | } | 
|  |  | 
|  | base::Time GetModifiedTime(const FileSystemURL& url) { | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  | base::FilePath data_path; | 
|  | base::File::Info file_info; | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetFileInfo(context.get(), url, &file_info, &data_path)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | return file_info.last_modified; | 
|  | } | 
|  |  | 
|  | void TestDirectoryTimestampHelper(const FileSystemURL& base_dir, | 
|  | bool copy, | 
|  | bool overwrite) { | 
|  | std::unique_ptr<FileSystemOperationContext> context; | 
|  | const FileSystemURL src_dir_url( | 
|  | FileSystemURLAppendUTF8(base_dir, "foo_dir")); | 
|  | const FileSystemURL dest_dir_url( | 
|  | FileSystemURLAppendUTF8(base_dir, "bar_dir")); | 
|  |  | 
|  | const FileSystemURL src_file_url( | 
|  | FileSystemURLAppendUTF8(src_dir_url, "hoge")); | 
|  | const FileSystemURL dest_file_url( | 
|  | FileSystemURLAppendUTF8(dest_dir_url, "fuga")); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), src_dir_url, true, true)); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), dest_dir_url, true, true)); | 
|  |  | 
|  | bool created = false; | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), src_file_url, &created)); | 
|  | if (overwrite) { | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), | 
|  | dest_file_url, &created)); | 
|  | } | 
|  |  | 
|  | ClearTimestamp(src_dir_url); | 
|  | ClearTimestamp(dest_dir_url); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CopyOrMoveFile(context.get(), | 
|  | src_file_url, dest_file_url, | 
|  | FileSystemOperation::OPTION_NONE, | 
|  | copy)); | 
|  | if (copy) | 
|  | EXPECT_EQ(base::Time(), GetModifiedTime(src_dir_url)); | 
|  | else | 
|  | EXPECT_NE(base::Time(), GetModifiedTime(src_dir_url)); | 
|  | EXPECT_NE(base::Time(), GetModifiedTime(dest_dir_url)); | 
|  | } | 
|  |  | 
|  | void MaybeDropDatabasesAliveCaseTestBody() { | 
|  | std::unique_ptr<ObfuscatedFileUtil> file_util = | 
|  | CreateObfuscatedFileUtil(NULL); | 
|  | file_util->InitOriginDatabase(GURL(), true /*create*/); | 
|  | ASSERT_TRUE(file_util->origin_database_ != NULL); | 
|  |  | 
|  | // Callback to Drop DB is called while ObfuscatedFileUtilTest is | 
|  | // still alive. | 
|  | file_util->db_flush_delay_seconds_ = 0; | 
|  | file_util->MarkUsed(); | 
|  | scoped_task_environment_.RunUntilIdle(); | 
|  |  | 
|  | ASSERT_TRUE(file_util->origin_database_ == NULL); | 
|  | } | 
|  |  | 
|  | void MaybeDropDatabasesAlreadyDeletedCaseTestBody() { | 
|  | // Run message loop after OFU is already deleted to make sure callback | 
|  | // doesn't cause a crash for use after free. | 
|  | { | 
|  | std::unique_ptr<ObfuscatedFileUtil> file_util = | 
|  | CreateObfuscatedFileUtil(NULL); | 
|  | file_util->InitOriginDatabase(GURL(), true /*create*/); | 
|  | file_util->db_flush_delay_seconds_ = 0; | 
|  | file_util->MarkUsed(); | 
|  | } | 
|  |  | 
|  | // At this point the callback is still in the message queue but OFU is gone. | 
|  | scoped_task_environment_.RunUntilIdle(); | 
|  | } | 
|  |  | 
|  | void DestroyDirectoryDatabase_IsolatedTestBody() { | 
|  | storage_policy_->AddIsolated(origin_); | 
|  | std::unique_ptr<ObfuscatedFileUtil> file_util = | 
|  | CreateObfuscatedFileUtil(storage_policy_.get()); | 
|  | const FileSystemURL url = FileSystemURL::CreateForTest( | 
|  | origin_, kFileSystemTypePersistent, base::FilePath()); | 
|  |  | 
|  | // Create DirectoryDatabase for isolated origin. | 
|  | SandboxDirectoryDatabase* db = | 
|  | file_util->GetDirectoryDatabase(url, true /* create */); | 
|  | ASSERT_TRUE(db != NULL); | 
|  |  | 
|  | // Destory it. | 
|  | file_util->DestroyDirectoryDatabase( | 
|  | url.origin(), GetTypeString(url.type())); | 
|  | ASSERT_TRUE(file_util->directories_.empty()); | 
|  | } | 
|  |  | 
|  | void GetDirectoryDatabase_IsolatedTestBody() { | 
|  | storage_policy_->AddIsolated(origin_); | 
|  | std::unique_ptr<ObfuscatedFileUtil> file_util = | 
|  | CreateObfuscatedFileUtil(storage_policy_.get()); | 
|  | const FileSystemURL url = FileSystemURL::CreateForTest( | 
|  | origin_, kFileSystemTypePersistent, base::FilePath()); | 
|  |  | 
|  | // Create DirectoryDatabase for isolated origin. | 
|  | SandboxDirectoryDatabase* db = | 
|  | file_util->GetDirectoryDatabase(url, true /* create */); | 
|  | ASSERT_TRUE(db != NULL); | 
|  | ASSERT_EQ(1U, file_util->directories_.size()); | 
|  |  | 
|  | // Remove isolated. | 
|  | storage_policy_->RemoveIsolated(url.origin()); | 
|  |  | 
|  | // This should still get the same database. | 
|  | SandboxDirectoryDatabase* db2 = | 
|  | file_util->GetDirectoryDatabase(url, false /* create */); | 
|  | ASSERT_EQ(db, db2); | 
|  | } | 
|  |  | 
|  | void MigrationBackFromIsolatedTestBody() { | 
|  | std::string kFakeDirectoryData("0123456789"); | 
|  | base::FilePath old_directory_db_path; | 
|  |  | 
|  | // Initialize the directory with one origin using | 
|  | // SandboxIsolatedOriginDatabase. | 
|  | { | 
|  | std::string origin_string = storage::GetIdentifierFromOrigin(origin_); | 
|  | SandboxIsolatedOriginDatabase database_old( | 
|  | origin_string, data_dir_path(), | 
|  | base::FilePath( | 
|  | SandboxIsolatedOriginDatabase::kObsoleteOriginDirectory)); | 
|  | base::FilePath path; | 
|  | EXPECT_TRUE(database_old.GetPathForOrigin(origin_string, &path)); | 
|  | EXPECT_FALSE(path.empty()); | 
|  |  | 
|  | // Populate the origin directory with some fake data. | 
|  | old_directory_db_path = data_dir_path().Append(path); | 
|  | ASSERT_TRUE(base::CreateDirectory(old_directory_db_path)); | 
|  | EXPECT_EQ(static_cast<int>(kFakeDirectoryData.size()), | 
|  | base::WriteFile(old_directory_db_path.AppendASCII("dummy"), | 
|  | kFakeDirectoryData.data(), | 
|  | kFakeDirectoryData.size())); | 
|  | } | 
|  |  | 
|  | storage_policy_->AddIsolated(origin_); | 
|  | std::unique_ptr<ObfuscatedFileUtil> file_util = | 
|  | CreateObfuscatedFileUtil(storage_policy_.get()); | 
|  | base::File::Error error = base::File::FILE_ERROR_FAILED; | 
|  | base::FilePath origin_directory = file_util->GetDirectoryForOrigin( | 
|  | origin_, true /* create */, &error); | 
|  | EXPECT_EQ(base::File::FILE_OK, error); | 
|  |  | 
|  | // The database is migrated from the old one. | 
|  | EXPECT_TRUE(base::DirectoryExists(origin_directory)); | 
|  | EXPECT_FALSE(base::DirectoryExists(old_directory_db_path)); | 
|  |  | 
|  | // Check we see the same contents in the new origin directory. | 
|  | std::string origin_db_data; | 
|  | EXPECT_TRUE(base::PathExists(origin_directory.AppendASCII("dummy"))); | 
|  | EXPECT_TRUE(base::ReadFileToString( | 
|  | origin_directory.AppendASCII("dummy"), &origin_db_data)); | 
|  | EXPECT_EQ(kFakeDirectoryData, origin_db_data); | 
|  | } | 
|  |  | 
|  | int64_t ComputeCurrentUsage() { | 
|  | return sandbox_file_system_.ComputeCurrentOriginUsage() - | 
|  | sandbox_file_system_.ComputeCurrentDirectoryDatabaseUsage(); | 
|  | } | 
|  |  | 
|  | FileSystemContext* file_system_context() { | 
|  | return sandbox_file_system_.file_system_context(); | 
|  | } | 
|  |  | 
|  | const base::FilePath& data_dir_path() const { return data_dir_.GetPath(); } | 
|  |  | 
|  | protected: | 
|  | base::test::ScopedTaskEnvironment scoped_task_environment_; | 
|  | base::ScopedTempDir data_dir_; | 
|  | scoped_refptr<MockSpecialStoragePolicy> storage_policy_; | 
|  | scoped_refptr<storage::QuotaManager> quota_manager_; | 
|  | scoped_refptr<FileSystemContext> file_system_context_; | 
|  | GURL origin_; | 
|  | storage::FileSystemType type_; | 
|  | SandboxFileSystemTestHelper sandbox_file_system_; | 
|  | storage::QuotaStatusCode quota_status_; | 
|  | int64_t usage_; | 
|  | storage::MockFileChangeObserver change_observer_; | 
|  | storage::ChangeObserverList change_observers_; | 
|  | base::WeakPtrFactory<ObfuscatedFileUtilTest> weak_factory_; | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtilTest); | 
|  | }; | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestCreateAndDeleteFile) { | 
|  | FileSystemURL url = CreateURLFromUTF8("fake/file"); | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  | int file_flags = base::File::FLAG_CREATE | base::File::FLAG_WRITE; | 
|  |  | 
|  | base::File file = ofu()->CreateOrOpen(context.get(), url, file_flags); | 
|  | EXPECT_FALSE(file.IsValid()); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, file.error_details()); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | ofu()->DeleteFile(context.get(), url)); | 
|  |  | 
|  | url = CreateURLFromUTF8("test file"); | 
|  |  | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | // Verify that file creation requires sufficient quota for the path. | 
|  | context.reset(NewContext(NULL)); | 
|  | context->set_allowed_bytes_growth( | 
|  | ObfuscatedFileUtil::ComputeFilePathCost(url.path()) - 1); | 
|  | file = ofu()->CreateOrOpen(context.get(), url, file_flags); | 
|  | EXPECT_FALSE(file.IsValid()); | 
|  | ASSERT_EQ(base::File::FILE_ERROR_NO_SPACE, file.error_details()); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | context->set_allowed_bytes_growth( | 
|  | ObfuscatedFileUtil::ComputeFilePathCost(url.path())); | 
|  | file = ofu()->CreateOrOpen(context.get(), url, file_flags); | 
|  | EXPECT_TRUE(file.IsValid()); | 
|  | ASSERT_TRUE(file.created()); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count()); | 
|  |  | 
|  | CheckFileAndCloseHandle(url, std::move(file)); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | base::FilePath local_path; | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetLocalFilePath(context.get(), url, &local_path)); | 
|  | EXPECT_TRUE(base::PathExists(local_path)); | 
|  |  | 
|  | // Verify that deleting a file isn't stopped by zero quota, and that it frees | 
|  | // up quote from its path. | 
|  | context.reset(NewContext(NULL)); | 
|  | context->set_allowed_bytes_growth(0); | 
|  | EXPECT_EQ(base::File::FILE_OK, ofu()->DeleteFile(context.get(), url)); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count()); | 
|  | EXPECT_FALSE(base::PathExists(local_path)); | 
|  | EXPECT_EQ(ObfuscatedFileUtil::ComputeFilePathCost(url.path()), | 
|  | context->allowed_bytes_growth()); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | bool exclusive = true; | 
|  | bool recursive = true; | 
|  | FileSystemURL directory_url = CreateURLFromUTF8( | 
|  | "series/of/directories"); | 
|  | url = FileSystemURLAppendUTF8(directory_url, "file name"); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), directory_url, exclusive, | 
|  | recursive)); | 
|  | // The oepration created 3 directories recursively. | 
|  | EXPECT_EQ(3, change_observer()->get_and_reset_create_directory_count()); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | file = ofu()->CreateOrOpen(context.get(), url, file_flags); | 
|  | ASSERT_TRUE(file.IsValid()); | 
|  | ASSERT_TRUE(file.created()); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count()); | 
|  |  | 
|  | CheckFileAndCloseHandle(url, std::move(file)); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetLocalFilePath(context.get(), url, &local_path)); | 
|  | EXPECT_TRUE(base::PathExists(local_path)); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, ofu()->DeleteFile(context.get(), url)); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count()); | 
|  | EXPECT_FALSE(base::PathExists(local_path)); | 
|  |  | 
|  | // Make sure we have no unexpected changes. | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestTruncate) { | 
|  | bool created = false; | 
|  | FileSystemURL url = CreateURLFromUTF8("file"); | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | ofu()->Truncate(context.get(), url, 4)); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), url, &created)); | 
|  | ASSERT_TRUE(created); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count()); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | base::FilePath local_path; | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetLocalFilePath(context.get(), url, &local_path)); | 
|  | EXPECT_EQ(0, GetSize(local_path)); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, ofu()->Truncate(context.get(), url, 10)); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count()); | 
|  | EXPECT_EQ(10, GetSize(local_path)); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, ofu()->Truncate(context.get(), url, 1)); | 
|  | EXPECT_EQ(1, GetSize(local_path)); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count()); | 
|  |  | 
|  | EXPECT_FALSE(DirectoryExists(url)); | 
|  | EXPECT_TRUE(PathExists(url)); | 
|  |  | 
|  | // Make sure we have no unexpected changes. | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestQuotaOnTruncation) { | 
|  | bool created = false; | 
|  | FileSystemURL url = CreateURLFromUTF8("file"); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists( | 
|  | AllowUsageIncrease(PathCost(url))->context(), | 
|  | url, &created)); | 
|  | ASSERT_TRUE(created); | 
|  | ASSERT_EQ(0, ComputeTotalFileSize()); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate(AllowUsageIncrease(1020)->context(), url, 1020)); | 
|  | ASSERT_EQ(1020, ComputeTotalFileSize()); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate(AllowUsageIncrease(-1020)->context(), url, 0)); | 
|  | ASSERT_EQ(0, ComputeTotalFileSize()); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE, | 
|  | ofu()->Truncate(DisallowUsageIncrease(1021)->context(), | 
|  | url, 1021)); | 
|  | ASSERT_EQ(0, ComputeTotalFileSize()); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate(AllowUsageIncrease(1020)->context(), url, 1020)); | 
|  | ASSERT_EQ(1020, ComputeTotalFileSize()); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate(AllowUsageIncrease(0)->context(), url, 1020)); | 
|  | ASSERT_EQ(1020, ComputeTotalFileSize()); | 
|  |  | 
|  | // quota exceeded | 
|  | { | 
|  | std::unique_ptr<UsageVerifyHelper> helper = AllowUsageIncrease(-1); | 
|  | helper->context()->set_allowed_bytes_growth( | 
|  | helper->context()->allowed_bytes_growth() - 1); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate(helper->context(), url, 1019)); | 
|  | ASSERT_EQ(1019, ComputeTotalFileSize()); | 
|  | } | 
|  |  | 
|  | // Delete backing file to make following truncation fail. | 
|  | base::FilePath local_path; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetLocalFilePath(UnlimitedContext().get(), url, | 
|  | &local_path)); | 
|  | ASSERT_FALSE(local_path.empty()); | 
|  | ASSERT_TRUE(base::DeleteFile(local_path, false)); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | ofu()->Truncate(LimitedContext(1234).get(), url, 1234)); | 
|  | ASSERT_EQ(0, ComputeTotalFileSize()); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestEnsureFileExists) { | 
|  | FileSystemURL url = CreateURLFromUTF8("fake/file"); | 
|  | bool created = false; | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | ofu()->EnsureFileExists(context.get(), url, &created)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | // Verify that file creation requires sufficient quota for the path. | 
|  | context.reset(NewContext(NULL)); | 
|  | url = CreateURLFromUTF8("test file"); | 
|  | created = false; | 
|  | context->set_allowed_bytes_growth( | 
|  | ObfuscatedFileUtil::ComputeFilePathCost(url.path()) - 1); | 
|  | ASSERT_EQ(base::File::FILE_ERROR_NO_SPACE, | 
|  | ofu()->EnsureFileExists(context.get(), url, &created)); | 
|  | ASSERT_FALSE(created); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | context->set_allowed_bytes_growth( | 
|  | ObfuscatedFileUtil::ComputeFilePathCost(url.path())); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), url, &created)); | 
|  | ASSERT_TRUE(created); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count()); | 
|  |  | 
|  | CheckFileAndCloseHandle(url, base::File()); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), url, &created)); | 
|  | ASSERT_FALSE(created); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | // Also test in a subdirectory. | 
|  | url = CreateURLFromUTF8("path/to/file.txt"); | 
|  | context.reset(NewContext(NULL)); | 
|  | bool exclusive = true; | 
|  | bool recursive = true; | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), FileSystemURLDirName(url), | 
|  | exclusive, recursive)); | 
|  | // 2 directories: path/ and path/to. | 
|  | EXPECT_EQ(2, change_observer()->get_and_reset_create_directory_count()); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), url, &created)); | 
|  | ASSERT_TRUE(created); | 
|  | EXPECT_FALSE(DirectoryExists(url)); | 
|  | EXPECT_TRUE(PathExists(url)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestDirectoryOps) { | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  |  | 
|  | bool exclusive = false; | 
|  | bool recursive = false; | 
|  | FileSystemURL url = CreateURLFromUTF8("foo/bar"); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | ofu()->CreateDirectory(context.get(), url, exclusive, recursive)); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | ofu()->DeleteDirectory(context.get(), url)); | 
|  |  | 
|  | FileSystemURL root = CreateURLFromUTF8(std::string()); | 
|  | EXPECT_FALSE(DirectoryExists(url)); | 
|  | EXPECT_FALSE(PathExists(url)); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_TRUE(ofu()->IsDirectoryEmpty(context.get(), root)); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | exclusive = false; | 
|  | recursive = true; | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), url, exclusive, recursive)); | 
|  | EXPECT_EQ(2, change_observer()->get_and_reset_create_directory_count()); | 
|  |  | 
|  | EXPECT_TRUE(DirectoryExists(url)); | 
|  | EXPECT_TRUE(PathExists(url)); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_FALSE(ofu()->IsDirectoryEmpty(context.get(), root)); | 
|  | EXPECT_TRUE(DirectoryExists(FileSystemURLDirName(url))); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_FALSE(ofu()->IsDirectoryEmpty(context.get(), | 
|  | FileSystemURLDirName(url))); | 
|  |  | 
|  | // Can't remove a non-empty directory. | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_EMPTY, | 
|  | ofu()->DeleteDirectory(context.get(), | 
|  | FileSystemURLDirName(url))); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | base::File::Info file_info; | 
|  | base::FilePath local_path; | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetFileInfo(context.get(), url, &file_info, &local_path)); | 
|  | EXPECT_TRUE(local_path.empty()); | 
|  | EXPECT_TRUE(file_info.is_directory); | 
|  | EXPECT_FALSE(file_info.is_symbolic_link); | 
|  |  | 
|  | // Same create again should succeed, since exclusive is false. | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), url, exclusive, recursive)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | exclusive = true; | 
|  | recursive = true; | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_EXISTS, | 
|  | ofu()->CreateDirectory(context.get(), url, exclusive, recursive)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | // Verify that deleting a directory isn't stopped by zero quota, and that it | 
|  | // frees up quota from its path. | 
|  | context.reset(NewContext(NULL)); | 
|  | context->set_allowed_bytes_growth(0); | 
|  | EXPECT_EQ(base::File::FILE_OK, ofu()->DeleteDirectory(context.get(), url)); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count()); | 
|  | EXPECT_EQ(ObfuscatedFileUtil::ComputeFilePathCost(url.path()), | 
|  | context->allowed_bytes_growth()); | 
|  |  | 
|  | url = CreateURLFromUTF8("foo/bop"); | 
|  |  | 
|  | EXPECT_FALSE(DirectoryExists(url)); | 
|  | EXPECT_FALSE(PathExists(url)); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_TRUE(ofu()->IsDirectoryEmpty(context.get(), url)); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | ofu()->GetFileInfo(context.get(), url, &file_info, &local_path)); | 
|  |  | 
|  | // Verify that file creation requires sufficient quota for the path. | 
|  | exclusive = true; | 
|  | recursive = false; | 
|  | context.reset(NewContext(NULL)); | 
|  | context->set_allowed_bytes_growth( | 
|  | ObfuscatedFileUtil::ComputeFilePathCost(url.path()) - 1); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE, | 
|  | ofu()->CreateDirectory(context.get(), url, exclusive, recursive)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | context->set_allowed_bytes_growth( | 
|  | ObfuscatedFileUtil::ComputeFilePathCost(url.path())); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), url, exclusive, recursive)); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count()); | 
|  |  | 
|  | EXPECT_TRUE(DirectoryExists(url)); | 
|  | EXPECT_TRUE(PathExists(url)); | 
|  |  | 
|  | exclusive = true; | 
|  | recursive = false; | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_EXISTS, | 
|  | ofu()->CreateDirectory(context.get(), url, exclusive, recursive)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | exclusive = true; | 
|  | recursive = false; | 
|  | url = CreateURLFromUTF8("foo"); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_EXISTS, | 
|  | ofu()->CreateDirectory(context.get(), url, exclusive, recursive)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  |  | 
|  | url = CreateURLFromUTF8("blah"); | 
|  |  | 
|  | EXPECT_FALSE(DirectoryExists(url)); | 
|  | EXPECT_FALSE(PathExists(url)); | 
|  |  | 
|  | exclusive = true; | 
|  | recursive = false; | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), url, exclusive, recursive)); | 
|  | EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count()); | 
|  |  | 
|  | EXPECT_TRUE(DirectoryExists(url)); | 
|  | EXPECT_TRUE(PathExists(url)); | 
|  |  | 
|  | exclusive = true; | 
|  | recursive = false; | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_EXISTS, | 
|  | ofu()->CreateDirectory(context.get(), url, exclusive, recursive)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestReadDirectory) { | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  | bool exclusive = true; | 
|  | bool recursive = true; | 
|  | FileSystemURL url = CreateURLFromUTF8("directory/to/use"); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), url, exclusive, recursive)); | 
|  | TestReadDirectoryHelper(url); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestReadRootWithSlash) { | 
|  | TestReadDirectoryHelper(CreateURLFromUTF8(std::string())); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestReadRootWithEmptyString) { | 
|  | TestReadDirectoryHelper(CreateURLFromUTF8("/")); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestReadDirectoryOnFile) { | 
|  | FileSystemURL url = CreateURLFromUTF8("file"); | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  |  | 
|  | bool created = false; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), url, &created)); | 
|  | ASSERT_TRUE(created); | 
|  |  | 
|  | std::vector<storage::DirectoryEntry> entries; | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY, | 
|  | AsyncFileTestHelper::ReadDirectory(file_system_context(), url, | 
|  | &entries)); | 
|  |  | 
|  | EXPECT_TRUE(ofu()->IsDirectoryEmpty(context.get(), url)); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestTouch) { | 
|  | FileSystemURL url = CreateURLFromUTF8("file"); | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  |  | 
|  | base::Time last_access_time = base::Time::Now(); | 
|  | base::Time last_modified_time = base::Time::Now(); | 
|  |  | 
|  | // It's not there yet. | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | ofu()->Touch(context.get(), url, last_access_time, | 
|  | last_modified_time)); | 
|  |  | 
|  | // OK, now create it. | 
|  | context.reset(NewContext(NULL)); | 
|  | bool created = false; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), url, &created)); | 
|  | ASSERT_TRUE(created); | 
|  | TestTouchHelper(url, true); | 
|  |  | 
|  | // Now test a directory: | 
|  | context.reset(NewContext(NULL)); | 
|  | bool exclusive = true; | 
|  | bool recursive = false; | 
|  | url = CreateURLFromUTF8("dir"); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), url, exclusive, recursive)); | 
|  | TestTouchHelper(url, false); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestPathQuotas) { | 
|  | FileSystemURL url = CreateURLFromUTF8("fake/file"); | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  |  | 
|  | url = CreateURLFromUTF8("file name"); | 
|  | context->set_allowed_bytes_growth(5); | 
|  | bool created = false; | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE, | 
|  | ofu()->EnsureFileExists(context.get(), url, &created)); | 
|  | EXPECT_FALSE(created); | 
|  | context->set_allowed_bytes_growth(1024); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), url, &created)); | 
|  | EXPECT_TRUE(created); | 
|  | int64_t path_cost = ObfuscatedFileUtil::ComputeFilePathCost(url.path()); | 
|  | EXPECT_EQ(1024 - path_cost, context->allowed_bytes_growth()); | 
|  |  | 
|  | context->set_allowed_bytes_growth(1024); | 
|  | bool exclusive = true; | 
|  | bool recursive = true; | 
|  | url = CreateURLFromUTF8("directory/to/use"); | 
|  | std::vector<base::FilePath::StringType> components; | 
|  | url.path().GetComponents(&components); | 
|  | path_cost = 0; | 
|  | typedef std::vector<base::FilePath::StringType>::iterator iterator; | 
|  | for (iterator iter = components.begin(); | 
|  | iter != components.end(); ++iter) { | 
|  | path_cost += ObfuscatedFileUtil::ComputeFilePathCost( | 
|  | base::FilePath(*iter)); | 
|  | } | 
|  | context.reset(NewContext(NULL)); | 
|  | context->set_allowed_bytes_growth(1024); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), url, exclusive, recursive)); | 
|  | EXPECT_EQ(1024 - path_cost, context->allowed_bytes_growth()); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestCopyOrMoveFileNotFound) { | 
|  | FileSystemURL source_url = CreateURLFromUTF8("path0.txt"); | 
|  | FileSystemURL dest_url = CreateURLFromUTF8("path1.txt"); | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  |  | 
|  | bool is_copy_not_move = false; | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | ofu()->CopyOrMoveFile(context.get(), source_url, dest_url, | 
|  | FileSystemOperation::OPTION_NONE, | 
|  | is_copy_not_move)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | context.reset(NewContext(NULL)); | 
|  | is_copy_not_move = true; | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | ofu()->CopyOrMoveFile(context.get(), source_url, dest_url, | 
|  | FileSystemOperation::OPTION_NONE, | 
|  | is_copy_not_move)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | source_url = CreateURLFromUTF8("dir/dir/file"); | 
|  | bool exclusive = true; | 
|  | bool recursive = true; | 
|  | context.reset(NewContext(NULL)); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), | 
|  | FileSystemURLDirName(source_url), | 
|  | exclusive, recursive)); | 
|  | EXPECT_EQ(2, change_observer()->get_and_reset_create_directory_count()); | 
|  | is_copy_not_move = false; | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | ofu()->CopyOrMoveFile(context.get(), source_url, dest_url, | 
|  | FileSystemOperation::OPTION_NONE, | 
|  | is_copy_not_move)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | context.reset(NewContext(NULL)); | 
|  | is_copy_not_move = true; | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | ofu()->CopyOrMoveFile(context.get(), source_url, dest_url, | 
|  | FileSystemOperation::OPTION_NONE, | 
|  | is_copy_not_move)); | 
|  | EXPECT_TRUE(change_observer()->HasNoChange()); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestCopyOrMoveFileSuccess) { | 
|  | const int64_t kSourceLength = 5; | 
|  | const int64_t kDestLength = 50; | 
|  |  | 
|  | for (size_t i = 0; i < arraysize(kCopyMoveTestCases); ++i) { | 
|  | SCOPED_TRACE(testing::Message() << "kCopyMoveTestCase " << i); | 
|  | const CopyMoveTestCaseRecord& test_case = kCopyMoveTestCases[i]; | 
|  | SCOPED_TRACE(testing::Message() << "\t is_copy_not_move " << | 
|  | test_case.is_copy_not_move); | 
|  | SCOPED_TRACE(testing::Message() << "\t source_path " << | 
|  | test_case.source_path); | 
|  | SCOPED_TRACE(testing::Message() << "\t dest_path " << | 
|  | test_case.dest_path); | 
|  | SCOPED_TRACE(testing::Message() << "\t cause_overwrite " << | 
|  | test_case.cause_overwrite); | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  |  | 
|  | bool exclusive = false; | 
|  | bool recursive = true; | 
|  | FileSystemURL source_url = CreateURLFromUTF8(test_case.source_path); | 
|  | FileSystemURL dest_url = CreateURLFromUTF8(test_case.dest_path); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), | 
|  | FileSystemURLDirName(source_url), | 
|  | exclusive, recursive)); | 
|  | context.reset(NewContext(NULL)); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), | 
|  | FileSystemURLDirName(dest_url), | 
|  | exclusive, recursive)); | 
|  |  | 
|  | bool created = false; | 
|  | context.reset(NewContext(NULL)); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), source_url, &created)); | 
|  | ASSERT_TRUE(created); | 
|  | context.reset(NewContext(NULL)); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate(context.get(), source_url, kSourceLength)); | 
|  |  | 
|  | if (test_case.cause_overwrite) { | 
|  | context.reset(NewContext(NULL)); | 
|  | created = false; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), dest_url, &created)); | 
|  | ASSERT_TRUE(created); | 
|  | context.reset(NewContext(NULL)); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate(context.get(), dest_url, kDestLength)); | 
|  | } | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CopyOrMoveFile(context.get(), source_url, dest_url, | 
|  | FileSystemOperation::OPTION_NONE, | 
|  | test_case.is_copy_not_move)); | 
|  |  | 
|  | if (test_case.is_copy_not_move) { | 
|  | base::File::Info file_info; | 
|  | base::FilePath local_path; | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetFileInfo(context.get(), source_url, &file_info, | 
|  | &local_path)); | 
|  | EXPECT_EQ(kSourceLength, file_info.size); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->DeleteFile(context.get(), source_url)); | 
|  | } else { | 
|  | base::File::Info file_info; | 
|  | base::FilePath local_path; | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | ofu()->GetFileInfo(context.get(), source_url, &file_info, | 
|  | &local_path)); | 
|  | } | 
|  | base::File::Info file_info; | 
|  | base::FilePath local_path; | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetFileInfo(context.get(), dest_url, &file_info, | 
|  | &local_path)); | 
|  | EXPECT_EQ(kSourceLength, file_info.size); | 
|  |  | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->DeleteFile(context.get(), dest_url)); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestCopyPathQuotas) { | 
|  | FileSystemURL src_url = CreateURLFromUTF8("src path"); | 
|  | FileSystemURL dest_url = CreateURLFromUTF8("destination path"); | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  | bool created = false; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), src_url, &created)); | 
|  |  | 
|  | bool is_copy = true; | 
|  | // Copy, no overwrite. | 
|  | context->set_allowed_bytes_growth( | 
|  | ObfuscatedFileUtil::ComputeFilePathCost(dest_url.path()) - 1); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE, | 
|  | ofu()->CopyOrMoveFile(context.get(), src_url, dest_url, | 
|  | FileSystemOperation::OPTION_NONE, is_copy)); | 
|  | context.reset(NewContext(NULL)); | 
|  | context->set_allowed_bytes_growth( | 
|  | ObfuscatedFileUtil::ComputeFilePathCost(dest_url.path())); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CopyOrMoveFile(context.get(), src_url, dest_url, | 
|  | FileSystemOperation::OPTION_NONE, is_copy)); | 
|  |  | 
|  | // Copy, with overwrite. | 
|  | context.reset(NewContext(NULL)); | 
|  | context->set_allowed_bytes_growth(0); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CopyOrMoveFile(context.get(), src_url, dest_url, | 
|  | FileSystemOperation::OPTION_NONE, is_copy)); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestMovePathQuotasWithRename) { | 
|  | FileSystemURL src_url = CreateURLFromUTF8("src path"); | 
|  | FileSystemURL dest_url = CreateURLFromUTF8("destination path"); | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  | bool created = false; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), src_url, &created)); | 
|  |  | 
|  | bool is_copy = false; | 
|  | // Move, rename, no overwrite. | 
|  | context.reset(NewContext(NULL)); | 
|  | context->set_allowed_bytes_growth( | 
|  | ObfuscatedFileUtil::ComputeFilePathCost(dest_url.path()) - | 
|  | ObfuscatedFileUtil::ComputeFilePathCost(src_url.path()) - 1); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE, | 
|  | ofu()->CopyOrMoveFile(context.get(), src_url, dest_url, | 
|  | FileSystemOperation::OPTION_NONE, is_copy)); | 
|  | context.reset(NewContext(NULL)); | 
|  | context->set_allowed_bytes_growth( | 
|  | ObfuscatedFileUtil::ComputeFilePathCost(dest_url.path()) - | 
|  | ObfuscatedFileUtil::ComputeFilePathCost(src_url.path())); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CopyOrMoveFile(context.get(), src_url, dest_url, | 
|  | FileSystemOperation::OPTION_NONE, is_copy)); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), src_url, &created)); | 
|  |  | 
|  | // Move, rename, with overwrite. | 
|  | context.reset(NewContext(NULL)); | 
|  | context->set_allowed_bytes_growth(0); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CopyOrMoveFile(context.get(), src_url, dest_url, | 
|  | FileSystemOperation::OPTION_NONE, is_copy)); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestMovePathQuotasWithoutRename) { | 
|  | FileSystemURL src_url = CreateURLFromUTF8("src path"); | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  | bool created = false; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), src_url, &created)); | 
|  |  | 
|  | bool exclusive = true; | 
|  | bool recursive = false; | 
|  | FileSystemURL dir_url = CreateURLFromUTF8("directory path"); | 
|  | context.reset(NewContext(NULL)); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), dir_url, exclusive, | 
|  | recursive)); | 
|  |  | 
|  | FileSystemURL dest_url = FileSystemURLAppend( | 
|  | dir_url, src_url.path().value()); | 
|  |  | 
|  | bool is_copy = false; | 
|  | int64_t allowed_bytes_growth = -1000;  // Over quota, this should still work. | 
|  | // Move, no rename, no overwrite. | 
|  | context.reset(NewContext(NULL)); | 
|  | context->set_allowed_bytes_growth(allowed_bytes_growth); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CopyOrMoveFile(context.get(), src_url, dest_url, | 
|  | FileSystemOperation::OPTION_NONE, is_copy)); | 
|  | EXPECT_EQ(allowed_bytes_growth, context->allowed_bytes_growth()); | 
|  |  | 
|  | // Move, no rename, with overwrite. | 
|  | context.reset(NewContext(NULL)); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), src_url, &created)); | 
|  | context.reset(NewContext(NULL)); | 
|  | context->set_allowed_bytes_growth(allowed_bytes_growth); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CopyOrMoveFile(context.get(), src_url, dest_url, | 
|  | FileSystemOperation::OPTION_NONE, is_copy)); | 
|  | EXPECT_EQ( | 
|  | allowed_bytes_growth + | 
|  | ObfuscatedFileUtil::ComputeFilePathCost(src_url.path()), | 
|  | context->allowed_bytes_growth()); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestCopyInForeignFile) { | 
|  | TestCopyInForeignFileHelper(false /* overwrite */); | 
|  | TestCopyInForeignFileHelper(true /* overwrite */); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestEnumerator) { | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  | FileSystemURL src_url = CreateURLFromUTF8("source dir"); | 
|  | bool exclusive = true; | 
|  | bool recursive = false; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), src_url, exclusive, | 
|  | recursive)); | 
|  |  | 
|  | std::set<base::FilePath::StringType> files; | 
|  | std::set<base::FilePath::StringType> directories; | 
|  | FillTestDirectory(src_url, &files, &directories); | 
|  |  | 
|  | FileSystemURL dest_url = CreateURLFromUTF8("destination dir"); | 
|  |  | 
|  | EXPECT_FALSE(DirectoryExists(dest_url)); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | AsyncFileTestHelper::Copy( | 
|  | file_system_context(), src_url, dest_url)); | 
|  |  | 
|  | ValidateTestDirectory(dest_url, files, directories); | 
|  | EXPECT_TRUE(DirectoryExists(src_url)); | 
|  | EXPECT_TRUE(DirectoryExists(dest_url)); | 
|  | recursive = true; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | AsyncFileTestHelper::Remove( | 
|  | file_system_context(), dest_url, recursive)); | 
|  | EXPECT_FALSE(DirectoryExists(dest_url)); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestOriginEnumerator) { | 
|  | std::unique_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator> enumerator( | 
|  | ofu()->CreateOriginEnumerator()); | 
|  | // The test helper starts out with a single filesystem. | 
|  | EXPECT_TRUE(enumerator.get()); | 
|  | EXPECT_EQ(origin(), enumerator->Next()); | 
|  | ASSERT_TRUE(type() == kFileSystemTypeTemporary); | 
|  | EXPECT_TRUE(HasFileSystemType(enumerator.get(), kFileSystemTypeTemporary)); | 
|  | EXPECT_FALSE(HasFileSystemType(enumerator.get(), kFileSystemTypePersistent)); | 
|  | EXPECT_EQ(GURL(), enumerator->Next()); | 
|  | EXPECT_FALSE(HasFileSystemType(enumerator.get(), kFileSystemTypeTemporary)); | 
|  | EXPECT_FALSE(HasFileSystemType(enumerator.get(), kFileSystemTypePersistent)); | 
|  |  | 
|  | std::set<GURL> origins_expected; | 
|  | origins_expected.insert(origin()); | 
|  |  | 
|  | for (size_t i = 0; i < arraysize(kOriginEnumerationTestRecords); ++i) { | 
|  | SCOPED_TRACE(testing::Message() << | 
|  | "Validating kOriginEnumerationTestRecords " << i); | 
|  | const OriginEnumerationTestRecord& record = | 
|  | kOriginEnumerationTestRecords[i]; | 
|  | GURL origin_url(record.origin_url); | 
|  | origins_expected.insert(origin_url); | 
|  | if (record.has_temporary) { | 
|  | std::unique_ptr<SandboxFileSystemTestHelper> file_system( | 
|  | NewFileSystem(origin_url, kFileSystemTypeTemporary)); | 
|  | std::unique_ptr<FileSystemOperationContext> context( | 
|  | NewContext(file_system.get())); | 
|  | bool created = false; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists( | 
|  | context.get(), | 
|  | file_system->CreateURLFromUTF8("file"), | 
|  | &created)); | 
|  | EXPECT_TRUE(created); | 
|  | } | 
|  | if (record.has_persistent) { | 
|  | std::unique_ptr<SandboxFileSystemTestHelper> file_system( | 
|  | NewFileSystem(origin_url, kFileSystemTypePersistent)); | 
|  | std::unique_ptr<FileSystemOperationContext> context( | 
|  | NewContext(file_system.get())); | 
|  | bool created = false; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists( | 
|  | context.get(), | 
|  | file_system->CreateURLFromUTF8("file"), | 
|  | &created)); | 
|  | EXPECT_TRUE(created); | 
|  | } | 
|  | } | 
|  | enumerator.reset(ofu()->CreateOriginEnumerator()); | 
|  | EXPECT_TRUE(enumerator.get()); | 
|  | std::set<GURL> origins_found; | 
|  | GURL origin_url; | 
|  | while (!(origin_url = enumerator->Next()).is_empty()) { | 
|  | origins_found.insert(origin_url); | 
|  | SCOPED_TRACE(testing::Message() << "Handling " << origin_url.spec()); | 
|  | bool found = false; | 
|  | for (size_t i = 0; !found && i < arraysize(kOriginEnumerationTestRecords); | 
|  | ++i) { | 
|  | const OriginEnumerationTestRecord& record = | 
|  | kOriginEnumerationTestRecords[i]; | 
|  | if (origin_url != record.origin_url) | 
|  | continue; | 
|  | found = true; | 
|  | EXPECT_EQ(record.has_temporary, | 
|  | HasFileSystemType(enumerator.get(), kFileSystemTypeTemporary)); | 
|  | EXPECT_EQ(record.has_persistent, | 
|  | HasFileSystemType(enumerator.get(), kFileSystemTypePersistent)); | 
|  | } | 
|  | // Deal with the default filesystem created by the test helper. | 
|  | if (!found && origin_url == origin()) { | 
|  | ASSERT_TRUE(type() == kFileSystemTypeTemporary); | 
|  | EXPECT_TRUE(HasFileSystemType(enumerator.get(), | 
|  | kFileSystemTypeTemporary)); | 
|  | EXPECT_FALSE(HasFileSystemType(enumerator.get(), | 
|  | kFileSystemTypePersistent)); | 
|  | found = true; | 
|  | } | 
|  | EXPECT_TRUE(found); | 
|  | } | 
|  |  | 
|  | std::set<GURL> diff; | 
|  | std::set_symmetric_difference(origins_expected.begin(), | 
|  | origins_expected.end(), origins_found.begin(), origins_found.end(), | 
|  | inserter(diff, diff.begin())); | 
|  | EXPECT_TRUE(diff.empty()); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestRevokeUsageCache) { | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  |  | 
|  | int64_t expected_quota = 0; | 
|  |  | 
|  | for (size_t i = 0; i < kRegularFileSystemTestCaseSize; ++i) { | 
|  | SCOPED_TRACE(testing::Message() << "Creating kRegularTestCase " << i); | 
|  | const FileSystemTestCaseRecord& test_case = | 
|  | kRegularFileSystemTestCases[i]; | 
|  | base::FilePath file_path(test_case.path); | 
|  | expected_quota += ObfuscatedFileUtil::ComputeFilePathCost(file_path); | 
|  | if (test_case.is_directory) { | 
|  | bool exclusive = true; | 
|  | bool recursive = false; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), CreateURL(file_path), | 
|  | exclusive, recursive)); | 
|  | } else { | 
|  | bool created = false; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), CreateURL(file_path), | 
|  | &created)); | 
|  | ASSERT_TRUE(created); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate(context.get(), CreateURL(file_path), | 
|  | test_case.data_file_size)); | 
|  | expected_quota += test_case.data_file_size; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Usually raw size in usage cache and the usage returned by QuotaUtil | 
|  | // should be same. | 
|  | EXPECT_EQ(expected_quota, SizeInUsageFile()); | 
|  | EXPECT_EQ(expected_quota, SizeByQuotaUtil()); | 
|  |  | 
|  | RevokeUsageCache(); | 
|  | EXPECT_EQ(-1, SizeInUsageFile()); | 
|  | EXPECT_EQ(expected_quota, SizeByQuotaUtil()); | 
|  |  | 
|  | // This should reconstruct the cache. | 
|  | GetUsageFromQuotaManager(); | 
|  | EXPECT_EQ(expected_quota, SizeInUsageFile()); | 
|  | EXPECT_EQ(expected_quota, SizeByQuotaUtil()); | 
|  | EXPECT_EQ(expected_quota, usage()); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestInconsistency) { | 
|  | const FileSystemURL kPath1 = CreateURLFromUTF8("hoge"); | 
|  | const FileSystemURL kPath2 = CreateURLFromUTF8("fuga"); | 
|  |  | 
|  | std::unique_ptr<FileSystemOperationContext> context; | 
|  | base::File::Info file_info; | 
|  | base::FilePath data_path; | 
|  | bool created = false; | 
|  |  | 
|  | // Create a non-empty file. | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), kPath1, &created)); | 
|  | EXPECT_TRUE(created); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate(context.get(), kPath1, 10)); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetFileInfo( | 
|  | context.get(), kPath1, &file_info, &data_path)); | 
|  | EXPECT_EQ(10, file_info.size); | 
|  |  | 
|  | // Destroy database to make inconsistency between database and filesystem. | 
|  | ofu()->DestroyDirectoryDatabase(origin(), type_string()); | 
|  |  | 
|  | // Try to get file info of broken file. | 
|  | EXPECT_FALSE(PathExists(kPath1)); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), kPath1, &created)); | 
|  | EXPECT_TRUE(created); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetFileInfo( | 
|  | context.get(), kPath1, &file_info, &data_path)); | 
|  | EXPECT_EQ(0, file_info.size); | 
|  |  | 
|  | // Make another broken file to |kPath2|. | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), kPath2, &created)); | 
|  | EXPECT_TRUE(created); | 
|  |  | 
|  | // Destroy again. | 
|  | ofu()->DestroyDirectoryDatabase(origin(), type_string()); | 
|  |  | 
|  | // Repair broken |kPath1|. | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | ofu()->Touch(context.get(), kPath1, base::Time::Now(), | 
|  | base::Time::Now())); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), kPath1, &created)); | 
|  | EXPECT_TRUE(created); | 
|  |  | 
|  | // Copy from sound |kPath1| to broken |kPath2|. | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CopyOrMoveFile(context.get(), kPath1, kPath2, | 
|  | FileSystemOperation::OPTION_NONE, | 
|  | true /* copy */)); | 
|  |  | 
|  | ofu()->DestroyDirectoryDatabase(origin(), type_string()); | 
|  | context.reset(NewContext(NULL)); | 
|  | base::File file = | 
|  | ofu()->CreateOrOpen(context.get(), kPath1, | 
|  | base::File::FLAG_READ | base::File::FLAG_CREATE); | 
|  | EXPECT_TRUE(file.IsValid()); | 
|  | EXPECT_TRUE(file.created()); | 
|  |  | 
|  | EXPECT_TRUE(file.GetInfo(&file_info)); | 
|  | EXPECT_EQ(0, file_info.size); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestIncompleteDirectoryReading) { | 
|  | const FileSystemURL kPath[] = { | 
|  | CreateURLFromUTF8("foo"), | 
|  | CreateURLFromUTF8("bar"), | 
|  | CreateURLFromUTF8("baz") | 
|  | }; | 
|  | const FileSystemURL empty_path = CreateURL(base::FilePath()); | 
|  | std::unique_ptr<FileSystemOperationContext> context; | 
|  |  | 
|  | for (size_t i = 0; i < arraysize(kPath); ++i) { | 
|  | bool created = false; | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), kPath[i], &created)); | 
|  | EXPECT_TRUE(created); | 
|  | } | 
|  |  | 
|  | std::vector<storage::DirectoryEntry> entries; | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | AsyncFileTestHelper::ReadDirectory( | 
|  | file_system_context(), empty_path, &entries)); | 
|  | EXPECT_EQ(3u, entries.size()); | 
|  |  | 
|  | base::FilePath local_path; | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetLocalFilePath(context.get(), kPath[0], &local_path)); | 
|  | EXPECT_TRUE(base::DeleteFile(local_path, false)); | 
|  |  | 
|  | entries.clear(); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | AsyncFileTestHelper::ReadDirectory( | 
|  | file_system_context(), empty_path, &entries)); | 
|  | EXPECT_EQ(arraysize(kPath) - 1, entries.size()); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestDirectoryTimestampForCreation) { | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  | const FileSystemURL dir_url = CreateURLFromUTF8("foo_dir"); | 
|  |  | 
|  | // Create working directory. | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), dir_url, false, false)); | 
|  |  | 
|  | // EnsureFileExists, create case. | 
|  | FileSystemURL url(FileSystemURLAppendUTF8(dir_url, "EnsureFileExists_file")); | 
|  | bool created = false; | 
|  | ClearTimestamp(dir_url); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), url, &created)); | 
|  | EXPECT_TRUE(created); | 
|  | EXPECT_NE(base::Time(), GetModifiedTime(dir_url)); | 
|  |  | 
|  | // non create case. | 
|  | created = true; | 
|  | ClearTimestamp(dir_url); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), url, &created)); | 
|  | EXPECT_FALSE(created); | 
|  | EXPECT_EQ(base::Time(), GetModifiedTime(dir_url)); | 
|  |  | 
|  | // fail case. | 
|  | url = FileSystemURLAppendUTF8(dir_url, "EnsureFileExists_dir"); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), url, false, false)); | 
|  |  | 
|  | ClearTimestamp(dir_url); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_A_FILE, | 
|  | ofu()->EnsureFileExists(context.get(), url, &created)); | 
|  | EXPECT_EQ(base::Time(), GetModifiedTime(dir_url)); | 
|  |  | 
|  | // CreateOrOpen, create case. | 
|  | url = FileSystemURLAppendUTF8(dir_url, "CreateOrOpen_file"); | 
|  | ClearTimestamp(dir_url); | 
|  | context.reset(NewContext(NULL)); | 
|  | base::File file = | 
|  | ofu()->CreateOrOpen(context.get(), url, | 
|  | base::File::FLAG_CREATE | base::File::FLAG_WRITE); | 
|  |  | 
|  | EXPECT_TRUE(file.IsValid()); | 
|  | EXPECT_TRUE(file.created()); | 
|  | file.Close(); | 
|  | EXPECT_NE(base::Time(), GetModifiedTime(dir_url)); | 
|  |  | 
|  | // open case. | 
|  | ClearTimestamp(dir_url); | 
|  | context.reset(NewContext(NULL)); | 
|  | file = ofu()->CreateOrOpen(context.get(), url, | 
|  | base::File::FLAG_OPEN | base::File::FLAG_WRITE); | 
|  | EXPECT_TRUE(file.IsValid()); | 
|  | EXPECT_FALSE(file.created()); | 
|  | file.Close(); | 
|  | EXPECT_EQ(base::Time(), GetModifiedTime(dir_url)); | 
|  |  | 
|  | // fail case | 
|  | ClearTimestamp(dir_url); | 
|  | context.reset(NewContext(NULL)); | 
|  | file = ofu()->CreateOrOpen(context.get(), url, | 
|  | base::File::FLAG_CREATE | base::File::FLAG_WRITE); | 
|  | EXPECT_FALSE(file.IsValid()); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_EXISTS, file.error_details()); | 
|  | EXPECT_EQ(base::Time(), GetModifiedTime(dir_url)); | 
|  |  | 
|  | // CreateDirectory, create case. | 
|  | // Creating CreateDirectory_dir and CreateDirectory_dir/subdir. | 
|  | url = FileSystemURLAppendUTF8(dir_url, "CreateDirectory_dir"); | 
|  | FileSystemURL subdir_url(FileSystemURLAppendUTF8(url, "subdir")); | 
|  | ClearTimestamp(dir_url); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), subdir_url, | 
|  | true /* exclusive */, true /* recursive */)); | 
|  | EXPECT_NE(base::Time(), GetModifiedTime(dir_url)); | 
|  |  | 
|  | // create subdir case. | 
|  | // Creating CreateDirectory_dir/subdir2. | 
|  | subdir_url = FileSystemURLAppendUTF8(url, "subdir2"); | 
|  | ClearTimestamp(dir_url); | 
|  | ClearTimestamp(url); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), subdir_url, | 
|  | true /* exclusive */, true /* recursive */)); | 
|  | EXPECT_EQ(base::Time(), GetModifiedTime(dir_url)); | 
|  | EXPECT_NE(base::Time(), GetModifiedTime(url)); | 
|  |  | 
|  | // fail case. | 
|  | url = FileSystemURLAppendUTF8(dir_url, "CreateDirectory_dir"); | 
|  | ClearTimestamp(dir_url); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_EXISTS, | 
|  | ofu()->CreateDirectory(context.get(), url, | 
|  | true /* exclusive */, true /* recursive */)); | 
|  | EXPECT_EQ(base::Time(), GetModifiedTime(dir_url)); | 
|  |  | 
|  | // CopyInForeignFile, create case. | 
|  | url = FileSystemURLAppendUTF8(dir_url, "CopyInForeignFile_file"); | 
|  | FileSystemURL src_path = FileSystemURLAppendUTF8( | 
|  | dir_url, "CopyInForeignFile_src_file"); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), src_path, &created)); | 
|  | EXPECT_TRUE(created); | 
|  | base::FilePath src_local_path; | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetLocalFilePath(context.get(), src_path, &src_local_path)); | 
|  |  | 
|  | ClearTimestamp(dir_url); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CopyInForeignFile(context.get(), | 
|  | src_local_path, | 
|  | url)); | 
|  | EXPECT_NE(base::Time(), GetModifiedTime(dir_url)); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestDirectoryTimestampForDeletion) { | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  | const FileSystemURL dir_url = CreateURLFromUTF8("foo_dir"); | 
|  |  | 
|  | // Create working directory. | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), dir_url, false, false)); | 
|  |  | 
|  | // DeleteFile, delete case. | 
|  | FileSystemURL url = FileSystemURLAppendUTF8( | 
|  | dir_url, "DeleteFile_file"); | 
|  | bool created = false; | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), url, &created)); | 
|  | EXPECT_TRUE(created); | 
|  |  | 
|  | ClearTimestamp(dir_url); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->DeleteFile(context.get(), url)); | 
|  | EXPECT_NE(base::Time(), GetModifiedTime(dir_url)); | 
|  |  | 
|  | // fail case. | 
|  | ClearTimestamp(dir_url); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, | 
|  | ofu()->DeleteFile(context.get(), url)); | 
|  | EXPECT_EQ(base::Time(), GetModifiedTime(dir_url)); | 
|  |  | 
|  | // DeleteDirectory, fail case. | 
|  | url = FileSystemURLAppendUTF8(dir_url, "DeleteDirectory_dir"); | 
|  | FileSystemURL file_path(FileSystemURLAppendUTF8(url, "pakeratta")); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), url, true, true)); | 
|  | created = false; | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), file_path, &created)); | 
|  | EXPECT_TRUE(created); | 
|  |  | 
|  | ClearTimestamp(dir_url); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_ERROR_NOT_EMPTY, | 
|  | ofu()->DeleteDirectory(context.get(), url)); | 
|  | EXPECT_EQ(base::Time(), GetModifiedTime(dir_url)); | 
|  |  | 
|  | // delete case. | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->DeleteFile(context.get(), file_path)); | 
|  |  | 
|  | ClearTimestamp(dir_url); | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, ofu()->DeleteDirectory(context.get(), url)); | 
|  | EXPECT_NE(base::Time(), GetModifiedTime(dir_url)); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestDirectoryTimestampForCopyAndMove) { | 
|  | TestDirectoryTimestampHelper( | 
|  | CreateURLFromUTF8("copy overwrite"), true, true); | 
|  | TestDirectoryTimestampHelper( | 
|  | CreateURLFromUTF8("copy non-overwrite"), true, false); | 
|  | TestDirectoryTimestampHelper( | 
|  | CreateURLFromUTF8("move overwrite"), false, true); | 
|  | TestDirectoryTimestampHelper( | 
|  | CreateURLFromUTF8("move non-overwrite"), false, false); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestFileEnumeratorTimestamp) { | 
|  | FileSystemURL dir = CreateURLFromUTF8("foo"); | 
|  | FileSystemURL url1 = FileSystemURLAppendUTF8(dir, "bar"); | 
|  | FileSystemURL url2 = FileSystemURLAppendUTF8(dir, "baz"); | 
|  |  | 
|  | std::unique_ptr<FileSystemOperationContext> context(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), dir, false, false)); | 
|  |  | 
|  | bool created = false; | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(context.get(), url1, &created)); | 
|  | EXPECT_TRUE(created); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory(context.get(), url2, false, false)); | 
|  |  | 
|  | base::FilePath file_path; | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetLocalFilePath(context.get(), url1, &file_path)); | 
|  | EXPECT_FALSE(file_path.empty()); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->Touch(context.get(), url1, | 
|  | base::Time::Now() + base::TimeDelta::FromHours(1), | 
|  | base::Time())); | 
|  |  | 
|  | context.reset(NewContext(NULL)); | 
|  | std::unique_ptr<storage::FileSystemFileUtil::AbstractFileEnumerator> | 
|  | file_enum(ofu()->CreateFileEnumerator(context.get(), dir, false)); | 
|  |  | 
|  | int count = 0; | 
|  | base::FilePath file_path_each; | 
|  | while (!(file_path_each = file_enum->Next()).empty()) { | 
|  | context.reset(NewContext(NULL)); | 
|  | base::File::Info file_info; | 
|  | base::FilePath file_path; | 
|  | EXPECT_EQ(base::File::FILE_OK, | 
|  | ofu()->GetFileInfo(context.get(), | 
|  | FileSystemURL::CreateForTest( | 
|  | dir.origin(), | 
|  | dir.mount_type(), | 
|  | file_path_each), | 
|  | &file_info, &file_path)); | 
|  | EXPECT_EQ(file_info.is_directory, file_enum->IsDirectory()); | 
|  | EXPECT_EQ(file_info.last_modified, file_enum->LastModifiedTime()); | 
|  | EXPECT_EQ(file_info.size, file_enum->Size()); | 
|  | ++count; | 
|  | } | 
|  | EXPECT_EQ(2, count); | 
|  | } | 
|  |  | 
|  | // crbug.com/176470 | 
|  | #if defined(OS_WIN) || defined(OS_ANDROID) | 
|  | #define MAYBE_TestQuotaOnCopyFile DISABLED_TestQuotaOnCopyFile | 
|  | #else | 
|  | #define MAYBE_TestQuotaOnCopyFile TestQuotaOnCopyFile | 
|  | #endif | 
|  | TEST_F(ObfuscatedFileUtilTest, MAYBE_TestQuotaOnCopyFile) { | 
|  | FileSystemURL from_file(CreateURLFromUTF8("fromfile")); | 
|  | FileSystemURL obstacle_file(CreateURLFromUTF8("obstaclefile")); | 
|  | FileSystemURL to_file1(CreateURLFromUTF8("tofile1")); | 
|  | FileSystemURL to_file2(CreateURLFromUTF8("tofile2")); | 
|  | bool created; | 
|  |  | 
|  | int64_t expected_total_file_size = 0; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists( | 
|  | AllowUsageIncrease(PathCost(from_file))->context(), | 
|  | from_file, &created)); | 
|  | ASSERT_TRUE(created); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists( | 
|  | AllowUsageIncrease(PathCost(obstacle_file))->context(), | 
|  | obstacle_file, &created)); | 
|  | ASSERT_TRUE(created); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | int64_t from_file_size = 1020; | 
|  | expected_total_file_size += from_file_size; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate( | 
|  | AllowUsageIncrease(from_file_size)->context(), | 
|  | from_file, from_file_size)); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | int64_t obstacle_file_size = 1; | 
|  | expected_total_file_size += obstacle_file_size; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate( | 
|  | AllowUsageIncrease(obstacle_file_size)->context(), | 
|  | obstacle_file, obstacle_file_size)); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | int64_t to_file1_size = from_file_size; | 
|  | expected_total_file_size += to_file1_size; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->CopyOrMoveFile( | 
|  | AllowUsageIncrease( | 
|  | PathCost(to_file1) + to_file1_size)->context(), | 
|  | from_file, to_file1, | 
|  | FileSystemOperation::OPTION_NONE, | 
|  | true /* copy */)); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_ERROR_NO_SPACE, | 
|  | ofu()->CopyOrMoveFile( | 
|  | DisallowUsageIncrease( | 
|  | PathCost(to_file2) + from_file_size)->context(), | 
|  | from_file, to_file2, FileSystemOperation::OPTION_NONE, | 
|  | true /* copy */)); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | int64_t old_obstacle_file_size = obstacle_file_size; | 
|  | obstacle_file_size = from_file_size; | 
|  | expected_total_file_size += obstacle_file_size - old_obstacle_file_size; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->CopyOrMoveFile( | 
|  | AllowUsageIncrease( | 
|  | obstacle_file_size - old_obstacle_file_size)->context(), | 
|  | from_file, obstacle_file, | 
|  | FileSystemOperation::OPTION_NONE, | 
|  | true /* copy */)); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | int64_t old_from_file_size = from_file_size; | 
|  | from_file_size = old_from_file_size - 1; | 
|  | expected_total_file_size += from_file_size - old_from_file_size; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate( | 
|  | AllowUsageIncrease( | 
|  | from_file_size - old_from_file_size)->context(), | 
|  | from_file, from_file_size)); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | // quota exceeded | 
|  | { | 
|  | old_obstacle_file_size = obstacle_file_size; | 
|  | obstacle_file_size = from_file_size; | 
|  | expected_total_file_size += obstacle_file_size - old_obstacle_file_size; | 
|  | std::unique_ptr<UsageVerifyHelper> helper = | 
|  | AllowUsageIncrease(obstacle_file_size - old_obstacle_file_size); | 
|  | helper->context()->set_allowed_bytes_growth( | 
|  | helper->context()->allowed_bytes_growth() - 1); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->CopyOrMoveFile( | 
|  | helper->context(), | 
|  | from_file, obstacle_file, | 
|  | FileSystemOperation::OPTION_NONE, | 
|  | true /* copy */)); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestQuotaOnMoveFile) { | 
|  | FileSystemURL from_file(CreateURLFromUTF8("fromfile")); | 
|  | FileSystemURL obstacle_file(CreateURLFromUTF8("obstaclefile")); | 
|  | FileSystemURL to_file(CreateURLFromUTF8("tofile")); | 
|  | bool created; | 
|  |  | 
|  | int64_t expected_total_file_size = 0; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists( | 
|  | AllowUsageIncrease(PathCost(from_file))->context(), | 
|  | from_file, &created)); | 
|  | ASSERT_TRUE(created); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | int64_t from_file_size = 1020; | 
|  | expected_total_file_size += from_file_size; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate( | 
|  | AllowUsageIncrease(from_file_size)->context(), | 
|  | from_file, from_file_size)); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | from_file_size = 0; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->CopyOrMoveFile( | 
|  | AllowUsageIncrease(-PathCost(from_file) + | 
|  | PathCost(to_file))->context(), | 
|  | from_file, to_file, | 
|  | FileSystemOperation::OPTION_NONE, | 
|  | false /* move */)); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists( | 
|  | AllowUsageIncrease(PathCost(from_file))->context(), | 
|  | from_file, &created)); | 
|  | ASSERT_TRUE(created); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists( | 
|  | AllowUsageIncrease(PathCost(obstacle_file))->context(), | 
|  | obstacle_file, &created)); | 
|  | ASSERT_TRUE(created); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | from_file_size = 1020; | 
|  | expected_total_file_size += from_file_size; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate( | 
|  | AllowUsageIncrease(from_file_size)->context(), | 
|  | from_file, from_file_size)); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | int64_t obstacle_file_size = 1; | 
|  | expected_total_file_size += obstacle_file_size; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate( | 
|  | AllowUsageIncrease(1)->context(), | 
|  | obstacle_file, obstacle_file_size)); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | int64_t old_obstacle_file_size = obstacle_file_size; | 
|  | obstacle_file_size = from_file_size; | 
|  | from_file_size = 0; | 
|  | expected_total_file_size -= old_obstacle_file_size; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->CopyOrMoveFile( | 
|  | AllowUsageIncrease( | 
|  | -old_obstacle_file_size - PathCost(from_file))->context(), | 
|  | from_file, obstacle_file, | 
|  | FileSystemOperation::OPTION_NONE, | 
|  | false /* move */)); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists( | 
|  | AllowUsageIncrease(PathCost(from_file))->context(), | 
|  | from_file, &created)); | 
|  | ASSERT_TRUE(created); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | from_file_size = 10; | 
|  | expected_total_file_size += from_file_size; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate( | 
|  | AllowUsageIncrease(from_file_size)->context(), | 
|  | from_file, from_file_size)); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  |  | 
|  | // quota exceeded even after operation | 
|  | old_obstacle_file_size = obstacle_file_size; | 
|  | obstacle_file_size = from_file_size; | 
|  | from_file_size = 0; | 
|  | expected_total_file_size -= old_obstacle_file_size; | 
|  | std::unique_ptr<FileSystemOperationContext> context = | 
|  | LimitedContext(-old_obstacle_file_size - PathCost(from_file) - 1); | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->CopyOrMoveFile( | 
|  | context.get(), from_file, obstacle_file, | 
|  | FileSystemOperation::OPTION_NONE, | 
|  | false /* move */)); | 
|  | ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize()); | 
|  | context.reset(); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestQuotaOnRemove) { | 
|  | FileSystemURL dir(CreateURLFromUTF8("dir")); | 
|  | FileSystemURL file(CreateURLFromUTF8("file")); | 
|  | FileSystemURL dfile1(CreateURLFromUTF8("dir/dfile1")); | 
|  | FileSystemURL dfile2(CreateURLFromUTF8("dir/dfile2")); | 
|  | bool created; | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists( | 
|  | AllowUsageIncrease(PathCost(file))->context(), | 
|  | file, &created)); | 
|  | ASSERT_TRUE(created); | 
|  | ASSERT_EQ(0, ComputeTotalFileSize()); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->CreateDirectory( | 
|  | AllowUsageIncrease(PathCost(dir))->context(), | 
|  | dir, false, false)); | 
|  | ASSERT_EQ(0, ComputeTotalFileSize()); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists( | 
|  | AllowUsageIncrease(PathCost(dfile1))->context(), | 
|  | dfile1, &created)); | 
|  | ASSERT_TRUE(created); | 
|  | ASSERT_EQ(0, ComputeTotalFileSize()); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists( | 
|  | AllowUsageIncrease(PathCost(dfile2))->context(), | 
|  | dfile2, &created)); | 
|  | ASSERT_TRUE(created); | 
|  | ASSERT_EQ(0, ComputeTotalFileSize()); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate( | 
|  | AllowUsageIncrease(340)->context(), | 
|  | file, 340)); | 
|  | ASSERT_EQ(340, ComputeTotalFileSize()); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate( | 
|  | AllowUsageIncrease(1020)->context(), | 
|  | dfile1, 1020)); | 
|  | ASSERT_EQ(1360, ComputeTotalFileSize()); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate( | 
|  | AllowUsageIncrease(120)->context(), | 
|  | dfile2, 120)); | 
|  | ASSERT_EQ(1480, ComputeTotalFileSize()); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->DeleteFile( | 
|  | AllowUsageIncrease(-PathCost(file) - 340)->context(), | 
|  | file)); | 
|  | ASSERT_EQ(1140, ComputeTotalFileSize()); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | AsyncFileTestHelper::Remove( | 
|  | file_system_context(), dir, true /* recursive */)); | 
|  | ASSERT_EQ(0, ComputeTotalFileSize()); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, TestQuotaOnOpen) { | 
|  | FileSystemURL url(CreateURLFromUTF8("file")); | 
|  |  | 
|  | bool created; | 
|  | // Creating a file. | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists( | 
|  | AllowUsageIncrease(PathCost(url))->context(), | 
|  | url, &created)); | 
|  | ASSERT_TRUE(created); | 
|  | ASSERT_EQ(0, ComputeTotalFileSize()); | 
|  |  | 
|  | // Opening it, which shouldn't change the usage. | 
|  | base::File file = | 
|  | ofu()->CreateOrOpen(AllowUsageIncrease(0)->context(), url, | 
|  | base::File::FLAG_OPEN | base::File::FLAG_WRITE); | 
|  | ASSERT_TRUE(file.IsValid()); | 
|  | ASSERT_EQ(0, ComputeTotalFileSize()); | 
|  | file.Close(); | 
|  |  | 
|  | const int length = 33; | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate( | 
|  | AllowUsageIncrease(length)->context(), url, length)); | 
|  | ASSERT_EQ(length, ComputeTotalFileSize()); | 
|  |  | 
|  | // Opening it with CREATE_ALWAYS flag, which should truncate the file size. | 
|  | file = ofu()->CreateOrOpen( | 
|  | AllowUsageIncrease(-length)->context(), url, | 
|  | base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); | 
|  | ASSERT_TRUE(file.IsValid()); | 
|  | ASSERT_EQ(0, ComputeTotalFileSize()); | 
|  | file.Close(); | 
|  |  | 
|  | // Extending the file again. | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->Truncate( | 
|  | AllowUsageIncrease(length)->context(), url, length)); | 
|  | ASSERT_EQ(length, ComputeTotalFileSize()); | 
|  |  | 
|  | // Opening it with TRUNCATED flag, which should truncate the file size. | 
|  | file = ofu()->CreateOrOpen( | 
|  | AllowUsageIncrease(-length)->context(), url, | 
|  | base::File::FLAG_OPEN_TRUNCATED | base::File::FLAG_WRITE); | 
|  | ASSERT_TRUE(file.IsValid()); | 
|  | ASSERT_EQ(0, ComputeTotalFileSize()); | 
|  | file.Close(); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, MaybeDropDatabasesAliveCase) { | 
|  | MaybeDropDatabasesAliveCaseTestBody(); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, MaybeDropDatabasesAlreadyDeletedCase) { | 
|  | MaybeDropDatabasesAlreadyDeletedCaseTestBody(); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, DestroyDirectoryDatabase_Isolated) { | 
|  | DestroyDirectoryDatabase_IsolatedTestBody(); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, GetDirectoryDatabase_Isolated) { | 
|  | GetDirectoryDatabase_IsolatedTestBody(); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, MigrationBackFromIsolated) { | 
|  | MigrationBackFromIsolatedTestBody(); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, OpenPathInNonDirectory) { | 
|  | FileSystemURL url(CreateURLFromUTF8("file")); | 
|  | FileSystemURL path_in_file(CreateURLFromUTF8("file/file")); | 
|  | bool created; | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(UnlimitedContext().get(), url, &created)); | 
|  | ASSERT_TRUE(created); | 
|  |  | 
|  | int file_flags = base::File::FLAG_CREATE | base::File::FLAG_WRITE; | 
|  | base::File file = | 
|  | ofu()->CreateOrOpen(UnlimitedContext().get(), path_in_file, file_flags); | 
|  | ASSERT_FALSE(file.IsValid()); | 
|  | ASSERT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY, file.error_details()); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY, | 
|  | ofu()->CreateDirectory(UnlimitedContext().get(), | 
|  | path_in_file, | 
|  | false /* exclusive */, | 
|  | false /* recursive */)); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, CreateDirectory_NotADirectoryInRecursive) { | 
|  | FileSystemURL file(CreateURLFromUTF8("file")); | 
|  | FileSystemURL path_in_file(CreateURLFromUTF8("file/child")); | 
|  | FileSystemURL path_in_file_in_file( | 
|  | CreateURLFromUTF8("file/child/grandchild")); | 
|  | bool created; | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_OK, | 
|  | ofu()->EnsureFileExists(UnlimitedContext().get(), file, &created)); | 
|  | ASSERT_TRUE(created); | 
|  |  | 
|  | ASSERT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY, | 
|  | ofu()->CreateDirectory(UnlimitedContext().get(), | 
|  | path_in_file, | 
|  | false /* exclusive */, | 
|  | true /* recursive */)); | 
|  | ASSERT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY, | 
|  | ofu()->CreateDirectory(UnlimitedContext().get(), | 
|  | path_in_file_in_file, | 
|  | false /* exclusive */, | 
|  | true /* recursive */)); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType) { | 
|  | const GURL origin1("http://www.example.com:12"); | 
|  | const GURL origin2("http://www.example.com:1234"); | 
|  |  | 
|  | // Create origin directories. | 
|  | std::unique_ptr<SandboxFileSystemTestHelper> fs1( | 
|  | NewFileSystem(origin1, kFileSystemTypeTemporary)); | 
|  | std::unique_ptr<SandboxFileSystemTestHelper> fs2( | 
|  | NewFileSystem(origin1, kFileSystemTypePersistent)); | 
|  | std::unique_ptr<SandboxFileSystemTestHelper> fs3( | 
|  | NewFileSystem(origin2, kFileSystemTypeTemporary)); | 
|  | std::unique_ptr<SandboxFileSystemTestHelper> fs4( | 
|  | NewFileSystem(origin2, kFileSystemTypePersistent)); | 
|  |  | 
|  | // Make sure directories for origin1 exist. | 
|  | base::File::Error error = base::File::FILE_ERROR_FAILED; | 
|  | ofu()->GetDirectoryForOriginAndType( | 
|  | origin1, GetTypeString(kFileSystemTypeTemporary), false, &error); | 
|  | ASSERT_EQ(base::File::FILE_OK, error); | 
|  | error = base::File::FILE_ERROR_FAILED; | 
|  | ofu()->GetDirectoryForOriginAndType( | 
|  | origin1, GetTypeString(kFileSystemTypePersistent), false, &error); | 
|  | ASSERT_EQ(base::File::FILE_OK, error); | 
|  |  | 
|  | // Make sure directories for origin2 exist. | 
|  | error = base::File::FILE_ERROR_FAILED; | 
|  | ofu()->GetDirectoryForOriginAndType( | 
|  | origin2, GetTypeString(kFileSystemTypeTemporary), false, &error); | 
|  | ASSERT_EQ(base::File::FILE_OK, error); | 
|  | error = base::File::FILE_ERROR_FAILED; | 
|  | ofu()->GetDirectoryForOriginAndType( | 
|  | origin2, GetTypeString(kFileSystemTypePersistent), false, &error); | 
|  | ASSERT_EQ(base::File::FILE_OK, error); | 
|  |  | 
|  | // Delete a directory for origin1's persistent filesystem. | 
|  | ofu()->DeleteDirectoryForOriginAndType( | 
|  | origin1, GetTypeString(kFileSystemTypePersistent)); | 
|  |  | 
|  | // The directory for origin1's temporary filesystem should not be removed. | 
|  | error = base::File::FILE_ERROR_FAILED; | 
|  | ofu()->GetDirectoryForOriginAndType( | 
|  | origin1, GetTypeString(kFileSystemTypeTemporary), false, &error); | 
|  | ASSERT_EQ(base::File::FILE_OK, error); | 
|  |  | 
|  | // The directory for origin1's persistent filesystem should be removed. | 
|  | error = base::File::FILE_ERROR_FAILED; | 
|  | ofu()->GetDirectoryForOriginAndType( | 
|  | origin1, GetTypeString(kFileSystemTypePersistent), false, &error); | 
|  | ASSERT_EQ(base::File::FILE_ERROR_NOT_FOUND, error); | 
|  |  | 
|  | // The directories for origin2 should not be removed. | 
|  | error = base::File::FILE_ERROR_FAILED; | 
|  | ofu()->GetDirectoryForOriginAndType( | 
|  | origin2, GetTypeString(kFileSystemTypeTemporary), false, &error); | 
|  | ASSERT_EQ(base::File::FILE_OK, error); | 
|  | error = base::File::FILE_ERROR_FAILED; | 
|  | ofu()->GetDirectoryForOriginAndType( | 
|  | origin2, GetTypeString(kFileSystemTypePersistent), false, &error); | 
|  | ASSERT_EQ(base::File::FILE_OK, error); | 
|  | } | 
|  |  | 
|  | TEST_F(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType_DeleteAll) { | 
|  | const GURL origin1("http://www.example.com:12"); | 
|  | const GURL origin2("http://www.example.com:1234"); | 
|  |  | 
|  | // Create origin directories. | 
|  | std::unique_ptr<SandboxFileSystemTestHelper> fs1( | 
|  | NewFileSystem(origin1, kFileSystemTypeTemporary)); | 
|  | std::unique_ptr<SandboxFileSystemTestHelper> fs2( | 
|  | NewFileSystem(origin1, kFileSystemTypePersistent)); | 
|  | std::unique_ptr<SandboxFileSystemTestHelper> fs3( | 
|  | NewFileSystem(origin2, kFileSystemTypeTemporary)); | 
|  | std::unique_ptr<SandboxFileSystemTestHelper> fs4( | 
|  | NewFileSystem(origin2, kFileSystemTypePersistent)); | 
|  |  | 
|  | // Make sure directories for origin1 exist. | 
|  | base::File::Error error = base::File::FILE_ERROR_FAILED; | 
|  | ofu()->GetDirectoryForOriginAndType( | 
|  | origin1, GetTypeString(kFileSystemTypeTemporary), false, &error); | 
|  | ASSERT_EQ(base::File::FILE_OK, error); | 
|  | error = base::File::FILE_ERROR_FAILED; | 
|  | ofu()->GetDirectoryForOriginAndType( | 
|  | origin1, GetTypeString(kFileSystemTypePersistent), false, &error); | 
|  | ASSERT_EQ(base::File::FILE_OK, error); | 
|  |  | 
|  | // Make sure directories for origin2 exist. | 
|  | error = base::File::FILE_ERROR_FAILED; | 
|  | ofu()->GetDirectoryForOriginAndType( | 
|  | origin2, GetTypeString(kFileSystemTypeTemporary), false, &error); | 
|  | ASSERT_EQ(base::File::FILE_OK, error); | 
|  | error = base::File::FILE_ERROR_FAILED; | 
|  | ofu()->GetDirectoryForOriginAndType( | 
|  | origin2, GetTypeString(kFileSystemTypePersistent), false, &error); | 
|  | ASSERT_EQ(base::File::FILE_OK, error); | 
|  |  | 
|  | // Delete all directories for origin1. | 
|  | ofu()->DeleteDirectoryForOriginAndType(origin1, std::string()); | 
|  |  | 
|  | // The directories for origin1 should be removed. | 
|  | error = base::File::FILE_ERROR_FAILED; | 
|  | ofu()->GetDirectoryForOriginAndType( | 
|  | origin1, GetTypeString(kFileSystemTypeTemporary), false, &error); | 
|  | ASSERT_EQ(base::File::FILE_ERROR_NOT_FOUND, error); | 
|  | error = base::File::FILE_ERROR_FAILED; | 
|  | ofu()->GetDirectoryForOriginAndType( | 
|  | origin1, GetTypeString(kFileSystemTypePersistent), false, &error); | 
|  | ASSERT_EQ(base::File::FILE_ERROR_NOT_FOUND, error); | 
|  |  | 
|  | // The directories for origin2 should not be removed. | 
|  | error = base::File::FILE_ERROR_FAILED; | 
|  | ofu()->GetDirectoryForOriginAndType( | 
|  | origin2, GetTypeString(kFileSystemTypeTemporary), false, &error); | 
|  | ASSERT_EQ(base::File::FILE_OK, error); | 
|  | error = base::File::FILE_ERROR_FAILED; | 
|  | ofu()->GetDirectoryForOriginAndType( | 
|  | origin2, GetTypeString(kFileSystemTypePersistent), false, &error); | 
|  | ASSERT_EQ(base::File::FILE_OK, error); | 
|  | } | 
|  |  | 
|  | }  // namespace content |