| // Copyright 2013 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifdef UNSAFE_BUFFERS_BUILD |
| // TODO(crbug.com/40285824): Remove this and convert code to safer constructs. |
| #pragma allow_unsafe_buffers |
| #endif |
| |
| #include "chrome/browser/ash/fileapi/file_system_backend.h" |
| |
| #include <stddef.h> |
| |
| #include <set> |
| |
| #include "base/files/file_path.h" |
| #include "chrome/browser/ash/fileapi/file_system_backend_delegate.h" |
| #include "chromeos/ash/components/dbus/cros_disks/cros_disks_client.h" |
| #include "extensions/common/constants.h" |
| #include "extensions/common/extension.h" |
| #include "storage/browser/file_system/external_mount_points.h" |
| #include "storage/browser/file_system/file_system_operation.h" |
| #include "storage/browser/file_system/file_system_url.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/common/storage_key/storage_key.h" |
| #include "url/origin.h" |
| |
| #define FPL(x) FILE_PATH_LITERAL(x) |
| |
| using storage::ExternalMountPoints; |
| using storage::FileSystemURL; |
| |
| namespace { |
| |
| FileSystemURL CreateFileSystemURL(const std::string& extension, |
| const char* path, |
| ExternalMountPoints* mount_points) { |
| return mount_points->CreateCrackedFileSystemURL( |
| blink::StorageKey::CreateFromStringForTesting("chrome-extension://" + |
| extension + "/"), |
| storage::kFileSystemTypeExternal, base::FilePath::FromUTF8Unsafe(path)); |
| } |
| |
| TEST(ChromeOSFileSystemBackendTest, DefaultMountPoints) { |
| // Make sure no system-level mount points are registered before testing |
| // to avoid flakiness. |
| storage::ExternalMountPoints::GetSystemInstance()->RevokeAllFileSystems(); |
| |
| scoped_refptr<storage::ExternalMountPoints> mount_points( |
| storage::ExternalMountPoints::CreateRefCounted()); |
| ash::FileSystemBackend backend( |
| nullptr, // profile |
| nullptr, // file_system_provider_delegate |
| nullptr, // mtp_delegate |
| nullptr, // arc_content_delegate |
| nullptr, // arc_documents_provider_delegate |
| nullptr, // drivefs_delegate |
| nullptr, // smbfs_delegate |
| mount_points.get(), storage::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(2u, root_dirs.size()); |
| |
| EXPECT_TRUE( |
| root_dirs_set.count(ash::CrosDisksClient::GetRemovableDiskMountPoint())); |
| EXPECT_TRUE( |
| root_dirs_set.count(ash::CrosDisksClient::GetArchiveMountPoint())); |
| } |
| |
| TEST(ChromeOSFileSystemBackendTest, GetRootDirectories) { |
| scoped_refptr<storage::ExternalMountPoints> mount_points( |
| storage::ExternalMountPoints::CreateRefCounted()); |
| |
| scoped_refptr<storage::ExternalMountPoints> system_mount_points( |
| storage::ExternalMountPoints::CreateRefCounted()); |
| |
| ash::FileSystemBackend backend(nullptr, // profile |
| nullptr, // file_system_provider_delegate |
| nullptr, // mtp_delegate |
| nullptr, // arc_content_delegate |
| nullptr, // arc_documents_provider_delegate |
| nullptr, // drivefs_delegate |
| nullptr, // smbfs_delegate |
| 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", storage::kFileSystemTypeLocal, |
| storage::FileSystemMountOption(), |
| base::FilePath(FPL("/a/b/c"))); |
| mount_points->RegisterFileSystem("d", storage::kFileSystemTypeLocal, |
| storage::FileSystemMountOption(), |
| base::FilePath(FPL("/b/c/d"))); |
| |
| // Register system test mount points. |
| system_mount_points->RegisterFileSystem("d", storage::kFileSystemTypeLocal, |
| storage::FileSystemMountOption(), |
| base::FilePath(FPL("/g/c/d"))); |
| system_mount_points->RegisterFileSystem("e", storage::kFileSystemTypeLocal, |
| storage::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) { |
| scoped_refptr<storage::ExternalMountPoints> mount_points( |
| storage::ExternalMountPoints::CreateRefCounted()); |
| scoped_refptr<storage::ExternalMountPoints> system_mount_points( |
| storage::ExternalMountPoints::CreateRefCounted()); |
| ash::FileSystemBackend backend(nullptr, // profile |
| nullptr, // file_system_provider_delegate |
| nullptr, // mtp_delegate |
| nullptr, // arc_content_delegate |
| nullptr, // arc_documents_provider_delegate |
| nullptr, // drivefs_delegate |
| nullptr, // smbfs_delegate |
| mount_points.get(), system_mount_points.get()); |
| |
| std::string extension("ddammdhioacbehjngdmkjcjbnfginlla"); |
| url::Origin origin = url::Origin::Create( |
| extensions::Extension::GetBaseURLFromExtensionId(extension)); |
| |
| // Initialize mount points. |
| ASSERT_TRUE(system_mount_points->RegisterFileSystem( |
| "system", storage::kFileSystemTypeLocal, storage::FileSystemMountOption(), |
| base::FilePath(FPL("/g/system")))); |
| ASSERT_TRUE(mount_points->RegisterFileSystem( |
| "removable", storage::kFileSystemTypeLocal, |
| storage::FileSystemMountOption(), |
| base::FilePath(FPL("/media/removable")))); |
| |
| // Backend specific mount point access. |
| EXPECT_FALSE(backend.IsAccessAllowed( |
| ash::BackendFunction::kCreateFileSystemOperation, |
| storage::OperationType::kCopy, |
| CreateFileSystemURL(extension, "removable/foo", mount_points.get()))); |
| |
| backend.GrantFileAccessToOrigin(origin, base::FilePath(FPL("removable/foo"))); |
| EXPECT_TRUE(backend.IsAccessAllowed( |
| ash::BackendFunction::kCreateFileSystemOperation, |
| storage::OperationType::kCopy, |
| CreateFileSystemURL(extension, "removable/foo", mount_points.get()))); |
| EXPECT_FALSE(backend.IsAccessAllowed( |
| ash::BackendFunction::kCreateFileSystemOperation, |
| storage::OperationType::kCopy, |
| CreateFileSystemURL(extension, "removable/foo1", mount_points.get()))); |
| |
| // System mount point access. |
| EXPECT_FALSE(backend.IsAccessAllowed( |
| ash::BackendFunction::kCreateFileSystemOperation, |
| storage::OperationType::kCopy, |
| CreateFileSystemURL(extension, "system/foo", system_mount_points.get()))); |
| |
| backend.GrantFileAccessToOrigin(origin, base::FilePath(FPL("system/foo"))); |
| EXPECT_TRUE(backend.IsAccessAllowed( |
| ash::BackendFunction::kCreateFileSystemOperation, |
| storage::OperationType::kCopy, |
| CreateFileSystemURL(extension, "system/foo", system_mount_points.get()))); |
| EXPECT_FALSE( |
| backend.IsAccessAllowed(ash::BackendFunction::kCreateFileSystemOperation, |
| storage::OperationType::kCopy, |
| 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", storage::kFileSystemTypeLocal, storage::FileSystemMountOption(), |
| base::FilePath(FPL("/foo/test")))); |
| EXPECT_FALSE(backend.IsAccessAllowed( |
| ash::BackendFunction::kCreateFileSystemOperation, |
| storage::OperationType::kCopy, |
| CreateFileSystemURL(extension, "test_/foo", mount_points.get()))); |
| |
| backend.RevokeAccessForOrigin(origin); |
| EXPECT_FALSE(backend.IsAccessAllowed( |
| ash::BackendFunction::kCreateFileSystemOperation, |
| storage::OperationType::kCopy, |
| CreateFileSystemURL(extension, "removable/foo", mount_points.get()))); |
| |
| // ImageLoader has access to all files GetMetadata(), GetFileStreamReader(). |
| std::string image_loader("pmfjbimdmchhbnneeidfognadeopoehp"); |
| EXPECT_TRUE(backend.IsAccessAllowed( |
| ash::BackendFunction::kCreateFileSystemOperation, |
| storage::OperationType::kGetMetadata, |
| CreateFileSystemURL(image_loader, "removable/foo", mount_points.get()))); |
| EXPECT_TRUE(backend.IsAccessAllowed( |
| ash::BackendFunction::kCreateFileStreamReader, |
| storage::OperationType::kNone, |
| CreateFileSystemURL(image_loader, "removable/foo", mount_points.get()))); |
| EXPECT_FALSE(backend.IsAccessAllowed( |
| ash::BackendFunction::kCreateFileSystemOperation, |
| storage::OperationType::kCopy, |
| CreateFileSystemURL(image_loader, "removable/foo", mount_points.get()))); |
| EXPECT_FALSE(backend.IsAccessAllowed( |
| ash::BackendFunction::kCreateFileStreamWriter, |
| storage::OperationType::kNone, |
| CreateFileSystemURL(image_loader, "removable/foo", mount_points.get()))); |
| } |
| |
| TEST(ChromeOSFileSystemBackendTest, GetVirtualPathConflictWithSystemPoints) { |
| scoped_refptr<storage::ExternalMountPoints> mount_points( |
| storage::ExternalMountPoints::CreateRefCounted()); |
| scoped_refptr<storage::ExternalMountPoints> system_mount_points( |
| storage::ExternalMountPoints::CreateRefCounted()); |
| ash::FileSystemBackend backend(nullptr, // profile |
| nullptr, // file_system_provider_delegate |
| nullptr, // mtp_delegate |
| nullptr, // arc_content_delegate |
| nullptr, // arc_documents_provider_delegate |
| nullptr, // drivefs_delegate |
| nullptr, // smbfs_delegate |
| mount_points.get(), system_mount_points.get()); |
| |
| const storage::FileSystemType type = storage::kFileSystemTypeLocal; |
| const storage::FileSystemMountOption option = |
| storage::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 < std::size(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 |