blob: f4a24f463064ceba0eb045c47924b59a7cbc013a [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 <fs/pseudo-file.h>
#include <fbl/vector.h>
#include <initializer_list>
#include <unittest/unittest.h>
#include <zircon/device/vfs.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")
namespace {
zx_status_t DummyReader(fbl::String* output) {
return ZX_OK;
}
zx_status_t DummyWriter(fbl::StringPiece 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](fbl::StringPiece 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_;
};
bool CheckRead(const fbl::RefPtr<fs::Vnode>& file, zx_status_t status,
size_t length, size_t offset, fbl::StringPiece expected) {
BEGIN_HELPER;
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(), "");
END_HELPER;
}
bool CheckWrite(const fbl::RefPtr<fs::Vnode>& file, zx_status_t status,
size_t offset, fbl::StringPiece content, size_t expected_actual) {
BEGIN_HELPER;
size_t actual = 0u;
EXPECT_EQ(status, file->Write(content.data(), content.size(), offset, &actual));
EXPECT_EQ(expected_actual, actual);
END_HELPER;
}
bool CheckAppend(const fbl::RefPtr<fs::Vnode>& file, zx_status_t status,
fbl::StringPiece content, size_t expected_end, size_t expected_actual) {
BEGIN_HELPER;
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);
END_HELPER;
}
bool TestOpenValidationBuffered() {
BEGIN_TEST;
// no read handler, no write handler
{
auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile());
EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_ERR_NOT_DIR, file->ValidateFlags(ZX_FS_FLAG_DIRECTORY));
}
// read handler, no write handler
{
auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile(&DummyReader));
EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_ERR_NOT_DIR, file->ValidateFlags(ZX_FS_FLAG_DIRECTORY));
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
EXPECT_NONNULL(redirect);
}
// no read handler, write handler
{
auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile(nullptr, &DummyWriter));
EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_ERR_NOT_DIR, file->ValidateFlags(ZX_FS_FLAG_DIRECTORY));
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_NONNULL(redirect);
}
// read handler, write handler
{
auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile(&DummyReader, &DummyWriter));
EXPECT_EQ(ZX_ERR_NOT_DIR, file->ValidateFlags(ZX_FS_FLAG_DIRECTORY));
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
EXPECT_NONNULL(redirect);
redirect.reset();
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_NONNULL(redirect);
redirect.reset();
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_NONNULL(redirect);
}
END_TEST;
}
bool TestOpenValidationUnbuffered() {
BEGIN_TEST;
// no read handler, no write handler
{
auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile());
EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_ERR_NOT_DIR, file->ValidateFlags(ZX_FS_FLAG_DIRECTORY));
}
// read handler, no write handler
{
auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile(&DummyReader));
EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_ERR_NOT_DIR, file->ValidateFlags(ZX_FS_FLAG_DIRECTORY));
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
EXPECT_NONNULL(redirect);
}
// no read handler, write handler
{
auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile(nullptr, &DummyWriter));
EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
EXPECT_EQ(ZX_ERR_ACCESS_DENIED, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_ERR_NOT_DIR, file->ValidateFlags(ZX_FS_FLAG_DIRECTORY));
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_NONNULL(redirect);
}
// read handler, write handler
{
auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile(&DummyReader, &DummyWriter));
EXPECT_EQ(ZX_ERR_NOT_DIR, file->ValidateFlags(ZX_FS_FLAG_DIRECTORY));
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
EXPECT_NONNULL(redirect);
redirect.reset();
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_NONNULL(redirect);
redirect.reset();
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_NONNULL(redirect);
}
END_TEST;
}
bool TestGetattrBuffered() {
BEGIN_TEST;
// no read handler, no write handler
{
auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile());
vnattr_t attr;
EXPECT_EQ(ZX_OK, file->Getattr(&attr));
EXPECT_EQ(V_TYPE_FILE, attr.mode);
EXPECT_EQ(1, attr.nlink);
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_FLAG_VNODE_REF_ONLY));
vnattr_t path_attr;
EXPECT_EQ(ZX_OK, file->Getattr(&path_attr));
EXPECT_BYTES_EQ((uint8_t*) &attr, (uint8_t*) &path_attr, sizeof(attr), "");
}
// read handler, no write handler
{
auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile(&DummyReader));
vnattr_t attr;
EXPECT_EQ(ZX_OK, file->Getattr(&attr));
EXPECT_EQ(V_TYPE_FILE | V_IRUSR, attr.mode);
EXPECT_EQ(1, attr.nlink);
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
vnattr_t open_attr;
EXPECT_EQ(ZX_OK, file->Getattr(&open_attr));
EXPECT_BYTES_EQ((uint8_t*)&attr, (uint8_t*)&open_attr, sizeof(attr), "");
}
// no read handler, write handler
{
auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile(nullptr, &DummyWriter));
vnattr_t attr;
EXPECT_EQ(ZX_OK, file->Getattr(&attr));
EXPECT_EQ(V_TYPE_FILE | V_IWUSR, attr.mode);
EXPECT_EQ(1, attr.nlink);
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
vnattr_t open_attr;
EXPECT_EQ(ZX_OK, file->Getattr(&open_attr));
EXPECT_BYTES_EQ((uint8_t*)&attr, (uint8_t*)&open_attr, sizeof(attr), "");
}
// read handler, write handler
{
auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile(&DummyReader, &DummyWriter));
vnattr_t attr;
EXPECT_EQ(ZX_OK, file->Getattr(&attr));
EXPECT_EQ(V_TYPE_FILE | V_IRUSR | V_IWUSR, attr.mode);
EXPECT_EQ(1, attr.nlink);
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE, &redirect));
vnattr_t open_attr;
EXPECT_EQ(ZX_OK, file->Getattr(&open_attr));
EXPECT_BYTES_EQ((uint8_t*)&attr, (uint8_t*)&open_attr, sizeof(attr), "");
}
END_TEST;
}
bool TestGetattrUnbuffered() {
BEGIN_TEST;
// no read handler, no write handler
{
auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile());
vnattr_t attr;
EXPECT_EQ(ZX_OK, file->Getattr(&attr));
EXPECT_EQ(V_TYPE_FILE, attr.mode);
EXPECT_EQ(1, attr.nlink);
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_FLAG_VNODE_REF_ONLY));
vnattr_t path_attr;
EXPECT_EQ(ZX_OK, file->Getattr(&path_attr));
EXPECT_BYTES_EQ((uint8_t*) &attr, (uint8_t*) &path_attr, sizeof(attr), "");
}
// read handler, no write handler
{
auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile(&DummyReader));
vnattr_t attr;
EXPECT_EQ(ZX_OK, file->Getattr(&attr));
EXPECT_EQ(V_TYPE_FILE | V_IRUSR, attr.mode);
EXPECT_EQ(1, attr.nlink);
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
vnattr_t open_attr;
EXPECT_EQ(ZX_OK, file->Getattr(&open_attr));
EXPECT_BYTES_EQ((uint8_t*)&attr, (uint8_t*)&open_attr, sizeof(attr), "");
}
// no read handler, write handler
{
auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile(nullptr, &DummyWriter));
vnattr_t attr;
EXPECT_EQ(ZX_OK, file->Getattr(&attr));
EXPECT_EQ(V_TYPE_FILE | V_IWUSR, attr.mode);
EXPECT_EQ(1, attr.nlink);
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
vnattr_t open_attr;
EXPECT_EQ(ZX_OK, file->Getattr(&open_attr));
EXPECT_BYTES_EQ((uint8_t*)&attr, (uint8_t*)&open_attr, sizeof(attr), "");
}
// read handler, write handler
{
auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile(&DummyReader, &DummyWriter));
vnattr_t attr;
EXPECT_EQ(ZX_OK, file->Getattr(&attr));
EXPECT_EQ(V_TYPE_FILE | V_IRUSR | V_IWUSR, attr.mode);
EXPECT_EQ(1, attr.nlink);
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE, &redirect));
vnattr_t open_attr;
EXPECT_EQ(ZX_OK, file->Getattr(&open_attr));
EXPECT_BYTES_EQ((uint8_t*)&attr, (uint8_t*)&open_attr, sizeof(attr), "");
}
END_TEST;
}
bool TestReadBuffered() {
BEGIN_TEST;
VectorReader reader{"first", "second", "",
fbl::String(fbl::StringPiece("null\0null", 9u))};
auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile(reader.GetHandler()));
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 0u, 0u, ""));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 0u, "firs"));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 2u, "rst"));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 5u, 0u, "first"));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 8u, 0u, "first"));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 2u, "cond"));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 6u, 0u, "second"));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 8u, 0u, "second"));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 0u, ""));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 2u, ""));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 0u, 0u, ""));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 0u, "null"));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 2u, fbl::StringPiece("ll\0n", 4u)));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 9u, 0u, fbl::StringPiece("null\0null", 9u)));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 12u, 0u, fbl::StringPiece("null\0null", 9u)));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_ERR_IO, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
}
END_TEST;
}
bool TestReadUnbuffered() {
BEGIN_TEST;
VectorReader reader{"first", "second", "third", "fourth", "fifth", "",
fbl::String(fbl::StringPiece("null\0null", 9u))};
auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile(reader.GetHandler()));
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 0u, 0u, ""));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 0u, "seco"));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 2u, ""));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 3u, 0u, "thi"));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 6u, 0u, "fourth"));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_READABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_READABLE, &redirect));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 8u, 0u, "fifth"));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 4u, 0u, ""));
EXPECT_TRUE(CheckRead(redirect, ZX_OK, 12u, 0u, fbl::StringPiece("null\0null", 9u)));
EXPECT_TRUE(CheckRead(redirect, ZX_ERR_IO, 0u, 0u, ""));
EXPECT_EQ(ZX_OK, redirect->Close());
}
END_TEST;
}
bool TestWriteBuffered() {
BEGIN_TEST;
VectorWriter writer(6u);
auto file = fbl::AdoptRef<fs::Vnode>(new fs::BufferedPseudoFile(nullptr, writer.GetHandler(), 10u));
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 0u, "fixx", 4u));
EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 0u, "", 0u));
EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 2u, "rst", 3u));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 0u, "second", 6u));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_TRUE(CheckAppend(redirect, ZX_OK, "thxrxxx", 7u, 7u));
EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 2u, "i", 1u));
EXPECT_EQ(ZX_OK, redirect->Truncate(4u));
EXPECT_TRUE(CheckAppend(redirect, ZX_OK, "d", 5u, 1u));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 0u, "null", 4u));
EXPECT_EQ(ZX_OK, redirect->Truncate(5u));
EXPECT_TRUE(CheckAppend(redirect, ZX_OK, "null", 9u, 4u));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_EQ(ZX_ERR_NO_SPACE, redirect->Truncate(11u));
EXPECT_TRUE(CheckAppend(redirect, ZX_OK, "too-long", 8u, 8u));
EXPECT_TRUE(CheckAppend(redirect, ZX_OK, "-off-the-end", 10u, 2u));
EXPECT_TRUE(CheckAppend(redirect, ZX_ERR_NO_SPACE, "-overflow", 0u, 0u));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &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"));
END_TEST;
}
bool TestWriteUnbuffered() {
BEGIN_TEST;
VectorWriter writer(12u);
auto file = fbl::AdoptRef<fs::Vnode>(new fs::UnbufferedPseudoFile(nullptr, writer.GetHandler()));
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 0u, "first", 5u));
EXPECT_TRUE(CheckWrite(redirect, ZX_ERR_NO_SPACE, 2u, "xxx", 0u));
EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 0u, "second", 6u));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_TRUE(CheckWrite(redirect, ZX_OK, 0u, "", 0u));
EXPECT_TRUE(CheckAppend(redirect, ZX_OK, "third", 5u, 5u));
EXPECT_TRUE(CheckAppend(redirect, ZX_OK, fbl::StringPiece("null\0null", 9u), 9u, 9u));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE | ZX_FS_FLAG_TRUNCATE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE | ZX_FS_FLAG_TRUNCATE, &redirect));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE | ZX_FS_FLAG_CREATE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE | ZX_FS_FLAG_CREATE, &redirect));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_EQ(ZX_OK, redirect->Truncate(0u));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_TRUE(CheckAppend(redirect, ZX_OK, "fourth", 6u, 6u));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_EQ(ZX_OK, redirect->Close());
}
{
fbl::RefPtr<fs::Vnode> redirect;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_TRUE(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;
EXPECT_EQ(ZX_OK, file->ValidateFlags(ZX_FS_RIGHT_WRITABLE));
EXPECT_EQ(ZX_OK, file->Open(ZX_FS_RIGHT_WRITABLE, &redirect));
EXPECT_TRUE(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"));
END_TEST;
}
} // namespace
BEGIN_TEST_CASE(pseudo_file_tests)
RUN_TEST(TestOpenValidationBuffered)
RUN_TEST(TestOpenValidationUnbuffered)
RUN_TEST(TestGetattrBuffered)
RUN_TEST(TestGetattrUnbuffered)
RUN_TEST(TestReadBuffered)
RUN_TEST(TestReadUnbuffered)
RUN_TEST(TestWriteBuffered)
RUN_TEST(TestWriteUnbuffered)
END_TEST_CASE(pseudo_file_tests)