2011-12-22 16:19:25 +01:00
|
|
|
/*
|
|
|
|
* \brief I/O channel for files opened via virtual directory service
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2011-02-17
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2013-01-10 21:44:47 +01:00
|
|
|
* Copyright (C) 2011-2013 Genode Labs GmbH
|
2011-12-22 16:19:25 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
2012-03-19 22:51:34 +01:00
|
|
|
#ifndef _NOUX__VFS_IO_CHANNEL_H_
|
|
|
|
#define _NOUX__VFS_IO_CHANNEL_H_
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/* Noux includes */
|
|
|
|
#include <io_channel.h>
|
2014-04-07 16:15:40 +02:00
|
|
|
#include <vfs/dir_file_system.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
namespace Noux {
|
|
|
|
|
2013-10-17 12:48:45 +02:00
|
|
|
struct Vfs_io_channel : Io_channel, Signal_dispatcher_base
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2014-04-07 16:15:40 +02:00
|
|
|
Vfs::Vfs_handle *_fh;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
Absolute_path _path;
|
2012-04-25 23:52:49 +02:00
|
|
|
Absolute_path _leaf_path;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-10-17 12:48:45 +02:00
|
|
|
Signal_receiver &_sig_rec;
|
|
|
|
|
2012-04-25 23:52:49 +02:00
|
|
|
Vfs_io_channel(char const *path, char const *leaf_path,
|
2014-04-07 16:15:40 +02:00
|
|
|
Vfs::Dir_file_system *root_dir, Vfs::Vfs_handle *vfs_handle,
|
2013-10-17 12:48:45 +02:00
|
|
|
Signal_receiver &sig_rec)
|
|
|
|
: _fh(vfs_handle), _path(path), _leaf_path(leaf_path),
|
|
|
|
_sig_rec(sig_rec)
|
|
|
|
{
|
2014-04-07 16:15:40 +02:00
|
|
|
_fh->fs().register_read_ready_sigh(_fh, _sig_rec.manage(this));
|
2013-10-17 12:48:45 +02:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2013-10-17 12:48:45 +02:00
|
|
|
~Vfs_io_channel()
|
|
|
|
{
|
|
|
|
_sig_rec.dissolve(this);
|
|
|
|
destroy(env()->heap(), _fh);
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
bool write(Sysio *sysio, size_t &offset) override
|
2012-04-25 23:52:49 +02:00
|
|
|
{
|
2014-09-09 14:32:31 +02:00
|
|
|
Vfs::file_size out_count = 0;
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
sysio->error.write = _fh->fs().write(_fh, sysio->write_in.chunk,
|
|
|
|
sysio->write_in.count, out_count);
|
2014-09-09 14:32:31 +02:00
|
|
|
if (sysio->error.write != Vfs::File_io_service::WRITE_OK)
|
|
|
|
return false;
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
_fh->advance_seek(out_count);
|
|
|
|
|
|
|
|
sysio->write_out.count = out_count;
|
|
|
|
offset = out_count;
|
2012-04-25 23:52:49 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
bool read(Sysio *sysio) override
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2014-04-07 16:15:40 +02:00
|
|
|
size_t count = min(sysio->read_in.count, sizeof(sysio->read_out.chunk));
|
|
|
|
|
2014-09-09 14:32:31 +02:00
|
|
|
Vfs::file_size out_count = 0;
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
sysio->error.read = _fh->fs().read(_fh, sysio->read_out.chunk, count, out_count);
|
|
|
|
|
|
|
|
if (sysio->error.read != Vfs::File_io_service::READ_OK)
|
2011-12-22 16:19:25 +01:00
|
|
|
return false;
|
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
sysio->read_out.count = out_count;
|
|
|
|
|
|
|
|
_fh->advance_seek(out_count);
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
bool fstat(Sysio *sysio) override
|
2012-04-25 23:52:49 +02:00
|
|
|
{
|
2012-07-24 18:47:16 +02:00
|
|
|
/*
|
2014-04-07 16:15:40 +02:00
|
|
|
* 'sysio.stat_in' is not used in '_fh->ds().stat()',
|
2012-07-24 18:47:16 +02:00
|
|
|
* so no 'sysio' member translation is needed here
|
|
|
|
*/
|
2014-04-07 16:15:40 +02:00
|
|
|
sysio->error.stat = _fh->ds().stat(_leaf_path.base(),
|
|
|
|
sysio->fstat_out.st);
|
|
|
|
|
|
|
|
return (sysio->error.stat == Vfs::Directory_service::STAT_OK);
|
|
|
|
|
2012-04-25 23:52:49 +02:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
bool ftruncate(Sysio *sysio) override
|
2012-08-02 15:17:24 +02:00
|
|
|
{
|
2014-04-07 16:15:40 +02:00
|
|
|
|
|
|
|
sysio->error.ftruncate = _fh->fs().ftruncate(_fh, sysio->ftruncate_in.length);
|
|
|
|
|
|
|
|
return (sysio->error.ftruncate == Vfs::File_io_service::FTRUNCATE_OK);
|
2012-08-02 15:17:24 +02:00
|
|
|
}
|
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
bool fcntl(Sysio *sysio) override
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
|
|
|
switch (sysio->fcntl_in.cmd) {
|
|
|
|
|
|
|
|
case Sysio::FCNTL_CMD_GET_FILE_STATUS_FLAGS:
|
|
|
|
|
|
|
|
sysio->fcntl_out.result = _fh->status_flags();
|
|
|
|
return true;
|
|
|
|
|
2015-11-05 11:07:19 +01:00
|
|
|
case Sysio::FCNTL_CMD_SET_FILE_STATUS_FLAGS:
|
|
|
|
_fh->status_flags(sysio->fcntl_in.long_arg);
|
|
|
|
return true;
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
default:
|
|
|
|
|
|
|
|
PWRN("invalid fcntl command %d", sysio->fcntl_in.cmd);
|
|
|
|
sysio->error.fcntl = Sysio::FCNTL_ERR_CMD_INVALID;
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2012-04-25 23:52:49 +02:00
|
|
|
/*
|
|
|
|
* The 'dirent' function for the root directory only (the
|
|
|
|
* 'Dir_file_system::open()' function handles all requests referring
|
|
|
|
* to directories). Hence, '_path' is the absolute path of the
|
|
|
|
* directory to inspect.
|
|
|
|
*/
|
2014-04-07 16:15:40 +02:00
|
|
|
bool dirent(Sysio *sysio) override
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Return artificial dir entries for "." and ".."
|
|
|
|
*/
|
2012-04-25 23:52:49 +02:00
|
|
|
unsigned const index = _fh->seek() / sizeof(Sysio::Dirent);
|
2011-12-22 16:19:25 +01:00
|
|
|
if (index < 2) {
|
2014-04-07 16:15:40 +02:00
|
|
|
sysio->dirent_out.entry.type = Vfs::Directory_service::DIRENT_TYPE_DIRECTORY;
|
2012-04-23 20:42:55 +02:00
|
|
|
strncpy(sysio->dirent_out.entry.name,
|
|
|
|
index ? ".." : ".",
|
|
|
|
sizeof(sysio->dirent_out.entry.name));
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
sysio->dirent_out.entry.fileno = 1;
|
2014-04-07 16:15:40 +02:00
|
|
|
_fh->advance_seek(sizeof(Sysio::Dirent));
|
2011-12-22 16:19:25 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-04-25 23:52:49 +02:00
|
|
|
* Delegate remaining dir-entry request to the actual file system.
|
|
|
|
* Align index range to zero when calling the directory service.
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
2012-04-25 23:52:49 +02:00
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
if (!_fh->ds().dirent(_path.base(), index - 2,
|
|
|
|
sysio->dirent_out.entry))
|
2012-04-25 23:52:49 +02:00
|
|
|
return false;
|
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
_fh->advance_seek(sizeof(Sysio::Dirent));
|
2012-04-25 23:52:49 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return size of file that the I/O channel refers to
|
|
|
|
*
|
|
|
|
* Note that this function overwrites the 'sysio' argument. Do not
|
|
|
|
* call it prior saving all input arguments from the original sysio
|
|
|
|
* structure.
|
|
|
|
*/
|
|
|
|
size_t size(Sysio *sysio)
|
|
|
|
{
|
|
|
|
if (fstat(sysio))
|
2012-09-10 17:40:17 +02:00
|
|
|
return sysio->fstat_out.st.size;
|
2012-04-25 23:52:49 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
bool ioctl(Sysio *sysio) override
|
2012-11-20 14:44:37 +01:00
|
|
|
{
|
2014-04-07 16:15:40 +02:00
|
|
|
Vfs::File_system::Ioctl_arg arg = (Vfs::File_system::Ioctl_arg)sysio->ioctl_in.argp;
|
|
|
|
|
|
|
|
sysio->error.ioctl = _fh->fs().ioctl(_fh, sysio->ioctl_in.request, arg, sysio->ioctl_out);
|
|
|
|
|
|
|
|
return (sysio->error.ioctl == Vfs::File_io_service::IOCTL_OK);
|
2012-11-20 14:44:37 +01:00
|
|
|
}
|
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
bool lseek(Sysio *sysio) override
|
2012-04-25 23:52:49 +02:00
|
|
|
{
|
|
|
|
switch (sysio->lseek_in.whence) {
|
2014-04-07 16:15:40 +02:00
|
|
|
case Sysio::LSEEK_SET: _fh->seek(sysio->lseek_in.offset); break;
|
|
|
|
case Sysio::LSEEK_CUR: _fh->advance_seek(sysio->lseek_in.offset); break;
|
2012-09-10 18:04:59 +02:00
|
|
|
case Sysio::LSEEK_END:
|
|
|
|
off_t offset = sysio->lseek_in.offset;
|
|
|
|
sysio->fstat_in.fd = sysio->lseek_in.fd;
|
2014-04-07 16:15:40 +02:00
|
|
|
_fh->seek(size(sysio) + offset);
|
2012-09-10 18:04:59 +02:00
|
|
|
break;
|
2012-04-25 23:52:49 +02:00
|
|
|
}
|
2014-04-07 16:15:40 +02:00
|
|
|
sysio->lseek_out.offset = _fh->seek();
|
2012-04-25 23:52:49 +02:00
|
|
|
return true;
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
2012-03-19 22:52:26 +01:00
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
bool check_unblock(bool rd, bool wr, bool ex) const override
|
2012-03-19 22:52:26 +01:00
|
|
|
{
|
2014-04-07 16:15:40 +02:00
|
|
|
return _fh->fs().check_unblock(_fh, rd, wr, ex);
|
2012-03-19 22:52:26 +01:00
|
|
|
}
|
2013-10-17 12:48:45 +02:00
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
bool path(char *path, size_t len) override
|
2013-08-02 12:42:12 +02:00
|
|
|
{
|
|
|
|
strncpy(path, _path.base(), len);
|
|
|
|
path[len - 1] = '\0';
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-04-07 16:15:40 +02:00
|
|
|
|
2013-10-17 12:48:45 +02:00
|
|
|
/**************************************
|
|
|
|
** Signal_dispatcher_base interface **
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called by Noux main loop on the occurrence of new input
|
|
|
|
*/
|
2014-04-07 16:15:40 +02:00
|
|
|
void dispatch(unsigned) override
|
2013-10-17 12:48:45 +02:00
|
|
|
{
|
|
|
|
Io_channel::invoke_all_notifiers();
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2012-03-19 22:51:34 +01:00
|
|
|
#endif /* _NOUX__VFS_IO_CHANNEL_H_ */
|