Beispiel #1
0
/**
 * This routine processes the lseek() system call.
 *
 * @param iop
 * @param offset
 * @param whence
 * @return off_t
 */
static off_t
rtems_rfs_rtems_file_lseek (rtems_libio_t* iop,
                            off_t          offset,
                            int            whence)
{
  rtems_rfs_file_handle* file = rtems_rfs_rtems_get_iop_file_handle (iop);
  off_t                  old_offset;
  off_t                  new_offset;

  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_LSEEK))
    printf("rtems-rfs: file-lseek: handle:%p offset:%" PRIdoff_t "\n", file, offset);

  rtems_rfs_rtems_lock (rtems_rfs_file_fs (file));

  old_offset = iop->offset;
  new_offset = rtems_filesystem_default_lseek_file (iop, offset, whence);
  if (new_offset != -1)
  {
    rtems_rfs_pos pos = iop->offset;
    int           rc = rtems_rfs_file_seek (file, pos, &pos);

    if (rc)
    {
      rtems_rfs_rtems_error ("file_lseek: lseek", rc);
      iop->offset = old_offset;
      new_offset = -1;
    }
  }

  rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file));

  return new_offset;
}
/**
 * This routine processes the lseek() system call.
 *
 * @param iop
 * @param offset
 * @param whence
 * @return off_t
 */
static off_t
rtems_rfs_rtems_file_lseek (rtems_libio_t* iop,
                            off_t          offset,
                            int            whence)
{
  rtems_rfs_file_handle* file = rtems_rfs_rtems_get_iop_file_handle (iop);
  rtems_rfs_pos          pos;
  int                    rc;

  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_LSEEK))
    printf("rtems-rfs: file-lseek: handle:%p offset:%" PRIdoff_t "\n", file, offset);

  rtems_rfs_rtems_lock (rtems_rfs_file_fs (file));

  pos = iop->offset;

  rc = rtems_rfs_file_seek (file, pos, &pos);
  if (rc)
  {
    rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file));
    return rtems_rfs_rtems_error ("file_lseek: lseek", rc);
  }

  rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file));

  return iop->offset;
}
Beispiel #3
0
/**
 * This routine processes the read() system call.
 *
 * @param iop
 * @param buffer
 * @param count
 * @return int
 */
static ssize_t
rtems_rfs_rtems_file_read (rtems_libio_t* iop,
                           void*          buffer,
                           size_t         count)
{
  rtems_rfs_file_handle* file = rtems_rfs_rtems_get_iop_file_handle (iop);
  rtems_rfs_pos          pos;
  uint8_t*               data = buffer;
  ssize_t                read = 0;
  int                    rc;

  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_READ))
    printf("rtems-rfs: file-read: handle:%p count:%zd\n", file, count);

  rtems_rfs_rtems_lock (rtems_rfs_file_fs (file));

  pos = iop->offset;

  if (pos < rtems_rfs_file_size (file))
  {
    while (count)
    {
      size_t size;

      rc = rtems_rfs_file_io_start (file, &size, true);
      if (rc > 0)
      {
        read = rtems_rfs_rtems_error ("file-read: read: io-start", rc);
        break;
      }

      if (size == 0)
        break;

      if (size > count)
        size = count;

      memcpy (data, rtems_rfs_file_data (file), size);

      data  += size;
      count -= size;
      read  += size;

      rc = rtems_rfs_file_io_end (file, size, true);
      if (rc > 0)
      {
        read = rtems_rfs_rtems_error ("file-read: read: io-end", rc);
        break;
      }
    }
  }

  if (read >= 0)
    iop->offset = pos + read;

  rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file));

  return read;
}
int
rtems_rfs_file_io_release (rtems_rfs_file_handle* handle)
{
  int rc = 0;
  if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
    rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
                                          rtems_rfs_file_buffer (handle));
  return rc;
}
Beispiel #5
0
/**
 * This routine processes the ftruncate() system call.
 *
 * @param iop
 * @param length
 * @return int
 */
static int
rtems_rfs_rtems_file_ftruncate (rtems_libio_t* iop,
                                off_t          length)
{
  rtems_rfs_file_handle* file = rtems_rfs_rtems_get_iop_file_handle (iop);
  int                    rc;

  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_FTRUNC))
    printf("rtems-rfs: file-ftrunc: handle:%p length:%" PRIdoff_t "\n", file, length);

  rtems_rfs_rtems_lock (rtems_rfs_file_fs (file));

  rc = rtems_rfs_file_set_size (file, length);
  if (rc)
    rc = rtems_rfs_rtems_error ("file_ftruncate: set size", rc);

  rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file));

  return rc;
}
Beispiel #6
0
/**
 * This routine processes the close() system call.  Note that there is nothing
 * to flush at this point.
 *
 * @param iop
 * @return int
 */
