Class: Kgio::File

Inherits:
File
  • Object
show all
Includes:
PipeMethods
Defined in:
ext/kgio/tryopen.c,
ext/kgio/tryopen.c

Overview

This subclass of the core File class adds the “tryopen” singleton method for opening files. A single “tryopen” and check for the return value may be used to avoid unnecessary stat(2) syscalls or File.open exceptions when checking for the existence of a file and opening it.

Class Method Summary collapse

Methods included from DefaultWaiters

#kgio_wait_readable, #kgio_wait_writable

Class Method Details

.tryopen(*args) ⇒ Object

Kgio::File.tryopen(filename, [, mode [, perm]]) -> Kgio::File or Symbol

Returns a Kgio::File object on a successful open. filename is a path to any file on the filesystem. If specified, mode is a bitmask of flags (see IO.sysopen) and perm should be an octal number.

This does not raise errors for most failures, but installs returns a Ruby symbol for the constant in the Errno::* namespace.

Common error symbols are:

  • :ENOENT

  • :EACCES

See your open(2) manpage for more information on open(2) errors.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'ext/kgio/tryopen.c', line 84

static VALUE s_tryopen(int argc, VALUE *argv, VALUE klass)
{
	long fd;
	VALUE pathname, flags, mode;
	struct open_args o;
	int retried = 0;
	VALUE rv;

	rb_scan_args(argc, argv, "12", &pathname, &flags, &mode);
	if (rb_respond_to(pathname, id_to_path))
		pathname = rb_funcall(pathname, id_to_path, 0);
	o.pathname = StringValueCStr(pathname);

	switch (TYPE(flags)) {
	case T_NIL: o.flags = O_RDONLY; break;
	case T_FIXNUM: o.flags = FIX2INT(flags); break;
	case T_BIGNUM: o.flags = NUM2INT(flags); break;
	default: rb_raise(rb_eArgError, "flags must be an Integer");
	}
	switch (TYPE(mode)) {
	case T_NIL: o.mode = 0666; break;
	case T_FIXNUM: o.mode = FIX2INT(mode); break;
	case T_BIGNUM: o.mode = NUM2INT(mode); break;
	default: rb_raise(rb_eArgError, "mode must be an Integer");
	}

retry:
	fd = (long)KGIO_WITHOUT_GVL(nogvl_open, &o, RUBY_UBF_IO, 0);
	if (fd < 0) {
		if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
			rb_gc();
			if (retried)
				rb_sys_fail(o.pathname);
			retried = 1;
			goto retry;
		}
		if (fd < 0) {
			int saved_errno = errno;

			if (!st_lookup(errno2sym, (st_data_t)errno, &rv)) {
				errno = saved_errno;
				rb_sys_fail(o.pathname);
			}
			return rv;
		}
	}
	rv = rb_funcall(klass, id_for_fd, 1, LONG2FIX(fd));
	set_file_path(rv, pathname);
	return rv;
}