/branches/dynload/uspace/srv/fs/tmpfs/tmpfs.h |
---|
40,7 → 40,9 |
#include <bool.h> |
#include <libadt/hash_table.h> |
#ifndef dprintf |
#define dprintf(...) printf(__VA_ARGS__) |
#endif |
typedef struct tmpfs_dentry { |
fs_index_t index; /**< TMPFS node index. */ |
60,6 → 62,9 |
extern fs_reg_t tmpfs_reg; |
extern libfs_ops_t tmpfs_libfs_ops; |
extern void tmpfs_mounted(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_mount(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_lookup(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_read(ipc_callid_t, ipc_call_t *); |
67,6 → 72,8 |
extern void tmpfs_truncate(ipc_callid_t, ipc_call_t *); |
extern void tmpfs_destroy(ipc_callid_t, ipc_call_t *); |
extern bool tmpfs_restore(dev_handle_t); |
#endif |
/** |
/branches/dynload/uspace/srv/fs/tmpfs/tmpfs_dump.c |
---|
0,0 → 1,253 |
/* |
* Copyright (c) 2008 Jakub Jermar |
* Copyright (c) 2008 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. |
*/ |
/** @addtogroup fs |
* @{ |
*/ |
/** |
* @file tmpfs_dump.c |
* @brief Support for loading TMPFS file system dump. |
*/ |
#include "tmpfs.h" |
#include "../../vfs/vfs.h" |
#include <ipc/ipc.h> |
#include <errno.h> |
#include <stdlib.h> |
#include <string.h> |
#include <sys/types.h> |
#include <as.h> |
#include <libfs.h> |
#include <ipc/services.h> |
#include <ipc/devmap.h> |
#include <sys/mman.h> |
#include <byteorder.h> |
#define BLOCK_SIZE 1024 // FIXME |
#define RD_BASE 1024 // FIXME |
#define RD_READ_BLOCK (RD_BASE + 1) |
struct rdentry { |
uint8_t type; |
uint32_t len; |
} __attribute__((packed)); |
static bool |
tmpfs_blockread(int phone, void *buffer, size_t *bufpos, size_t *buflen, |
size_t *pos, void *dst, size_t size) |
{ |
size_t offset = 0; |
size_t left = size; |
while (left > 0) { |
size_t rd; |
if (*bufpos + left < *buflen) |
rd = left; |
else |
rd = *buflen - *bufpos; |
if (rd > 0) { |
memcpy(dst + offset, buffer + *bufpos, rd); |
offset += rd; |
*bufpos += rd; |
*pos += rd; |
left -= rd; |
} |
if (*bufpos == *buflen) { |
ipcarg_t retval; |
int rc = ipc_call_sync_2_1(phone, RD_READ_BLOCK, |
*pos / BLOCK_SIZE, BLOCK_SIZE, |
&retval); |
if ((rc != EOK) || (retval != EOK)) |
return false; |
*bufpos = 0; |
*buflen = BLOCK_SIZE; |
} |
} |
return true; |
} |
static bool |
tmpfs_restore_recursion(int phone, void *block, size_t *bufpos, size_t *buflen, |
size_t *pos, tmpfs_dentry_t *parent) |
{ |
struct rdentry entry; |
libfs_ops_t *ops = &tmpfs_libfs_ops; |
do { |
char *fname; |
tmpfs_dentry_t *node; |
uint32_t size; |
if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, &entry, |
sizeof(entry))) |
return false; |
entry.len = uint32_t_le2host(entry.len); |
switch (entry.type) { |
case 0: |
break; |
case 1: |
fname = malloc(entry.len + 1); |
if (fname == NULL) |
return false; |
node = (tmpfs_dentry_t *) ops->create(L_FILE); |
if (node == NULL) { |
free(fname); |
return false; |
} |
if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, |
fname, entry.len)) { |
ops->destroy((void *) node); |
free(fname); |
return false; |
} |
fname[entry.len] = 0; |
if (!ops->link((void *) parent, (void *) node, fname)) { |
ops->destroy((void *) node); |
free(fname); |
return false; |
} |
free(fname); |
if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, |
&size, sizeof(size))) |
return false; |
size = uint32_t_le2host(size); |
node->data = malloc(size); |
if (node->data == NULL) |
return false; |
node->size = size; |
if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, |
node->data, size)) |
return false; |
break; |
case 2: |
fname = malloc(entry.len + 1); |
if (fname == NULL) |
return false; |
node = (tmpfs_dentry_t *) ops->create(L_DIRECTORY); |
if (node == NULL) { |
free(fname); |
return false; |
} |
if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, |
fname, entry.len)) { |
ops->destroy((void *) node); |
free(fname); |
return false; |
} |
fname[entry.len] = 0; |
if (!ops->link((void *) parent, (void *) node, fname)) { |
ops->destroy((void *) node); |
free(fname); |
return false; |
} |
free(fname); |
if (!tmpfs_restore_recursion(phone, block, bufpos, |
buflen, pos, node)) |
return false; |
break; |
default: |
return false; |
} |
} while (entry.type != 0); |
return true; |
} |
bool tmpfs_restore(dev_handle_t dev) |
{ |
libfs_ops_t *ops = &tmpfs_libfs_ops; |
void *block = mmap(NULL, BLOCK_SIZE, |
PROTO_READ | PROTO_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); |
if (block == NULL) |
return false; |
int phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, |
DEVMAP_CONNECT_TO_DEVICE, dev); |
if (phone < 0) { |
munmap(block, BLOCK_SIZE); |
return false; |
} |
if (ipc_share_out_start(phone, block, AS_AREA_READ | AS_AREA_WRITE) != |
EOK) |
goto error; |
size_t bufpos = 0; |
size_t buflen = 0; |
size_t pos = 0; |
char tag[6]; |
if (!tmpfs_blockread(phone, block, &bufpos, &buflen, &pos, tag, 5)) |
goto error; |
tag[5] = 0; |
if (strcmp(tag, "TMPFS") != 0) |
goto error; |
if (!tmpfs_restore_recursion(phone, block, &bufpos, &buflen, &pos, |
ops->root_get(dev))) |
goto error; |
ipc_hangup(phone); |
munmap(block, BLOCK_SIZE); |
return true; |
error: |
ipc_hangup(phone); |
munmap(block, BLOCK_SIZE); |
return false; |
} |
/** |
* @} |
*/ |
/branches/dynload/uspace/srv/fs/tmpfs/tmpfs.c |
---|
61,6 → 61,7 |
[IPC_METHOD_TO_VFS_OP(VFS_WRITE)] = VFS_OP_DEFINED, |
[IPC_METHOD_TO_VFS_OP(VFS_TRUNCATE)] = VFS_OP_DEFINED, |
[IPC_METHOD_TO_VFS_OP(VFS_MOUNT)] = VFS_OP_DEFINED, |
[IPC_METHOD_TO_VFS_OP(VFS_MOUNTED)] = VFS_OP_DEFINED, |
[IPC_METHOD_TO_VFS_OP(VFS_UNMOUNT)] = VFS_OP_NULL, |
[IPC_METHOD_TO_VFS_OP(VFS_DESTROY)] = VFS_OP_DEFINED, |
} |
105,6 → 106,9 |
callid = async_get_call(&call); |
switch (IPC_GET_METHOD(call)) { |
case VFS_MOUNTED: |
tmpfs_mounted(callid, &call); |
break; |
case VFS_MOUNT: |
tmpfs_mount(callid, &call); |
break; |
/branches/dynload/uspace/srv/fs/tmpfs/tmpfs_ops.c |
---|
50,10 → 50,6 |
#include <libadt/hash_table.h> |
#include <as.h> |
#include <libfs.h> |
#include <ipc/services.h> |
#include <ipc/devmap.h> |
#include <sys/mman.h> |
#include <byteorder.h> |
#define min(a, b) ((a) < (b) ? (a) : (b)) |
#define max(a, b) ((a) > (b) ? (a) : (b)) |
62,10 → 58,6 |
#define NAMES_BUCKETS 4 |
#define BLOCK_SIZE 1024 // FIXME |
#define RD_BASE 1024 // FIXME |
#define RD_READ_BLOCK (RD_BASE + 1) |
/* |
* For now, we don't distinguish between different dev_handles/instances. All |
* requests resolve to the only instance, rooted in the following variable. |
148,11 → 140,6 |
/** Hash table of all directory entries. */ |
hash_table_t dentries; |
struct rdentry { |
uint8_t type; |
uint32_t len; |
} __attribute__((packed)); |
/* Implementation of hash table interface for the dentries hash table. */ |
static hash_index_t dentries_hash(unsigned long *key) |
{ |
250,177 → 237,6 |
return true; |
} |
static bool tmpfs_blockread(int phone, void *buffer, size_t *bufpos, size_t *buflen, size_t *pos, void *dst, size_t size) |
{ |
size_t offset = 0; |
size_t left = size; |
while (left > 0) { |
size_t rd; |
if (*bufpos + left < *buflen) |
rd = left; |
else |
rd = *buflen - *bufpos; |
if (rd > 0) { |
memcpy(dst + offset, buffer + *bufpos, rd); |
offset += rd; |
*bufpos += rd; |
*pos += rd; |
left -= rd; |
} |
if (*bufpos == *buflen) { |
int retval; |
int rc = ipc_call_sync_2_1(phone, RD_READ_BLOCK, *pos / BLOCK_SIZE, BLOCK_SIZE, (sysarg_t *) &retval); |
if ((rc != EOK) || (retval != EOK)) |
return false; |
*bufpos = 0; |
*buflen = BLOCK_SIZE; |
} |
} |
return true; |
} |
static bool tmpfs_restore_recursion(int phone, void *block, size_t *bufpos, size_t *buflen, size_t *pos, tmpfs_dentry_t *parent) |
{ |
struct rdentry entry; |
do { |
char *fname; |
tmpfs_dentry_t *node; |
uint32_t size; |
if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, &entry, sizeof(entry))) |
return false; |
entry.len = uint32_t_le2host(entry.len); |
switch (entry.type) { |
case 0: |
break; |
case 1: |
fname = malloc(entry.len + 1); |
if (fname == NULL) |
return false; |
node = (tmpfs_dentry_t *) tmpfs_create_node(L_FILE); |
if (node == NULL) { |
free(fname); |
return false; |
} |
if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, fname, entry.len)) { |
tmpfs_destroy_node((void *) node); |
free(fname); |
return false; |
} |
fname[entry.len] = 0; |
if (!tmpfs_link_node((void *) parent, (void *) node, fname)) { |
tmpfs_destroy_node((void *) node); |
free(fname); |
return false; |
} |
free(fname); |
if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, &size, sizeof(size))) |
return false; |
size = uint32_t_le2host(size); |
node->data = malloc(size); |
if (node->data == NULL) |
return false; |
node->size = size; |
if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, node->data, size)) |
return false; |
break; |
case 2: |
fname = malloc(entry.len + 1); |
if (fname == NULL) |
return false; |
node = (tmpfs_dentry_t *) tmpfs_create_node(L_DIRECTORY); |
if (node == NULL) { |
free(fname); |
return false; |
} |
if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, fname, entry.len)) { |
tmpfs_destroy_node((void *) node); |
free(fname); |
return false; |
} |
fname[entry.len] = 0; |
if (!tmpfs_link_node((void *) parent, (void *) node, fname)) { |
tmpfs_destroy_node((void *) node); |
free(fname); |
return false; |
} |
free(fname); |
if (!tmpfs_restore_recursion(phone, block, bufpos, buflen, pos, node)) |
return false; |
break; |
default: |
return false; |
} |
} while (entry.type != 0); |
return true; |
} |
static bool tmpfs_restore(dev_handle_t dev) |
{ |
void *block = mmap(NULL, BLOCK_SIZE, |
PROTO_READ | PROTO_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); |
if (block == NULL) |
return false; |
int phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, DEVMAP_CONNECT_TO_DEVICE, dev); |
if (phone < 0) { |
munmap(block, BLOCK_SIZE); |
return false; |
} |
if (ipc_share_out_start(phone, block, AS_AREA_READ | AS_AREA_WRITE) != EOK) |
goto error; |
size_t bufpos = 0; |
size_t buflen = 0; |
size_t pos = 0; |
char tag[6]; |
if (!tmpfs_blockread(phone, block, &bufpos, &buflen, &pos, tag, 5)) |
goto error; |
tag[5] = 0; |
if (strcmp(tag, "TMPFS") != 0) |
goto error; |
if (!tmpfs_restore_recursion(phone, block, &bufpos, &buflen, &pos, root)) |
goto error; |
ipc_hangup(phone); |
munmap(block, BLOCK_SIZE); |
return true; |
error: |
ipc_hangup(phone); |
munmap(block, BLOCK_SIZE); |
return false; |
} |
/** Compare one component of path to a directory entry. |
* |
* @param parentp Pointer to node from which we descended. |
577,36 → 393,38 |
return EOK; |
} |
void tmpfs_mounted(ipc_callid_t rid, ipc_call_t *request) |
{ |
dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request); |
/* Initialize TMPFS. */ |
if (!root && !tmpfs_init()) { |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
if (dev_handle >= 0) { |
if (tmpfs_restore(dev_handle)) |
ipc_answer_0(rid, EOK); |
else |
ipc_answer_0(rid, ELIMIT); |
} else { |
ipc_answer_0(rid, EOK); |
} |
} |
void tmpfs_mount(ipc_callid_t rid, ipc_call_t *request) |
{ |
dev_handle_t mr_dev_handle = (dev_handle_t) IPC_GET_ARG1(*request); |
fs_index_t mr_index = (fs_index_t) IPC_GET_ARG2(*request); |
fs_handle_t mp_fs_handle = (fs_handle_t) IPC_GET_ARG3(*request); |
dev_handle_t mp_dev_handle = (dev_handle_t) IPC_GET_ARG4(*request); |
fs_index_t mp_index = (fs_index_t) IPC_GET_ARG5(*request); |
dev_handle_t mp_dev_handle = (dev_handle_t) IPC_GET_ARG1(*request); |
fs_index_t mp_index = (fs_index_t) IPC_GET_ARG2(*request); |
fs_handle_t mr_fs_handle = (fs_handle_t) IPC_GET_ARG3(*request); |
dev_handle_t mr_dev_handle = (dev_handle_t) IPC_GET_ARG4(*request); |
if ((mr_index == root->index) && |
(mp_fs_handle == tmpfs_reg.fs_handle) && |
(mp_index == mr_index)) { |
if (mr_dev_handle >= 0) { |
if (tmpfs_restore(mr_dev_handle)) |
ipc_answer_0(rid, EOK); |
else |
ipc_answer_0(rid, ELIMIT); |
} else |
ipc_answer_0(rid, EOK); |
} else |
ipc_answer_0(rid, ENOTSUP); |
ipc_answer_0(rid, ENOTSUP); |
} |
void tmpfs_lookup(ipc_callid_t rid, ipc_call_t *request) |
{ |
/* Initialize TMPFS. */ |
if (!root && !tmpfs_init()) { |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
libfs_lookup(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request); |
} |
/branches/dynload/uspace/srv/fs/tmpfs/Makefile |
---|
44,7 → 44,8 |
OUTPUT = tmpfs |
SOURCES = \ |
tmpfs.c \ |
tmpfs_ops.c |
tmpfs_ops.c \ |
tmpfs_dump.c |
OBJECTS := $(addsuffix .o,$(basename $(SOURCES))) |