/**
 * Find a block indirectly held in a table of block numbers.
 *
 * @param fs The file system.
 * @param buffer The handle to access the block data by.
 * @param block The block number of the table of block numbers.
 * @param offset The offset in the table of the block number to return. This is
 *               a block number offset not a byte offset into the table.
 * @param result Pointer to the result of the search.
 * @return int The error number (errno). No error if 0.
 */
static int
rtems_rfs_block_find_indirect (rtems_rfs_file_system*   fs,
                               rtems_rfs_buffer_handle* buffer,
                               rtems_rfs_block_no       block,
                               int                      offset,
                               rtems_rfs_block_no*      result)
{
   int rc;

  /*
   * If the handle has a buffer and this request is a different block the current
   * buffer is released.
   */
  rc = rtems_rfs_buffer_handle_request (fs, buffer, block, true);
  if (rc > 0)
    return rc;

  *result = rtems_rfs_block_get_number (buffer, offset);
  if ((*result + 1) == 0)
    *result = 0;

  if (*result >= rtems_rfs_fs_blocks (fs))
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BLOCK_FIND))
      printf ("rtems-rfs: block-find: invalid block in table:"
              " block=%" PRId32 ", indirect=%" PRId32 "/%d\n", *result, block, offset);
    *result = 0;
    rc = EIO;
  }

  return 0;
}
Exemple #2
0
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;
}
/**
 * Return the map after loading from disk if not already loaded.
 *
 * @param control The bitmap control.
 * @param rtems_rfs_bitmap_map* Pointer to the bitmap map data if no error.
 * @return int The error number (errno). No error if 0.
 */
static int
rtems_rfs_bitmap_load_map (rtems_rfs_bitmap_control* control,
                           rtems_rfs_bitmap_map*     map)
{
  int rc;

  if (!control->buffer)
    return ENXIO;

  *map = NULL;

  rc = rtems_rfs_buffer_handle_request (control->fs,
                                        control->buffer,
                                        control->block,
                                        true);
  if (rc)
    return rc;

  *map = rtems_rfs_buffer_data (control->buffer);
  return 0;
}
/**
 * Allocate an indirect block to a map.
 *
 * @param fs The file system data.
 * @param map The map the allocation is for.
 * @param buffer The buffer the indirect block is accessed by.
 * @param block The block number of the indirect block allocated.
 * @param upping True is upping the map to the next indirect level.
 * @return int The error number (errno). No error if 0.
 */
