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 File Routines
0009  *
0010  * These functions manage files.
0011  */
0012 
0013 /*
0014  *  COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
0015  *
0016  * Redistribution and use in source and binary forms, with or without
0017  * modification, are permitted provided that the following conditions
0018  * are met:
0019  * 1. Redistributions of source code must retain the above copyright
0020  *    notice, this list of conditions and the following disclaimer.
0021  * 2. Redistributions in binary form must reproduce the above copyright
0022  *    notice, this list of conditions and the following disclaimer in the
0023  *    documentation and/or other materials provided with the distribution.
0024  *
0025  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0026  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0027  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0028  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0029  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0030  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0031  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0032  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0033  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0034  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0035  * POSSIBILITY OF SUCH DAMAGE.
0036  */
0037 
0038 #ifdef HAVE_CONFIG_H
0039 #include "config.h"
0040 #endif
0041 
0042 #include <inttypes.h>
0043 #include <stdlib.h>
0044 #include <string.h>
0045 
0046 #include <rtems/rfs/rtems-rfs-block-pos.h>
0047 #include <rtems/rfs/rtems-rfs-file.h>
0048 #include <rtems/rfs/rtems-rfs-file-system.h>
0049 #include <rtems/rfs/rtems-rfs-trace.h>
0050 
0051 int
0052 rtems_rfs_file_open (rtems_rfs_file_system*  fs,
0053                      rtems_rfs_ino           ino,
0054                      int                     oflag,
0055                      rtems_rfs_file_handle** file)
0056 {
0057   rtems_rfs_file_handle* handle;
0058   rtems_rfs_file_shared* shared;
0059   int                    rc;
0060 
0061   if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
0062     printf ("rtems-rfs: file-open: ino=%" PRId32 "\n", ino);
0063 
0064   *file = NULL;
0065 
0066   /*
0067    * Allocate a new handle and initialise it. Do this before we deal with the
0068    * shared node data so we do not have to be concerned with reference
0069    * counting.
0070    */
0071   handle = malloc (sizeof (rtems_rfs_file_handle));
0072   if (!handle)
0073     return ENOMEM;
0074 
0075   memset (handle, 0, sizeof (rtems_rfs_file_handle));
0076 
0077   rc = rtems_rfs_buffer_handle_open (fs, &handle->buffer);
0078   if (rc > 0)
0079   {
0080     if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
0081       printf ("rtems-rfs: file-open: buffer handle open failed: %d: %s\n",
0082               rc, strerror (rc));
0083     free (handle);
0084     return rc;
0085   }
0086 
0087   /*
0088    * Scan the file system data list of open files for this ino. If found up
0089    * the reference count and return the pointer to the data.
0090    */
0091   shared = rtems_rfs_file_get_shared (fs, ino);
0092   if (shared)
0093   {
0094     shared->references++;
0095     if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
0096       printf ("rtems-rfs: file-open: ino=%" PRId32 " shared\n", ino);
0097   }
0098   else
0099   {
0100     /*
0101      * None exists so create. Copy in the shared parts of the inode we hold in
0102      * memory.
0103      */
0104     shared = malloc (sizeof (rtems_rfs_file_shared));
0105     if (!shared)
0106     {
0107       rtems_rfs_buffer_handle_close (fs, &handle->buffer);
0108       free (handle);
0109       return ENOMEM;
0110     }
0111 
0112     memset (shared, 0, sizeof (rtems_rfs_file_shared));
0113 
0114     rc = rtems_rfs_inode_open (fs, ino, &shared->inode, true);
0115     if (rc > 0)
0116     {
0117       if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
0118         printf ("rtems-rfs: file-open: inode open failed: %d: %s\n",
0119                 rc, strerror (rc));
0120       free (shared);
0121       rtems_rfs_buffer_handle_close (fs, &handle->buffer);
0122       free (handle);
0123       return rc;
0124     }
0125 
0126     rc = rtems_rfs_block_map_open (fs, &shared->inode, &shared->map);
0127     if (rc > 0)
0128     {
0129       if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
0130         printf ("rtems-rfs: file-open: block map open failed: %d: %s\n",
0131                 rc, strerror (rc));
0132       rtems_rfs_inode_close (fs, &shared->inode);
0133       free (shared);
0134       rtems_rfs_buffer_handle_close (fs, &handle->buffer);
0135       free (handle);
0136       return rc;
0137     }
0138 
0139     shared->references = 1;
0140     shared->size.count = rtems_rfs_inode_get_block_count (&shared->inode);
0141     shared->size.offset = rtems_rfs_inode_get_block_offset (&shared->inode);
0142     shared->atime = rtems_rfs_inode_get_atime (&shared->inode);
0143     shared->mtime = rtems_rfs_inode_get_mtime (&shared->inode);
0144     shared->ctime = rtems_rfs_inode_get_ctime (&shared->inode);
0145     shared->fs = fs;
0146 
0147     rtems_chain_append_unprotected (&fs->file_shares, &shared->link);
0148 
0149     rtems_rfs_inode_unload (fs, &shared->inode, false);
0150 
0151     if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
0152       printf ("rtems-rfs: file-open: ino=%" PRId32 " share created\n", ino);
0153   }
0154 
0155   handle->flags  = oflag;
0156   handle->shared = shared;
0157 
0158   *file = handle;
0159 
0160   return 0;
0161 }
0162 
0163 int
0164 rtems_rfs_file_close (rtems_rfs_file_system* fs,
0165                       rtems_rfs_file_handle* handle)
0166 {
0167   int rrc;
0168   int rc;
0169 
0170   rrc = 0;
0171 
0172   if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
0173     printf ("rtems-rfs: file-close: entry: ino=%" PRId32 "\n",
0174             handle->shared->inode.ino);
0175 
0176   if (handle->shared->references > 0)
0177     handle->shared->references--;
0178 
0179   if (handle->shared->references == 0)
0180   {
0181     if (!rtems_rfs_inode_is_loaded (&handle->shared->inode))
0182       rrc = rtems_rfs_inode_load (fs, &handle->shared->inode);
0183 
0184     if (rrc == 0)
0185     {
0186       /*
0187        * @todo This could be clever and only update if different.
0188        */
0189       rtems_rfs_inode_set_atime (&handle->shared->inode,
0190                                  handle->shared->atime);
0191       rtems_rfs_inode_set_mtime (&handle->shared->inode,
0192                                  handle->shared->mtime);
0193       rtems_rfs_inode_set_ctime (&handle->shared->inode,
0194                                  handle->shared->ctime);
0195       if (!rtems_rfs_block_size_equal (&handle->shared->size,
0196                                        &handle->shared->map.size))
0197         rtems_rfs_block_map_set_size (&handle->shared->map,
0198                                       &handle->shared->size);
0199     }
0200 
0201     rc = rtems_rfs_block_map_close (fs, &handle->shared->map);
0202     if (rc > 0)
0203     {
0204       if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
0205         printf ("rtems-rfs: file-close: map close error: ino=%" PRId32 ": %d: %s\n",
0206                 handle->shared->inode.ino, rc, strerror (rc));
0207       if (rrc == 0)
0208         rrc = rc;
0209     }
0210 
0211     rc = rtems_rfs_inode_close (fs, &handle->shared->inode);
0212     if (rc > 0)
0213     {
0214       if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
0215         printf ("rtems-rfs: file-close: inode close error: ino=%" PRId32 ": %d: %s\n",
0216                 handle->shared->inode.ino, rc, strerror (rc));
0217       if (rrc == 0)
0218         rrc = rc;
0219     }
0220 
0221     rtems_chain_extract_unprotected (&handle->shared->link);
0222     free (handle->shared);
0223   }
0224 
0225   rc = rtems_rfs_buffer_handle_close (fs, &handle->buffer);
0226   if ((rrc == 0) && (rc > 0))
0227     rrc = rc;
0228 
0229   if (rrc > 0)
0230   {
0231     if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
0232       printf ("rtems-rfs: file-close: result: %d: %s\n", rrc, strerror (rrc));
0233   }
0234 
0235   free (handle);
0236 
0237   return rrc;
0238 }
0239 
0240 int
0241 rtems_rfs_file_io_start (rtems_rfs_file_handle* handle,
0242                          size_t*                available,
0243                          bool                   read)
0244 {
0245   size_t size;
0246 
0247   if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
0248     printf ("rtems-rfs: file-io: start: %s pos=%" PRIu32 ":%" PRIu32 "\n",
0249             read ? "read" : "write",  handle->bpos.bno, handle->bpos.boff);
0250 
0251   if (!rtems_rfs_buffer_handle_has_block (&handle->buffer))
0252   {
0253     rtems_rfs_buffer_block block;
0254     bool                   request_read;
0255     int                    rc;
0256 
0257     request_read = read;
0258 
0259     rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
0260                                    rtems_rfs_file_map (handle),
0261                                    rtems_rfs_file_bpos (handle),
0262                                    &block);
0263     if (rc > 0)
0264     {
0265       /*
0266        * Has the read reached the EOF ?
0267        */
0268       if (read && (rc == ENXIO))
0269       {
0270         *available = 0;
0271         return 0;
0272       }
0273 
0274       if (rc != ENXIO)
0275         return rc;
0276 
0277       if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
0278         printf ("rtems-rfs: file-io: start: grow\n");
0279 
0280       rc = rtems_rfs_block_map_grow (rtems_rfs_file_fs (handle),
0281                                      rtems_rfs_file_map (handle),
0282                                      1, &block);
0283       if (rc > 0)
0284         return rc;
0285 
0286       request_read = false;
0287     }
0288     else
0289     {
0290       /*
0291        * If this is a write check if the write starts within a block or the
0292        * amount of data is less than a block size. If it is read the block
0293        * rather than getting a block to fill.
0294        */
0295       if (!read &&
0296           (rtems_rfs_file_block_offset (handle) ||
0297            (*available < rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle)))))
0298         request_read = true;
0299     }
0300 
0301     if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
0302       printf ("rtems-rfs: file-io: start: block=%" PRIu32 " request-read=%s\n",
0303               block, request_read ? "yes" : "no");
0304 
0305     rc = rtems_rfs_buffer_handle_request (rtems_rfs_file_fs (handle),
0306                                           rtems_rfs_file_buffer (handle),
0307                                           block, request_read);
0308     if (rc > 0)
0309       return rc;
0310   }
0311 
0312   if (read
0313       && rtems_rfs_block_map_last (rtems_rfs_file_map (handle))
0314       && rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle)))
0315     size = rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle));
0316   else
0317     size = rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
0318 
0319   *available = size - rtems_rfs_file_block_offset (handle);
0320 
0321   if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
0322     printf ("rtems-rfs: file-io: start: available=%zu (%zu)\n",
0323             *available, size);
0324 
0325   return 0;
0326 }
0327 
0328 int
0329 rtems_rfs_file_io_end (rtems_rfs_file_handle* handle,
0330                        size_t                 size,
0331                        bool                   read)
0332 {
0333   bool atime;
0334   bool mtime;
0335   bool length;
0336   int  rc = 0;
0337 
0338   if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
0339     printf ("rtems-rfs: file-io:   end: %s size=%zu\n",
0340             read ? "read" : "write", size);
0341 
0342   if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
0343   {
0344     if (!read)
0345       rtems_rfs_buffer_mark_dirty (rtems_rfs_file_buffer (handle));
0346     rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
0347                                           rtems_rfs_file_buffer (handle));
0348     if (rc > 0)
0349     {
0350       printf (
0351         "rtems-rfs: file-io:   end: error on release: %s size=%zu: %d: %s\n",
0352         read ? "read" : "write", size, rc, strerror (rc));
0353 
0354       return rc;
0355     }
0356   }
0357 
0358   /*
0359    * Update the handle's position. Only a block size can be handled at a time
0360    * so no special maths is needed. If the offset is bigger than the block size
0361    * increase the block number and adjust the offset.
0362    *
0363    * If we are the last block and the position is past the current size update
0364    * the size with the new length. The map holds the block count.
0365    */
0366   handle->bpos.boff += size;
0367 
0368   if (handle->bpos.boff >=
0369       rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle)))
0370   {
0371     handle->bpos.bno++;
0372     handle->bpos.boff -= rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
0373   }
0374 
0375   length = false;
0376   mtime = !read;
0377 
0378   if (!read &&
0379       rtems_rfs_block_map_past_end (rtems_rfs_file_map (handle),
0380                                     rtems_rfs_file_bpos (handle)))
0381   {
0382     rtems_rfs_block_map_set_size_offset (rtems_rfs_file_map (handle),
0383                                          handle->bpos.boff);
0384     length = true;
0385   }
0386 
0387   atime  = rtems_rfs_file_update_atime (handle);
0388   mtime  = rtems_rfs_file_update_mtime (handle) && mtime;
0389   length = rtems_rfs_file_update_length (handle) && length;
0390 
0391   if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
0392     printf ("rtems-rfs: file-io:   end: pos=%" PRIu32 ":%" PRIu32 " %c %c %c\n",
0393             handle->bpos.bno, handle->bpos.boff,
0394             atime ? 'A' : '-', mtime ? 'M' : '-', length ? 'L' : '-');
0395 
0396   if (atime || mtime)
0397   {
0398     time_t now = time (NULL);
0399     if (read && atime)
0400       handle->shared->atime = now;
0401     if (!read && mtime)
0402       handle->shared->mtime = now;
0403   }
0404   if (length)
0405   {
0406     handle->shared->size.count =
0407       rtems_rfs_block_map_count (rtems_rfs_file_map (handle));
0408     handle->shared->size.offset =
0409       rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle));
0410   }
0411 
0412   return rc;
0413 }
0414 
0415 int
0416 rtems_rfs_file_io_release (rtems_rfs_file_handle* handle)
0417 {
0418   int rc = 0;
0419   if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
0420     rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
0421                                           rtems_rfs_file_buffer (handle));
0422   return rc;
0423 }
0424 
0425 int
0426 rtems_rfs_file_seek (rtems_rfs_file_handle* handle,
0427                      rtems_rfs_pos          pos,
0428                      rtems_rfs_pos*         new_pos)
0429 {
0430   if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
0431     printf ("rtems-rfs: file-seek: new=%" PRIu64 "\n", pos);
0432 
0433   /*
0434    * This call only sets the position if it is in a valid part of the file. The
0435    * user can request past the end of the file then write to extend the
0436    * file. The lseek entry states:
0437    *
0438    *    "Although lseek() may position the file offset beyond the end of the
0439    *     file, this function does not itself extend the size of the file."
0440    *
0441    * This means the file needs to set the file size to the pos only when a
0442    * write occurs.
0443    */
0444   if (pos <= rtems_rfs_file_shared_get_size (rtems_rfs_file_fs (handle),
0445                                             handle->shared))
0446   {
0447     rtems_rfs_file_set_bpos (handle, pos);
0448 
0449     /*
0450      * If the file has a block check if it maps to the current position and it
0451      * does not release it. That will force us to get the block at the new
0452      * position when the I/O starts.
0453      */
0454     if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
0455     {
0456       rtems_rfs_buffer_block block;
0457       int                    rc;
0458 
0459       rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
0460                                      rtems_rfs_file_map (handle),
0461                                      rtems_rfs_file_bpos (handle),
0462                                      &block);
0463       if (rc > 0)
0464         return rc;
0465       if (rtems_rfs_buffer_bnum (&handle->buffer) != block)
0466       {
0467         rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
0468                                               rtems_rfs_file_buffer (handle));
0469         if (rc > 0)
0470           return rc;
0471       }
0472     }
0473   }
0474   else
0475   {
0476     /*
0477      * The seek is outside the current file so release any buffer. A write will
0478      * extend the file.
0479      */
0480     int rc = rtems_rfs_file_io_release (handle);
0481     if (rc > 0)
0482       return rc;
0483   }
0484 
0485   *new_pos = pos;
0486   return 0;
0487 }
0488 
0489 int
0490 rtems_rfs_file_set_size (rtems_rfs_file_handle* handle,
0491                          rtems_rfs_pos          new_size)
0492 {
0493   rtems_rfs_block_map* map  = rtems_rfs_file_map (handle);
0494   rtems_rfs_pos        size;
0495   int                  rc;
0496 
0497   if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
0498     printf ("rtems-rfs: file-set-size: size=%" PRIu64 "\n", new_size);
0499 
0500   size = rtems_rfs_file_size (handle);
0501 
0502   /*
0503    * If the file is same size do nothing else grow or shrink it ?
0504    *
0505    * If the file does not change size do not update the times.
0506    */
0507   if (size != new_size)
0508   {
0509     /*
0510      * Short cut for the common truncate on open call.
0511      */
0512     if (new_size == 0)
0513     {
0514       rc = rtems_rfs_block_map_free_all (rtems_rfs_file_fs (handle), map);
0515       if (rc > 0)
0516         return rc;
0517     }
0518     else
0519     {
0520       if (size < new_size)
0521       {
0522         /*
0523          * Grow. Fill with 0's.
0524          */
0525         rtems_rfs_pos count;
0526         uint32_t      length;
0527         bool          read_block;
0528 
0529         count = new_size - size;
0530         length = rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
0531         read_block = false;
0532 
0533         while (count)
0534         {
0535           rtems_rfs_buffer_block block;
0536           rtems_rfs_block_pos    bpos;
0537           uint8_t*               dst;
0538 
0539           /*
0540            * Get the block position for the current end of the file as seen by
0541            * the map. If not found and the EOF grow the map then fill the block
0542            * with 0.
0543            */
0544           rtems_rfs_block_size_get_bpos (rtems_rfs_block_map_size (map), &bpos);
0545           rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
0546                                          map, &bpos, &block);
0547           if (rc > 0)
0548           {
0549             /*
0550              * Have we reached the EOF ?
0551              */
0552             if (rc != ENXIO)
0553               return rc;
0554 
0555             rc = rtems_rfs_block_map_grow (rtems_rfs_file_fs (handle),
0556                                            map, 1, &block);
0557             if (rc > 0)
0558               return rc;
0559           }
0560 
0561           if (count < (length - bpos.boff))
0562           {
0563             length = count + bpos.boff;
0564             read_block = true;
0565             rtems_rfs_block_map_set_size_offset (map, length);
0566           }
0567           else
0568           {
0569             rtems_rfs_block_map_set_size_offset (map, 0);
0570           }
0571 
0572           /*
0573            * Only read the block if the length is not the block size.
0574            */
0575           rc = rtems_rfs_buffer_handle_request (rtems_rfs_file_fs (handle),
0576                                                 rtems_rfs_file_buffer (handle),
0577                                                 block, read_block);
0578           if (rc > 0)
0579             return rc;
0580 
0581           dst = rtems_rfs_buffer_data (&handle->buffer);
0582           memset (dst + bpos.boff, 0, length - bpos.boff);
0583 
0584           rtems_rfs_buffer_mark_dirty (rtems_rfs_file_buffer (handle));
0585 
0586           rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
0587                                                 rtems_rfs_file_buffer (handle));
0588           if (rc > 0)
0589             return rc;
0590 
0591           count -= length - bpos.boff;
0592         }
0593       }
0594       else
0595       {
0596         /*
0597          * Shrink
0598          */
0599         rtems_rfs_block_no blocks;
0600         uint32_t           offset;
0601 
0602         blocks =
0603           rtems_rfs_block_map_count (map) -
0604           (((new_size - 1) /
0605             rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle))) + 1);
0606 
0607         offset =
0608           new_size % rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
0609 
0610         if (blocks)
0611         {
0612           int rc;
0613           rc = rtems_rfs_block_map_shrink (rtems_rfs_file_fs (handle),
0614                                            rtems_rfs_file_map (handle),
0615                                            blocks);
0616           if (rc > 0)
0617             return rc;
0618         }
0619 
0620         rtems_rfs_block_map_set_size_offset (map, offset);
0621 
0622         if (rtems_rfs_block_pos_past_end (rtems_rfs_file_bpos (handle),
0623                                           rtems_rfs_block_map_size (map)))
0624           rtems_rfs_block_size_get_bpos (rtems_rfs_block_map_size (map),
0625                                          rtems_rfs_file_bpos (handle));
0626       }
0627     }
0628 
0629     handle->shared->size.count  = rtems_rfs_block_map_count (map);
0630     handle->shared->size.offset = rtems_rfs_block_map_size_offset (map);
0631   }
0632 
0633   if (rtems_rfs_file_update_mtime (handle))
0634     handle->shared->mtime = time (NULL);
0635 
0636   return 0;
0637 }
0638 
0639 rtems_rfs_file_shared*
0640 rtems_rfs_file_get_shared (rtems_rfs_file_system* fs,
0641                            rtems_rfs_ino          ino)
0642 {
0643   rtems_chain_node* node;
0644   node = rtems_chain_first (&fs->file_shares);
0645   while (!rtems_chain_is_tail (&fs->file_shares, node))
0646   {
0647     rtems_rfs_file_shared* shared;
0648     shared = (rtems_rfs_file_shared*) node;
0649     if (shared->inode.ino == ino)
0650       return shared;
0651     node = rtems_chain_next (node);
0652   }
0653   return NULL;
0654 }