static int
rtems_rfs_rtems_file_close (rtems_libio_t* iop)
{
  rtems_rfs_file_handle* file = rtems_rfs_rtems_get_iop_file_handle (iop);
  rtems_rfs_file_system* fs = rtems_rfs_file_fs (file);
  int                    rc;

  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_CLOSE))
    printf("rtems-rfs: file-close: handle:%p\n", file);

  rtems_rfs_rtems_lock (fs);

  rc = rtems_rfs_file_close (fs, file);
  if (rc > 0)
    rc = rtems_rfs_rtems_error ("file-close: file close", rc);

  rtems_rfs_rtems_unlock (fs);
  return rc;
}
Beispiel #7
0
/**
 * This routine processes the write() system call.
 *
 * @param iop
 * @param buffer
 * @param count
 * @return ssize_t
 */
static ssize_t
rtems_rfs_rtems_file_write (rtems_libio_t* iop,
                            const void*    buffer,
                            size_t         count)
{
  rtems_rfs_file_handle* file = rtems_rfs_rtems_get_iop_file_handle (iop);
  rtems_rfs_pos          pos;
  rtems_rfs_pos          file_size;
  const uint8_t*         data = buffer;
  ssize_t                write = 0;
  int                    rc;

  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_WRITE))
    printf("rtems-rfs: file-write: handle:%p count:%zd\n", file, count);

  rtems_rfs_rtems_lock (rtems_rfs_file_fs (file));

  pos = iop->offset;
  file_size = rtems_rfs_file_size (file);
  if (pos > file_size)
  {
    /*
     * If the iop position is past the physical end of the file we need to set
     * the file size to the new length before writing.  The
     * rtems_rfs_file_io_end() will grow the file subsequently.
     */
    rc = rtems_rfs_file_set_size (file, pos);
    if (rc)
    {
      rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file));
      return rtems_rfs_rtems_error ("file-write: write extend", rc);
    }

    rtems_rfs_file_set_bpos (file, pos);
  }
  else if (pos < file_size && rtems_libio_iop_is_append(iop))
  {
    pos = file_size;
    rc = rtems_rfs_file_seek (file, pos, &pos);
    if (rc)
    {
      rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file));
      return rtems_rfs_rtems_error ("file-write: write append seek", rc);
    }
  }

  while (count)
  {
    size_t size = count;

    rc = rtems_rfs_file_io_start (file, &size, false);
    if (rc)
    {
      /*
       * If we have run out of space and have written some data return that
       * amount first as the inode will have accounted for it. This means
       * there was no error and the return code from can be ignored.
       */
      if (!write)
        write = rtems_rfs_rtems_error ("file-write: write open", rc);
      break;
    }

    if (size > count)
      size = count;

    memcpy (rtems_rfs_file_data (file), data, size);

    data  += size;
    count -= size;
    write  += size;

    rc = rtems_rfs_file_io_end (file, size, false);
    if (rc)
    {
      write = rtems_rfs_rtems_error ("file-write: write close", rc);
      break;
    }
  }

  if (write >= 0)
    iop->offset = pos + write;

  rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file));

  return write;
}
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;
}
int
rtems_rfs_file_seek (rtems_rfs_file_handle* handle,
                     rtems_rfs_pos          pos,
                     rtems_rfs_pos*         new_pos)
{
  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
    printf ("rtems-rfs: file-seek: new=%" PRIu64 "\n", pos);
  
  /*
   * This call only sets the position if it is in a valid part of the file. The
   * user can request past the end of the file then write to extend the
   * file. The lseek entry states:
   *
   *    "Although lseek() may position the file offset beyond the end of the
   *     file, this function does not itself extend the size of the file."
   *
   * This means the file needs to set the file size to the pos only when a
   * write occurs.
   */
  if (pos < rtems_rfs_file_shared_get_size (rtems_rfs_file_fs (handle),
                                            handle->shared))
  {
    rtems_rfs_file_set_bpos (handle, pos);
    
    /*
     * If the file has a block check if it maps to the current position and it
     * does not release it. That will force us to get the block at the new
     * position when the I/O starts.
     */
    if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
    {
      rtems_rfs_buffer_block block;
      int                    rc;
      
      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)
        return rc;
      if (rtems_rfs_buffer_bnum (&handle->buffer) != block)
      {        
        rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
                                              rtems_rfs_file_buffer (handle));
        if (rc > 0)
          return rc;
      }
    }
  }
  else
  {
    /*
     * The seek is outside the current file so release any buffer. A write will
     * extend the file.
     */
    int rc = rtems_rfs_file_io_release (handle);
    if (rc > 0)
      return rc;
  }
  
  *new_pos = pos;
  return 0;
}
int
rtems_rfs_file_io_end (rtems_rfs_file_handle* handle,
                       size_t                 size,
                       bool                   read)
{
  bool atime;
  bool mtime;
  bool length;
  int  rc = 0;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
    printf ("rtems-rfs: file-io:   end: %s size=%zu\n",
            read ? "read" : "write", size);
  
  if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
  {
    if (!read)
      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)
    {
      printf (
        "rtems-rfs: file-io:   end: error on release: %s size=%zu: %d: %s\n",
        read ? "read" : "write", size, rc, strerror (rc));
      
      return rc;
    }
  }

  /*
   * Update the handle's position. Only a block size can be handled at a time
   * so no special maths is needed. If the offset is bigger than the block size
   * increase the block number and adjust the offset.
   *
   * If we are the last block and the position is past the current size update
   * the size with the new length. The map holds the block count.
   */
  handle->bpos.boff += size;

  if (handle->bpos.boff >=
      rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle)))
  {
    handle->bpos.bno++;
    handle->bpos.boff -= rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
  }

  length = false;
  mtime = false;
  
  if (!read &&
      rtems_rfs_block_map_past_end (rtems_rfs_file_map (handle),
                                    rtems_rfs_file_bpos (handle)))
  {
    rtems_rfs_block_map_set_size_offset (rtems_rfs_file_map (handle),
                                         handle->bpos.boff);
    length = true;
    mtime = true;
  }
  
  atime  = rtems_rfs_file_update_atime (handle);
  mtime  = rtems_rfs_file_update_mtime (handle) && mtime;
  length = rtems_rfs_file_update_length (handle) && length;
  
  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
    printf ("rtems-rfs: file-io:   end: pos=%" PRIu32 ":%" PRIu32 " %c %c %c\n",
            handle->bpos.bno, handle->bpos.boff,
            atime ? 'A' : '-', mtime ? 'M' : '-', length ? 'L' : '-');
  
  if (atime || mtime)
  {
    time_t now = time (NULL);
    if (read && atime)
      handle->shared->atime = now;
    if (!read && mtime)
      handle->shared->mtime = now;
  }
  if (length)
  {
    handle->shared->size.count =
      rtems_rfs_block_map_count (rtems_rfs_file_map (handle));
    handle->shared->size.offset =
      rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle));
  }
  
  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;
}
/**
 * This routine processes the write() system call.
 *
 * @param iop
 * @param buffer
 * @param count
 * @return ssize_t
 */
