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 ); }
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; }
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; }
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 ); }
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; }
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; }
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; }
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 ); }
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; }
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 ); }
/** * 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; }
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 ); }
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; }
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 ); }
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; }
/** * 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 ); }
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; }
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 ); }
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; }
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; }
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; }
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; }
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; }
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; }
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; }