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

ruby-changes:29730

From: knu <ko1@a...>
Date: Fri, 5 Jul 2013 02:22:18 +0900 (JST)
Subject: [ruby-changes:29730] knu:r41782 (trunk): * lib/fileutils.rb (FileUtils.chmod{,_R}): Enhance the symbolic

knu	2013-07-05 02:22:08 +0900 (Fri, 05 Jul 2013)

  New Revision: 41782

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=41782

  Log:
    * lib/fileutils.rb (FileUtils.chmod{,_R}): Enhance the symbolic
      mode parser to support the permission symbols u/g/o and multiple
      actions as defined in SUS, so that chmod("g=o+w", file) works as
      expected.  Invalid symbolic modes are now rejected with
      ArgumentError.

  Modified files:
    trunk/ChangeLog
    trunk/lib/fileutils.rb
    trunk/test/fileutils/test_fileutils.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 41781)
+++ ChangeLog	(revision 41782)
@@ -1,9 +1,15 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
-Fri Jul  5 01:23:33 2013  Akinori MUSHA  <knu@i...>
+Fri Jul  5 02:14:00 2013  Akinori MUSHA  <knu@i...>
 
 	* lib/fileutils.rb (FileUtils#symbolic_modes_to_i): Fix the wrong
 	  character class [+-=], which happened to match all desired
 	  characters but also match undesired characters.
 
+	* lib/fileutils.rb (FileUtils.chmod{,_R}): Enhance the symbolic
+	  mode parser to support the permission symbols u/g/o and multiple
+	  actions as defined in SUS, so that chmod("g=o+w", file) works as
+	  expected.  Invalid symbolic modes are now rejected with
+	  ArgumentError.
+
 Fri Jul  5 00:25:39 2013  Nobuyoshi Nakada  <nobu@r...>
 
 	* lib/mkmf.rb (have_framework): allow header file to check.
Index: lib/fileutils.rb
===================================================================
--- lib/fileutils.rb	(revision 41781)
+++ lib/fileutils.rb	(revision 41782)
@@ -868,62 +868,78 @@ module FileUtils https://github.com/ruby/ruby/blob/trunk/lib/fileutils.rb#L868
   OPT_TABLE['install'] = [:mode, :preserve, :noop, :verbose]
 
   def user_mask(target)  #:nodoc:
-    mask = 0
-    target.each_byte do |byte_chr|
-      case byte_chr.chr
-        when "u"
-          mask |= 04700
-        when "g"
-          mask |= 02070
-        when "o"
-          mask |= 01007
-        when "a"
-          mask |= 07777
+    target.each_char.inject(0) do |mask, chr|
+      case chr
+      when "u"
+        mask | 04700
+      when "g"
+        mask | 02070
+      when "o"
+        mask | 01007
+      when "a"
+        mask | 07777
+      else
+        raise ArgumentError, "invalid `who' symbol in file mode: #{chr}"
       end
     end
-    mask
   end
   private_module_function :user_mask
 
-  def mode_mask(mode, path)  #:nodoc:
-    mask = 0
-    mode.each_byte do |byte_chr|
-      case byte_chr.chr
-        when "r"
-          mask |= 0444
-        when "w"
-          mask |= 0222
-        when "x"
-          mask |= 0111
-        when "X"
-          mask |= 0111 if FileTest::directory? path
-        when "s"
-          mask |= 06000
-        when "t"
-          mask |= 01000
-      end
+  def apply_mask(mode, user_mask, op, mode_mask)
+    case op
+    when '='
+      (mode & ~user_mask) | (user_mask & mode_mask)
+    when '+'
+      mode | (user_mask & mode_mask)
+    when '-'
+      mode & ~(user_mask & mode_mask)
     end
-    mask
   end
-  private_module_function :mode_mask
+  private_module_function :apply_mask
 
-  def symbolic_modes_to_i(modes, path)  #:nodoc:
-    current_mode = (File.stat(path).mode & 07777)
-    modes.split(/,/).inject(0) do |mode, mode_sym|
-      mode_sym = "a#{mode_sym}" if mode_sym =~ %r!^[=+-]!
-      target, mode = mode_sym.split %r![=+-]!
+  def symbolic_modes_to_i(mode_sym, path)  #:nodoc:
+    mode_sym.split(/,/).inject(File.stat(path).mode & 07777) do |current_mode, clause|
+      target, *actions = clause.split(/([=+-])/)
+      raise ArgumentError, "invalid file mode: #{mode_sym}" if actions.empty?
+      target = 'a' if target.empty?
       user_mask = user_mask(target)
-      mode_mask = mode_mask(mode ? mode : "", path)
+      actions.each_slice(2) do |op, perm|
+        need_apply = op == '='
+        mode_mask = (perm || '').each_char.inject(0) do |mask, chr|
+          case chr
+          when "r"
+            mask | 0444
+          when "w"
+            mask | 0222
+          when "x"
+            mask | 0111
+          when "X"
+            if FileTest.directory? path
+              mask | 0111
+            else
+              mask
+            end
+          when "s"
+            mask | 06000
+          when "t"
+            mask | 01000
+          when "u", "g", "o"
+            if mask.nonzero?
+              current_mode = apply_mask(current_mode, user_mask, op, mask)
+            end
+            need_apply = false
+            copy_mask = user_mask(chr)
+            (current_mode & copy_mask) / (copy_mask & 0111) * (user_mask & 0111)
+          else
+            raise ArgumentError, "invalid `perm' symbol in file mode: #{chr}"
+          end
+        end
 
-      case mode_sym
-        when /=/
-          current_mode &= ~(user_mask)
-          current_mode |= user_mask & mode_mask
-        when /\+/
-          current_mode |= user_mask & mode_mask
-        when /-/
-          current_mode &= ~(user_mask & mode_mask)
+        if mode_mask.nonzero? || need_apply
+          current_mode = apply_mask(current_mode, user_mask, op, mode_mask)
+        end
       end
+      current_mode
     end
   end
   private_module_function :symbolic_modes_to_i
Index: test/fileutils/test_fileutils.rb
===================================================================
--- test/fileutils/test_fileutils.rb	(revision 41781)
+++ test/fileutils/test_fileutils.rb	(revision 41782)
@@ -932,6 +932,12 @@ class TestFileUtils https://github.com/ruby/ruby/blob/trunk/test/fileutils/test_fileutils.rb#L932
     check_singleton :chmod
 
     touch 'tmp/a'
+    chmod "u=wrx,g=rx,o=x", 'tmp/a'
+    assert_equal 0751, File.stat('tmp/a').mode & 07777
+    chmod "g+w-x", 'tmp/a'
+    assert_equal 0761, File.stat('tmp/a').mode & 07777
+    chmod "o+r,g=o+w,o-r,u-o", 'tmp/a' # 761 => 763 => 773 => 771 => 671
+    assert_equal 0671, File.stat('tmp/a').mode & 07777
     chmod "u=wrx,g=,o=", 'tmp/a'
     assert_equal 0700, File.stat('tmp/a').mode & 0777
     chmod "u=rx,go=", 'tmp/a'
@@ -956,6 +962,26 @@ class TestFileUtils https://github.com/ruby/ruby/blob/trunk/test/fileutils/test_fileutils.rb#L962
       assert_equal 0500, File.stat('tmp/a').mode & 07777
     end
 
+    assert_raises_with_message(ArgumentError, /invalid\b.*\bfile mode/) {
+      chmod "a", 'tmp/a'
+    }
+
+    assert_raises_with_message(ArgumentError, /invalid\b.*\bfile mode/) {
+      chmod "x+a", 'tmp/a'
+    }
+
+    assert_raises_with_message(ArgumentError, /invalid\b.*\bfile mode/) {
+      chmod "u+z", 'tmp/a'
+    }
+
+    assert_raises_with_message(ArgumentError, /invalid\b.*\bfile mode/) {
+      chmod ",+x", 'tmp/a'
+    }
+
+    assert_raises_with_message(ArgumentError, /invalid\b.*\bfile mode/) {
+      chmod "755", 'tmp/a'
+    }
+
   end if have_file_perm?
 
 

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

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