blob: 80c0ecd25930d52af34ed45322788dc20c9336bc [file] [log] [blame]
// Copyright 2018 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/zxio/ops.h>
#include <lib/zxio/zxio.h>
#include <zircon/syscalls.h>
// The private fields of a |zxio_t| object.
//
// In |ops.h|, the |zxio_t| struct is defined as opaque. Clients of the zxio
// library are forbidden from relying upon the structure of |zxio_t| objects.
// To avoid temptation, the details of the structure are defined only in this
// implementation file and are not visible in the header.
typedef struct zxio_internal {
const zxio_ops_t* ops;
uint64_t reserved[3];
} zxio_internal_t;
static_assert(sizeof(zxio_t) == sizeof(zxio_internal_t), "zxio_t should match zxio_internal_t");
typedef struct zxio_dirent_iterator_internal {
zxio_t* io;
uint8_t* buffer;
uint64_t capacity;
uint64_t count;
uint64_t index;
uint64_t opaque[3];
} zxio_dirent_iterator_internal_t;
static_assert(sizeof(zxio_dirent_iterator_t) == sizeof(zxio_dirent_iterator_internal_t),
"zxio_dirent_iterator_t should match zxio_dirent_iterator_internal_t");
static_assert(ZXIO_READABLE == __ZX_OBJECT_READABLE, "ZXIO signal bits should match ZX");
static_assert(ZXIO_WRITABLE == __ZX_OBJECT_WRITABLE, "ZXIO signal bits should match ZX");
static_assert(ZXIO_READ_DISABLED == ZX_SOCKET_PEER_WRITE_DISABLED,
"ZXIO signal bits should match ZX");
static_assert(ZXIO_WRITE_DISABLED == ZX_SOCKET_WRITE_DISABLED, "ZXIO signal bits should match ZX");
static_assert(ZXIO_READ_THRESHOLD == ZX_SOCKET_READ_THRESHOLD, "ZXIO signal bits should match ZX");
static_assert(ZXIO_WRITE_THRESHOLD == ZX_SOCKET_WRITE_THRESHOLD,
"ZXIO signal bits should match ZX");
void zxio_init(zxio_t* io, const zxio_ops_t* ops) {
zxio_internal_t* zio = (zxio_internal_t*)io;
memset(zio, 0, sizeof(*zio));
zio->ops = ops;
}
zx_status_t zxio_release(zxio_t* io, zx_handle_t* out_handle) {
zxio_internal_t* zio = (zxio_internal_t*)io;
return zio->ops->release(io, out_handle);
}
zx_status_t zxio_clone(zxio_t* io, zx_handle_t* out_handle) {
zxio_internal_t* zio = (zxio_internal_t*)io;
return zio->ops->clone(io, out_handle);
}
zx_status_t zxio_close(zxio_t* io) {
zxio_internal_t* zio = (zxio_internal_t*)io;
return zio->ops->close(io);
}
zx_status_t zxio_wait_one(zxio_t* io, zxio_signals_t signals, zx_time_t deadline,
zxio_signals_t* out_observed) {
zx_handle_t handle = ZX_HANDLE_INVALID;
zx_signals_t zx_signals = ZX_SIGNAL_NONE;
zxio_wait_begin(io, signals, &handle, &zx_signals);
if (handle == ZX_HANDLE_INVALID) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_signals_t zx_observed = ZX_SIGNAL_NONE;
zx_status_t status = zx_object_wait_one(handle, zx_signals, deadline, &zx_observed);
if (status != ZX_OK) {
return status;
}
zxio_wait_end(io, zx_signals, out_observed);
return ZX_OK;
}
void zxio_wait_begin(zxio_t* io, zxio_signals_t zxio_signals, zx_handle_t* out_handle,
zx_signals_t* out_zx_signals) {
zxio_internal_t* zio = (zxio_internal_t*)io;
return zio->ops->wait_begin(io, zxio_signals, out_handle, out_zx_signals);
}
void zxio_wait_end(zxio_t* io, zx_signals_t zx_signals, zxio_signals_t* out_zxio_signals) {
zxio_internal_t* zio = (zxio_internal_t*)io;
return zio->ops->wait_end(io, zx_signals, out_zxio_signals);
}
zx_status_t zxio_sync(zxio_t* io) {
zxio_internal_t* zio = (zxio_internal_t*)io;
return zio->ops->sync(io);
}
zx_status_t zxio_attr_get(zxio_t* io, zxio_node_attr_t* out_attr) {
zxio_internal_t* zio = (zxio_internal_t*)io;
return zio->ops->attr_get(io, out_attr);
}
zx_status_t zxio_attr_set(zxio_t* io, uint32_t flags, const zxio_node_attr_t* attr) {
zxio_internal_t* zio = (zxio_internal_t*)io;
return zio->ops->attr_set(io, flags, attr);
}
zx_status_t zxio_read(zxio_t* io, void* buffer, size_t capacity, zxio_flags_t flags,
size_t* out_actual) {
const zx_iovec_t vector = {
.buffer = buffer,
.capacity = capacity,
};
return zxio_read_vector(io, &vector, 1, flags, out_actual);
}
zx_status_t zxio_read_at(zxio_t* io, zx_off_t offset, void* buffer, size_t capacity,
zxio_flags_t flags, size_t* out_actual) {
const zx_iovec_t vector = {
.buffer = buffer,
.capacity = capacity,
};
return zxio_read_vector_at(io, offset, &vector, 1, flags, out_actual);
}
zx_status_t zxio_write(zxio_t* io, const void* buffer, size_t capacity, zxio_flags_t flags,
size_t* out_actual) {
const zx_iovec_t vector = {
.buffer = const_cast<void*>(buffer),
.capacity = capacity,
};
return zxio_write_vector(io, &vector, 1, flags, out_actual);
}
zx_status_t zxio_write_at(zxio_t* io, zx_off_t offset, const void* buffer, size_t capacity,
zxio_flags_t flags, size_t* out_actual) {
const zx_iovec_t vector = {
.buffer = const_cast<void*>(buffer),
.capacity = capacity,
};
return zxio_write_vector_at(io, offset, &vector, 1, flags, out_actual);
}
zx_status_t zxio_read_vector(zxio_t* io, const zx_iovec_t* vector, size_t vector_count,
zxio_flags_t flags, size_t* out_actual) {
auto zio = (zxio_internal_t*)io;
return zio->ops->read_vector(io, vector, vector_count, flags, out_actual);
}
zx_status_t zxio_read_vector_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) {
auto zio = (zxio_internal_t*)io;
return zio->ops->read_vector_at(io, offset, vector, vector_count, flags, out_actual);
}
zx_status_t zxio_write_vector(zxio_t* io, const zx_iovec_t* vector, size_t vector_count,
zxio_flags_t flags, size_t* out_actual) {
auto zio = (zxio_internal_t*)io;
return zio->ops->write_vector(io, vector, vector_count, flags, out_actual);
}
zx_status_t zxio_write_vector_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) {
auto zio = (zxio_internal_t*)io;
return zio->ops->write_vector_at(io, offset, vector, vector_count, flags, out_actual);
}
zx_status_t zxio_seek(zxio_t* io, zx_off_t offset, zxio_seek_origin_t start, size_t* out_offset) {
zxio_internal_t* zio = (zxio_internal_t*)io;
return zio->ops->seek(io, offset, start, out_offset);
}
zx_status_t zxio_truncate(zxio_t* io, size_t length) {
zxio_internal_t* zio = (zxio_internal_t*)io;
return zio->ops->truncate(io, length);
}
zx_status_t zxio_flags_get(zxio_t* io, uint32_t* out_flags) {
zxio_internal_t* zio = (zxio_internal_t*)io;
return zio->ops->flags_get(io, out_flags);
}
zx_status_t zxio_flags_set(zxio_t* io, uint32_t flags) {
zxio_internal_t* zio = (zxio_internal_t*)io;
return zio->ops->flags_set(io, flags);
}
zx_status_t zxio_token_get(zxio_t* io, zx_handle_t* out_token) {
zxio_internal_t* zio = (zxio_internal_t*)io;
return zio->ops->token_get(io, out_token);
}
zx_status_t zxio_vmo_get(zxio_t* io, uint32_t flags, zx_handle_t* out_vmo, size_t* out_size) {
zxio_internal_t* zio = (zxio_internal_t*)io;
return zio->ops->vmo_get(io, flags, out_vmo, out_size);
}
zx_status_t zxio_vmo_get_copy(zxio_t* io, zx_handle_t* out_vmo, size_t* out_size) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t zxio_vmo_get_clone(zxio_t* io, zx_handle_t* out_vmo, size_t* out_size) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t zxio_vmo_get_exact(zxio_t* io, zx_handle_t* out_vmo, size_t* out_size) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t zxio_open(zxio_t* directory, uint32_t flags, uint32_t mode, const char* path,
zxio_t** out_io) {
zxio_internal_t* zio = (zxio_internal_t*)directory;
return zio->ops->open(directory, flags, mode, path, out_io);
}
zx_status_t zxio_open_async(zxio_t* directory, uint32_t flags, uint32_t mode, const char* path,
size_t path_len, zx_handle_t request) {
zxio_internal_t* zio = (zxio_internal_t*)directory;
return zio->ops->open_async(directory, flags, mode, path, path_len, request);
}
zx_status_t zxio_unlink(zxio_t* directory, const char* path) {
zxio_internal_t* zio = (zxio_internal_t*)directory;
return zio->ops->unlink(directory, path);
}
zx_status_t zxio_rename(zxio_t* old_directory, const char* old_path,
zx_handle_t new_directory_token, const char* new_path) {
zxio_internal_t* zio = (zxio_internal_t*)old_directory;
return zio->ops->rename(old_directory, old_path, new_directory_token, new_path);
}
zx_status_t zxio_link(zxio_t* src_directory, const char* src_path, zxio_t* dst_directory,
const char* dst_path) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t zxio_dirent_iterator_init(zxio_dirent_iterator_t* iterator, zxio_t* directory,
void* buffer, size_t capacity) {
zxio_internal_t* zio = (zxio_internal_t*)directory;
zxio_dirent_iterator_internal_t* iter = (zxio_dirent_iterator_internal_t*)iterator;
iter->io = directory;
iter->buffer = reinterpret_cast<uint8_t*>(buffer);
iter->capacity = capacity;
iter->count = 0;
iter->index = 0;
if (!zio->ops->readdir) {
return ZX_ERR_NOT_SUPPORTED;
}
return ZX_OK;
}
zx_status_t zxio_dirent_iterator_next(zxio_dirent_iterator_t* iterator, zxio_dirent_t** out_entry) {
zxio_dirent_iterator_internal_t* iter = (zxio_dirent_iterator_internal_t*)iterator;
zxio_internal_t* zio = (zxio_internal_t*)iter->io;
if (!zio->ops->readdir) {
return ZX_ERR_NOT_SUPPORTED;
}
if (iter->index >= iter->count) {
size_t count;
zx_status_t status = zio->ops->readdir(iter->io, iter->buffer, iter->capacity, &count);
if (status != ZX_OK) {
return status;
}
if (count == 0) {
return ZX_ERR_NOT_FOUND;
}
iter->count = count;
iter->index = 0;
}
auto entry = reinterpret_cast<zxio_dirent_t*>(&iter->buffer[iter->index]);
// Check if we can read the entry size.
if (iter->index + sizeof(zxio_dirent_t) > iter->count) {
// Should not happen
return ZX_ERR_INTERNAL;
}
size_t entry_size = sizeof(zxio_dirent_t) + entry->size;
// Check if we can read the whole entry.
if (iter->index + entry_size > iter->count) {
// Should not happen
return ZX_ERR_INTERNAL;
}
iter->index += entry_size;
*out_entry = entry;
return ZX_OK;
}
zx_status_t zxio_isatty(zxio_t* io, bool* tty) {
zxio_internal_t* zio = (zxio_internal_t*)io;
return zio->ops->isatty(io, tty);
}