static int
rtems_rfs_block_map_indirect_alloc (rtems_rfs_file_system*   fs,
                                    rtems_rfs_block_map*     map,
                                    rtems_rfs_buffer_handle* buffer,
                                    rtems_rfs_block_no*      block,
                                    bool                     upping)
{
  rtems_rfs_bitmap_bit new_block;
  int                  rc;
  /*
   * Save the new block locally because upping can have *block pointing to the
   * slots which are cleared when upping.
   */
  rc = rtems_rfs_group_bitmap_alloc (fs, map->last_map_block, false, &new_block);
  if (rc > 0)
    return rc;
  rc = rtems_rfs_buffer_handle_request (fs, buffer, new_block, false);
  if (rc > 0)
  {
    rtems_rfs_group_bitmap_free (fs, false, new_block);
    return rc;
  }
  memset (rtems_rfs_buffer_data (buffer), 0xff, rtems_rfs_fs_block_size (fs));
  if (upping)
  {
    int b;
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BLOCK_MAP_GROW))
      printf ("rtems-rfs: block-map-grow: upping: block-count=%" PRId32 "\n",
              map->size.count);
    for (b = 0; b < RTEMS_RFS_INODE_BLOCKS; b++)
      rtems_rfs_block_set_number (buffer, b, map->blocks[b]);
    memset (map->blocks, 0, sizeof (map->blocks));
  }
  rtems_rfs_buffer_mark_dirty (buffer);
  *block = new_block;
  map->last_map_block = new_block;
  return 0;
}
Exemple #5
0
int
rtems_rfs_dir_empty (rtems_rfs_file_system*  fs,
                     rtems_rfs_inode_handle* dir)
{
  rtems_rfs_block_map     map;
  rtems_rfs_buffer_handle buffer;
  rtems_rfs_block_no      block;
  bool                    empty;
  int                     rc;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
    printf ("rtems-rfs: dir-empty: dir=%" PRId32 "\n", rtems_rfs_inode_ino (dir));

  empty = true;
  
  rc = rtems_rfs_block_map_open (fs, dir, &map);
  if (rc > 0)
    return rc;

  rc = rtems_rfs_block_map_seek (fs, &map, 0, &block);
  if (rc > 0)
  {
    rtems_rfs_block_map_close (fs, &map);
    return rc;
  }
  
  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
  if (rc > 0)
  {
    rtems_rfs_block_map_close (fs, &map);
    return rc;
  }

  /*
   * Look for an empty entry and if this is the last block that is the end of
   * the directory.
   */
  while (empty)
  {
    uint8_t* entry;
    int      offset;
    
    rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
    if (rc > 0)
      break;

    entry  = rtems_rfs_buffer_data (&buffer);
    offset = 0;
    
    while (offset < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE))
    {
      rtems_rfs_ino eino;
      int           elength;

      elength = rtems_rfs_dir_entry_length (entry);
      eino    = rtems_rfs_dir_entry_ino (entry);

      if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
        break;

      if (rtems_rfs_dir_entry_valid (fs, elength, eino))
      {
        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_EMPTY))
          printf ("rtems-rfs: dir-empty: "
                  "bad length or ino for ino %" PRIu32 ": %u/%" PRIu32 " @ %04x\n",
                  rtems_rfs_inode_ino (dir), elength, eino, offset);
        rc = EIO;
        break;
      }
        
      /*
       * Ignore the current (.) and parent (..) entries. Anything else means
       * the directory is not empty.
       */
      if (((elength != (RTEMS_RFS_DIR_ENTRY_SIZE + 1)) ||
           (entry[RTEMS_RFS_DIR_ENTRY_SIZE] != '.')) &&
          ((elength != (RTEMS_RFS_DIR_ENTRY_SIZE + 2)) ||
           (entry[RTEMS_RFS_DIR_ENTRY_SIZE] != '.') ||
           (entry[RTEMS_RFS_DIR_ENTRY_SIZE + 1] != '.')))
      {
        empty = false;
        break;
      }

      entry  += elength;
      offset += elength;
    }

    if (empty)
    {
      rc = rtems_rfs_block_map_next_block (fs, &map, &block);
      if (rc > 0)
      {
        if (rc == ENXIO)
          rc = 0;
        break;
      }
    }
  }

  if ((rc == 0) && !empty)
    rc = ENOTEMPTY;
  
  rtems_rfs_buffer_handle_close (fs, &buffer);
  rtems_rfs_block_map_close (fs, &map);
  return rc;
}
Exemple #6
0
int
rtems_rfs_dir_lookup_ino (rtems_rfs_file_system*  fs,
                          rtems_rfs_inode_handle* inode,
                          const char*             name,
                          int                     length,
                          rtems_rfs_ino*          ino,
                          uint32_t*               offset)
{
  rtems_rfs_block_map     map;
  rtems_rfs_buffer_handle entries;
  int                     rc;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
  {
    int c;
    printf ("rtems-rfs: dir-lookup-ino: lookup ino: root=%" PRId32 ", path=",
            inode->ino);
    for (c = 0; c < length; c++)
      printf ("%c", name[c]);
    printf (", len=%d\n", length);
  }

  *ino = RTEMS_RFS_EMPTY_INO;
  *offset = 0;
  
  rc = rtems_rfs_block_map_open (fs, inode, &map);
  if (rc > 0)
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
      printf ("rtems-rfs: dir-lookup-ino: map open failed for ino %" PRIu32 ": %d: %s",
              rtems_rfs_inode_ino (inode), rc, strerror (rc));
    return rc;
  }
  
  rc = rtems_rfs_buffer_handle_open (fs, &entries);
  if (rc > 0)
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
      printf ("rtems-rfs: dir-lookup-ino: handle open failed for ino %" PRIu32 ": %d: %s",
              rtems_rfs_inode_ino (inode), rc, strerror (rc));
    rtems_rfs_block_map_close (fs, &map);
    return rc;
  }
  else
  {
    rtems_rfs_block_no block;
    uint32_t           hash;

    /*
     * Calculate the hash of the look up string.
     */
    hash = rtems_rfs_dir_hash (name, length);
  
    /*
     * Locate the first block. The map points to the start after open so just
     * seek 0. If an error the block will be 0.
     */
    rc = rtems_rfs_block_map_seek (fs, &map, 0, &block);
    if (rc > 0)
    {
      if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
        printf ("rtems-rfs: dir-lookup-ino: block map find failed: %d: %s\n",
                rc, strerror (rc));
      if (rc == ENXIO)
        rc = ENOENT;
      rtems_rfs_buffer_handle_close (fs, &entries);
      rtems_rfs_block_map_close (fs, &map);
      return rc;
    }
        
    while ((rc == 0) && block)
    {
      uint8_t* entry;
      
      if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
        printf ("rtems-rfs: dir-lookup-ino: block read, ino=%" PRIu32 " bno=%" PRId32 "\n",
                rtems_rfs_inode_ino (inode), map.bpos.bno);
      
      rc = rtems_rfs_buffer_handle_request (fs, &entries, block, true); 
      if (rc > 0)
      {
        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
          printf ("rtems-rfs: dir-lookup-ino: block read, ino=%" PRIu32 " block=%" PRId32 ": %d: %s\n",
                  rtems_rfs_inode_ino (inode), block, rc, strerror (rc));
        break;
      }

      /*
       * Search the block to see if the name matches. A hash of 0xffff or 0x0
       * means the entry is empty.
       */

      entry = rtems_rfs_buffer_data (&entries);
      
      map.bpos.boff = 0;

      while (map.bpos.boff < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE))
      {
        uint32_t ehash;
        int      elength;
      
        ehash  = rtems_rfs_dir_entry_hash (entry);
        elength = rtems_rfs_dir_entry_length (entry);
        *ino = rtems_rfs_dir_entry_ino (entry);

        if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
          break;
        
        if (rtems_rfs_dir_entry_valid (fs, elength, *ino))
        {
          if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
            printf ("rtems-rfs: dir-lookup-ino: "
                    "bad length or ino for ino %" PRIu32 ": %u/%" PRId32 " @ %04" PRIx32 "\n",
                    rtems_rfs_inode_ino (inode), elength, *ino, map.bpos.boff);
          rc = EIO;
          break;
        }
          
        if (ehash == hash)
        {
          if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO_CHECK))
            printf ("rtems-rfs: dir-lookup-ino: "
                    "checking entry for ino %" PRId32 ": bno=%04" PRIx32 "/off=%04" PRIx32
                    " length:%d ino:%" PRId32 "\n",
                    rtems_rfs_inode_ino (inode), map.bpos.bno, map.bpos.boff,
                    elength, rtems_rfs_dir_entry_ino (entry));

          if (memcmp (entry + RTEMS_RFS_DIR_ENTRY_SIZE, name, length) == 0)
          {
            *offset = rtems_rfs_block_map_pos (fs, &map);
            
            if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO_FOUND))
              printf ("rtems-rfs: dir-lookup-ino: "
                      "entry found in ino %" PRIu32 ", ino=%" PRIu32 " offset=%" PRIu32 "\n",
                      rtems_rfs_inode_ino (inode), *ino, *offset);

            rtems_rfs_buffer_handle_close (fs, &entries);
            rtems_rfs_block_map_close (fs, &map);
            return 0;
          }
        }

        map.bpos.boff += elength;
        entry += elength;
      }

      if (rc == 0)
      {
        rc = rtems_rfs_block_map_next_block (fs, &map, &block);
        if ((rc > 0) && (rc != ENXIO))
        {
          if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
            printf ("rtems-rfs: dir-lookup-ino: "
                    "block map next block failed in ino %" PRIu32 ": %d: %s\n",
                    rtems_rfs_inode_ino (inode), rc, strerror (rc));
        }
        if (rc == ENXIO)
          rc = ENOENT;
      }
    }

    if ((rc == 0) && (block == 0))
    {
      rc = EIO;
      if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
        printf ("rtems-rfs: dir-lookup-ino: block is 0 in ino %" PRIu32 ": %d: %s\n",
                rtems_rfs_inode_ino (inode), rc, strerror (rc));
    }
  }
  
  rtems_rfs_buffer_handle_close (fs, &entries);
  rtems_rfs_block_map_close (fs, &map);
  return rc;
}
Exemple #7
0
int
rtems_rfs_dir_read (rtems_rfs_file_system*  fs,
                    rtems_rfs_inode_handle* dir,
                    rtems_rfs_pos_rel       offset,
                    struct dirent*          dirent,
                    size_t*                 length)
{
  rtems_rfs_block_map     map;
  rtems_rfs_buffer_handle buffer;
  rtems_rfs_block_no      block;
  int                     rc;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
    printf ("rtems-rfs: dir-read: dir=%" PRId32 " offset=%" PRId64 "\n",
            rtems_rfs_inode_ino (dir), offset);

  *length = 0;
  
  rc = rtems_rfs_block_map_open (fs, dir, &map);
  if (rc > 0)
    return rc;

  if (((rtems_rfs_fs_block_size (fs) -
        (offset % rtems_rfs_fs_block_size (fs))) <= RTEMS_RFS_DIR_ENTRY_SIZE))
    offset = (((offset / rtems_rfs_fs_block_size (fs)) + 1) *
              rtems_rfs_fs_block_size (fs));
  
  rc = rtems_rfs_block_map_seek (fs, &map, offset, &block);
  if (rc > 0)
  {
    if (rc == ENXIO)
      rc = ENOENT;
    rtems_rfs_block_map_close (fs, &map);
    return rc;
  }
  
  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
  if (rc > 0)
  {
    rtems_rfs_block_map_close (fs, &map);
    return rc;
  }

  /*
   * Look for an empty entry and if this is the last block that is the end of
   * the directory.
   */
  while (rc == 0)
  {
    uint8_t*      entry;
    rtems_rfs_ino eino;
    int           elength;    
    int           remaining;
    
    rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
    if (rc > 0)
    {
      rtems_rfs_buffer_handle_close (fs, &buffer);
      rtems_rfs_block_map_close (fs, &map);
      return rc;
    }

    entry  = rtems_rfs_buffer_data (&buffer);
    entry += map.bpos.boff;
    
    elength = rtems_rfs_dir_entry_length (entry);
    eino    = rtems_rfs_dir_entry_ino (entry);

    if (elength != RTEMS_RFS_DIR_ENTRY_EMPTY)
    {
      if (rtems_rfs_dir_entry_valid (fs, elength, eino))
      {
        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
          printf ("rtems-rfs: dir-read: "
                  "bad length or ino for ino %" PRIu32 ": %u/%" PRId32 " @ %04" PRIx32 "\n",
                  rtems_rfs_inode_ino (dir), elength, eino, map.bpos.boff);
        rc = EIO;
        break;
      }
        
      memset (dirent, 0, sizeof (struct dirent));
      dirent->d_off = offset;
      dirent->d_reclen = sizeof (struct dirent);

      *length += elength;

      remaining = rtems_rfs_fs_block_size (fs) - (map.bpos.boff + elength);
      
      if (remaining <= RTEMS_RFS_DIR_ENTRY_SIZE)
        *length += remaining;
      
      elength -= RTEMS_RFS_DIR_ENTRY_SIZE;
      if (elength > NAME_MAX)
        elength = NAME_MAX;
      
      memcpy (dirent->d_name, entry + RTEMS_RFS_DIR_ENTRY_SIZE, elength);

      dirent->d_ino = rtems_rfs_dir_entry_ino (entry);
      dirent->d_namlen = elength;
      
      if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
        printf ("rtems-rfs: dir-read: found off:%" PRIdoff_t " ino:%ld name=%s\n",
                dirent->d_off, dirent->d_ino, dirent->d_name);
      break;
    }

    *length += rtems_rfs_fs_block_size (fs) - map.bpos.boff;
    
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
      printf ("rtems-rfs: dir-read: next block: off:%" PRId64 " length:%zd\n",
              offset, *length);
      
    rc = rtems_rfs_block_map_next_block (fs, &map, &block);
    if (rc == ENXIO)
      rc = ENOENT;
  }

  rtems_rfs_buffer_handle_close (fs, &buffer);
  rtems_rfs_block_map_close (fs, &map);
  return rc;
}
Exemple #8
0
int
rtems_rfs_dir_del_entry (rtems_rfs_file_system*  fs,
                         rtems_rfs_inode_handle* dir,
                         rtems_rfs_ino           ino,
                         uint32_t                offset)
{  
  rtems_rfs_block_map     map;
  rtems_rfs_block_no      block;
  rtems_rfs_buffer_handle buffer;
  bool                    search;
  int                     rc;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
    printf ("rtems-rfs: dir-del-entry: dir=%" PRId32 ", entry=%" PRId32 " offset=%" PRIu32 "\n",
            rtems_rfs_inode_ino (dir), ino, offset);

  rc = rtems_rfs_block_map_open (fs, dir, &map);
  if (rc > 0)
    return rc;

  rc = rtems_rfs_block_map_seek (fs, &map, offset, &block);
  if (rc > 0)
  {
    if (rc == ENXIO)
      rc = ENOENT;
    rtems_rfs_block_map_close (fs, &map);
    return rc;
  }

  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
  if (rc > 0)
  {
    rtems_rfs_block_map_close (fs, &map);
    return rc;
  }

  /*
   * Only search if the offset is 0 else we are at that position.
   */
  search = offset ? false : true;

  while (rc == 0)
  {
    uint8_t* entry;
    int      eoffset;
    
    rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
    if (rc > 0)
    {
      if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
        printf ("rtems-rfs: dir-del-entry: "
                "block buffer req failed for ino %" PRIu32 ": %d: %s\n",
                rtems_rfs_inode_ino (dir), rc, strerror (rc));
      break;
    }

    /*
     * If we are searching start at the beginning of the block. If not searching
     * skip to the offset in the block.
     */
    if (search)
      eoffset = 0;
    else
      eoffset = offset % rtems_rfs_fs_block_size (fs);
    
    entry = rtems_rfs_buffer_data (&buffer) + eoffset;
    
    while (eoffset < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE))
    {
      rtems_rfs_ino eino;
      int           elength;

      elength = rtems_rfs_dir_entry_length (entry);
      eino    = rtems_rfs_dir_entry_ino (entry);

      if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
        break;
      
      if (rtems_rfs_dir_entry_valid (fs, elength, eino))
      {
        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
          printf ("rtems-rfs: dir-del-entry: "
                  "bad length or ino for ino %" PRIu32 ": %u/%" PRId32
                  " @ %" PRIu32 ".%04x\n",
                  rtems_rfs_inode_ino (dir), elength, eino, block, eoffset);
        rc = EIO;
        break;
      }

      if (ino == rtems_rfs_dir_entry_ino (entry))
      {
        uint32_t remaining;
        remaining = rtems_rfs_fs_block_size (fs) - (eoffset + elength);
        memmove (entry, entry + elength, remaining);
        memset (entry + remaining, 0xff, elength);

        /*
         * If the remainder of the block is empty and this is the start of the
         * block and it is the last block in the map shrink the map.
         *
         * @note We could check again to see if the new end block in the map is
         *       also empty. This way we could clean up an empty directory.
         */
        elength = rtems_rfs_dir_entry_length (entry);

        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
          printf ("rtems-rfs: dir-del-entry: "
                  "last block free for ino %" PRIu32 ": elength=%i block=%" PRIu32
                  " offset=%d last=%s\n",
                  ino, elength, block, eoffset,
                  rtems_rfs_block_map_last (&map) ? "yes" : "no");

        if ((elength == RTEMS_RFS_DIR_ENTRY_EMPTY) &&
            (eoffset == 0) && rtems_rfs_block_map_last (&map))
        {
          rc = rtems_rfs_block_map_shrink (fs, &map, 1);
          if (rc > 0)
          {
            if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
              printf ("rtems-rfs: dir-del-entry: "
                      "block map shrink failed for ino %" PRIu32 ": %d: %s\n",
                      rtems_rfs_inode_ino (dir), rc, strerror (rc));
          }
        }
        
        rtems_rfs_buffer_mark_dirty (&buffer);
        rtems_rfs_buffer_handle_close (fs, &buffer);
        rtems_rfs_block_map_close (fs, &map);
        return 0;
      }

      if (!search)
      {
        rc = EIO;
        break;
      }
      
      entry   += elength;
      eoffset += elength;
    }

    if (rc == 0)
    {
      rc = rtems_rfs_block_map_next_block (fs, &map, &block);
      if (rc == ENXIO)
        rc = ENOENT;
    }
  }
  
  rtems_rfs_buffer_handle_close (fs, &buffer);
  rtems_rfs_block_map_close (fs, &map);
  return rc;
}
Exemple #9
0
int
rtems_rfs_dir_add_entry (rtems_rfs_file_system*  fs,
                         rtems_rfs_inode_handle* dir,
                         const char*             name,
                         size_t                  length,
                         rtems_rfs_ino           ino)
{
  rtems_rfs_block_map     map;
  rtems_rfs_block_pos     bpos;
  rtems_rfs_buffer_handle buffer;
  int                     rc;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
  {
    int c;
    printf ("rtems-rfs: dir-add-entry: dir=%" PRId32 ", name=",
            rtems_rfs_inode_ino (dir));
    for (c = 0; c < length; c++)
      printf ("%c", name[c]);
    printf (", len=%zd\n", length);
  }
        
  rc = rtems_rfs_block_map_open (fs, dir, &map);
  if (rc > 0)
    return rc;

  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
  if (rc > 0)
  {
    rtems_rfs_block_map_close (fs, &map);
    return rc;
  }
  
  /*
   * Search the map from the beginning to find any empty space.
   */
  rtems_rfs_block_set_bpos_zero (&bpos);
  
  while (true)
  {
    rtems_rfs_block_no block;
    uint8_t*           entry;
    int                offset;
    bool               read = true;
    
    /*
     * Locate the first block. If an error the block will be 0. If the map is
     * empty which happens when creating a directory and adding the first entry
     * the seek will return ENXIO. In this case we need to grow the directory.
     */
    rc = rtems_rfs_block_map_find (fs, &map, &bpos, &block);
    if (rc > 0)
    {
      if (rc != ENXIO)
      {
        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
          printf ("rtems-rfs: dir-add-entry: "
                  "block map find failed for ino %" PRIu32 ": %d: %s\n",
                  rtems_rfs_inode_ino (dir), rc, strerror (rc));
        break;
      }

      /*
       * We have reached the end of the directory so add a block.
       */
      rc = rtems_rfs_block_map_grow (fs, &map, 1, &block);
      if (rc > 0)
      {
        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
          printf ("rtems-rfs: dir-add-entry: "
                  "block map grow failed for ino %" PRIu32 ": %d: %s\n",
                  rtems_rfs_inode_ino (dir), rc, strerror (rc));
        break;
      }

      read = false;
    }

    bpos.bno++;
    
    rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, read);
    if (rc > 0)
    {
      if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
        printf ("rtems-rfs: dir-add-entry: "
                "block buffer req failed for ino %" PRIu32 ": %d: %s\n",
                rtems_rfs_inode_ino (dir), rc, strerror (rc));
      break;
    }
    
    entry  = rtems_rfs_buffer_data (&buffer);
    
    if (!read)
      memset (entry, 0xff, rtems_rfs_fs_block_size (fs));

    offset = 0;
    
    while (offset < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE))
    {
      rtems_rfs_ino eino;
      int           elength;

      elength = rtems_rfs_dir_entry_length (entry);
      eino    = rtems_rfs_dir_entry_ino (entry);

      if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
      {
        if ((length + RTEMS_RFS_DIR_ENTRY_SIZE) <
            (rtems_rfs_fs_block_size (fs) - offset))
        {
          uint32_t hash;
          hash = rtems_rfs_dir_hash (name, length);
          rtems_rfs_dir_set_entry_hash (entry, hash);
          rtems_rfs_dir_set_entry_ino (entry, ino);
          rtems_rfs_dir_set_entry_length (entry,
                                          RTEMS_RFS_DIR_ENTRY_SIZE + length);
          memcpy (entry + RTEMS_RFS_DIR_ENTRY_SIZE, name, length);
          rtems_rfs_buffer_mark_dirty (&buffer);
          rtems_rfs_buffer_handle_close (fs, &buffer);
          rtems_rfs_block_map_close (fs, &map);
          return 0;
        }

        break;
      }
      
      if (rtems_rfs_dir_entry_valid (fs, elength, eino))
      {
        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
          printf ("rtems-rfs: dir-add-entry: "
                  "bad length or ino for ino %" PRIu32 ": %u/%" PRId32 " @ %04x\n",
                  rtems_rfs_inode_ino (dir), elength, eino, offset);
        rtems_rfs_buffer_handle_close (fs, &buffer);
        rtems_rfs_block_map_close (fs, &map);
        return EIO;
      }
        
      entry  += elength;
      offset += elength;
    }
  }
  
  rtems_rfs_buffer_handle_close (fs, &buffer);
  rtems_rfs_block_map_close (fs, &map);
  return rc;
}
int
rtems_rfs_file_set_size (rtems_rfs_file_handle* handle,
                         rtems_rfs_pos          new_size)
{
  rtems_rfs_block_map* map  = rtems_rfs_file_map (handle);
  rtems_rfs_pos        size;
  int                  rc;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
    printf ("rtems-rfs: file-set-size: size=%" PRIu64 "\n", new_size);

  size = rtems_rfs_file_size (handle);
  
  /*
   * If the file is same size do nothing else grow or shrink it ?
   *
   * If the file does not change size do not update the times.
   */
  if (size != new_size)
  {
    /*
     * Short cut for the common truncate on open call.
     */
    if (new_size == 0)
    {
      rc = rtems_rfs_block_map_free_all (rtems_rfs_file_fs (handle), map);
      if (rc > 0)
        return rc;
    }
    else
    {
      if (size < new_size)
      {
        /*
         * Grow. Fill with 0's.
         */
        rtems_rfs_pos count;
        uint32_t      length;
        bool          read_block;

        count = new_size - size;
        length = rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
        read_block = false;
        
        while (count)
        {
          rtems_rfs_buffer_block block;
          rtems_rfs_block_pos    bpos;
          uint8_t*               dst;

          /*
           * Get the block position for the current end of the file as seen by
           * the map. If not found and the EOF grow the map then fill the block
           * with 0.
           */
          rtems_rfs_block_size_get_bpos (rtems_rfs_block_map_size (map), &bpos);
          rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
                                         map, &bpos, &block);
          if (rc > 0)
          {
            /*
             * Have we reached the EOF ?
             */
            if (rc != ENXIO)
              return rc;

            rc = rtems_rfs_block_map_grow (rtems_rfs_file_fs (handle),
                                           map, 1, &block);
            if (rc > 0)
              return rc;
          }

          if (count < (length - bpos.boff))
          {
            length = count + bpos.boff;
            read_block = true;
            rtems_rfs_block_map_set_size_offset (map, length);
          }
          else
          {
            rtems_rfs_block_map_set_size_offset (map, 0);
          }

          /*
           * Only read the block if the length is not the block size.
           */
          rc = rtems_rfs_buffer_handle_request (rtems_rfs_file_fs (handle),
                                                rtems_rfs_file_buffer (handle),
                                                block, read_block);
          if (rc > 0)
            return rc;

          dst = rtems_rfs_buffer_data (&handle->buffer);
          memset (dst + bpos.boff, 0, length - bpos.boff);

          rtems_rfs_buffer_mark_dirty (rtems_rfs_file_buffer (handle));

          rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
                                                rtems_rfs_file_buffer (handle));
          if (rc > 0)
            return rc;
        
          count -= length - bpos.boff;
        }
      }
      else
      {
        /*
         * Shrink
         */
        rtems_rfs_block_no blocks;
        uint32_t           offset;
    
        blocks =
          rtems_rfs_block_map_count (map) -
          (((new_size - 1) /
            rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle))) + 1);

        offset =
          new_size % rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
      
        if (blocks)
        {
          int rc;
          rc = rtems_rfs_block_map_shrink (rtems_rfs_file_fs (handle),
                                           rtems_rfs_file_map (handle),
                                           blocks);
          if (rc > 0)
            return rc;
        }

        rtems_rfs_block_map_set_size_offset (map, offset);

        if (rtems_rfs_block_pos_past_end (rtems_rfs_file_bpos (handle),
                                          rtems_rfs_block_map_size (map)))
          rtems_rfs_block_size_get_bpos (rtems_rfs_block_map_size (map),
                                         rtems_rfs_file_bpos (handle));
      }
    }

    handle->shared->size.count  = rtems_rfs_block_map_count (map);
    handle->shared->size.offset = rtems_rfs_block_map_size_offset (map);

    if (rtems_rfs_file_update_mtime (handle))
      handle->shared->mtime = time (NULL);
  }
  
  return 0;
}
Exemple #11
0
static int
rtems_rfs_shell_block (rtems_rfs_file_system* fs, int argc, char *argv[])
{
  rtems_rfs_buffer_handle buffer;
  rtems_rfs_block_no      block;
  uint8_t*                data;
  bool                    state;
  int                     b;
  int                     rc;
  
  if (argc <= 1)
  {
    printf ("error: no block number provided\n");
    return 1;
  }

  block = strtoul (argv[1], 0, 0);

  rtems_rfs_shell_lock_rfs (fs);
  
  rc = rtems_rfs_group_bitmap_test (fs, false, block, &state);
  if (rc > 0)
  {
    rtems_rfs_shell_unlock_rfs (fs);
    printf ("error: testing block state: block=%" PRIu32 ": (%d) %s\n",
            block, rc, strerror (rc));
    return 1;
  }

  printf (" %5" PRIu32 ": block %s\n", block, state ? "allocated" : "free");
    
  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
  if (rc > 0)
  {
    rtems_rfs_shell_unlock_rfs (fs);
    printf ("error: opening buffer handle: block=%" PRIu32 ": (%d) %s\n",
            block, rc, strerror (rc));
    return 1;
  }

  rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &buffer);
    rtems_rfs_shell_unlock_rfs (fs);
    printf ("error: requesting buffer handle: block=%" PRIu32 ": (%d) %s\n",
            block, rc, strerror (rc));
    return 1;
  }

  for (b = 0, data = rtems_rfs_buffer_data (&buffer);
       b < rtems_rfs_fs_block_size (fs);
       b++, data++)
  {
    int mod = b % 16;
    if (mod == 0)
    {
      if (b)
        printf ("\n");
      printf ("%04x ", b);
    }
    if (mod == 8)
      printf (" ");
    printf ("%02x ", *data);
  }

  printf ("\n");
  
  rc = rtems_rfs_buffer_handle_close (fs, &buffer);
  if (rc > 0)
  {
    rtems_rfs_shell_unlock_rfs (fs);
    printf ("error: closing buffer handle: block=%" PRIu32 ": (%d) %s\n",
            block, rc, strerror (rc));
    return 1;
  }
  
  rtems_rfs_shell_unlock_rfs (fs);
  
  return 0;
}
Exemple #12
0
static bool
rtems_rfs_write_superblock (rtems_rfs_file_system* fs)
{
  rtems_rfs_buffer_handle handle;
  uint8_t*                sb;
  int                     rc;

  rc = rtems_rfs_buffer_handle_open (fs, &handle);
  if (rc > 0)
  {
    printf ("rtems-rfs: write-superblock: handle open failed: %d: %s\n",
            rc, strerror (rc));
    return false;
  }

  rc = rtems_rfs_buffer_handle_request (fs, &handle, 0, false);
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    printf ("rtems-rfs: write-superblock: request failed: %d: %s\n",
            rc, strerror (rc));
    return false;
  }

  sb = rtems_rfs_buffer_data (&handle);
  
