Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:18

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup rtems_rfs
0007  *
0008  * @brief RTEMS File System Interface for RTEMS
0009  */
0010 
0011 /*
0012  *  COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
0013  *
0014  *  Modifications to support reference counting in the file system are
0015  *  Copyright (c) 2012 embedded brains GmbH & Co. KG
0016  *
0017  * Redistribution and use in source and binary forms, with or without
0018  * modification, are permitted provided that the following conditions
0019  * are met:
0020  * 1. Redistributions of source code must retain the above copyright
0021  *    notice, this list of conditions and the following disclaimer.
0022  * 2. Redistributions in binary form must reproduce the above copyright
0023  *    notice, this list of conditions and the following disclaimer in the
0024  *    documentation and/or other materials provided with the distribution.
0025  *
0026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0027  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0028  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0029  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0030  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0031  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0032  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0033  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0034  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0035  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0036  * POSSIBILITY OF SUCH DAMAGE.
0037  */
0038 
0039 #ifdef HAVE_CONFIG_H
0040 #include "config.h"
0041 #endif
0042 
0043 #include <sys/param.h>
0044 #include <inttypes.h>
0045 #include <string.h>
0046 #include <stdlib.h>
0047 
0048 #include <rtems/inttypes.h>
0049 
0050 #include <rtems/rfs/rtems-rfs-file.h>
0051 #include <rtems/rfs/rtems-rfs-dir.h>
0052 #include <rtems/rfs/rtems-rfs-link.h>
0053 #include "rtems-rfs-rtems.h"
0054 
0055 static bool
0056 rtems_rfs_rtems_eval_perms (rtems_filesystem_eval_path_context_t *ctx,
0057                             int eval_flags,
0058                             rtems_rfs_inode_handle* inode)
0059 {
0060   return rtems_filesystem_eval_path_check_access(
0061     ctx,
0062     eval_flags,
0063     rtems_rfs_inode_get_mode (inode),
0064     rtems_rfs_inode_get_uid (inode),
0065     rtems_rfs_inode_get_gid (inode)
0066   );
0067 }
0068 
0069 static void
0070 rtems_rfs_rtems_lock_by_mt_entry (
0071   const rtems_filesystem_mount_table_entry_t *mt_entry
0072 )
0073 {
0074   rtems_rfs_file_system* fs = mt_entry->fs_info;
0075 
0076   rtems_rfs_rtems_lock (fs);
0077 }
0078 
0079 static void
0080 rtems_rfs_rtems_unlock_by_mt_entry (
0081   const rtems_filesystem_mount_table_entry_t *mt_entry
0082 )
0083 {
0084   rtems_rfs_file_system* fs = mt_entry->fs_info;
0085 
0086   rtems_rfs_rtems_unlock (fs);
0087 }
0088 
0089 static bool
0090 rtems_rfs_rtems_is_directory(
0091   rtems_filesystem_eval_path_context_t *ctx,
0092   void *arg
0093 )
0094 {
0095   rtems_rfs_inode_handle* inode = arg;
0096 
0097   return S_ISDIR (rtems_rfs_inode_get_mode (inode));
0098 }
0099 
0100 static void rtems_rfs_rtems_follow_link(
0101   rtems_filesystem_eval_path_context_t* ctx,
0102   rtems_rfs_file_system* fs,
0103   rtems_rfs_ino ino
0104 )
0105 {
0106   size_t len = MAXPATHLEN;
0107   char *link = malloc(len + 1);
0108 
0109   if (link != NULL) {
0110     int rc = rtems_rfs_symlink_read (fs, ino, link, len, &len);
0111 
0112     if (rc == 0) {
0113       rtems_filesystem_eval_path_recursive (ctx, link, len);
0114     } else {
0115       rtems_filesystem_eval_path_error (ctx, 0);
0116     }
0117 
0118     free(link);
0119   } else {
0120     rtems_filesystem_eval_path_error (ctx, ENOMEM);
0121   }
0122 }
0123 
0124 static rtems_filesystem_eval_path_generic_status
0125 rtems_rfs_rtems_eval_token(
0126   rtems_filesystem_eval_path_context_t *ctx,
0127   void *arg,
0128   const char *token,
0129   size_t tokenlen
0130 )
0131 {
0132   rtems_filesystem_eval_path_generic_status status =
0133     RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE;
0134   rtems_rfs_inode_handle* inode = arg;
0135   bool access_ok = rtems_rfs_rtems_eval_perms (ctx, RTEMS_FS_PERMS_EXEC, inode);
0136 
0137   if (access_ok) {
0138     if (rtems_filesystem_is_current_directory (token, tokenlen)) {
0139       rtems_filesystem_eval_path_clear_token (ctx);
0140     } else {
0141       rtems_filesystem_location_info_t *currentloc =
0142         rtems_filesystem_eval_path_get_currentloc( ctx );
0143       rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (currentloc);
0144       rtems_rfs_ino entry_ino;
0145       uint32_t entry_doff;
0146       int rc = rtems_rfs_dir_lookup_ino (
0147         fs,
0148         inode,
0149         token,
0150         tokenlen,
0151         &entry_ino,
0152         &entry_doff
0153       );
0154 
0155       if (rc == 0) {
0156         rc = rtems_rfs_inode_close (fs, inode);
0157         if (rc == 0) {
0158           rc = rtems_rfs_inode_open (fs, entry_ino, inode, true);
0159         }
0160 
0161         if (rc != 0) {
0162           /*
0163            * This prevents the rtems_rfs_inode_close() from doing something in
0164            * rtems_rfs_rtems_eval_path().
0165            */
0166           memset (inode, 0, sizeof(*inode));
0167         }
0168       } else {
0169         status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_NO_ENTRY;
0170         rc = -1;
0171       }
0172 
0173       if (rc == 0) {
0174         bool is_sym_link = S_ISLNK (rtems_rfs_inode_get_mode (inode));
0175         int eval_flags = rtems_filesystem_eval_path_get_flags (ctx);
0176         bool follow_sym_link = (eval_flags & RTEMS_FS_FOLLOW_SYM_LINK) != 0;
0177         bool terminal = !rtems_filesystem_eval_path_has_path (ctx);
0178 
0179         rtems_filesystem_eval_path_clear_token (ctx);
0180 
0181         if (is_sym_link && (follow_sym_link || !terminal)) {
0182           rtems_rfs_rtems_follow_link (ctx, fs, entry_ino);
0183         } else {
0184           rc = rtems_rfs_rtems_set_handlers (currentloc, inode) ? 0 : EIO;
0185           if (rc == 0) {
0186             rtems_rfs_rtems_set_pathloc_ino (currentloc, entry_ino);
0187             rtems_rfs_rtems_set_pathloc_doff (currentloc, entry_doff);
0188 
0189             if (!terminal) {
0190               status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE;
0191             }
0192           } else {
0193             rtems_filesystem_eval_path_error (
0194               ctx,
0195               rtems_rfs_rtems_error ("eval_path: set handlers", rc)
0196             );
0197           }
0198         }
0199       }
0200     }
0201   }
0202 
0203   return status;
0204 }
0205 
0206 static const rtems_filesystem_eval_path_generic_config
0207 rtems_rfs_rtems_eval_config = {
0208   .is_directory = rtems_rfs_rtems_is_directory,
0209   .eval_token = rtems_rfs_rtems_eval_token
0210 };
0211 
0212 static void
0213 rtems_rfs_rtems_eval_path (rtems_filesystem_eval_path_context_t *ctx)
0214 {
0215   rtems_filesystem_location_info_t *currentloc =
0216     rtems_filesystem_eval_path_get_currentloc (ctx);
0217   rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (currentloc);
0218   rtems_rfs_ino ino = rtems_rfs_rtems_get_pathloc_ino (currentloc);
0219   rtems_rfs_inode_handle inode;
0220   int rc;
0221 
0222   rc = rtems_rfs_inode_open (fs, ino, &inode, true);
0223   if (rc == 0) {
0224     rtems_filesystem_eval_path_generic (
0225       ctx,
0226       &inode,
0227       &rtems_rfs_rtems_eval_config
0228     );
0229     rc = rtems_rfs_inode_close (fs, &inode);
0230     if (rc != 0) {
0231       rtems_filesystem_eval_path_error (
0232         ctx,
0233         rtems_rfs_rtems_error ("eval_path: closing inode", rc)
0234       );
0235     }
0236   } else {
0237     rtems_filesystem_eval_path_error (
0238       ctx,
0239       rtems_rfs_rtems_error ("eval_path: opening inode", rc)
0240     );
0241   }
0242 }
0243 
0244 /**
0245  * The following rouine creates a new link node under parent with the name
0246  * given in name. The link node is set to point to the node at targetloc.
0247  */
0248 static int
0249 rtems_rfs_rtems_link (const rtems_filesystem_location_info_t *parentloc,
0250                       const rtems_filesystem_location_info_t *targetloc,
0251                       const char *name,
0252                       size_t namelen)
0253 {
0254   rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (targetloc);
0255   rtems_rfs_ino          target = rtems_rfs_rtems_get_pathloc_ino (targetloc);
0256   rtems_rfs_ino          parent = rtems_rfs_rtems_get_pathloc_ino (parentloc);
0257   int                    rc;
0258 
0259   if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_LINK))
0260     printf ("rtems-rfs-rtems: link: in: parent:%" PRId32 " target:%" PRId32 "\n",
0261             parent, target);
0262 
0263   rc = rtems_rfs_link (fs, name, namelen, parent, target, false);
0264   if (rc)
0265   {
0266     return rtems_rfs_rtems_error ("link: linking", rc);
0267     }
0268 
0269 
0270     return 0;
0271 }
0272 
0273 /**
0274  * This routine is the implementation of the chown() system call for the
0275  * RFS.
0276  *
0277  * @param pathloc
0278  * @param owner
0279  * @param group
0280  * return int
0281  */
0282 
0283 static int
0284 rtems_rfs_rtems_chown (const rtems_filesystem_location_info_t *pathloc,
0285                        uid_t                                   owner,
0286                        gid_t                                   group)
0287 {
0288   rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
0289   rtems_rfs_ino          ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
0290   rtems_rfs_inode_handle inode;
0291   int                    rc;
0292 
0293   if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_CHOWN))
0294     printf ("rtems-rfs-rtems: chown: in: ino:%" PRId32 " uid:%d gid:%d\n",
0295             ino, owner, group);
0296 
0297   rc = rtems_rfs_inode_open (fs, ino, &inode, true);
0298   if (rc > 0)
0299   {
0300     return rtems_rfs_rtems_error ("chown: opening inode", rc);
0301   }
0302 
0303   rtems_rfs_inode_set_uid_gid (&inode, owner, group);
0304 
0305   rc = rtems_rfs_inode_close (fs, &inode);
0306   if (rc)
0307   {
0308     return rtems_rfs_rtems_error ("chown: closing inode", rc);
0309   }
0310 
0311   return 0;
0312 }
0313 
0314 /**
0315  * This routine is the implementation of the utime() system call for the
0316  * RFS.
0317  *
0318  * @param pathloc The path to the file to be modified
0319  * @param times The times to update the file to
0320  * return int
0321  */
0322 
0323 static int
0324 rtems_rfs_rtems_utimens(const rtems_filesystem_location_info_t* pathloc,
0325                         struct timespec                         times[2])
0326 {
0327   rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
0328   rtems_rfs_ino          ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
0329   rtems_rfs_inode_handle inode;
0330   int                    rc;
0331 
0332   rc = rtems_rfs_inode_open (fs, ino, &inode, true);
0333   if (rc)
0334   {
0335     return rtems_rfs_rtems_error ("utime: read inode", rc);
0336   }
0337 
0338   rtems_rfs_inode_set_atime (&inode, times[0].tv_sec);
0339   rtems_rfs_inode_set_mtime (&inode, times[1].tv_sec);
0340 
0341   rc = rtems_rfs_inode_close (fs, &inode);
0342   if (rc)
0343   {
0344     return rtems_rfs_rtems_error ("utime: closing inode", rc);
0345   }
0346 
0347   return 0;
0348 }
0349 
0350 /**
0351  * The following routine creates a new symbolic link node under parent with the
0352  * name given in node_name.
0353  */
0354 
0355 static int
0356 rtems_rfs_rtems_symlink (const rtems_filesystem_location_info_t* parent_loc,
0357                          const char*                             node_name,
0358                          size_t                                  node_name_len,
0359                          const char*                             target)
0360 {
0361   rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (parent_loc);
0362   rtems_rfs_ino          parent = rtems_rfs_rtems_get_pathloc_ino (parent_loc);
0363   int                    rc;
0364 
0365   rc = rtems_rfs_symlink (fs, node_name, node_name_len,
0366                           target, strlen (target),
0367                           geteuid(), getegid(), parent);
0368   if (rc)
0369   {
0370     return rtems_rfs_rtems_error ("symlink: linking", rc);
0371   }
0372 
0373   return 0;
0374 }
0375 
0376 /**
0377  * The following rouine puts the symblic links destination name into buf.
0378  */
0379 
0380 static ssize_t
0381 rtems_rfs_rtems_readlink (const rtems_filesystem_location_info_t* pathloc,
0382                           char*                                   buf,
0383                           size_t                                  bufsize)
0384 {
0385   rtems_rfs_file_system*  fs = rtems_rfs_rtems_pathloc_dev (pathloc);
0386   rtems_rfs_ino           ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
0387   size_t                  length;
0388   int                     rc;
0389 
0390   if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_READLINK))
0391     printf ("rtems-rfs-rtems: readlink: in: ino:%" PRId32 "\n", ino);
0392 
0393   rc = rtems_rfs_symlink_read (fs, ino, buf, bufsize, &length);
0394   if (rc)
0395   {
0396     return rtems_rfs_rtems_error ("readlink: reading link", rc);
0397   }
0398 
0399   return (ssize_t) length;
0400 }
0401 
0402 static int
0403 rtems_rfs_rtems_fchmod (const rtems_filesystem_location_info_t* pathloc,
0404                         mode_t                                  mode)
0405 {
0406   rtems_rfs_file_system*  fs = rtems_rfs_rtems_pathloc_dev (pathloc);
0407   rtems_rfs_ino           ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
0408   rtems_rfs_inode_handle  inode;
0409   int                     rc;
0410 
0411   if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FCHMOD))
0412     printf ("rtems-rfs-rtems: fchmod: in: ino:%" PRId32 " mode:%06" PRIomode_t "\n",
0413             ino, mode);
0414 
0415   rc = rtems_rfs_inode_open (fs, ino, &inode, true);
0416   if (rc)
0417   {
0418     return rtems_rfs_rtems_error ("fchmod: opening inode", rc);
0419   }
0420 
0421   rtems_rfs_inode_set_mode (&inode, mode);
0422 
0423   rc = rtems_rfs_inode_close (fs, &inode);
0424   if (rc > 0)
0425   {
0426     return rtems_rfs_rtems_error ("fchmod: closing inode", rc);
0427   }
0428 
0429   return 0;
0430 }
0431 
0432 int
0433 rtems_rfs_rtems_fstat (const rtems_filesystem_location_info_t* pathloc,
0434                        struct stat*                            buf)
0435 {
0436   rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
0437   rtems_rfs_ino          ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
0438   rtems_rfs_inode_handle inode;
0439   rtems_rfs_file_shared* shared;
0440   uint16_t               mode;
0441   int                    rc;
0442 
0443   if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_STAT))
0444     printf ("rtems-rfs-rtems: stat: in: ino:%" PRId32 "\n", ino);
0445 
0446   rc = rtems_rfs_inode_open (fs, ino, &inode, true);
0447   if (rc)
0448   {
0449     return rtems_rfs_rtems_error ("stat: opening inode", rc);
0450   }
0451 
0452   mode = rtems_rfs_inode_get_mode (&inode);
0453 
0454   if (RTEMS_RFS_S_ISCHR (mode) || RTEMS_RFS_S_ISBLK (mode))
0455   {
0456     buf->st_rdev =
0457       rtems_filesystem_make_dev_t (rtems_rfs_inode_get_block (&inode, 0),
0458                                    rtems_rfs_inode_get_block (&inode, 1));
0459   }
0460 
0461   buf->st_dev     = (dev_t) (uintptr_t)rtems_rfs_fs_device (fs);
0462   buf->st_ino     = rtems_rfs_inode_ino (&inode);
0463   buf->st_mode    = rtems_rfs_rtems_mode (mode);
0464   buf->st_nlink   = rtems_rfs_inode_get_links (&inode);
0465   buf->st_uid     = rtems_rfs_inode_get_uid (&inode);
0466   buf->st_gid     = rtems_rfs_inode_get_gid (&inode);
0467 
0468   /*
0469    * Need to check is the ino is an open file. If so we take the values from
0470    * the open file rather than the inode.
0471    */
0472   shared = rtems_rfs_file_get_shared (fs, rtems_rfs_inode_ino (&inode));
0473 
0474   if (shared)
0475   {
0476     buf->st_atime   = rtems_rfs_file_shared_get_atime (shared);
0477     buf->st_mtime   = rtems_rfs_file_shared_get_mtime (shared);
0478     buf->st_ctime   = rtems_rfs_file_shared_get_ctime (shared);
0479     buf->st_blocks  = rtems_rfs_file_shared_get_block_count (shared);
0480 
0481     if (S_ISLNK (buf->st_mode))
0482       buf->st_size = rtems_rfs_file_shared_get_block_offset (shared);
0483     else
0484       buf->st_size = rtems_rfs_file_shared_get_size (fs, shared);
0485   }
0486   else
0487   {
0488     buf->st_atime   = rtems_rfs_inode_get_atime (&inode);
0489     buf->st_mtime   = rtems_rfs_inode_get_mtime (&inode);
0490     buf->st_ctime   = rtems_rfs_inode_get_ctime (&inode);
0491     buf->st_blocks  = rtems_rfs_inode_get_block_count (&inode);
0492 
0493     if (S_ISLNK (buf->st_mode))
0494       buf->st_size = rtems_rfs_inode_get_block_offset (&inode);
0495     else
0496       buf->st_size = rtems_rfs_inode_get_size (fs, &inode);
0497   }
0498 
0499   buf->st_blksize = rtems_rfs_fs_block_size (fs);
0500 
0501   rc = rtems_rfs_inode_close (fs, &inode);
0502   if (rc > 0)
0503   {
0504     return rtems_rfs_rtems_error ("stat: closing inode", rc);
0505   }
0506 
0507   return 0;
0508 }
0509 
0510 /**
0511  * Routine to create a node in the RFS file system.
0512  */
0513 
0514 static int
0515 rtems_rfs_rtems_mknod (const rtems_filesystem_location_info_t *parentloc,
0516                        const char                             *name,
0517                        size_t                                  namelen,
0518                        mode_t                                  mode,
0519                        dev_t                                   dev)
0520 {
0521   rtems_rfs_file_system*  fs = rtems_rfs_rtems_pathloc_dev (parentloc);
0522   rtems_rfs_ino           parent = rtems_rfs_rtems_get_pathloc_ino (parentloc);
0523   rtems_rfs_ino           ino;
0524   rtems_rfs_inode_handle  inode;
0525   uid_t                   uid;
0526   gid_t                   gid;
0527   int                     rc;
0528 
0529   uid = geteuid ();
0530   gid = getegid ();
0531 
0532   rc = rtems_rfs_inode_create (fs, parent, name, namelen,
0533                                rtems_rfs_rtems_imode (mode),
0534                                1, uid, gid, &ino);
0535   if (rc > 0)
0536   {
0537     return rtems_rfs_rtems_error ("mknod: inode create", rc);
0538   }
0539 
0540   rc = rtems_rfs_inode_open (fs, ino, &inode, true);
0541   if (rc > 0)
0542   {
0543     return rtems_rfs_rtems_error ("mknod: inode open", rc);
0544   }
0545 
0546   if (S_ISDIR(mode) || S_ISREG(mode))
0547   {
0548   }
0549   else if (S_ISCHR (mode) || S_ISBLK (mode))
0550   {
0551     int major;
0552     int minor;
0553     rtems_filesystem_split_dev_t (dev, major, minor);
0554     rtems_rfs_inode_set_block (&inode, 0, major);
0555     rtems_rfs_inode_set_block (&inode, 1, minor);
0556   }
0557   else
0558   {
0559     rtems_rfs_inode_close (fs, &inode);
0560     return rtems_rfs_rtems_error ("mknod: bad mode", EINVAL);
0561   }
0562 
0563   rc = rtems_rfs_inode_close (fs, &inode);
0564   if (rc > 0)
0565   {
0566     return rtems_rfs_rtems_error ("mknod: closing inode", rc);
0567   }
0568 
0569   return 0;
0570 }
0571 
0572 /**
0573  * Routine to remove a node from the RFS file system.
0574  *
0575  * @param parent_pathloc
0576  * @param pathloc
0577  * @return int
0578  */
0579 int
0580 rtems_rfs_rtems_rmnod (const rtems_filesystem_location_info_t* parent_pathloc,
0581                        const rtems_filesystem_location_info_t* pathloc)
0582 {
0583   rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
0584   rtems_rfs_ino          parent = rtems_rfs_rtems_get_pathloc_ino (parent_pathloc);
0585   rtems_rfs_ino          ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
0586   uint32_t               doff = rtems_rfs_rtems_get_pathloc_doff (pathloc);
0587   int                    rc;
0588 
0589   if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_RMNOD))
0590     printf ("rtems-rfs: rmnod: parent:%" PRId32 " doff:%" PRIu32 ", ino:%" PRId32 "\n",
0591             parent, doff, ino);
0592 
0593   rc = rtems_rfs_unlink (fs, parent, ino, doff, rtems_rfs_unlink_dir_if_empty);
0594   if (rc)
0595   {
0596     return rtems_rfs_rtems_error ("rmnod: unlinking", rc);
0597   }
0598 
0599   return 0;
0600 }
0601 
0602 /**
0603  * The following routine does a sync on an inode node. Currently it flushes
0604  * everything related to this device.
0605  *
0606  * @param iop
0607  * @return int
0608  */
0609 int
0610 rtems_rfs_rtems_fdatasync (rtems_libio_t* iop)
0611 {
0612   int rc;
0613 
0614   rc = rtems_rfs_buffer_sync (rtems_rfs_rtems_pathloc_dev (&iop->pathinfo));
0615   if (rc)
0616     return rtems_rfs_rtems_error ("fdatasync: sync", rc);
0617 
0618   return 0;
0619 }
0620 
0621 /**
0622  * Rename the node.
0623  */
0624 static int
0625 rtems_rfs_rtems_rename(const rtems_filesystem_location_info_t* old_parent_loc,
0626                        const rtems_filesystem_location_info_t* old_loc,
0627                        const rtems_filesystem_location_info_t* new_parent_loc,
0628                        const char*                             new_name,
0629                        size_t                                  new_name_len)
0630 {
0631   rtems_rfs_file_system*  fs = rtems_rfs_rtems_pathloc_dev (old_loc);
0632   rtems_rfs_ino           old_parent;
0633   rtems_rfs_ino           new_parent;
0634   rtems_rfs_ino           ino;
0635   uint32_t                doff;
0636   int                     rc;
0637 
0638   old_parent = rtems_rfs_rtems_get_pathloc_ino (old_parent_loc);
0639   new_parent = rtems_rfs_rtems_get_pathloc_ino (new_parent_loc);
0640 
0641   ino  = rtems_rfs_rtems_get_pathloc_ino (old_loc);
0642   doff = rtems_rfs_rtems_get_pathloc_doff (old_loc);
0643 
0644   if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_RENAME))
0645     printf ("rtems-rfs: rename: ino:%" PRId32 " doff:%" PRIu32 ", new parent:%" PRId32 "\n",
0646             ino, doff, new_parent);
0647 
0648   /*
0649    * Link to the inode before unlinking so the inode is not erased when
0650    * unlinked.
0651    */
0652   rc = rtems_rfs_link (fs, new_name, new_name_len, new_parent, ino, true);
0653   if (rc)
0654   {
0655     return rtems_rfs_rtems_error ("rename: linking", rc);
0656   }
0657 
0658   /*
0659    * Unlink all inodes even directories with the dir option as false because a
0660    * directory may not be empty.
0661    */
0662   rc = rtems_rfs_unlink (fs, old_parent, ino, doff,
0663                          rtems_rfs_unlink_dir_allowed);
0664   if (rc)
0665   {
0666     return rtems_rfs_rtems_error ("rename: unlinking", rc);
0667   }
0668 
0669   return 0;
0670 }
0671 
0672 /**
0673  * Return the file system stat data.
0674  *
0675  * @param pathloc
0676  * @param sb
0677  * @return int
0678  */
0679 static int
0680 rtems_rfs_rtems_statvfs (
0681   const rtems_filesystem_location_info_t *__restrict pathloc,
0682   struct statvfs *__restrict                         sb)
0683 {
0684   rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
0685   size_t                 blocks;
0686   size_t                 inodes;
0687 
0688   rtems_rfs_group_usage (fs, &blocks, &inodes);
0689 
0690   sb->f_bsize   = rtems_rfs_fs_block_size (fs);
0691   sb->f_frsize  = rtems_rfs_fs_media_block_size (fs);
0692   sb->f_blocks  = rtems_rfs_fs_media_blocks (fs);
0693   sb->f_bfree   = rtems_rfs_fs_blocks (fs) - blocks - 1; /* do not count the superblock */
0694   sb->f_bavail  = sb->f_bfree;
0695   sb->f_files   = rtems_rfs_fs_inodes (fs);
0696   sb->f_ffree   = rtems_rfs_fs_inodes (fs) - inodes;
0697   sb->f_favail  = sb->f_ffree;
0698   sb->f_fsid    = RTEMS_RFS_SB_MAGIC;
0699   sb->f_flag    = rtems_rfs_fs_flags (fs);
0700   sb->f_namemax = rtems_rfs_fs_max_name (fs);
0701 
0702   return 0;
0703 }
0704 
0705 /**
0706  *  Handler table for RFS link nodes
0707  */
0708 const rtems_filesystem_file_handlers_r rtems_rfs_rtems_link_handlers =
0709 {
0710   .open_h      = rtems_filesystem_default_open,
0711   .close_h     = rtems_filesystem_default_close,
0712   .read_h      = rtems_filesystem_default_read,
0713   .write_h     = rtems_filesystem_default_write,
0714   .ioctl_h     = rtems_filesystem_default_ioctl,
0715   .lseek_h     = rtems_filesystem_default_lseek,
0716   .fstat_h     = rtems_rfs_rtems_fstat,
0717   .ftruncate_h = rtems_filesystem_default_ftruncate,
0718   .fsync_h     = rtems_filesystem_default_fsync_or_fdatasync,
0719   .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
0720   .fcntl_h     = rtems_filesystem_default_fcntl,
0721   .kqfilter_h  = rtems_filesystem_default_kqfilter,
0722   .mmap_h      = rtems_filesystem_default_mmap,
0723   .poll_h      = rtems_filesystem_default_poll,
0724   .readv_h     = rtems_filesystem_default_readv,
0725   .writev_h    = rtems_filesystem_default_writev
0726 };
0727 
0728 /**
0729  * Forward decl for the ops table.
0730  */
0731 
0732 int rtems_rfs_rtems_initialise (rtems_filesystem_mount_table_entry_t *mt_entry,
0733                                 const void                           *data);
0734 void rtems_rfs_rtems_shutdown (rtems_filesystem_mount_table_entry_t *mt_entry);
0735 
0736 /**
0737  * RFS file system operations table.
0738  */
0739 const rtems_filesystem_operations_table rtems_rfs_ops =
0740 {
0741   .lock_h         = rtems_rfs_rtems_lock_by_mt_entry,
0742   .unlock_h       = rtems_rfs_rtems_unlock_by_mt_entry,
0743   .are_nodes_equal_h = rtems_filesystem_default_are_nodes_equal,
0744   .eval_path_h    = rtems_rfs_rtems_eval_path,
0745   .link_h         = rtems_rfs_rtems_link,
0746   .fchmod_h       = rtems_rfs_rtems_fchmod,
0747   .mknod_h        = rtems_rfs_rtems_mknod,
0748   .rmnod_h        = rtems_rfs_rtems_rmnod,
0749   .chown_h        = rtems_rfs_rtems_chown,
0750   .clonenod_h     = rtems_filesystem_default_clonenode,
0751   .freenod_h      = rtems_filesystem_default_freenode,
0752   .mount_h        = rtems_filesystem_default_mount,
0753   .unmount_h      = rtems_filesystem_default_unmount,
0754   .fsunmount_me_h = rtems_rfs_rtems_shutdown,
0755   .utimens_h      = rtems_rfs_rtems_utimens,
0756   .symlink_h      = rtems_rfs_rtems_symlink,
0757   .readlink_h     = rtems_rfs_rtems_readlink,
0758   .rename_h       = rtems_rfs_rtems_rename,
0759   .statvfs_h      = rtems_rfs_rtems_statvfs
0760 };
0761 
0762 /**
0763  * Open the file system.
0764  */
0765 
0766 int
0767 rtems_rfs_rtems_initialise (rtems_filesystem_mount_table_entry_t* mt_entry,
0768                             const void*                           data)
0769 {
0770   rtems_rfs_rtems_private* rtems;
0771   rtems_rfs_file_system*   fs;
0772   uint32_t                 flags = 0;
0773   uint32_t                 max_held_buffers = RTEMS_RFS_FS_MAX_HELD_BUFFERS;
0774   const char*              options = data;
0775   int                      rc;
0776 
0777   /*
0778    * Parse the options the user specifiies.
0779    */
0780   while (options)
0781   {
0782     printf ("options=%s\n", options);
0783     if (strncmp (options, "hold-bitmaps",
0784                  sizeof ("hold-bitmaps") - 1) == 0)
0785       flags |= RTEMS_RFS_FS_BITMAPS_HOLD;
0786     else if (strncmp (options, "no-local-cache",
0787                       sizeof ("no-local-cache") - 1) == 0)
0788       flags |= RTEMS_RFS_FS_NO_LOCAL_CACHE;
0789     else if (strncmp (options, "max-held-bufs",
0790                       sizeof ("max-held-bufs") - 1) == 0)
0791     {
0792       max_held_buffers = strtoul (options + sizeof ("max-held-bufs"), 0, 0);
0793     }
0794     else
0795       return rtems_rfs_rtems_error ("initialise: invalid option", EINVAL);
0796 
0797     options = strchr (options, ',');
0798     if (options)
0799     {
0800       ++options;
0801       if (*options == '\0')
0802         options = NULL;
0803     }
0804   }
0805 
0806   rtems = malloc (sizeof (rtems_rfs_rtems_private));
0807   if (!rtems)
0808     return rtems_rfs_rtems_error ("initialise: local data", ENOMEM);
0809 
0810   memset (rtems, 0, sizeof (rtems_rfs_rtems_private));
0811 
0812   rc = rtems_rfs_mutex_create (&rtems->access);
0813   if (rc > 0)
0814   {
0815     free (rtems);
0816     return rtems_rfs_rtems_error ("initialise: cannot create mutex", rc);
0817   }
0818 
0819   rc = rtems_rfs_mutex_lock (&rtems->access);
0820   if (rc > 0)
0821   {
0822     rtems_rfs_mutex_destroy (&rtems->access);
0823     free (rtems);
0824     return rtems_rfs_rtems_error ("initialise: cannot lock access  mutex", rc);
0825   }
0826 
0827   rc = rtems_rfs_fs_open (mt_entry->dev, rtems, flags, max_held_buffers, &fs);
0828   if (rc)
0829   {
0830     rtems_rfs_mutex_unlock (&rtems->access);
0831     rtems_rfs_mutex_destroy (&rtems->access);
0832     free (rtems);
0833     return rtems_rfs_rtems_error ("initialise: open", errno);
0834   }
0835 
0836   mt_entry->fs_info                          = fs;
0837   mt_entry->ops                              = &rtems_rfs_ops;
0838   mt_entry->mt_fs_root->location.node_access = (void*) RTEMS_RFS_ROOT_INO;
0839   mt_entry->mt_fs_root->location.handlers    = &rtems_rfs_rtems_dir_handlers;
0840 
0841   rtems_rfs_rtems_unlock (fs);
0842 
0843   return 0;
0844 }
0845 
0846 /**
0847  * Shutdown the file system.
0848  */
0849 void
0850 rtems_rfs_rtems_shutdown (rtems_filesystem_mount_table_entry_t* mt_entry)
0851 {
0852   rtems_rfs_file_system*   fs = mt_entry->fs_info;
0853   rtems_rfs_rtems_private* rtems;
0854 
0855   rtems = rtems_rfs_fs_user (fs);
0856 
0857   /* FIXME: Return value? */
0858   rtems_rfs_fs_close(fs);
0859 
0860   rtems_rfs_mutex_destroy (&rtems->access);
0861   free (rtems);
0862 }