mruby-io: introduce HAL for platform abstraction

separates platform-specific code into hal-posix-io and hal-win-io gems,
making mruby-io platform-independent. HAL interface defined in
mrbgems/mruby-io/include/io_hal.h covers file operations, I/O operations,
and process operations. follows mruby-task dependency pattern where HAL
gems depend on feature gem. ws2_32 library linked in hal-win-io gem.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-10-15 11:53:37 +09:00
parent 87c8889726
commit 74ca22f281
9 changed files with 1865 additions and 177 deletions
+8
View File
@@ -0,0 +1,8 @@
MRuby::Gem::Specification.new('hal-posix-io') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'POSIX HAL for mruby-io (Linux, macOS, BSD, Unix)'
# HAL gem depends on feature gem - brings in mruby-io automatically
spec.add_dependency 'mruby-io', core: 'mruby-io'
end
+578
View File
@@ -0,0 +1,578 @@
/*
** io_hal.c - POSIX HAL implementation for mruby-io
**
** See Copyright Notice in mruby.h
**
** POSIX implementation for I/O operations using standard POSIX APIs.
** Supported platforms: Linux, macOS, BSD, Unix
*/
#include <mruby.h>
#include <io_hal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <sys/param.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <pwd.h>
#ifndef __DJGPP__
#include <libgen.h>
#endif
/* Maximum path length */
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
/*
* Helper Functions
*/
/* Convert POSIX struct stat to mrb_io_stat */
static void
convert_stat(const struct stat *src, mrb_io_stat *dst)
{
/* Save time values to avoid macro expansion issues */
time_t atime = src->st_atime;
time_t mtime = src->st_mtime;
time_t ctime = src->st_ctime;
dst->st_dev = (uint64_t)src->st_dev;
dst->st_ino = (uint64_t)src->st_ino;
dst->st_mode = (uint32_t)src->st_mode;
dst->st_nlink = (uint32_t)src->st_nlink;
dst->st_uid = (uint32_t)src->st_uid;
dst->st_gid = (uint32_t)src->st_gid;
dst->st_rdev = (uint64_t)src->st_rdev;
dst->st_size = (int64_t)src->st_size;
/* Assign time values after undefinining macros */
#undef st_atime
#undef st_mtime
#undef st_ctime
dst->st_atime = (int64_t)atime;
dst->st_mtime = (int64_t)mtime;
dst->st_ctime = (int64_t)ctime;
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
dst->st_blksize = (int64_t)src->st_blksize;
#else
dst->st_blksize = 512;
#endif
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
dst->st_blocks = (int64_t)src->st_blocks;
#else
dst->st_blocks = (dst->st_size + 511) / 512;
#endif
}
/*
* File Operations
*/
int
mrb_io_hal_stat(mrb_state *mrb, const char *path, mrb_io_stat *st)
{
struct stat s;
(void)mrb;
if (stat(path, &s) == -1) {
return -1;
}
convert_stat(&s, st);
return 0;
}
int
mrb_io_hal_fstat(mrb_state *mrb, int fd, mrb_io_stat *st)
{
struct stat s;
(void)mrb;
if (fstat(fd, &s) == -1) {
return -1;
}
convert_stat(&s, st);
return 0;
}
int
mrb_io_hal_lstat(mrb_state *mrb, const char *path, mrb_io_stat *st)
{
struct stat s;
(void)mrb;
if (lstat(path, &s) == -1) {
return -1;
}
convert_stat(&s, st);
return 0;
}
int
mrb_io_hal_chmod(mrb_state *mrb, const char *path, uint32_t mode)
{
(void)mrb;
return chmod(path, (mode_t)mode);
}
uint32_t
mrb_io_hal_umask(mrb_state *mrb, int32_t mask)
{
mode_t old;
(void)mrb;
if (mask < 0) {
/* Just query current value */
old = umask(0);
umask(old);
}
else {
old = umask((mode_t)mask);
}
return (uint32_t)old;
}
int
mrb_io_hal_ftruncate(mrb_state *mrb, int fd, int64_t length)
{
(void)mrb;
return ftruncate(fd, (off_t)length);
}
int
mrb_io_hal_flock(mrb_state *mrb, int fd, int operation)
{
(void)mrb;
while (flock(fd, operation) == -1) {
if (errno == EINTR) {
continue; /* Retry on interrupt */
}
return -1;
}
return 0;
}
int
mrb_io_hal_unlink(mrb_state *mrb, const char *path)
{
(void)mrb;
return unlink(path);
}
int
mrb_io_hal_rename(mrb_state *mrb, const char *oldpath, const char *newpath)
{
(void)mrb;
return rename(oldpath, newpath);
}
int
mrb_io_hal_symlink(mrb_state *mrb, const char *target, const char *linkpath)
{
(void)mrb;
return symlink(target, linkpath);
}
int64_t
mrb_io_hal_readlink(mrb_state *mrb, const char *path, char *buf, size_t bufsize)
{
ssize_t rc;
(void)mrb;
rc = readlink(path, buf, bufsize);
return (int64_t)rc;
}
char*
mrb_io_hal_realpath(mrb_state *mrb, const char *path, char *resolved)
{
(void)mrb;
return realpath(path, resolved);
}
char*
mrb_io_hal_getcwd(mrb_state *mrb, char *buf, size_t size)
{
(void)mrb;
return getcwd(buf, size);
}
const char*
mrb_io_hal_getenv(mrb_state *mrb, const char *name)
{
(void)mrb;
return getenv(name);
}
const char*
mrb_io_hal_gethome(mrb_state *mrb, const char *username)
{
const char *home;
if (username == NULL || *username == '\0') {
/* Get current user's home */
home = getenv("HOME");
if (home == NULL) {
errno = ENOENT;
return NULL;
}
}
else {
/* Get specified user's home */
struct passwd *pwd = getpwnam(username);
if (pwd == NULL) {
errno = ENOENT;
return NULL;
}
home = pwd->pw_dir;
}
return home;
}
/*
* Core I/O Operations
*/
int
mrb_io_hal_open(mrb_state *mrb, const char *path, int flags, uint32_t mode)
{
int fd;
(void)mrb;
fd = open(path, flags, (mode_t)mode);
if (fd == -1) {
return -1;
}
/* Set close-on-exec for non-standard descriptors */
#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
if (fd > 2) {
int fd_flags = fcntl(fd, F_GETFD);
if (fd_flags != -1) {
fcntl(fd, F_SETFD, fd_flags | FD_CLOEXEC);
}
}
#endif
return fd;
}
int
mrb_io_hal_close(mrb_state *mrb, int fd)
{
(void)mrb;
return close(fd);
}
int64_t
mrb_io_hal_read(mrb_state *mrb, int fd, void *buf, size_t count)
{
ssize_t n;
(void)mrb;
n = read(fd, buf, count);
return (int64_t)n;
}
int64_t
mrb_io_hal_write(mrb_state *mrb, int fd, const void *buf, size_t count)
{
ssize_t n;
(void)mrb;
n = write(fd, buf, count);
return (int64_t)n;
}
int64_t
mrb_io_hal_lseek(mrb_state *mrb, int fd, int64_t offset, int whence)
{
off_t pos;
int posix_whence;
(void)mrb;
/* Convert MRB_IO_SEEK_* to POSIX SEEK_* */
switch (whence) {
case MRB_IO_SEEK_SET: posix_whence = SEEK_SET; break;
case MRB_IO_SEEK_CUR: posix_whence = SEEK_CUR; break;
case MRB_IO_SEEK_END: posix_whence = SEEK_END; break;
default:
errno = EINVAL;
return -1;
}
pos = lseek(fd, (off_t)offset, posix_whence);
return (int64_t)pos;
}
int
mrb_io_hal_dup(mrb_state *mrb, int fd)
{
int new_fd;
(void)mrb;
new_fd = dup(fd);
if (new_fd == -1) {
return -1;
}
/* Set close-on-exec */
#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
if (new_fd > 2) {
int fd_flags = fcntl(new_fd, F_GETFD);
if (fd_flags != -1) {
fcntl(new_fd, F_SETFD, fd_flags | FD_CLOEXEC);
}
}
#endif
return new_fd;
}
int
mrb_io_hal_fcntl(mrb_state *mrb, int fd, int cmd, int arg)
{
(void)mrb;
return fcntl(fd, cmd, arg);
}
int
mrb_io_hal_isatty(mrb_state *mrb, int fd)
{
(void)mrb;
return isatty(fd) ? 1 : 0;
}
int
mrb_io_hal_pipe(mrb_state *mrb, int fds[2])
{
int ret;
(void)mrb;
ret = pipe(fds);
if (ret == -1) {
return -1;
}
/* Set close-on-exec on both ends */
#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
for (int i = 0; i < 2; i++) {
int fd_flags = fcntl(fds[i], F_GETFD);
if (fd_flags != -1) {
fcntl(fds[i], F_SETFD, fd_flags | FD_CLOEXEC);
}
}
#endif
return 0;
}
/*
* Process Operations
*/
int
mrb_io_hal_spawn_process(mrb_state *mrb, const char *cmd,
int stdin_fd, int stdout_fd, int stderr_fd,
int *pid)
{
pid_t child_pid;
(void)mrb;
/* Skip leading whitespace */
while (*cmd == ' ' || *cmd == '\t' || *cmd == '\n') {
cmd++;
}
if (!*cmd) {
errno = ENOENT;
return -1;
}
child_pid = fork();
if (child_pid == -1) {
/* Fork failed */
return -1;
}
if (child_pid == 0) {
/* Child process */
/* Redirect stdin */
if (stdin_fd != -1) {
dup2(stdin_fd, STDIN_FILENO);
if (stdin_fd > 2) close(stdin_fd);
}
/* Redirect stdout */
if (stdout_fd != -1) {
dup2(stdout_fd, STDOUT_FILENO);
if (stdout_fd > 2) close(stdout_fd);
}
/* Redirect stderr */
if (stderr_fd != -1) {
dup2(stderr_fd, STDERR_FILENO);
if (stderr_fd > 2) close(stderr_fd);
}
/* Close all other file descriptors */
int max_fd = sysconf(_SC_OPEN_MAX);
if (max_fd == -1) max_fd = 1024;
for (int i = 3; i < max_fd; i++) {
close(i);
}
/* Execute command via shell */
execl("/bin/sh", "sh", "-c", cmd, (char*)NULL);
/* If execl returns, it failed */
_exit(127);
}
/* Parent process */
*pid = (int)child_pid;
return 0;
}
int
mrb_io_hal_waitpid(mrb_state *mrb, int pid, int *status, int options)
{
pid_t result;
int stat;
(void)mrb;
result = waitpid((pid_t)pid, &stat, options);
if (result == -1) {
return -1;
}
if (status != NULL) {
*status = stat;
}
return (int)result;
}
/*
* I/O Multiplexing
*/
struct mrb_io_fdset {
fd_set fds;
};
mrb_io_fdset*
mrb_io_hal_fdset_alloc(mrb_state *mrb)
{
mrb_io_fdset *fdset = (mrb_io_fdset*)mrb_malloc(mrb, sizeof(mrb_io_fdset));
FD_ZERO(&fdset->fds);
return fdset;
}
void
mrb_io_hal_fdset_free(mrb_state *mrb, mrb_io_fdset *fdset)
{
if (fdset) {
mrb_free(mrb, fdset);
}
}
void
mrb_io_hal_fdset_zero(mrb_state *mrb, mrb_io_fdset *fdset)
{
(void)mrb;
if (fdset) {
FD_ZERO(&fdset->fds);
}
}
void
mrb_io_hal_fdset_set(mrb_state *mrb, int fd, mrb_io_fdset *fdset)
{
(void)mrb;
if (fdset) {
FD_SET(fd, &fdset->fds);
}
}
int
mrb_io_hal_fdset_isset(mrb_state *mrb, int fd, mrb_io_fdset *fdset)
{
(void)mrb;
if (fdset) {
return FD_ISSET(fd, &fdset->fds);
}
return 0;
}
int
mrb_io_hal_select(mrb_state *mrb, int nfds,
mrb_io_fdset *readfds,
mrb_io_fdset *writefds,
mrb_io_fdset *errorfds,
mrb_io_timeval *timeout)
{
fd_set *r = readfds ? &readfds->fds : NULL;
fd_set *w = writefds ? &writefds->fds : NULL;
fd_set *e = errorfds ? &errorfds->fds : NULL;
struct timeval *tv = NULL;
struct timeval tv_storage;
(void)mrb;
if (timeout) {
tv_storage.tv_sec = (time_t)timeout->tv_sec;
tv_storage.tv_usec = (suseconds_t)timeout->tv_usec;
tv = &tv_storage;
}
return select(nfds, r, w, e, tv);
}
/*
* HAL Initialization/Finalization
*/
void
mrb_io_hal_init(mrb_state *mrb)
{
(void)mrb;
/* No special initialization needed for POSIX */
}
void
mrb_io_hal_final(mrb_state *mrb)
{
(void)mrb;
/* No special cleanup needed for POSIX */
}
/*
* Gem initialization
*/
void
mrb_hal_posix_io_gem_init(mrb_state *mrb)
{
(void)mrb;
/* HAL interface functions are called by mruby-io gem */
}
void
mrb_hal_posix_io_gem_final(mrb_state *mrb)
{
(void)mrb;
/* Cleanup handled by mrb_io_hal_final called from mruby-io */
}
+11
View File
@@ -0,0 +1,11 @@
MRuby::Gem::Specification.new('hal-win-io') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'Windows HAL for mruby-io (Windows, MinGW)'
# HAL gem depends on feature gem - brings in mruby-io automatically
spec.add_dependency 'mruby-io', core: 'mruby-io'
# Link Windows socket library
spec.linker.libraries << "ws2_32"
end
+671
View File
@@ -0,0 +1,671 @@
/*
** io_hal.c - Windows HAL implementation for mruby-io
**
** See Copyright Notice in mruby.h
**
** Windows implementation for I/O operations using Win32 APIs.
** Supported platforms: Windows, MinGW
*/
#include <mruby.h>
#include <io_hal.h>
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
/* Maximum path length */
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
/*
* Helper Functions
*/
/* Convert Windows struct _stat64 to mrb_io_stat */
static void
convert_stat(const struct _stat64 *src, mrb_io_stat *dst)
{
dst->st_dev = (uint64_t)src->st_dev;
dst->st_ino = (uint64_t)src->st_ino;
dst->st_mode = (uint32_t)src->st_mode;
dst->st_nlink = (uint32_t)src->st_nlink;
dst->st_uid = 0; /* Windows doesn't have Unix-style UIDs */
dst->st_gid = 0; /* Windows doesn't have Unix-style GIDs */
dst->st_rdev = (uint64_t)src->st_rdev;
dst->st_size = (int64_t)src->st_size;
dst->st_atime = (int64_t)src->st_atime;
dst->st_mtime = (int64_t)src->st_mtime;
dst->st_ctime = (int64_t)src->st_ctime;
dst->st_blksize = 512;
dst->st_blocks = (dst->st_size + 511) / 512;
}
/* Convert errno to Windows errno */
static void
set_errno_from_win_error(DWORD error)
{
switch (error) {
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
errno = ENOENT;
break;
case ERROR_ACCESS_DENIED:
errno = EACCES;
break;
case ERROR_NOT_ENOUGH_MEMORY:
errno = ENOMEM;
break;
case ERROR_INVALID_HANDLE:
errno = EBADF;
break;
case ERROR_ALREADY_EXISTS:
errno = EEXIST;
break;
default:
errno = EIO;
break;
}
}
/*
* File Operations
*/
int
mrb_io_hal_stat(mrb_state *mrb, const char *path, mrb_io_stat *st)
{
struct _stat64 s;
(void)mrb;
if (_stat64(path, &s) == -1) {
return -1;
}
convert_stat(&s, st);
return 0;
}
int
mrb_io_hal_fstat(mrb_state *mrb, int fd, mrb_io_stat *st)
{
struct _stat64 s;
(void)mrb;
if (_fstat64(fd, &s) == -1) {
return -1;
}
convert_stat(&s, st);
return 0;
}
int
mrb_io_hal_lstat(mrb_state *mrb, const char *path, mrb_io_stat *st)
{
/* Windows doesn't distinguish lstat from stat */
return mrb_io_hal_stat(mrb, path, st);
}
int
mrb_io_hal_chmod(mrb_state *mrb, const char *path, uint32_t mode)
{
(void)mrb;
return _chmod(path, (int)mode);
}
uint32_t
mrb_io_hal_umask(mrb_state *mrb, int32_t mask)
{
int old;
(void)mrb;
if (mask < 0) {
/* Just query current value */
old = _umask(0);
_umask(old);
}
else {
old = _umask((int)mask);
}
return (uint32_t)old;
}
int
mrb_io_hal_ftruncate(mrb_state *mrb, int fd, int64_t length)
{
(void)mrb;
return _chsize_s(fd, length);
}
int
mrb_io_hal_flock(mrb_state *mrb, int fd, int operation)
{
HANDLE h;
OVERLAPPED overlapped;
DWORD flags = 0;
(void)mrb;
h = (HANDLE)_get_osfhandle(fd);
if (h == INVALID_HANDLE_VALUE) {
errno = EBADF;
return -1;
}
memset(&overlapped, 0, sizeof(overlapped));
if (operation & MRB_IO_LOCK_UN) {
if (!UnlockFileEx(h, 0, MAXDWORD, MAXDWORD, &overlapped)) {
set_errno_from_win_error(GetLastError());
return -1;
}
return 0;
}
if (operation & MRB_IO_LOCK_EX) {
flags |= LOCKFILE_EXCLUSIVE_LOCK;
}
if (operation & MRB_IO_LOCK_NB) {
flags |= LOCKFILE_FAIL_IMMEDIATELY;
}
if (!LockFileEx(h, flags, 0, MAXDWORD, MAXDWORD, &overlapped)) {
set_errno_from_win_error(GetLastError());
return -1;
}
return 0;
}
int
mrb_io_hal_unlink(mrb_state *mrb, const char *path)
{
(void)mrb;
return _unlink(path);
}
int
mrb_io_hal_rename(mrb_state *mrb, const char *oldpath, const char *newpath)
{
(void)mrb;
return rename(oldpath, newpath);
}
int
mrb_io_hal_symlink(mrb_state *mrb, const char *target, const char *linkpath)
{
DWORD flags = 0;
(void)mrb;
/* Check if target is a directory */
DWORD attrs = GetFileAttributes(target);
if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
}
if (!CreateSymbolicLink(linkpath, target, flags)) {
set_errno_from_win_error(GetLastError());
return -1;
}
return 0;
}
int64_t
mrb_io_hal_readlink(mrb_state *mrb, const char *path, char *buf, size_t bufsize)
{
HANDLE h;
DWORD ret;
char temp[PATH_MAX];
(void)mrb;
h = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (h == INVALID_HANDLE_VALUE) {
set_errno_from_win_error(GetLastError());
return -1;
}
ret = GetFinalPathNameByHandle(h, temp, PATH_MAX, FILE_NAME_NORMALIZED);
CloseHandle(h);
if (ret == 0 || ret >= PATH_MAX) {
errno = EIO;
return -1;
}
/* Remove \\?\ prefix if present */
const char *result = temp;
if (strncmp(temp, "\\\\?\\", 4) == 0) {
result = temp + 4;
}
size_t len = strlen(result);
if (len > bufsize) {
len = bufsize;
}
memcpy(buf, result, len);
return (int64_t)len;
}
char*
mrb_io_hal_realpath(mrb_state *mrb, const char *path, char *resolved)
{
DWORD ret;
(void)mrb;
ret = GetFullPathName(path, PATH_MAX, resolved, NULL);
if (ret == 0 || ret >= PATH_MAX) {
set_errno_from_win_error(GetLastError());
return NULL;
}
return resolved;
}
char*
mrb_io_hal_getcwd(mrb_state *mrb, char *buf, size_t size)
{
(void)mrb;
return _getcwd(buf, (int)size);
}
const char*
mrb_io_hal_getenv(mrb_state *mrb, const char *name)
{
(void)mrb;
return getenv(name);
}
const char*
mrb_io_hal_gethome(mrb_state *mrb, const char *username)
{
const char *home;
(void)mrb;
if (username != NULL && *username != '\0') {
/* Windows doesn't have a simple way to get other users' home directories */
errno = ENOSYS;
return NULL;
}
/* Try USERPROFILE first, then HOMEDRIVE+HOMEPATH */
home = getenv("USERPROFILE");
if (home == NULL) {
const char *homedrive = getenv("HOMEDRIVE");
const char *homepath = getenv("HOMEPATH");
if (homedrive && homepath) {
static char homebuf[PATH_MAX];
snprintf(homebuf, PATH_MAX, "%s%s", homedrive, homepath);
return homebuf;
}
errno = ENOENT;
return NULL;
}
return home;
}
/*
* Core I/O Operations
*/
int
mrb_io_hal_open(mrb_state *mrb, const char *path, int flags, uint32_t mode)
{
int fd;
(void)mrb;
/* Windows uses _open with slightly different flags */
fd = _open(path, flags | _O_BINARY, (int)mode);
if (fd == -1) {
return -1;
}
/* Set close-on-exec for non-standard descriptors */
if (fd > 2) {
SetHandleInformation((HANDLE)_get_osfhandle(fd), HANDLE_FLAG_INHERIT, 0);
}
return fd;
}
int
mrb_io_hal_close(mrb_state *mrb, int fd)
{
(void)mrb;
return _close(fd);
}
int64_t
mrb_io_hal_read(mrb_state *mrb, int fd, void *buf, size_t count)
{
int n;
(void)mrb;
n = _read(fd, buf, (unsigned int)count);
return (int64_t)n;
}
int64_t
mrb_io_hal_write(mrb_state *mrb, int fd, const void *buf, size_t count)
{
int n;
(void)mrb;
n = _write(fd, buf, (unsigned int)count);
return (int64_t)n;
}
int64_t
mrb_io_hal_lseek(mrb_state *mrb, int fd, int64_t offset, int whence)
{
__int64 pos;
int win_whence;
(void)mrb;
/* Convert MRB_IO_SEEK_* to Windows SEEK_* */
switch (whence) {
case MRB_IO_SEEK_SET: win_whence = SEEK_SET; break;
case MRB_IO_SEEK_CUR: win_whence = SEEK_CUR; break;
case MRB_IO_SEEK_END: win_whence = SEEK_END; break;
default:
errno = EINVAL;
return -1;
}
pos = _lseeki64(fd, (__int64)offset, win_whence);
return (int64_t)pos;
}
int
mrb_io_hal_dup(mrb_state *mrb, int fd)
{
int new_fd;
(void)mrb;
new_fd = _dup(fd);
if (new_fd == -1) {
return -1;
}
/* Set close-on-exec */
if (new_fd > 2) {
SetHandleInformation((HANDLE)_get_osfhandle(new_fd), HANDLE_FLAG_INHERIT, 0);
}
return new_fd;
}
int
mrb_io_hal_fcntl(mrb_state *mrb, int fd, int cmd, int arg)
{
/* Windows has limited fcntl support */
(void)mrb;
(void)fd;
(void)cmd;
(void)arg;
errno = ENOSYS;
return -1;
}
int
mrb_io_hal_isatty(mrb_state *mrb, int fd)
{
(void)mrb;
return _isatty(fd) ? 1 : 0;
}
int
mrb_io_hal_pipe(mrb_state *mrb, int fds[2])
{
int ret;
(void)mrb;
ret = _pipe(fds, 4096, _O_BINARY);
if (ret == -1) {
return -1;
}
/* Set close-on-exec on both ends */
SetHandleInformation((HANDLE)_get_osfhandle(fds[0]), HANDLE_FLAG_INHERIT, 0);
SetHandleInformation((HANDLE)_get_osfhandle(fds[1]), HANDLE_FLAG_INHERIT, 0);
return 0;
}
/*
* Process Operations
*/
int
mrb_io_hal_spawn_process(mrb_state *mrb, const char *cmd,
int stdin_fd, int stdout_fd, int stderr_fd,
int *pid)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
HANDLE h_stdin = INVALID_HANDLE_VALUE;
HANDLE h_stdout = INVALID_HANDLE_VALUE;
HANDLE h_stderr = INVALID_HANDLE_VALUE;
char cmdline[8192];
BOOL ret;
(void)mrb;
/* Skip leading whitespace */
while (*cmd == ' ' || *cmd == '\t' || *cmd == '\n') {
cmd++;
}
if (!*cmd) {
errno = ENOENT;
return -1;
}
/* Build command line - use cmd.exe to execute */
snprintf(cmdline, sizeof(cmdline), "cmd.exe /c %s", cmd);
/* Setup startup info */
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
/* Convert file descriptors to handles */
if (stdin_fd != -1) {
h_stdin = (HANDLE)_get_osfhandle(stdin_fd);
si.hStdInput = h_stdin;
}
else {
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
}
if (stdout_fd != -1) {
h_stdout = (HANDLE)_get_osfhandle(stdout_fd);
si.hStdOutput = h_stdout;
}
else {
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
}
if (stderr_fd != -1) {
h_stderr = (HANDLE)_get_osfhandle(stderr_fd);
si.hStdError = h_stderr;
}
else {
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
}
/* Create process */
memset(&pi, 0, sizeof(pi));
ret = CreateProcess(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
if (!ret) {
set_errno_from_win_error(GetLastError());
return -1;
}
/* Close thread handle - we don't need it */
CloseHandle(pi.hThread);
/* Store process handle as PID (will be used in waitpid) */
*pid = (int)pi.hProcess;
return 0;
}
int
mrb_io_hal_waitpid(mrb_state *mrb, int pid, int *status, int options)
{
HANDLE h = (HANDLE)pid;
DWORD wait_result;
DWORD exit_code;
DWORD timeout;
(void)mrb;
/* Convert options to timeout */
timeout = (options != 0) ? 0 : INFINITE;
wait_result = WaitForSingleObject(h, timeout);
if (wait_result == WAIT_TIMEOUT) {
return 0; /* Non-blocking wait, no change */
}
if (wait_result != WAIT_OBJECT_0) {
set_errno_from_win_error(GetLastError());
return -1;
}
/* Get exit code */
if (!GetExitCodeProcess(h, &exit_code)) {
set_errno_from_win_error(GetLastError());
return -1;
}
if (status != NULL) {
/* Store exit code in status (shifted to match Unix convention) */
*status = (int)(exit_code << 8);
}
/* Close process handle */
CloseHandle(h);
return pid;
}
/*
* I/O Multiplexing
*/
struct mrb_io_fdset {
fd_set fds;
};
mrb_io_fdset*
mrb_io_hal_fdset_alloc(mrb_state *mrb)
{
mrb_io_fdset *fdset = (mrb_io_fdset*)mrb_malloc(mrb, sizeof(mrb_io_fdset));
FD_ZERO(&fdset->fds);
return fdset;
}
void
mrb_io_hal_fdset_free(mrb_state *mrb, mrb_io_fdset *fdset)
{
if (fdset) {
mrb_free(mrb, fdset);
}
}
void
mrb_io_hal_fdset_zero(mrb_state *mrb, mrb_io_fdset *fdset)
{
(void)mrb;
if (fdset) {
FD_ZERO(&fdset->fds);
}
}
void
mrb_io_hal_fdset_set(mrb_state *mrb, int fd, mrb_io_fdset *fdset)
{
(void)mrb;
if (fdset) {
FD_SET(fd, &fdset->fds);
}
}
int
mrb_io_hal_fdset_isset(mrb_state *mrb, int fd, mrb_io_fdset *fdset)
{
(void)mrb;
if (fdset) {
return FD_ISSET(fd, &fdset->fds);
}
return 0;
}
int
mrb_io_hal_select(mrb_state *mrb, int nfds,
mrb_io_fdset *readfds,
mrb_io_fdset *writefds,
mrb_io_fdset *errorfds,
mrb_io_timeval *timeout)
{
fd_set *r = readfds ? &readfds->fds : NULL;
fd_set *w = writefds ? &writefds->fds : NULL;
fd_set *e = errorfds ? &errorfds->fds : NULL;
struct timeval *tv = NULL;
struct timeval tv_storage;
(void)mrb;
(void)nfds; /* Windows select() doesn't use nfds */
if (timeout) {
tv_storage.tv_sec = (long)timeout->tv_sec;
tv_storage.tv_usec = (long)timeout->tv_usec;
tv = &tv_storage;
}
return select(0, r, w, e, tv);
}
/*
* HAL Initialization/Finalization
*/
void
mrb_io_hal_init(mrb_state *mrb)
{
(void)mrb;
/* Initialize Winsock for select() support */
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
}
void
mrb_io_hal_final(mrb_state *mrb)
{
(void)mrb;
/* Cleanup Winsock */
WSACleanup();
}
/*
* Gem initialization
*/
void
mrb_hal_win_io_gem_init(mrb_state *mrb)
{
(void)mrb;
/* HAL interface functions are called by mruby-io gem */
}
void
mrb_hal_win_io_gem_final(mrb_state *mrb)
{
(void)mrb;
/* Cleanup handled by mrb_io_hal_final called from mruby-io */
}
+451
View File
@@ -0,0 +1,451 @@
/*
** io_hal.h - IO Hardware Abstraction Layer (HAL)
**
** See Copyright Notice in mruby.h
**
** This header defines the HAL interface for platform-specific I/O operations.
** Platform-specific implementations (hal-posix-io, hal-win-io, etc.) must
** provide all functions declared here.
*/
#ifndef MRUBY_IO_HAL_H
#define MRUBY_IO_HAL_H
#include <mruby.h>
#include <stdint.h>
/*
* Platform-independent type definitions
*/
/* File status structure - platform-independent representation */
typedef struct mrb_io_stat {
uint64_t st_dev; /* Device ID */
uint64_t st_ino; /* Inode number */
uint32_t st_mode; /* File mode/permissions */
uint32_t st_nlink; /* Number of hard links */
uint32_t st_uid; /* User ID */
uint32_t st_gid; /* Group ID */
uint64_t st_rdev; /* Device ID (if special file) */
int64_t st_size; /* File size in bytes */
int64_t st_atime; /* Last access time */
int64_t st_mtime; /* Last modification time */
int64_t st_ctime; /* Last status change time */
int64_t st_blksize; /* Block size for filesystem I/O */
int64_t st_blocks; /* Number of 512B blocks allocated */
} mrb_io_stat;
/* Timeval structure for select() */
typedef struct mrb_io_timeval {
int64_t tv_sec; /* Seconds */
int64_t tv_usec; /* Microseconds */
} mrb_io_timeval;
/* File descriptor set for select() */
typedef struct mrb_io_fdset mrb_io_fdset;
/*
* File mode constants (POSIX-style)
*/
/* File type masks */
#define MRB_IO_S_IFMT 0170000 /* Type of file mask */
#define MRB_IO_S_IFSOCK 0140000 /* Socket */
#define MRB_IO_S_IFLNK 0120000 /* Symbolic link */
#define MRB_IO_S_IFREG 0100000 /* Regular file */
#define MRB_IO_S_IFBLK 0060000 /* Block device */
#define MRB_IO_S_IFDIR 0040000 /* Directory */
#define MRB_IO_S_IFCHR 0020000 /* Character device */
#define MRB_IO_S_IFIFO 0010000 /* FIFO */
/* File type test macros */
#define MRB_IO_S_ISREG(m) (((m) & MRB_IO_S_IFMT) == MRB_IO_S_IFREG)
#define MRB_IO_S_ISDIR(m) (((m) & MRB_IO_S_IFMT) == MRB_IO_S_IFDIR)
#define MRB_IO_S_ISCHR(m) (((m) & MRB_IO_S_IFMT) == MRB_IO_S_IFCHR)
#define MRB_IO_S_ISBLK(m) (((m) & MRB_IO_S_IFMT) == MRB_IO_S_IFBLK)
#define MRB_IO_S_ISFIFO(m) (((m) & MRB_IO_S_IFMT) == MRB_IO_S_IFIFO)
#define MRB_IO_S_ISLNK(m) (((m) & MRB_IO_S_IFMT) == MRB_IO_S_IFLNK)
#define MRB_IO_S_ISSOCK(m) (((m) & MRB_IO_S_IFMT) == MRB_IO_S_IFSOCK)
/* File lock constants */
#define MRB_IO_LOCK_SH 1 /* Shared lock */
#define MRB_IO_LOCK_EX 2 /* Exclusive lock */
#define MRB_IO_LOCK_NB 4 /* Non-blocking */
#define MRB_IO_LOCK_UN 8 /* Unlock */
/* Seek constants */
#define MRB_IO_SEEK_SET 0 /* Seek from beginning */
#define MRB_IO_SEEK_CUR 1 /* Seek from current position */
#define MRB_IO_SEEK_END 2 /* Seek from end */
/*
* HAL Interface - File Operations
*/
/**
* Get file status by path
*
* @param mrb mruby state
* @param path File path (UTF-8)
* @param st Output stat structure
* @return 0 on success, -1 on error (sets errno)
*/
int mrb_io_hal_stat(mrb_state *mrb, const char *path, mrb_io_stat *st);
/**
* Get file status by descriptor
*
* @param mrb mruby state
* @param fd File descriptor
* @param st Output stat structure
* @return 0 on success, -1 on error (sets errno)
*/
int mrb_io_hal_fstat(mrb_state *mrb, int fd, mrb_io_stat *st);
/**
* Get link status (don't follow symlinks)
*
* @param mrb mruby state
* @param path File path (UTF-8)
* @param st Output stat structure
* @return 0 on success, -1 on error (sets errno)
*/
int mrb_io_hal_lstat(mrb_state *mrb, const char *path, mrb_io_stat *st);
/**
* Change file permissions
*
* @param mrb mruby state
* @param path File path (UTF-8)
* @param mode New permission mode
* @return 0 on success, -1 on error (sets errno)
*/
int mrb_io_hal_chmod(mrb_state *mrb, const char *path, uint32_t mode);
/**
* Set/get file creation mask
*
* @param mrb mruby state
* @param mask New umask value (if < 0, only returns current value)
* @return Previous umask value
*/
uint32_t mrb_io_hal_umask(mrb_state *mrb, int32_t mask);
/**
* Truncate file to specified length
*
* @param mrb mruby state
* @param fd File descriptor
* @param length New file length
* @return 0 on success, -1 on error (sets errno)
*/
int mrb_io_hal_ftruncate(mrb_state *mrb, int fd, int64_t length);
/**
* Apply or remove advisory lock on file
*
* @param mrb mruby state
* @param fd File descriptor
* @param operation Lock operation (MRB_IO_LOCK_*)
* @return 0 on success, -1 on error (sets errno)
*/
int mrb_io_hal_flock(mrb_state *mrb, int fd, int operation);
/**
* Delete a file
*
* @param mrb mruby state
* @param path File path (UTF-8)
* @return 0 on success, -1 on error (sets errno)
*/
int mrb_io_hal_unlink(mrb_state *mrb, const char *path);
/**
* Rename a file
*
* @param mrb mruby state
* @param oldpath Old file path (UTF-8)
* @param newpath New file path (UTF-8)
* @return 0 on success, -1 on error (sets errno)
*/
int mrb_io_hal_rename(mrb_state *mrb, const char *oldpath, const char *newpath);
/**
* Create a symbolic link
*
* @param mrb mruby state
* @param target Target path (UTF-8)
* @param linkpath Link path (UTF-8)
* @return 0 on success, -1 on error (sets errno)
*/
int mrb_io_hal_symlink(mrb_state *mrb, const char *target, const char *linkpath);
/**
* Read value of a symbolic link
*
* @param mrb mruby state
* @param path Symlink path (UTF-8)
* @param buf Buffer to store result (UTF-8)
* @param bufsize Buffer size
* @return Number of bytes placed in buf, -1 on error (sets errno)
*/
int64_t mrb_io_hal_readlink(mrb_state *mrb, const char *path, char *buf, size_t bufsize);
/**
* Resolve pathname to absolute path
*
* @param mrb mruby state
* @param path Pathname (UTF-8)
* @param resolved Buffer for resolved path (must be at least PATH_MAX size)
* @return Pointer to resolved on success, NULL on error (sets errno)
*/
char* mrb_io_hal_realpath(mrb_state *mrb, const char *path, char *resolved);
/**
* Get current working directory
*
* @param mrb mruby state
* @param buf Buffer to store result (UTF-8)
* @param size Buffer size
* @return Pointer to buf on success, NULL on error (sets errno)
*/
char* mrb_io_hal_getcwd(mrb_state *mrb, char *buf, size_t size);
/**
* Get environment variable
*
* @param mrb mruby state
* @param name Variable name
* @return Value string (UTF-8) or NULL if not found
*/
const char* mrb_io_hal_getenv(mrb_state *mrb, const char *name);
/**
* Get user's home directory
*
* @param mrb mruby state
* @param username User name (NULL for current user)
* @return Home directory path (UTF-8) or NULL on error (sets errno)
*/
const char* mrb_io_hal_gethome(mrb_state *mrb, const char *username);
/*
* HAL Interface - Core I/O Operations
*/
/**
* Open file
*
* @param mrb mruby state
* @param path File path (UTF-8)
* @param flags Open flags (O_RDONLY, O_WRONLY, O_RDWR, etc.)
* @param mode Creation mode (used if O_CREAT is set)
* @return File descriptor on success, -1 on error (sets errno)
*/
int mrb_io_hal_open(mrb_state *mrb, const char *path, int flags, uint32_t mode);
/**
* Close file descriptor
*
* @param mrb mruby state
* @param fd File descriptor
* @return 0 on success, -1 on error (sets errno)
*/
int mrb_io_hal_close(mrb_state *mrb, int fd);
/**
* Read from file descriptor
*
* @param mrb mruby state
* @param fd File descriptor
* @param buf Buffer to store data
* @param count Maximum bytes to read
* @return Number of bytes read, 0 on EOF, -1 on error (sets errno)
*/
int64_t mrb_io_hal_read(mrb_state *mrb, int fd, void *buf, size_t count);
/**
* Write to file descriptor
*
* @param mrb mruby state
* @param fd File descriptor
* @param buf Data to write
* @param count Number of bytes to write
* @return Number of bytes written, -1 on error (sets errno)
*/
int64_t mrb_io_hal_write(mrb_state *mrb, int fd, const void *buf, size_t count);
/**
* Reposition file offset
*
* @param mrb mruby state
* @param fd File descriptor
* @param offset Offset value
* @param whence Reference point (MRB_IO_SEEK_SET/CUR/END)
* @return New offset from beginning of file, -1 on error (sets errno)
*/
int64_t mrb_io_hal_lseek(mrb_state *mrb, int fd, int64_t offset, int whence);
/**
* Duplicate file descriptor
*
* @param mrb mruby state
* @param fd File descriptor to duplicate
* @return New descriptor on success, -1 on error (sets errno)
*/
int mrb_io_hal_dup(mrb_state *mrb, int fd);
/**
* Manipulate file descriptor
*
* @param mrb mruby state
* @param fd File descriptor
* @param cmd Command (F_GETFD, F_SETFD, etc.)
* @param arg Command argument
* @return Depends on command, -1 on error (sets errno)
*/
int mrb_io_hal_fcntl(mrb_state *mrb, int fd, int cmd, int arg);
/**
* Check if descriptor refers to terminal
*
* @param mrb mruby state
* @param fd File descriptor
* @return 1 if TTY, 0 if not, -1 on error (sets errno)
*/
int mrb_io_hal_isatty(mrb_state *mrb, int fd);
/**
* Create pipe
*
* @param mrb mruby state
* @param fds Array to store two file descriptors [read_end, write_end]
* @return 0 on success, -1 on error (sets errno)
*/
int mrb_io_hal_pipe(mrb_state *mrb, int fds[2]);
/*
* HAL Interface - Process Operations
*/
/**
* Spawn a new process
*
* Creates a new process and executes the command. File descriptors can be
* redirected for stdin/stdout/stderr (-1 means don't redirect).
*
* POSIX: Uses fork() + dup2() + execl()
* Windows: Uses CreateProcess() with STARTUPINFO
*
* @param mrb mruby state
* @param cmd Command to execute (shell command)
* @param stdin_fd File descriptor to use for stdin (-1 = don't redirect)
* @param stdout_fd File descriptor to use for stdout (-1 = don't redirect)
* @param stderr_fd File descriptor to use for stderr (-1 = don't redirect)
* @param pid Output parameter for process ID
* @return 0 on success, -1 on error (sets errno)
*/
int mrb_io_hal_spawn_process(mrb_state *mrb, const char *cmd,
int stdin_fd, int stdout_fd, int stderr_fd,
int *pid);
/**
* Wait for process to change state
*
* @param mrb mruby state
* @param pid Process ID to wait for
* @param status Output parameter for exit status
* @param options Wait options (0 for blocking wait)
* @return Process ID on success, -1 on error (sets errno)
*/
int mrb_io_hal_waitpid(mrb_state *mrb, int pid, int *status, int options);
/*
* HAL Interface - I/O Multiplexing
*/
/**
* Allocate file descriptor set
*
* @param mrb mruby state
* @return Pointer to fdset or NULL on error
*/
mrb_io_fdset* mrb_io_hal_fdset_alloc(mrb_state *mrb);
/**
* Free file descriptor set
*
* @param mrb mruby state
* @param fdset File descriptor set to free
*/
void mrb_io_hal_fdset_free(mrb_state *mrb, mrb_io_fdset *fdset);
/**
* Clear file descriptor set
*
* @param mrb mruby state
* @param fdset File descriptor set
*/
void mrb_io_hal_fdset_zero(mrb_state *mrb, mrb_io_fdset *fdset);
/**
* Add descriptor to set
*
* @param mrb mruby state
* @param fd File descriptor
* @param fdset File descriptor set
*/
void mrb_io_hal_fdset_set(mrb_state *mrb, int fd, mrb_io_fdset *fdset);
/**
* Check if descriptor is in set
*
* @param mrb mruby state
* @param fd File descriptor
* @param fdset File descriptor set
* @return Non-zero if fd is in set, 0 otherwise
*/
int mrb_io_hal_fdset_isset(mrb_state *mrb, int fd, mrb_io_fdset *fdset);
/**
* Monitor multiple file descriptors
*
* @param mrb mruby state
* @param nfds Highest file descriptor number + 1
* @param readfds Set of descriptors to check for reading (NULL = ignore)
* @param writefds Set of descriptors to check for writing (NULL = ignore)
* @param errorfds Set of descriptors to check for errors (NULL = ignore)
* @param timeout Timeout (NULL = block indefinitely)
* @return Number of ready descriptors, 0 on timeout, -1 on error (sets errno)
*/
int mrb_io_hal_select(mrb_state *mrb, int nfds,
mrb_io_fdset *readfds,
mrb_io_fdset *writefds,
mrb_io_fdset *errorfds,
mrb_io_timeval *timeout);
/*
* HAL Initialization/Finalization
*/
/**
* Initialize I/O HAL
*
* Called during gem initialization. Platform-specific HAL should perform
* any necessary setup here.
*
* @param mrb mruby state
*/
void mrb_io_hal_init(mrb_state *mrb);
/**
* Finalize I/O HAL
*
* Called during gem finalization. Platform-specific HAL should perform
* any necessary cleanup here.
*
* @param mrb mruby state
*/
void mrb_io_hal_final(mrb_state *mrb);
#endif /* MRUBY_IO_HAL_H */
+26 -3
View File
@@ -3,9 +3,32 @@ MRuby::Gem::Specification.new('mruby-io') do |spec|
spec.authors = ['Internet Initiative Japan Inc.', 'mruby developers']
spec.summary = 'IO and File class'
if spec.for_windows?
spec.linker.libraries << "ws2_32"
end
spec.build.defines << "HAVE_MRUBY_IO_GEM"
spec.add_test_dependency 'mruby-time', core: 'mruby-time'
# Check if HAL gem is loaded
# HAL gems must be explicitly specified in build config (recommended) or via auto-selection below
spec.build.gems.one? { |g| g.name =~ /^hal-.*-io$/ } or begin
# No HAL found - determine appropriate error message or auto-load
suggested_hal = if spec.for_windows?
'hal-win-io'
elsif RUBY_PLATFORM =~ /linux|darwin|bsd/
'hal-posix-io'
else
nil
end
if suggested_hal
# Auto-load HAL gem for convenience (for development)
# This works because HAL gems declare dependency on mruby-io
warn "mruby-io: No HAL specified, loading #{suggested_hal} (explicit selection recommended)"
spec.build.gem core: suggested_hal
else
# Unknown platform - fail with helpful message
fail "mruby-io: No HAL available for platform '#{RUBY_PLATFORM}'.\n" \
"Please specify HAL gem explicitly in your build config:\n" \
" conf.gem core: 'hal-posix-io' # For Linux/macOS/BSD\n" \
" conf.gem core: 'hal-win-io' # For Windows"
end
end
end
+50 -79
View File
@@ -10,6 +10,7 @@
#include <mruby/ext/io.h>
#include <mruby/error.h>
#include <mruby/presym.h>
#include <io_hal.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -19,6 +20,18 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
/* Undefine system macros that conflict with mrb_io_stat field names */
#ifdef st_atime
#undef st_atime
#endif
#ifdef st_mtime
#undef st_mtime
#endif
#ifdef st_ctime
#undef st_ctime
#endif
#if defined(_WIN32)
#include <windows.h>
#include <io.h>
@@ -62,17 +75,18 @@
#define DIRSEP_P(ch) ((ch) == '/')
#endif
/* Use HAL lock constants */
#ifndef LOCK_SH
#define LOCK_SH 1
#define LOCK_SH MRB_IO_LOCK_SH
#endif
#ifndef LOCK_EX
#define LOCK_EX 2
#define LOCK_EX MRB_IO_LOCK_EX
#endif
#ifndef LOCK_NB
#define LOCK_NB 4
#define LOCK_NB MRB_IO_LOCK_NB
#endif
#ifndef LOCK_UN
#define LOCK_UN 8
#define LOCK_UN MRB_IO_LOCK_UN
#endif
#if !defined(_WIN32) || defined(MRB_MINGW32_LEGACY)
@@ -117,21 +131,16 @@ flock(int fd, int operation)
static mrb_value
mrb_file_s_umask(mrb_state *mrb, mrb_value klass)
{
#if defined(_WIN32)
/* nothing to do on windows */
return mrb_fixnum_value(0);
mrb_int mask;
uint32_t omask;
#else
mrb_int mask, omask;
if (mrb_get_args(mrb, "|i", &mask) == 0) {
omask = umask(0);
umask(omask);
omask = mrb_io_hal_umask(mrb, -1);
}
else {
omask = umask(mask);
omask = mrb_io_hal_umask(mrb, (int32_t)mask);
}
return mrb_fixnum_value(omask);
#endif
}
/*
@@ -155,7 +164,7 @@ mrb_file_s_unlink(mrb_state *mrb, mrb_value obj)
mrb_ensure_string_type(mrb, pathv);
const char *utf8_path = RSTRING_CSTR(mrb, pathv);
char *path = mrb_locale_from_utf8(utf8_path, -1);
if (UNLINK(path) < 0) {
if (mrb_io_hal_unlink(mrb, path) < 0) {
mrb_locale_free(path);
mrb_sys_fail(mrb, utf8_path);
}
@@ -180,9 +189,12 @@ mrb_file_s_rename(mrb_state *mrb, mrb_value obj)
mrb_get_args(mrb, "SS", &from, &to);
char *src = mrb_locale_from_utf8(RSTRING_CSTR(mrb, from), -1);
char *dst = mrb_locale_from_utf8(RSTRING_CSTR(mrb, to), -1);
if (rename(src, dst) < 0) {
if (mrb_io_hal_rename(mrb, src, dst) < 0) {
#if defined(_WIN32)
if (CHMOD(dst, 0666) == 0 && UNLINK(dst) == 0 && rename(src, dst) == 0) {
/* Windows retry: try chmod+unlink+rename if initial rename fails */
if (mrb_io_hal_chmod(mrb, dst, 0666) == 0 &&
mrb_io_hal_unlink(mrb, dst) == 0 &&
mrb_io_hal_rename(mrb, src, dst) == 0) {
mrb_locale_free(src);
mrb_locale_free(dst);
return mrb_fixnum_value(0);
@@ -389,7 +401,7 @@ mrb_file_realpath(mrb_state *mrb, mrb_value klass)
}
char *cpath = mrb_locale_from_utf8(RSTRING_CSTR(mrb, pathname), -1);
mrb_value result = mrb_str_new_capa(mrb, PATH_MAX);
if (realpath(cpath, RSTRING_PTR(result)) == NULL) {
if (mrb_io_hal_realpath(mrb, cpath, RSTRING_PTR(result)) == NULL) {
mrb_locale_free(cpath);
mrb_sys_fail(mrb, RSTRING_CSTR(mrb, pathname));
return result; /* not reached */
@@ -404,7 +416,7 @@ path_getwd(mrb_state *mrb)
{
char buf[MAXPATHLEN];
if (GETCWD(buf, MAXPATHLEN) == NULL) {
if (mrb_io_hal_getcwd(mrb, buf, MAXPATHLEN) == NULL) {
mrb_sys_fail(mrb, "getcwd(2)");
}
char *utf8 = mrb_utf8_from_locale(buf, -1);
@@ -516,12 +528,7 @@ path_gethome(mrb_state *mrb, const char **pathp)
ptrdiff_t len = *pathp - username;
if (len == 0) {
home = getenv("HOME");
#ifdef _WIN32
if (home == NULL) {
home = getenv("USERPROFILE");
}
#endif
home = mrb_io_hal_gethome(mrb, NULL);
if (home == NULL) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "couldn't find HOME environment -- expanding '~'");
}
@@ -531,18 +538,13 @@ path_gethome(mrb_state *mrb, const char **pathp)
}
else {
const char *uname = RSTRING_CSTR(mrb, mrb_str_new(mrb, username, (mrb_int)len));
#if defined(_WIN32) || defined(MRB_IO_NO_PWNAM)
mrb_raisef(mrb, E_ARGUMENT_ERROR, "user %s doesn't exist", uname);
#else
const struct passwd *pwd = getpwnam(uname);
if (pwd == NULL) {
home = mrb_io_hal_gethome(mrb, uname);
if (home == NULL) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "user %s doesn't exist", uname);
}
home = pwd->pw_dir;
if (!path_absolute_p(home)) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "non-absolute home of ~%s", uname);
}
#endif
}
home = mrb_utf8_from_locale(home, -1);
path = mrb_str_new_cstr(mrb, home);
@@ -689,10 +691,10 @@ static mrb_value
mrb_file_atime(mrb_state *mrb, mrb_value self)
{
int fd = mrb_io_fileno(mrb, self);
mrb_stat st;
mrb_io_stat st;
mrb->c->ci->mid = 0;
if (mrb_fstat(fd, &st) == -1)
if (mrb_io_hal_fstat(mrb, fd, &st) == -1)
mrb_sys_fail(mrb, "atime");
if (TIME_OVERFLOW_P(st.st_atime)) {
TIME_BIGTIME(mrb, st.st_atime);
@@ -704,10 +706,10 @@ static mrb_value
mrb_file_ctime(mrb_state *mrb, mrb_value self)
{
int fd = mrb_io_fileno(mrb, self);
mrb_stat st;
mrb_io_stat st;
mrb->c->ci->mid = 0;
if (mrb_fstat(fd, &st) == -1)
if (mrb_io_hal_fstat(mrb, fd, &st) == -1)
mrb_sys_fail(mrb, "ctime");
if (TIME_OVERFLOW_P(st.st_ctime)) {
TIME_BIGTIME(mrb, st.st_ctime);
@@ -719,10 +721,10 @@ static mrb_value
mrb_file_mtime(mrb_state *mrb, mrb_value self)
{
int fd = mrb_io_fileno(mrb, self);
mrb_stat st;
mrb_io_stat st;
mrb->c->ci->mid = 0;
if (mrb_fstat(fd, &st) == -1)
if (mrb_io_hal_fstat(mrb, fd, &st) == -1)
mrb_sys_fail(mrb, "mtime");
if (TIME_OVERFLOW_P(st.st_mtime)) {
TIME_BIGTIME(mrb, st.st_mtime);
@@ -752,7 +754,7 @@ mrb_file_flock(mrb_state *mrb, mrb_value self)
mrb_get_args(mrb, "i", &operation);
int fd = mrb_io_fileno(mrb, self);
while (flock(fd, (int)operation) == -1) {
while (mrb_io_hal_flock(mrb, fd, (int)operation) == -1) {
switch (errno) {
case EINTR:
/* retry */
@@ -761,7 +763,7 @@ mrb_file_flock(mrb_state *mrb, mrb_value self)
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
case EWOULDBLOCK: /* FreeBSD OpenBSD Linux */
#endif
if (operation & LOCK_NB) {
if (operation & MRB_IO_LOCK_NB) {
return mrb_false_value();
}
/* FALLTHRU - should not happen */
@@ -785,9 +787,9 @@ mrb_file_flock(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_file_size(mrb_state *mrb, mrb_value self)
{
mrb_stat st;
mrb_io_stat st;
int fd = mrb_io_fileno(mrb, self);
if (mrb_fstat(fd, &st) == -1) {
if (mrb_io_hal_fstat(mrb, fd, &st) == -1) {
mrb_sys_fail(mrb, "fstat");
}
@@ -803,31 +805,9 @@ mrb_file_size(mrb_state *mrb, mrb_value self)
}
static int
mrb_ftruncate(int fd, mrb_int length)
mrb_ftruncate(mrb_state *mrb, int fd, mrb_int length)
{
#ifndef _WIN32
return ftruncate(fd, (off_t)length);
#else
__int64 cur;
HANDLE file = (HANDLE)_get_osfhandle(fd);
if (file == INVALID_HANDLE_VALUE) {
return -1;
}
cur = _lseeki64(fd, 0, SEEK_CUR);
if (cur == -1) return -1;
if (_lseeki64(fd, (__int64)length, SEEK_SET) == -1) return -1;
if (!SetEndOfFile(file)) {
errno = EINVAL; /* TODO: GetLastError to errno */
return -1;
}
if (_lseeki64(fd, cur, SEEK_SET) == -1) return -1;
return 0;
#endif /* _WIN32 */
return mrb_io_hal_ftruncate(mrb, fd, (int64_t)length);
}
/*
@@ -847,7 +827,7 @@ mrb_file_truncate(mrb_state *mrb, mrb_value self)
mrb_value lenv = mrb_get_arg1(mrb);
int fd = mrb_io_fileno(mrb, self);
mrb_int length = mrb_as_int(mrb, lenv);
if (mrb_ftruncate(fd, length) != 0) {
if (mrb_ftruncate(mrb, fd, length) != 0) {
mrb_sys_fail(mrb, "ftruncate");
}
@@ -865,22 +845,18 @@ mrb_file_truncate(mrb_state *mrb, mrb_value self)
static mrb_value
mrb_file_s_symlink(mrb_state *mrb, mrb_value klass)
{
#if defined(_WIN32)
mrb_raise(mrb, E_NOTIMP_ERROR, "symlink is not supported on this platform");
#else
mrb_value from, to;
mrb_get_args(mrb, "SS", &from, &to);
const char *src = mrb_locale_from_utf8(RSTRING_CSTR(mrb, from), -1);
const char *dst = mrb_locale_from_utf8(RSTRING_CSTR(mrb, to), -1);
if (symlink(src, dst) == -1) {
if (mrb_io_hal_symlink(mrb, src, dst) == -1) {
mrb_locale_free(src);
mrb_locale_free(dst);
mrb_sys_fail(mrb, RSTRING_CSTR(mrb, mrb_format(mrb, "(%v, %v)", from, to)));
}
mrb_locale_free(src);
mrb_locale_free(dst);
#endif
return mrb_fixnum_value(0);
}
@@ -906,7 +882,7 @@ mrb_file_s_chmod(mrb_state *mrb, mrb_value klass)
mrb_ensure_string_type(mrb, filenames[i]);
const char *utf8_path = RSTRING_CSTR(mrb, filenames[i]);
char *path = mrb_locale_from_utf8(utf8_path, -1);
if (CHMOD(path, mode) == -1) {
if (mrb_io_hal_chmod(mrb, path, (uint32_t)mode) == -1) {
mrb_locale_free(path);
mrb_sys_fail(mrb, utf8_path);
}
@@ -929,10 +905,6 @@ mrb_file_s_chmod(mrb_state *mrb, mrb_value klass)
static mrb_value
mrb_file_s_readlink(mrb_state *mrb, mrb_value klass)
{
#if defined(_WIN32)
mrb_raise(mrb, E_NOTIMP_ERROR, "readlink is not supported on this platform");
return mrb_nil_value(); // unreachable
#else
const char *path;
size_t bufsize = 100;
@@ -941,8 +913,8 @@ mrb_file_s_readlink(mrb_state *mrb, mrb_value klass)
char *tmp = mrb_locale_from_utf8(path, -1);
char *buf = (char*)mrb_malloc(mrb, bufsize);
ssize_t rc;
while ((rc = readlink(tmp, buf, bufsize)) == (ssize_t)bufsize) {
int64_t rc;
while ((rc = mrb_io_hal_readlink(mrb, tmp, buf, bufsize)) == (int64_t)bufsize) {
bufsize += 100;
buf = (char*)mrb_realloc(mrb, buf, bufsize);
}
@@ -958,7 +930,6 @@ mrb_file_s_readlink(mrb_state *mrb, mrb_value klass)
mrb_free(mrb, buf);
return ret;
#endif
}
/*
+16 -46
View File
@@ -9,27 +9,11 @@
#include <mruby/ext/io.h>
#include <mruby/error.h>
#include <mruby/presym.h>
#include <io_hal.h>
#include <sys/types.h>
#include <sys/stat.h>
#if defined(_WIN32)
#define LSTAT stat
#include <winsock.h>
#else
#define LSTAT lstat
#include <sys/file.h>
#include <sys/param.h>
#include <sys/wait.h>
#ifndef __DJGPP__
#include <libgen.h>
#endif
#include <pwd.h>
#include <unistd.h>
#endif
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
@@ -37,14 +21,14 @@
extern struct mrb_data_type mrb_io_type;
static int
mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat)
mrb_stat0(mrb_state *mrb, mrb_value obj, mrb_io_stat *st, int do_lstat)
{
if (mrb_obj_is_kind_of(mrb, obj, mrb_class_get_id(mrb, MRB_SYM(IO)))) {
struct mrb_io *fptr;
fptr = (struct mrb_io*)mrb_data_get_ptr(mrb, obj, &mrb_io_type);
if (fptr && fptr->fd >= 0) {
return fstat(fptr->fd, st);
return mrb_io_hal_fstat(mrb, fptr->fd, st);
}
mrb_raise(mrb, E_IO_ERROR, "closed stream");
@@ -54,10 +38,10 @@ mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat)
char *path = mrb_locale_from_utf8(RSTRING_CSTR(mrb, obj), -1);
int ret;
if (do_lstat) {
ret = LSTAT(path, st);
ret = mrb_io_hal_lstat(mrb, path, st);
}
else {
ret = stat(path, st);
ret = mrb_io_hal_stat(mrb, path, st);
}
mrb_locale_free(path);
return ret;
@@ -65,18 +49,16 @@ mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat)
}
static int
mrb_stat(mrb_state *mrb, mrb_value obj, struct stat *st)
mrb_stat(mrb_state *mrb, mrb_value obj, mrb_io_stat *st)
{
return mrb_stat0(mrb, obj, st, 0);
}
#ifdef S_ISLNK
static int
mrb_lstat(mrb_state *mrb, mrb_value obj, struct stat *st)
mrb_lstat(mrb_state *mrb, mrb_value obj, mrb_io_stat *st)
{
return mrb_stat0(mrb, obj, st, 1);
}
#endif
/*
* call-seq:
@@ -97,7 +79,7 @@ mrb_filetest_s_directory_p(mrb_state *mrb, mrb_value klass)
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif
struct stat st;
mrb_io_stat st;
mrb_value obj = mrb_get_arg1(mrb);
if (mrb_stat(mrb, obj, &st) < 0)
@@ -122,15 +104,12 @@ mrb_filetest_s_directory_p(mrb_state *mrb, mrb_value klass)
static mrb_value
mrb_filetest_s_pipe_p(mrb_state *mrb, mrb_value klass)
{
#if defined(_WIN32)
mrb_raise(mrb, E_NOTIMP_ERROR, "pipe is not supported on this platform");
#else
#ifdef S_IFIFO
# ifndef S_ISFIFO
# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
# endif
struct stat st;
mrb_io_stat st;
mrb_value obj = mrb_get_arg1(mrb);
if (mrb_stat(mrb, obj, &st) < 0)
@@ -140,7 +119,6 @@ mrb_filetest_s_pipe_p(mrb_state *mrb, mrb_value klass)
#endif
return mrb_false_value();
#endif
}
/*
@@ -157,9 +135,6 @@ mrb_filetest_s_pipe_p(mrb_state *mrb, mrb_value klass)
static mrb_value
mrb_filetest_s_symlink_p(mrb_state *mrb, mrb_value klass)
{
#if defined(_WIN32)
mrb_raise(mrb, E_NOTIMP_ERROR, "symlink is not supported on this platform");
#else
#ifndef S_ISLNK
# ifdef _S_ISLNK
# define S_ISLNK(m) _S_ISLNK(m)
@@ -175,7 +150,7 @@ mrb_filetest_s_symlink_p(mrb_state *mrb, mrb_value klass)
#endif
#ifdef S_ISLNK
struct stat st;
mrb_io_stat st;
mrb_value obj = mrb_get_arg1(mrb);
if (mrb_lstat(mrb, obj, &st) == -1)
@@ -185,7 +160,6 @@ mrb_filetest_s_symlink_p(mrb_state *mrb, mrb_value klass)
#endif
return mrb_false_value();
#endif
}
/*
@@ -202,9 +176,6 @@ mrb_filetest_s_symlink_p(mrb_state *mrb, mrb_value klass)
static mrb_value
mrb_filetest_s_socket_p(mrb_state *mrb, mrb_value klass)
{
#if defined(_WIN32)
mrb_raise(mrb, E_NOTIMP_ERROR, "socket is not supported on this platform");
#else
#ifndef S_ISSOCK
# ifdef _S_ISSOCK
# define S_ISSOCK(m) _S_ISSOCK(m)
@@ -220,7 +191,7 @@ mrb_filetest_s_socket_p(mrb_state *mrb, mrb_value klass)
#endif
#ifdef S_ISSOCK
struct stat st;
mrb_io_stat st;
mrb_value obj = mrb_get_arg1(mrb);
if (mrb_stat(mrb, obj, &st) < 0)
@@ -230,7 +201,6 @@ mrb_filetest_s_socket_p(mrb_state *mrb, mrb_value klass)
#endif
return mrb_false_value();
#endif
}
/*
@@ -251,7 +221,7 @@ mrb_filetest_s_socket_p(mrb_state *mrb, mrb_value klass)
static mrb_value
mrb_filetest_s_exist_p(mrb_state *mrb, mrb_value klass)
{
struct stat st;
mrb_io_stat st;
mrb_value obj = mrb_get_arg1(mrb);
if (mrb_stat(mrb, obj, &st) < 0)
@@ -278,7 +248,7 @@ mrb_filetest_s_file_p(mrb_state *mrb, mrb_value klass)
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif
struct stat st;
mrb_io_stat st;
mrb_value obj = mrb_get_arg1(mrb);
if (mrb_stat(mrb, obj, &st) < 0)
@@ -303,7 +273,7 @@ mrb_filetest_s_file_p(mrb_state *mrb, mrb_value klass)
static mrb_value
mrb_filetest_s_zero_p(mrb_state *mrb, mrb_value klass)
{
struct stat st;
mrb_io_stat st;
mrb_value obj = mrb_get_arg1(mrb);
if (mrb_stat(mrb, obj, &st) < 0)
@@ -330,7 +300,7 @@ mrb_filetest_s_zero_p(mrb_state *mrb, mrb_value klass)
static mrb_value
mrb_filetest_s_size(mrb_state *mrb, mrb_value klass)
{
struct stat st;
mrb_io_stat st;
mrb_value obj = mrb_get_arg1(mrb);
if (mrb_stat(mrb, obj, &st) < 0)
@@ -354,7 +324,7 @@ mrb_filetest_s_size(mrb_state *mrb, mrb_value klass)
static mrb_value
mrb_filetest_s_size_p(mrb_state *mrb, mrb_value klass)
{
struct stat st;
mrb_io_stat st;
mrb_value obj = mrb_get_arg1(mrb);
if (mrb_stat(mrb, obj, &st) < 0)
+54 -49
View File
@@ -13,6 +13,7 @@
#include <mruby/error.h>
#include <mruby/internal.h>
#include <mruby/presym.h>
#include <io_hal.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -1367,21 +1368,21 @@ io_pid(mrb_state *mrb, mrb_value io)
return mrb_nil_value();
}
static struct timeval
static mrb_io_timeval
time2timeval(mrb_state *mrb, mrb_value time)
{
struct timeval t = { 0, 0 };
mrb_io_timeval t = { 0, 0 };
switch (mrb_type(time)) {
case MRB_TT_INTEGER:
t.tv_sec = (ftime_t)mrb_integer(time);
t.tv_sec = (int64_t)mrb_integer(time);
t.tv_usec = 0;
break;
#ifndef MRB_NO_FLOAT
case MRB_TT_FLOAT:
t.tv_sec = (ftime_t)mrb_float(time);
t.tv_usec = (fsuseconds_t)((mrb_float(time) - t.tv_sec) * 1000000.0);
t.tv_sec = (int64_t)mrb_float(time);
t.tv_usec = (int64_t)((mrb_float(time) - t.tv_sec) * 1000000.0);
break;
#endif
@@ -1487,7 +1488,7 @@ io_s_select(mrb_state *mrb, mrb_value klass)
write = argv[1];
mrb_value read = argv[0];
struct timeval *tp, timerec;
mrb_io_timeval *tp, timerec;
if (mrb_nil_p(timeout)) {
tp = NULL;
}
@@ -1496,20 +1497,22 @@ io_s_select(mrb_state *mrb, mrb_value klass)
tp = &timerec;
}
fd_set pset, rset, *rp;
FD_ZERO(&pset);
mrb_io_fdset *pset = mrb_io_hal_fdset_alloc(mrb);
mrb_io_fdset *rset = NULL;
mrb_io_fdset *rp = NULL;
mrb_io_hal_fdset_zero(mrb, pset);
if (!mrb_nil_p(read)) {
mrb_check_type(mrb, read, MRB_TT_ARRAY);
rp = &rset;
FD_ZERO(rp);
rset = mrb_io_hal_fdset_alloc(mrb);
rp = rset;
mrb_io_hal_fdset_zero(mrb, rp);
for (int i = 0; i < RARRAY_LEN(read); i++) {
read_io = RARRAY_PTR(read)[i];
fptr = io_get_open_fptr(mrb, read_io);
if (fptr->fd >= FD_SETSIZE) continue;
FD_SET(fptr->fd, rp);
mrb_io_hal_fdset_set(mrb, fptr->fd, rp);
if (mrb_io_read_data_pending(mrb, fptr)) {
pending++;
FD_SET(fptr->fd, &pset);
mrb_io_hal_fdset_set(mrb, fptr->fd, pset);
}
if (max < fptr->fd)
max = fptr->fd;
@@ -1519,75 +1522,72 @@ io_s_select(mrb_state *mrb, mrb_value klass)
tp = &timerec;
}
}
else {
rp = NULL;
}
fd_set wset, *wp;
mrb_io_fdset *wset = NULL;
mrb_io_fdset *wp = NULL;
if (!mrb_nil_p(write)) {
mrb_check_type(mrb, write, MRB_TT_ARRAY);
wp = &wset;
FD_ZERO(wp);
wset = mrb_io_hal_fdset_alloc(mrb);
wp = wset;
mrb_io_hal_fdset_zero(mrb, wp);
for (int i = 0; i < RARRAY_LEN(write); i++) {
fptr = io_get_open_fptr(mrb, RARRAY_PTR(write)[i]);
if (fptr->fd >= FD_SETSIZE) continue;
FD_SET(fptr->fd, wp);
mrb_io_hal_fdset_set(mrb, fptr->fd, wp);
if (max < fptr->fd)
max = fptr->fd;
if (fptr->fd2 >= 0) {
FD_SET(fptr->fd2, wp);
mrb_io_hal_fdset_set(mrb, fptr->fd2, wp);
if (max < fptr->fd2)
max = fptr->fd2;
}
}
}
else {
wp = NULL;
}
fd_set eset, *ep;
mrb_io_fdset *eset = NULL;
mrb_io_fdset *ep = NULL;
if (!mrb_nil_p(except)) {
mrb_check_type(mrb, except, MRB_TT_ARRAY);
ep = &eset;
FD_ZERO(ep);
eset = mrb_io_hal_fdset_alloc(mrb);
ep = eset;
mrb_io_hal_fdset_zero(mrb, ep);
for (int i = 0; i < RARRAY_LEN(except); i++) {
fptr = io_get_open_fptr(mrb, RARRAY_PTR(except)[i]);
if (fptr->fd >= FD_SETSIZE) continue;
FD_SET(fptr->fd, ep);
mrb_io_hal_fdset_set(mrb, fptr->fd, ep);
if (max < fptr->fd)
max = fptr->fd;
if (fptr->fd2 >= 0) {
FD_SET(fptr->fd2, ep);
mrb_io_hal_fdset_set(mrb, fptr->fd2, ep);
if (max < fptr->fd2)
max = fptr->fd2;
}
}
}
else {
ep = NULL;
}
max++;
int n;
retry:
n = select(max, rp, wp, ep, tp);
n = mrb_io_hal_select(mrb, max, rp, wp, ep, tp);
if (n < 0) {
#ifdef _WIN32
errno = WSAGetLastError();
if (errno != WSAEINTR)
if (errno != EINTR) {
mrb_io_hal_fdset_free(mrb, pset);
mrb_io_hal_fdset_free(mrb, rset);
mrb_io_hal_fdset_free(mrb, wset);
mrb_io_hal_fdset_free(mrb, eset);
mrb_sys_fail(mrb, "select failed");
#else
if (errno != EINTR)
mrb_sys_fail(mrb, "select failed");
#endif
}
if (tp == NULL)
goto retry;
interrupt_flag = 1;
}
if (!pending && n == 0)
if (!pending && n == 0) {
mrb_io_hal_fdset_free(mrb, pset);
mrb_io_hal_fdset_free(mrb, rset);
mrb_io_hal_fdset_free(mrb, wset);
mrb_io_hal_fdset_free(mrb, eset);
return mrb_nil_value();
}
result = mrb_ary_new_capa(mrb, 3);
mrb_ary_push(mrb, result, rp ? mrb_ary_new(mrb) : mrb_ary_new_capa(mrb, 0));
@@ -1599,8 +1599,8 @@ retry:
list = RARRAY_PTR(result)[0];
for (int i = 0; i < RARRAY_LEN(read); i++) {
fptr = io_get_open_fptr(mrb, RARRAY_PTR(read)[i]);
if (FD_ISSET(fptr->fd, rp) ||
FD_ISSET(fptr->fd, &pset)) {
if (mrb_io_hal_fdset_isset(mrb, fptr->fd, rp) ||
mrb_io_hal_fdset_isset(mrb, fptr->fd, pset)) {
mrb_ary_push(mrb, list, RARRAY_PTR(read)[i]);
}
}
@@ -1610,10 +1610,10 @@ retry:
list = RARRAY_PTR(result)[1];
for (int i = 0; i < RARRAY_LEN(write); i++) {
fptr = io_get_open_fptr(mrb, RARRAY_PTR(write)[i]);
if (FD_ISSET(fptr->fd, wp)) {
if (mrb_io_hal_fdset_isset(mrb, fptr->fd, wp)) {
mrb_ary_push(mrb, list, RARRAY_PTR(write)[i]);
}
else if (fptr->fd2 >= 0 && FD_ISSET(fptr->fd2, wp)) {
else if (fptr->fd2 >= 0 && mrb_io_hal_fdset_isset(mrb, fptr->fd2, wp)) {
mrb_ary_push(mrb, list, RARRAY_PTR(write)[i]);
}
}
@@ -1623,16 +1623,21 @@ retry:
list = RARRAY_PTR(result)[2];
for (int i = 0; i < RARRAY_LEN(except); i++) {
fptr = io_get_open_fptr(mrb, RARRAY_PTR(except)[i]);
if (FD_ISSET(fptr->fd, ep)) {
if (mrb_io_hal_fdset_isset(mrb, fptr->fd, ep)) {
mrb_ary_push(mrb, list, RARRAY_PTR(except)[i]);
}
else if (fptr->fd2 >= 0 && FD_ISSET(fptr->fd2, ep)) {
else if (fptr->fd2 >= 0 && mrb_io_hal_fdset_isset(mrb, fptr->fd2, ep)) {
mrb_ary_push(mrb, list, RARRAY_PTR(except)[i]);
}
}
}
}
mrb_io_hal_fdset_free(mrb, pset);
mrb_io_hal_fdset_free(mrb, rset);
mrb_io_hal_fdset_free(mrb, wset);
mrb_io_hal_fdset_free(mrb, eset);
return result;
}