Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3152 → Rev 3153

/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)))
 
/branches/dynload/uspace/srv/fs/fat/fat_idx.c
74,6 → 74,32
/** List of unused structures. */
static LIST_INITIALIZE(unused_head);
 
static void unused_initialize(unused_t *u, dev_handle_t dev_handle)
{
link_initialize(&u->link);
u->dev_handle = dev_handle;
u->next = 0;
u->remaining = ((uint64_t)((fs_index_t)-1)) + 1;
list_initialize(&u->freed_head);
}
 
static unused_t *unused_find(dev_handle_t dev_handle, bool lock)
{
unused_t *u;
link_t *l;
 
if (lock)
futex_down(&unused_futex);
for (l = unused_head.next; l != &unused_head; l = l->next) {
u = list_get_instance(l, unused_t, link);
if (u->dev_handle == dev_handle)
return u;
}
if (lock)
futex_up(&unused_futex);
return NULL;
}
 
/** Futex protecting the up_hash and ui_hash. */
static futex_t used_futex = FUTEX_INITIALIZER;
 
190,22 → 216,13
/** Allocate a VFS index which is not currently in use. */
static bool fat_idx_alloc(dev_handle_t dev_handle, fs_index_t *index)
{
link_t *l;
unused_t *u;
assert(index);
futex_down(&unused_futex);
for (l = unused_head.next; l != &unused_head; l = l->next) {
u = list_get_instance(l, unused_t, link);
if (u->dev_handle == dev_handle)
goto hit;
}
futex_up(&unused_futex);
/* dev_handle not found */
return false;
u = unused_find(dev_handle, true);
if (!u)
return false;
 
hit:
if (list_empty(&u->freed_head)) {
if (u->remaining) {
/*
261,21 → 278,11
/** Free a VFS index, which is no longer in use. */
static void fat_idx_free(dev_handle_t dev_handle, fs_index_t index)
{
link_t *l;
unused_t *u;
 
futex_down(&unused_futex);
for (l = unused_head.next; l != &unused_head; l = l->next) {
u = list_get_instance(l, unused_t, link);
if (u->dev_handle == dev_handle)
goto hit;
}
futex_up(&unused_futex);
u = unused_find(dev_handle, true);
assert(u);
 
/* should not happen */
assert(0);
 
hit:
if (u->next == index + 1) {
/* The index can be returned directly to the counter. */
u->next--;
401,3 → 408,60
return fidx;
}
 
int fat_idx_init(void)
{
if (!hash_table_create(&up_hash, UPH_BUCKETS, 3, &uph_ops))
return ENOMEM;
if (!hash_table_create(&ui_hash, UIH_BUCKETS, 2, &uih_ops)) {
hash_table_destroy(&up_hash);
return ENOMEM;
}
return EOK;
}
 
void fat_idx_fini(void)
{
/* We assume the hash tables are empty. */
hash_table_destroy(&up_hash);
hash_table_destroy(&ui_hash);
}
 
int fat_idx_init_by_dev_handle(dev_handle_t dev_handle)
{
unused_t *u;
int rc = EOK;
 
u = (unused_t *) malloc(sizeof(unused_t));
if (!u)
return ENOMEM;
unused_initialize(u, dev_handle);
futex_down(&unused_futex);
if (!unused_find(dev_handle, false))
list_append(&u->link, &unused_head);
else
rc = EEXIST;
futex_up(&unused_futex);
return rc;
}
 
void fat_idx_fini_by_dev_handle(dev_handle_t dev_handle)
{
unused_t *u;
 
u = unused_find(dev_handle, true);
assert(u);
list_remove(&u->link);
futex_up(&unused_futex);
 
while (!list_empty(&u->freed_head)) {
freed_t *f;
f = list_get_instance(u->freed_head.next, freed_t, link);
list_remove(&f->link);
free(f);
}
free(u);
}
 
/**
* @}
*/
/branches/dynload/uspace/srv/fs/fat/fat.h
40,7 → 40,9
#include <bool.h>
#include "../../vfs/vfs.h"
 
#ifndef dprintf
#define dprintf(...) printf(__VA_ARGS__)
#endif
 
typedef struct {
uint8_t ji[3]; /**< Jump instruction. */
217,11 → 219,18
 
extern fs_reg_t fat_reg;
 
extern void fat_mounted(ipc_callid_t, ipc_call_t *);
extern void fat_mount(ipc_callid_t, ipc_call_t *);
extern void fat_lookup(ipc_callid_t, ipc_call_t *);
 
extern fat_idx_t *fat_idx_get_by_pos(dev_handle_t, fat_cluster_t, unsigned);
extern fat_idx_t *fat_idx_get_by_index(dev_handle_t, fs_index_t);
 
extern int fat_idx_init(void);
extern void fat_idx_fini(void);
extern int fat_idx_init_by_dev_handle(dev_handle_t);
extern void fat_idx_fini_by_dev_handle(dev_handle_t);
 
#endif
 
/**
/branches/dynload/uspace/srv/fs/fat/fat.c
55,6 → 55,7
[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_MOUNT)] = VFS_OP_NULL,
[IPC_METHOD_TO_VFS_OP(VFS_MOUNTED)] = VFS_OP_DEFINED,
[IPC_METHOD_TO_VFS_OP(VFS_UNMOUNT)] = VFS_OP_NULL,
}
};
97,6 → 98,12
callid = async_get_call(&call);
switch (IPC_GET_METHOD(call)) {
case VFS_MOUNTED:
fat_mounted(callid, &call);
break;
case VFS_MOUNT:
fat_mount(callid, &call);
break;
case VFS_LOOKUP:
fat_lookup(callid, &call);
break;
110,9 → 117,14
int main(int argc, char **argv)
{
int vfs_phone;
int rc;
 
printf("FAT: HelenOS FAT file system server.\n");
 
rc = fat_idx_init();
if (rc != EOK)
goto err;
 
vfs_phone = ipc_connect_me_to(PHONE_NS, SERVICE_VFS, 0, 0);
while (vfs_phone < EOK) {
usleep(10000);
119,11 → 131,10
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;
fat_idx_fini();
goto err;
}
dprintf("FAT filesystem registered, fs_handle=%d.\n",
132,6 → 143,10
async_manager();
/* not reached */
return 0;
 
err:
printf("Failed to register the FAT file system (%d)\n", rc);
return rc;
}
 
/**
/branches/dynload/uspace/srv/fs/fat/fat_ops.c
112,12 → 112,17
#define FAT_BS(b) ((fat_bs_t *)((b)->data))
 
#define FAT_CLST_RES0 0x0000
#define FAT_CLST_RES1 0x0001 /* internally used to mark root directory */
#define FAT_CLST_RES1 0x0001
#define FAT_CLST_FIRST 0x0002
#define FAT_CLST_BAD 0xfff7
#define FAT_CLST_LAST1 0xfff8
#define FAT_CLST_LAST8 0xffff
 
/* internally used to mark root directory's parent */
#define FAT_CLST_ROOTPAR FAT_CLST_RES0
/* internally used to mark root directory */
#define FAT_CLST_ROOT FAT_CLST_RES1
 
#define fat_block_get(np, off) \
_fat_block_get((np)->idx->dev_handle, (np)->firstc, (off))
 
151,7 → 156,7
rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
ssa = rscnt + fatcnt * sf + rds;
 
if (firstc == FAT_CLST_RES1) {
if (firstc == FAT_CLST_ROOT) {
/* root directory special case */
assert(offset < rds);
b = block_get(dev_handle, rscnt + fatcnt * sf + offset);
521,7 → 526,7
 
static void *fat_root_get(dev_handle_t dev_handle)
{
return NULL; /* TODO */
return fat_node_get(dev_handle, 0);
}
 
static char fat_plb_get_char(unsigned pos)
558,6 → 563,60
.is_file = fat_is_file
};
 
void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
{
dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
block_t *bb;
uint16_t rde;
int rc;
 
/* Read the number of root directory entries. */
bb = block_get(dev_handle, BS_BLOCK);
rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
block_put(bb);
 
rc = fat_idx_init_by_dev_handle(dev_handle);
if (rc != EOK) {
ipc_answer_0(rid, rc);
return;
}
 
/* Initialize the root node. */
fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
if (!rootp) {
fat_idx_fini_by_dev_handle(dev_handle);
ipc_answer_0(rid, ENOMEM);
return;
}
fat_node_initialize(rootp);
 
fat_idx_t *ridxp = fat_idx_get_by_pos(dev_handle, FAT_CLST_ROOTPAR, 0);
if (!ridxp) {
free(rootp);
fat_idx_fini_by_dev_handle(dev_handle);
ipc_answer_0(rid, ENOMEM);
return;
}
assert(ridxp->index == 0);
/* ridxp->lock held */
 
rootp->type = FAT_DIRECTORY;
rootp->firstc = FAT_CLST_ROOT;
rootp->refcnt = 1;
rootp->size = rde * sizeof(fat_dentry_t);
rootp->idx = ridxp;
ridxp->nodep = rootp;
futex_up(&ridxp->lock);
 
ipc_answer_0(rid, EOK);
}
 
void fat_mount(ipc_callid_t rid, ipc_call_t *request)
{
ipc_answer_0(rid, ENOTSUP);
}
 
void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
{
libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);