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