Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2728 → Rev 2729

/branches/network/uspace/srv/fs/tmpfs/tmpfs_ops.c
0,0 → 1,493
/*
* Copyright (c) 2008 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup fs
* @{
*/
 
/**
* @file tmpfs_ops.c
* @brief Implementation of VFS operations for the TMPFS file system
* server.
*/
 
#include "tmpfs.h"
#include "../../vfs/vfs.h"
#include <ipc/ipc.h>
#include <async.h>
#include <errno.h>
#include <atomic.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <dirent.h>
#include <assert.h>
#include <sys/types.h>
#include <libadt/hash_table.h>
#include <as.h>
 
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
 
#define PLB_GET_CHAR(i) (tmpfs_reg.plb_ro[(i) % PLB_SIZE])
 
#define DENTRIES_BUCKETS 256
 
/*
* Hash table of all directory entries.
*/
hash_table_t dentries;
 
static hash_index_t dentries_hash(unsigned long *key)
{
return *key % DENTRIES_BUCKETS;
}
 
static int dentries_compare(unsigned long *key, hash_count_t keys,
link_t *item)
{
tmpfs_dentry_t *dentry = hash_table_get_instance(item, tmpfs_dentry_t,
dh_link);
return dentry->index == *key;
}
 
static void dentries_remove_callback(link_t *item)
{
}
 
/** TMPFS dentries hash table operations. */
hash_table_operations_t dentries_ops = {
.hash = dentries_hash,
.compare = dentries_compare,
.remove_callback = dentries_remove_callback
};
 
unsigned tmpfs_next_index = 1;
 
static void tmpfs_dentry_initialize(tmpfs_dentry_t *dentry)
{
dentry->index = 0;
dentry->parent = NULL;
dentry->sibling = NULL;
dentry->child = NULL;
dentry->name = NULL;
dentry->type = TMPFS_NONE;
dentry->size = 0;
dentry->data = NULL;
link_initialize(&dentry->dh_link);
}
 
/*
* For now, we don't distinguish between different dev_handles/instances. All
* requests resolve to the only instance, rooted in the following variable.
*/
static tmpfs_dentry_t *root;
 
static bool tmpfs_init(void)
{
if (!hash_table_create(&dentries, DENTRIES_BUCKETS, 1, &dentries_ops))
return false;
 
root = (tmpfs_dentry_t *) malloc(sizeof(tmpfs_dentry_t));
if (!root)
return false;
tmpfs_dentry_initialize(root);
root->index = tmpfs_next_index++;
root->name = "";
root->type = TMPFS_DIRECTORY;
hash_table_insert(&dentries, &root->index, &root->dh_link);
 
return true;
}
 
/** Compare one component of path to a directory entry.
*
* @param dentry Directory entry to compare the path component with.
* @param component Array of characters holding component name.
*
* @return True on match, false otherwise.
*/
static bool match_component(tmpfs_dentry_t *dentry, const char *component)
{
return !strcmp(dentry->name, component);
}
 
static unsigned long create_node(tmpfs_dentry_t *dentry,
const char *component, int lflag)
{
assert(dentry->type == TMPFS_DIRECTORY);
assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
 
tmpfs_dentry_t *node = malloc(sizeof(tmpfs_dentry_t));
if (!node)
return 0;
size_t len = strlen(component);
char *name = malloc(len + 1);
if (!name) {
free(node);
return 0;
}
strcpy(name, component);
 
tmpfs_dentry_initialize(node);
node->index = tmpfs_next_index++;
node->name = name;
node->parent = dentry;
if (lflag & L_DIRECTORY)
node->type = TMPFS_DIRECTORY;
else
node->type = TMPFS_FILE;
 
/* Insert the new node into the namespace. */
if (dentry->child) {
tmpfs_dentry_t *tmp = dentry->child;
while (tmp->sibling)
tmp = tmp->sibling;
tmp->sibling = node;
} else {
dentry->child = node;
}
 
/* Insert the new node into the dentry hash table. */
hash_table_insert(&dentries, &node->index, &node->dh_link);
return node->index;
}
 
static int destroy_component(tmpfs_dentry_t *dentry)
{
return EPERM;
}
 