#define write_sb(_o, _d) rtems_rfs_write_u32(sb + (_o), _d)
  
  memset (sb, 0xff, rtems_rfs_fs_block_size (fs));

  write_sb (RTEMS_RFS_SB_OFFSET_MAGIC, RTEMS_RFS_SB_MAGIC);
  write_sb (RTEMS_RFS_SB_OFFSET_VERSION, RTEMS_RFS_VERSION);
  write_sb (RTEMS_RFS_SB_OFFSET_BLOCKS, rtems_rfs_fs_blocks (fs));
  write_sb (RTEMS_RFS_SB_OFFSET_BLOCK_SIZE, rtems_rfs_fs_block_size (fs));
  write_sb (RTEMS_RFS_SB_OFFSET_BAD_BLOCKS, fs->bad_blocks);
  write_sb (RTEMS_RFS_SB_OFFSET_MAX_NAME_LENGTH, fs->max_name_length);
  write_sb (RTEMS_RFS_SB_OFFSET_GROUPS, fs->group_count);
  write_sb (RTEMS_RFS_SB_OFFSET_GROUP_BLOCKS, fs->group_blocks);
  write_sb (RTEMS_RFS_SB_OFFSET_GROUP_INODES, fs->group_inodes);
  write_sb (RTEMS_RFS_SB_OFFSET_INODE_SIZE, RTEMS_RFS_INODE_SIZE);

  rtems_rfs_buffer_mark_dirty (&handle);

  rc = rtems_rfs_buffer_handle_release (fs, &handle);
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    printf ("rtems-rfs: write-superblock: buffer release failed: %d: %s\n",
            rc, strerror (rc));
    return false;
  }

  rc = rtems_rfs_buffer_handle_close (fs, &handle);
  if (rc > 0)
  {
    printf ("rtems-rfs: write-superblock: buffer handle close failed: %d: %s\n",
            rc, strerror (rc));
    return false;
  }
  
  return true;
}
Exemple #13
0
int
rtems_rfs_symlink_read (rtems_rfs_file_system* fs,
                        rtems_rfs_ino          link,
                        char*                  path,
                        size_t                 size,
                        size_t*                length)
{
  rtems_rfs_inode_handle inode;
  int                    rc;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_SYMLINK_READ))
    printf ("rtems-rfs: symlink-read: link:%" PRIu32 "\n", link);

  rc = rtems_rfs_inode_open (fs, link, &inode, true);
  if (rc)
    return rc;

  if (!RTEMS_RFS_S_ISLNK (rtems_rfs_inode_get_mode (&inode)))
  {
    rtems_rfs_inode_close (fs, &inode);
    return EINVAL;
  }

  *length = rtems_rfs_inode_get_block_offset (&inode);

  if (size < *length)
  {
    *length = size;
  }

  if (rtems_rfs_inode_get_block_count (&inode) == 0)
  {
    memcpy (path, inode.node->data.name, *length);
  }
  else
  {
    rtems_rfs_block_map     map;
    rtems_rfs_block_no      block;
    rtems_rfs_buffer_handle buffer;
    char*                   data;

    rc = rtems_rfs_block_map_open (fs, &inode, &map);
    if (rc > 0)
    {
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }

    rc = rtems_rfs_block_map_seek (fs, &map, 0, &block);
    if (rc > 0)
    {
      rtems_rfs_block_map_close (fs, &map);
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }

    rc = rtems_rfs_buffer_handle_open (fs, &buffer);
    if (rc > 0)
    {
      rtems_rfs_block_map_close (fs, &map);
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }

    rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, false);
    if (rc > 0)
    {
      rtems_rfs_block_map_close (fs, &map);
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }

    data = rtems_rfs_buffer_data (&buffer);
    memcpy (path, data, *length);

    rc = rtems_rfs_buffer_handle_close (fs, &buffer);
    if (rc > 0)
    {
      rtems_rfs_block_map_close (fs, &map);
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }

    rc = rtems_rfs_block_map_close (fs, &map);
    if (rc > 0)
    {
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }
  }

  rc = rtems_rfs_inode_close (fs, &inode);

  return rc;
}
Exemple #14
0
int
rtems_rfs_symlink (rtems_rfs_file_system* fs,
                   const char*            name,
                   int                    length,
                   const char*            link,
                   int                    link_length,
                   uid_t                  uid,
                   gid_t                  gid,
                   rtems_rfs_ino          parent)
{
  rtems_rfs_inode_handle inode;
  rtems_rfs_ino          ino;
  int                    rc;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_SYMLINK))
  {
    int c;
    printf ("rtems-rfs: symlink: parent:%" PRIu32 " name:", parent);
    for (c = 0; c < length; c++)
      printf ("%c", name[c]);
    printf (" link:");
    for (c = 0; c < link_length; c++)
      printf ("%c", link[c]);
  }

  if (link_length >= rtems_rfs_fs_block_size (fs))
    return ENAMETOOLONG;

  rc = rtems_rfs_inode_create (fs, parent, name, strlen (name),
                               RTEMS_RFS_S_SYMLINK,
                               1, uid, gid, &ino);
  if (rc > 0)
    return rc;

  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
  if (rc > 0)
    return rc;

  /*
   * If the link length is less than the length of data union in the inode
   * place the link into the data area else allocate a block and write the link
   * to that.
   */
  if (link_length < RTEMS_RFS_INODE_DATA_NAME_SIZE)
  {
    memset (inode.node->data.name, 0, RTEMS_RFS_INODE_DATA_NAME_SIZE);
    memcpy (inode.node->data.name, link, link_length);
    rtems_rfs_inode_set_block_count (&inode, 0);
  }
  else
  {
    rtems_rfs_block_map     map;
    rtems_rfs_block_no      block;
    rtems_rfs_buffer_handle buffer;
    uint8_t*                data;

    rc = rtems_rfs_block_map_open (fs, &inode, &map);
    if (rc > 0)
    {
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }

    rc = rtems_rfs_block_map_grow (fs, &map, 1, &block);
    if (rc > 0)
    {
      rtems_rfs_block_map_close (fs, &map);
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }

    rc = rtems_rfs_buffer_handle_open (fs, &buffer);
    if (rc > 0)
    {
      rtems_rfs_block_map_close (fs, &map);
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }

    rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, false);
    if (rc > 0)
    {
      rtems_rfs_block_map_close (fs, &map);
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }

    data = rtems_rfs_buffer_data (&buffer);

    memset (data, 0xff, rtems_rfs_fs_block_size (fs));
    memcpy (data, link, link_length);

    rc = rtems_rfs_buffer_handle_close (fs, &buffer);
    if (rc > 0)
    {
      rtems_rfs_block_map_close (fs, &map);
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }

    rc = rtems_rfs_block_map_close (fs, &map);
    if (rc > 0)
    {
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }
  }

  rtems_rfs_inode_set_block_offset (&inode, link_length);

  rc = rtems_rfs_inode_close (fs, &inode);

  return rc;
}
int
rtems_rfs_block_map_shrink (rtems_rfs_file_system* fs,
                            rtems_rfs_block_map*   map,
                            size_t                 blocks)
{
  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BLOCK_MAP_SHRINK))
    printf ("rtems-rfs: block-map-shrink: entry: blocks=%zd count=%" PRIu32 "\n",
            blocks, map->size.count);

  if (map->size.count == 0)
    return 0;

  if (blocks > map->size.count)
    blocks = map->size.count;

  while (blocks)
  {
    rtems_rfs_block_no block;
    rtems_rfs_block_no block_to_free;
    int                rc;

    block = map->size.count - 1;

    if (block < RTEMS_RFS_INODE_BLOCKS)
    {
      /*
       * We have less than RTEMS_RFS_INODE_BLOCKS so they are held in the
       * inode.
       */
      block_to_free = map->blocks[block];
      map->blocks[block] = 0;
    }
    else
    {
      /*
       * Single indirect access is occuring. It could still be doubly indirect.
       *
       * The 'direct' variable is the offset in to the indirect table of
       * blocks, and 'singly' is the inode block index of the singly indirect
       * table of block numbers.
       */
      rtems_rfs_block_no direct;
      rtems_rfs_block_no singly;

      direct = block % fs->blocks_per_block;
      singly = block / fs->blocks_per_block;

      if (block < fs->block_map_singly_blocks)
      {
        /*
         * Request the indirect block and then obtain the block number from the
         * indirect block.
         */
        rc = rtems_rfs_buffer_handle_request (fs, &map->singly_buffer,
                                              map->blocks[singly], true);
        if (rc > 0)
          return rc;

        block_to_free = rtems_rfs_block_get_number (&map->singly_buffer,
                                                    direct);

        rc = rtems_rfs_block_map_indirect_shrink (fs, map, &map->singly_buffer,
                                                  singly, direct);
        if (rc)
          return rc;
      }
      else if (block < fs->block_map_doubly_blocks)
      {
        /*
         * Doubly indirect tables are being used. The 'doubly' variable is the
         * index in to the inode's block table and points to a singly indirect
         * table of block numbers. The 'doubly_singly' variable is the index
         * into the doubly indirect table pointing to the singly indirect table
         * of block numbers that form the map. This is used later to determine
         * if the current doubly indirect table needs to be freed. The 'direct'
         * value is still valid for doubly indirect tables.
         */
        rtems_rfs_block_no doubly;
        rtems_rfs_block_no doubly_singly;

        doubly        = singly / fs->blocks_per_block;
        doubly_singly = singly % fs->blocks_per_block;

        rc = rtems_rfs_buffer_handle_request (fs, &map->doubly_buffer,
                                              map->blocks[doubly], true);
        if (rc > 0)
          return rc;

        singly = rtems_rfs_block_get_number (&map->doubly_buffer,
                                             doubly_singly);

        /*
         * Read the singly indirect table and get the block number.
         */
        rc = rtems_rfs_buffer_handle_request (fs, &map->singly_buffer,
                                              singly, true);
        if (rc > 0)
          return rc;

        block_to_free = rtems_rfs_block_get_number (&map->singly_buffer,
                                                    direct);

        if (direct == 0)
        {
          rc = rtems_rfs_group_bitmap_free (fs, false, singly);
          if (rc > 0)
            return rc;

          map->last_map_block = singly;

          rc = rtems_rfs_block_map_indirect_shrink (fs, map, &map->doubly_buffer,
                                                    doubly, doubly_singly);
          if (rc)
            return rc;
        }
      }
      else
      {
        rc = EIO;
        break;
      }
    }
    rc = rtems_rfs_group_bitmap_free (fs, false, block_to_free);
    if (rc > 0)
      return rc;
    map->size.count--;
    map->size.offset = 0;
    map->last_data_block = block_to_free;
    map->dirty = true;
    blocks--;
  }

  if (map->size.count == 0)
  {
    map->last_map_block = 0;
    map->last_data_block = 0;
  }

  /*
   * Keep the position inside the map.
   */
  if (rtems_rfs_block_pos_past_end (&map->bpos, &map->size))
    rtems_rfs_block_size_get_bpos (&map->size, &map->bpos);

  return 0;
}
int
rtems_rfs_block_map_grow (rtems_rfs_file_system* fs,
                          rtems_rfs_block_map*   map,
                          size_t                 blocks,
                          rtems_rfs_block_no*    new_block)
{
  int b;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BLOCK_MAP_GROW))
    printf ("rtems-rfs: block-map-grow: entry: blocks=%zd count=%" PRIu32 "\n",
            blocks, map->size.count);

  if ((map->size.count + blocks) >= rtems_rfs_fs_max_block_map_blocks (fs))
    return EFBIG;

  /*
   * Allocate a block at a time. The buffer handles hold the blocks so adding
   * this way does not thrash the cache with lots of requests.
   */
  for (b = 0; b < blocks; b++)
  {
    rtems_rfs_bitmap_bit block;
    int                  rc;

    /*
     * Allocate the block. If an indirect block is needed and cannot be
     * allocated free this block.
     */

    rc = rtems_rfs_group_bitmap_alloc (fs, map->last_data_block,
                                       false, &block);
    if (rc > 0)
      return rc;

    if (map->size.count < RTEMS_RFS_INODE_BLOCKS)
      map->blocks[map->size.count] = block;
    else
    {
      /*
       * Single indirect access is occuring. It could still be doubly indirect.
       */
      rtems_rfs_block_no direct;
      rtems_rfs_block_no singly;

      direct = map->size.count % fs->blocks_per_block;
      singly = map->size.count / fs->blocks_per_block;

      if (map->size.count < fs->block_map_singly_blocks)
      {
        /*
         * Singly indirect tables are being used. Allocate a new block for a
         * mapping table if direct is 0 or we are moving up (upping). If upping
         * move the direct blocks into the table and if not this is the first
         * entry of a new block.
         */
        if ((direct == 0) ||
            ((singly == 0) && (direct == RTEMS_RFS_INODE_BLOCKS)))
        {
          /*
           * Upping is when we move from direct to singly indirect.
           */
          bool upping;
          upping = map->size.count == RTEMS_RFS_INODE_BLOCKS;
          rc = rtems_rfs_block_map_indirect_alloc (fs, map,
                                                   &map->singly_buffer,
                                                   &map->blocks[singly],
                                                   upping);
        }
        else
        {
          rc = rtems_rfs_buffer_handle_request (fs,  &map->singly_buffer,
                                                map->blocks[singly], true);
        }

        if (rc > 0)
        {
          rtems_rfs_group_bitmap_free (fs, false, block);
          return rc;
        }
      }
      else
      {
        /*
         * Doubly indirect tables are being used.
         */
        rtems_rfs_block_no doubly;
        rtems_rfs_block_no singly_block;

        doubly  = singly / fs->blocks_per_block;
        singly %= fs->blocks_per_block;

        /*
         * Allocate a new block for a singly indirect table if direct is 0 as
         * it is the first entry of a new block. We may also need to allocate a
         * doubly indirect block as well. Both always occur when direct is 0
         * and the doubly indirect block when singly is 0.
         */
        if (direct == 0)
        {
          rc = rtems_rfs_block_map_indirect_alloc (fs, map,
                                                   &map->singly_buffer,
                                                   &singly_block,
                                                   false);
          if (rc > 0)
          {
            rtems_rfs_group_bitmap_free (fs, false, block);
            return rc;
          }

          /*
           * Allocate a new block for a doubly indirect table if singly is 0 as
           * it is the first entry of a new singly indirect block.
           */
          if ((singly == 0) ||
              ((doubly == 0) && (singly == RTEMS_RFS_INODE_BLOCKS)))
          {
            bool upping;
            upping = map->size.count == fs->block_map_singly_blocks;
            rc = rtems_rfs_block_map_indirect_alloc (fs, map,
                                                     &map->doubly_buffer,
                                                     &map->blocks[doubly],
                                                     upping);
            if (rc > 0)
            {
              rtems_rfs_group_bitmap_free (fs, false, singly_block);
              rtems_rfs_group_bitmap_free (fs, false, block);
              return rc;
            }
          }
          else
          {
            rc = rtems_rfs_buffer_handle_request (fs, &map->doubly_buffer,
                                                  map->blocks[doubly], true);
            if (rc > 0)
            {
              rtems_rfs_group_bitmap_free (fs, false, singly_block);
              rtems_rfs_group_bitmap_free (fs, false, block);
              return rc;
            }
          }

          rtems_rfs_block_set_number (&map->doubly_buffer,
                                      singly,
                                      singly_block);
        }
        else
        {
          rc = rtems_rfs_buffer_handle_request (fs,
                                                &map->doubly_buffer,
                                                map->blocks[doubly],
                                                true);
          if (rc > 0)
          {
            rtems_rfs_group_bitmap_free (fs, false, block);
            return rc;
          }

          singly_block = rtems_rfs_block_get_number (&map->doubly_buffer,
                                                     singly);

          rc = rtems_rfs_buffer_handle_request (fs, &map->singly_buffer,
                                                singly_block, true);
          if (rc > 0)
          {
            rtems_rfs_group_bitmap_free (fs, false, block);
            return rc;
          }
        }
      }

      rtems_rfs_block_set_number (&map->singly_buffer, direct, block);
    }

    map->size.count++;
    map->size.offset = 0;

    if (b == 0)
      *new_block = block;
    map->last_data_block = block;
    map->dirty = true;
  }

  return 0;
}
static int
rtems_rfs_fs_read_superblock (rtems_rfs_file_system* fs)
{
  rtems_rfs_buffer_handle handle;
  uint8_t*                sb;
  int                     group;
  int                     rc;

  rc = rtems_rfs_buffer_handle_open (fs, &handle);
  if (rc > 0)
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: handle open failed: %d: %s\n",
              rc, strerror (rc));
    return rc;
  }

  rc = rtems_rfs_buffer_handle_request (fs, &handle, 0, true);
  if (rc > 0)
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: request failed%d: %s\n",
              rc, strerror (rc));
    return rc;
  }

  sb = rtems_rfs_buffer_data (&handle);

