[PATCH 3/5] imfs: Add IMFS_add_node()

Sebastian Huber sebastian.huber at embedded-brains.de
Tue Mar 3 10:50:14 UTC 2020


Update #3894.
---
 cpukit/Makefile.am                                |   2 +
 cpukit/include/rtems/imfs.h                       | 159 +++++++++++++++--
 cpukit/libfs/src/imfs/imfs_add_node.c             | 112 ++++++++++++
 cpukit/libfs/src/imfs/imfs_node.c                 |   8 +-
 cpukit/libfs/src/imfs/imfs_node_destroy_default.c |  47 +++++
 testsuites/fstests/fsimfsgeneric01/init.c         | 206 ++++++++++++++++++----
 6 files changed, 484 insertions(+), 50 deletions(-)
 create mode 100644 cpukit/libfs/src/imfs/imfs_add_node.c
 create mode 100644 cpukit/libfs/src/imfs/imfs_node_destroy_default.c

diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index 298580e20d..884fb8c402 100644
--- a/cpukit/Makefile.am
+++ b/cpukit/Makefile.am
@@ -413,6 +413,7 @@ librtemscpu_a_SOURCES += libfs/src/dosfs/msdos_rename.c
 librtemscpu_a_SOURCES += libfs/src/dosfs/msdos_rmnod.c
 librtemscpu_a_SOURCES += libfs/src/dosfs/msdos_statvfs.c
 librtemscpu_a_SOURCES += libfs/src/imfs/deviceio.c
+librtemscpu_a_SOURCES += libfs/src/imfs/imfs_add_node.c
 librtemscpu_a_SOURCES += libfs/src/imfs/imfs_chown.c
 librtemscpu_a_SOURCES += libfs/src/imfs/imfs_config.c
 librtemscpu_a_SOURCES += libfs/src/imfs/imfs_creat.c
@@ -435,6 +436,7 @@ librtemscpu_a_SOURCES += libfs/src/imfs/imfs_memfile.c
 librtemscpu_a_SOURCES += libfs/src/imfs/imfs_mknod.c
 librtemscpu_a_SOURCES += libfs/src/imfs/imfs_mount.c
 librtemscpu_a_SOURCES += libfs/src/imfs/imfs_node.c
+librtemscpu_a_SOURCES += libfs/src/imfs/imfs_node_destroy_default.c
 librtemscpu_a_SOURCES += libfs/src/imfs/imfs_rename.c
 librtemscpu_a_SOURCES += libfs/src/imfs/imfs_rmnod.c
 librtemscpu_a_SOURCES += libfs/src/imfs/imfs_stat.c
diff --git a/cpukit/include/rtems/imfs.h b/cpukit/include/rtems/imfs.h
index 1490186287..565d103226 100644
--- a/cpukit/include/rtems/imfs.h
+++ b/cpukit/include/rtems/imfs.h
@@ -206,6 +206,15 @@ typedef void (*IMFS_node_control_destroy)( IMFS_jnode_t *node );
  */
 void IMFS_node_destroy_default( IMFS_jnode_t *node );
 
+/**
+ * @brief Does nothing.
+ *
+ * @param node The IMFS node.
+ *
+ * @see IMFS_node_control.
+ */
+void IMFS_do_nothing_destroy( IMFS_jnode_t *node );
+
 /**
  * @brief IMFS node control.
  */
@@ -319,6 +328,11 @@ typedef struct {
   size_t      size;
 } IMFS_linearfile_context;
 
+static inline IMFS_jnode_t *IMFS_iop_to_node( const rtems_libio_t *iop )
+{
+  return (IMFS_jnode_t *) iop->pathinfo.node_access;
+}
+
 static inline IMFS_directory_t *IMFS_iop_to_directory(
   const rtems_libio_t *iop
 )
@@ -594,6 +608,92 @@ static inline bool IMFS_is_imfs_instance(
   return loc->mt_entry->ops->clonenod_h == IMFS_node_clone;
 }
 