void tmpfs_lookup(ipc_callid_t rid, ipc_call_t *request)
{
unsigned next = IPC_GET_ARG1(*request);
unsigned last = IPC_GET_ARG2(*request);
int dev_handle = IPC_GET_ARG3(*request);
int lflag = IPC_GET_ARG4(*request);
 
if (last < next)
last += PLB_SIZE;
 
/*
* Initialize TMPFS.
*/
if (!root && !tmpfs_init()) {
ipc_answer_0(rid, ENOMEM);
return;
}
 
tmpfs_dentry_t *dtmp = root->child;
tmpfs_dentry_t *dcur = root;
 
if (PLB_GET_CHAR(next) == '/')
next++; /* eat slash */
char component[NAME_MAX + 1];
int len = 0;
while (dtmp && next <= last) {
 
/* collect the component */
if (PLB_GET_CHAR(next) != '/') {
if (len + 1 == NAME_MAX) {
/* comopnent length overflow */
ipc_answer_0(rid, ENAMETOOLONG);
return;
}
component[len++] = PLB_GET_CHAR(next);
next++; /* process next character */
if (next <= last)
continue;
}
 
assert(len);
component[len] = '\0';
next++; /* eat slash */
len = 0;
 
/* match the component */
while (dtmp && !match_component(dtmp, component))
dtmp = dtmp->sibling;
 
/* handle miss: match amongst siblings */
if (!dtmp) {
if ((next > last) && (lflag & L_CREATE)) {
/* no components left and L_CREATE specified */
if (dcur->type != TMPFS_DIRECTORY) {
ipc_answer_0(rid, ENOTDIR);
return;
}
unsigned long index = create_node(dcur,
component, lflag);
if (index > 0) {
ipc_answer_4(rid, EOK,
tmpfs_reg.fs_handle, dev_handle,
index, 0);
} else {
ipc_answer_0(rid, ENOSPC);
}
return;
}
ipc_answer_0(rid, ENOENT);
return;
}
 
/* descend one level */
dcur = dtmp;
dtmp = dtmp->child;
}
 
/* handle miss: excessive components */
if (!dtmp && next <= last) {
if (lflag & L_CREATE) {
if (dcur->type != TMPFS_DIRECTORY) {
ipc_answer_0(rid, ENOTDIR);
return;
}
 
/* collect next component */
while (next <= last) {
if (PLB_GET_CHAR(next) == '/') {
/* more than one component */
ipc_answer_0(rid, ENOENT);
return;
}
if (len + 1 == NAME_MAX) {
/* component length overflow */
ipc_answer_0(rid, ENAMETOOLONG);
return;
}
component[len++] = PLB_GET_CHAR(next);
next++; /* process next character */
}
assert(len);
component[len] = '\0';
len = 0;
unsigned long index;
index = create_node(dcur, component, lflag);
if (index) {
ipc_answer_4(rid, EOK, tmpfs_reg.fs_handle,
dev_handle, index, 0);
} else {
ipc_answer_0(rid, ENOSPC);
}
return;
}
ipc_answer_0(rid, ENOENT);
return;
}
 
/* handle hit */
if (lflag & L_DESTROY) {
int res = destroy_component(dcur);
ipc_answer_0(rid, res);
return;
}
if ((lflag & (L_CREATE | L_EXCLUSIVE)) == (L_CREATE | L_EXCLUSIVE)) {
ipc_answer_0(rid, EEXIST);
return;
}
if ((lflag & L_FILE) && (dcur->type != TMPFS_FILE)) {
ipc_answer_0(rid, EISDIR);
return;
}
if ((lflag & L_DIRECTORY) && (dcur->type != TMPFS_DIRECTORY)) {
ipc_answer_0(rid, ENOTDIR);
return;
}
 
ipc_answer_4(rid, EOK, tmpfs_reg.fs_handle, dev_handle, dcur->index,
dcur->size);
}
 
