diff options
Diffstat (limited to 'cpukit/libfs/src/rfs/rtems-rfs-file-system.c')
-rw-r--r-- | cpukit/libfs/src/rfs/rtems-rfs-file-system.c | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-file-system.c b/cpukit/libfs/src/rfs/rtems-rfs-file-system.c new file mode 100644 index 0000000000..ce355be824 --- /dev/null +++ b/cpukit/libfs/src/rfs/rtems-rfs-file-system.c @@ -0,0 +1,278 @@ +/* + * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ +/** + * @file + * + * @ingroup rtems-rfs + * + * RTEMS File Systems Open + * + * Open the file system by reading the superblock and then the group data. + */ + +#include <rtems/rfs/rtems-rfs-data.h> +#include <rtems/rfs/rtems-rfs-file-system.h> +#include <rtems/rfs/rtems-rfs-inode.h> +#include <rtems/rfs/rtems-rfs-trace.h> + +static int +rtems_rfs_fs_read_superblock (rtems_rfs_file_system* fs) +{ + rtems_rfs_buffer_handle handle; + uint8_t* sb; + int group; + int rc; + + rc = rtems_rfs_buffer_handle_open (fs, &handle); + if (rc > 0) + { + if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) + printf ("rtems-rfs: read-superblock: handle open failed: %d: %s\n", + rc, strerror (rc)); + return rc; + } + + rc = rtems_rfs_buffer_handle_request (fs, &handle, 0, true); + if (rc > 0) + { + if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) + printf ("rtems-rfs: read-superblock: request failed%d: %s\n", + rc, strerror (rc)); + return rc; + } + + sb = rtems_rfs_buffer_data (&handle); + +#define read_sb(_o) rtems_rfs_read_u32 (sb + (_o)) + + if (read_sb (RTEMS_RFS_SB_OFFSET_MAGIC) != RTEMS_RFS_SB_MAGIC) + { + rtems_rfs_buffer_handle_close (fs, &handle); + if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) + printf ("rtems-rfs: read-superblock: invalid superblock, bad magic\n"); + return EIO; + } + + fs->blocks = read_sb (RTEMS_RFS_SB_OFFSET_BLOCKS); + fs->block_size = read_sb (RTEMS_RFS_SB_OFFSET_BLOCK_SIZE); + + if (rtems_rfs_fs_size(fs) > rtems_rfs_fs_media_size (fs)) + { + rtems_rfs_buffer_handle_close (fs, &handle); + if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) + printf ("rtems-rfs: read-superblock: invalid superblock block/size count\n"); + return EIO; + } + + fs->bad_blocks = read_sb (RTEMS_RFS_SB_OFFSET_BAD_BLOCKS); + fs->max_name_length = read_sb (RTEMS_RFS_SB_OFFSET_MAX_NAME_LENGTH); + fs->group_count = read_sb (RTEMS_RFS_SB_OFFSET_GROUPS); + fs->group_blocks = read_sb (RTEMS_RFS_SB_OFFSET_GROUP_BLOCKS); + fs->group_inodes = read_sb (RTEMS_RFS_SB_OFFSET_GROUP_INODES); + + fs->blocks_per_block = rtems_rfs_fs_block_size (fs) / sizeof (rtems_rfs_inode_block); + + fs->block_map_singly_blocks = + fs->blocks_per_block * RTEMS_RFS_INODE_BLOCKS; + fs->block_map_doubly_blocks = + fs->blocks_per_block * fs->blocks_per_block * RTEMS_RFS_INODE_BLOCKS; + + fs->inodes = fs->group_count * fs->group_inodes; + + fs->inodes_per_block = fs->block_size / sizeof (rtems_rfs_inode); + + if (fs->group_blocks > + rtems_rfs_bitmap_numof_bits (rtems_rfs_fs_block_size (fs))) + { + rtems_rfs_buffer_handle_close (fs, &handle); + if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) + printf ("rtems-rfs: read-superblock: groups blocks larger than block bits\n"); + return EIO; + } + + rtems_rfs_buffer_handle_close (fs, &handle); + + /* + * Change the block size to the value in the superblock. + */ + rc = rtems_rfs_buffer_setblksize (fs, rtems_rfs_fs_block_size (fs)); + if (rc > 0) + { + rtems_rfs_buffer_handle_close (fs, &handle); + if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) + printf ("rtems-rfs: read-superblock: invalid superblock block size%d: %s\n", + rc, strerror (rc)); + return rc; + } + + fs->groups = calloc (fs->group_count, sizeof (rtems_rfs_group)); + + if (!fs->groups) + { + rtems_rfs_buffer_handle_close (fs, &handle); + if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) + printf ("rtems-rfs: read-superblock: no memory for group table\n"); + return ENOMEM; + } + + /* + * Perform each phase of group initialisation at the same time. This way we + * know how far the initialisation has gone if an error occurs and we need to + * close everything. + */ + for (group = 0; group < fs->group_count; group++) + { + rc = rtems_rfs_group_open (fs, + rtems_rfs_fs_block (fs, group, 0), + fs->group_blocks, + fs->group_inodes, + &fs->groups[group]); + if (rc > 0) + { + int g; + for (g = 0; g < group; g++) + rtems_rfs_group_close (fs, &fs->groups[g]); + rtems_rfs_buffer_handle_close (fs, &handle); + if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) + printf ("rtems-rfs: read-superblock: no memory for group table%d: %s\n", + rc, strerror (rc)); + return rc; + } + } + + return 0; +} + +int +rtems_rfs_fs_open (const char* name, + void* user, + uint32_t flags, + rtems_rfs_file_system** fs) +{ + rtems_rfs_group* group; + size_t group_base; + rtems_rfs_inode_handle inode; + uint16_t mode; + int rc; + + if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) + printf ("rtems-rfs: open: %s\n", name); + + *fs = malloc (sizeof (rtems_rfs_file_system)); + if (!*fs) + { + if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) + printf ("rtems-rfs: open: no memory for file system data\n"); + errno = ENOMEM; + return -1; + } + + memset (*fs, 0, sizeof (rtems_rfs_file_system)); + + (*fs)->user = user; + rtems_chain_initialize_empty (&(*fs)->buffers); + rtems_chain_initialize_empty (&(*fs)->release); + rtems_chain_initialize_empty (&(*fs)->release_modified); + rtems_chain_initialize_empty (&(*fs)->file_shares); + + (*fs)->max_held_buffers = RTEMS_RFS_FS_MAX_HELD_BUFFERS; + (*fs)->buffers_count = 0; + (*fs)->release_count = 0; + (*fs)->release_modified_count = 0; + (*fs)->flags = flags; + + group = &(*fs)->groups[0]; + group_base = 0; + + /* + * Open the buffer interface. + */ + rc = rtems_rfs_buffer_open (name, *fs); + if (rc > 0) + { + free (*fs); + if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) + printf ("rtems-rfs: open: buffer open failed: %d: %s\n", + rc, strerror (rc)); + errno = rc; + return -1; + } + + rc = rtems_rfs_fs_read_superblock (*fs); + if (rc > 0) + { + rtems_rfs_buffer_close (*fs); + free (*fs); + if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) + printf ("rtems-rfs: open: reading superblock: %d: %s\n", + rc, strerror (rc)); + errno = rc; + return -1; + } + + rc = rtems_rfs_inode_open (*fs, RTEMS_RFS_ROOT_INO, &inode, true); + if (rc > 0) + { + rtems_rfs_buffer_close (*fs); + free (*fs); + if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) + printf ("rtems-rfs: open: reading root inode: %d: %s\n", + rc, strerror (rc)); + errno = rc; + return -1; + } + + if (((*fs)->flags & RTEMS_RFS_FS_FORCE_OPEN) == 0) + { + mode = rtems_rfs_inode_get_mode (&inode); + + if ((mode == 0xffff) || !RTEMS_RFS_S_ISDIR (mode)) + { + rtems_rfs_inode_close (*fs, &inode); + rtems_rfs_buffer_close (*fs); + free (*fs); + if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) + printf ("rtems-rfs: open: invalid root inode mode\n"); + errno = EIO; + return -1; + } + } + + rc = rtems_rfs_inode_close (*fs, &inode); + if (rc > 0) + { + rtems_rfs_buffer_close (*fs); + free (*fs); + if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) + printf ("rtems-rfs: open: closing root inode: %d: %s\n", rc, strerror (rc)); + errno = rc; + return -1; + } + + errno = 0; + return 0; +} + +int +rtems_rfs_fs_close (rtems_rfs_file_system* fs) +{ + int group; + + if (rtems_rfs_trace (RTEMS_RFS_TRACE_CLOSE)) + printf ("rtems-rfs: close\n"); + + for (group = 0; group < fs->group_count; group++) + rtems_rfs_group_close (fs, &fs->groups[group]); + + rtems_rfs_buffer_close (fs); + + free (fs); + return 0; +} |