1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* 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.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@41782 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
knu 2013-07-04 17:22:08 +00:00
parent 45116b6a6d
commit a0011cd54d
3 changed files with 94 additions and 46 deletions

View file

@ -1,9 +1,15 @@
Fri Jul 5 01:23:33 2013 Akinori MUSHA <knu@iDaemons.org>
Fri Jul 5 02:14:00 2013 Akinori MUSHA <knu@iDaemons.org>
* 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@ruby-lang.org>
* lib/mkmf.rb (have_framework): allow header file to check.

View file

@ -868,62 +868,78 @@ module FileUtils
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

View file

@ -932,6 +932,12 @@ class TestFileUtils
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
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?