void tmpfs_read(ipc_callid_t rid, ipc_call_t *request)
{
int dev_handle = IPC_GET_ARG1(*request);
unsigned long index = IPC_GET_ARG2(*request);
off_t pos = IPC_GET_ARG3(*request);
 
/*
* Lookup the respective dentry.
*/
link_t *hlp;
hlp = hash_table_find(&dentries, &index);
if (!hlp) {
ipc_answer_0(rid, ENOENT);
return;
}
tmpfs_dentry_t *dentry = hash_table_get_instance(hlp, tmpfs_dentry_t,
dh_link);
 
/*
* Receive the read request.
*/
ipc_callid_t callid;
size_t len;
if (!ipc_data_read_receive(&callid, &len)) {
ipc_answer_0(callid, EINVAL);
ipc_answer_0(rid, EINVAL);
return;
}
 
size_t bytes;
if (dentry->type == TMPFS_FILE) {
bytes = max(0, min(dentry->size - pos, len));
(void) ipc_data_read_finalize(callid, dentry->data + pos,
bytes);
} else {
int i;
tmpfs_dentry_t *cur = dentry->child;
assert(dentry->type == TMPFS_DIRECTORY);
/*
* Yes, we really use O(n) algorithm here.
* If it bothers someone, it could be fixed by introducing a
* hash table.
*/
for (i = 0, cur = dentry->child; i < pos && cur; i++,
cur = cur->sibling)
;
 
if (!cur) {
ipc_answer_0(callid, ENOENT);
ipc_answer_1(rid, ENOENT, 0);
return;
}
 
(void) ipc_data_read_finalize(callid, cur->name,
strlen(cur->name) + 1);
bytes = 1;
}
 
/*
* Answer the VFS_READ call.
*/
ipc_answer_1(rid, EOK, bytes);
}
 
void tmpfs_write(ipc_callid_t rid, ipc_call_t *request)
{
int dev_handle = IPC_GET_ARG1(*request);
unsigned long index = IPC_GET_ARG2(*request);
off_t pos = IPC_GET_ARG3(*request);
 
/*
* Lookup the respective dentry.
*/
link_t *hlp;
hlp = hash_table_find(&dentries, &index);
if (!hlp) {
ipc_answer_0(rid, ENOENT);
return;
}
tmpfs_dentry_t *dentry = hash_table_get_instance(hlp, tmpfs_dentry_t,
dh_link);
 
/*
* Receive the write request.
*/
ipc_callid_t callid;
size_t len;
if (!ipc_data_write_receive(&callid, &len)) {
ipc_answer_0(callid, EINVAL);
ipc_answer_0(rid, EINVAL);
return;
}
 
/*
* Check whether the file needs to grow.
*/
if (pos + len <= dentry->size) {
/* The file size is not changing. */
(void) ipc_data_write_finalize(callid, dentry->data + pos, len);
ipc_answer_2(rid, EOK, len, dentry->size);
return;
}
size_t delta = (pos + len) - dentry->size;
/*
* At this point, we are deliberately extremely straightforward and
* simply realloc the contents of the file on every write that grows the
* file. In the end, the situation might not be as bad as it may look:
* our heap allocator can save us and just grow the block whenever
* possible.
*/
void *newdata = realloc(dentry->data, dentry->size + delta);
if (!newdata) {
ipc_answer_0(callid, ENOMEM);
ipc_answer_2(rid, EOK, 0, dentry->size);
return;
}
/* Clear any newly allocated memory in order to emulate gaps. */
memset(newdata + dentry->size, 0, delta);
dentry->size += delta;
dentry->data = newdata;
(void) ipc_data_write_finalize(callid, dentry->data + pos, len);
ipc_answer_2(rid, EOK, len, dentry->size);
}
 
void tmpfs_truncate(ipc_callid_t rid, ipc_call_t *request)
{
int dev_handle = IPC_GET_ARG1(*request);
unsigned long index = IPC_GET_ARG2(*request);
size_t size = IPC_GET_ARG3(*request);
 
/*
* Lookup the respective dentry.
*/
link_t *hlp;
hlp = hash_table_find(&dentries, &index);
if (!hlp) {
ipc_answer_0(rid, ENOENT);
return;
}
tmpfs_dentry_t *dentry = hash_table_get_instance(hlp, tmpfs_dentry_t,
dh_link);
 
if (size == dentry->size) {
ipc_answer_0(rid, EOK);
return;
}
 
void *newdata = realloc(dentry->data, size);
if (!newdata) {
ipc_answer_0(rid, ENOMEM);
return;
}
if (size > dentry->size) {
size_t delta = size - dentry->size;
memset(newdata + dentry->size, 0, delta);
}
dentry->size = size;
dentry->data = newdata;
ipc_answer_0(rid, EOK);
}
 
