Commit 7a8a7167 authored by Jonas Termansen's avatar Jonas Termansen

Move readv/writev family and sendmsg/recvmsg into drivers.

parent 28229eb6
/*
* Copyright (c) 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
* Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
......@@ -17,16 +17,22 @@
* A file descriptor.
*/
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <assert.h>
#include <errno.h>
#include <fsmarshall-msg.h>
#include <limits.h>
#include <stdint.h>
#include <string.h>
#include <sortix/dirent.h>
#include <sortix/fcntl.h>
#ifndef IOV_MAX
#include <sortix/limits.h>
#endif
#include <sortix/mount.h>
#include <sortix/seek.h>
#include <sortix/stat.h>
......@@ -293,6 +299,36 @@ ssize_t Descriptor::read(ioctx_t* ctx, uint8_t* buf, size_t count)
return ret;
}
ssize_t Descriptor::readv(ioctx_t* ctx, const struct iovec* iov_ptr, int iovcnt)
{
if ( !(dflags & O_READ) )
return errno = EPERM, -1;
if ( iovcnt < 0 || IOV_MAX < iovcnt )
return errno = EINVAL, -1;
struct iovec* iov = new struct iovec[iovcnt];
if ( !iov )
return -1;
size_t iov_size = sizeof(struct iovec) * iovcnt;
if ( !ctx->copy_from_src(iov, iov_ptr, iov_size) )
return delete[] iov, -1;
int old_ctx_dflags = ctx->dflags;
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
if ( !IsSeekable() )
{
ssize_t result = vnode->readv(ctx, iov, iovcnt);
ctx->dflags = old_ctx_dflags;
delete[] iov;
return result;
}
ScopedLock lock(&current_offset_lock);
ssize_t ret = vnode->preadv(ctx, iov, iovcnt, current_offset);
if ( 0 <= ret )
current_offset += ret;
ctx->dflags = old_ctx_dflags;
delete[] iov;
return ret;
}
ssize_t Descriptor::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
{
if ( !(dflags & O_READ) )
......@@ -310,6 +346,27 @@ ssize_t Descriptor::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
return result;
}
ssize_t Descriptor::preadv(ioctx_t* ctx, const struct iovec* iov_ptr,
int iovcnt, off_t off)
{
if ( !(dflags & O_READ) )
return errno = EPERM, -1;
if ( off < 0 || iovcnt < 0 || IOV_MAX < iovcnt )
return errno = EINVAL, -1;
struct iovec* iov = new struct iovec[iovcnt];
if ( !iov )
return -1;
size_t iov_size = sizeof(struct iovec) * iovcnt;
if ( !ctx->copy_from_src(iov, iov_ptr, iov_size) )
return delete[] iov, -1;
int old_ctx_dflags = ctx->dflags;
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
ssize_t result = vnode->preadv(ctx, iov, iovcnt, off);
ctx->dflags = old_ctx_dflags;
delete[] iov;
return result;
}
ssize_t Descriptor::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
{
if ( !(dflags & O_WRITE) )
......@@ -344,7 +401,49 @@ ssize_t Descriptor::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
return ret;
}
ssize_t Descriptor::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off)
ssize_t Descriptor::writev(ioctx_t* ctx, const struct iovec* iov_ptr,
int iovcnt)
{
if ( !(dflags & O_WRITE) )
return errno = EPERM, -1;
if ( iovcnt < 0 || IOV_MAX < iovcnt )
return errno = EINVAL, -1;
struct iovec* iov = new struct iovec[iovcnt];
if ( !iov )
return -1;
size_t iov_size = sizeof(struct iovec) * iovcnt;
if ( !ctx->copy_from_src(iov, iov_ptr, iov_size) )
return delete[] iov, -1;
int old_ctx_dflags = ctx->dflags;
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
if ( !IsSeekable() )
{
ssize_t result = vnode->writev(ctx, iov, iovcnt);
ctx->dflags = old_ctx_dflags;
delete[] iov;
return result;
}
ScopedLock lock(&current_offset_lock);
if ( ctx->dflags & O_APPEND )
{
off_t end = vnode->lseek(ctx, 0, SEEK_END);
if ( end < 0 )
{
ctx->dflags = old_ctx_dflags;
return -1;
}
current_offset = end;
}
ssize_t ret = vnode->pwritev(ctx, iov, iovcnt, current_offset);
if ( 0 <= ret )
current_offset += ret;
ctx->dflags = old_ctx_dflags;
delete[] iov;
return ret;
}
ssize_t Descriptor::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
off_t off)
{
if ( !(dflags & O_WRITE) )
return errno = EPERM, -1;
......@@ -361,6 +460,27 @@ ssize_t Descriptor::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t
return result;
}
ssize_t Descriptor::pwritev(ioctx_t* ctx, const struct iovec* iov_ptr,
int iovcnt, off_t off)
{
if ( !(dflags & O_WRITE) )
return errno = EPERM, -1;
if ( off < 0 || iovcnt < 0 || IOV_MAX < iovcnt )
return errno = EINVAL, -1;
struct iovec* iov = new struct iovec[iovcnt];
if ( !iov )
return -1;
size_t iov_size = sizeof(struct iovec) * iovcnt;
if ( !ctx->copy_from_src(iov, iov_ptr, iov_size) )
return delete[] iov, -1;
int old_ctx_dflags = ctx->dflags;
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
ssize_t result = vnode->pwritev(ctx, iov, iovcnt, off);
ctx->dflags = old_ctx_dflags;
delete[] iov;
return result;
}
static inline bool valid_utimens_timespec(struct timespec ts)
{
return ts.tv_nsec < 1000000000 ||
......@@ -755,22 +875,56 @@ int Descriptor::listen(ioctx_t* ctx, int backlog)
ssize_t Descriptor::recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags)
{
if ( SIZE_MAX < count )
count = SSIZE_MAX;
int old_ctx_dflags = ctx->dflags;
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
if ( flags & MSG_DONTWAIT )
ctx->dflags |= O_NONBLOCK;
flags &= ~MSG_DONTWAIT;
ssize_t result = vnode->recv(ctx, buf, count, flags);
ctx->dflags = old_ctx_dflags;
return result;
}
ssize_t Descriptor::recvmsg(ioctx_t* ctx, struct msghdr* msg, int flags)
{
int old_ctx_dflags = ctx->dflags;
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
if ( flags & MSG_DONTWAIT )
ctx->dflags |= O_NONBLOCK;
flags &= ~MSG_DONTWAIT;
ssize_t result = vnode->recvmsg(ctx, msg, flags);
ctx->dflags = old_ctx_dflags;
return result;
}
ssize_t Descriptor::send(ioctx_t* ctx, const uint8_t* buf, size_t count, int flags)
{
if ( SIZE_MAX < count )
count = SSIZE_MAX;
int old_ctx_dflags = ctx->dflags;
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
if ( flags & MSG_DONTWAIT )
ctx->dflags |= O_NONBLOCK;
flags &= ~MSG_DONTWAIT;
ssize_t result = vnode->send(ctx, buf, count, flags);
ctx->dflags = old_ctx_dflags;
return result;
}
ssize_t Descriptor::sendmsg(ioctx_t* ctx, const struct msghdr* msg, int flags)
{
int old_ctx_dflags = ctx->dflags;
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
if ( flags & MSG_DONTWAIT )
ctx->dflags |= O_NONBLOCK;
flags &= ~MSG_DONTWAIT;
ssize_t result = vnode->sendmsg(ctx, msg, flags);
ctx->dflags = old_ctx_dflags;
return result;
}
int Descriptor::getsockopt(ioctx_t* ctx, int level, int option_name,
void* option_value, size_t* option_size_ptr)
{
......
/*
* Copyright (c) 2013 Jonas 'Sortie' Termansen.
* Copyright (c) 2013, 2014, 2017 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
......@@ -18,6 +18,7 @@
*/
#include <sys/types.h>
#include <sys/uio.h>
#include <assert.h>
#include <errno.h>
......@@ -309,91 +310,118 @@ void FileCache::InitializeFileData(off_t to_where)
}
}
ssize_t FileCache::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
ssize_t FileCache::preadv(ioctx_t* ctx, const struct iovec* iovs, int iovcnt,
off_t off)
{
ScopedLock lock(&fcache_mutex);
if ( off < 0 )
return errno = EINVAL, -1;
if ( file_size <= off )
return 0;
off_t available_bytes = file_size - off;
if ( (uintmax_t) available_bytes < (uintmax_t) count )
count = available_bytes;
if ( (size_t) SSIZE_MAX < count )
count = (size_t) SSIZE_MAX;
size_t sofar = 0;
while ( sofar < count )
ssize_t so_far = 0;
int iov_i = 0;
size_t iov_offset = 0;
while ( iov_i < iovcnt && so_far < SSIZE_MAX )
{
off_t current_off = off + (off_t) sofar;
size_t left = count - sofar;
off_t current_off = off + (off_t) so_far;
if ( file_size <= current_off )
break;
size_t maxcount = SSIZE_MAX - so_far;
if ( (uintmax_t) (file_size - current_off) < maxcount )
maxcount = file_size - current_off;
if ( maxcount == 0 )
break;
const struct iovec* iov = &iovs[iov_i];
uint8_t* buf = (uint8_t*) iov->iov_base + iov_offset;
size_t count = iov->iov_len - iov_offset;
if ( maxcount < count )
count = maxcount;
if ( count == 0 )
{
iov_i++;
iov_offset = 0;
continue;
}
size_t block_off = (size_t) (current_off % Page::Size());
size_t block_num = (size_t) (current_off / Page::Size());
size_t block_left = Page::Size() - block_off;
size_t amount_to_copy = left < block_left ? left : block_left;
size_t amount = count < block_left ? count : block_left;
assert(block_num < blocks_used);
BlockCacheBlock* block = blocks[block_num];
const uint8_t* block_data = kernel_block_cache->BlockData(block);
const uint8_t* src_data = block_data + block_off;
uint8_t* dest_buf = buf + sofar;
off_t end_at = current_off + (off_t) amount_to_copy;
if ( file_written < end_at )
InitializeFileData(end_at);
if ( !ctx->copy_to_dest(dest_buf, src_data, amount_to_copy) )
return sofar ? (ssize_t) sofar : -1;
sofar += amount_to_copy;
if ( file_written < current_off + (off_t) amount )
InitializeFileData(current_off + (off_t) amount);
if ( !ctx->copy_to_dest(buf, src_data, amount) )
return so_far ? (ssize_t) so_far : -1;
so_far += amount;
kernel_block_cache->MarkUsed(block);
iov_offset += amount;
if ( iov_offset == iov->iov_len )
{
iov_i++;
iov_offset = 0;
}
}
return (ssize_t) sofar;
return so_far;
}
ssize_t FileCache::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off)
ssize_t FileCache::pwritev(ioctx_t* ctx, const struct iovec* iovs, int iovcnt,
off_t off)
{
ScopedLock lock(&fcache_mutex);
if ( off < 0 )
return errno = EINVAL, -1;
off_t available_growth = OFF_MAX - off;
if ( (uintmax_t) available_growth < (uintmax_t) count )
count = (size_t) available_growth;
// TODO: Rather than doing an EOF - shouldn't errno be set to something like
// "Hey, the filesize limit has been reached"?
if ( (size_t) SSIZE_MAX < count )
count = (size_t) SSIZE_MAX;
off_t write_end = off + (off_t) count;
if ( file_size < write_end && !ChangeSize(write_end, false) )
{
if ( file_size < off )
return -1;
count = (size_t) (file_size - off);
write_end = off + (off_t) count;
}
assert(write_end <= file_size);
size_t sofar = 0;
while ( sofar < count )
ssize_t so_far = 0;
int iov_i = 0;
size_t iov_offset = 0;
while ( iov_i < iovcnt && so_far < SSIZE_MAX )
{
off_t current_off = off + (off_t) sofar;
size_t left = count - sofar;
off_t current_off = off + (off_t) so_far;
size_t maxcount = SSIZE_MAX - so_far;
if ( (uintmax_t) (OFF_MAX - current_off) < maxcount )
maxcount = OFF_MAX - current_off;
const struct iovec* iov = &iovs[iov_i];
uint8_t* buf = (uint8_t*) iov->iov_base + iov_offset;
size_t count = iov->iov_len - iov_offset;
if ( maxcount < count )
count = maxcount;
if ( count == 0 )
{
if ( so_far == 0 && maxcount == 0 && iov->iov_len != 0 )
return errno = ENOSPC, -1;
iov_i++;
iov_offset = 0;
continue;
}
off_t write_end = current_off + count;
if ( file_size < write_end && !ChangeSize(write_end, false) )
{
if ( file_size <= current_off )
return -1;
if ( (uintmax_t) (file_size - current_off) < count )
count = file_size - current_off;
}
size_t block_off = (size_t) (current_off % Page::Size());
size_t block_num = (size_t) (current_off / Page::Size());
size_t block_left = Page::Size() - block_off;
size_t amount_to_copy = left < block_left ? left : block_left;
size_t amount = count < block_left ? count : block_left;
assert(block_num < blocks_used);
BlockCacheBlock* block = blocks[block_num];
uint8_t* block_data = kernel_block_cache->BlockData(block);
uint8_t* data = block_data + block_off;
const uint8_t* src_buf = buf + sofar;
off_t begin_at = off + (off_t) sofar;
off_t end_at = current_off + (off_t) amount_to_copy;
if ( file_written < begin_at )
InitializeFileData(begin_at);
if ( file_written < current_off )
InitializeFileData(current_off);
assert(amount);
modified = true; /* Unconditionally - copy_from_src can fail midway. */
if ( !ctx->copy_from_src(data, src_buf, amount_to_copy) )
return sofar ? (ssize_t) sofar : -1;
if ( file_written < end_at )
file_written = end_at;
sofar += amount_to_copy;
if ( !ctx->copy_from_src(data, buf, amount) )
return so_far ? (ssize_t) so_far : -1;
if ( file_written < current_off + (off_t) amount )
file_written = current_off + (off_t) amount;
so_far += amount;
kernel_block_cache->MarkModified(block);
iov_offset += amount;
if ( iov_offset == iov->iov_len )
{
iov_i++;
iov_offset = 0;
}
}
return (ssize_t) sofar;
return so_far;
}
int FileCache::truncate(ioctx_t* /*ctx*/, off_t length)
......
......@@ -18,6 +18,7 @@
*/
#include <sys/types.h>
#include <sys/uio.h>
#include <assert.h>
#include <errno.h>
......@@ -124,6 +125,7 @@ File::File(InodeType inode_type, mode_t type, dev_t dev, ino_t ino, uid_t owner,
this->stat_blksize = 1;
this->dev = dev;
this->ino = ino;
this->supports_iovec = true;
}
File::~File()
......@@ -147,14 +149,16 @@ off_t File::lseek(ioctx_t* ctx, off_t offset, int whence)
return fcache.lseek(ctx, offset, whence);
}
ssize_t File::pread(ioctx_t* ctx, uint8_t* dest, size_t count, off_t off)
ssize_t File::preadv(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
off_t off)
{
return fcache.pread(ctx, dest, count, off);
return fcache.preadv(ctx, iov, iovcnt, off);
}
ssize_t File::pwrite(ioctx_t* ctx, const uint8_t* src, size_t count, off_t off)
ssize_t File::pwritev(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
off_t off)
{
ssize_t ret = fcache.pwrite(ctx, src, count, off);
ssize_t ret = fcache.pwritev(ctx, iov, iovcnt, off);
if ( 0 < ret )
{
ScopedLock lock(&metalock);
......@@ -170,7 +174,11 @@ ssize_t File::readlink(ioctx_t* ctx, char* buf, size_t bufsize)
return errno = EINVAL, -1;
if ( (size_t) SSIZE_MAX < bufsize )
bufsize = SSIZE_MAX;
return fcache.pread(ctx, (uint8_t*) buf, bufsize, 0);
struct iovec iov;
memset(&iov, 0, sizeof(iov));
iov.iov_base = buf;
iov.iov_len = bufsize;
return fcache.preadv(ctx, &iov, 1, 0);
}
ssize_t File::tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count)
......
......@@ -41,10 +41,10 @@ public:
virtual ~File();
virtual int truncate(ioctx_t* ctx, off_t length);
virtual off_t lseek(ioctx_t* ctx, off_t offset, int whence);
virtual ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count,
off_t off);
virtual ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
virtual ssize_t preadv(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
off_t off);
virtual ssize_t pwritev(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
off_t off);
virtual ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
virtual ssize_t tcgetblob(ioctx_t* ctx, const char* name, void* buffer,
size_t count);
......
/*
* Copyright (c) 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
* Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
......@@ -204,11 +204,17 @@ public:
virtual int truncate(ioctx_t* ctx, off_t length);
virtual off_t lseek(ioctx_t* ctx, off_t offset, int whence);
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
virtual ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count,
off_t off);
virtual ssize_t readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
virtual ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off);
virtual ssize_t preadv(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
off_t off);
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
virtual ssize_t writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
virtual ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
off_t off);
virtual ssize_t pwritev(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
off_t off);
virtual int utimens(ioctx_t* ctx, const struct timespec* times);
virtual int isatty(ioctx_t* ctx);
virtual ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent,
......@@ -242,8 +248,10 @@ public:
virtual int connect(ioctx_t* ctx, const uint8_t* addr, size_t addrlen);
virtual int listen(ioctx_t* ctx, int backlog);
virtual ssize_t recv(ioctx_t* ctx, uint8_t* buf, size_t count, int flags);
virtual ssize_t recvmsg(ioctx_t* ctx, struct msghdr* msg, int flags);
virtual ssize_t send(ioctx_t* ctx, const uint8_t* buf, size_t count,
int flags);
virtual ssize_t sendmsg(ioctx_t* ctx, const struct msghdr* msg, int flags);
virtual int getsockopt(ioctx_t* ctx, int level, int option_name,
void* option_value, size_t* option_size_ptr);
virtual int setsockopt(ioctx_t* ctx, int level, int option_name,
......@@ -898,6 +906,32 @@ ssize_t Unode::read(ioctx_t* ctx, uint8_t* buf, size_t count)
return ret;
}
ssize_t Unode::readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
{
ssize_t sofar = 0;
for ( int i = 0; i < iovcnt && sofar < SSIZE_MAX; i++ )
{
size_t maxcount = SSIZE_MAX - sofar;
uint8_t* buf = (uint8_t*) iov[i].iov_base;
size_t count = iov[i].iov_len;
if ( maxcount < count )
count = maxcount;
int old_dflags = ctx->dflags;
if ( sofar )
ctx->dflags |= O_NONBLOCK;
ssize_t amount = read(ctx, buf, count);
ctx->dflags = old_dflags;
if ( amount < 0 )
return sofar ? sofar : -1;
if ( amount == 0 )
break;
sofar += amount;
if ( (size_t) amount < count )
break;
}
return sofar;
}
ssize_t Unode::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
{
Channel* channel = server->Connect(ctx);
......@@ -921,6 +955,36 @@ ssize_t Unode::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
return ret;
}
ssize_t Unode::preadv(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
off_t off)
{
ssize_t sofar = 0;
for ( int i = 0; i < iovcnt && sofar < SSIZE_MAX; i++ )
{
size_t maxcount = SSIZE_MAX - sofar;
uint8_t* buf = (uint8_t*) iov[i].iov_base;
size_t count = iov[i].iov_len;
if ( maxcount < count )
count = maxcount;
off_t offset;
if ( __builtin_add_overflow(off, sofar, &offset) )
return sofar ? sofar : (errno = EOVERFLOW, -1);
int old_dflags = ctx->dflags;
if ( sofar )
ctx->dflags |= O_NONBLOCK;
ssize_t amount = pread(ctx, buf, count, offset);
ctx->dflags = old_dflags;
if ( amount < 0 )
return sofar ? sofar : -1;
if ( amount == 0 )
break;
sofar += amount;
if ( (size_t) amount < count )
break;
}
return sofar;
}
ssize_t Unode::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
{
Channel* channel = server->Connect(ctx);
......@@ -945,6 +1009,32 @@ ssize_t Unode::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
return ret;
}
ssize_t Unode::writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt)
{
ssize_t sofar = 0;
for ( int i = 0; i < iovcnt && sofar < SSIZE_MAX; i++ )
{
size_t maxcount = SSIZE_MAX - sofar;
const uint8_t* buf = (uint8_t*) iov[i].iov_base;
size_t count = iov[i].iov_len;
if ( maxcount < count )
count = maxcount;
int old_dflags = ctx->dflags;
if ( sofar )
ctx->dflags |= O_NONBLOCK;
ssize_t amount = write(ctx, buf, count);
ctx->dflags = old_dflags;
if ( amount < 0 )
return sofar ? sofar : -1;
if ( amount == 0 )
break;
sofar += amount;
if ( (size_t) amount < count )
break;
}
return sofar;
}
ssize_t Unode::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off)
{
Channel* channel = server->Connect(ctx);
......@@ -970,6 +1060,36 @@ ssize_t Unode::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off)
return ret;
}
ssize_t Unode::pwritev(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
off_t off)
{
ssize_t sofar = 0;
for ( int i = 0; i < iovcnt && sofar < SSIZE_MAX; i++ )
{
size_t maxcount = SSIZE_MAX - sofar;
uint8_t* buf = (uint8_t*) iov[i].iov_base;
size_t count = iov[i].iov_len;
if ( maxcount < count )
count = maxcount;
off_t offset;
if ( __builtin_add_overflow(off, sofar, &offset) )
return sofar ? sofar : (errno = EOVERFLOW, -1);
int old_dflags = ctx->dflags;
if ( sofar )
ctx->dflags |= O_NONBLOCK;
ssize_t amount = pwrite(ctx, buf, count, offset);
ctx->dflags = old_dflags;
if ( amount < 0 )
return sofar ? sofar : -1;
if ( amount == 0 )
break;
sofar += amount;
if ( (size_t) amount < count )
break;
}
return sofar;
}
int Unode::utimens(ioctx_t* ctx, const struct timespec* times)
{
Channel* channel = server->Connect(ctx);
......@@ -1368,12 +1488,23 @@ ssize_t Unode::recv(ioctx_t* /*ctx*/, uint8_t* /*buf*/, size_t /*count*/,
return errno = ENOTSOCK, -1;
}
ssize_t Unode::recvmsg(ioctx_t* /*ctx*/, struct msghdr* /*msg*/, int /*flags*/)
{
return errno = ENOTSOCK, -1;
}
ssize_t Unode::send(ioctx_t* /*ctx*/, const uint8_t* /*buf*/, size_t /*count*/,
int /*flags*/)
{
return errno = ENOTSOCK, -1;
}
ssize_t Unode::sendmsg(ioctx_t* /*ctx*/, const struct msghdr* /*msg*/,
int /*flags*/)
{
return errno = ENOTSOCK, -1;
}
int Unode::getsockopt(ioctx_t* ctx, int level, int option_name,
void* option_value, size_t* option_size_ptr)
{
......
/*
* Copyright (c) 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
* Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
......@@ -30,6 +30,8 @@
#include <sortix/kernel/refcount.h>
struct dirent;
struct iovec;
struct msghdr;
struct stat;
struct statvfs;
struct termios;
......@@ -64,9 +66,15 @@ public:
int truncate(ioctx_t* ctx, off_t length);
off_t lseek(ioctx_t* ctx, off_t offset, int whence);
ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
ssize_t readv(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
ssize_t pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off);
ssize_t preadv(ioctx_t* ctx, const struct iovec* iov, int iovcnt,
off_t off);
ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
ssize_t writev(ioctx_t* ctx, const struct iovec* iov, int iovcnt);
ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off);