sortix-mirror/kernel/fs/user.cpp

1806 lines
47 KiB
C++
Raw Normal View History

/*
2021-02-16 21:19:50 +00:00
* Copyright (c) 2012-2017, 2021 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
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* fs/user.cpp
* User-space filesystem.
*/
2013-01-30 19:33:13 +00:00
#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
2013-05-16 15:58:16 +00:00
#include <timespec.h>
2013-01-30 19:33:13 +00:00
#include <sortix/dirent.h>
#include <sortix/fcntl.h>
#include <sortix/ioctl.h>
2013-01-30 19:33:13 +00:00
#include <sortix/stat.h>
#include <sortix/timespec.h>
2016-01-23 19:56:07 +00:00
#include <sortix/winsize.h>
2013-01-30 19:33:13 +00:00
#include <fsmarshall-msg.h>
2013-10-27 00:42:10 +00:00
#include <sortix/kernel/descriptor.h>
2013-01-30 19:33:13 +00:00
#include <sortix/kernel/inode.h>
#include <sortix/kernel/ioctx.h>
2013-10-27 00:42:10 +00:00
#include <sortix/kernel/kernel.h>
#include <sortix/kernel/kthread.h>
2013-01-30 19:33:13 +00:00
#include <sortix/kernel/mtable.h>
2021-02-16 21:19:50 +00:00
#include <sortix/kernel/poll.h>
#include <sortix/kernel/process.h>
2013-10-27 00:42:10 +00:00
#include <sortix/kernel/refcount.h>
#include <sortix/kernel/scheduler.h>
2013-10-27 00:42:10 +00:00
#include <sortix/kernel/syscall.h>
#include <sortix/kernel/thread.h>
2013-10-27 00:42:10 +00:00
#include <sortix/kernel/vnode.h>
2013-01-30 19:33:13 +00:00
namespace Sortix {
namespace UserFS {
class ChannelDirection;
class Channel;
class ChannelNode;
class Server;
class ServerNode;
class Unode;
class ChannelDirection
{
public:
ChannelDirection();
~ChannelDirection();
size_t Send(ioctx_t* ctx, const void* ptr, size_t least, size_t max);
size_t Recv(ioctx_t* ctx, void* ptr, size_t least, size_t max);
void SendClose();
void RecvClose();
private:
static const size_t BUFFER_SIZE = 8192;
uint8_t buffer[BUFFER_SIZE];
size_t buffer_used;
size_t buffer_offset;
kthread_mutex_t transfer_lock;
kthread_cond_t not_empty;
kthread_cond_t not_full;
bool still_reading;
bool still_writing;
public:
uintptr_t sender_system_tid;
uintptr_t receiver_system_tid;
2013-01-30 19:33:13 +00:00
};
class Channel
{
public:
Channel(ioctx_t* ioctx);
2013-01-30 19:33:13 +00:00
~Channel();
public:
void InformSystemTids(uintptr_t client_tid, uintptr_t server_tid);
2013-01-30 19:33:13 +00:00
public:
bool KernelSend(ioctx_t* ctx, const void* ptr, size_t count)
{
return KernelSend(ctx, ptr, count, count) == count;
}
size_t KernelSend(ioctx_t* ctx, const void* ptr, size_t least, size_t max);
bool KernelRecv(ioctx_t* ctx, void* ptr, size_t count)
{
return KernelRecv(ctx, ptr, count, count) == count;
}
size_t KernelRecv(ioctx_t* ctx, void* ptr, size_t least, size_t max);
void KernelClose();
public:
bool UserSend(ioctx_t* ctx, const void* ptr, size_t count)
{
return UserSend(ctx, ptr, count, count) == count;
}
size_t UserSend(ioctx_t* ctx, const void* ptr, size_t least, size_t max);
bool UserRecv(ioctx_t* ctx, void* ptr, size_t count)
{
return UserRecv(ctx, ptr, count, count) == count;
}
size_t UserRecv(ioctx_t* ctx, void* ptr, size_t least, size_t max);
void UserClose();
private:
kthread_mutex_t kernel_lock;
kthread_mutex_t user_lock;
kthread_mutex_t destruction_lock;
ChannelDirection from_kernel;
ChannelDirection from_user;
bool kernel_closed;
bool user_closed;
public:
uid_t uid;
gid_t gid;
2013-01-30 19:33:13 +00:00
};
class ChannelNode : public AbstractInode
{
public:
ChannelNode();
ChannelNode(Channel* channel);
virtual ~ChannelNode();
2013-01-30 19:33:13 +00:00
void Construct(Channel* channel);
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
private:
Channel* channel;
};
class Server : public Refcountable
{
public:
Server();
virtual ~Server();
void Disconnect();
2014-05-07 12:14:38 +00:00
void Unmount();
Channel* Connect(ioctx_t* ctx);
Channel* Accept(ioctx_t* ctx);
2013-01-30 19:33:13 +00:00
Ref<Inode> BootstrapNode(ino_t ino, mode_t type);
Ref<Inode> OpenNode(ino_t ino, mode_t type);
private:
kthread_mutex_t connect_lock;
kthread_cond_t connecting_cond;
kthread_cond_t connectable_cond;
uintptr_t listener_system_tid;
uintptr_t connecter_system_tid;
2013-01-30 19:33:13 +00:00
Channel* connecting;
bool disconnected;
2014-05-07 12:14:38 +00:00
bool unmounted;
2013-01-30 19:33:13 +00:00
};
class ServerNode : public AbstractInode
{
public:
ServerNode(Ref<Server> server);
virtual ~ServerNode();
virtual Ref<Inode> accept4(ioctx_t* ctx, uint8_t* addr, size_t* addrlen,
int flags);
2013-01-30 19:33:13 +00:00
private:
Ref<Server> server;
};
class Unode : public Inode
{
public:
Unode(Ref<Server> server, ino_t ino, mode_t type);
virtual ~Unode();
virtual bool pass();
virtual void unpass();
2013-01-30 19:33:13 +00:00
virtual void linked();
virtual void unlinked();
virtual int sync(ioctx_t* ctx);
virtual int stat(ioctx_t* ctx, struct stat* st);
virtual int statvfs(ioctx_t* ctx, struct statvfs* stvfs);
2013-01-30 19:33:13 +00:00
virtual int chmod(ioctx_t* ctx, mode_t mode);
virtual int chown(ioctx_t* ctx, uid_t owner, gid_t group);
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 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);
2013-01-30 19:33:13 +00:00
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);
2013-01-30 19:33:13 +00:00
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);
2016-02-24 15:29:37 +00:00
virtual int utimens(ioctx_t* ctx, const struct timespec* times);
2013-01-30 19:33:13 +00:00
virtual int isatty(ioctx_t* ctx);
2015-11-20 01:57:09 +00:00
virtual ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent,
size_t size, off_t start);
2013-01-30 19:33:13 +00:00
virtual Ref<Inode> open(ioctx_t* ctx, const char* filename, int flags,
mode_t mode);
2016-10-22 21:47:28 +00:00
virtual Ref<Inode> factory(ioctx_t* ctx, const char* filename, int flags,
mode_t mode);
2013-01-30 19:33:13 +00:00
virtual int mkdir(ioctx_t* ctx, const char* filename, mode_t mode);
virtual int link(ioctx_t* ctx, const char* filename, Ref<Inode> node);
virtual int link_raw(ioctx_t* ctx, const char* filename, Ref<Inode> node);
virtual int unlink(ioctx_t* ctx, const char* filename);
virtual int unlink_raw(ioctx_t* ctx, const char* filename);
virtual int rmdir(ioctx_t* ctx, const char* filename);
virtual int rmdir_me(ioctx_t* ctx);
virtual int symlink(ioctx_t* ctx, const char* oldname,
const char* filename);
virtual ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
2013-12-20 20:55:05 +00:00
virtual int tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp);
virtual int ioctl(ioctx_t* ctx, int cmd, uintptr_t arg);
2013-06-12 00:18:07 +00:00
virtual int tcsetpgrp(ioctx_t* ctx, pid_t pgid);
virtual pid_t tcgetpgrp(ioctx_t* ctx);
2013-01-30 19:33:13 +00:00
virtual int settermmode(ioctx_t* ctx, unsigned mode);
virtual int gettermmode(ioctx_t* ctx, unsigned* mode);
2012-12-29 22:09:09 +00:00
virtual int poll(ioctx_t* ctx, PollNode* node);
2012-12-20 15:19:07 +00:00
virtual int rename_here(ioctx_t* ctx, Ref<Inode> from, const char* oldname,
const char* newname);
virtual Ref<Inode> accept4(ioctx_t* ctx, uint8_t* addr, size_t* addrlen,
int flags);
2013-03-19 21:40:37 +00:00
virtual int bind(ioctx_t* ctx, const uint8_t* addr, size_t addrlen);
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);
2013-03-19 21:40:37 +00:00
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);
2014-02-28 16:10:08 +00:00
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,
const void* option_value, size_t option_size);
2014-05-05 19:36:40 +00:00
virtual ssize_t tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count);
virtual ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count);
2014-05-07 12:14:38 +00:00
virtual int unmounted(ioctx_t* ctx);
2016-01-23 19:56:07 +00:00
virtual int tcdrain(ioctx_t* ctx);
virtual int tcflow(ioctx_t* ctx, int action);
virtual int tcflush(ioctx_t* ctx, int queue_selector);
virtual int tcgetattr(ioctx_t* ctx, struct termios* tio);
virtual pid_t tcgetsid(ioctx_t* ctx);
virtual int tcsendbreak(ioctx_t* ctx, int duration);
virtual int tcsetattr(ioctx_t* ctx, int actions, const struct termios* tio);
2016-08-06 13:44:37 +00:00
virtual int shutdown(ioctx_t* ctx, int how);
virtual int getpeername(ioctx_t* ctx, uint8_t* addr, size_t* addrsize);
virtual int getsockname(ioctx_t* ctx, uint8_t* addr, size_t* addrsize);
2013-01-30 19:33:13 +00:00
private:
bool SendMessage(Channel* channel, size_t type, void* ptr, size_t size,
size_t extra = 0);
bool RecvMessage(Channel* channel, size_t type, void* ptr, size_t size);
void RecvError(Channel* channel);
bool RecvBoolean(Channel* channel);
void UnexpectedResponse(Channel* channel, struct fsm_msg_header* hdr);
private:
ioctx_t kctx;
Ref<Server> server;
};
//
// Implementation of Channel Directory.
//
ChannelDirection::ChannelDirection()
{
buffer_used = 0;
buffer_offset = 0;
transfer_lock = KTHREAD_MUTEX_INITIALIZER;
not_empty = KTHREAD_COND_INITIALIZER;
not_full = KTHREAD_COND_INITIALIZER;
still_reading = true;
still_writing = true;
sender_system_tid = 0;
receiver_system_tid = 0;
2013-01-30 19:33:13 +00:00
}
ChannelDirection::~ChannelDirection()
{
}
size_t ChannelDirection::Send(ioctx_t* ctx, const void* ptr, size_t least, size_t max)
{
const uint8_t* src = (const uint8_t*) ptr;
size_t sofar = 0;
CurrentThread()->yield_to_tid = receiver_system_tid;
2013-01-30 19:33:13 +00:00
ScopedLock inner_lock(&transfer_lock);
sender_system_tid = CurrentThread()->system_tid;
2013-01-30 19:33:13 +00:00
while ( true )
{
while ( true )
{
if ( !still_reading )
return errno = ECONNRESET, sofar;
2013-01-30 19:33:13 +00:00
if ( buffer_used < BUFFER_SIZE )
break;
if ( least <= sofar )
return sofar;
if ( !kthread_cond_wait_signal(&not_full, &transfer_lock) )
return errno = EINTR, sofar;
}
size_t use_offset = (buffer_offset + buffer_used) % BUFFER_SIZE;
size_t count = max - sofar;
size_t available_to_end = BUFFER_SIZE - use_offset;
size_t available = BUFFER_SIZE - buffer_used;
if ( available_to_end < available )
available = available_to_end;
if ( available < count )
count = available;
2014-09-30 15:42:24 +00:00
if ( !ctx->copy_from_src(buffer + use_offset, src + sofar, count) )
2013-01-30 19:33:13 +00:00
return sofar;
if ( !buffer_used )
kthread_cond_signal(&not_empty);
buffer_used += count;
sofar += count;
if ( sofar == max )
return sofar;
}
}
size_t ChannelDirection::Recv(ioctx_t* ctx, void* ptr, size_t least, size_t max)
{
uint8_t* dst = (uint8_t*) ptr;
size_t sofar = 0;
CurrentThread()->yield_to_tid = sender_system_tid;
2013-01-30 19:33:13 +00:00
ScopedLock inner_lock(&transfer_lock);
receiver_system_tid = CurrentThread()->system_tid;
2013-01-30 19:33:13 +00:00
while ( true )
{
while ( true )
{
if ( buffer_used )
break;
if ( least <= sofar )
return sofar;
if ( !still_writing )
return errno = ECONNRESET, sofar;
2013-01-30 19:33:13 +00:00
if ( !kthread_cond_wait_signal(&not_empty, &transfer_lock) )
return errno = EINTR, sofar;
}
size_t use_offset = buffer_offset;
size_t count = max - sofar;
size_t available_to_end = BUFFER_SIZE - use_offset;
size_t available = buffer_used;
if ( available_to_end < available )
available = available_to_end;
if ( available < count )
count = available;
2014-09-30 15:42:24 +00:00
if ( !ctx->copy_to_dest(dst + sofar, buffer + use_offset, count) )
2013-01-30 19:33:13 +00:00
return sofar;
if ( buffer_used == BUFFER_SIZE )
kthread_cond_signal(&not_full);
buffer_offset = (buffer_offset + count) % BUFFER_SIZE;
buffer_used -= count;
sofar += count;
if ( sofar == max )
return sofar;
}
}
void ChannelDirection::SendClose()
{
ScopedLock lock(&transfer_lock);
still_writing = false;
kthread_cond_signal(&not_empty);
}
void ChannelDirection::RecvClose()
{
ScopedLock lock(&transfer_lock);
still_reading = false;
2013-01-30 19:33:13 +00:00
kthread_cond_signal(&not_full);
}
//
// Implementation of Channel.
//
Channel::Channel(ioctx_t* ctx)
2013-01-30 19:33:13 +00:00
{
kernel_lock = KTHREAD_MUTEX_INITIALIZER;
user_lock = KTHREAD_MUTEX_INITIALIZER;
destruction_lock = KTHREAD_MUTEX_INITIALIZER;
user_closed = false;
kernel_closed = false;
uid = ctx ? ctx->uid : 0;
gid = ctx ? ctx->gid : 0;
2013-01-30 19:33:13 +00:00
}
Channel::~Channel()
{
}
void Channel::InformSystemTids(uintptr_t client_tid, uintptr_t server_tid)
{
from_kernel.sender_system_tid = client_tid;
from_kernel.receiver_system_tid = server_tid;
from_user.sender_system_tid = server_tid;
from_user.receiver_system_tid = client_tid;
}
2013-01-30 19:33:13 +00:00
size_t Channel::KernelSend(ioctx_t* ctx, const void* ptr, size_t least,
size_t max)
{
ScopedLockSignal outer_lock(&kernel_lock);
if ( !outer_lock.IsAcquired() )
return errno = EINTR, 0;
size_t ret = from_kernel.Send(ctx, ptr, least, max);
CurrentThread()->yield_to_tid = 0;
Scheduler::ScheduleTrueThread();
2013-01-30 19:33:13 +00:00
return ret;
}
size_t Channel::KernelRecv(ioctx_t* ctx, void* ptr, size_t least, size_t max)
{
ScopedLockSignal outer_lock(&kernel_lock);
if ( !outer_lock.IsAcquired() )
return errno = EINTR, 0;
CurrentThread()->yield_to_tid = 0;
Scheduler::ScheduleTrueThread();
2013-01-30 19:33:13 +00:00
return from_user.Recv(ctx, ptr, least, max);
}
void Channel::KernelClose()
{
// No lock needed, this thread is the last to use this object as kernel.
from_kernel.SendClose();
from_user.RecvClose();
kthread_mutex_lock(&destruction_lock);
kernel_closed = true;
bool delete_this = user_closed;
kthread_mutex_unlock(&destruction_lock);
if ( delete_this )
delete this;
}
size_t Channel::UserSend(ioctx_t* ctx, const void* ptr, size_t least,
size_t max)
{
ScopedLockSignal outer_lock(&user_lock);
if ( !outer_lock.IsAcquired() )
return errno = EINTR, 0;
size_t ret = from_user.Send(ctx, ptr, least, max);
CurrentThread()->yield_to_tid = 0;
Scheduler::ScheduleTrueThread();
return ret;
2013-01-30 19:33:13 +00:00
}
size_t Channel::UserRecv(ioctx_t* ctx, void* ptr, size_t least, size_t max)
{
ScopedLockSignal outer_lock(&user_lock);
if ( !outer_lock.IsAcquired() )
return errno = EINTR, 0;
size_t ret = from_kernel.Recv(ctx, ptr, least, max);
CurrentThread()->yield_to_tid = 0;
Scheduler::ScheduleTrueThread();
return ret;
2013-01-30 19:33:13 +00:00
}
void Channel::UserClose()
{
// No lock needed, this thread is the last to use this object as user.
from_kernel.RecvClose();
from_user.SendClose();
kthread_mutex_lock(&destruction_lock);
user_closed = true;
bool delete_this = kernel_closed;
kthread_mutex_unlock(&destruction_lock);
if ( delete_this )
delete this;
}
//
// Implementation of ChannelNode.
//
ChannelNode::ChannelNode()
{
channel = NULL;
}
ChannelNode::ChannelNode(Channel* channel)
{
Construct(channel);
}
ChannelNode::~ChannelNode()
{
if ( channel )
channel->UserClose();
}
void ChannelNode::Construct(Channel* channel)
{
inode_type = INODE_TYPE_STREAM;
this->channel = channel;
this->type = S_IFCHR;
this->dev = (dev_t) this;
this->ino = 0;
// TODO: Set uid, gid, mode.
}
ssize_t ChannelNode::read(ioctx_t* ctx, uint8_t* buf, size_t count)
{
return channel->UserRecv(ctx, buf, /*1*/ count, count);
}
ssize_t ChannelNode::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
{
return channel->UserSend(ctx, buf, /*1*/ count, count);
}
//
// Implementation of Server.
//
Server::Server()
{
connect_lock = KTHREAD_MUTEX_INITIALIZER;
connecting_cond = KTHREAD_COND_INITIALIZER;
connectable_cond = KTHREAD_COND_INITIALIZER;
listener_system_tid = 0;
2013-01-30 19:33:13 +00:00
connecting = NULL;
disconnected = false;
2014-05-07 12:14:38 +00:00
unmounted = false;
2013-01-30 19:33:13 +00:00
}
Server::~Server()
{
}
void Server::Disconnect()
{
ScopedLock lock(&connect_lock);
disconnected = true;
kthread_cond_signal(&connectable_cond);
}
2014-05-07 12:14:38 +00:00
void Server::Unmount()
{
ScopedLock lock(&connect_lock);
unmounted = true;
kthread_cond_signal(&connecting_cond);
}
Channel* Server::Connect(ioctx_t* ctx)
2013-01-30 19:33:13 +00:00
{
Channel* channel = new Channel(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return NULL;
CurrentThread()->yield_to_tid = listener_system_tid;
2013-01-30 19:33:13 +00:00
ScopedLock lock(&connect_lock);
while ( !disconnected && connecting )
{
2013-01-30 19:33:13 +00:00
if ( !kthread_cond_wait_signal(&connectable_cond, &connect_lock) )
{
CurrentThread()->yield_to_tid = 0;
2013-01-30 19:33:13 +00:00
delete channel;
return errno = EINTR, (Channel*) NULL;
}
}
CurrentThread()->yield_to_tid = 0;
if ( disconnected )
return delete channel, errno = ECONNREFUSED, (Channel*) NULL;
channel->InformSystemTids(CurrentThread()->system_tid, listener_system_tid);
2013-01-30 19:33:13 +00:00
connecting = channel;
kthread_cond_signal(&connecting_cond);
return channel;
}
Channel* Server::Accept(ioctx_t* ctx)
2013-01-30 19:33:13 +00:00
{
ScopedLock lock(&connect_lock);
listener_system_tid = CurrentThread()->system_tid;
2014-05-07 12:14:38 +00:00
while ( !connecting && !unmounted )
{
if ( ctx->dflags & O_NONBLOCK )
return errno = EWOULDBLOCK, (Channel*) NULL;
2013-01-30 19:33:13 +00:00
if ( !kthread_cond_wait_signal(&connecting_cond, &connect_lock) )
return errno = EINTR, (Channel*) NULL;
}
2014-05-07 12:14:38 +00:00
if ( unmounted )
return errno = ECONNRESET, (Channel*) NULL;
2013-01-30 19:33:13 +00:00
Channel* result = connecting;
connecting = NULL;
kthread_cond_signal(&connectable_cond);
return result;
}
Ref<Inode> Server::BootstrapNode(ino_t ino, mode_t type)
{
return Ref<Inode>(new Unode(Ref<Server>(this), ino, type));
}
Ref<Inode> Server::OpenNode(ino_t ino, mode_t type)
{
return BootstrapNode(ino, type);
}
//
// Implementation of ServerNode.
//
ServerNode::ServerNode(Ref<Server> server)
{
inode_type = INODE_TYPE_UNKNOWN;
this->server = server;
2014-05-07 12:14:38 +00:00
this->type = S_IFSOCK;
2013-01-30 19:33:13 +00:00
this->dev = (dev_t) this;
this->ino = 0;
// TODO: Set uid, gid, mode.
}
ServerNode::~ServerNode()
{
server->Disconnect();
2013-01-30 19:33:13 +00:00
}
Ref<Inode> ServerNode::accept4(ioctx_t* ctx, uint8_t* addr, size_t* addrlen,
int flags)
2013-01-30 19:33:13 +00:00
{
2014-05-07 12:14:38 +00:00
(void) addr;
if ( flags & ~(0) )
return errno = EINVAL, Ref<Inode>(NULL);
2014-05-07 12:14:38 +00:00
size_t out_addrlen = 0;
if ( addrlen && !ctx->copy_to_dest(addrlen, &out_addrlen, sizeof(out_addrlen)) )
return Ref<Inode>(NULL);
Ref<ChannelNode> node(new ChannelNode);
if ( !node )
return Ref<Inode>(NULL);
Channel* channel = server->Accept(ctx);
2014-05-07 12:14:38 +00:00
if ( !channel )
return Ref<Inode>(NULL);
node->Construct(channel);
return node;
2013-01-30 19:33:13 +00:00
}
//
// Implementation of Unode.
//
Unode::Unode(Ref<Server> server, ino_t ino, mode_t type)
{
SetupKernelIOCtx(&kctx);
this->server = server;
this->ino = ino;
this->dev = (dev_t) server.Get();
2013-01-30 19:33:13 +00:00
this->type = type;
// Let the remote know that the kernel is using this inode.
Thread* thread = CurrentThread();
bool saved = thread->force_no_signals;
thread->force_no_signals = true;
thread->DoUpdatePendingSignal();
if ( Channel* channel = server->Connect(NULL) )
{
struct fsm_req_refer msg;
msg.ino = ino;
SendMessage(channel, FSM_REQ_REFER, &msg, sizeof(msg));
channel->KernelClose();
}
thread->force_no_signals = saved;
thread->DoUpdatePendingSignal();
2013-01-30 19:33:13 +00:00
}
Unode::~Unode()
{
// Let the remote know that the kernel is no longer using this inode.
Thread* thread = CurrentThread();
bool saved = thread->force_no_signals;
thread->force_no_signals = true;
thread->DoUpdatePendingSignal();
if ( Channel* channel = server->Connect(NULL) )
{
struct fsm_req_unref msg;
msg.ino = ino;
SendMessage(channel, FSM_REQ_UNREF, &msg, sizeof(msg));
channel->KernelClose();
}
thread->force_no_signals = saved;
thread->DoUpdatePendingSignal();
2013-01-30 19:33:13 +00:00
}
bool Unode::SendMessage(Channel* channel, size_t type, void* ptr, size_t size,
size_t extra)
{
struct fsm_msg_header hdr;
hdr.msgtype = type;
hdr.msgsize = size + extra;
hdr.uid = channel->uid;
hdr.gid = channel->gid;
2013-01-30 19:33:13 +00:00
if ( !channel->KernelSend(&kctx, &hdr, sizeof(hdr)) )
return false;
if ( !channel->KernelSend(&kctx, ptr, size) )
return false;
return true;
}
bool Unode::RecvMessage(Channel* channel, size_t type, void* ptr, size_t size)
{
struct fsm_msg_header resp_hdr;
if ( !channel->KernelRecv(&kctx, &resp_hdr, sizeof(resp_hdr)) )
return false;
if ( resp_hdr.msgtype != type )
{
UnexpectedResponse(channel, &resp_hdr);
return false;
}
return !ptr || !size || channel->KernelRecv(&kctx, ptr, size);
}
void Unode::RecvError(Channel* channel)
{
SetupKernelIOCtx(&kctx);
struct fsm_resp_error resp;
if ( channel->KernelRecv(&kctx, &resp, sizeof(resp)) )
errno = resp.errnum;
// In case of error, errno is set to that error.
}
bool Unode::RecvBoolean(Channel* channel)
{
struct fsm_msg_header resp_hdr;
if ( !channel->KernelRecv(&kctx, &resp_hdr, sizeof(resp_hdr)) )
return false;
if ( resp_hdr.msgtype == FSM_RESP_SUCCESS )
return true;
UnexpectedResponse(channel, &resp_hdr);
return false;
}
void Unode::UnexpectedResponse(Channel* channel, struct fsm_msg_header* hdr)
{
if ( hdr->msgtype == FSM_RESP_ERROR )
RecvError(channel);
else
errno = EIO;
}
bool Unode::pass()
{
return true;
}
void Unode::unpass()
{
}
2013-01-30 19:33:13 +00:00
void Unode::linked()
{
}
void Unode::unlinked()
{
}
int Unode::sync(ioctx_t* ctx)
2013-01-30 19:33:13 +00:00
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_sync msg;
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_SYNC, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::stat(ioctx_t* ctx, struct stat* st)
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_stat msg;
struct fsm_resp_stat resp;
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_STAT, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_STAT, &resp, sizeof(resp)) &&
(resp.st.st_dev = (dev_t) server.Get(), true) &&
2013-01-30 19:33:13 +00:00
ctx->copy_to_dest(st, &resp.st, sizeof(*st)) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::statvfs(ioctx_t* ctx, struct statvfs* stvfs)
{
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_statvfs msg;
struct fsm_resp_statvfs resp;
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_STATVFS, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_STATVFS, &resp, sizeof(resp)) &&
(resp.stvfs.f_fsid = (dev_t) server.Get(), true) &&
(resp.stvfs.f_flag |= ST_NOSUID, true) &&
ctx->copy_to_dest(stvfs, &resp.stvfs, sizeof(*stvfs)) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::chmod(ioctx_t* ctx, mode_t mode)
2013-01-30 19:33:13 +00:00
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_chmod msg;
msg.ino = ino;
msg.mode = mode;
if ( SendMessage(channel, FSM_REQ_CHMOD, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::chown(ioctx_t* ctx, uid_t owner, gid_t group)
2013-01-30 19:33:13 +00:00
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_chown msg;
msg.ino = ino;
msg.uid = owner;
msg.gid = group;
if ( SendMessage(channel, FSM_REQ_CHOWN, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::truncate(ioctx_t* ctx, off_t length)
2013-01-30 19:33:13 +00:00
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_truncate msg;
msg.ino = ino;
msg.size = length;
if ( SendMessage(channel, FSM_REQ_TRUNCATE, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
off_t Unode::lseek(ioctx_t* ctx, off_t offset, int whence)
2013-01-30 19:33:13 +00:00
{
Fix SEEK_END, file offset overflow, and read/write/mkpartition syscall bugs. Fix SEEK_END seeking twice as far as requested. Centralize lseek handling in one place and avoid overflow bugs. Inode lseek handlers now only need to handle SEEK_END with offset 0. Prevent the file offset from ever going below zero or overflowing. Character devices are now not seekable, but lseek will pretend they are, yet always stay at the file offset 0. pread/pwrite on character devices will now ignore the file offset and call read/write. This change prevents character devices from being memory mapped, notably /dev/zero can no longer be memory mapped. None of the current ports seem to rely on this behavior and will work with just MAP_ANONYMOUS. Refactor read and write system calls to have a shared return statement for both seekable and non-seekable IO. Fix file offset overflow bugs in read and write system calls. Fix system calls returning EPERM instead of properly returning EBADF when the file has not been opened in the right mode. Truncate IO counts and total vector IO length so the IO operation does not do any IO beyond OFF_MAX. Truncate also total vector IO length for recvmsg and sendmsg. Fail with EINVAL if total vector IO length exceeds SSIZE_MAX. Don't stop early if the total IO length is zero, so zero length IO now block on any locks internal to the inode. Handle reads at the maximum file offset with an end of file condition and handle writes of at least one byte at the maximum file offset by failing with EFBIG. Refactor UtilMemoryBuffer to store the file size using off_t instead of size_t to avoid casts and keep file sizes in the off_t type. Properly handle errors in the code, such as failing with EROFS instead of EBADF if the backing memory is not writeable, and failing with EFBIG if writing beyond the end of the file. Fix mkpartition not rejecting invalid partition start offsets and lengths. Strictly enforce partition start and length checks in the partition code. Enforce partitions exist within regular files or block devices. Fix a few indention issues.
2017-10-26 15:12:07 +00:00
if ( whence != SEEK_END && offset != 0 )
return errno = EINVAL, -1;
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
off_t ret = -1;
struct fsm_req_lseek msg;
struct fsm_resp_lseek resp;
msg.ino = ino;
msg.offset = offset;
msg.whence = whence;
if ( SendMessage(channel, FSM_REQ_LSEEK, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_LSEEK, &resp, sizeof(resp)) )
ret = resp.offset;
channel->KernelClose();
return ret;
}
ssize_t Unode::read(ioctx_t* ctx, uint8_t* buf, size_t count)
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
ssize_t ret = -1;
struct fsm_req_read msg;
struct fsm_resp_read resp;
msg.ino = ino;
msg.count = count;
if ( SendMessage(channel, FSM_REQ_READ, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_READ, &resp, sizeof(resp)) )
{
if ( resp.count < count )
count = resp.count;
if ( channel->KernelRecv(ctx, buf, count) )
ret = (ssize_t) count;
}
channel->KernelClose();
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;
}
2013-01-30 19:33:13 +00:00
ssize_t Unode::pread(ioctx_t* ctx, uint8_t* buf, size_t count, off_t off)
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
ssize_t ret = -1;
struct fsm_req_pread msg;
struct fsm_resp_read resp;
msg.ino = ino;
msg.count = count;
msg.offset = off;
if ( SendMessage(channel, FSM_REQ_PREAD, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_READ, &resp, sizeof(resp)) )
{
if ( resp.count < count )
count = resp.count;
if ( channel->KernelRecv(ctx, buf, count) )
ret = (ssize_t) count;
}
channel->KernelClose();
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;
}
2013-01-30 19:33:13 +00:00
ssize_t Unode::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_write msg;
msg.ino = ino;
msg.count = count;
struct fsm_msg_header hdr;
hdr.msgtype = FSM_REQ_WRITE;
hdr.msgsize = sizeof(msg) + count;
hdr.uid = ctx->uid;
hdr.gid = ctx->gid;
2013-01-30 19:33:13 +00:00
struct fsm_resp_write resp;
if ( channel->KernelSend(&kctx, &hdr, sizeof(hdr)) &&
channel->KernelSend(&kctx, &msg, sizeof(msg)) &&
channel->KernelSend(ctx, buf, count) &&
RecvMessage(channel, FSM_RESP_WRITE, &resp, sizeof(resp)) )
ret = (ssize_t) resp.count;
channel->KernelClose();
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;
}
2013-01-30 19:33:13 +00:00
ssize_t Unode::pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count, off_t off)
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
ssize_t ret = -1;
struct fsm_req_pwrite msg;
msg.ino = ino;
msg.count = count;
msg.offset = off;
struct fsm_msg_header hdr;
hdr.msgtype = FSM_REQ_PWRITE;
hdr.msgsize = sizeof(msg) + count;
hdr.uid = ctx->uid;
hdr.gid = ctx->gid;
2013-01-30 19:33:13 +00:00
struct fsm_resp_write resp;
if ( channel->KernelSend(&kctx, &hdr, sizeof(hdr)) &&
channel->KernelSend(&kctx, &msg, sizeof(msg)) &&
channel->KernelSend(ctx, buf, count) &&
RecvMessage(channel, FSM_RESP_WRITE, &resp, sizeof(resp)) )
ret = (ssize_t) resp.count;
channel->KernelClose();
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;
}
2016-02-24 15:29:37 +00:00
int Unode::utimens(ioctx_t* ctx, const struct timespec* times)
2013-01-30 19:33:13 +00:00
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_utimens msg;
2013-01-30 19:33:13 +00:00
msg.ino = ino;
2016-02-24 15:29:37 +00:00
msg.times[0] = times[0];
msg.times[1] = times[1];
if ( SendMessage(channel, FSM_REQ_UTIMENS, &msg, sizeof(msg)) &&
2013-01-30 19:33:13 +00:00
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::isatty(ioctx_t* ctx)
2013-01-30 19:33:13 +00:00
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return 0;
int ret = 0;
struct fsm_req_isatty msg;
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_ISATTY, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 1;
channel->KernelClose();
return ret;
}
2015-11-20 01:57:09 +00:00
ssize_t Unode::readdirents(ioctx_t* ctx, struct dirent* dirent, size_t size,
off_t start)
2013-01-30 19:33:13 +00:00
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
ssize_t ret = -1;
struct fsm_req_readdirents msg;
struct fsm_resp_readdirents resp;
msg.ino = ino;
msg.rec_num = start;
errno = 0;
if ( SendMessage(channel, FSM_REQ_READDIRENTS, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_READDIRENTS, &resp, sizeof(resp)) )
{
if ( !resp.namelen )
{
ret = 0;
goto break_if;
}
2015-11-20 01:57:09 +00:00
struct dirent entry;
memset(&entry, 0, sizeof(entry));
2013-01-30 19:33:13 +00:00
entry.d_reclen = sizeof(entry) + resp.namelen + 1;
entry.d_namlen = resp.namelen;
entry.d_dev = (dev_t) server.Get();
2013-01-30 19:33:13 +00:00
entry.d_ino = resp.ino;
entry.d_type = resp.type;
2013-01-30 19:33:13 +00:00
2014-09-30 15:42:24 +00:00
if ( !ctx->copy_to_dest(dirent, &entry, sizeof(entry)) )
2013-01-30 19:33:13 +00:00
goto break_if;
2015-11-20 01:57:09 +00:00
if ( size < entry.d_reclen && (errno = ERANGE) )
2013-01-30 19:33:13 +00:00
goto break_if;
2015-11-20 01:57:09 +00:00
char nul = '\0';
2013-01-30 19:33:13 +00:00
if ( channel->KernelRecv(ctx, dirent->d_name, resp.namelen) &&
2014-09-30 15:42:24 +00:00
ctx->copy_to_dest(&dirent->d_name[resp.namelen], &nul, 1) )
2015-11-20 01:57:09 +00:00
ret = (ssize_t) entry.d_reclen;
2013-01-30 19:33:13 +00:00
} break_if:
channel->KernelClose();
return ret;
}
Ref<Inode> Unode::open(ioctx_t* ctx, const char* filename, int flags,
2013-01-30 19:33:13 +00:00
mode_t mode)
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return Ref<Inode>(NULL);
size_t filenamelen = strlen(filename);
Ref<Inode> ret;
struct fsm_req_open msg;
msg.dirino = ino;
msg.flags = flags;
msg.mode = mode;
msg.namelen = filenamelen;
struct fsm_resp_open resp;
if ( SendMessage(channel, FSM_REQ_OPEN, &msg, sizeof(msg), filenamelen) &&
channel->KernelSend(&kctx, filename, filenamelen) &&
RecvMessage(channel, FSM_RESP_OPEN, &resp, sizeof(resp)) )
ret = server->OpenNode(resp.ino, resp.type);
channel->KernelClose();
return ret;
}
2016-10-22 21:47:28 +00:00
Ref<Inode> Unode::factory(ioctx_t* /*ctx*/, const char* /*filename*/,
int /*flags*/, mode_t /*mode*/)
{
return errno = EBADF, Ref<Inode>(NULL);
}
int Unode::mkdir(ioctx_t* ctx, const char* filename, mode_t mode)
2013-01-30 19:33:13 +00:00
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
2013-01-30 19:33:13 +00:00
size_t filenamelen = strlen(filename);
int ret = -1;
struct fsm_req_mkdir msg;
msg.dirino = ino;
msg.mode = mode;
msg.namelen = filenamelen;
struct fsm_resp_mkdir resp;
if ( SendMessage(channel, FSM_REQ_MKDIR, &msg, sizeof(msg), filenamelen) &&
channel->KernelSend(&kctx, filename, filenamelen) &&
RecvMessage(channel, FSM_RESP_MKDIR, &resp, sizeof(resp)) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::link(ioctx_t* ctx, const char* filename, Ref<Inode> node)
2013-01-30 19:33:13 +00:00
{
if ( node->dev != this->dev )
return errno = EXDEV, -1;
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
2013-01-30 19:33:13 +00:00
size_t filenamelen = strlen(filename);
int ret = -1;
struct fsm_req_link msg;
msg.dirino = ino;
msg.linkino = node->ino;
msg.namelen = filenamelen;
if ( SendMessage(channel, FSM_REQ_LINK, &msg, sizeof(msg), filenamelen) &&
channel->KernelSend(&kctx, filename, filenamelen) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::link_raw(ioctx_t* /*ctx*/, const char* /*filename*/, Ref<Inode> /*node*/)
{
return errno = EPERM, -1;
}
int Unode::unlink(ioctx_t* ctx, const char* filename)
2013-01-30 19:33:13 +00:00
{
// TODO: Make sure the target is no longer used!
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
2013-01-30 19:33:13 +00:00
size_t filenamelen = strlen(filename);
int ret = -1;
struct fsm_req_unlink msg;
msg.dirino = ino;
msg.namelen = filenamelen;
if ( SendMessage(channel, FSM_REQ_UNLINK, &msg, sizeof(msg), filenamelen) &&
channel->KernelSend(&kctx, filename, filenamelen) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::unlink_raw(ioctx_t* /*ctx*/, const char* /*filename*/)
{
return errno = EPERM, -1;
}
int Unode::rmdir(ioctx_t* ctx, const char* filename)
2013-01-30 19:33:13 +00:00
{
// TODO: Make sure the target is no longer used!
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
2013-01-30 19:33:13 +00:00
size_t filenamelen = strlen(filename);
int ret = -1;
struct fsm_req_rmdir msg;
msg.dirino = ino;
msg.namelen = filenamelen;
if ( SendMessage(channel, FSM_REQ_RMDIR, &msg, sizeof(msg), filenamelen) &&
channel->KernelSend(&kctx, filename, filenamelen) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::rmdir_me(ioctx_t* /*ctx*/)
{
return errno = EPERM, -1;
}
int Unode::symlink(ioctx_t* ctx, const char* oldname, const char* filename)
2013-01-30 19:33:13 +00:00
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
2013-01-30 19:33:13 +00:00
size_t oldnamelen = strlen(oldname);
size_t filenamelen = strlen(filename);
int ret = -1;
struct fsm_req_symlink msg;
msg.dirino = ino;
msg.targetlen = oldnamelen;
msg.namelen = filenamelen;
size_t extra = msg.targetlen + msg.namelen;
if ( SendMessage(channel, FSM_REQ_SYMLINK, &msg, sizeof(msg), extra) &&
channel->KernelSend(&kctx, oldname, oldnamelen) &&
channel->KernelSend(&kctx, filename, filenamelen) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
ssize_t Unode::readlink(ioctx_t* ctx, char* buf, size_t bufsiz)
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
ssize_t ret = -1;
struct fsm_req_readlink msg;
struct fsm_resp_readlink resp;
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_READLINK, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_READLINK, &resp, sizeof(resp)) )
{
if ( resp.targetlen < bufsiz )
bufsiz = resp.targetlen;
if ( channel->KernelRecv(ctx, buf, bufsiz) )
ret = (ssize_t) bufsiz;
}
channel->KernelClose();
return ret;
}
2013-12-20 20:55:05 +00:00
int Unode::tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp)
{
Channel* channel = server->Connect(ctx);
2013-12-20 20:55:05 +00:00
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_tcgetwincurpos msg;
struct fsm_resp_tcgetwincurpos resp;
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_TCGETWINCURPOS, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_TCGETWINCURPOS, &resp, sizeof(resp)) &&
ctx->copy_to_dest(wcp, &resp.pos, sizeof(*wcp)) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::ioctl(ioctx_t* ctx, int cmd, uintptr_t arg)
2013-01-30 19:33:13 +00:00
{
if ( cmd == TIOCGWINSZ )
{
struct winsize* ws = (struct winsize*) arg;
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_tcgetwinsize msg;
struct fsm_resp_tcgetwinsize resp;
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_TCGETWINSIZE, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_TCGETWINSIZE, &resp, sizeof(resp)) &&
ctx->copy_to_dest(ws, &resp.size, sizeof(*ws)) )
ret = 0;
channel->KernelClose();
return ret;
}
return errno = ENOTTY, -1;
2013-01-30 19:33:13 +00:00
}
int Unode::tcsetpgrp(ioctx_t* ctx, pid_t pgid)
2013-06-12 00:18:07 +00:00
{
Channel* channel = server->Connect(ctx);
2013-06-12 00:18:07 +00:00
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_tcsetpgrp msg;
msg.ino = ino;
msg.pgid = pgid;
if ( SendMessage(channel, FSM_REQ_TCSETPGRP, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
pid_t Unode::tcgetpgrp(ioctx_t* ctx)
2013-06-12 00:18:07 +00:00
{
Channel* channel = server->Connect(ctx);
2013-06-12 00:18:07 +00:00
if ( !channel )
return -1;
pid_t ret = -1;
struct fsm_req_tcgetpgrp msg;
struct fsm_resp_tcgetpgrp resp;
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_TCGETPGRP, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_TCGETPGRP, &resp, sizeof(resp)) )
ret = resp.pgid;
channel->KernelClose();
return ret;
}
int Unode::settermmode(ioctx_t* ctx, unsigned mode)
2013-01-30 19:33:13 +00:00
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_settermmode msg;
msg.ino = ino;
msg.termmode = mode;
if ( SendMessage(channel, FSM_REQ_SETTERMMODE, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::gettermmode(ioctx_t* ctx, unsigned* mode)
{
Channel* channel = server->Connect(ctx);
2013-01-30 19:33:13 +00:00
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_gettermmode msg;
struct fsm_resp_gettermmode resp;
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_GETTERMMODE, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_GETTERMMODE, &resp, sizeof(resp)) &&
ctx->copy_to_dest(mode, &resp.termmode, sizeof(*mode)) )
ret = 0;
channel->KernelClose();
return ret;
}
2021-02-16 21:19:50 +00:00
int Unode::poll(ioctx_t* /*ctx*/, PollNode* node)
2012-12-29 22:09:09 +00:00
{
2021-02-16 21:19:50 +00:00
short status = POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM;
if ( !(status & node->events) )
return errno = EAGAIN, -1;
node->master->revents |= status & node->events;
return 0;
2012-12-29 22:09:09 +00:00
}
int Unode::rename_here(ioctx_t* ctx, Ref<Inode> from, const char* oldname,
2012-12-20 15:19:07 +00:00
const char* newname)
{
Channel* channel = server->Connect(ctx);
2012-12-20 15:19:07 +00:00
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_rename msg;
msg.olddirino = from->ino;
msg.newdirino = this->ino;
2012-12-20 15:19:07 +00:00
msg.oldnamelen = strlen(oldname);
msg.newnamelen = strlen(newname);
size_t extra = msg.oldnamelen + msg.newnamelen;
if ( SendMessage(channel, FSM_REQ_RENAME, &msg, sizeof(msg), extra) &&
channel->KernelSend(&kctx, oldname, msg.oldnamelen) &&
channel->KernelSend(&kctx, newname, msg.newnamelen) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
Ref<Inode> Unode::accept4(ioctx_t* /*ctx*/, uint8_t* /*addr*/,
size_t* /*addrlen*/, int /*flags*/)
2013-03-19 21:40:37 +00:00
{
return errno = ENOTSOCK, Ref<Inode>();
}
int Unode::bind(ioctx_t* /*ctx*/, const uint8_t* /*addr*/, size_t /*addrlen*/)
{
return errno = ENOTSOCK, -1;
}
int Unode::connect(ioctx_t* /*ctx*/, const uint8_t* /*addr*/, size_t /*addrlen*/)
{
return errno = ENOTSOCK, -1;
}
int Unode::listen(ioctx_t* /*ctx*/, int /*backlog*/)
{
return errno = ENOTSOCK, -1;
}
ssize_t Unode::recv(ioctx_t* /*ctx*/, uint8_t* /*buf*/, size_t /*count*/,
int /*flags*/)
{
return errno = ENOTSOCK, -1;
}
ssize_t Unode::recvmsg(ioctx_t* /*ctx*/, struct msghdr* /*msg*/, int /*flags*/)
{
return errno = ENOTSOCK, -1;
}
2013-03-19 21:40:37 +00:00
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;
}
2014-02-28 16:10:08 +00:00
int Unode::getsockopt(ioctx_t* ctx, int level, int option_name,
void* option_value, size_t* option_size_ptr)
{
size_t option_size;
if ( !ctx->copy_from_src(&option_size, option_size_ptr, sizeof(option_size)) )
return -1;
Channel* channel = server->Connect(ctx);
2014-02-28 16:10:08 +00:00
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_getsockopt msg;
struct fsm_resp_getsockopt resp;
msg.ino = ino;
msg.level = level;
msg.option_name = option_name;
msg.max_option_size = option_size;
if ( SendMessage(channel, FSM_REQ_GETSOCKOPT, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_GETSOCKOPT, &resp, sizeof(resp)) )
{
if ( resp.option_size < option_size )
option_size = resp.option_size;
if ( channel->KernelRecv(ctx, option_value, option_size) )
ret = 0;
if ( !ctx->copy_to_dest(option_size_ptr, &option_size, sizeof(option_size)) )
ret = -1;
}
channel->KernelClose();
return ret;
}
int Unode::setsockopt(ioctx_t* ctx, int level, int option_name,
const void* option_value, size_t option_size)
{
Channel* channel = server->Connect(ctx);
2014-02-28 16:10:08 +00:00
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_setsockopt msg;
msg.ino = ino;
msg.level = level;
msg.option_name = option_name;
msg.option_size = option_size;
if ( SendMessage(channel, FSM_REQ_SETSOCKOPT, &msg, sizeof(msg)) &&
channel->KernelSend(ctx, option_value, option_size) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
2014-05-05 19:36:40 +00:00
ssize_t Unode::tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count)
{
Channel* channel = server->Connect(ctx);
2014-05-05 19:36:40 +00:00
if ( !channel )
return -1;
if ( !buffer )
count = SSIZE_MAX;
ssize_t ret = -1;
size_t namelen = name ? strlen(name) : 0;
struct fsm_req_tcgetblob msg;
struct fsm_resp_tcgetblob resp;
msg.ino = ino;
msg.namelen = namelen;
if ( SendMessage(channel, FSM_REQ_TCGETBLOB, &msg, sizeof(msg), namelen) &&
channel->KernelSend(&kctx, name, namelen) &&
RecvMessage(channel, FSM_RESP_TCGETBLOB, &resp, sizeof(resp)) )
{
if ( resp.count < count )
count = resp.count;
if ( count < resp.count )
errno = ERANGE;
else if ( !buffer || channel->KernelRecv(ctx, buffer, count) )
ret = (ssize_t) count;
}
channel->KernelClose();
return ret;
}
ssize_t Unode::tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count)
{
Channel* channel = server->Connect(ctx);
2014-05-05 19:36:40 +00:00
if ( !channel )
return -1;
ssize_t ret = -1;
size_t namelen = name ? strlen(name) : 0;
if ( SIZE_MAX - count < namelen )
return errno = EOVERFLOW, -1;
struct fsm_req_tcsetblob msg;
struct fsm_resp_tcsetblob resp;
msg.ino = ino;
msg.namelen = namelen;
msg.count = count;
if ( SendMessage(channel, FSM_REQ_TCSETBLOB, &msg, sizeof(msg), namelen + count) &&
channel->KernelSend(&kctx, name, namelen) &&
channel->KernelSend(ctx, buffer, count) &&
RecvMessage(channel, FSM_RESP_TCSETBLOB, &resp, sizeof(resp)) )
ret = (ssize_t) resp.count;
channel->KernelClose();
return ret;
}
2014-05-07 12:14:38 +00:00
int Unode::unmounted(ioctx_t* /*ctx*/)
2013-01-30 19:33:13 +00:00
{
2014-05-07 12:14:38 +00:00
server->Unmount();
return 0;
2013-01-30 19:33:13 +00:00
}
2016-01-23 19:56:07 +00:00
int Unode::tcdrain(ioctx_t* ctx)
{
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_tcdrain msg;
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_TCDRAIN, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::tcflow(ioctx_t* ctx, int action)
{
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_tcflow msg;
msg.ino = ino;
msg.action = action;
if ( SendMessage(channel, FSM_REQ_TCFLOW, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::tcflush(ioctx_t* ctx, int queue_selector)
{
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_tcflush msg;
msg.ino = ino;
msg.queue_selector = queue_selector;
if ( SendMessage(channel, FSM_REQ_TCFLUSH, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::tcgetattr(ioctx_t* ctx, struct termios* io_tio)
{
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_tcgetattr msg;
struct fsm_resp_tcgetattr resp;
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_TCGETATTR, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_TCGETATTR, &msg, sizeof(msg)) &&
ctx->copy_to_dest(io_tio, &resp.tio, sizeof(resp.tio)) )
ret = 0;
channel->KernelClose();
return ret;
}
pid_t Unode::tcgetsid(ioctx_t* ctx)
{
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
pid_t ret = -1;
struct fsm_req_tcgetsid msg;
struct fsm_resp_tcgetsid resp;
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_TCGETSID, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_TCGETSID, &msg, sizeof(msg)) )
ret = resp.sid;
channel->KernelClose();
return ret;
}
int Unode::tcsendbreak(ioctx_t* ctx, int duration)
{
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_tcsendbreak msg;
msg.ino = ino;
msg.duration = duration;
if ( SendMessage(channel, FSM_REQ_TCSENDBREAK, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::tcsetattr(ioctx_t* ctx, int actions, const struct termios* user_tio)
{
struct fsm_req_tcsetattr msg;
if ( !ctx->copy_from_src(&msg.tio, user_tio, sizeof(msg.tio)) )
return -1;
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
int ret = -1;
msg.ino = ino;
msg.actions = actions;
if ( SendMessage(channel, FSM_REQ_TCSETATTR, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
2016-08-06 13:44:37 +00:00
int Unode::shutdown(ioctx_t* ctx, int how)
{
struct fsm_req_shutdown msg;
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
int ret = -1;
msg.ino = ino;
msg.how = how;
if ( SendMessage(channel, FSM_REQ_SHUTDOWN, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::getpeername(ioctx_t* /*ctx*/, uint8_t* /*addr*/,
size_t* /*addrsize*/)
{
return errno = ENOTSOCK, -1;
}
int Unode::getsockname(ioctx_t* /*ctx*/, uint8_t* /*addr*/,
size_t* /*addrsize*/)
{
return errno = ENOTSOCK, -1;
}
2014-05-07 12:14:38 +00:00
bool Bootstrap(Ref<Inode>* out_root,
Ref<Inode>* out_server,
const struct stat* rootst)
2013-01-30 19:33:13 +00:00
{
2014-05-07 12:14:38 +00:00
Ref<Server> server(new Server());
if ( !server )
return false;
2013-01-30 19:33:13 +00:00
2014-05-07 12:14:38 +00:00
ino_t root_inode_ino = rootst->st_ino;
mode_t root_inode_type = rootst->st_mode & S_IFMT;
Ref<Inode> root_inode = server->OpenNode(root_inode_ino, root_inode_type);
if ( !root_inode )
return false;
2014-05-07 12:14:38 +00:00
Ref<ServerNode> server_inode(new ServerNode(server));
if ( !server_inode )
return false;
2014-05-07 12:14:38 +00:00
return *out_root = root_inode, *out_server = server_inode, true;
2013-01-30 19:33:13 +00:00
}
} // namespace UserFS
} // namespace Sortix