Exemplo n.º 1
0
int getdents(
  int   dd_fd,
  char *dd_buf,
  int   dd_len
)
{
  rtems_libio_t *iop;
  rtems_filesystem_node_types_t type;

  /*
   *  Get the file control block structure associated with the file descriptor
   */
  iop = rtems_libio_iop( dd_fd );

  /*
   *  Make sure we are working on a directory
   */
  type = rtems_filesystem_node_type( &iop->pathinfo );
  if ( type != RTEMS_FILESYSTEM_DIRECTORY )
    rtems_set_errno_and_return_minus_one( ENOTDIR );

  /*
   *  Return the number of bytes that were actually transfered as a result
   *  of the read attempt.
   */
  return (*iop->pathinfo.handlers->read_h)( iop, dd_buf, dd_len  );
}
Exemplo n.º 2
0
Arquivo: write.c Projeto: rtemss/rtems
ssize_t write(
  int         fd,
  const void *buffer,
  size_t      count
)
{
  ssize_t  rc;
  rtems_libio_t     *iop;

  rtems_libio_check_fd( fd );
  iop = rtems_libio_iop( fd );
  rtems_libio_check_is_open( iop );
  rtems_libio_check_buffer( buffer );
  rtems_libio_check_count( count );
  rtems_libio_check_permissions_with_error( iop, LIBIO_FLAGS_WRITE, EBADF );

  /*
   *  Now process the write() request.
   */
  rc = (*iop->pathinfo.handlers->write_h)( iop, buffer, count );

  if ( rc > 0 )
    iop->offset += rc;

  return rc;
}
Exemplo n.º 3
0
ssize_t read(
  int         fd,
  void       *buffer,
  size_t      count
)
{
  ssize_t      rc;
  rtems_libio_t *iop;

  rtems_libio_check_fd( fd );
  iop = rtems_libio_iop( fd );
  rtems_libio_check_is_open( iop );
  rtems_libio_check_buffer( buffer );
  rtems_libio_check_count( count );
  rtems_libio_check_permissions_with_error( iop, LIBIO_FLAGS_READ, EBADF );

  /*
   *  Now process the read().
   */

  if ( !iop->handlers->read_h )
    rtems_set_errno_and_return_minus_one( ENOTSUP );

  rc = (*iop->handlers->read_h)( iop, buffer, count );

  if ( rc > 0 )
    iop->offset += rc;

  return rc;
}
Exemplo n.º 4
0
int ftruncate(
  int     fd,
  off_t   length
)
{
  rtems_libio_t                    *iop;
  rtems_filesystem_location_info_t  loc;

  rtems_libio_check_fd( fd );
  iop = rtems_libio_iop( fd );
  rtems_libio_check_is_open(iop);
  rtems_libio_check_permissions( iop, LIBIO_FLAGS_WRITE );

  /*
   *  Now process the ftruncate() request.
   */

  /*
   *  Make sure we are not working on a directory
   */

  loc = iop->pathinfo;
  if ( !loc.ops->node_type_h )
    rtems_set_errno_and_return_minus_one( ENOTSUP );

  if ( (*loc.ops->node_type_h)( &loc ) == RTEMS_FILESYSTEM_DIRECTORY )
    rtems_set_errno_and_return_minus_one( EISDIR );

  rtems_libio_check_permissions( iop, LIBIO_FLAGS_WRITE );

  if ( !iop->handlers->ftruncate_h )
    rtems_set_errno_and_return_minus_one( ENOTSUP );

  return (*iop->handlers->ftruncate_h)( iop, length );
}
Exemplo n.º 5
0
int ioctl(
  int  fd,
  ioctl_command_t  command,
  ...
)
{
  va_list            ap;
  int                rc;
  rtems_libio_t     *iop;
  void              *buffer;

  rtems_libio_check_fd( fd );
  iop = rtems_libio_iop( fd );
  rtems_libio_check_is_open(iop);

  va_start(ap, command);

  buffer = va_arg(ap, void *);

  /*
   *  Now process the ioctl().
   */
  rc = (*iop->pathinfo.handlers->ioctl_h)( iop, command, buffer );

  va_end( ap );
  return rc;
}
Exemplo n.º 6
0
off_t lseek(
    int     fd,
    off_t   offset,
    int     whence
)
{
    rtems_libio_t *iop;
    off_t          old_offset;
    off_t          status;

    rtems_libio_check_fd( fd );
    iop = rtems_libio_iop( fd );
    rtems_libio_check_is_open(iop);

    /*
     *  Check as many errors as possible before touching iop->offset.
     */

    if ( !iop->handlers->lseek_h )
        rtems_set_errno_and_return_minus_one( ENOTSUP );

    /*
     *  Now process the lseek().
     */

    old_offset = iop->offset;
    switch ( whence ) {
    case SEEK_SET:
        iop->offset = offset;
        break;

    case SEEK_CUR:
        iop->offset += offset;
        break;

    case SEEK_END:
        iop->offset = iop->size + offset;
        break;

    default:
        rtems_set_errno_and_return_minus_one( EINVAL );
    }

    /*
     *  At this time, handlers assume iop->offset has the desired
     *  new offset.
     */

    status = (*iop->handlers->lseek_h)( iop, offset, whence );
    if ( status == (off_t) -1 )
        iop->offset = old_offset;

    /*
     *  So if the operation failed, we have to restore iop->offset.
     */

    return status;
}
Exemplo n.º 7
0
int fchdir(
    int       fd
)
{
    rtems_libio_t *iop;
    rtems_filesystem_location_info_t loc, saved;

    rtems_libio_check_fd( fd );
    iop = rtems_libio_iop( fd );
    rtems_libio_check_is_open(iop);

    /*
     * Verify you can change directory into this node.
     */

    if ( !iop->pathinfo.ops ) {
        rtems_set_errno_and_return_minus_one( ENOTSUP );
    }

    if ( !iop->pathinfo.ops->node_type_h ) {
        rtems_set_errno_and_return_minus_one( ENOTSUP );
    }

    if (  (*iop->pathinfo.ops->node_type_h)( &iop->pathinfo ) !=
            RTEMS_FILESYSTEM_DIRECTORY ) {
        rtems_set_errno_and_return_minus_one( ENOTDIR );
    }


    /*
     * FIXME : I feel there should be another call to
     *         actually take into account the extra reference to
     *         this node which we are making here. I can
     *         see the freenode interface but do not see
     *         allocnode node interface. It maybe node_type.
     *
     * FIXED:  T.Straumann: it is evaluate_path()
     *         but note the race condition. Threads who
     *         share their rtems_filesystem_current better
     *         be synchronized!
     */

    saved                    = rtems_filesystem_current;
    rtems_filesystem_current = iop->pathinfo;

    /* clone the current node */
    if (rtems_filesystem_evaluate_path(".", 1, 0, &loc, 0)) {
        /* cloning failed; restore original and bail out */
        rtems_filesystem_current = saved;
        return -1;
    }
    /* release the old one */
    rtems_filesystem_freenode( &saved );

    rtems_filesystem_current = loc;

    return 0;
}
Exemplo n.º 8
0
off_t lseek( int fd, off_t offset, int whence )
{
  rtems_libio_t *iop;

  rtems_libio_check_fd( fd );
  iop = rtems_libio_iop( fd );
  rtems_libio_check_is_open(iop);

  return (*iop->pathinfo.handlers->lseek_h)( iop, offset, whence );
}
Exemplo n.º 9
0
Arquivo: close.c Projeto: gedare/rtems
int close(
  int  fd
)
{
  rtems_libio_t *iop;
  unsigned int   flags;
  int            rc;

  if ( (uint32_t) fd >= rtems_libio_number_iops ) {
    rtems_set_errno_and_return_minus_one( EBADF );
  }

  iop = rtems_libio_iop( fd );
  flags = rtems_libio_iop_flags( iop );

  while ( true ) {
    unsigned int desired;
    bool         success;

    if ( ( flags & LIBIO_FLAGS_OPEN ) == 0 ) {
      rtems_set_errno_and_return_minus_one( EBADF );
    }

    /* The expected flags */
    flags &= LIBIO_FLAGS_REFERENCE_INC - 1U;

    desired = flags & ~LIBIO_FLAGS_OPEN;
    success = _Atomic_Compare_exchange_uint(
      &iop->flags,
      &flags,
      desired,
      ATOMIC_ORDER_ACQ_REL,
      ATOMIC_ORDER_RELAXED
    );

    if ( success ) {
      break;
    }

    if ( ( flags & ~( LIBIO_FLAGS_REFERENCE_INC - 1U ) ) != 0 ) {
      rtems_set_errno_and_return_minus_one( EBUSY );
    }
  }

  rc = (*iop->pathinfo.handlers->close_h)( iop );

  rtems_libio_free( iop );

  return rc;
}
Exemplo n.º 10
0
Arquivo: fsync.c Projeto: rtemss/rtems
int fsync(
  int     fd
)
{
  rtems_libio_t *iop;

  rtems_libio_check_fd( fd );
  iop = rtems_libio_iop( fd );
  rtems_libio_check_is_open(iop);

  /*
   *  Now process the fsync().
   */

  return (*iop->pathinfo.handlers->fsync_h)( iop );
}
Exemplo n.º 11
0
/**
 *  POSIX 1003.1b 5.6.5 - Change Owner and Group of a File
 */
