// 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 "chrome/browser/chromeos/fileapi/file_system_backend.h" #include <set> #include "base/files/file_path.h" #include "base/path_service.h" #include "chromeos/dbus/cros_disks_client.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/url_util.h" #include "webkit/browser/fileapi/external_mount_points.h" #include "webkit/browser/fileapi/file_system_url.h" #include "webkit/browser/quota/mock_special_storage_policy.h" #define FPL(x) FILE_PATH_LITERAL(x) using fileapi::ExternalMountPoints; using fileapi::FileSystemURL; namespace { FileSystemURL CreateFileSystemURL(const std::string& extension, const char* path, ExternalMountPoints* mount_points) { return mount_points->CreateCrackedFileSystemURL( GURL("chrome-extension://" + extension + "/"), fileapi::kFileSystemTypeExternal, base::FilePath::FromUTF8Unsafe(path)); } TEST(ChromeOSFileSystemBackendTest, DefaultMountPoints) { // Make sure no system-level mount points are registered before testing // to avoid flakiness. fileapi::ExternalMountPoints::GetSystemInstance()->RevokeAllFileSystems(); scoped_refptr<quota::SpecialStoragePolicy> storage_policy = new quota::MockSpecialStoragePolicy(); scoped_refptr<fileapi::ExternalMountPoints> mount_points( fileapi::ExternalMountPoints::CreateRefCounted()); chromeos::FileSystemBackend backend( NULL, // drive_delegate storage_policy, mount_points.get(), fileapi::ExternalMountPoints::GetSystemInstance()); backend.AddSystemMountPoints(); std::vector<base::FilePath> root_dirs = backend.GetRootDirectories(); std::set<base::FilePath> root_dirs_set(root_dirs.begin(), root_dirs.end()); // By default there should be 3 mount points (in system mount points): EXPECT_EQ(3u, root_dirs.size()); EXPECT_TRUE(root_dirs_set.count( chromeos::CrosDisksClient::GetRemovableDiskMountPoint())); EXPECT_TRUE(root_dirs_set.count( chromeos::CrosDisksClient::GetArchiveMountPoint())); EXPECT_TRUE(root_dirs_set.count(base::FilePath(FPL("/usr/share/oem")))); } TEST(ChromeOSFileSystemBackendTest, GetRootDirectories) { scoped_refptr<quota::SpecialStoragePolicy> storage_policy = new quota::MockSpecialStoragePolicy(); scoped_refptr<fileapi::ExternalMountPoints> mount_points( fileapi::ExternalMountPoints::CreateRefCounted()); scoped_refptr<fileapi::ExternalMountPoints> system_mount_points( fileapi::ExternalMountPoints::CreateRefCounted()); chromeos::FileSystemBackend backend( NULL, // drive_delegate storage_policy, mount_points.get(), system_mount_points.get()); const size_t initial_root_dirs_size = backend.GetRootDirectories().size(); // Register 'local' test mount points. mount_points->RegisterFileSystem("c", fileapi::kFileSystemTypeNativeLocal, fileapi::FileSystemMountOption(), base::FilePath(FPL("/a/b/c"))); mount_points->RegisterFileSystem("d", fileapi::kFileSystemTypeNativeLocal, fileapi::FileSystemMountOption(), base::FilePath(FPL("/b/c/d"))); // Register system test mount points. system_mount_points->RegisterFileSystem("d", fileapi::kFileSystemTypeNativeLocal, fileapi::FileSystemMountOption(), base::FilePath(FPL("/g/c/d"))); system_mount_points->RegisterFileSystem("e", fileapi::kFileSystemTypeNativeLocal, fileapi::FileSystemMountOption(), base::FilePath(FPL("/g/d/e"))); std::vector<base::FilePath> root_dirs = backend.GetRootDirectories(); std::set<base::FilePath> root_dirs_set(root_dirs.begin(), root_dirs.end()); EXPECT_EQ(initial_root_dirs_size + 4, root_dirs.size()); EXPECT_TRUE(root_dirs_set.count(base::FilePath(FPL("/a/b/c")))); EXPECT_TRUE(root_dirs_set.count(base::FilePath(FPL("/b/c/d")))); EXPECT_TRUE(root_dirs_set.count(base::FilePath(FPL("/g/c/d")))); EXPECT_TRUE(root_dirs_set.count(base::FilePath(FPL("/g/d/e")))); } TEST(ChromeOSFileSystemBackendTest, AccessPermissions) { url_util::AddStandardScheme("chrome-extension"); scoped_refptr<quota::MockSpecialStoragePolicy> storage_policy = new quota::MockSpecialStoragePolicy(); scoped_refptr<fileapi::ExternalMountPoints> mount_points( fileapi::ExternalMountPoints::CreateRefCounted()); scoped_refptr<fileapi::ExternalMountPoints> system_mount_points( fileapi::ExternalMountPoints::CreateRefCounted()); chromeos::FileSystemBackend backend( NULL, // drive_delegate storage_policy, mount_points.get(), system_mount_points.get()); std::string extension("ddammdhioacbehjngdmkjcjbnfginlla"); storage_policy->AddFileHandler(extension); // Initialize mount points. ASSERT_TRUE(system_mount_points->RegisterFileSystem( "system", fileapi::kFileSystemTypeNativeLocal, fileapi::FileSystemMountOption(), base::FilePath(FPL("/g/system")))); ASSERT_TRUE(mount_points->RegisterFileSystem( "removable", fileapi::kFileSystemTypeNativeLocal, fileapi::FileSystemMountOption(), base::FilePath(FPL("/media/removable")))); ASSERT_TRUE(mount_points->RegisterFileSystem( "oem", fileapi::kFileSystemTypeRestrictedNativeLocal, fileapi::FileSystemMountOption(), base::FilePath(FPL("/usr/share/oem")))); // Backend specific mount point access. EXPECT_FALSE(backend.IsAccessAllowed( CreateFileSystemURL(extension, "removable/foo", mount_points.get()))); backend.GrantFileAccessToExtension(extension, base::FilePath(FPL("removable/foo"))); EXPECT_TRUE(backend.IsAccessAllowed( CreateFileSystemURL(extension, "removable/foo", mount_points.get()))); EXPECT_FALSE(backend.IsAccessAllowed( CreateFileSystemURL(extension, "removable/foo1", mount_points.get()))); // System mount point access. EXPECT_FALSE(backend.IsAccessAllowed( CreateFileSystemURL(extension, "system/foo", system_mount_points.get()))); backend.GrantFileAccessToExtension(extension, base::FilePath(FPL("system/foo"))); EXPECT_TRUE(backend.IsAccessAllowed( CreateFileSystemURL(extension, "system/foo", system_mount_points.get()))); EXPECT_FALSE(backend.IsAccessAllowed( CreateFileSystemURL(extension, "system/foo1", system_mount_points.get()))); // oem is restricted file system. backend.GrantFileAccessToExtension( extension, base::FilePath(FPL("oem/foo"))); // The extension should not be able to access the file even if // GrantFileAccessToExtension was called. EXPECT_FALSE(backend.IsAccessAllowed( CreateFileSystemURL(extension, "oem/foo", mount_points.get()))); backend.GrantFullAccessToExtension(extension); // The extension should be able to access restricted file system after it was // granted full access. EXPECT_TRUE(backend.IsAccessAllowed( CreateFileSystemURL(extension, "oem/foo", mount_points.get()))); // The extension which was granted full access should be able to access any // path on current file systems. EXPECT_TRUE(backend.IsAccessAllowed( CreateFileSystemURL(extension, "removable/foo1", mount_points.get()))); EXPECT_TRUE(backend.IsAccessAllowed( CreateFileSystemURL(extension, "system/foo1", system_mount_points.get()))); // The extension cannot access new mount points. // TODO(tbarzic): This should probably be changed. ASSERT_TRUE(mount_points->RegisterFileSystem( "test", fileapi::kFileSystemTypeNativeLocal, fileapi::FileSystemMountOption(), base::FilePath(FPL("/foo/test")))); EXPECT_FALSE(backend.IsAccessAllowed( CreateFileSystemURL(extension, "test_/foo", mount_points.get()))); backend.RevokeAccessForExtension(extension); EXPECT_FALSE(backend.IsAccessAllowed( CreateFileSystemURL(extension, "removable/foo", mount_points.get()))); fileapi::FileSystemURL internal_url = FileSystemURL::CreateForTest( GURL("chrome://foo"), fileapi::kFileSystemTypeExternal, base::FilePath(FPL("removable/"))); // Internal WebUI should have full access. EXPECT_TRUE(backend.IsAccessAllowed(internal_url)); } TEST(ChromeOSFileSystemBackendTest, GetVirtualPathConflictWithSystemPoints) { scoped_refptr<quota::MockSpecialStoragePolicy> storage_policy = new quota::MockSpecialStoragePolicy(); scoped_refptr<fileapi::ExternalMountPoints> mount_points( fileapi::ExternalMountPoints::CreateRefCounted()); scoped_refptr<fileapi::ExternalMountPoints> system_mount_points( fileapi::ExternalMountPoints::CreateRefCounted()); chromeos::FileSystemBackend backend( NULL, // drive_delegate storage_policy, mount_points.get(), system_mount_points.get()); const fileapi::FileSystemType type = fileapi::kFileSystemTypeNativeLocal; const fileapi::FileSystemMountOption option = fileapi::FileSystemMountOption(); // Backend specific mount points. ASSERT_TRUE(mount_points->RegisterFileSystem( "b", type, option, base::FilePath(FPL("/a/b")))); ASSERT_TRUE(mount_points->RegisterFileSystem( "y", type, option, base::FilePath(FPL("/z/y")))); ASSERT_TRUE(mount_points->RegisterFileSystem( "n", type, option, base::FilePath(FPL("/m/n")))); // System mount points ASSERT_TRUE(system_mount_points->RegisterFileSystem( "gb", type, option, base::FilePath(FPL("/a/b")))); ASSERT_TRUE( system_mount_points->RegisterFileSystem( "gz", type, option, base::FilePath(FPL("/z")))); ASSERT_TRUE(system_mount_points->RegisterFileSystem( "gp", type, option, base::FilePath(FPL("/m/n/o/p")))); struct TestCase { const base::FilePath::CharType* const local_path; bool success; const base::FilePath::CharType* const virtual_path; }; const TestCase kTestCases[] = { // Same paths in both mount points. { FPL("/a/b/c/d"), true, FPL("b/c/d") }, // System mount points path more specific. { FPL("/m/n/o/p/r/s"), true, FPL("n/o/p/r/s") }, // System mount points path less specific. { FPL("/z/y/x"), true, FPL("y/x") }, // Only system mount points path matches. { FPL("/z/q/r/s"), true, FPL("gz/q/r/s") }, // No match. { FPL("/foo/xxx"), false, FPL("") }, }; for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { // Initialize virtual path with a value. base::FilePath virtual_path(FPL("/mount")); base::FilePath local_path(kTestCases[i].local_path); EXPECT_EQ(kTestCases[i].success, backend.GetVirtualPath(local_path, &virtual_path)) << "Resolving " << kTestCases[i].local_path; // There are no guarantees for |virtual_path| value if |GetVirtualPath| // fails. if (!kTestCases[i].success) continue; base::FilePath expected_virtual_path(kTestCases[i].virtual_path); EXPECT_EQ(expected_virtual_path, virtual_path) << "Resolving " << kTestCases[i].local_path; } } } // namespace