/* * 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 Inode Routines. * * These functions manage inodes in the RFS file system. An inode is part of a * block that reside after the bitmaps in the group. */ #include #include #include #include int rtems_rfs_inode_alloc (rtems_rfs_file_system* fs, rtems_rfs_bitmap_bit goal, rtems_rfs_ino* ino) { rtems_rfs_bitmap_bit bit; int rc; rc = rtems_rfs_group_bitmap_alloc (fs, goal, true, &bit); *ino = bit; return rc; } int rtems_rfs_inode_free (rtems_rfs_file_system* fs, rtems_rfs_ino ino) { rtems_rfs_bitmap_bit bit; bit = ino; return rtems_rfs_group_bitmap_free (fs, true, bit); } int rtems_rfs_inode_open (rtems_rfs_file_system* fs, rtems_rfs_ino ino, rtems_rfs_inode_handle* handle, bool load) { int group; int gino; int index; int rc; if (rtems_rfs_trace (RTEMS_RFS_TRACE_INODE_OPEN)) printf ("rtems-rfs: inode-open: ino: %lu\n", ino); if (ino == RTEMS_RFS_EMPTY_INO) return EINVAL; if ((ino - RTEMS_RFS_ROOT_INO) > rtems_rfs_fs_inodes (fs)) return EINVAL; handle->ino = ino; handle->node = NULL; handle->loads = 0; gino = ino - RTEMS_RFS_ROOT_INO; group = gino / fs->group_inodes; gino = gino % fs->group_inodes; index = (gino / fs->inodes_per_block) + RTEMS_RFS_GROUP_INODE_BLOCK; handle->offset = gino % fs->inodes_per_block; handle->block = rtems_rfs_group_block (&fs->groups[group], index); rc = rtems_rfs_buffer_handle_open (fs, &handle->buffer); if ((rc == 0) && load) rc = rtems_rfs_inode_load (fs, handle); return rc; } int rtems_rfs_inode_close (rtems_rfs_file_system* fs, rtems_rfs_inode_handle* handle) { int rc; if (rtems_rfs_trace (RTEMS_RFS_TRACE_INODE_CLOSE)) printf ("rtems-rfs: inode-close: ino: %lu\n", handle->ino); rc = rtems_rfs_inode_unload (fs, handle, true); if ((rc == 0) && (handle->loads > 0)) { if (rtems_rfs_trace (RTEMS_RFS_TRACE_INODE_CLOSE)) printf ("rtems-rfs: inode-close: bad loads number: %d\n", handle->loads); rc = EIO; } handle->ino = 0; return rc; } int rtems_rfs_inode_load (rtems_rfs_file_system* fs, rtems_rfs_inode_handle* handle) { if (rtems_rfs_trace (RTEMS_RFS_TRACE_INODE_LOAD)) printf ("rtems-rfs: inode-load: ino=%lu loads=%i loaded=%s\n", handle->ino, handle->loads, rtems_rfs_inode_is_loaded (handle) ? "yes" : "no"); /* * An inode does not move so once loaded no need to do again. */ if (!rtems_rfs_inode_is_loaded (handle)) { int rc; rc = rtems_rfs_buffer_handle_request (fs,&handle->buffer, handle->block, true); if (rc > 0) return rc; handle->node = rtems_rfs_buffer_data (&handle->buffer); handle->node += handle->offset; } handle->loads++; return 0; } int rtems_rfs_inode_unload (rtems_rfs_file_system* fs, rtems_rfs_inode_handle* handle, bool update_ctime) { int rc = 0; if (rtems_rfs_trace (RTEMS_RFS_TRACE_INODE_UNLOAD)) printf ("rtems-rfs: inode-unload: ino=%lu loads=%i loaded=%s\n", handle->ino, handle->loads, rtems_rfs_inode_is_loaded (handle) ? "yes" : "no"); if (rtems_rfs_inode_is_loaded (handle)) { if (handle->loads == 0) return EIO; handle->loads--; if (handle->loads == 0) { /* * If the buffer is dirty it will be release. Also set the ctime. */ if (rtems_rfs_buffer_dirty (&handle->buffer) && update_ctime) rtems_rfs_inode_set_ctime (handle, time (NULL)); rc = rtems_rfs_buffer_handle_release (fs, &handle->buffer); handle->node = NULL; } } return rc; } int rtems_rfs_inode_create (rtems_rfs_file_system* fs, rtems_rfs_ino parent, const char* name, size_t length, uint16_t mode, uint16_t links, uid_t uid, gid_t gid, rtems_rfs_ino* ino) { rtems_rfs_inode_handle parent_inode; rtems_rfs_inode_handle inode; int rc; if (rtems_rfs_trace (RTEMS_RFS_TRACE_INODE_CREATE)) { const char* type = "unknown"; int c; if (RTEMS_RFS_S_ISDIR (mode)) type = "dir"; else if (RTEMS_RFS_S_ISCHR (mode)) type = "char"; else if (RTEMS_RFS_S_ISBLK (mode)) type = "block"; else if (RTEMS_RFS_S_ISREG (mode)) type = "file"; else if (RTEMS_RFS_S_ISLNK (mode)) type = "link"; printf("rtems-rfs: inode-create: parent:%lu name:", parent); for (c = 0; c < length; c++) printf ("%c", name[c]); printf (" type:%s mode:%04x (%03o)\n", type, mode, mode & ((1 << 10) - 1)); } rc = rtems_rfs_inode_alloc (fs, parent, ino); if (rc > 0) return rc; rc = rtems_rfs_inode_open (fs, *ino, &inode, true); if (rc > 0) return rc; rc = rtems_rfs_inode_initialise (&inode, links, mode, uid, gid); if (rc > 0) { rtems_rfs_inode_close (fs, &inode); rtems_rfs_inode_free (fs, *ino); return rc; } /* * Only handle the specifics of a directory. Let caller handle the others. */ if (RTEMS_RFS_S_ISDIR (mode)) { rc = rtems_rfs_dir_add_entry (fs, &inode, ".", 1, *ino); if (rc == 0) rc = rtems_rfs_dir_add_entry (fs, &inode, "..", 2, parent); if (rc > 0) { rtems_rfs_inode_delete (fs, &inode); rtems_rfs_inode_close (fs, &inode); return rc; } } rc = rtems_rfs_inode_open (fs, parent, &parent_inode, true); if (rc > 0) { rtems_rfs_inode_delete (fs, &inode); rtems_rfs_inode_close (fs, &inode); return rc; } rc = rtems_rfs_dir_add_entry (fs, &parent_inode, name, length, *ino); if (rc > 0) { rtems_rfs_inode_delete (fs, &inode); rtems_rfs_inode_close (fs, &inode); rtems_rfs_inode_close (fs, &parent_inode); return rc; } /* * If the node is a directory update the parent link count as the * new directory has the '..' link that points to the parent. */ if (RTEMS_RFS_S_ISDIR (mode)) rtems_rfs_inode_set_links (&parent_inode, rtems_rfs_inode_get_links (&parent_inode) + 1); rc = rtems_rfs_inode_close (fs, &parent_inode); if (rc > 0) { rtems_rfs_inode_delete (fs, &inode); rtems_rfs_inode_close (fs, &inode); return rc; } rc = rtems_rfs_inode_close (fs, &inode); if (rc > 0) { rtems_rfs_inode_free (fs, *ino); return rc; } return 0; } int rtems_rfs_inode_delete (rtems_rfs_file_system* fs, rtems_rfs_inode_handle* handle) { int rc = 0; if (rtems_rfs_inode_is_loaded (handle)) { rtems_rfs_block_map map; /* * Free the ino number. */ rc = rtems_rfs_inode_free (fs, handle->ino); if (rc > 0) return rc; /* * Free the blocks the inode may have attached. */ rc = rtems_rfs_block_map_open (fs, handle, &map); if (rc == 0) { int rrc; rrc = rtems_rfs_block_map_free_all (fs, &map); rc = rtems_rfs_block_map_close (fs, &map); if (rc > 0) rrc = rc; memset (handle->node, 0xff, sizeof (rtems_rfs_inode)); rtems_rfs_buffer_mark_dirty (&handle->buffer); /* * Do the release here to avoid the ctime field being set on a * close. Also if there loads is greater then one then other loads * active. Forcing the loads count to 0. */ rc = rtems_rfs_buffer_handle_release (fs, &handle->buffer); handle->loads = 0; handle->node = NULL; } } return rc; } int rtems_rfs_inode_initialise (rtems_rfs_inode_handle* handle, uint16_t links, uint16_t mode, uid_t uid, gid_t gid) { int b; rtems_rfs_inode_set_links (handle, links); rtems_rfs_inode_set_flags (handle, 0); rtems_rfs_inode_set_mode (handle, mode); rtems_rfs_inode_set_uid_gid (handle, uid, gid); rtems_rfs_inode_set_block_offset (handle, 0); rtems_rfs_inode_set_block_count (handle, 0); for (b = 0; b < RTEMS_RFS_INODE_BLOCKS; b++) rtems_rfs_inode_set_block (handle, b, 0); rtems_rfs_inode_set_last_map_block (handle, 0); rtems_rfs_inode_set_last_data_block (handle, 0); return rtems_rfs_inode_time_stamp_now (handle, true, true); } int rtems_rfs_inode_time_stamp_now (rtems_rfs_inode_handle* handle, bool atime, bool mtime) { time_t now; if (!rtems_rfs_inode_is_loaded (handle)) return ENXIO; now = time (NULL); if (atime) rtems_rfs_inode_set_atime (handle, now); if (mtime) rtems_rfs_inode_set_mtime (handle, now); return 0; } rtems_rfs_pos rtems_rfs_inode_get_size (rtems_rfs_file_system* fs, rtems_rfs_inode_handle* handle) { rtems_rfs_block_size size; size.count = rtems_rfs_inode_get_block_count (handle); size.offset = rtems_rfs_inode_get_block_offset (handle); return rtems_rfs_block_get_size (fs, &size); }