Ejemplo n.º 1
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_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;
}
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;
}
Ejemplo n.º 4
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;
}