blob: 097398c694578f6ef6fc58a911dc88534379f164 [file] [log] [blame]
// Copyright 2019 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 <lib/vfs/cpp/vmo_file.h>
namespace vfs {
VmoFile::VmoFile(zx::unowned_vmo unowned_vmo, size_t offset, size_t length,
WriteOption write_option, Sharing vmo_sharing)
: offset_(offset), length_(length), write_option_(write_option), vmo_sharing_(vmo_sharing) {
unowned_vmo->duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo_);
}
VmoFile::VmoFile(zx::vmo vmo, size_t offset, size_t length, WriteOption write_option,
Sharing vmo_sharing)
: offset_(offset),
length_(length),
write_option_(write_option),
vmo_sharing_(vmo_sharing),
vmo_(std::move(vmo)) {}
VmoFile::~VmoFile() = default;
zx::vmo VmoFile::GetVmoForDescribe() {
zx::vmo result_vmo;
switch (vmo_sharing_) {
case Sharing::NONE:
break;
case Sharing::DUPLICATE:
// TODO(fxbug.dev/45287): As part of fxbug.dev/85334 it was discovered that Describe leaks
// writable handles even if the connection lacks OPEN_RIGHT_WRITABLE. If duplicate handles
// to the underlying VMO require specific rights, they should be obtained via GetBuffer(),
// or we need to allow the VmoFile node itself query the connection rights (since these are
// currently not available when handling the Describe call).
//
// If an exact/duplicate handle includes ZX_RIGHT_WRITE, we need to either track possible size
// changes to the backing VMO, provide a writable child slice, or explicitly set the
// content size and ensure the duplicate handle lacks ZX_RIGHT_SET_PROPERTY.
vmo_.duplicate(ZX_RIGHTS_BASIC | ZX_RIGHT_READ | ZX_RIGHT_MAP | ZX_RIGHT_GET_PROPERTY,
&result_vmo);
break;
case Sharing::CLONE_COW:
vmo_.create_child(ZX_VMO_CHILD_SNAPSHOT_AT_LEAST_ON_WRITE, offset_, length_, &result_vmo);
break;
}
return result_vmo;
}
void VmoFile::Describe(fuchsia::io::NodeInfo* out_info) {
zx::vmo client_vmo = GetVmoForDescribe();
switch (vmo_sharing_) {
case Sharing::NONE:
out_info->set_file(fuchsia::io::FileObject());
break;
case Sharing::DUPLICATE:
case Sharing::CLONE_COW:
if (!client_vmo.is_valid()) {
return;
}
out_info->vmofile() =
fuchsia::io::Vmofile{.vmo = std::move(client_vmo), .offset = offset_, .length = length_};
break;
}
}
void VmoFile::Describe2(fuchsia::io::ConnectionInfo* out_info) {
zx::vmo client_vmo = GetVmoForDescribe();
switch (vmo_sharing_) {
case Sharing::NONE:
out_info->set_representation(fuchsia::io::Representation::WithFile(fuchsia::io::FileInfo()));
break;
case Sharing::DUPLICATE:
case Sharing::CLONE_COW:
if (!client_vmo.is_valid()) {
return;
}
fuchsia::io::MemoryInfo mem_info;
mem_info.set_buffer(
fuchsia::mem::Range{.vmo = std::move(client_vmo), .offset = offset_, .size = length_});
out_info->set_representation(fuchsia::io::Representation::WithMemory(std::move(mem_info)));
break;
}
}
zx_status_t VmoFile::ReadAt(uint64_t length, uint64_t offset, std::vector<uint8_t>* out_data) {
if (length == 0u || offset >= length_) {
return ZX_OK;
}
size_t remaining_length = length_ - offset;
if (length > remaining_length) {
length = remaining_length;
}
out_data->resize(length);
return vmo_.read(out_data->data(), offset_ + offset, length);
}
zx_status_t VmoFile::WriteAt(std::vector<uint8_t> data, uint64_t offset, uint64_t* out_actual) {
if (write_option_ != WriteOption::WRITABLE) {
return ZX_ERR_NOT_SUPPORTED;
}
size_t length = data.size();
if (length == 0u) {
*out_actual = 0u;
return ZX_OK;
}
if (offset >= length_) {
return ZX_ERR_NO_SPACE;
}
size_t remaining_length = length_ - offset;
if (length > remaining_length) {
length = remaining_length;
}
zx_status_t status = vmo_.write(data.data(), offset_ + offset, length);
if (status == ZX_OK) {
*out_actual = length;
}
return status;
}
zx_status_t VmoFile::Truncate(uint64_t length) { return ZX_ERR_NOT_SUPPORTED; }
size_t VmoFile::GetCapacity() { return length_; }
size_t VmoFile::GetLength() { return length_; }
zx_status_t VmoFile::GetAttr(fuchsia::io::NodeAttributes* out_attributes) const {
fuchsia::io::OpenFlags flags = fuchsia::io::OpenFlags::RIGHT_READABLE;
if (write_option_ == WriteOption::WRITABLE) {
flags |= fuchsia::io::OpenFlags::RIGHT_WRITABLE;
}
out_attributes->mode = fuchsia::io::MODE_TYPE_FILE | static_cast<uint32_t>(flags);
out_attributes->id = fuchsia::io::INO_UNKNOWN;
out_attributes->content_size = length_;
out_attributes->storage_size = length_;
out_attributes->link_count = 1;
out_attributes->creation_time = 0;
out_attributes->modification_time = 0;
return ZX_OK;
}
NodeKind::Type VmoFile::GetKind() const {
return File::GetKind() | NodeKind::kVmo | NodeKind::kReadable |
(write_option_ == WriteOption::WRITABLE ? NodeKind::kWritable : 0);
}
} // namespace vfs