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 Systems Link Routines
0009  * 
0010  * These functions manage links. A link is the addition of a directory entry
0011  * in a parent directory and incrementing the links count in the inode.
0012  */
0013 
0014 /*
0015  *  COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
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 <inttypes.h>
0044 #include <string.h>
0045 
0046 #include <rtems/rfs/rtems-rfs-block.h>
0047 #include <rtems/rfs/rtems-rfs-buffer.h>
0048 #include <rtems/rfs/rtems-rfs-file-system.h>
0049 #include <rtems/rfs/rtems-rfs-trace.h>
0050 #include <rtems/rfs/rtems-rfs-dir.h>
0051 #include <rtems/rfs/rtems-rfs-dir-hash.h>
0052 #include <rtems/rfs/rtems-rfs-link.h>
0053 
0054 int
0055 rtems_rfs_link (rtems_rfs_file_system* fs,
0056                 const char*            name,
0057                 int                    length,
0058                 rtems_rfs_ino          parent,
0059                 rtems_rfs_ino          target,
0060                 bool                   link_dir)
0061 {
0062   rtems_rfs_inode_handle parent_inode;
0063   rtems_rfs_inode_handle target_inode;
0064   uint16_t               links;
0065   int                    rc;
0066 
0067   if (rtems_rfs_trace (RTEMS_RFS_TRACE_LINK))
0068   {
0069     int c;
0070     printf ("rtems-rfs: link: parent(%" PRIu32 ") -> ", parent);
0071     for (c = 0; c < length; c++)
0072       printf ("%c", name[c]);
0073     printf ("(%" PRIu32 ")\n", target);
0074   }
0075 
0076   rc = rtems_rfs_inode_open (fs, target, &target_inode, true);
0077   if (rc)
0078     return rc;
0079 
0080   /*
0081    * If the target inode is a directory and we cannot link directories
0082    * return a not supported error code.
0083    */
0084   if (!link_dir && S_ISDIR (rtems_rfs_inode_get_mode (&target_inode)))
0085   {
0086     rtems_rfs_inode_close (fs, &target_inode);
0087     return ENOTSUP;
0088   }
0089 
0090   rc = rtems_rfs_inode_open (fs, parent, &parent_inode, true);
0091   if (rc)
0092   {
0093     rtems_rfs_inode_close (fs, &target_inode);
0094     return rc;
0095   }
0096 
0097   rc = rtems_rfs_dir_add_entry (fs, &parent_inode, name, length, target);
0098   if (rc > 0)
0099   {
0100     rtems_rfs_inode_close (fs, &parent_inode);
0101     rtems_rfs_inode_close (fs, &target_inode);
0102     return rc;
0103   }
0104 
0105   links = rtems_rfs_inode_get_links (&target_inode) + 1;
0106   rtems_rfs_inode_set_links (&target_inode, links);
0107 
0108   rc = rtems_rfs_inode_time_stamp_now (&parent_inode, true, true);
0109   if (rc > 0)
0110   {
0111     rtems_rfs_inode_close (fs, &parent_inode);
0112     rtems_rfs_inode_close (fs, &target_inode);
0113     return rc;
0114   }
0115 
0116   rc = rtems_rfs_inode_close (fs, &parent_inode);
0117   if (rc > 0)
0118   {
0119     rtems_rfs_inode_close (fs, &target_inode);
0120     return rc;
0121   }
0122 
0123   rc = rtems_rfs_inode_close (fs, &target_inode);
0124 
0125   return rc;
0126 }
0127 
0128 int
0129 rtems_rfs_unlink (rtems_rfs_file_system* fs,
0130                   rtems_rfs_ino          parent,
0131                   rtems_rfs_ino          target,
0132                   uint32_t               doff,
0133                   rtems_rfs_unlink_dir   dir_mode)
0134 {
0135   rtems_rfs_inode_handle parent_inode;
0136   rtems_rfs_inode_handle target_inode;
0137   uint16_t               links;
0138   bool                   dir;
0139   int                    rc;
0140 
0141   if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
0142     printf ("rtems-rfs: unlink: parent(%" PRIu32 ") -X-> (%" PRIu32 ")\n", parent, target);
0143 
0144   rc = rtems_rfs_inode_open (fs, target, &target_inode, true);
0145   if (rc)
0146     return rc;
0147 
0148   /*
0149    * If a directory process the unlink mode.
0150    */
0151 
0152   dir = RTEMS_RFS_S_ISDIR (rtems_rfs_inode_get_mode (&target_inode));
0153   if (dir)
0154   {
0155     switch (dir_mode)
0156     {
0157       case rtems_rfs_unlink_dir_denied:
0158         if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
0159           printf ("rtems-rfs: link is a directory\n");
0160         rtems_rfs_inode_close (fs, &target_inode);
0161         return EISDIR;
0162 
0163       case rtems_rfs_unlink_dir_if_empty:
0164         rc = rtems_rfs_dir_empty (fs, &target_inode);
0165         if (rc > 0)
0166         {
0167           if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
0168             printf ("rtems-rfs: dir-empty: %d: %s\n", rc, strerror (rc));
0169           rtems_rfs_inode_close (fs, &target_inode);
0170           return rc;
0171         }
0172         break;
0173 
0174       default:
0175         break;
0176     }
0177   }
0178 
0179   rc = rtems_rfs_inode_open (fs, parent, &parent_inode, true);
0180   if (rc)
0181   {
0182     if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
0183       printf ("rtems-rfs: link: inode-open failed: %d: %s\n",
0184               rc, strerror (rc));
0185     rtems_rfs_inode_close (fs, &target_inode);
0186     return rc;
0187   }
0188 
0189   rc = rtems_rfs_dir_del_entry (fs, &parent_inode, target, doff);
0190   if (rc > 0)
0191   {
0192     if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
0193       printf ("rtems-rfs: unlink: dir-del failed: %d: %s\n",
0194               rc, strerror (rc));
0195     rtems_rfs_inode_close (fs, &parent_inode);
0196     rtems_rfs_inode_close (fs, &target_inode);
0197     return rc;
0198   }
0199 
0200   links = rtems_rfs_inode_get_links (&target_inode);
0201 
0202   if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
0203     printf ("rtems-rfs: unlink: target:%" PRIu32 " links:%u\n", target, links);
0204 
0205   if (links > 1)
0206   {
0207     links--;
0208     rtems_rfs_inode_set_links (&target_inode, links);
0209   }
0210   else
0211   {
0212     /*
0213      * Erasing the inode releases all blocks attached to it.
0214      */
0215     rc = rtems_rfs_inode_delete (fs, &target_inode);
0216     if (rc > 0)
0217     {
0218       if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
0219         printf ("rtems-rfs: unlink: inode-del failed: %d: %s\n",
0220                 rc, strerror (rc));
0221       rtems_rfs_inode_close (fs, &parent_inode);
0222       rtems_rfs_inode_close (fs, &target_inode);
0223       return rc;
0224     }
0225 
0226     if (dir)
0227     {
0228       links = rtems_rfs_inode_get_links (&parent_inode);
0229       if (links > 1)
0230         links--;
0231       rtems_rfs_inode_set_links (&parent_inode, links);
0232     }
0233   }
0234 
0235   rc = rtems_rfs_inode_time_stamp_now (&parent_inode, true, true);
0236   if (rc > 0)
0237   {
0238     if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
0239       printf ("rtems-rfs: link: inode-time-stamp failed: %d: %s\n",
0240               rc, strerror (rc));
0241     rtems_rfs_inode_close (fs, &parent_inode);
0242     rtems_rfs_inode_close (fs, &target_inode);
0243     return rc;
0244   }
0245 
0246   rc = rtems_rfs_inode_close (fs, &parent_inode);
0247   if (rc > 0)
0248   {
0249     if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
0250       printf ("rtems-rfs: link: parent inode-close failed: %d: %s\n",
0251               rc, strerror (rc));
0252     rtems_rfs_inode_close (fs, &target_inode);
0253     return rc;
0254   }
0255 
0256   rc = rtems_rfs_inode_close (fs, &target_inode);
0257 
0258   if ((rc > 0) && rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
0259     printf ("rtems-rfs: link: target inode-close failed: %d: %s\n",
0260             rc, strerror (rc));
0261 
0262   return rc;
0263 }
0264 
0265 int
0266 rtems_rfs_symlink (rtems_rfs_file_system* fs,
0267                    const char*            name,
0268                    int                    length,
0269                    const char*            link,
0270                    int                    link_length,
0271                    uid_t                  uid,
0272                    gid_t                  gid,
0273                    rtems_rfs_ino          parent)
0274 {
0275   rtems_rfs_inode_handle inode;
0276   rtems_rfs_ino          ino;
0277   int                    rc;
0278 
0279   if (rtems_rfs_trace (RTEMS_RFS_TRACE_SYMLINK))
0280   {
0281     int c;
0282     printf ("rtems-rfs: symlink: parent:%" PRIu32 " name:", parent);
0283     for (c = 0; c < length; c++)
0284       printf ("%c", name[c]);
0285     printf (" link:");
0286     for (c = 0; c < link_length; c++)
0287       printf ("%c", link[c]);
0288   }
0289 
0290   if (link_length >= rtems_rfs_fs_block_size (fs))
0291     return ENAMETOOLONG;
0292 
0293   rc = rtems_rfs_inode_create (fs, parent, name, strlen (name),
0294                                RTEMS_RFS_S_SYMLINK,
0295                                1, uid, gid, &ino);
0296   if (rc > 0)
0297     return rc;
0298 
0299   rc = rtems_rfs_inode_open (fs, ino, &inode, true);
0300   if (rc > 0)
0301     return rc;
0302 
0303   /*
0304    * If the link length is less than the length of data union in the inode
0305    * place the link into the data area else allocate a block and write the link
0306    * to that.
0307    */
0308   if (link_length < RTEMS_RFS_INODE_DATA_NAME_SIZE)
0309   {
0310     memset (inode.node->data.name, 0, RTEMS_RFS_INODE_DATA_NAME_SIZE);
0311     memcpy (inode.node->data.name, link, link_length);
0312     rtems_rfs_inode_set_block_count (&inode, 0);
0313   }
0314   else
0315   {
0316     rtems_rfs_block_map     map;
0317     rtems_rfs_block_no      block;
0318     rtems_rfs_buffer_handle buffer;
0319     uint8_t*                data;
0320 
0321     rc = rtems_rfs_block_map_open (fs, &inode, &map);
0322     if (rc > 0)
0323     {
0324       rtems_rfs_inode_close (fs, &inode);
0325       return rc;
0326     }
0327 
0328     rc = rtems_rfs_block_map_grow (fs, &map, 1, &block);
0329     if (rc > 0)
0330     {
0331       rtems_rfs_block_map_close (fs, &map);
0332       rtems_rfs_inode_close (fs, &inode);
0333       return rc;
0334     }
0335 
0336     rc = rtems_rfs_buffer_handle_open (fs, &buffer);
0337     if (rc > 0)
0338     {
0339       rtems_rfs_block_map_close (fs, &map);
0340       rtems_rfs_inode_close (fs, &inode);
0341       return rc;
0342     }
0343 
0344     rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, false);
0345     if (rc > 0)
0346     {
0347       rtems_rfs_block_map_close (fs, &map);
0348       rtems_rfs_inode_close (fs, &inode);
0349       return rc;
0350     }
0351 
0352     data = rtems_rfs_buffer_data (&buffer);
0353 
0354     memset (data, 0xff, rtems_rfs_fs_block_size (fs));
0355     memcpy (data, link, link_length);
0356 
0357     rc = rtems_rfs_buffer_handle_close (fs, &buffer);
0358     if (rc > 0)
0359     {
0360       rtems_rfs_block_map_close (fs, &map);
0361       rtems_rfs_inode_close (fs, &inode);
0362       return rc;
0363     }
0364 
0365     rc = rtems_rfs_block_map_close (fs, &map);
0366     if (rc > 0)
0367     {
0368       rtems_rfs_inode_close (fs, &inode);
0369       return rc;
0370     }
0371   }
0372 
0373   rtems_rfs_inode_set_block_offset (&inode, link_length);
0374 
0375   rc = rtems_rfs_inode_close (fs, &inode);
0376 
0377   return rc;
0378 }
0379 
0380 int
0381 rtems_rfs_symlink_read (rtems_rfs_file_system* fs,
0382                         rtems_rfs_ino          link,
0383                         char*                  path,
0384                         size_t                 size,
0385                         size_t*                length)
0386 {
0387   rtems_rfs_inode_handle inode;
0388   int                    rc;
0389 
0390   if (rtems_rfs_trace (RTEMS_RFS_TRACE_SYMLINK_READ))
0391     printf ("rtems-rfs: symlink-read: link:%" PRIu32 "\n", link);
0392 
0393   rc = rtems_rfs_inode_open (fs, link, &inode, true);
0394   if (rc)
0395     return rc;
0396 
0397   if (!RTEMS_RFS_S_ISLNK (rtems_rfs_inode_get_mode (&inode)))
0398   {
0399     rtems_rfs_inode_close (fs, &inode);
0400     return EINVAL;
0401   }
0402 
0403   *length = rtems_rfs_inode_get_block_offset (&inode);
0404 
0405   if (size < *length)
0406   {
0407     *length = size;
0408   }
0409 
0410   if (rtems_rfs_inode_get_block_count (&inode) == 0)
0411   {
0412     memcpy (path, inode.node->data.name, *length);
0413   }
0414   else
0415   {
0416     rtems_rfs_block_map     map;
0417     rtems_rfs_block_no      block;
0418     rtems_rfs_buffer_handle buffer;
0419     char*                   data;
0420 
0421     rc = rtems_rfs_block_map_open (fs, &inode, &map);
0422     if (rc > 0)
0423     {
0424       rtems_rfs_inode_close (fs, &inode);
0425       return rc;
0426     }
0427 
0428     rc = rtems_rfs_block_map_seek (fs, &map, 0, &block);
0429     if (rc > 0)
0430     {
0431       rtems_rfs_block_map_close (fs, &map);
0432       rtems_rfs_inode_close (fs, &inode);
0433       return rc;
0434     }
0435 
0436     rc = rtems_rfs_buffer_handle_open (fs, &buffer);
0437     if (rc > 0)
0438     {
0439       rtems_rfs_block_map_close (fs, &map);
0440       rtems_rfs_inode_close (fs, &inode);
0441       return rc;
0442     }
0443 
0444     rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, false);
0445     if (rc > 0)
0446     {
0447       rtems_rfs_block_map_close (fs, &map);
0448       rtems_rfs_inode_close (fs, &inode);
0449       return rc;
0450     }
0451 
0452     data = rtems_rfs_buffer_data (&buffer);
0453     memcpy (path, data, *length);
0454 
0455     rc = rtems_rfs_buffer_handle_close (fs, &buffer);
0456     if (rc > 0)
0457     {
0458       rtems_rfs_block_map_close (fs, &map);
0459       rtems_rfs_inode_close (fs, &inode);
0460       return rc;
0461     }
0462 
0463     rc = rtems_rfs_block_map_close (fs, &map);
0464     if (rc > 0)
0465     {
0466       rtems_rfs_inode_close (fs, &inode);
0467       return rc;
0468     }
0469   }
0470 
0471   rc = rtems_rfs_inode_close (fs, &inode);
0472 
0473   return rc;
0474 }