drop remaining 1.8 and fragile autopush code paths
[kgio.git] / ext / kgio / tryopen.c
blob87017a534f77e1ffa66bc4c9cc706c566cd04542
1 /* We do not modify RSTRING in this file, so RSTRING_MODIFIED is not needed */
2 #include <ruby.h>
3 #include <ruby/io.h>
5 #ifdef HAVE_RUBY_ST_H
6 # include <ruby/st.h>
7 #else
8 # include <st.h>
9 #endif
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <errno.h>
15 #include "set_file_path.h"
16 #include "kgio.h"
18 static ID id_for_fd, id_to_path, id_path;
19 static st_table *errno2sym;
21 struct open_args {
22 const char *pathname;
23 int flags;
24 mode_t mode;
27 #ifndef HAVE_RB_CLOEXEC_OPEN
28 # define rb_cloexec_open(p,f,m) open((p),(f),(m))
29 #endif
31 static void * nogvl_open(void *ptr)
33 struct open_args *o = ptr;
34 long fd = (long)rb_cloexec_open(o->pathname, o->flags, o->mode);
36 return (void *)fd;
40 * call-seq:
42 * Kgio::File.tryopen(filename, [, mode [, perm]]) -> Kgio::File or Symbol
44 * Returns a Kgio::File object on a successful open. +filename+ is a
45 * path to any file on the filesystem. If specified, +mode+ is a bitmask
46 * of flags (see IO.sysopen) and +perm+ should be an octal number.
48 * This does not raise errors for most failures, but installs returns a
49 * Ruby symbol for the constant in the Errno::* namespace.
51 * Common error symbols are:
53 * - :ENOENT
54 * - :EACCES
56 * See your open(2) manpage for more information on open(2) errors.
58 static VALUE s_tryopen(int argc, VALUE *argv, VALUE klass)
60 long fd;
61 VALUE pathname, flags, mode;
62 struct open_args o;
63 int retried = 0;
64 VALUE rv;
66 rb_scan_args(argc, argv, "12", &pathname, &flags, &mode);
67 if (rb_respond_to(pathname, id_to_path))
68 pathname = rb_funcall(pathname, id_to_path, 0);
69 o.pathname = StringValueCStr(pathname);
71 switch (TYPE(flags)) {
72 case T_NIL: o.flags = O_RDONLY; break;
73 case T_FIXNUM: o.flags = FIX2INT(flags); break;
74 case T_BIGNUM: o.flags = NUM2INT(flags); break;
75 default: rb_raise(rb_eArgError, "flags must be an Integer");
77 switch (TYPE(mode)) {
78 case T_NIL: o.mode = 0666; break;
79 case T_FIXNUM: o.mode = FIX2INT(mode); break;
80 case T_BIGNUM: o.mode = NUM2INT(mode); break;
81 default: rb_raise(rb_eArgError, "mode must be an Integer");
84 retry:
85 fd = (long)KGIO_WITHOUT_GVL(nogvl_open, &o, RUBY_UBF_IO, 0);
86 if (fd < 0) {
87 if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
88 rb_gc();
89 if (retried)
90 rb_sys_fail(o.pathname);
91 retried = 1;
92 goto retry;
94 if (fd < 0) {
95 int saved_errno = errno;
97 if (!st_lookup(errno2sym, (st_data_t)errno, &rv)) {
98 errno = saved_errno;
99 rb_sys_fail(o.pathname);
101 return rv;
104 rv = rb_funcall(klass, id_for_fd, 1, LONG2FIX(fd));
105 set_file_path(rv, pathname);
106 return rv;
109 void init_kgio_tryopen(void)
111 VALUE mKgio = rb_define_module("Kgio");
112 VALUE mPipeMethods = rb_const_get(mKgio, rb_intern("PipeMethods"));
113 VALUE cFile;
114 VALUE tmp;
115 long i, len;
117 id_path = rb_intern("path");
118 id_for_fd = rb_intern("for_fd");
119 id_to_path = rb_intern("to_path");
122 * Document-class: Kgio::File
124 * This subclass of the core File class adds the "tryopen" singleton
125 * method for opening files. A single "tryopen" and check for the
126 * return value may be used to avoid unnecessary stat(2) syscalls
127 * or File.open exceptions when checking for the existence of a file
128 * and opening it.
130 cFile = rb_define_class_under(mKgio, "File", rb_cFile);
131 rb_define_singleton_method(cFile, "tryopen", s_tryopen, -1);
132 rb_include_module(cFile, mPipeMethods);
134 errno2sym = st_init_numtable();
135 tmp = rb_funcall(rb_mErrno, rb_intern("constants"), 0);
136 len = RARRAY_LEN(tmp);
137 for (i = 0; i < len; i++) {
138 VALUE error;
139 VALUE err = rb_ary_entry(tmp, i);
140 ID const_id;
142 switch (TYPE(err)) {
143 case T_SYMBOL: const_id = SYM2ID(err); break;
144 case T_STRING: const_id = rb_intern(RSTRING_PTR(err)); break;
145 default: {
146 VALUE i = rb_inspect(err);
147 const char *s = RSTRING_PTR(i);
149 rb_bug("constant not a symbol or string: %s", s);
150 RB_GC_GUARD(i);
154 error = rb_const_get(rb_mErrno, const_id);
155 if ((TYPE(error) != T_CLASS) ||
156 !rb_const_defined(error, rb_intern("Errno")))
157 continue;
159 error = rb_const_get(error, rb_intern("Errno"));
160 switch (TYPE(error)) {
161 case T_FIXNUM:
162 case T_BIGNUM:
163 st_insert(errno2sym, (st_data_t)NUM2INT(error),
164 ID2SYM(const_id));
167 RB_GC_GUARD(tmp);