summaryrefslogtreecommitdiffstats
path: root/cpukit/libfs/src/rfs/rtems-rfs-inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libfs/src/rfs/rtems-rfs-inode.c')
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-inode.c402
1 files changed, 402 insertions, 0 deletions
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-inode.c b/cpukit/libfs/src/rfs/rtems-rfs-inode.c
new file mode 100644
index 0000000000..ab3f4b7e65
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-inode.c
@@ -0,0 +1,402 @@
+/*
+ * 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 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.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <inttypes.h>
+
+#include <rtems/rfs/rtems-rfs-block.h>
+#include <rtems/rfs/rtems-rfs-file-system.h>
+#include <rtems/rfs/rtems-rfs-inode.h>
+#include <rtems/rfs/rtems-rfs-dir.h>
+
+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: %" PRIu32 "\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: %" PRIu32 "\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=%" PRIu32 " 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=%" PRIu32 " 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:%" PRIu32 " 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));
+ }
+
+ /*
+ * The file type is field within the mode. Check we have a sane mode set.
+ */
+ switch (mode & RTEMS_RFS_S_IFMT)
+ {
+ case RTEMS_RFS_S_IFDIR:
+ case RTEMS_RFS_S_IFCHR:
+ case RTEMS_RFS_S_IFBLK:
+ case RTEMS_RFS_S_IFREG:
+ case RTEMS_RFS_S_IFLNK:
+ break;
+ default:
+ return EINVAL;
+ }
+
+ 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)
+ {
+ rtems_rfs_inode_free (fs, *ino);
+ 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.
+ *
+ * The inode delete will free the inode.
+ */
+ 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_trace (RTEMS_RFS_TRACE_INODE_DELETE))
+ printf("rtems-rfs: inode-delete: ino:%" PRIu32 " loaded:%s\n",
+ rtems_rfs_inode_ino (handle),
+ rtems_rfs_inode_is_loaded (handle) ? "yes" : "no");
+
+ 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, RTEMS_RFS_INODE_SIZE);
+ 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);
+}