/**
* @}
*/
/branches/network/uspace/srv/fs/tmpfs/tmpfs.c
0,0 → 1,158
/*
* Copyright (c) 2006 Martin Decky
* Copyright (c) 2008 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup fs
* @{
*/
 
/**
* @file tmpfs.c
* @brief File system driver for in-memory file system.
*
* Every instance of tmpfs exists purely in memory and has neither a disk layout
* nor any permanent storage (e.g. disk blocks). With each system reboot, data
* stored in a tmpfs file system is lost.
*/
 
#include "tmpfs.h"
#include <ipc/ipc.h>
#include <ipc/services.h>
#include <async.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <libfs.h>
#include "../../vfs/vfs.h"
 
 
vfs_info_t tmpfs_vfs_info = {
.name = "tmpfs",
.ops = {
[IPC_METHOD_TO_VFS_OP(VFS_LOOKUP)] = VFS_OP_DEFINED,
[IPC_METHOD_TO_VFS_OP(VFS_OPEN)] = VFS_OP_DEFINED,
[IPC_METHOD_TO_VFS_OP(VFS_CLOSE)] = VFS_OP_DEFINED,
[IPC_METHOD_TO_VFS_OP(VFS_READ)] = VFS_OP_DEFINED,
[IPC_METHOD_TO_VFS_OP(VFS_WRITE)] = VFS_OP_DEFINED,
[IPC_METHOD_TO_VFS_OP(VFS_TRUNCATE)] = VFS_OP_NULL,
[IPC_METHOD_TO_VFS_OP(VFS_RENAME)] = VFS_OP_NULL,
[IPC_METHOD_TO_VFS_OP(VFS_OPENDIR)] = VFS_OP_NULL,
[IPC_METHOD_TO_VFS_OP(VFS_READDIR)] = VFS_OP_NULL,
[IPC_METHOD_TO_VFS_OP(VFS_CLOSEDIR)] = VFS_OP_NULL,
[IPC_METHOD_TO_VFS_OP(VFS_UNLINK)] = VFS_OP_NULL,
[IPC_METHOD_TO_VFS_OP(VFS_MOUNT)] = VFS_OP_NULL,
[IPC_METHOD_TO_VFS_OP(VFS_UNMOUNT)] = VFS_OP_NULL,
}
};
 
fs_reg_t tmpfs_reg;
 
/**
* This connection fibril processes VFS requests from VFS.
*
* In order to support simultaneous VFS requests, our design is as follows.
* The connection fibril accepts VFS requests from VFS. If there is only one
* instance of the fibril, VFS will need to serialize all VFS requests it sends
* to FAT. To overcome this bottleneck, VFS can send TMPFS the
* IPC_M_CONNECT_ME_TO call. In that case, a new connection fibril will be
* created, which in turn will accept the call. Thus, a new phone will be
* opened for VFS.
*
* There are few issues with this arrangement. First, VFS can run out of
* available phones. In that case, VFS can close some other phones or use one
* phone for more serialized requests. Similarily, TMPFS can refuse to duplicate
* the connection. VFS should then just make use of already existing phones and
* route its requests through them. To avoid paying the fibril creation price
* upon each request, TMPFS might want to keep the connections open after the
* request has been completed.
*/
static void tmpfs_connection(ipc_callid_t iid, ipc_call_t *icall)
{
if (iid) {
/*
* This only happens for connections opened by
* IPC_M_CONNECT_ME_TO calls as opposed to callback connections
* created by IPC_M_CONNECT_TO_ME.
*/
ipc_answer_0(iid, EOK);
}
dprintf("VFS-TMPFS connection established.\n");
while (1) {
ipc_callid_t callid;
ipc_call_t call;
callid = async_get_call(&call);
switch (IPC_GET_METHOD(call)) {
case VFS_LOOKUP:
tmpfs_lookup(callid, &call);
break;
case VFS_READ:
tmpfs_read(callid, &call);
break;
case VFS_WRITE:
tmpfs_write(callid, &call);
break;
default:
ipc_answer_0(callid, ENOTSUP);
break;
}
}
}
 
