aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog14
-rw-r--r--NEWS4
-rw-r--r--lib/fileutils.rb92
-rw-r--r--test/fileutils/test_fileutils.rb41
4 files changed, 149 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index e40b890a41..1798485ad2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+Mon May 2 01:02:04 2011 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * lib/fileutils.rb (FileUtils#chmod): accept symbolic mode argument.
+ The patch was written by takkanm. [ruby-core:26029][Feature #2190]
+
+ * lib/fileutils.rb (FileUtils#fu_mode): new helper function.
+ * lib/fileutils.rb (FileUtils#symbolic_modes_to_i): ditto.
+ * lib/fileutils.rb (FileUtils#mode_mask): ditto.
+ * lib/fileutils.rb (FileUtils#user_mask): ditto.
+
+ * test/fileutils/test_fileutils.rb (TestFileUtils#test_chmod_symbol_mode):
+ new test for the above symbolic mode.
+ * test/fileutils/test_fileutils.rb (TestFileUtils#test_chmod_R): ditto.
+
Mon May 2 00:36:12 2011 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
* ext/socket/init.c (rsock_connect): add to care EINTR. based
diff --git a/NEWS b/NEWS
index fca7558321..698453b43e 100644
--- a/NEWS
+++ b/NEWS
@@ -143,6 +143,10 @@ with all sufficient information, see the ChangeLog file.
* Zlib.deflate
* Zlib.inflate
+* FileUtils
+ * extended method:
+ * FileUtils#chmod supports symbolic mode argument.
+
=== Language changes
* Regexps now support Unicode 6.0. (new characters and scripts)
diff --git a/lib/fileutils.rb b/lib/fileutils.rb
index dc956a67ab..423257cd15 100644
--- a/lib/fileutils.rb
+++ b/lib/fileutils.rb
@@ -860,23 +860,110 @@ module FileUtils
OPT_TABLE['install'] = [:mode, :preserve, :noop, :verbose]
+ def user_mask(target)
+ 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
+ end
+ end
+ mask
+ end
+ private_module_function :user_mask
+
+ def mode_mask(mode, path)
+ 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
+ end
+ mask
+ end
+ private_module_function :mode_mask
+
+ def symbolic_modes_to_i(modes, path)
+ 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![+-=]!
+ user_mask = user_mask(target)
+ mode_mask = mode_mask(mode ? mode : "", path)
+
+ 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)
+ end
+ end
+ end
+ private_module_function :symbolic_modes_to_i
+
+ def fu_mode(mode, path)
+ mode.is_a?(String) ? symbolic_modes_to_i(mode, path) : mode
+ end
+ private_module_function :fu_mode
+
#
# Options: noop verbose
#
# Changes permission bits on the named files (in +list+) to the bit pattern
# represented by +mode+.
#
+ # +mode+ is the symbolic and absolute mode can be used.
+ #
+ # Absolute mode is
# FileUtils.chmod 0755, 'somecommand'
# FileUtils.chmod 0644, %w(my.rb your.rb his.rb her.rb)
# FileUtils.chmod 0755, '/usr/bin/ruby', :verbose => true
#
+ # Symbolic mode is
+ # FileUtils.chmod "u=wrx,go=rx", 'somecommand'
+ # FileUtils.chmod "u=wr,go=rr", %w(my.rb your.rb his.rb her.rb)
+ # FileUtils.chmod "u=wrx,go=rx", '/usr/bin/ruby', :verbose => true
+ #
+ # "a" is user, group, other mask.
+ # "u" is user's mask.
+ # "g" is group's mask.
+ # "o" is other's mask.
+ # "w" is write permission.
+ # "r" is read permission.
+ # "x" is execute permission.
+ # "s" is uid, gid.
+ # "t" is sticky bit.
+ # "+" is added to a class given the specified mode.
+ # "-" Is removed from a given class given mode.
+ # "=" Is the exact nature of the class will be given a specified mode.
+
def chmod(mode, list, options = {})
fu_check_options options, OPT_TABLE['chmod']
list = fu_list(list)
fu_output_message sprintf('chmod %o %s', mode, list.join(' ')) if options[:verbose]
return if options[:noop]
list.each do |path|
- Entry_.new(path).chmod mode
+ Entry_.new(path).chmod(fu_mode(mode, path))
end
end
module_function :chmod
@@ -890,6 +977,7 @@ module FileUtils
# to the bit pattern represented by +mode+.
#
# FileUtils.chmod_R 0700, "/tmp/app.#{$$}"
+ # FileUtils.chmod_R "u=wrx", "/tmp/app.#{$$}"
#
def chmod_R(mode, list, options = {})
fu_check_options options, OPT_TABLE['chmod_R']
@@ -901,7 +989,7 @@ module FileUtils
list.each do |root|
Entry_.new(root).traverse do |ent|
begin
- ent.chmod mode
+ ent.chmod(fu_mode(mode, ent.path))
rescue
raise unless options[:force]
end
diff --git a/test/fileutils/test_fileutils.rb b/test/fileutils/test_fileutils.rb
index 290ba21f0d..68f363109d 100644
--- a/test/fileutils/test_fileutils.rb
+++ b/test/fileutils/test_fileutils.rb
@@ -893,6 +893,29 @@ class TestFileUtils
assert_equal 0500, File.stat('tmp/a').mode & 0777
end if have_file_perm?
+ def test_chmod_symbol_mode
+ check_singleton :chmod
+
+ touch 'tmp/a'
+ chmod "u=wrx,g=,o=", 'tmp/a'
+ assert_equal 0700, File.stat('tmp/a').mode & 0777
+ chmod "u=rx,go=", 'tmp/a'
+ assert_equal 0500, File.stat('tmp/a').mode & 0777
+ chmod "+wrx", 'tmp/a'
+ assert_equal 0777, File.stat('tmp/a').mode & 0777
+ chmod "u+s,o=s", 'tmp/a'
+ assert_equal 04770, File.stat('tmp/a').mode & 07777
+ chmod "u-w,go-wrx", 'tmp/a'
+ assert_equal 04500, File.stat('tmp/a').mode & 07777
+ chmod "+s", 'tmp/a'
+ assert_equal 06500, File.stat('tmp/a').mode & 07777
+ chmod "u+t,o+t", 'tmp/a'
+ assert_equal 07500, File.stat('tmp/a').mode & 07777
+ chmod "a-t,a-s", 'tmp/a'
+ assert_equal 0500, File.stat('tmp/a').mode & 07777
+ end if have_file_perm?
+
+
def test_chmod_R
check_singleton :chmod_R
@@ -911,6 +934,24 @@ class TestFileUtils
chmod_R 0700, 'tmp/dir' # to remove
end if have_file_perm?
+ def test_chmod_symbol_mode_R
+ check_singleton :chmod_R
+
+ mkdir_p 'tmp/dir/dir'
+ touch %w( tmp/dir/file tmp/dir/dir/file )
+ chmod_R "u=wrx,g=,o=", 'tmp/dir'
+ assert_equal 0700, File.stat('tmp/dir').mode & 0777
+ assert_equal 0700, File.stat('tmp/dir/file').mode & 0777
+ assert_equal 0700, File.stat('tmp/dir/dir').mode & 0777
+ assert_equal 0700, File.stat('tmp/dir/dir/file').mode & 0777
+ chmod_R "u=xr,g+X,o=", 'tmp/dir'
+ assert_equal 0510, File.stat('tmp/dir').mode & 0777
+ assert_equal 0500, File.stat('tmp/dir/file').mode & 0777
+ assert_equal 0510, File.stat('tmp/dir/dir').mode & 0777
+ assert_equal 0500, File.stat('tmp/dir/dir/file').mode & 0777
+ chmod_R 0700, 'tmp/dir' # to remove
+ end if have_file_perm?
+
# FIXME: How can I test this method?
def test_chown
check_singleton :chown