static ssize_t
rtems_rfs_rtems_file_write (rtems_libio_t* iop,
                            const void*    buffer,
                            size_t         count)
{
  rtems_rfs_file_handle* file = rtems_rfs_rtems_get_iop_file_handle (iop);
  rtems_rfs_pos          pos;
  const uint8_t*         data = buffer;
  ssize_t                write = 0;
  int                    rc;

  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_WRITE))
    printf("rtems-rfs: file-write: handle:%p count:%zd\n", file, count);

  rtems_rfs_rtems_lock (rtems_rfs_file_fs (file));

  pos = iop->offset;

  /*
   * If the iop position is past the physical end of the file we need to set
   * the file size to the new length before writing. If the position equals the
   * size of file we are still past the end of the file as positions number
   * from 0. For a specific position we need a file that has a length of one
   * more.
   */

  if (pos >= rtems_rfs_file_size (file))
  {
    rc = rtems_rfs_file_set_size (file, pos + 1);
    if (rc)
    {
      rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file));
      return rtems_rfs_rtems_error ("file-write: write extend", rc);
    }
  }

  rtems_rfs_file_set_bpos (file, pos);

  while (count)
  {
    size_t size = count;

    rc = rtems_rfs_file_io_start (file, &size, false);
    if (rc)
    {
      write = rtems_rfs_rtems_error ("file-write: write open", rc);
      break;
    }

    if (size > count)
      size = count;

    memcpy (rtems_rfs_file_data (file), data, size);

    data  += size;
    count -= size;
    write  += size;

    rc = rtems_rfs_file_io_end (file, size, false);
    if (rc)
    {
      write = rtems_rfs_rtems_error ("file-write: write close", rc);
      break;
    }
  }

  iop->size = rtems_rfs_file_size (file);

  rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file));

  return write;
}