blob: f19f82ec94552061501bfe4f233c062f95a2ef97 [file] [log] [blame]
// Copyright 2017 The Fuchsia 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 <zxtest/zxtest.h>
#include "src/storage/lib/vfs/cpp/pseudo_dir.h"
#include "src/storage/lib/vfs/cpp/pseudo_file.h"
#include "src/storage/lib/vfs/cpp/tests/dir_test_util.h"
#include "src/storage/lib/vfs/cpp/vfs_types.h"
namespace {
TEST(PseudoDir, ApiTest) {
auto dir = fbl::MakeRefCounted<fs::PseudoDir>();
auto subdir = fbl::MakeRefCounted<fs::PseudoDir>();
auto file1 = fbl::MakeRefCounted<fs::UnbufferedPseudoFile>();
auto file2 = fbl::MakeRefCounted<fs::UnbufferedPseudoFile>();
// add entries
EXPECT_EQ(ZX_OK, dir->AddEntry("subdir", subdir));
EXPECT_EQ(ZX_OK, dir->AddEntry("file1", file1));
EXPECT_EQ(ZX_OK, dir->AddEntry("file2", file2));
EXPECT_EQ(ZX_OK, dir->AddEntry("file2b", file2));
// try to add duplicates
EXPECT_EQ(ZX_ERR_ALREADY_EXISTS, dir->AddEntry("subdir", subdir));
EXPECT_EQ(ZX_ERR_ALREADY_EXISTS, dir->AddEntry("file1", subdir));
// remove entries
EXPECT_EQ(ZX_OK, dir->RemoveEntry("file2"));
EXPECT_EQ(ZX_ERR_NOT_FOUND, dir->RemoveEntry("file2"));
// open as directory
fs::VnodeConnectionOptions options_directory{.flags = fuchsia_io::OpenFlags::kDirectory};
fbl::RefPtr<fs::Vnode> redirect;
auto validated_options = dir->ValidateOptions(options_directory);
EXPECT_TRUE(validated_options.is_ok());
EXPECT_EQ(ZX_OK, dir->Open(&redirect));
EXPECT_NULL(redirect);
// verify node protocol type
EXPECT_EQ(dir->GetProtocols(), fuchsia_io::NodeProtocolKinds::kDirectory);
// verify node attributes
zx::result attr = dir->GetAttributes();
ASSERT_TRUE(attr.is_ok());
constexpr fs::VnodeAttributes kExpectedAttrs{.content_size = 0, .storage_size = 0};
EXPECT_EQ(kExpectedAttrs, *attr);
// lookup entries
fbl::RefPtr<fs::Vnode> node;
EXPECT_EQ(ZX_OK, dir->Lookup("subdir", &node));
EXPECT_EQ(subdir.get(), node.get());
EXPECT_EQ(ZX_OK, dir->Lookup("file1", &node));
EXPECT_EQ(file1.get(), node.get());
EXPECT_EQ(ZX_ERR_NOT_FOUND, dir->Lookup("file2", &node));
EXPECT_EQ(ZX_OK, dir->Lookup("file2b", &node));
EXPECT_EQ(file2.get(), node.get());
// readdir
{
fs::VdirCookie cookie;
uint8_t buffer[4096];
size_t length;
EXPECT_EQ(dir->Readdir(&cookie, buffer, sizeof(buffer), &length), ZX_OK);
fs::DirentChecker dc(buffer, length);
dc.ExpectEntry(".", V_TYPE_DIR);
dc.ExpectEntry("subdir", V_TYPE_DIR);
dc.ExpectEntry("file1", V_TYPE_FILE);
dc.ExpectEntry("file2b", V_TYPE_FILE);
dc.ExpectEnd();
}
// readdir with small buffer
{
fs::VdirCookie cookie;
uint8_t buffer[2 * sizeof(vdirent) + 13];
size_t length;
EXPECT_EQ(dir->Readdir(&cookie, buffer, sizeof(buffer), &length), ZX_OK);
fs::DirentChecker dc(buffer, length);
dc.ExpectEntry(".", V_TYPE_DIR);
dc.ExpectEntry("subdir", V_TYPE_DIR);
dc.ExpectEnd();
// readdir again
EXPECT_EQ(dir->Readdir(&cookie, buffer, sizeof(buffer), &length), ZX_OK);
fs::DirentChecker dc1(buffer, length);
dc1.ExpectEntry("file1", V_TYPE_FILE);
dc1.ExpectEntry("file2b", V_TYPE_FILE);
dc1.ExpectEnd();
}
// test removed entries do not appear in readdir or lookup
dir->RemoveEntry("file1");
{
fs::VdirCookie cookie;
uint8_t buffer[4096];
size_t length;
EXPECT_EQ(dir->Readdir(&cookie, buffer, sizeof(buffer), &length), ZX_OK);
fs::DirentChecker dc(buffer, length);
dc.ExpectEntry(".", V_TYPE_DIR);
dc.ExpectEntry("subdir", V_TYPE_DIR);
dc.ExpectEntry("file2b", V_TYPE_FILE);
dc.ExpectEnd();
}
EXPECT_EQ(ZX_ERR_NOT_FOUND, dir->Lookup("file1", &node));
// remove all entries
dir->RemoveAllEntries();
// readdir again
{
fs::VdirCookie cookie;
uint8_t buffer[4096];
size_t length;
EXPECT_EQ(dir->Readdir(&cookie, buffer, sizeof(buffer), &length), ZX_OK);
fs::DirentChecker dc(buffer, length);
dc.ExpectEntry(".", V_TYPE_DIR);
dc.ExpectEnd();
}
// FIXME(https://fxbug.dev/42106069): Can't unittest watch/notify (hard to isolate right now).
}
TEST(PseudoDir, RejectOpenFlagNotDirectory) {
auto dir = fbl::MakeRefCounted<fs::PseudoDir>();
auto result = dir->ValidateOptions(fs::VnodeConnectionOptions{
.flags = fuchsia_io::OpenFlags::kNotDirectory, .rights = fuchsia_io::kRStarDir});
ASSERT_TRUE(result.is_error());
EXPECT_EQ(ZX_ERR_NOT_FILE, result.status_value());
}
} // namespace