haeberlen@ira.uka.de
#include <config.h>
#include <idl4glue.h>
#include <new>
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sdi/log.h>
#include <sdi/util.h>
#include <sdi/panic.h>
#include <sdi/locator.h>
#include <if/iflocator.h>
#include "minixfs-server.h"
#include "minixfs.h"
#include "datastructures.h"
#include "filesystem.h"
namespace {
const size_t MAX_BUFSIZE = 8192;
}
struct minix_objectid_t {
union {
struct {
unsigned int inode : 24;
unsigned int filesystem : 8;
};
objectid_t objectid;
};
} __attribute__((packed));
ASSERT_SIZE(minix_objectid_t, sizeof(objectid_t));
IDL4_INLINE void minixfs_GetEntry_implementation(CORBA_Object _caller, const objectid_t directory_handle, const CORBA_char *name, const interfaceid_t interfaceid, L4_ThreadId_t *server, objectid_t *object_handle, idl4_server_environment *_env)
{
const minix_objectid_t& dir_handle
= reinterpret_cast<const minix_objectid_t&> (directory_handle);
if(dir_handle.filesystem >= filesystem_count) {
#ifdef PRINT_ERROR
printf("Invalid filesystem");
#endif
CORBA_exception_set (_env, ex_invalid_objectid, 0);
return;
}
FileSystem* fs = filesystems[dir_handle.filesystem];
INodeWrapper dirinode;
ErrorCode res = fs->store.readINode(&dirinode, dir_handle.inode);
if(res != NO_ERROR) {
#ifdef PRINT_ERROR
printf("Couldn't read inode %d\n", dir_handle.inode);
#endif
CORBA_exception_set(_env, ex_invalid_objectid, 0);
return;
}
if(!dirinode.isDir()) {
#ifdef PRINT_ERROR
printf("objectid is not a directory\n");
#endif
CORBA_exception_set(_env, ex_invalid_objectid, 0);
return;
}
INodeWrapper entry;
res = fs->getDirectoryEntry(&dirinode, &entry, name);
if(res != NO_ERROR) {
#ifdef PRINT_ERROR
printf("DirEntry '%s' not found\n", name);
#endif
CORBA_exception_set(_env, ex_not_found, 0);
return;
}
switch(interfaceid) {
case IF_DIRECTORY_ID:
if(!entry.isDir()) {
#ifdef PRINT_ERROR
printf("Entry is not a directory\n");
#endif
CORBA_exception_set(_env, ex_not_supported, 0);
return;
}
break;
case IF_FILE_ID:
if(!entry.isFile()) {
#ifdef PRINT_ERROR
printf("Entry is not a file\n");
#endif
CORBA_exception_set(_env, ex_not_supported, 0);
return;
}
break;
default:
CORBA_exception_set(_env, ex_not_supported, 0);
break;
}
*server = L4_Myself();
minix_objectid_t& result = reinterpret_cast<minix_objectid_t&> (*object_handle);
result.filesystem = dir_handle.filesystem;
result.inode = entry.num;
}
IDL4_PUBLISH_MINIXFS_GETENTRY(minixfs_GetEntry_implementation);
IDL4_INLINE void minixfs_EnumerateEntry_implementation(CORBA_Object _caller, const objectid_t directory_handle, const interfaceid_t interfaceid, const L4_Word_t entry, L4_ThreadId_t *server, objectid_t *object_handle, CORBA_char **name, idl4_server_environment *_env)
{
const minix_objectid_t& dir_handle
= reinterpret_cast<const minix_objectid_t&> (directory_handle);
if(dir_handle.filesystem >= filesystem_count) {
#ifdef PRINT_ERROR
printf("Invalid filesystem");
#endif
CORBA_exception_set (_env, ex_invalid_objectid, 0);
return;
}
FileSystem* fs = filesystems[dir_handle.filesystem];
INodeWrapper dirinode;
ErrorCode res = fs->store.readINode(&dirinode, dir_handle.inode);
if(res != NO_ERROR) {
#ifdef PRINT_ERROR
printf("Couldn't read inode %d\n", dir_handle.inode);
#endif
CORBA_exception_set(_env, ex_invalid_objectid, 0);
return;
}
if(!dirinode.isDir()) {
#ifdef PRINT_ERROR
printf("objectid is not a directory\n");
#endif
CORBA_exception_set(_env, ex_invalid_objectid, 0);
return;
}
if(interfaceid != (interfaceid_t) ANY_INTERFACE) {
#ifdef PRINT_ERROR
printf("Enumerating specific interfaces not supported yet\n");
#endif
*server = L4_nilthread;
*object_handle = 0;
return;
}
ObjectStore::DataPointer pointer;
fs->store.initDataPointer(pointer, &dirinode);
res = fs->store.seek(pointer, entry * sizeof(DirectoryEntry));
if(res != NO_ERROR) {
#ifdef PRINT_ERROR
printf("Entry %lu doesn't exist\n", entry);
#endif
*server = L4_nilthread;
*object_handle = 0;
fs->store.close(pointer);
return;
}
DirectoryEntry dir_entry;
if(fs->store.read(pointer, &dir_entry, sizeof(dir_entry)) != sizeof(dir_entry)) {
#ifdef PRINT_ERROR
printf("Entry %lu doesn't exist\n", entry);
#endif
*server = L4_nilthread;
*object_handle = 0;
fs->store.close(pointer);
return;
}
fs->store.close(pointer);
size_t i;
for(i = 0; i < sizeof(dir_entry.name) && dir_entry.name[i] != 0; ++i) {
(*name)[i] = dir_entry.name[i];
}
(*name)[i] = 0;
*server = L4_Myself();
minix_objectid_t& resultid = reinterpret_cast<minix_objectid_t&> (*object_handle);
resultid.filesystem = dir_handle.filesystem;
resultid.inode = dir_entry.inode;
return;
}
IDL4_PUBLISH_MINIXFS_ENUMERATEENTRY(minixfs_EnumerateEntry_implementation);
IDL4_INLINE void minixfs_Read_implementation(CORBA_Object _caller, const objectid_t filehandle, const uint32_t pos, const idlsize_t size, buffer_t *buffer, idl4_server_environment *_env)
{
const minix_objectid_t& handle
= reinterpret_cast<const minix_objectid_t&> (filehandle);
if(handle.filesystem >= filesystem_count) {
#ifdef PRINT_ERROR
printf("Invalid filesystem %d(%d)", handle.filesystem, filesystem_count);
#endif
buffer->_length = 0;
CORBA_exception_set (_env, ex_invalid_objectid, 0);
return;
}
FileSystem* fs = filesystems[handle.filesystem];
INodeWrapper inode;
ErrorCode res = fs->store.readINode(&inode, handle.inode);
if(res != NO_ERROR) {
#ifdef PRINT_ERROR
printf("Couldn't read inode %d\n", handle.inode);
#endif
buffer->_length = 0;
CORBA_exception_set(_env, ex_invalid_objectid, 0);
return;
}
if(!inode.isFile()) {
#ifdef PRINT_ERROR
printf("objectid is not a file\n");
#endif
buffer->_length = 0;
CORBA_exception_set(_env, ex_invalid_objectid, 0);
return;
}
ObjectStore::DataPointer pointer;
fs->store.initDataPointer(pointer, &inode);
res = fs->store.seek(pointer, pos);
if(res != NO_ERROR) {
#ifdef PRINT_ERROR
printf("Couldn't seek to %u\n", pos);
#endif
buffer->_length = 0;
fs->store.close(pointer);
return;
}
size_t readsize = size;
assert(readsize <= MAX_BUFSIZE);
buffer->_length = fs->store.read(pointer, buffer->_buffer, readsize);
fs->store.close(pointer);
}
IDL4_PUBLISH_MINIXFS_READ(minixfs_Read_implementation);
IDL4_INLINE void minixfs_Write_implementation(CORBA_Object _caller, const objectid_t filehandle, const uint32_t pos, idlsize_t* size, buffer_t *buffer, idl4_server_environment *_env)
{
const minix_objectid_t& handle
= reinterpret_cast<const minix_objectid_t&> (filehandle);
if(handle.filesystem >= filesystem_count) {
#ifdef PRINT_ERROR
printf("Invalid filesystem %d(%d)", handle.filesystem, filesystem_count);
#endif
buffer->_length = 0;
CORBA_exception_set (_env, ex_invalid_objectid, 0);
return;
}
FileSystem* fs = filesystems[handle.filesystem];
INodeWrapper inode;
ErrorCode res = fs->store.readINode(&inode, handle.inode);
if(res != NO_ERROR) {
#ifdef PRINT_ERROR
printf("Couldn't read inode %d\n", handle.inode);
#endif
buffer->_length = 0;
CORBA_exception_set(_env, ex_invalid_objectid, 0);
return;
}
if(!inode.isFile()) {
#ifdef PRINT_ERROR
printf("objectid is not a file\n");
#endif
buffer->_length = 0;
CORBA_exception_set(_env, ex_invalid_objectid, 0);
return;
}
ObjectStore::DataPointer pointer;
fs->store.initDataPointer(pointer, &inode);
res = fs->store.seek(pointer, pos);
if(res != NO_ERROR) {
#ifdef PRINT_ERROR
printf("Couldn't seek to %u\n", pos);
#endif
buffer->_length = 0;
fs->store.close(pointer);
return;
}
*size = fs->store.write(pointer, buffer->_buffer, buffer->_length);
fs->store.close(pointer);
}
IDL4_PUBLISH_MINIXFS_WRITE(minixfs_Write_implementation);
IDL4_INLINE void minixfs_GetFileSize_implementation(CORBA_Object _caller, const objectid_t filehandle, idlsize_t *filesize, idl4_server_environment *_env)
{
const minix_objectid_t& handle
= reinterpret_cast<const minix_objectid_t&> (filehandle);
if(handle.filesystem >= filesystem_count) {
#ifdef PRINT_ERROR
printf("Invalid filesystem %d(%d)\n", handle.filesystem, filesystem_count);
#endif
CORBA_exception_set (_env, ex_invalid_objectid, 0);
return;
}
FileSystem* fs = filesystems[handle.filesystem];
INodeWrapper inode;
ErrorCode res = fs->store.readINode(&inode, handle.inode);
if(res != NO_ERROR) {
#ifdef PRINT_ERROR
printf("Couldn't read inode %d\n", handle.inode);
#endif
CORBA_exception_set(_env, ex_invalid_objectid, 0);
return;
}
if(!inode.isFile()) {
#ifdef PRINT_ERROR
printf("objectid is not a file\n");
#endif
CORBA_exception_set(_env, ex_invalid_objectid, 0);
return;
}
*filesize = inode.size;
}
IDL4_PUBLISH_MINIXFS_GETFILESIZE(minixfs_GetFileSize_implementation);
IDL4_INLINE void minixfs_Create_implementation(CORBA_Object _caller, const objectid_t dir, const CORBA_char *name, L4_ThreadId_t *server, objectid_t *newhandle, idl4_server_environment *_env)
{
const minix_objectid_t& handle
= reinterpret_cast<const minix_objectid_t&> (dir);
if(handle.filesystem >= filesystem_count) {
#ifdef PRINT_ERROR
printf("Invalid filesystem %d(%d)\n", handle.filesystem, filesystem_count);
#endif
CORBA_exception_set (_env, ex_invalid_objectid, 0);
return;
}
FileSystem* fs = filesystems[handle.filesystem];
INodeWrapper inode;
ErrorCode res = fs->store.readINode(&inode, handle.inode);
if(res != NO_ERROR) {
#ifdef PRINT_ERROR
printf("Couldn't read inode %d\n", handle.inode);
#endif
CORBA_exception_set(_env, ex_invalid_objectid, 0);
return;
}
if(!inode.isDir()) {
#ifdef PRINT_ERROR
printf("objectid is not a directory\n");
#endif
CORBA_exception_set(_env, ex_invalid_objectid, 0);
return;
}
INodeWrapper* newinode = fs->store.allocINode(INode::TYPE_FILE);
if(newinode == NULL) {
#ifdef PRINT_ERROR
printf("Couldn't create new INode\n");
#endif
CORBA_exception_set(_env, ex_disk_full, 0);
return;
}
res = fs->linkINode(&inode, name, newinode);
if(res != NO_ERROR) {
delete newinode;
#ifdef PRINT_ERROR
printf("Couldn't link inode to directory\n");
#endif
CORBA_exception_set(_env, ex_disk_full, 0);
return;
}
*server = L4_Myself();
minix_objectid_t& newminixhandle
= reinterpret_cast<minix_objectid_t&> (newhandle);
newminixhandle.filesystem = handle.filesystem;
newminixhandle.inode = newinode->num;
delete newinode;
}
IDL4_PUBLISH_MINIXFS_CREATE(minixfs_Create_implementation);
IDL4_INLINE void minixfs_Remove_implementation(CORBA_Object _caller, const objectid_t dir, const objectid_t handle, idl4_server_environment *_env)
{
return;
}
IDL4_PUBLISH_MINIXFS_REMOVE(minixfs_Remove_implementation);
IDL4_INLINE void minixfs_MkDir_implementation(CORBA_Object _caller, const objectid_t parentdir, const CORBA_char *name, idl4_server_environment *_env)
{
const minix_objectid_t& handle
= reinterpret_cast<const minix_objectid_t&> (parentdir);
if(handle.filesystem >= filesystem_count) {
#ifdef PRINT_ERROR
printf("Invalid filesystem %d(%d)\n", handle.filesystem, filesystem_count);
#endif
CORBA_exception_set (_env, ex_invalid_objectid, 0);
return;
}
FileSystem* fs = filesystems[handle.filesystem];
INodeWrapper inode;
ErrorCode res = fs->store.readINode(&inode, handle.inode);
if(res != NO_ERROR) {
#ifdef PRINT_ERROR
printf("Couldn't read inode %d\n", handle.inode);
#endif
CORBA_exception_set(_env, ex_invalid_objectid, 0);
return;
}
if(!inode.isDir()) {
#ifdef PRINT_ERROR
printf("objectid is not a directory\n");
#endif
CORBA_exception_set(_env, ex_invalid_objectid, 0);
return;
}
res = fs->createDirectory(&inode, name);
if(res != NO_ERROR) {
#ifdef PRINT_ERROR
printf("Couldn't create directory\n");
#endif
CORBA_exception_set(_env, ex_disk_full, 0);
return;
}
}
IDL4_PUBLISH_MINIXFS_MKDIR(minixfs_MkDir_implementation);
IDL4_INLINE void minixfs_RmDir_implementation(CORBA_Object _caller, objectid_t *parendir, const objectid_t handle, idl4_server_environment *_env)
{
}
IDL4_PUBLISH_MINIXFS_RMDIR(minixfs_RmDir_implementation);
void *minixfs_vtable_4[MINIXFS_DEFAULT_VTABLE_SIZE] = MINIXFS_DEFAULT_VTABLE_4;
void *minixfs_vtable_5[MINIXFS_DEFAULT_VTABLE_SIZE] = MINIXFS_DEFAULT_VTABLE_5;
void *minixfs_vtable_6[MINIXFS_DEFAULT_VTABLE_SIZE] = MINIXFS_DEFAULT_VTABLE_6;
void *minixfs_vtable_11[MINIXFS_DEFAULT_VTABLE_SIZE] = MINIXFS_DEFAULT_VTABLE_11;
void *minixfs_vtable_discard[MINIXFS_DEFAULT_VTABLE_SIZE] = MINIXFS_DEFAULT_VTABLE_DISCARD;
void **minixfs_itable[16] = { minixfs_vtable_discard, minixfs_vtable_discard, minixfs_vtable_discard, minixfs_vtable_discard, minixfs_vtable_4, minixfs_vtable_5, minixfs_vtable_6, minixfs_vtable_discard, minixfs_vtable_discard, minixfs_vtable_discard, minixfs_vtable_discard, minixfs_vtable_11, minixfs_vtable_discard, minixfs_vtable_discard, minixfs_vtable_discard, minixfs_vtable_discard };
static void announce()
{
CORBA_Environment env (idl4_default_environment);
for(size_t i = 0; i < filesystem_count; ++i) {
char name[128];
snprintf(name, sizeof(name), "minixfs%u", i);
minix_objectid_t handle;
handle.filesystem = i;
handle.inode = 1;
if(Register(GetLocator(), name, IF_DIRECTORY_ID, handle.objectid) != OK
|| Register(GetLocator(), name, IF_ENUMERABLE_ID, handle.objectid) != OK
|| Register(GetLocator(), name, IF_FILE_ID, handle.objectid) != OK) {
panic("Problem registering minixfs");
}
}
}
void minixfs_server()
{
L4_ThreadId_t partner;
L4_MsgTag_t msgtag;
idl4_msgbuf_t msgbuf;
long cnt;
idl4_msgbuf_init(&msgbuf);
for (cnt = 0;cnt < MINIXFS_STRBUF_SIZE;cnt++)
idl4_msgbuf_add_buffer(&msgbuf, malloc(MAX_BUFSIZE), MAX_BUFSIZE);
announce();
while(true) {
partner = L4_nilthread;
msgtag.raw = 0;
cnt = 0;
while (true) {
idl4_msgbuf_sync(&msgbuf);
idl4_reply_and_wait(&partner, &msgtag, &msgbuf, &cnt);
if (idl4_is_error(&msgtag))
break;
idl4_process_request(&partner, &msgtag, &msgbuf, &cnt, minixfs_itable[idl4_get_interface_id(&msgtag) & MINIXFS_IID_MASK][idl4_get_function_id(&msgtag) & MINIXFS_FID_MASK]);
}
}
}
void minixfs_discard()
{
panic("minixfs message discarded");
}