int main(int argc, char **argv)
{
int vfs_phone;
 
printf("TMPFS: HelenOS TMPFS file system server.\n");
 
vfs_phone = ipc_connect_me_to(PHONE_NS, SERVICE_VFS, 0, 0);
while (vfs_phone < EOK) {
usleep(10000);
vfs_phone = ipc_connect_me_to(PHONE_NS, SERVICE_VFS, 0, 0);
}
int rc;
rc = fs_register(vfs_phone, &tmpfs_reg, &tmpfs_vfs_info,
tmpfs_connection);
if (rc != EOK) {
printf("Failed to register the TMPFS file system (%d)\n", rc);
return rc;
}
dprintf("TMPFS filesystem registered, fs_handle=%d.\n",
tmpfs_reg.fs_handle);
 
async_manager();
/* not reached */
return 0;
}
 
/**
* @}
*/
/branches/network/uspace/srv/fs/tmpfs/tmpfs.h
0,0 → 1,72
/*
* Copyright (c) 2008 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup fs
* @{
*/
 
#ifndef TMPFS_TMPFS_H_
#define TMPFS_TMPFS_H_
 
#include <ipc/ipc.h>
#include <libfs.h>
#include <atomic.h>
#include <sys/types.h>
#include <bool.h>
#include <libadt/hash_table.h>
 
#define dprintf(...) printf(__VA_ARGS__)
 
typedef struct tmpfs_dentry {
unsigned long index; /**< TMPFS node index. */
link_t dh_link; /**< Dentries hash table link. */
struct tmpfs_dentry *parent;
struct tmpfs_dentry *sibling;
struct tmpfs_dentry *child;
char *name;
enum {
TMPFS_NONE,
TMPFS_FILE,
TMPFS_DIRECTORY
} type;
size_t size; /**< File size if type is TMPFS_FILE. */
void *data; /**< File content's if type is TMPFS_FILE. */
} tmpfs_dentry_t;
 
extern fs_reg_t tmpfs_reg;
 
extern void tmpfs_lookup(ipc_callid_t, ipc_call_t *);
extern void tmpfs_read(ipc_callid_t, ipc_call_t *);
extern void tmpfs_write(ipc_callid_t, ipc_call_t *);
extern void tmpfs_truncate(ipc_callid_t, ipc_call_t *);
 
#endif
 
/**
* @}
*/
/branches/network/uspace/srv/fs/tmpfs/Makefile
0,0 → 1,76
#
# Copyright (c) 2006 Martin Decky
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# - Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# - The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
 
## Setup toolchain
#
 
LIBC_PREFIX = ../../../lib/libc
LIBFS_PREFIX = ../../../lib/libfs
SOFTINT_PREFIX = ../../../lib/softint
include $(LIBC_PREFIX)/Makefile.toolchain
 
CFLAGS += -I $(LIBFS_PREFIX)
 
LIBS = $(LIBC_PREFIX)/libc.a $(LIBFS_PREFIX)/libfs.a
 
## Sources
#
 
OUTPUT = tmpfs
SOURCES = \
tmpfs.c \
tmpfs_ops.c
 
OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
 
.PHONY: all clean depend disasm
 
all: $(OUTPUT) disasm
 
-include Makefile.depend
 
clean:
-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend
 
depend:
$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
 
