[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]