#define read_sb(_o) rtems_rfs_read_u32 (sb + (_o))

  if (read_sb (RTEMS_RFS_SB_OFFSET_MAGIC) != RTEMS_RFS_SB_MAGIC)
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: invalid superblock, bad magic\n");
    rtems_rfs_buffer_handle_close (fs, &handle);
    return EIO;
  }

  fs->blocks     = read_sb (RTEMS_RFS_SB_OFFSET_BLOCKS);
  fs->block_size = read_sb (RTEMS_RFS_SB_OFFSET_BLOCK_SIZE);

  if (rtems_rfs_fs_size(fs) > rtems_rfs_fs_media_size (fs))
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: invalid superblock block/size count\n");
    rtems_rfs_buffer_handle_close (fs, &handle);
    return EIO;
  }

  if ((read_sb (RTEMS_RFS_SB_OFFSET_VERSION) & RTEMS_RFS_VERSION_MASK) !=
      (RTEMS_RFS_VERSION * RTEMS_RFS_VERSION_MASK))
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: incompatible version: %08" PRIx32 " (%08" PRIx32 ")\n",
              read_sb (RTEMS_RFS_SB_OFFSET_VERSION), RTEMS_RFS_VERSION_MASK);
    rtems_rfs_buffer_handle_close (fs, &handle);
    return EIO;
  }

  if (read_sb (RTEMS_RFS_SB_OFFSET_INODE_SIZE) != RTEMS_RFS_INODE_SIZE)
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: inode size mismatch: fs:%" PRId32 " target:%" PRId32 "\n",
              read_sb (RTEMS_RFS_SB_OFFSET_VERSION), RTEMS_RFS_VERSION_MASK);
    rtems_rfs_buffer_handle_close (fs, &handle);
    return EIO;
  }

  fs->bad_blocks      = read_sb (RTEMS_RFS_SB_OFFSET_BAD_BLOCKS);
  fs->max_name_length = read_sb (RTEMS_RFS_SB_OFFSET_MAX_NAME_LENGTH);
  fs->group_count     = read_sb (RTEMS_RFS_SB_OFFSET_GROUPS);
  fs->group_blocks    = read_sb (RTEMS_RFS_SB_OFFSET_GROUP_BLOCKS);
  fs->group_inodes    = read_sb (RTEMS_RFS_SB_OFFSET_GROUP_INODES);

  fs->blocks_per_block =
    rtems_rfs_fs_block_size (fs) / sizeof (rtems_rfs_inode_block);

  fs->block_map_singly_blocks =
    fs->blocks_per_block * RTEMS_RFS_INODE_BLOCKS;
  fs->block_map_doubly_blocks =
    fs->blocks_per_block * fs->blocks_per_block * RTEMS_RFS_INODE_BLOCKS;

  fs->inodes = fs->group_count * fs->group_inodes;

  fs->inodes_per_block = fs->block_size / RTEMS_RFS_INODE_SIZE;

  if (fs->group_blocks >
      rtems_rfs_bitmap_numof_bits (rtems_rfs_fs_block_size (fs)))
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: groups blocks larger than block bits\n");
    return EIO;
  }

  rtems_rfs_buffer_handle_close (fs, &handle);

  /*
   * Change the block size to the value in the superblock.
   */
  rc = rtems_rfs_buffer_setblksize (fs, rtems_rfs_fs_block_size (fs));
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: invalid superblock block size%d: %s\n",
              rc, strerror (rc));
    return rc;
  }

  fs->groups = calloc (fs->group_count, sizeof (rtems_rfs_group));

  if (!fs->groups)
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: no memory for group table\n");
    return ENOMEM;
  }

  /*
   * Perform each phase of group initialisation at the same time. This way we
   * know how far the initialisation has gone if an error occurs and we need to
   * close everything.
   */
  for (group = 0; group < fs->group_count; group++)
  {
    rc = rtems_rfs_group_open (fs,
                               rtems_rfs_fs_block (fs, group, 0),
                               fs->group_blocks,
                               fs->group_inodes,
                               &fs->groups[group]);
    if (rc > 0)
    {
      int g;
      for (g = 0; g < group; g++)
        rtems_rfs_group_close (fs, &fs->groups[g]);
      rtems_rfs_buffer_handle_close (fs, &handle);
      if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
        printf ("rtems-rfs: read-superblock: no memory for group table%d: %s\n",
                rc, strerror (rc));
      return rc;
    }
  }

  return 0;
}
int
rtems_rfs_file_io_start (rtems_rfs_file_handle* handle,
                         size_t*                available,
                         bool                   read)
{
  size_t size;
  
  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
    printf ("rtems-rfs: file-io: start: %s pos=%" PRIu32 ":%" PRIu32 "\n",
            read ? "read" : "write",  handle->bpos.bno, handle->bpos.boff);
  
  if (!rtems_rfs_buffer_handle_has_block (&handle->buffer))
  {
    rtems_rfs_buffer_block block;
    bool                   request_read;
    int                    rc;
     
    request_read = read;
    
    rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
                                   rtems_rfs_file_map (handle),
                                   rtems_rfs_file_bpos (handle),
                                   &block);
    if (rc > 0)
    {
      /*
       * Has the read reached the EOF ?
       */
      if (read && (rc == ENXIO))
      {
        *available = 0;
        return 0;
      }
      
      if (rc != ENXIO)
        return rc;

      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
        printf ("rtems-rfs: file-io: start: grow\n");
      
      rc = rtems_rfs_block_map_grow (rtems_rfs_file_fs (handle),
                                     rtems_rfs_file_map (handle),
                                     1, &block);
      if (rc > 0)
        return rc;

      request_read = false;
    }
    else
    {
      /*
       * If this is a write check if the write starts within a block or the
       * amount of data is less than a block size. If it is read the block
       * rather than getting a block to fill.
       */
      if (!read &&
          (rtems_rfs_file_block_offset (handle) ||
           (*available < rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle)))))
        request_read = true;
    }
    
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
      printf ("rtems-rfs: file-io: start: block=%" PRIu32 " request-read=%s\n",
              block, request_read ? "yes" : "no");
    
    rc = rtems_rfs_buffer_handle_request (rtems_rfs_file_fs (handle),
                                          rtems_rfs_file_buffer (handle),
                                          block, request_read);
    if (rc > 0)
      return rc;
  }
  
  if (read
      && rtems_rfs_block_map_last (rtems_rfs_file_map (handle))
      && rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle)))
    size = rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle));
  else
    size = rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
  
  *available = size - rtems_rfs_file_block_offset (handle);

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
    printf ("rtems-rfs: file-io: start: available=%zu (%zu)\n",
            *available, size);
    
  return 0;
}
Exemple #19
0
static bool
rtems_rfs_write_group (rtems_rfs_file_system* fs,
                       int                    group,
                       bool                   initialise_inodes,
                       bool                   verbose)
{
  rtems_rfs_buffer_handle  handle;
  rtems_rfs_bitmap_control bitmap;
  rtems_rfs_buffer_block   group_base;
  size_t                   group_size;
  int                      blocks;
  int                      b;
  int                      rc;
  
  group_base = rtems_rfs_fs_block (fs, group, 0);

  if (group_base > rtems_rfs_fs_blocks (fs))
  {
    printf ("rtems-rfs: write-group: group %d base beyond disk limit\n",
            group);
    return false;
  }

  group_size = fs->group_blocks;

  /*
   * Be nice to strange sizes of disks. These are embedded systems after all
   * and nice numbers do not always work out. Let the last block pick up the
   * remainder of the blocks.
   */
  if ((group_base + group_size) > rtems_rfs_fs_blocks (fs))
    group_size = rtems_rfs_fs_blocks (fs) - group_base;

  if (verbose)
    printf ("\rrtems-rfs: format: group %3d: base = %" PRId32 ", size = %zd",
            group, group_base, group_size);

  /*
   * Open a handle and request an empty buffer.
   */
  rc = rtems_rfs_buffer_handle_open (fs, &handle);
  if (rc > 0)
  {
    printf ("\nrtems-rfs: write-group: handle open failed: %d: %s\n",
            rc, strerror (rc));
    return false;
  }

  if (verbose)
    printf (", blocks");
  
  /*
   * Open the block bitmap using the new buffer.
   */
  rc = rtems_rfs_bitmap_open (&bitmap, fs, &handle, group_size,
                              group_base + RTEMS_RFS_GROUP_BLOCK_BITMAP_BLOCK);
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    printf ("\nrtems-rfs: write-group: group %3d: open block bitmap failed: %d: %s\n",
            group, rc, strerror (rc));
    return false;
  }

  /*
   * Force the whole buffer to a known state. The bit map may not occupy the
   * whole block.
   */
  memset (rtems_rfs_buffer_data (&handle), 0xff, rtems_rfs_fs_block_size (fs));
  
  /*
   * Clear the bitmap.
   */
  rc = rtems_rfs_bitmap_map_clear_all (&bitmap);
  if (rc > 0)
  {
    rtems_rfs_bitmap_close (&bitmap);
    rtems_rfs_buffer_handle_close (fs, &handle);
    printf ("\nrtems-rfs: write-group: group %3d: block bitmap clear all failed: %d: %s\n",
            group, rc, strerror (rc));
    return false;
  }
  
  /*
   * Forced allocation of the block bitmap.
   */
  rtems_rfs_bitmap_map_set (&bitmap, RTEMS_RFS_GROUP_BLOCK_BITMAP_BLOCK);

  /*
   * Forced allocation of the inode bitmap.
   */
  rtems_rfs_bitmap_map_set (&bitmap, RTEMS_RFS_GROUP_INODE_BITMAP_BLOCK);

  /*
   * Determine the number of inodes blocks in the group.
   */
  blocks = rtems_rfs_rup_quotient (fs->group_inodes, fs->inodes_per_block);

  /*
   * Forced allocation of the inode blocks which follow the block bitmap.
   */
  for (b = 0; b < blocks; b++)
    rtems_rfs_bitmap_map_set (&bitmap, b + RTEMS_RFS_GROUP_INODE_BLOCK);

  /*
   * Close the block bitmap.
   */
  rc = rtems_rfs_bitmap_close (&bitmap);
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    printf ("\nrtems-rfs: write-group: group %3d: close block bitmap failed: %d: %s\n",
            group, rc, strerror (rc));
    return false;
  }

  rtems_rfs_buffer_mark_dirty (&handle);

  if (verbose)
    printf (", inodes");
  
  /*
   * Open the inode bitmap using the old buffer. Should release any changes.
   */
  rc = rtems_rfs_bitmap_open (&bitmap, fs, &handle, group_size,
                              group_base + RTEMS_RFS_GROUP_INODE_BITMAP_BLOCK);
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    printf ("\nrtems-rfs: write-group: group %3d: open inode bitmap failed: %d: %s\n",
            group, rc, strerror (rc));
    return false;
  }

  /*
   * Force the whole buffer to a known state. The bit map may not occupy the
   * whole block.
   */
  memset (rtems_rfs_buffer_data (&handle), 0x00, rtems_rfs_fs_block_size (fs));
  
  /*
   * Clear the inode bitmap.
   */
  rc = rtems_rfs_bitmap_map_clear_all (&bitmap);
  if (rc > 0)
  {
    rtems_rfs_bitmap_close (&bitmap);
    rtems_rfs_buffer_handle_close (fs, &handle);
    printf ("\nrtems-rfs: write-group: group %3d: inode bitmap" \
            " clear all failed: %d: %s\n", group, rc, strerror (rc));
    return false;
  }
  
  /*
   * Close the inode bitmap.
   */
  rc = rtems_rfs_bitmap_close (&bitmap);
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    printf ("\nrtems-rfs: write-group: group %3d: close inode" \
            " bitmap failed: %d: %s\n", group, rc, strerror (rc));
    return false;
  }

  rtems_rfs_buffer_mark_dirty (&handle);

  /*
   * Initialise the inode tables if required to do so.
   */
  if (initialise_inodes)
  {
    for (b = 0; b < blocks; b++)
    {
      rc = rtems_rfs_buffer_handle_request (fs, &handle,
                                            group_base + b + RTEMS_RFS_GROUP_INODE_BLOCK,
                                            false);
      if (rc > 0)
      {
        rtems_rfs_buffer_handle_close (fs, &handle);
        printf ("\nrtems-rfs: write-group: group %3d: block %" PRId32 " request failed: %d: %s\n",
                group, group_base + b + RTEMS_RFS_GROUP_INODE_BLOCK,
                rc, strerror (rc));
        return false;
      }
    
      /*
       * Force the whole buffer to a known state. The bit map may not occupy the
       * whole block.
       */
      memset (rtems_rfs_buffer_data (&handle), 0xff, rtems_rfs_fs_block_size (fs));
  
      rtems_rfs_buffer_mark_dirty (&handle);
    }
  }
  
  rc = rtems_rfs_buffer_handle_close (fs, &handle);
  if (rc > 0)
  {
    printf ("\nrtems-rfs: write-group: buffer handle close failed: %d: %s\n",
            rc, strerror (rc));
    return false;
  }
  
  return true;
}
Exemple #20
0
static int
rtems_rfs_shell_dir (rtems_rfs_file_system* fs, int argc, char *argv[])
{
  rtems_rfs_buffer_handle buffer;
  rtems_rfs_block_no      block;
  uint8_t*                data;
  bool                    state;
  int                     entry;
  int                     b;
  int                     rc;
  
  if (argc <= 1)
  {
    printf ("error: no block number provided\n");
    return 1;
  }

  block = strtoul (argv[1], 0, 0);

  rtems_rfs_shell_lock_rfs (fs);
  
  rc = rtems_rfs_group_bitmap_test (fs, false, block, &state);
  if (rc > 0)
  {
    rtems_rfs_shell_unlock_rfs (fs);
    printf ("error: testing block state: block=%" PRIu32 ": (%d) %s\n",
            block, rc, strerror (rc));
    return 1;
  }

  printf (" %5" PRIu32 ": block %s\n", block, state ? "allocated" : "free");

  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
  if (rc > 0)
  {
    rtems_rfs_shell_unlock_rfs (fs);
    printf ("error: opening buffer handle: block=%" PRIu32 ": (%d) %s\n",
            block, rc, strerror (rc));
    return 1;
  }

  rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &buffer);
    rtems_rfs_shell_unlock_rfs (fs);
    printf ("error: requesting buffer handle: block=%" PRIu32 ": (%d) %s\n",
            block, rc, strerror (rc));
    return 1;
  }

  b = 0;
  entry = 1;
  data = rtems_rfs_buffer_data (&buffer);
  
  while (b < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE - 1))
  {
    rtems_rfs_ino eino;
    int           elength;
    int           length;
    int           c;

    eino    = rtems_rfs_dir_entry_ino (data);
    elength = rtems_rfs_dir_entry_length (data);
    
    if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
      break;

    if ((elength < RTEMS_RFS_DIR_ENTRY_SIZE) ||
        (elength >= rtems_rfs_fs_max_name (fs)))
    {
      printf (" %5d: entry length appears corrupt: %d\n", entry, elength);
      break;
    }
    
    if ((eino < RTEMS_RFS_ROOT_INO) || (eino >= rtems_rfs_fs_inodes (fs)))
    {
      printf (" %5d: entry ino appears corrupt: ino=%" PRId32 "\n", entry, eino);
      break;
    }
    
    length = elength - RTEMS_RFS_DIR_ENTRY_SIZE;
    
    printf (" %5d: %04x inode=%-6" PRIu32 " hash=%08" PRIx32 " name[%03u]=",
            entry, b,
            rtems_rfs_dir_entry_ino (data),
            rtems_rfs_dir_entry_hash (data),
            length);

    if (length > 50)
      length = 50;
    
    for (c = 0; c < length; c++)
      printf ("%c", data[RTEMS_RFS_DIR_ENTRY_SIZE + c]);
    if (length < elength - RTEMS_RFS_DIR_ENTRY_SIZE)
      printf ("...");
    printf ("\n");

    b += elength;
    data += elength;
    entry++;
  }
  
  rc = rtems_rfs_buffer_handle_close (fs, &buffer);
  if (rc > 0)
  {
    rtems_rfs_shell_unlock_rfs (fs);
    printf ("error: closing buffer handle: block=%" PRIu32 ": (%d) %s\n",
            block, rc, strerror (rc));
    return 1;
  }
  
  rtems_rfs_shell_unlock_rfs (fs);
  
  return 0;
}