int fchown( int fd, uid_t owner, gid_t group )
{
  int rv;
  rtems_libio_t *iop;

  rtems_libio_check_fd( fd );
  iop = rtems_libio_iop( fd );
  rtems_libio_check_is_open(iop);

  rtems_filesystem_instance_lock( &iop->pathinfo );

  rv = rtems_filesystem_chown( &iop->pathinfo, owner, group );

  rtems_filesystem_instance_unlock( &iop->pathinfo );

  return rv;
}
Exemplo n.º 12
0
int fdatasync(
  int     fd
)
{
  rtems_libio_t *iop;

  rtems_libio_check_fd( fd );
  iop = rtems_libio_iop( fd );
  rtems_libio_check_is_open(iop);
  rtems_libio_check_permissions_with_error( iop, LIBIO_FLAGS_WRITE, EBADF );

  /*
   *  Now process the fdatasync().
   */

  return (*iop->pathinfo.handlers->fdatasync_h)( iop );
}
Exemplo n.º 13
0
int close(
  int  fd
)
{
  rtems_libio_t      *iop;
  int                 rc;

  rtems_libio_check_fd(fd);
  iop = rtems_libio_iop(fd);
  rtems_libio_check_is_open(iop);

  iop->flags &= ~LIBIO_FLAGS_OPEN;

  rc = (*iop->pathinfo.handlers->close_h)( iop );

  rtems_libio_free( iop );

  return rc;
}
Exemplo n.º 14
0
int fchmod(
  int       fd,
  mode_t    mode
)
{
  rtems_libio_t *iop;

  rtems_libio_check_fd( fd );
  iop = rtems_libio_iop( fd );
  rtems_libio_check_is_open(iop);

  /*
   *  Now process the fchmod().
   */
  if ( !iop->handlers->fchmod_h )
    rtems_set_errno_and_return_minus_one( ENOTSUP );

  return (*iop->pathinfo.handlers->fchmod_h)( &iop->pathinfo, mode );
}
Exemplo n.º 15
0
int close(
  int  fd
)
{
  rtems_libio_t      *iop;
  rtems_status_code   rc;

  rtems_libio_check_fd(fd);
  iop = rtems_libio_iop(fd);
  rtems_libio_check_is_open(iop);

  rc = RTEMS_SUCCESSFUL;
  if ( iop->handlers->close_h )
    rc = (*iop->handlers->close_h)( iop );

  rtems_filesystem_freenode( &iop->pathinfo );
  rtems_libio_free( iop );

  return rc;
}
Exemplo n.º 16
0
/**
 *  POSIX 1003.1b 6.4.1 - Read From a File
 */