$(OUTPUT): $(OBJECTS) $(LIBS)
$(LD) -T $(LIBC_PREFIX)/arch/$(ARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
 
disasm:
$(OBJDUMP) -d $(OUTPUT) >$(OUTPUT).disasm
 
%.o: %.S
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
 
%.o: %.s
$(AS) $(AFLAGS) $< -o $@
 
%.o: %.c
$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
/branches/network/uspace/srv/fs/fat/fat.c
0,0 → 1,146
/*
* Copyright (c) 2006 Martin Decky
* Copyright (c) 2008 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup fs
* @{
*/
 
/**
* @file fat.c
* @brief FAT file system driver for HelenOS.
*/
 
#include "fat.h"
#include <ipc/ipc.h>
#include <ipc/services.h>
#include <async.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <libfs.h>
#include "../../vfs/vfs.h"
 
 
vfs_info_t fat_vfs_info = {
.name = "fat",
.ops = {
[IPC_METHOD_TO_VFS_OP(VFS_LOOKUP)] = VFS_OP_DEFINED,
[IPC_METHOD_TO_VFS_OP(VFS_OPEN)] = VFS_OP_DEFINED,
[IPC_METHOD_TO_VFS_OP(VFS_CLOSE)] = VFS_OP_DEFINED,
[IPC_METHOD_TO_VFS_OP(VFS_READ)] = VFS_OP_DEFINED,
[IPC_METHOD_TO_VFS_OP(VFS_WRITE)] = VFS_OP_NULL,
[IPC_METHOD_TO_VFS_OP(VFS_TRUNCATE)] = VFS_OP_NULL,
[IPC_METHOD_TO_VFS_OP(VFS_RENAME)] = VFS_OP_NULL,
[IPC_METHOD_TO_VFS_OP(VFS_OPENDIR)] = VFS_OP_NULL,
[IPC_METHOD_TO_VFS_OP(VFS_READDIR)] = VFS_OP_NULL,
[IPC_METHOD_TO_VFS_OP(VFS_CLOSEDIR)] = VFS_OP_NULL,
[IPC_METHOD_TO_VFS_OP(VFS_UNLINK)] = VFS_OP_NULL,
[IPC_METHOD_TO_VFS_OP(VFS_MOUNT)] = VFS_OP_NULL,
[IPC_METHOD_TO_VFS_OP(VFS_UNMOUNT)] = VFS_OP_NULL,
}
};
 
fs_reg_t fat_reg;
 
/**
* This connection fibril processes VFS requests from VFS.
*
* In order to support simultaneous VFS requests, our design is as follows.
* The connection fibril accepts VFS requests from VFS. If there is only one
* instance of the fibril, VFS will need to serialize all VFS requests it sends
* to FAT. To overcome this bottleneck, VFS can send FAT the IPC_M_CONNECT_ME_TO
* call. In that case, a new connection fibril will be created, which in turn
* will accept the call. Thus, a new phone will be opened for VFS.
*
* There are few issues with this arrangement. First, VFS can run out of
* available phones. In that case, VFS can close some other phones or use one
* phone for more serialized requests. Similarily, FAT can refuse to duplicate
* the connection. VFS should then just make use of already existing phones and
* route its requests through them. To avoid paying the fibril creation price
* upon each request, FAT might want to keep the connections open after the
* request has been completed.
*/
static void fat_connection(ipc_callid_t iid, ipc_call_t *icall)
{
if (iid) {
/*
* This only happens for connections opened by
* IPC_M_CONNECT_ME_TO calls as opposed to callback connections
* created by IPC_M_CONNECT_TO_ME.
*/
ipc_answer_0(iid, EOK);
}
dprintf("VFS-FAT connection established.\n");
while (1) {
ipc_callid_t callid;
ipc_call_t call;
callid = async_get_call(&call);
switch (IPC_GET_METHOD(call)) {
case VFS_LOOKUP:
fat_lookup(callid, &call);
break;
default:
ipc_answer_0(callid, ENOTSUP);
break;
}
}
}
 
int main(int argc, char **argv)
{
int vfs_phone;
 
printf("FAT: HelenOS FAT file system server.\n");
 
vfs_phone = ipc_connect_me_to(PHONE_NS, SERVICE_VFS, 0, 0);
while (vfs_phone < EOK) {
usleep(10000);
vfs_phone = ipc_connect_me_to(PHONE_NS, SERVICE_VFS, 0, 0);
}
int rc;
rc = fs_register(vfs_phone, &fat_reg, &fat_vfs_info, fat_connection);
if (rc != EOK) {
printf("Failed to register the FAT file system (%d)\n", rc);
return rc;
}
dprintf("FAT filesystem registered, fs_handle=%d.\n",
fat_reg.fs_handle);
 
async_manager();
/* not reached */
return 0;
}
 
/**
* @}
*/
/branches/network/uspace/srv/fs/fat/fat.h
0,0 → 1,145
/*
* Copyright (c) 2007 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup fs
* @{
*/
 
#ifndef FAT_FAT_H_
#define FAT_FAT_H_
 
#include <ipc/ipc.h>
#include <libfs.h>
#include <atomic.h>
#include <sys/types.h>
#include <bool.h>
 
#define dprintf(...) printf(__VA_ARGS__)
 
typedef struct {
uint8_t ji[3]; /**< Jump instruction. */
uint8_t oem_name[8];
/* BIOS Parameter Block */
uint16_t bps; /**< Bytes per sector. */
uint8_t spc; /**< Sectors per cluster. */
uint16_t rsc; /**< Reserved sector count. */
uint8_t fatcnt; /**< Number of FATs. */
uint16_t root_ent_max; /**< Maximum number of root directory
entries. */
uint16_t totsec; /**< Total sectors. */
uint8_t mdesc; /**< Media descriptor. */
uint16_t sec_per_fat; /**< Sectors per FAT12/FAT16. */
uint16_t sec_per_track; /**< Sectors per track. */
uint16_t headcnt; /**< Number of heads. */
uint32_t hidden_sec; /**< Hidden sectors. */
uint32_t total_sec; /**< Total sectors. */
 
union {
struct {
/* FAT12/FAT16 only: Extended BIOS Parameter Block */
/** Physical drive number. */
uint8_t pdn;
uint8_t reserved;
/** Extended boot signature. */
uint8_t ebs;
/** Serial number. */
uint32_t id;
/** Volume label. */
uint8_t label[11];
/** FAT type. */
uint8_t type[8];
/** Boot code. */
uint8_t boot_code[448];
/** Boot sector signature. */
uint16_t signature;
} __attribute__ ((packed));
struct {
/* FAT32 only */
/** Sectors per FAT. */
uint32_t sectors_per_fat;
/** FAT flags. */
uint16_t flags;
/** Version. */
uint16_t version;
/** Cluster number of root directory. */
uint32_t root_cluster;
/** Sector number of file system information sector. */
uint16_t fsinfo_sec;
/** Sector number of boot sector copy. */
uint16_t bscopy_sec;
uint8_t reserved1[12];
/** Physical drive number. */
uint8_t pdn;
uint8_t reserved2;
/** Extended boot signature. */
uint8_t ebs;
/** Serial number. */
uint32_t id;
/** Volume label. */
uint8_t label;
/** FAT type. */
uint8_t type[8];
/** Boot code. */
uint8_t boot_code[420];
/** Signature. */
uint16_t signature;
} __attribute__ ((packed));
};
} __attribute__ ((packed)) fat_bs_t;
 
typedef struct {
uint8_t name[8];
uint8_t ext[3];
uint8_t attr;
uint8_t reserved;
uint8_t ctime_fine;
uint16_t ctime;
uint16_t cdate;
uint16_t adate;
union {
uint16_t eaidx; /* FAT12/FAT16 */
uint16_t firstc_hi; /* FAT32 */
};
uint16_t mtime;
uint16_t mdate;
union {
uint16_t firstc; /* FAT12/FAT16 */
uint16_t firstc_lo; /* FAT32 */
};
uint32_t size;
} __attribute__ ((packed)) fat_dentry_t;
 
extern fs_reg_t fat_reg;
 
extern void fat_lookup(ipc_callid_t, ipc_call_t *);
 
#endif
 
/**
* @}
*/
/branches/network/uspace/srv/fs/fat/fat_ops.c
0,0 → 1,142
/*
* Copyright (c) 2007 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup fs
* @{
*/
 
/**
* @file fat_ops.c
* @brief Implementation of VFS operations for the FAT file system server.
*/
 
#include "fat.h"
#include "../../vfs/vfs.h"
#include <ipc/ipc.h>
#include <async.h>
#include <errno.h>
 
#define PLB_GET_CHAR(i) (fat_reg.plb_ro[(i) % PLB_SIZE])
 
#define FAT_NAME_LEN 8
#define FAT_EXT_LEN 3
 
#define FAT_PAD ' '
 
#define FAT_DENTRY_UNUSED 0x00
#define FAT_DENTRY_E5_ESC 0x05
#define FAT_DENTRY_DOT 0x2e
#define FAT_DENTRY_ERASED 0xe5
 
/** Compare one component of path to a directory entry.
*
* @param dentry Directory entry to compare the path component with.
* @param start Index into PLB where the path component starts.
* @param last Index of the last character of the path in PLB.
*
* @return Zero on failure or delta such that (index + delta) %
* PLB_SIZE points to a new path component in PLB.
*/
static unsigned match_path_component(fat_dentry_t *dentry, unsigned start,
unsigned last)
{
unsigned cur; /* current position in PLB */
int pos; /* current position in dentry->name or dentry->ext */
bool name_processed = false;
bool dot_processed = false;
bool ext_processed = false;
 
if (last < start)
last += PLB_SIZE;
for (pos = 0, cur = start; (cur <= last) && (PLB_GET_CHAR(cur) != '/');
pos++, cur++) {
if (!name_processed) {
if ((pos == FAT_NAME_LEN - 1) ||
(dentry->name[pos + 1] == FAT_PAD)) {
/* this is the last character in name */
name_processed = true;
}
if (dentry->name[0] == FAT_PAD) {
/* name is empty */
name_processed = true;
} else if ((pos == 0) && (dentry->name[pos] ==
FAT_DENTRY_E5_ESC)) {
if (PLB_GET_CHAR(cur) == 0xe5)
continue;
else
return 0; /* character mismatch */
} else {
if (PLB_GET_CHAR(cur) == dentry->name[pos])
continue;
else
return 0; /* character mismatch */
}
}
if (!dot_processed) {
dot_processed = true;
pos = -1;
if (PLB_GET_CHAR(cur) != '.')
return 0;
continue;
}
if (!ext_processed) {
if ((pos == FAT_EXT_LEN - 1) ||
(dentry->ext[pos + 1] == FAT_PAD)) {
/* this is the last character in ext */
ext_processed = true;
}
if (dentry->ext[0] == FAT_PAD) {
/* ext is empty; the match will fail */
ext_processed = true;
} else if (PLB_GET_CHAR(cur) == dentry->ext[pos]) {
continue;
} else {
/* character mismatch */
return 0;
}
}
return 0; /* extra characters in the component */
}
if (ext_processed || (name_processed && dentry->ext[0] == FAT_PAD))
return cur - start;
else
return 0;
}
 
void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
{
int first = IPC_GET_ARG1(*request);
int second = IPC_GET_ARG2(*request);
int dev_handle = IPC_GET_ARG3(*request);
 
}
 
/**
* @}
*/
/branches/network/uspace/srv/fs/fat/Makefile
0,0 → 1,76
#
# Copyright (c) 2006 Martin Decky
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# - Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# - The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
 
## Setup toolchain
#
 
LIBC_PREFIX = ../../../lib/libc
LIBFS_PREFIX = ../../../lib/libfs
SOFTINT_PREFIX = ../../../lib/softint
include $(LIBC_PREFIX)/Makefile.toolchain
 
CFLAGS += -I $(LIBFS_PREFIX)
 
LIBS = $(LIBC_PREFIX)/libc.a $(LIBFS_PREFIX)/libfs.a
 
## Sources
#
 
OUTPUT = fat
SOURCES = \
fat.c \
fat_ops.c
 
OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
 
.PHONY: all clean depend disasm
 
all: $(OUTPUT) disasm
 
-include Makefile.depend
 
clean:
-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend
 
depend:
$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
 
$(OUTPUT): $(OBJECTS) $(LIBS)
$(LD) -T $(LIBC_PREFIX)/arch/$(ARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
 
disasm:
$(OBJDUMP) -d $(OUTPUT) >$(OUTPUT).disasm
 
%.o: %.S
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
 
%.o: %.s
$(AS) $(AFLAGS) $< -o $@
 
%.o: %.c
$(CC) $(DEFS) $(CFLAGS) -c $< -o $@