blob: 47504dcad8f0827bb1cd9f94ec0ee80d8baaf634 [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 <zircon/device/vfs.h>
#include <initializer_list>
#include <string_view>
#include <fbl/vector.h>
#include <zxtest/zxtest.h>
#include "src/lib/storage/vfs/cpp/pseudo_file.h"
#define EXPECT_FSTR_EQ(expected, actual) \
EXPECT_BYTES_EQ(reinterpret_cast<const uint8_t*>(expected.c_str()), \
reinterpret_cast<const uint8_t*>(actual.c_str()), expected.size() + 1u, \
"unequal fbl::String")
#define EXPECT_ATTR_EQ(expected, actual) \
EXPECT_TRUE(expected == actual, "unequal fs::VnodeAttributes")
namespace {
using VnodeOptions = fs::VnodeConnectionOptions;
zx_status_t DummyReader(fbl::String* output) { return ZX_OK; }
zx_status_t DummyWriter(std::string_view input) { return ZX_OK; }
class VectorReader {
public:
VectorReader(std::initializer_list<fbl::String> strings) : strings_(strings) {}
fs::PseudoFile::ReadHandler GetHandler() {
return [this](fbl::String* output) {
if (index_ >= strings_.size())
return ZX_ERR_IO;
*output = strings_[index_++];
return ZX_OK;
};
}
const fbl::Vector<fbl::String>& strings() const { return strings_; }
private:
fbl::Vector<fbl::String> strings_;
size_t index_ = 0u;
};
class VectorWriter {
public:
VectorWriter(size_t max_strings) : max_strings_(max_strings) {}
fs::PseudoFile::WriteHandler GetHandler() {
return [this](std::string_view input) {
if (strings_.size() >= max_strings_)
return ZX_ERR_IO;
strings_.push_back(fbl::String(input));
return ZX_OK;
};
}
const fbl::Vector<fbl::String>& strings() const { return strings_; }
private:
const size_t max_strings_;
fbl::Vector<fbl::String> strings_;
};
void CheckRead(const fbl::RefPtr<fs::Vnode>& file, zx_status_t status, size_t length, size_t offset,
std::string_view expected) {
uint8_t buf[length];
memset(buf, '!', length);
size_t actual = 0u;
EXPECT_EQ(status, file->Read(buf, length, offset, &actual));
EXPECT_EQ(expected.size(), actual);
EXPECT_BYTES_EQ(reinterpret_cast<const uint8_t*>(expected.data()), buf, expected.size(), "");
}
void CheckWrite(const fbl::RefPtr<fs::Vnode>& file, zx_status_t status, size_t offset,
std::string_view content, size_t expected_actual) {
size_t actual = 0u;
EXPECT_EQ(status, file->Write(content.data(), content.size(), offset, &actual));
EXPECT_EQ(expected_actual, actual);
}
void CheckAppend(const fbl::RefPtr<fs::Vnode>& file, zx_status_t status, std::string_view content,
size_t expected_end, size_t expected_actual) {
size_t end = 0u;
size_t actual = 0u;
EXPECT_EQ(status, file->Append(content.data(), content.size(), &end, &actual));
EXPECT_EQ(expected_end, end);
EXPECT_EQ(expected_actual, actual);
}
#define EXPECT_RESULT_OK(expr) EXPECT_TRUE((expr).is_ok())
#define EXPECT_RESULT_ERROR(error_val, expr) \
EXPECT_TRUE((expr).is_error()); \
EXPECT_EQ(error_val, (expr).error())
TEST(PseudoFile, OpenValidationBuffered) {
// no read handler, no write handler
{
auto file = fbl::MakeRefCounted<fs::BufferedPseudoFile>();
EXPECT_RESULT_ERROR(ZX_ERR_ACCESS_DENIED, file->ValidateOptions(VnodeOptions::ReadOnly()));
EXPECT_RESULT_ERROR(ZX_ERR_ACCESS_DENIED, file->ValidateOptions(VnodeOptions::ReadWrite()));
EXPECT_RESULT_ERROR(ZX_ERR_ACCESS_DENIED, file->ValidateOptions(VnodeOptions::WriteOnly()));
EXPECT_RESULT_ERROR(ZX_ERR_NOT_DIR, file->ValidateOptions(VnodeOptions().set_directory()));
}
// read handler, no write handler
{
auto file = fbl::MakeRefCounted<fs::BufferedPseudoFile>(&DummyReader);
EXPECT_RESULT_ERROR(ZX_ERR_ACCESS_DENIED, file->ValidateOptions(VnodeOptions::ReadWrite()));
EXPECT_RESULT_ERROR(ZX_ERR_ACCESS_DENIED, file->ValidateOptions(VnodeOptions::WriteOnly()));
EXPECT_RESULT_ERROR(ZX_ERR_NOT_DIR, file->ValidateOptions(VnodeOptions().set_directory()));
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::ReadOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
EXPECT_TRUE(redirect);
}
// no read handler, write handler
{
auto file = fbl::MakeRefCounted<fs::BufferedPseudoFile>(nullptr, &DummyWriter);
EXPECT_RESULT_ERROR(ZX_ERR_ACCESS_DENIED, file->ValidateOptions(VnodeOptions::ReadOnly()));
EXPECT_RESULT_ERROR(ZX_ERR_ACCESS_DENIED, file->ValidateOptions(VnodeOptions::ReadWrite()));
EXPECT_RESULT_ERROR(ZX_ERR_NOT_DIR, file->ValidateOptions(VnodeOptions().set_directory()));
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
EXPECT_TRUE(redirect);
}
// read handler, write handler
{
auto file = fbl::MakeRefCounted<fs::BufferedPseudoFile>(&DummyReader, &DummyWriter);
EXPECT_RESULT_ERROR(ZX_ERR_NOT_DIR, file->ValidateOptions(VnodeOptions().set_directory()));
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::ReadOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
EXPECT_TRUE(redirect);
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::ReadWrite());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
EXPECT_TRUE(redirect);
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
EXPECT_TRUE(redirect);
}
}
}
TEST(PseudoFile, OpenValidationUnbuffered) {
// no read handler, no write handler
{
auto file = fbl::MakeRefCounted<fs::UnbufferedPseudoFile>();
EXPECT_RESULT_ERROR(ZX_ERR_ACCESS_DENIED, file->ValidateOptions(VnodeOptions::ReadOnly()));
EXPECT_RESULT_ERROR(ZX_ERR_ACCESS_DENIED, file->ValidateOptions(VnodeOptions::ReadWrite()));
EXPECT_RESULT_ERROR(ZX_ERR_ACCESS_DENIED, file->ValidateOptions(VnodeOptions::WriteOnly()));
EXPECT_RESULT_ERROR(ZX_ERR_NOT_DIR, file->ValidateOptions(VnodeOptions().set_directory()));
}
// read handler, no write handler
{
auto file = fbl::MakeRefCounted<fs::UnbufferedPseudoFile>(&DummyReader);
EXPECT_RESULT_ERROR(ZX_ERR_ACCESS_DENIED, file->ValidateOptions(VnodeOptions::ReadWrite()));
EXPECT_RESULT_ERROR(ZX_ERR_ACCESS_DENIED, file->ValidateOptions(VnodeOptions::WriteOnly()));
EXPECT_RESULT_ERROR(ZX_ERR_NOT_DIR, file->ValidateOptions(VnodeOptions().set_directory()));
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::ReadOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
EXPECT_TRUE(redirect);
}
// no read handler, write handler
{
auto file = fbl::MakeRefCounted<fs::UnbufferedPseudoFile>(nullptr, &DummyWriter);
EXPECT_RESULT_ERROR(ZX_ERR_ACCESS_DENIED, file->ValidateOptions(VnodeOptions::ReadOnly()));
EXPECT_RESULT_ERROR(ZX_ERR_ACCESS_DENIED, file->ValidateOptions(VnodeOptions::ReadWrite()));
EXPECT_RESULT_ERROR(ZX_ERR_NOT_DIR, file->ValidateOptions(VnodeOptions().set_directory()));
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
EXPECT_TRUE(redirect);
}
// read handler, write handler
{
auto file = fbl::MakeRefCounted<fs::UnbufferedPseudoFile>(&DummyReader, &DummyWriter);
EXPECT_RESULT_ERROR(ZX_ERR_NOT_DIR, file->ValidateOptions(VnodeOptions().set_directory()));
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::ReadOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
EXPECT_TRUE(redirect);
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::ReadWrite());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
EXPECT_TRUE(redirect);
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
EXPECT_TRUE(redirect);
}
}
}
TEST(PseudoFile, GetattrBuffered) {
// no read handler, no write handler
{
auto file = fbl::MakeRefCounted<fs::BufferedPseudoFile>();
fs::VnodeAttributes attr;
EXPECT_EQ(ZX_OK, file->GetAttributes(&attr));
EXPECT_EQ(V_TYPE_FILE, attr.mode);
EXPECT_EQ(1, attr.link_count);
EXPECT_RESULT_OK(file->ValidateOptions(VnodeOptions().set_node_reference()));
fs::VnodeAttributes path_attr;
EXPECT_EQ(ZX_OK, file->GetAttributes(&path_attr));
EXPECT_ATTR_EQ(attr, path_attr);
}
// read handler, no write handler
{
auto file = fbl::MakeRefCounted<fs::BufferedPseudoFile>(&DummyReader);
fs::VnodeAttributes attr;
EXPECT_EQ(ZX_OK, file->GetAttributes(&attr));
EXPECT_EQ(V_TYPE_FILE | V_IRUSR, attr.mode);
EXPECT_EQ(1, attr.link_count);
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::ReadOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
fs::VnodeAttributes open_attr;
EXPECT_EQ(ZX_OK, file->GetAttributes(&open_attr));
EXPECT_ATTR_EQ(attr, open_attr);
}
// no read handler, write handler
{
auto file = fbl::MakeRefCounted<fs::BufferedPseudoFile>(nullptr, &DummyWriter);
fs::VnodeAttributes attr;
EXPECT_EQ(ZX_OK, file->GetAttributes(&attr));
EXPECT_EQ(V_TYPE_FILE | V_IWUSR, attr.mode);
EXPECT_EQ(1, attr.link_count);
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
fs::VnodeAttributes open_attr;
EXPECT_EQ(ZX_OK, file->GetAttributes(&open_attr));
EXPECT_ATTR_EQ(attr, open_attr);
}
// read handler, write handler
{
auto file = fbl::MakeRefCounted<fs::BufferedPseudoFile>(&DummyReader, &DummyWriter);
fs::VnodeAttributes attr;
EXPECT_EQ(ZX_OK, file->GetAttributes(&attr));
EXPECT_EQ(V_TYPE_FILE | V_IRUSR | V_IWUSR, attr.mode);
EXPECT_EQ(1, attr.link_count);
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::ReadWrite());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
fs::VnodeAttributes open_attr;
EXPECT_EQ(ZX_OK, file->GetAttributes(&open_attr));
EXPECT_ATTR_EQ(attr, open_attr);
}
}
TEST(PseudoFile, GetattrUnbuffered) {
// no read handler, no write handler
{
auto file = fbl::MakeRefCounted<fs::UnbufferedPseudoFile>();
fs::VnodeAttributes attr;
EXPECT_EQ(ZX_OK, file->GetAttributes(&attr));
EXPECT_EQ(V_TYPE_FILE, attr.mode);
EXPECT_EQ(1, attr.link_count);
EXPECT_RESULT_OK(file->ValidateOptions(VnodeOptions().set_node_reference()));
fs::VnodeAttributes path_attr;
EXPECT_EQ(ZX_OK, file->GetAttributes(&path_attr));
EXPECT_ATTR_EQ(attr, path_attr);
}
// read handler, no write handler
{
auto file = fbl::MakeRefCounted<fs::UnbufferedPseudoFile>(&DummyReader);
fs::VnodeAttributes attr;
EXPECT_EQ(ZX_OK, file->GetAttributes(&attr));
EXPECT_EQ(V_TYPE_FILE | V_IRUSR, attr.mode);
EXPECT_EQ(1, attr.link_count);
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::ReadOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
fs::VnodeAttributes open_attr;
EXPECT_EQ(ZX_OK, file->GetAttributes(&open_attr));
EXPECT_ATTR_EQ(attr, open_attr);
}
// no read handler, write handler
{
auto file = fbl::MakeRefCounted<fs::UnbufferedPseudoFile>(nullptr, &DummyWriter);
fs::VnodeAttributes attr;
EXPECT_EQ(ZX_OK, file->GetAttributes(&attr));
EXPECT_EQ(V_TYPE_FILE | V_IWUSR, attr.mode);
EXPECT_EQ(1, attr.link_count);
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
fs::VnodeAttributes open_attr;
EXPECT_EQ(ZX_OK, file->GetAttributes(&open_attr));
EXPECT_ATTR_EQ(attr, open_attr);
}
// read handler, write handler
{
auto file = fbl::MakeRefCounted<fs::UnbufferedPseudoFile>(&DummyReader, &DummyWriter);
fs::VnodeAttributes attr;
EXPECT_EQ(ZX_OK, file->GetAttributes(&attr));
EXPECT_EQ(V_TYPE_FILE | V_IRUSR | V_IWUSR, attr.mode);
EXPECT_EQ(1, attr.link_count);
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::ReadWrite());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
fs::VnodeAttributes open_attr;
EXPECT_EQ(ZX_OK, file->GetAttributes(&open_attr));
EXPECT_ATTR_EQ(attr, open_attr);
}
}
TEST(PseudoFile, ReadBuffered) {
VectorReader reader{"first", "second", "", fbl::String(std::string_view("null\0null", 9u))};
auto file = fbl::MakeRefCounted<fs::BufferedPseudoFile>(reader.GetHandler());
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::ReadOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
CheckRead(redirect, ZX_OK, 0u, 0u, "");
CheckRead(redirect, ZX_OK, 4u, 0u, "firs");
CheckRead(redirect, ZX_OK, 4u, 2u, "rst");
CheckRead(redirect, ZX_OK, 5u, 0u, "first");
CheckRead(redirect, ZX_OK, 8u, 0u, "first");
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::ReadOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
CheckRead(redirect, ZX_OK, 4u, 2u, "cond");
CheckRead(redirect, ZX_OK, 6u, 0u, "second");
CheckRead(redirect, ZX_OK, 8u, 0u, "second");
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::ReadOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
CheckRead(redirect, ZX_OK, 4u, 0u, "");
CheckRead(redirect, ZX_OK, 4u, 2u, "");
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::ReadOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
CheckRead(redirect, ZX_OK, 0u, 0u, "");
CheckRead(redirect, ZX_OK, 4u, 0u, "null");
CheckRead(redirect, ZX_OK, 4u, 2u, std::string_view("ll\0n", 4u));
CheckRead(redirect, ZX_OK, 9u, 0u, std::string_view("null\0null", 9u));
CheckRead(redirect, ZX_OK, 12u, 0u, std::string_view("null\0null", 9u));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::ReadOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_ERR_IO, file->Open(result.value(), &redirect));
}
}
TEST(PseudoFile, ReadUnbuffered) {
VectorReader reader{"first",
"second",
"third",
"fourth",
"fifth",
"",
fbl::String(std::string_view("null\0null", 9u))};
auto file = fbl::MakeRefCounted<fs::UnbufferedPseudoFile>(reader.GetHandler());
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::ReadOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
CheckRead(redirect, ZX_OK, 0u, 0u, "");
CheckRead(redirect, ZX_OK, 4u, 0u, "seco");
CheckRead(redirect, ZX_OK, 4u, 2u, "");
CheckRead(redirect, ZX_OK, 3u, 0u, "thi");
CheckRead(redirect, ZX_OK, 6u, 0u, "fourth");
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::ReadOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
CheckRead(redirect, ZX_OK, 8u, 0u, "fifth");
CheckRead(redirect, ZX_OK, 4u, 0u, "");
CheckRead(redirect, ZX_OK, 12u, 0u, std::string_view("null\0null", 9u));
CheckRead(redirect, ZX_ERR_IO, 0u, 0u, "");
EXPECT_EQ(ZX_OK, redirect->Close());
}
}
TEST(PseudoFile, WriteBuffered) {
VectorWriter writer(6u);
auto file = fbl::MakeRefCounted<fs::BufferedPseudoFile>(nullptr, writer.GetHandler(), 10u);
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
CheckWrite(redirect, ZX_OK, 0u, "fixx", 4u);
CheckWrite(redirect, ZX_OK, 0u, "", 0u);
CheckWrite(redirect, ZX_OK, 2u, "rst", 3u);
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
CheckWrite(redirect, ZX_OK, 0u, "second", 6u);
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
CheckAppend(redirect, ZX_OK, "thxrxxx", 7u, 7u);
CheckWrite(redirect, ZX_OK, 2u, "i", 1u);
EXPECT_EQ(ZX_OK, redirect->Truncate(4u));
CheckAppend(redirect, ZX_OK, "d", 5u, 1u);
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
CheckWrite(redirect, ZX_OK, 0u, "null", 4u);
EXPECT_EQ(ZX_OK, redirect->Truncate(5u));
CheckAppend(redirect, ZX_OK, "null", 9u, 4u);
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
EXPECT_EQ(ZX_ERR_NO_SPACE, redirect->Truncate(11u));
CheckAppend(redirect, ZX_OK, "too-long", 8u, 8u);
CheckAppend(redirect, ZX_OK, "-off-the-end", 10u, 2u);
CheckAppend(redirect, ZX_ERR_NO_SPACE, "-overflow", 0u, 0u);
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
EXPECT_EQ(ZX_ERR_IO, redirect->Close());
}
EXPECT_EQ(6u, writer.strings().size());
EXPECT_FSTR_EQ(writer.strings()[0], fbl::String("first"));
EXPECT_FSTR_EQ(writer.strings()[1], fbl::String("second"));
EXPECT_FSTR_EQ(writer.strings()[2], fbl::String(""));
EXPECT_FSTR_EQ(writer.strings()[3], fbl::String("third"));
EXPECT_FSTR_EQ(writer.strings()[4], fbl::String("null\0null", 9u));
EXPECT_FSTR_EQ(writer.strings()[5], fbl::String("too-long-o"));
}
TEST(PseudoFile, WriteUnbuffered) {
VectorWriter writer(12u);
auto file = fbl::MakeRefCounted<fs::UnbufferedPseudoFile>(nullptr, writer.GetHandler());
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
CheckWrite(redirect, ZX_OK, 0u, "first", 5u);
CheckWrite(redirect, ZX_ERR_NO_SPACE, 2u, "xxx", 0u);
CheckWrite(redirect, ZX_OK, 0u, "second", 6u);
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
CheckWrite(redirect, ZX_OK, 0u, "", 0u);
CheckAppend(redirect, ZX_OK, "third", 5u, 5u);
CheckAppend(redirect, ZX_OK, std::string_view("null\0null", 9u), 9u, 9u);
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly().set_truncate());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly().set_create());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
EXPECT_EQ(ZX_OK, redirect->Truncate(0u));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
CheckAppend(redirect, ZX_OK, "fourth", 6u, 6u);
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
CheckAppend(redirect, ZX_OK, "fifth", 5u, 5u);
EXPECT_EQ(ZX_ERR_INVALID_ARGS, redirect->Truncate(10u));
EXPECT_EQ(ZX_OK, redirect->Truncate(0u));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
auto result = file->ValidateOptions(VnodeOptions::WriteOnly());
EXPECT_RESULT_OK(result);
EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect));
CheckWrite(redirect, ZX_OK, 0u, "a long string", 13u);
EXPECT_EQ(ZX_OK, redirect->Truncate(0u));
EXPECT_EQ(ZX_ERR_IO, redirect->Close());
}
EXPECT_EQ(12u, writer.strings().size());
EXPECT_FSTR_EQ(writer.strings()[0], fbl::String("first"));
EXPECT_FSTR_EQ(writer.strings()[1], fbl::String("second"));
EXPECT_FSTR_EQ(writer.strings()[2], fbl::String(""));
EXPECT_FSTR_EQ(writer.strings()[3], fbl::String("third"));
EXPECT_FSTR_EQ(writer.strings()[4], fbl::String("null\0null", 9u));
EXPECT_FSTR_EQ(writer.strings()[5], fbl::String(""));
EXPECT_FSTR_EQ(writer.strings()[6], fbl::String(""));
EXPECT_FSTR_EQ(writer.strings()[7], fbl::String(""));
EXPECT_FSTR_EQ(writer.strings()[8], fbl::String("fourth"));
EXPECT_FSTR_EQ(writer.strings()[9], fbl::String("fifth"));
EXPECT_FSTR_EQ(writer.strings()[10], fbl::String(""));
EXPECT_FSTR_EQ(writer.strings()[11], fbl::String("a long string"));
}
} // namespace