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
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2012-01-03 15:35:05 +01:00
|
|
|
* Copyright (C) 2011-2012 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>
|
|
|
|
#include <file_system.h>
|
2012-04-25 23:52:49 +02:00
|
|
|
#include <dir_file_system.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
#include <pwd.h>
|
|
|
|
|
|
|
|
namespace Noux {
|
|
|
|
|
|
|
|
struct Vfs_io_channel : public Io_channel
|
|
|
|
{
|
|
|
|
Vfs_handle *_fh;
|
|
|
|
|
|
|
|
Absolute_path _path;
|
2012-04-25 23:52:49 +02:00
|
|
|
Absolute_path _leaf_path;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2012-04-25 23:52:49 +02:00
|
|
|
Vfs_io_channel(char const *path, char const *leaf_path,
|
|
|
|
Dir_file_system *root_dir, Vfs_handle *vfs_handle)
|
|
|
|
: _fh(vfs_handle), _path(path), _leaf_path(leaf_path) { }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2012-04-25 23:52:49 +02:00
|
|
|
~Vfs_io_channel() { destroy(env()->heap(), _fh); }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2012-04-25 23:52:49 +02:00
|
|
|
bool write(Sysio *sysio, size_t &count)
|
|
|
|
{
|
|
|
|
if (!_fh->fs()->write(sysio, _fh))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
count = sysio->write_out.count;
|
|
|
|
_fh->_seek += count;
|
|
|
|
return true;
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
bool read(Sysio *sysio)
|
|
|
|
{
|
|
|
|
if (!_fh->fs()->read(sysio, _fh))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
_fh->_seek += sysio->read_out.count;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-04-25 23:52:49 +02:00
|
|
|
bool fstat(Sysio *sysio)
|
|
|
|
{
|
2012-07-24 18:47:16 +02:00
|
|
|
/*
|
|
|
|
* 'sysio.stat_in' is not used in '_fh->ds()->stat()',
|
|
|
|
* so no 'sysio' member translation is needed here
|
|
|
|
*/
|
|
|
|
bool result = _fh->ds()->stat(sysio, _leaf_path.base());
|
|
|
|
sysio->fstat_out.st = sysio->stat_out.st;
|
|
|
|
return result;
|
2012-04-25 23:52:49 +02:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
bool fcntl(Sysio *sysio)
|
|
|
|
{
|
|
|
|
switch (sysio->fcntl_in.cmd) {
|
|
|
|
|
|
|
|
case Sysio::FCNTL_CMD_GET_FILE_STATUS_FLAGS:
|
|
|
|
|
|
|
|
sysio->fcntl_out.result = _fh->status_flags();
|
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
PWRN("invalid fcntl command %d", sysio->fcntl_in.cmd);
|
|
|
|
sysio->error.fcntl = Sysio::FCNTL_ERR_CMD_INVALID;
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
bool fchdir(Sysio *sysio, Pwd *pwd)
|
|
|
|
{
|
2012-07-24 18:47:16 +02:00
|
|
|
sysio->fstat_in.fd = sysio->fchdir_in.fd;
|
|
|
|
|
|
|
|
fstat(sysio);
|
|
|
|
|
|
|
|
if ((sysio->fstat_out.st.mode & Sysio::STAT_MODE_DIRECTORY) !=
|
|
|
|
Sysio::STAT_MODE_DIRECTORY) {
|
|
|
|
sysio->error.fchdir = Sysio::FCHDIR_ERR_NOT_DIR;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
pwd->pwd(_path.base());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
*/
|
2011-12-22 16:19:25 +01:00
|
|
|
bool dirent(Sysio *sysio)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* 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) {
|
|
|
|
sysio->dirent_out.entry.type = Sysio::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;
|
2012-04-25 23:52:49 +02:00
|
|
|
_fh->_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
|
|
|
|
|
|
|
if (!_fh->ds()->dirent(sysio, _path.base(), index - 2))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
_fh->_seek += sizeof(Sysio::Dirent);
|
|
|
|
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))
|
|
|
|
return sysio->stat_out.st.size;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool lseek(Sysio *sysio)
|
|
|
|
{
|
|
|
|
switch (sysio->lseek_in.whence) {
|
|
|
|
case Sysio::LSEEK_SET: _fh->_seek = sysio->lseek_in.offset; break;
|
|
|
|
case Sysio::LSEEK_CUR: break;
|
|
|
|
case Sysio::LSEEK_END: _fh->_seek = size(sysio); break;
|
|
|
|
}
|
|
|
|
sysio->lseek_out.offset = _fh->_seek;
|
|
|
|
return true;
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
2012-03-19 22:52:26 +01:00
|
|
|
|
|
|
|
bool check_unblock(bool rd, bool wr, bool ex) const
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* XXX For now, we use the TAR fs only, which never blocks.
|
|
|
|
* However, real file systems may block.
|
|
|
|
*/
|
|
|
|
return true;
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2012-03-19 22:51:34 +01:00
|
|
|
#endif /* _NOUX__VFS_IO_CHANNEL_H_ */
|