blob: 5affcb45d7c2f36518fe8fced57b4b1759332667 [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 <fuchsia/io/llcpp/fidl.h>
#include <lib/zxio/inception.h>
#include <lib/zxio/null.h>
#include <lib/zxio/ops.h>
#include <sys/stat.h>
#include <zircon/syscalls.h>
#include "private.h"
static_assert(sizeof(zxio_vmo_t) <= sizeof(zxio_storage_t),
"zxio_vmo_t must fit inside zxio_storage_t.");
static zx_status_t zxio_vmo_destroy(zxio_t* io) {
auto file = reinterpret_cast<zxio_vmo_t*>(io);
file->~zxio_vmo_t();
return ZX_OK;
}
static zx_status_t zxio_vmo_release(zxio_t* io, zx_handle_t* out_handle) {
auto file = reinterpret_cast<zxio_vmo_t*>(io);
*out_handle = file->vmo.release();
return ZX_OK;
}
static zx_status_t zxio_vmo_clone(zxio_t* io, zx_handle_t* out_handle) {
auto file = reinterpret_cast<zxio_vmo_t*>(io);
zx::vmo vmo;
zx_status_t status = file->vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo);
*out_handle = vmo.release();
return status;
}
static zx_status_t zxio_vmo_attr_get(zxio_t* io, zxio_node_attributes_t* out_attr) {
auto file = reinterpret_cast<zxio_vmo_t*>(io);
*out_attr = {};
ZXIO_NODE_ATTR_SET(*out_attr, protocols, ZXIO_NODE_PROTOCOL_FILE | ZXIO_NODE_PROTOCOL_MEMORY);
ZXIO_NODE_ATTR_SET(*out_attr, abilities,
ZXIO_OPERATION_READ_BYTES | ZXIO_OPERATION_GET_ATTRIBUTES);
ZXIO_NODE_ATTR_SET(*out_attr, content_size, file->size);
return ZX_OK;
}
static zx_status_t zxio_vmo_readv(zxio_t* io, const zx_iovec_t* vector, size_t vector_count,
zxio_flags_t flags, size_t* out_actual) {
if (flags) {
return ZX_ERR_NOT_SUPPORTED;
}
auto file = reinterpret_cast<zxio_vmo_t*>(io);
sync_mutex_lock(&file->lock);
zx_status_t status =
zxio_vmo_do_vector(0, file->size, &file->offset, vector, vector_count, out_actual,
[&](void* buffer, zx_off_t offset, size_t capacity) {
return file->vmo.read(buffer, offset, capacity);
});
sync_mutex_unlock(&file->lock);
return status;
}
static zx_status_t zxio_vmo_readv_at(zxio_t* io, zx_off_t offset, const zx_iovec_t* vector,
size_t vector_count, zxio_flags_t flags, size_t* out_actual) {
if (flags) {
return ZX_ERR_NOT_SUPPORTED;
}
auto file = reinterpret_cast<zxio_vmo_t*>(io);
return zxio_vmo_do_vector(0, file->size, &offset, vector, vector_count, out_actual,
[&](void* buffer, zx_off_t offset, size_t capacity) {
return file->vmo.read(buffer, offset, capacity);
});
}
static zx_status_t zxio_vmo_writev(zxio_t* io, const zx_iovec_t* vector, size_t vector_count,
zxio_flags_t flags, size_t* out_actual) {
if (flags) {
return ZX_ERR_NOT_SUPPORTED;
}
auto file = reinterpret_cast<zxio_vmo_t*>(io);
sync_mutex_lock(&file->lock);
zx_status_t status =
zxio_vmo_do_vector(0, file->size, &file->offset, vector, vector_count, out_actual,
[&](void* buffer, zx_off_t offset, size_t capacity) {
return file->vmo.write(buffer, offset, capacity);
});
sync_mutex_unlock(&file->lock);
return status;
}
static zx_status_t zxio_vmo_writev_at(zxio_t* io, zx_off_t offset, const zx_iovec_t* vector,
size_t vector_count, zxio_flags_t flags, size_t* out_actual) {
if (flags) {
return ZX_ERR_NOT_SUPPORTED;
}
auto file = reinterpret_cast<zxio_vmo_t*>(io);
return zxio_vmo_do_vector(0, file->size, &offset, vector, vector_count, out_actual,
[&](void* buffer, zx_off_t offset, size_t capacity) {
return file->vmo.write(buffer, offset, capacity);
});
}
zx_status_t zxio_vmo_seek(zxio_t* io, zxio_seek_origin_t start, int64_t offset,
size_t* out_offset) {
auto file = reinterpret_cast<zxio_vmo_t*>(io);
sync_mutex_lock(&file->lock);
zx_off_t origin;
switch (start) {
case ZXIO_SEEK_ORIGIN_START:
origin = 0;
break;
case ZXIO_SEEK_ORIGIN_CURRENT:
origin = file->offset;
break;
case ZXIO_SEEK_ORIGIN_END:
origin = file->size;
break;
default:
sync_mutex_unlock(&file->lock);
return ZX_ERR_INVALID_ARGS;
}
zx_off_t at;
if (add_overflow(origin, offset, &at)) {
sync_mutex_unlock(&file->lock);
return ZX_ERR_OUT_OF_RANGE;
}
if (at > file->size) {
sync_mutex_unlock(&file->lock);
return ZX_ERR_OUT_OF_RANGE;
}
file->offset = at;
sync_mutex_unlock(&file->lock);
*out_offset = at;
return ZX_OK;
}
static constexpr zxio_ops_t zxio_vmo_ops = []() {
zxio_ops_t ops = zxio_default_ops;
ops.destroy = zxio_vmo_destroy;
ops.release = zxio_vmo_release;
ops.clone = zxio_vmo_clone;
ops.attr_get = zxio_vmo_attr_get;
ops.readv = zxio_vmo_readv;
ops.readv_at = zxio_vmo_readv_at;
ops.writev = zxio_vmo_writev;
ops.writev_at = zxio_vmo_writev_at;
ops.seek = zxio_vmo_seek;
return ops;
}();
zx_status_t zxio_vmo_init(zxio_storage_t* storage, zx::vmo vmo, zx_off_t offset) {
uint64_t size;
zx_status_t status = vmo.get_size(&size);
if (status != ZX_OK) {
return status;
}
auto file = new (storage) zxio_vmo_t{
.io = storage->io,
.vmo = std::move(vmo),
.size = size,
.offset = std::min(offset, size),
.lock = {},
};
zxio_init(&file->io, &zxio_vmo_ops);
return ZX_OK;
}