ruby-changes:52029
From: kazu <ko1@a...>
Date: Thu, 9 Aug 2018 17:49:15 +0900 (JST)
Subject: [ruby-changes:52029] kazu:r64245 (trunk): add 'x' mode character for O_EXCL
kazu 2018-08-09 17:49:09 +0900 (Thu, 09 Aug 2018) New Revision: 64245 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=64245 Log: add 'x' mode character for O_EXCL [Feature #11258] Patch by cremno (cremno phobia) Modified files: trunk/NEWS trunk/include/ruby/io.h trunk/io.c trunk/test/ruby/test_io.rb Index: io.c =================================================================== --- io.c (revision 64244) +++ io.c (revision 64245) @@ -1369,6 +1369,11 @@ io_binwrite(VALUE str, const char *ptr, https://github.com/ruby/ruby/blob/trunk/io.c#L1369 # define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \ (fmode & FMODE_TEXTMODE) ? (c) : (a)) + +#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \ + MODE_BTMODE(d, e, f) : \ + MODE_BTMODE(a, b, c)) + static VALUE do_writeconv(VALUE str, rb_io_t *fptr, int *converted) { @@ -5360,10 +5365,10 @@ rb_io_fmode_modestr(int fmode) https://github.com/ruby/ruby/blob/trunk/io.c#L5365 case FMODE_READABLE: return MODE_BTMODE("r", "rb", "rt"); case FMODE_WRITABLE: - return MODE_BTMODE("w", "wb", "wt"); + return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx"); case FMODE_READWRITE: if (fmode & FMODE_CREATE) { - return MODE_BTMODE("w+", "wb+", "wt+"); + return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x"); } return MODE_BTMODE("r+", "rb+", "rt+"); } @@ -5412,6 +5417,11 @@ rb_io_modestr_fmode(const char *modestr) https://github.com/ruby/ruby/blob/trunk/io.c#L5417 case '+': fmode |= FMODE_READWRITE; break; + case 'x': + if (modestr[0] != 'w') + goto error; + fmode |= FMODE_EXCL; + break; default: goto error; case ':': @@ -5455,6 +5465,9 @@ rb_io_oflags_fmode(int oflags) https://github.com/ruby/ruby/blob/trunk/io.c#L5465 if (oflags & O_CREAT) { fmode |= FMODE_CREATE; } + if (oflags & O_EXCL) { + fmode |= FMODE_EXCL; + } #ifdef O_BINARY if (oflags & O_BINARY) { fmode |= FMODE_BINMODE; @@ -5490,6 +5503,9 @@ rb_io_fmode_oflags(int fmode) https://github.com/ruby/ruby/blob/trunk/io.c#L5503 if (fmode & FMODE_CREATE) { oflags |= O_CREAT; } + if (fmode & FMODE_EXCL) { + oflags |= O_EXCL; + } #ifdef O_BINARY if (fmode & FMODE_BINMODE) { oflags |= O_BINARY; @@ -5513,7 +5529,11 @@ rb_io_oflags_modestr(int oflags) https://github.com/ruby/ruby/blob/trunk/io.c#L5529 #else # define MODE_BINARY(a,b) (a) #endif - int accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR); + int accmode; + if (oflags & O_EXCL) { + rb_raise(rb_eArgError, "exclusive access mode is not supported"); + } + accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR); if (oflags & O_APPEND) { if (accmode == O_WRONLY) { return MODE_BINARY("a", "ab"); @@ -5522,7 +5542,7 @@ rb_io_oflags_modestr(int oflags) https://github.com/ruby/ruby/blob/trunk/io.c#L5542 return MODE_BINARY("a+", "ab+"); } } - switch (oflags & (O_RDONLY|O_WRONLY|O_RDWR)) { + switch (accmode) { default: rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags); case O_RDONLY: @@ -8052,6 +8072,10 @@ rb_io_make_open_file(VALUE obj) https://github.com/ruby/ruby/blob/trunk/io.c#L8072 * * "t" Text file mode * + * The exclusive access mode ("x") can be used together with "w" to ensure + * the file is created. <code>Errno::EEXIST</code> is raised when it already + * exists. It may not be supported with all kinds of streams (e.g. pipes). + * * When the open mode of original IO is read only, the mode cannot be * changed to be writable. Similarly, the open mode cannot be changed from * write only to readable. Index: include/ruby/io.h =================================================================== --- include/ruby/io.h (revision 64244) +++ include/ruby/io.h (revision 64245) @@ -113,6 +113,7 @@ typedef struct rb_io_t { https://github.com/ruby/ruby/blob/trunk/include/ruby/io.h#L113 #define FMODE_APPEND 0x00000040 #define FMODE_CREATE 0x00000080 /* #define FMODE_NOREVLOOKUP 0x00000100 */ +#define FMODE_EXCL 0x00000400 #define FMODE_TRUNC 0x00000800 #define FMODE_TEXTMODE 0x00001000 /* #define FMODE_PREP 0x00010000 */ Index: NEWS =================================================================== --- NEWS (revision 64244) +++ NEWS (revision 64245) @@ -81,6 +81,10 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L81 * Hash#filter is a new alias for Hash#select [Feature #13784] * Hash#filter! is a new alias for Hash#select! [Feature #13784] +* IO + + * new mode character 'x' to open files for exclusive access [Feature #11258] + * Kernel * Kernel#then is a new alias for Kernel#yield_self [Feature #14594] Index: test/ruby/test_io.rb =================================================================== --- test/ruby/test_io.rb (revision 64244) +++ test/ruby/test_io.rb (revision 64245) @@ -3555,6 +3555,14 @@ __END__ https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io.rb#L3555 end end if File::BINARY != 0 + def test_exclusive_mode + make_tempfile do |t| + assert_raise(Errno::EEXIST){ open(t.path, 'wx'){} } + assert_raise(ArgumentError){ open(t.path, 'rx'){} } + assert_raise(ArgumentError){ open(t.path, 'ax'){} } + end + end + def test_race_gets_and_close assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}") bug13076 = '[ruby-core:78845] [Bug #13076]' -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/