This project is closed and read-only.
Backport #6127 ยป ruby-io-c.patch
| /Users/dlampa/carrier-build-root/local_build/carrier-ruby-1.9.3p194-2/src/ruby-build/ruby-source/io.c 2012-10-10 09:02:34.000000000 -0500 | ||
|---|---|---|
|
if (max_file_descriptor < fd) max_file_descriptor = fd;
|
||
|
}
|
||
|
void
|
||
|
rb_maygvl_fd_fix_cloexec(int fd)
|
||
|
{
|
||
|
/* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
|
||
|
#ifdef F_GETFD
|
||
|
int flags, flags2, ret;
|
||
|
flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
|
||
|
if (flags == -1) {
|
||
|
rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
|
||
|
}
|
||
|
if (fd <= 2)
|
||
|
flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
|
||
|
else
|
||
|
flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
|
||
|
if (flags != flags2) {
|
||
|
ret = fcntl(fd, F_SETFD, flags2);
|
||
|
if (ret == -1) {
|
||
|
rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
int
|
||
|
rb_cloexec_fcntl_dupfd(int fd, int minfd)
|
||
|
{
|
||
|
int ret;
|
||
|
#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC)
|
||
|
static int try_dupfd_cloexec = 1;
|
||
|
if (try_dupfd_cloexec) {
|
||
|
ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
|
||
|
if (ret != -1) {
|
||
|
if (ret <= 2)
|
||
|
rb_maygvl_fd_fix_cloexec(ret);
|
||
|
return ret;
|
||
|
}
|
||
|
/* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
|
||
|
if (errno == EINVAL) {
|
||
|
ret = fcntl(fd, F_DUPFD, minfd);
|
||
|
if (ret != -1) {
|
||
|
try_dupfd_cloexec = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
ret = fcntl(fd, F_DUPFD, minfd);
|
||
|
}
|
||
|
#else
|
||
|
ret = fcntl(fd, F_DUPFD, minfd);
|
||
|
#endif
|
||
|
if (ret == -1) return -1;
|
||
|
rb_maygvl_fd_fix_cloexec(ret);
|
||
|
return ret;
|
||
|
}
|
||
|
#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
|
||
|
#define ARGF argf_of(argf)
|
||
| ... | ... | |
|
return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
|
||
|
}
|
||
|
struct io_cntl_arg {
|
||
|
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
|
||
|
typedef unsigned long ioctl_req_t;
|
||
|
#define NUM2IOCTLREQ(num) NUM2ULONG(num)
|
||
|
#else
|
||
|
typedef int ioctl_req_t;
|
||
|
#define NUM2IOCTLREQ(num) NUM2INT(num)
|
||
|
#endif
|
||
|
struct ioctl_arg {
|
||
|
int fd;
|
||
|
int cmd;
|
||
|
ioctl_req_t cmd;
|
||
|
long narg;
|
||
|
int io_p;
|
||
|
};
|
||
|
static VALUE nogvl_io_cntl(void *ptr)
|
||
|
static VALUE nogvl_ioctl(void *ptr)
|
||
|
{
|
||
|
struct io_cntl_arg *arg = ptr;
|
||
|
struct ioctl_arg *arg = ptr;
|
||
|
if (arg->io_p)
|
||
|
return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
|
||
|
else
|
||
|
return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
|
||
|
return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
|
||
|
}
|
||
|
static int
|
||
|
io_cntl(int fd, int cmd, long narg, int io_p)
|
||
|
do_ioctl(int fd, ioctl_req_t cmd, long narg)
|
||
|
{
|
||
|
int retval;
|
||
|
struct io_cntl_arg arg;
|
||
|
#ifndef HAVE_FCNTL
|
||
|
if (!io_p) {
|
||
|
rb_notimplement();
|
||
|
}
|
||
|
#endif
|
||
|
struct ioctl_arg arg;
|
||
|
arg.fd = fd;
|
||
|
arg.cmd = cmd;
|
||
|
arg.narg = narg;
|
||
|
arg.io_p = io_p;
|
||
|
retval = (int)rb_thread_io_blocking_region(nogvl_io_cntl, &arg, fd);
|
||
|
#if defined(F_DUPFD)
|
||
|
if (!io_p && retval != -1 && cmd == F_DUPFD) {
|
||
|
rb_update_max_fd(retval);
|
||
|
}
|
||
|
#endif
|
||
|
retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
|
||
|
return retval;
|
||
|
}
|
||
|
static VALUE
|
||
|
rb_io_ctl(VALUE io, VALUE req, VALUE arg, int io_p)
|
||
|
static long
|
||
|
ioctl_narg_len(ioctl_req_t cmd)
|
||
|
{
|
||
|
int cmd = NUM2INT(req);
|
||
|
rb_io_t *fptr;
|
||
|
long len = 0;
|
||
|
long narg = 0;
|
||
|
int retval;
|
||
|
long len;
|
||
|
rb_secure(2);
|
||
|
#ifdef IOCPARM_MASK
|
||
|
#ifndef IOCPARM_LEN
|
||
|
#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
|
||
|
#endif
|
||
|
#endif
|
||
|
#ifdef IOCPARM_LEN
|
||
|
len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
|
||
|
#elif defined(_IOC_SIZE)
|
||
|
len = _IOC_SIZE(cmd);
|
||
|
#else
|
||
|
len = 256; /* otherwise guess at what's safe */
|
||
|
#endif
|
||
|
return len;
|
||
|
}
|
||
|
#ifdef HAVE_FCNTL
|
||
|
#ifdef __linux__
|
||
|
typedef long fcntl_arg_t;
|
||
|
#else
|
||
|
/* posix */
|
||
|
typedef int fcntl_arg_t;
|
||
|
#endif
|
||
|
static long
|
||
|
fcntl_narg_len(int cmd)
|
||
|
{
|
||
|
long len;
|
||
|
switch (cmd) {
|
||
|
#ifdef F_DUPFD
|
||
|
case F_DUPFD:
|
||
|
len = sizeof(fcntl_arg_t);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_DUP2FD /* bsd specific */
|
||
|
case F_DUP2FD:
|
||
|
len = sizeof(int);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_DUPFD_CLOEXEC /* linux specific */
|
||
|
case F_DUPFD_CLOEXEC:
|
||
|
len = sizeof(fcntl_arg_t);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_GETFD
|
||
|
case F_GETFD:
|
||
|
len = 1;
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_SETFD
|
||
|
case F_SETFD:
|
||
|
len = sizeof(fcntl_arg_t);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_GETFL
|
||
|
case F_GETFL:
|
||
|
len = 1;
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_SETFL
|
||
|
case F_SETFL:
|
||
|
len = sizeof(fcntl_arg_t);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_GETOWN
|
||
|
case F_GETOWN:
|
||
|
len = 1;
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_SETOWN
|
||
|
case F_SETOWN:
|
||
|
len = sizeof(fcntl_arg_t);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_GETOWN_EX /* linux specific */
|
||
|
case F_GETOWN_EX:
|
||
|
len = sizeof(struct f_owner_ex);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_SETOWN_EX /* linux specific */
|
||
|
case F_SETOWN_EX:
|
||
|
len = sizeof(struct f_owner_ex);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_GETLK
|
||
|
case F_GETLK:
|
||
|
len = sizeof(struct flock);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_SETLK
|
||
|
case F_SETLK:
|
||
|
len = sizeof(struct flock);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_SETLKW
|
||
|
case F_SETLKW:
|
||
|
len = sizeof(struct flock);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_READAHEAD /* bsd specific */
|
||
|
case F_READAHEAD:
|
||
|
len = sizeof(int);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_RDAHEAD /* Darwin specific */
|
||
|
case F_RDAHEAD:
|
||
|
len = sizeof(int);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_GETSIG /* linux specific */
|
||
|
case F_GETSIG:
|
||
|
len = 1;
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_SETSIG /* linux specific */
|
||
|
case F_SETSIG:
|
||
|
len = sizeof(fcntl_arg_t);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_GETLEASE /* linux specific */
|
||
|
case F_GETLEASE:
|
||
|
len = 1;
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_SETLEASE /* linux specific */
|
||
|
case F_SETLEASE:
|
||
|
len = sizeof(fcntl_arg_t);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef F_NOTIFY /* linux specific */
|
||
|
case F_NOTIFY:
|
||
|
len = sizeof(fcntl_arg_t);
|
||
|
break;
|
||
|
#endif
|
||
|
default:
|
||
|
len = 256;
|
||
|
break;
|
||
|
}
|
||
|
return len;
|
||
|
}
|
||
|
#else /* HAVE_FCNTL */
|
||
|
static long
|
||
|
fcntl_narg_len(int cmd)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
#endif /* HAVE_FCNTL */
|
||
|
static long
|
||
|
setup_narg(ioctl_req_t cmd, VALUE *argp, int io_p)
|
||
|
{
|
||
|
long narg = 0;
|
||
|
VALUE arg = *argp;
|
||
|
if (NIL_P(arg) || arg == Qfalse) {
|
||
|
narg = 0;
|
||
| ... | ... | |
|
narg = NUM2LONG(arg);
|
||
|
}
|
||
|
else {
|
||
|
arg = tmp;
|
||
|
#ifdef IOCPARM_MASK
|
||
|
#ifndef IOCPARM_LEN
|
||
|
#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
|
||
|
#endif
|
||
|
#endif
|
||
|
#ifdef IOCPARM_LEN
|
||
|
len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
|
||
|
#else
|
||
|
len = 256; /* otherwise guess at what's safe */
|
||
|
#endif
|
||
|
long len;
|
||
|
*argp = arg = tmp;
|
||
|
if (io_p)
|
||
|
len = ioctl_narg_len(cmd);
|
||
|
else
|
||
|
len = fcntl_narg_len((int)cmd);
|
||
|
rb_str_modify(arg);
|
||
|
if (len <= RSTRING_LEN(arg)) {
|
||
|
len = RSTRING_LEN(arg);
|
||
|
}
|
||
|
if (RSTRING_LEN(arg) < len) {
|
||
|
/* expand for data + sentinel. */
|
||
|
if (RSTRING_LEN(arg) < len+1) {
|
||
|
rb_str_resize(arg, len+1);
|
||
|
}
|
||
|
RSTRING_PTR(arg)[len] = 17; /* a little sanity check here */
|
||
|
/* a little sanity check here */
|
||
|
RSTRING_PTR(arg)[RSTRING_LEN(arg) - 1] = 17;
|
||
|
narg = (long)(SIGNED_VALUE)RSTRING_PTR(arg);
|
||
|
}
|
||
|
}
|
||
|
GetOpenFile(io, fptr);
|
||
|
retval = io_cntl(fptr->fd, cmd, narg, io_p);
|
||
|
if (retval < 0) rb_sys_fail_path(fptr->pathv);
|
||
|
if (TYPE(arg) == T_STRING && RSTRING_PTR(arg)[len] != 17) {
|
||
|
rb_raise(rb_eArgError, "return value overflowed string");
|
||
|
return narg;
|
||
|
}
|
||
|
if (!io_p && cmd == F_SETFL) {
|
||
|
if (narg & O_NONBLOCK) {
|
||
|
fptr->mode |= FMODE_WSPLIT_INITIALIZED;
|
||
|
fptr->mode &= ~FMODE_WSPLIT;
|
||
|
}
|
||
|
else {
|
||
|
fptr->mode &= ~(FMODE_WSPLIT_INITIALIZED|FMODE_WSPLIT);
|
||
|
}
|
||
|
static VALUE
|
||
|
rb_ioctl(VALUE io, VALUE req, VALUE arg)
|
||
|
{
|
||
|
ioctl_req_t cmd = NUM2IOCTLREQ(req);
|
||
|
rb_io_t *fptr;
|
||
|
long narg;
|
||
|
int retval;
|
||
|
|
||
|
rb_secure(2);
|
||
|
narg = setup_narg(cmd, &arg, 1);
|
||
|
GetOpenFile(io, fptr);
|
||
|
retval = do_ioctl(fptr->fd, cmd, narg);
|
||
|
if (retval < 0) rb_sys_fail_path(fptr->pathv);
|
||
|
if (RB_TYPE_P(arg, T_STRING)) {
|
||
|
if (RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] != 17)
|
||
|
rb_raise(rb_eArgError, "return value overflowed string");
|
||
|
RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] = '\0';
|
||
|
}
|
||
|
return INT2NUM(retval);
|
||
|
}
|
||
|
/*
|
||
|
* call-seq:
|
||
|
* ios.ioctl(integer_cmd, arg) -> integer
|
||
| ... | ... | |
|
VALUE req, arg;
|
||
|
rb_scan_args(argc, argv, "11", &req, &arg);
|
||
|
return rb_io_ctl(io, req, arg, 1);
|
||
|
return rb_ioctl(io, req, arg);
|
||
|
}
|
||
|
#ifdef HAVE_FCNTL
|
||
|
struct fcntl_arg {
|
||
|
int fd;
|
||
|
int cmd;
|
||
|
long narg;
|
||
|
};
|
||
|
static VALUE nogvl_fcntl(void *ptr)
|
||
|
{
|
||
|
struct fcntl_arg *arg = ptr;
|
||
|
#if defined(F_DUPFD)
|
||
|
if (arg->cmd == F_DUPFD)
|
||
|
return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
|
||
|
#endif
|
||
|
return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
|
||
|
}
|
||
|
static int
|
||
|
do_fcntl(int fd, int cmd, long narg)
|
||
|
{
|
||
|
int retval;
|
||
|
struct fcntl_arg arg;
|
||
|
arg.fd = fd;
|
||
|
arg.cmd = cmd;
|
||
|
arg.narg = narg;
|
||
|
retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
|
||
|
#if defined(F_DUPFD)
|
||
|
if (retval != -1 && cmd == F_DUPFD) {
|
||
|
rb_update_max_fd(retval);
|
||
|
}
|
||
|
#endif
|
||
|
return retval;
|
||
|
}
|
||
|
static VALUE
|
||
|
rb_fcntl(VALUE io, VALUE req, VALUE arg)
|
||
|
{
|
||
|
int cmd = NUM2INT(req);
|
||
|
rb_io_t *fptr;
|
||
|
long narg;
|
||
|
int retval;
|
||
|
rb_secure(2);
|
||
|
narg = setup_narg(cmd, &arg, 0);
|
||
|
GetOpenFile(io, fptr);
|
||
|
retval = do_fcntl(fptr->fd, cmd, narg);
|
||
|
if (retval < 0) rb_sys_fail_path(fptr->pathv);
|
||
|
if (RB_TYPE_P(arg, T_STRING)) {
|
||
|
if (RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] != 17)
|
||
|
rb_raise(rb_eArgError, "return value overflowed string");
|
||
|
RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] = '\0';
|
||
|
}
|
||
|
if (cmd == F_SETFL) {
|
||
|
if (narg & O_NONBLOCK) {
|
||
|
fptr->mode |= FMODE_WSPLIT_INITIALIZED;
|
||
|
fptr->mode &= ~FMODE_WSPLIT;
|
||
|
}
|
||
|
else {
|
||
|
fptr->mode &= ~(FMODE_WSPLIT_INITIALIZED|FMODE_WSPLIT);
|
||
|
}
|
||
|
}
|
||
|
return INT2NUM(retval);
|
||
|
}
|
||
|
/*
|
||
|
* call-seq:
|
||
|
* ios.fcntl(integer_cmd, arg) -> integer
|
||
| ... | ... | |
|
VALUE req, arg;
|
||
|
rb_scan_args(argc, argv, "11", &req, &arg);
|
||
|
return rb_io_ctl(io, req, arg, 0);
|
||
|
return rb_fcntl(io, req, arg);
|
||
|
}
|
||
|
#else
|
||
|
#define rb_io_fcntl rb_f_notimplement
|
||