/* * COPYRIGHT (c) 2010 Chris Johns * * 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. */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include uint64_t rtems_rfs_fs_size (rtems_rfs_file_system* fs) { uint64_t blocks = rtems_rfs_fs_blocks (fs); uint64_t block_size = rtems_rfs_fs_block_size (fs); return blocks * block_size; } uint64_t rtems_rfs_fs_media_size (rtems_rfs_file_system* fs) { uint64_t media_blocks = (uint64_t) rtems_rfs_fs_media_blocks (fs); uint64_t media_block_size = (uint64_t) rtems_rfs_fs_media_block_size (fs); return media_blocks * media_block_size; } 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) { if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) printf ("rtems-rfs: read-superblock: invalid superblock, bad magic\n"); rtems_rfs_buffer_handle_close (fs, &handle); 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)) { if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) printf ("rtems-rfs: read-superblock: invalid superblock block/size count\n"); rtems_rfs_buffer_handle_close (fs, &handle); return EIO; } if ((read_sb (RTEMS_RFS_SB_OFFSET_VERSION) & RTEMS_RFS_VERSION_MASK) != (RTEMS_RFS_VERSION * RTEMS_RFS_VERSION_MASK)) { if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) printf ("rtems-rfs: read-superblock: incompatible version: %08" PRIx32 " (%08" PRIx32 ")\n", read_sb (RTEMS_RFS_SB_OFFSET_VERSION), RTEMS_RFS_VERSION_MASK); rtems_rfs_buffer_handle_close (fs, &handle); return EIO; } if (read_sb (RTEMS_RFS_SB_OFFSET_INODE_SIZE) != RTEMS_RFS_INODE_SIZE) { if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN)) printf ("rtems-rfs: read-superblock: inode size mismatch: fs:%" PRId32 " target:%" PRId32 "\n", read_sb (RTEMS_RFS_SB_OFFSET_VERSION), RTEMS_RFS_VERSION_MASK); rtems_rfs_buffer_handle_close (fs, &handle); 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 / RTEMS_RFS_INODE_SIZE; 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; }