From: Tanaka Akira Date: 2004-04-15T15:47:29+09:00 Subject: [ruby-dev:23381] gdbm read only access ふと、GDBM を read only で access したくなったのですが、GDBM.open には gdbm_open の read_write 引数に GDBM_READER を渡す方法がないことに気が つきました。 GDBM.open は常にとりあえず書き込み可能な open を試してみて、それが失敗 したら読み込みのみの open を試すようです。 しかし、application が read only と分かっている時に write mode での open を行うと、なんかのひょうしにファイルを壊してしまうのが恐いので、 次のように GDBM::READER などを指定した場合には指定した通りの read_write 引数を渡すようにするのはどうでしょうか。 ただし、GDBM_READER は 0 であり、そのままだと指定されたかどうか分から ないため、今までの指定しなかった時の挙動と区別するために 0x20000000 を 加えてあります。 Index: ext/gdbm/gdbm.c =================================================================== RCS file: /src/ruby/ext/gdbm/gdbm.c,v retrieving revision 1.27 diff -u -r1.27 gdbm.c --- ext/gdbm/gdbm.c 6 May 2003 06:51:30 -0000 1.27 +++ ext/gdbm/gdbm.c 15 Apr 2004 06:38:39 -0000 @@ -16,6 +16,8 @@ static VALUE rb_cGDBM, rb_eGDBMError, rb_eGDBMFatalError; +#define RUBY_GDBM_RW_BIT 0x20000000 + #define MY_BLOCK_SIZE (2048) #define MY_FATAL_FUNC rb_gdbm_fatal static void @@ -100,16 +102,23 @@ SafeStringValue(file); - dbm = 0; - if (mode >= 0) - dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, - GDBM_WRCREAT|flags, mode, MY_FATAL_FUNC); - if (!dbm) + if (flags & RUBY_GDBM_RW_BIT) { + flags &= ~RUBY_GDBM_RW_BIT; dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, - GDBM_WRITER|flags, 0, MY_FATAL_FUNC); - if (!dbm) - dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, - GDBM_READER|flags, 0, MY_FATAL_FUNC); + flags, mode, MY_FATAL_FUNC); + } + else { + dbm = 0; + if (mode >= 0) + dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, + GDBM_WRCREAT|flags, mode, MY_FATAL_FUNC); + if (!dbm) + dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, + GDBM_WRITER|flags, 0, MY_FATAL_FUNC); + if (!dbm) + dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, + GDBM_READER|flags, 0, MY_FATAL_FUNC); + } if (!dbm) { if (mode == -1) return Qnil; @@ -992,13 +1001,12 @@ rb_define_method(rb_cGDBM, "to_a", fgdbm_to_a, 0); rb_define_method(rb_cGDBM, "to_hash", fgdbm_to_hash, 0); - /* flags for gdbm_opn() */ - /* - rb_define_const(rb_cGDBM, "READER", INT2FIX(GDBM_READER)); - rb_define_const(rb_cGDBM, "WRITER", INT2FIX(GDBM_WRITER)); - rb_define_const(rb_cGDBM, "WRCREAT", INT2FIX(GDBM_WRCREAT)); - rb_define_const(rb_cGDBM, "NEWDB", INT2FIX(GDBM_NEWDB)); - */ + /* flags for gdbm_open() */ + rb_define_const(rb_cGDBM, "READER", INT2FIX(GDBM_READER|RUBY_GDBM_RW_BIT)); + rb_define_const(rb_cGDBM, "WRITER", INT2FIX(GDBM_WRITER|RUBY_GDBM_RW_BIT)); + rb_define_const(rb_cGDBM, "WRCREAT", INT2FIX(GDBM_WRCREAT|RUBY_GDBM_RW_BIT)); + rb_define_const(rb_cGDBM, "NEWDB", INT2FIX(GDBM_NEWDB|RUBY_GDBM_RW_BIT)); + rb_define_const(rb_cGDBM, "FAST", INT2FIX(GDBM_FAST)); /* this flag is obsolete in gdbm 1.8. On gdbm 1.8, fast mode is default behavior. */ ちなみに、gdbm には freeze も効きません。 % ruby -rgdbm -e 'GDBM.open("zz.dbm", 0644) {|dbm| dbm.freeze; dbm["a"] = "a"; p dbm["a"]}' "a" -- [田中 哲][たなか あきら][Tanaka Akira]