+/**
+ * @brief Initializer for an IMFS node control.
+ *
+ * @param handlers The file system node handlers.
+ * @param init The node initialization method.
+ * @param destroy The node destruction method.
+ */
+#define IMFS_NODE_CONTROL_INITIALIZER( handlers, init, destroy ) \
+  { \
+    ( handlers ), \
+    ( init ), \
+    IMFS_node_remove_default, \
+    ( destroy ) \
+  }
+
+/**
+ * @brief Initializer for an IMFS node.
+ *
+ * Initialize the node control with IMFS_NODE_CONTROL_INITIALIZER().
+ *
+ * @param node_control The node control of the IMFS node.
+ * @param name The name of the IMFS node.
+ * @param namelen The length of the name of the IMFS node.
+ * @param mode The mode of the IMFS node.
+ *
+ * @see IMFS_node_preinitialize().
+ */
+#define IMFS_NODE_INITIALIZER( node_control, name, namelen, mode ) \
+  { \
+    { NULL, NULL }, \
+    NULL, \
+    ( name ), \
+    ( namelen ), \
+    ( mode ), \
+    0, \
+    0, \
+    0, \
+    0, \
+    0, \
+    0, \
+    0, \
+    ( node_control ) \
+  }
+
+/**
+ * @brief Preinitializes an IMFS node.
+ *
+ * Initialize the node control with IMFS_NODE_CONTROL_INITIALIZER().
+ *
+ * @param node The IMFS node to preinitialize.
+ * @param node_control The node control of the IMFS node.
+ * @param name The name of the IMFS node.
+ * @param namelen The length of the name of the IMFS node.
+ * @param mode The mode of the IMFS node.
+ *
+ * @see IMFS_NODE_INITIALIZER().
+ */
+static inline void IMFS_node_preinitialize(
+  IMFS_jnode_t            *node,
+  const IMFS_node_control *node_control,
+  const char              *name,
+  size_t                   namelen,
+  mode_t                   mode
+)
+{
+  node->control = node_control;
+  node->name = name;
+  node->namelen = namelen;
+  node->st_mode = mode;
+}
+
+/**
+ * @brief Adds an IMFS node.
+ *
+ * Initialize the node with IMFS_NODE_INITIALIZER(), IMFS_node_preinitialize(),
+ * IMFS_GENERIC_NODE_INITIALIZER(), or IMFS_generic_node_preinitialize().
+ *
+ * @param path The path of parent directories for the IMFS node to add.
+ * @param node The IMFS node to add.
+ * @param arg The argument passed to the node initialization method.
+ *
+ * @retval 0 Successful operation.
+ * @retval -1 An error occurred.  The @c errno indicates the error.
+ */
+int IMFS_add_node( const char *path, IMFS_jnode_t *node, void *arg );
+
 extern int IMFS_make_node(
   const char              *path,
   mode_t                   mode,
@@ -638,20 +738,56 @@ extern int IMFS_make_linearfile(
  * @{
  */
 
+/* Provided for backward compatibility */
+#define IMFS_GENERIC_INITIALIZER( handlers, init, destroy ) \
+  IMFS_NODE_CONTROL_INITIALIZER( handlers, init, destroy )
+
 /**
  * @brief Initializer for a generic node control.
  *
- * @param[in] handlers The file system node handlers.
- * @param[in] init The node initialization method.
- * @param[in] destroy The node destruction method.
+ * @param handlers The file system node handlers.
+ * @param init The node initialization method.
+ * @param destroy The node destruction method.
  */
-#define IMFS_GENERIC_INITIALIZER( handlers, init, destroy ) \
-  { \
-    ( handlers ), \
-    ( init ), \
-    IMFS_node_remove_default, \
-    ( destroy ) \
-  }
+#define IMFS_GENERIC_CONTROL_INITIALIZER( handlers, init, destroy ) \
+  IMFS_NODE_CONTROL_INITIALIZER( handlers, init, destroy )
+
+/**
+ * @brief Initializer for a generic node.
+ *
+ * Initialize the node control with IMFS_GENERIC_CONTROL_INITIALIZER().
+ *
+ * @param node_control The node control of the IMFS generic node.
+ * @param name The name of the IMFS generic node.
+ * @param namelen The length of the name of the IMFS generic node.
+ * @param mode The mode of the IMFS generic node.
+ */
+#define IMFS_GENERIC_NODE_INITIALIZER( node_control, name, namelen, mode ) \
+  { IMFS_NODE_INITIALIZER( node_control, name, namelen, mode ), NULL }
+
+/**
+ * @brief Preinitializes a generic IMFS node.
+ *
+ * Initialize the node control with IMFS_GENERIC_CONTROL_INITIALIZER().
+ *
+ * @param node The generic IMFS node to preinitialize.
+ * @param node_control The node control of the generic IMFS node.
+ * @param name The name of the generic IMFS node.
+ * @param namelen The length of the name of the generic IMFS node.
+ * @param mode The mode of the generic IMFS node.
+ *
+ * @see IMFS_GENERIC_NODE_INITIALIZER().
+ */
+static inline void IMFS_generic_node_preinitialize(
+  IMFS_generic_t          *node,
+  const IMFS_node_control *node_control,
+  const char              *name,
+  size_t                   namelen,
+  mode_t                   mode
+)
+{
+  IMFS_node_preinitialize( &node->Node, node_control, name, namelen, mode );
+}
 
 /**
  * @brief Makes a generic IMFS node.
@@ -692,7 +828,8 @@ extern int IMFS_make_linearfile(
  *   IMFS_node_destroy_default(node);
  * }
  *
- * static const IMFS_node_control some_node_control = IMFS_GENERIC_INITIALIZER(
+ * static const IMFS_node_control
+ * some_node_control = IMFS_GENERIC_CONTROL_INITIALIZER(
  *   &some_node_handlers,
  *   some_node_init,
  *   some_node_destroy
diff --git a/cpukit/libfs/src/imfs/imfs_add_node.c b/cpukit/libfs/src/imfs/imfs_add_node.c
new file mode 100644
index 0000000000..ad26c5b26c
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_add_node.c
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup IMFS
+ *
+ * @brief IMFS Add a Node
+ */
+
+/*
+ * Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/imfs.h>
+
+int IMFS_add_node( const char *path, IMFS_jnode_t *node, void *arg )
+{
+  mode_t                                  mode;
+  rtems_filesystem_eval_path_context_t    ctx;
+  const rtems_filesystem_location_info_t *currentloc;
+  int                                     eval_flags;
+  int                                     rv;
+
+  mode = node->st_mode;
+  mode &= ~rtems_filesystem_umask;
+
+  switch (mode & S_IFMT) {
+    case S_IFBLK:
+    case S_IFCHR:
+    case S_IFIFO:
+    case S_IFREG:
+    case S_IFSOCK:
+      break;
+    default:
+      errno = EINVAL;
+      return -1;
+  }
+
+  eval_flags = RTEMS_FS_FOLLOW_LINK;
+  currentloc = rtems_filesystem_eval_path_start( &ctx, path, eval_flags );
+
+  if ( IMFS_is_imfs_instance( currentloc ) ) {
+    eval_flags = RTEMS_FS_MAKE | RTEMS_FS_EXCLUSIVE;
+    rtems_filesystem_eval_path_set_flags( &ctx, eval_flags );
+    rtems_filesystem_eval_path_set_path( &ctx, node->name, node->namelen );
+    rtems_filesystem_eval_path_continue( &ctx );
+
+    if ( rtems_filesystem_eval_path_get_token( &ctx ) == node->name ) {
+      IMFS_assert(
+        rtems_filesystem_eval_path_get_tokenlen( &ctx ) == node->namelen
+      );
+      node = IMFS_initialize_node(
+        node,
+        node->control,
+        node->name,
+        node->namelen,
+        mode,
+        arg
+      );
+      if ( node != NULL ) {
+        IMFS_jnode_t *parent;
+
+        currentloc = rtems_filesystem_eval_path_get_currentloc( &ctx );
+        parent = currentloc->node_access;
+        IMFS_assert( parent != NULL );
+        IMFS_add_to_directory( parent, node );
+        IMFS_mtime_ctime_update( parent );
+        rv = 0;
+      } else {
+        rv = -1;
+      }
+    } else {
+      if ( rtems_filesystem_eval_path_get_token( &ctx ) != NULL ) {
+        rtems_filesystem_eval_path_error( &ctx, EINVAL );
+      }
+
+      rv = -1;
+    }
+  } else {
+    rtems_filesystem_eval_path_error( &ctx, ENOTSUP );
+    rv = -1;
+  }
+
+  rtems_filesystem_eval_path_cleanup( &ctx );
+  return rv;
+}
diff --git a/cpukit/libfs/src/imfs/imfs_node.c b/cpukit/libfs/src/imfs/imfs_node.c
index ae087bd58f..c6a4b4bd4e 100644
--- a/cpukit/libfs/src/imfs/imfs_node.c
+++ b/cpukit/libfs/src/imfs/imfs_node.c
@@ -18,13 +18,11 @@
  */
 
 #if HAVE_CONFIG_H
-  #include "config.h"
+#include "config.h"
 #endif
 
 #include <rtems/imfs.h>
 
-#include <stdlib.h>
-
 IMFS_jnode_t *IMFS_initialize_node(
   IMFS_jnode_t *node,
   const IMFS_node_control *node_control,
@@ -105,7 +103,7 @@ IMFS_jnode_t *IMFS_node_remove_default(
   return node;
 }
 
-void IMFS_node_destroy_default( IMFS_jnode_t *node )
+void IMFS_do_nothing_destroy( IMFS_jnode_t *node )
 {
-  free( node );
+  (void) node;
 }
diff --git a/cpukit/libfs/src/imfs/imfs_node_destroy_default.c b/cpukit/libfs/src/imfs/imfs_node_destroy_default.c
new file mode 100644
index 0000000000..2340baa8d1
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_node_destroy_default.c
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup IMFS
+ *
+ * @brief IMFS Default Node Destruction
+ */
+
+/*
+ * Copyright (C) 2014 embedded brains GmbH (http://www.embedded-brains.de)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/imfs.h>
+
+#include <stdlib.h>
+
+void IMFS_node_destroy_default( IMFS_jnode_t *node )
+{
+  free( node );
+}
diff --git a/testsuites/fstests/fsimfsgeneric01/init.c b/testsuites/fstests/fsimfsgeneric01/init.c
index dc216181a4..e553f36ce0 100644
--- a/testsuites/fstests/fsimfsgeneric01/init.c
+++ b/testsuites/fstests/fsimfsgeneric01/init.c
@@ -1,11 +1,5 @@
 /*
- * Copyright (c) 2012-2014 embedded brains GmbH.  All rights reserved.
- *
- *  embedded brains GmbH
- *  Dornierstr. 4
- *  82178 Puchheim
- *  Germany
- *  <rtems at embedded-brains.de>
+ * Copyright (C) 2012, 2020 embedded brains GmbH (http://www.embedded-brains.de)
  *
  * The license and distribution terms for this file may be
  * found in the file LICENSE in this distribution or at
@@ -13,11 +7,9 @@
  */
 
 #ifdef HAVE_CONFIG_H
-  #include "config.h"
+#include "config.h"
 #endif
 
-#include "tmacros.h"
-
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/uio.h>
@@ -29,6 +21,8 @@
 #include <rtems/malloc.h>
 #include <rtems/libcsupport.h>
 
+#include <tmacros.h>
+
 const char rtems_test_name[] = "FSIMFSGENERIC 1";
 
 typedef enum {
@@ -302,28 +296,18 @@ static const IMFS_node_control node_control = {
   .node_destroy = node_destroy
 };
 
-static void test_imfs_make_generic_node(void)
+static void test_node_operations(const char *path)
 {
-  test_state state = TEST_NEW;
-  int rv = 0;
-  int fd = 0;
-  const char *path = "generic";
-  char buf [1];
-  ssize_t n = 0;
-  off_t off = 0;
+  int rv;
+  int fd;
+  char buf[1];
+  ssize_t n;
+  off_t off;
   struct iovec iov = {
-    .iov_base = &buf [0],
+    .iov_base = &buf[0],
     .iov_len = (int) sizeof(buf)
   };
 
-  rv = IMFS_make_generic_node(
-    path,
-    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
-    &node_control,
-    &state
-  );
-  rtems_test_assert(rv == 0);
-
   fd = open(path, O_RDWR);
   rtems_test_assert(fd >= 0);
 
@@ -336,7 +320,7 @@ static void test_imfs_make_generic_node(void)
   rv = ioctl(fd, 0);
   rtems_test_assert(rv == 0);
 
-  off = lseek(fd, off, SEEK_SET);
+  off = lseek(fd, 0, SEEK_SET);
   rtems_test_assert(off == 0);
 
   rv = ftruncate(fd, 0);
@@ -362,7 +346,24 @@ static void test_imfs_make_generic_node(void)
 
   rv = unlink(path);
   rtems_test_assert(rv == 0);
+}
+
+static void test_imfs_make_generic_node(void)
+{
+  static const char path[] = "generic";
+  test_state state;
+  int rv;
+
+  state = TEST_NEW;
+  rv = IMFS_make_generic_node(
+    path,
+    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
+    &node_control,
+    &state
+  );
+  rtems_test_assert(rv == 0);
 
+  test_node_operations(path);
   rtems_test_assert(state == TEST_DESTROYED);
 }
 
@@ -402,16 +403,20 @@ static int other_clone(rtems_filesystem_location_info_t *loc)
   return (*imfs_ops->clonenod_h)(loc);
 }
 
+static rtems_filesystem_mount_table_entry_t *get_imfs_mt_entry(void)
+{
+  return (rtems_filesystem_mount_table_entry_t *)
+    rtems_chain_first(&rtems_filesystem_mount_table);
+}
+
 static void test_imfs_make_generic_node_errors(void)
 {
-  int rv = 0;
-  const char *path = "generic";
-  rtems_chain_control *chain = &rtems_filesystem_mount_table;
-  rtems_filesystem_mount_table_entry_t *mt_entry =
-    (rtems_filesystem_mount_table_entry_t *) rtems_chain_first(chain);
+  static const char path[] = "generic";
+  rtems_filesystem_mount_table_entry_t *mt_entry;
   rtems_filesystem_operations_table other_ops;
-  void *opaque = NULL;
   rtems_resource_snapshot before;
+  void *opaque;
+  int rv;
 
   rtems_resource_snapshot_take(&before);
 
@@ -427,6 +432,7 @@ static void test_imfs_make_generic_node_errors(void)
   rtems_test_assert(rtems_resource_snapshot_check(&before));
 
   errno = 0;
+  mt_entry = get_imfs_mt_entry();
   imfs_ops = mt_entry->ops;
   other_ops = *imfs_ops;
   other_ops.clonenod_h = other_clone;
@@ -478,12 +484,142 @@ static void test_imfs_make_generic_node_errors(void)
   rtems_test_assert(rtems_resource_snapshot_check(&before));
 }
 
+static void user_node_destroy(IMFS_jnode_t *node)
+{
+  test_state *state = IMFS_generic_get_context_by_node(node);
+
+  rtems_test_assert(*state == TEST_REMOVED);
+  *state = TEST_DESTROYED;
+}
+
+static const IMFS_node_control user_node_control = {
+  .handlers = &node_handlers,
+  .node_initialize = node_initialize,
+  .node_remove = node_remove,
+  .node_destroy = user_node_destroy
+};
+
+static void test_imfs_add_node(void)
+{
+  static const char path[] = "/";
+  static const char name[] = "node";
+  size_t namelen = sizeof(name) - 1;
+  void *opaque;
+  rtems_resource_snapshot before;
+  IMFS_generic_t node = IMFS_GENERIC_NODE_INITIALIZER(
+    &user_node_control,
+    name,
+    namelen,
+    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO
+  );
+  test_state state;
+  int rv;
+
+  /* Ensure that sure no dynamic memory is used */
+  opaque = rtems_heap_greedy_allocate(NULL, 0);
+
+  rtems_resource_snapshot_take(&before);
+
+  state = TEST_NEW;
+  rv = IMFS_add_node(path, &node.Node, &state);
+  rtems_test_assert(rv == 0);
+
+  test_node_operations(name);
+  rtems_test_assert(state == TEST_DESTROYED);
+
+  rtems_test_assert(rtems_resource_snapshot_check(&before));
+  rtems_heap_greedy_free(opaque);
+}
+
+static void test_imfs_add_node_errors(void)
+{
+  static const char path[] = "/";
+  static const char name[] = "node";
+  size_t namelen = sizeof(name) - 1;
+  const char invalid_name[] = "/node";
+  size_t invalid_namelen = sizeof(invalid_name) - 1;
+  IMFS_jnode_t node = IMFS_NODE_INITIALIZER(
+    &user_node_control,
+    name,
+    namelen,
+    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO
+  );
+  IMFS_jnode_t invalid_mode_node = IMFS_NODE_INITIALIZER(
+    &user_node_control,
+    name,
+    namelen,
+    S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO
+  );
+  IMFS_jnode_t init_error_node = IMFS_NODE_INITIALIZER(
+    &node_initialization_error_control,
+    name,
+    namelen,
+    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO
+  );
+  IMFS_jnode_t invalid_name_node = IMFS_NODE_INITIALIZER(
+    &user_node_control,
+    invalid_name,
+    invalid_namelen,
+    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO
+  );
+  rtems_filesystem_mount_table_entry_t *mt_entry;
+  rtems_filesystem_operations_table other_ops;
+  void *opaque;
+  rtems_resource_snapshot before;
+  int rv;
+
+  /* Ensure that sure no dynamic memory is used */
+  opaque = rtems_heap_greedy_allocate(NULL, 0);
+
+  rtems_resource_snapshot_take(&before);
+
+  errno = 0;
+  rv = IMFS_add_node(path, &invalid_mode_node, NULL);
+  rtems_test_assert(rv == -1);
+  rtems_test_assert(errno == EINVAL);
+  rtems_test_assert(rtems_resource_snapshot_check(&before));
+
+  errno = 0;
+  mt_entry = get_imfs_mt_entry();
+  imfs_ops = mt_entry->ops;
+  other_ops = *imfs_ops;
+  other_ops.clonenod_h = other_clone;
+  mt_entry->ops = &other_ops;
+  rv = IMFS_add_node(path, &node, NULL);
+  mt_entry->ops = imfs_ops;
+  rtems_test_assert(rv == -1);
+  rtems_test_assert(errno == ENOTSUP);
+  rtems_test_assert(rtems_resource_snapshot_check(&before));
+
+  errno = 0;
+  rv = IMFS_add_node(path, &init_error_node, NULL);
+  rtems_test_assert(rv == -1);
+  rtems_test_assert(errno == EIO);
+  rtems_test_assert(rtems_resource_snapshot_check(&before));
+
+  errno = 0;
+  rv = IMFS_add_node("/nil/nada", &node, NULL);
+  rtems_test_assert(rv == -1);
+  rtems_test_assert(errno == ENOENT);
+  rtems_test_assert(rtems_resource_snapshot_check(&before));
+
+  errno = 0;
+  rv = IMFS_add_node(path, &invalid_name_node, NULL);
+  rtems_test_assert(rv == -1);
+  rtems_test_assert(errno == EINVAL);
+  rtems_test_assert(rtems_resource_snapshot_check(&before));
+
+  rtems_heap_greedy_free(opaque);
+}
+
 static void Init(rtems_task_argument arg)
 {
   TEST_BEGIN();
 
   test_imfs_make_generic_node();
   test_imfs_make_generic_node_errors();
+  test_imfs_add_node();
+  test_imfs_add_node_errors();
 
   TEST_END();
   rtems_test_exit(0);
@@ -496,6 +632,8 @@ static void Init(rtems_task_argument arg)
 
 #define CONFIGURE_MAXIMUM_TASKS 1
 
+#define CONFIGURE_UNIFIED_WORK_AREAS
+
 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
 
 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
-- 
2.16.4



More information about the devel mailing list