ssize_t read(
  int         fd,
  void       *buffer,
  size_t      count
)
{
  rtems_libio_t *iop;

  rtems_libio_check_fd( fd );
  iop = rtems_libio_iop( fd );
  rtems_libio_check_is_open( iop );
  rtems_libio_check_buffer( buffer );
  rtems_libio_check_count( count );
  rtems_libio_check_permissions_with_error( iop, LIBIO_FLAGS_READ, EBADF );

  /*
   *  Now process the read().
   */
  return (*iop->pathinfo.handlers->read_h)( iop, buffer, count );
}
Exemplo n.º 17
0
int ftruncate( int fd, off_t length )
{
  int rv = 0;

  if ( length >= 0 ) {
    rtems_libio_t *iop;

    rtems_libio_check_fd( fd );
    iop = rtems_libio_iop( fd );
    rtems_libio_check_is_open( iop );
    rtems_libio_check_permissions( iop, LIBIO_FLAGS_WRITE );

    rv = (*iop->pathinfo.handlers->ftruncate_h)( iop, length );
  } else {
    errno = EINVAL;
    rv = -1;
  }

  return rv;
}
Exemplo n.º 18
0
long telldir(
  DIR *dirp
)
{
  rtems_libio_t  *iop;

  if ( !dirp )
    rtems_set_errno_and_return_minus_one( EBADF );

  /*
   *  Get the file control block structure associated with the
   *  file descriptor
   */

  iop = rtems_libio_iop( dirp->dd_fd );

  if (iop == NULL)
     assert(0);

  return (long)( iop->offset );
}
Exemplo n.º 19
0
Arquivo: fcntl.c Projeto: AoLaD/rtems
static int duplicate2_iop( rtems_libio_t *iop, int fd2 )
{
  rtems_libio_t *iop2;
  int            rv = 0;

  rtems_libio_check_fd( fd2 );
  iop2 = rtems_libio_iop( fd2 );

  if (iop != iop2)
  {
    int oflag;

    if ((iop2->flags & LIBIO_FLAGS_OPEN) != 0) {
      rv = (*iop2->pathinfo.handlers->close_h)( iop2 );
    }

    if (rv == 0) {
      oflag = rtems_libio_to_fcntl_flags( iop->flags );
      oflag &= ~O_CREAT;
      iop2->flags |= rtems_libio_fcntl_flags( oflag );

      rtems_filesystem_instance_lock( &iop->pathinfo );
      rtems_filesystem_location_clone( &iop2->pathinfo, &iop->pathinfo );
      rtems_filesystem_instance_unlock( &iop->pathinfo );

      /*
       * XXX: We call the open handler here to have a proper open and close
       *      pair.
       *
       * FIXME: What to do with the path?
       */
      rv = (*iop2->pathinfo.handlers->open_h)( iop2, NULL, oflag, 0 );
      if ( rv == 0 ) {
        rv = fd2;
      }
    }
  }

  return rv;
}
Exemplo n.º 20
0
int fchdir( int fd )
{
  int rv = 0;
  rtems_libio_t *iop;
  struct stat st;
  rtems_filesystem_location_info_t loc;

  st.st_mode = 0;
  st.st_uid = 0;
  st.st_gid = 0;

  rtems_libio_check_fd( fd );
  iop = rtems_libio_iop( fd );
  rtems_libio_check_is_open( iop );

  rtems_filesystem_instance_lock( &iop->pathinfo );
  rv = (*iop->pathinfo.handlers->fstat_h)( &iop->pathinfo, &st );
  if ( rv == 0 ) {
    bool access_ok = rtems_filesystem_check_access(
      RTEMS_FS_PERMS_EXEC,
      st.st_mode,
      st.st_uid,
      st.st_gid
    );

    if ( access_ok ) {
      rtems_filesystem_location_clone( &loc, &iop->pathinfo );
    } else {
      errno = EACCES;
      rv = -1;
    }
  }
  rtems_filesystem_instance_unlock( &iop->pathinfo );

  if ( rv == 0 ) {
    rv = rtems_filesystem_chdir( &loc );
  }

  return rv;
}
Exemplo n.º 21
0
long fpathconf(
  int   fd,
  int   name
)
{
  long                                    return_value;
  rtems_libio_t                          *iop;
  rtems_filesystem_limits_and_options_t  *the_limits;

  rtems_libio_check_fd(fd);
  iop = rtems_libio_iop(fd);
  rtems_libio_check_is_open(iop);
  rtems_libio_check_permissions(iop, LIBIO_FLAGS_READ);

  /*
   *  Now process the information request.
   */

  the_limits = &iop->pathinfo.mt_entry->pathconf_limits_and_options;

  switch ( name ) {
    case _PC_LINK_MAX:
      return_value = the_limits->link_max;
      break;
    case _PC_MAX_CANON:
      return_value = the_limits->max_canon;
      break;
    case _PC_MAX_INPUT:
      return_value = the_limits->max_input;
      break;
    case _PC_NAME_MAX:
      return_value = the_limits->name_max;
      break;
    case _PC_PATH_MAX:
      return_value = the_limits->path_max;
      break;
    case _PC_PIPE_BUF:
      return_value = the_limits->pipe_buf;
      break;
    case _PC_CHOWN_RESTRICTED:
      return_value = the_limits->posix_chown_restrictions;
      break;
    case _PC_NO_TRUNC:
      return_value = the_limits->posix_no_trunc;
      break;
    case _PC_VDISABLE:
      return_value = the_limits->posix_vdisable;
      break;
    case _PC_ASYNC_IO:
      return_value = the_limits->posix_async_io;
      break;
    case _PC_PRIO_IO:
      return_value = the_limits->posix_prio_io;
      break;
    case _PC_SYNC_IO:
      return_value = the_limits->posix_sync_io;
      break;
    default:
      rtems_set_errno_and_return_minus_one( EINVAL );
      break;
  }

  return return_value;
}
Exemplo n.º 22
0
ssize_t writev(
  int                 fd,
  const struct iovec *iov,
  int                 iovcnt
)
{
  ssize_t        total;
  int            v;
  int            bytes;
  rtems_libio_t *iop;
  ssize_t        old;
  bool           all_zeros;

  rtems_libio_check_fd( fd );
  iop = rtems_libio_iop( fd );
  rtems_libio_check_is_open( iop );
  rtems_libio_check_permissions_with_error( iop, LIBIO_FLAGS_WRITE, EBADF );

  /*
   *  Argument validation on IO vector
   */
  if ( !iov )
    rtems_set_errno_and_return_minus_one( EINVAL );

  if ( iovcnt <= 0 )
    rtems_set_errno_and_return_minus_one( EINVAL );

  if ( iovcnt > IOV_MAX )
    rtems_set_errno_and_return_minus_one( EINVAL );

  if ( !iop->handlers->write_h )
    rtems_set_errno_and_return_minus_one( ENOTSUP );

  /*
   *  OpenGroup says that you are supposed to return EINVAL if the
   *  sum of the iov_len values in the iov array would overflow a
   *  ssize_t.
   *
   *  Also we would like to ensure that no IO is performed if there
   *  are obvious errors in the iovec.  So this extra loop ensures
   *  that we do not do anything if there is an argument error.
   *
   *  In addition,the OpenGroup specification says that if all the
   *  iov_len entries are zero, then the call has no effect.  So
   *  this loop does that check as well and sets "all-zero" appropriately.
   *  The variable "all_zero" is used as an early exit point before
   *  entering the write loop.
   */
  all_zeros = true;
  for ( old=0, total=0, v=0 ; v < iovcnt ; v++ ) {

    if ( !iov[v].iov_base )
      rtems_set_errno_and_return_minus_one( EINVAL );

    if ( iov[v].iov_len < 0 )
      rtems_set_errno_and_return_minus_one( EINVAL );

    if ( iov[v].iov_len )
      all_zeros = false;

    /* check for wrap */
    old    = total;
    total += iov[v].iov_len;
    if ( total < old || total > SSIZE_MAX )
      rtems_set_errno_and_return_minus_one( EINVAL );
  }

  /*
   * A writev with all zeros is supposed to have no effect per OpenGroup.
   */
  if ( all_zeros == true ) {
    return 0;
  }

  /*
   *  Now process the writev().
   */
  for ( total=0, v=0 ; v < iovcnt ; v++ ) {
    /* all zero lengths has no effect */
    if ( iov[v].iov_len == 0 )
      continue;

    bytes = (*iop->handlers->write_h)( iop, iov[v].iov_base, iov[v].iov_len );

    if ( bytes < 0 )
      return -1;

    if ( bytes > 0 ) {
      iop->offset += bytes;
      total       += bytes;
    }

    if (bytes != iov[ v ].iov_len)
      break;
  }

  return total;
}
Exemplo n.º 23
0
Arquivo: fcntl.c Projeto: AoLaD/rtems
static int vfcntl(
  int fd,
  int cmd,
  va_list ap
)
{
  rtems_libio_t *iop;
  int            fd2;
  int            flags;
  int            mask;
  int            ret = 0;

  rtems_libio_check_fd( fd );
  iop = rtems_libio_iop( fd );
  rtems_libio_check_is_open(iop);

  /*
   *  Now process the fcntl().
   */

  /*
   *  This switch should contain all the cases from POSIX.
   */

  switch ( cmd ) {
    case F_DUPFD:        /* dup */
      ret = duplicate_iop( iop );
      break;

    case F_DUP2FD:       /* dup2 */
      fd2 = va_arg( ap, int );
      ret = duplicate2_iop( iop, fd2 );
      break;

    case F_GETFD:        /* get f_flags */
      ret = ((iop->flags & LIBIO_FLAGS_CLOSE_ON_EXEC) != 0);
      break;

    case F_SETFD:        /* set f_flags */
      /*
       *  Interpret the third argument as the "close on exec()" flag.
       *  If this argument is 1, then the file descriptor is to be closed
       *  if a new process is exec()'ed.  Since RTEMS does not support
       *  processes, then we can ignore this one except to make
       *  F_GETFD work.
       */

      if ( va_arg( ap, int ) )
        iop->flags |= LIBIO_FLAGS_CLOSE_ON_EXEC;
      else
        iop->flags &= ~LIBIO_FLAGS_CLOSE_ON_EXEC;
      break;

    case F_GETFL:        /* more flags (cloexec) */
      ret = rtems_libio_to_fcntl_flags( iop->flags );
      break;

    case F_SETFL:
      flags = rtems_libio_fcntl_flags( va_arg( ap, int ) );
      mask = LIBIO_FLAGS_NO_DELAY | LIBIO_FLAGS_APPEND;

      /*
       *  XXX If we are turning on append, should we seek to the end?
       */

      iop->flags = (iop->flags & ~mask) | (flags & mask);
      break;

    case F_GETLK:
      errno = ENOTSUP;
      ret = -1;
      break;

    case F_SETLK:
      errno = ENOTSUP;
      ret = -1;
      break;

    case F_SETLKW:
      errno = ENOTSUP;
      ret = -1;
      break;

    case F_SETOWN:       /*  for sockets. */
      errno = ENOTSUP;
      ret = -1;
      break;

    case F_GETOWN:       /*  for sockets. */
      errno = ENOTSUP;
      ret = -1;
      break;

    default:
      errno = EINVAL;
      ret = -1;
      break;
  }
Exemplo n.º 24
0
Arquivo: mmap.c Projeto: gedare/rtems
void *mmap(
  void *addr, size_t len, int prot, int flags, int fildes, off_t off
)
{
  struct stat     sb;
  mmap_mapping   *mapping;
  mmap_mapping   *current_mapping;
  ssize_t         r;
  rtems_libio_t  *iop;
  bool            map_fixed;
  bool            map_anonymous;
  bool            map_shared;
  bool            map_private;
  bool            is_shared_shm;
  int             err;

  map_fixed = (flags & MAP_FIXED) == MAP_FIXED;
  map_anonymous = (flags & MAP_ANON) == MAP_ANON;
  map_shared = (flags & MAP_SHARED) == MAP_SHARED;
  map_private = (flags & MAP_PRIVATE) == MAP_PRIVATE;

  /* Clear errno. */
  errno = 0;
  iop = NULL;

  if ( len == 0 ) {
    errno = EINVAL;
    return MAP_FAILED;
  }

  /*
   * We can provide read, write and execute because the memory in RTEMS does
   * not normally have protections but we cannot hide access to memory.
   */
  if ( prot == PROT_NONE ) {
    errno = ENOTSUP;
    return MAP_FAILED;
  }

  /*
   * We can not normally provide restriction of write access. Reject any
   * attempt to map without write permission, since we are not able to
   * prevent a write from succeeding.
   */
  if ( PROT_WRITE != (prot & PROT_WRITE) ) {
    errno = ENOTSUP;
    return MAP_FAILED;
  }

  /*
   * Anonymous mappings must have file descriptor set to -1 and the offset
   * set to 0. Shared mappings are not supported with Anonymous mappings at
   * this time
   */
  if ( map_anonymous && (fildes != -1 || off != 0 || map_shared) ) {
    errno = EINVAL;
    return MAP_FAILED;
  }

  /*
   * If MAP_ANON is declared without MAP_PRIVATE or MAP_SHARED,
   * force MAP_PRIVATE
   */
  if ( map_anonymous && !map_private && !map_shared ) {
    flags |= MAP_PRIVATE;
    map_private = true;
  }

  /* Check for supported flags */
  if ((flags & ~(MAP_SHARED | MAP_PRIVATE | MAP_FIXED | MAP_ANON)) != 0) {
    errno = EINVAL;
    return MAP_FAILED;
  }

  /* Either MAP_SHARED or MAP_PRIVATE must be defined, but not both */
  if ( map_shared ) {
    if ( map_private ) {
      errno = EINVAL;
      return MAP_FAILED;
    }
  } else if ( !map_private ) {
    errno = EINVAL;
    return MAP_FAILED;
  }

  /* Check for illegal addresses. Watch out for address wrap. */
  if ( map_fixed ) {
    if ((uintptr_t)addr & PAGE_MASK) {
      errno = EINVAL;
      return MAP_FAILED;
    }
    if ( addr == NULL ) {
      errno = EINVAL;
      return MAP_FAILED;
    }
    if (addr + len < addr) {
      errno = EINVAL;
      return MAP_FAILED;
    }
  }

  if ( !map_anonymous ) {
    /*
     * Get a stat of the file to get the dev + inode number and to make sure the
     * fd is ok. The normal libio calls cannot be used because we need to return
     * MAP_FAILED on error and they return -1 directly without coming back to
     * here.
     */
    if ( fstat( fildes, &sb ) < 0 ) {
      errno = EBADF;
      return MAP_FAILED;
    }

    /* fstat ensures we have a good file descriptor. Hold on to iop. */
    iop = rtems_libio_iop( fildes );

    /* Check the type of file we have and make sure it is supported. */
    if ( S_ISDIR( sb.st_mode ) || S_ISLNK( sb.st_mode )) {
      errno = ENODEV;
      return MAP_FAILED;
    }

    /* Check to see if the mapping is valid for a regular file. */
    if ( S_ISREG( sb.st_mode )
    /* FIXME: Should this be using strict inequality (>) comparisons? It would
     * be valid to map a region exactly equal to the st_size, e.g. see below. */
         && (( off >= sb.st_size ) || (( off + len ) >= sb.st_size ))) {
      errno = EOVERFLOW;
      return MAP_FAILED;
    }

    /* Check to see if the mapping is valid for other file/object types. */
    if ( !S_ISCHR( sb.st_mode ) && sb.st_size < off + len ) {
      errno = ENXIO;
      return MAP_FAILED;
    }

    /* Do not seek on character devices, pipes, sockets, or memory objects. */
    if ( S_ISREG( sb.st_mode ) || S_ISBLK( sb.st_mode ) ) {
      if ( lseek( fildes, off, SEEK_SET ) < 0 ) {
        return MAP_FAILED;
      }
    }

    /* cdevs do not provide private mappings of any kind. */
    if ( S_ISCHR( sb.st_mode ) && map_private ) {
      errno = EINVAL;
      return MAP_FAILED;
    }
  }

  /* Create the mapping */
  mapping = malloc( sizeof( mmap_mapping ));
  if ( !mapping ) {
    errno = ENOMEM;
    return MAP_FAILED;
  }
  memset( mapping, 0, sizeof( mmap_mapping ));
  mapping->len = len;
  mapping->flags = flags;

  if ( !map_anonymous ) {
    /*
     * HACK: We should have a better generic way to distinguish between
     * shm objects and other mmap'd files. We need to know at munmap time
     * if the mapping is to a shared memory object in order to refcnt shms.
     * We could do this by providing mmap in the file operations if needed.
     */
    if ( S_ISREG( sb.st_mode ) || S_ISBLK( sb.st_mode ) ||
         S_ISCHR( sb.st_mode ) || S_ISFIFO( sb.st_mode ) ||
         S_ISSOCK( sb.st_mode ) ) {
      is_shared_shm = false;
    } else {
      is_shared_shm = true;
    }
  } else {
    is_shared_shm = false;
  }

  if ( map_fixed ) {
    mapping->addr = addr;
  } else if ( map_private ) {
    /* private mappings of shared memory do not need special treatment. */
    is_shared_shm = false;
    posix_memalign( &mapping->addr, PAGE_SIZE, len );
    if ( !mapping->addr ) {
      free( mapping );
      errno = ENOMEM;
      return MAP_FAILED;
    }
  }

  /* MAP_FIXED is not supported for shared memory objects with MAP_SHARED. */
  if ( map_fixed && is_shared_shm ) {
    free( mapping );
    errno = ENOTSUP;
    return MAP_FAILED;
  }

  mmap_mappings_lock_obtain();

  if ( map_fixed ) {
    rtems_chain_node* node = rtems_chain_first (&mmap_mappings);
    while ( !rtems_chain_is_tail( &mmap_mappings, node )) {
      /*
       * If the map is fixed see if this address is already mapped. At this
       * point in time if there is an overlap in the mappings we return an
       * error. POSIX allows us to also return successfully by unmapping
       * the overlapping prior mappings.
       */
      current_mapping = (mmap_mapping*) node;
      if ( ( addr >= current_mapping->addr ) &&
           ( addr < ( current_mapping->addr + current_mapping->len )) ) {
        free( mapping );
        mmap_mappings_lock_release( );
        errno = ENXIO;
        return MAP_FAILED;
      }
      node = rtems_chain_next( node );
    }
  }

  /* Populate the data */
  if ( map_private ) {
    if ( !map_anonymous ) {
      /*
       * Use read() for private mappings. This updates atime as needed.
       * Changes to the underlying object will NOT be reflected in the mapping.
       * The underlying object can be removed while the mapping exists.
       */
      r = read( fildes, mapping->addr, len );

      if ( r != len ) {
        mmap_mappings_lock_release( );
        if ( !map_fixed ) {
          free( mapping->addr );
        }
        free( mapping );
        errno = ENXIO;
        return MAP_FAILED;
      }
    } else if ( !map_fixed ) {
      memset( mapping->addr, 0, len );
    }
  } else if ( map_shared ) {
    if ( is_shared_shm ) {
      /* FIXME: This use of implementation details is a hack. */
      mapping->shm = iop_to_shm( iop );
    }

    err = (*iop->pathinfo.handlers->mmap_h)(
        iop, &mapping->addr, len, prot, off );
    if ( err != 0 ) {
      mmap_mappings_lock_release( );
      free( mapping );
      return MAP_FAILED;
    }
  }

  rtems_chain_append_unprotected( &mmap_mappings, &mapping->node );

  mmap_mappings_lock_release( );

  return mapping->addr;
}
Exemplo n.º 25
0
ssize_t readv(
  int                 fd,
  const struct iovec *iov,
  int                 iovcnt
)
{
  ssize_t        total;
  int            v;
  int            bytes;
  rtems_libio_t *iop;
  bool           all_zeros;

  rtems_libio_check_fd( fd );
  iop = rtems_libio_iop( fd );
  rtems_libio_check_is_open( iop );
  rtems_libio_check_permissions_with_error( iop, LIBIO_FLAGS_READ, EBADF );

  /*
   *  Argument validation on IO vector
   */
  if ( !iov )
    rtems_set_errno_and_return_minus_one( EINVAL );

  if ( iovcnt <= 0 )
    rtems_set_errno_and_return_minus_one( EINVAL );

  if ( iovcnt > IOV_MAX )
    rtems_set_errno_and_return_minus_one( EINVAL );

  /*
   *  OpenGroup says that you are supposed to return EINVAL if the
   *  sum of the iov_len values in the iov array would overflow a
   *  ssize_t.
   *
   *  Also we would like to ensure that no IO is performed if there
   *  are obvious errors in the iovec.  So this extra loop ensures
   *  that we do not do anything if there is an argument error.
   */

  all_zeros = true;
  for ( total=0, v=0 ; v < iovcnt ; v++ ) {
    ssize_t old;

    /*
     *  iov[v].iov_len cannot be less than 0 because size_t is unsigned.
     *  So we only check for zero.
     */
    if ( iov[v].iov_base == 0 )
      rtems_set_errno_and_return_minus_one( EINVAL );

    /* check for wrap */
    old    = total;
    total += iov[v].iov_len;
    if ( total < old )
      rtems_set_errno_and_return_minus_one( EINVAL );

    if ( iov[v].iov_len )
      all_zeros = false;
  }

  /*
   *  A readv with all zeros logically has no effect.  Even though
   *  OpenGroup didn't address this case as they did with writev(),
   *  we will handle it the same way for symmetry.
   */
  if ( all_zeros == true ) {
    return 0;
  }

  /*
   *  Now process the readv().
   */
  for ( total=0, v=0 ; v < iovcnt ; v++ ) {
    bytes = (*iop->pathinfo.handlers->read_h)(
      iop,
      iov[v].iov_base,
      iov[v].iov_len
    );

    if ( bytes < 0 )
      return -1;

    if ( bytes > 0 ) {
      iop->offset += bytes;
      total       += bytes;
    }

    if (bytes != iov[ v ].iov_len)
      break;
  }

  return total;
}