ruby-changes:15122
From: nobu <ko1@a...>
Date: Sun, 21 Mar 2010 19:56:03 +0900 (JST)
Subject: [ruby-changes:15122] Ruby:r26999 (trunk): * io.c (rb_io_initialize): add autoclose argument to control close
nobu 2010-03-21 19:52:31 +0900 (Sun, 21 Mar 2010) New Revision: 26999 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=26999 Log: * io.c (rb_io_initialize): add autoclose argument to control close at finalization. [ruby-core:26222] * io.c (rb_io_autoclose_p, rb_io_set_autoclose): new methods. Modified files: trunk/ChangeLog trunk/io.c trunk/test/ruby/test_io.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 26998) +++ ChangeLog (revision 26999) @@ -1,3 +1,10 @@ +Sun Mar 21 19:52:27 2010 Nobuyoshi Nakada <nobu@r...> + + * io.c (rb_io_initialize): add autoclose argument to control close + at finalization. [ruby-core:26222] + + * io.c (rb_io_autoclose_p, rb_io_set_autoclose): new methods. + Sun Mar 21 19:50:04 2010 Tanaka Akira <akr@f...> * ext/socket: make sources rdoc friendly. Index: io.c =================================================================== --- io.c (revision 26998) +++ io.c (revision 26999) @@ -133,7 +133,7 @@ static ID id_write, id_read, id_getc, id_flush, id_readpartial; static VALUE sym_mode, sym_perm, sym_extenc, sym_intenc, sym_encoding, sym_open_args; -static VALUE sym_textmode, sym_binmode; +static VALUE sym_textmode, sym_binmode, sym_autoclose; struct timeval rb_time_interval(VALUE); @@ -6319,6 +6319,9 @@ * If the value is truth value, same as "b" in argument <code>mode</code>. * :binmode :: * If the value is truth value, same as "t" in argument <code>mode</code>. + * :autoclose :: + * If the value is +false+, the _fd_ will be kept open after this + * +IO+ instance gets finalized. * * Also <code>opt</code> can have same keys in <code>String#encode</code> for * controlling conversion between the external encoding and the internal encoding. @@ -6389,6 +6392,9 @@ rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError)); } #endif + if (!NIL_P(opt) && rb_hash_aref(opt, sym_autoclose) == Qfalse) { + fmode |= FMODE_PREP; + } MakeOpenFile(io, fp); fp->fd = fd; fp->mode = fmode; @@ -6483,6 +6489,53 @@ return io; } +/* + * call-seq: + * ios.autoclose? => true or false + * + * Returns +true+ if the underlying file descriptor of _ios_ will be + * closed automatically at its finalization, otherwise +false+. + */ + +static VALUE +rb_io_autoclose_p(VALUE io) +{ + rb_io_t *fptr; + rb_secure(4); + GetOpenFile(io, fptr); + return (fptr->mode & FMODE_PREP) ? Qfalse : Qtrue; +} + +/* + * call-seq: + * io.autoclose = bool => true or false + * + * Sets auto-close flag. + * + * f = open("/dev/null") + * IO.for_fd(f.fileno) + * # ... + * f.gets # may cause IOError + * + * f = open("/dev/null") + * IO.for_fd(f.fileno).autoclose = true + * # ... + * f.gets # won't cause IOError + */ + +static VALUE +rb_io_set_autoclose(VALUE io, VALUE autoclose) +{ + rb_io_t *fptr; + rb_secure(4); + GetOpenFile(io, fptr); + if (!RTEST(autoclose)) + fptr->mode |= FMODE_PREP; + else + fptr->mode &= ~FMODE_PREP; + return io; +} + static void argf_mark(void *ptr) { @@ -9803,6 +9856,9 @@ rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0); rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1); + rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0); + rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1); + rb_define_variable("$stdin", &rb_stdin); rb_stdin = prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>"); rb_define_hooked_variable("$stdout", &rb_stdout, 0, stdout_setter); @@ -9957,4 +10013,5 @@ sym_open_args = ID2SYM(rb_intern("open_args")); sym_textmode = ID2SYM(rb_intern("textmode")); sym_binmode = ID2SYM(rb_intern("binmode")); + sym_autoclose = ID2SYM(rb_intern("autoclose")); } Index: test/ruby/test_io.rb =================================================================== --- test/ruby/test_io.rb (revision 26998) +++ test/ruby/test_io.rb (revision 26999) @@ -1266,6 +1266,49 @@ f.close end + def try_fdopen(fd, autoclose = true, level = 100) + if level > 0 + try_fdopen(fd, autoclose, level - 1) + GC.start + level + else + IO.for_fd(fd, autoclose: autoclose) + nil + end + end + + def test_autoclose + feature2250 = '[ruby-core:26222]' + pre = 'ft2250' + + Tempfile.new(pre) do |t| + f = IO.for_fd(t.fileno) + assert_equal(true, f.autoclose?) + f.autoclose = false + assert_equal(false, f.autoclose?) + f.close + assert_nothing_raised(Errno::EBADF) {t.close} + + t.open + f = IO.for_fd(t.fileno, autoclose: false) + assert_equal(false, f.autoclose?) + f.autoclose = true + assert_equal(true, f.autoclose?) + f.close + assert_raise(Errno::EBADF) {t.close} + end + + Tempfile.new(pre) do |t| + try_fdopen(t.fileno) + assert_raise(Errno::EBADF) {t.close} + end + + Tempfile.new(pre) do |t| + try_fdopen(f.fileno, false) + assert_nothing_raised(Errno::EBADF) {t.close} + end + end + def test_open_redirect o = Object.new def o.to_open; self; end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/