diff options
author | knu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-07-04 17:22:08 +0000 |
---|---|---|
committer | knu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-07-04 17:22:08 +0000 |
commit | a0011cd54d1da03ef7097092a6cdf2daaa33fc35 (patch) | |
tree | 7da8901e3e5f22df81850583d376b91efd6d454d /lib | |
parent | 45116b6a6d7c3c0ef927863ed947cce4146ea3f1 (diff) | |
download | ruby-a0011cd54d1da03ef7097092a6cdf2daaa33fc35.tar.gz |
* 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
Diffstat (limited to 'lib')
-rw-r--r-- | lib/fileutils.rb | 108 |
1 files changed, 62 insertions, 46 deletions
diff --git a/lib/fileutils.rb b/lib/fileutils.rb index a75aab5f04..cee60892fa 100644 --- a/lib/fileutils.rb +++ b/lib/fileutils.rb @@ -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) - - 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) + 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 + + 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 |