14 #include <sys/types.h>
18 #include "set_file_path.h"
19 #include "ancient_ruby.h"
21 static ID id_for_fd
, id_to_path
, id_path
;
22 static st_table
*errno2sym
;
30 #ifndef HAVE_RB_CLOEXEC_OPEN
31 # define rb_cloexec_open(p,f,m) open((p),(f),(m))
34 static VALUE
nogvl_open(void *ptr
)
36 struct open_args
*o
= ptr
;
38 return (VALUE
)rb_cloexec_open(o
->pathname
, o
->flags
, o
->mode
);
41 #ifndef HAVE_RB_THREAD_BLOCKING_REGION
42 # define RUBY_UBF_IO ((void *)(-1))
44 typedef void rb_unblock_function_t(void *);
45 typedef VALUE
rb_blocking_function_t(void *);
46 static VALUE
my_thread_blocking_region(
47 rb_blocking_function_t
*fn
, void *data1
,
48 rb_unblock_function_t
*ubf
, void *data2
)
52 TRAP_BEG
; /* for FIFO */
58 #define rb_thread_blocking_region(fn,data1,ubf,data2) \
59 my_thread_blocking_region((fn),(data1),(ubf),(data2))
60 #endif /* ! HAVE_RB_THREAD_BLOCKING_REGION */
65 * Kgio::File.tryopen(filename, [, mode [, perm]]) -> Kgio::File or Symbol
67 * Returns a Kgio::File object on a successful open. +filename+ is a
68 * path to any file on the filesystem. If specified, +mode+ is a bitmask
69 * of flags (see IO.sysopen) and +perm+ should be an octal number.
71 * This does not raise errors for most failures, but installs returns a
72 * Ruby symbol for the constant in the Errno::* namespace.
74 * Common error symbols are:
79 * See your open(2) manpage for more information on open(2) errors.
81 static VALUE
s_tryopen(int argc
, VALUE
*argv
, VALUE klass
)
84 VALUE pathname
, flags
, mode
;
89 rb_scan_args(argc
, argv
, "12", &pathname
, &flags
, &mode
);
90 if (rb_respond_to(pathname
, id_to_path
))
91 pathname
= rb_funcall(pathname
, id_to_path
, 0);
92 o
.pathname
= StringValueCStr(pathname
);
94 switch (TYPE(flags
)) {
95 case T_NIL
: o
.flags
= O_RDONLY
; break;
96 case T_FIXNUM
: o
.flags
= FIX2INT(flags
); break;
97 case T_BIGNUM
: o
.flags
= NUM2INT(flags
); break;
98 default: rb_raise(rb_eArgError
, "flags must be an Integer");
100 switch (TYPE(mode
)) {
101 case T_NIL
: o
.mode
= 0666; break;
102 case T_FIXNUM
: o
.mode
= FIX2INT(mode
); break;
103 case T_BIGNUM
: o
.mode
= NUM2INT(mode
); break;
104 default: rb_raise(rb_eArgError
, "mode must be an Integer");
108 fd
= (int)rb_thread_blocking_region(nogvl_open
, &o
, RUBY_UBF_IO
, 0);
110 if (errno
== EMFILE
|| errno
== ENFILE
|| errno
== ENOMEM
) {
113 rb_sys_fail(o
.pathname
);
118 int saved_errno
= errno
;
120 if (!st_lookup(errno2sym
, (st_data_t
)errno
, &rv
)) {
122 rb_sys_fail(o
.pathname
);
127 rv
= rb_funcall(klass
, id_for_fd
, 1, INT2FIX(fd
));
128 set_file_path(rv
, pathname
);
132 void init_kgio_tryopen(void)
134 VALUE mKgio
= rb_define_module("Kgio");
135 VALUE mPipeMethods
= rb_const_get(mKgio
, rb_intern("PipeMethods"));
141 id_path
= rb_intern("path");
142 id_for_fd
= rb_intern("for_fd");
143 id_to_path
= rb_intern("to_path");
146 * Document-class: Kgio::File
148 * This subclass of the core File class adds the "tryopen" singleton
149 * method for opening files. A single "tryopen" and check for the
150 * return value may be used to avoid unnecessary stat(2) syscalls
151 * or File.open exceptions when checking for the existence of a file
154 cFile
= rb_define_class_under(mKgio
, "File", rb_cFile
);
155 rb_define_singleton_method(cFile
, "tryopen", s_tryopen
, -1);
156 rb_include_module(cFile
, mPipeMethods
);
158 if (!rb_funcall(cFile
, rb_intern("method_defined?"), 1,
160 rb_define_alias(cFile
, "to_path", "path");
162 errno2sym
= st_init_numtable();
163 tmp
= rb_funcall(rb_mErrno
, rb_intern("constants"), 0);
164 ptr
= RARRAY_PTR(tmp
);
165 len
= RARRAY_LEN(tmp
);
166 for (; --len
>= 0; ptr
++) {
170 switch (TYPE(*ptr
)) {
171 case T_SYMBOL
: const_id
= SYM2ID(*ptr
); break;
172 case T_STRING
: const_id
= rb_intern(RSTRING_PTR(*ptr
)); break;
173 default: rb_bug("constant not a symbol or string");
176 error
= rb_const_get(rb_mErrno
, const_id
);
177 if ((TYPE(error
) != T_CLASS
) ||
178 !rb_const_defined(error
, rb_intern("Errno")))
181 error
= rb_const_get(error
, rb_intern("Errno"));
182 switch (TYPE(error
)) {
185 st_insert(errno2sym
, (st_data_t
)NUM2INT(error
),