From: Trevor Vaughan <[email protected]>
Signed-off-by: Trevor Vaughan - Onyx Point <[email protected]> --- lib/puppet/type/file.rb | 2 +- lib/puppet/type/file/mode.rb | 141 +++++++++++++++++++++++++++++++++--------- spec/unit/type/file/mode.rb | 61 ++++++++++++++++++ 3 files changed, 173 insertions(+), 31 deletions(-) create mode 100755 spec/unit/type/file/mode.rb diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb index 2f5b5df..ede4b1a 100644 --- a/lib/puppet/type/file.rb +++ b/lib/puppet/type/file.rb @@ -725,7 +725,7 @@ module Puppet path = self[:path] end - mode = self.should(:mode) # might be nil + mode = self.should(:mode) ? self.property(:mode).sym2oct(self.stat,self.should(:mode)) : nil # might be nil umask = mode ? 000 : 022 Puppet::Util.withumask(umask) do diff --git a/lib/puppet/type/file/mode.rb b/lib/puppet/type/file/mode.rb index 83034cb..da0d09d 100755 --- a/lib/puppet/type/file/mode.rb +++ b/lib/puppet/type/file/mode.rb @@ -4,9 +4,8 @@ module Puppet Puppet::Type.type(:file).newproperty(:mode) do require 'etc' - desc "Mode the file should be. Currently relatively limited: - you must specify the exact mode the file should be. - + desc "Mode the file should be. You may specify either the precise octal mode or the POSIX symbolic mode per GNU coreutils chmod. + Note that when you set the mode of a directory, Puppet always sets the search/traverse (1) bit anywhere the read (4) bit is set. This is almost always what you want: read allows you to list the @@ -22,16 +21,90 @@ module Puppet In this case all of the files underneath ``/some/dir`` will have mode 644, and all of the directories will have mode 755." - @event = :file_changed + # The bitwise position of the UGO fields. + SYMBASE = { + "u" => 6, + "g" => 3, + "o" => 0 + } + + # The general mask for activating the appropriate sections of 'how'. + SYMLEFT = { + "u" => 05700, + "g" => 03070, + "o" => 01007, + "a" => 07777 + } + # The regular expression for matching a valid symbolic mode. + SYMREG = /^(([ugoa]+)([+-=])([rwxst]+|[ugo]),?)+$/ + + # This is a helper that takes the current mode and the new mode and + # returns the adjusted decimal representation octal file mode (0700, + # etc...) + # + # The current mode (curmode) can be represented either as an integer + # string or as a File::Stat object. + def sym2oct(curmode,newmode) + if !newmode.nil? and newmode.to_s =~ /^\d+$/ then + value = newmode + else + # Set this to 0600 so that we can actually read and write the + # file as a normal user. + if curmode.nil? then + value = 00600 + elsif curmode.is_a?(File::Stat) then + value = curmode.mode & 07777 + else + value = Integer("0#{curmode}") + end + + # This needs to remain variable. + right = { + "r" => 00444, + "w" => 00222, + "x" => 00111, + "s" => 06000, + "t" => 01000, + "u" => 00700, + "g" => 00070, + "o" => 00007 + } + + newmode.split(",").each do |cmd| + match = cmd.match(SYMREG) or return value + # The following vars are directly dependent on the + # structure of SYMREG above + who = match[2] + what = match[3] + how = match[4].split(//).uniq.to_s + if how =~ /^[ugo]$/ then + who.split(//).uniq.each do |lhv| + right[how] = ( ((value << (SYMBASE[lhv] - SYMBASE[how])) & right[lhv]) | ( value & ~right[lhv] ) ) & 0777 + end + end + who = who.split(//).inject(num=0) {|num,b| num |= SYMLEFT[b]; num } + how = how.split(//).inject(num=0) {|num,b| num |= right[b]; num } + mask = who & how + case what + when "+": value = value | mask + when "-": value = value & ~mask + when "=": value = ( mask & who ) | ( value & ~(who & 0777) ) + end + end + value = "0%o" % value + end + Integer(value) + end + + # Our modes are octal, so make sure they print correctly. Other # valid values are symbols, basically def is_to_s(currentvalue) - case currentvalue - when Integer + if currentvalue.is_a?(Integer) then return "%o" % currentvalue - when Symbol + elsif ( currentvalue.is_a?(Symbol) or ( currentvalue.is_a?(String) and currentvalue.match(SYMREG))) then return currentvalue else raise Puppet::DevError, "Invalid current value for mode: %s" % @@ -40,10 +113,9 @@ module Puppet end def should_to_s(newvalue = @should) - case newvalue - when Integer + if newvalue.is_a?(Integer) then return "%o" % newvalue - when Symbol + elsif ( newvalue.is_a?(Symbol) or ( newvalue.is_a?(String) and newvalue.match(SYMREG))) then return newvalue else raise Puppet::DevError, "Invalid 'should' value for mode: %s" % @@ -52,29 +124,32 @@ module Puppet end munge do |should| - # this is pretty hackish, but i need to make sure the number is in - # octal, yet the number can only be specified as a string right now + # This handles both numbers and symbolic modes matching SYMREG + # + # Note: This now returns a string and the accepting function must + # know how to handle it! + value = should if value.is_a?(String) - unless value =~ /^\d+$/ - raise Puppet::Error, "File modes can only be numbers, not %s" % + if value =~ /^\d+$/ then + unless value =~ /^0/ + value = "0#{value}" + end + + old = value + begin + value = Integer(value) + rescue ArgumentError => detail + raise Puppet::DevError, "Could not convert %s to integer" % + old.inspect + end + elsif value.match(SYMREG).nil? then + raise Puppet::DevError, "Symbolic mode %s does not match #{SYMREG}" % value.inspect end - # Make sure our number looks like octal. - unless value =~ /^0/ - value = "0" + value - end - old = value - begin - value = Integer(value) - rescue ArgumentError => detail - raise Puppet::DevError, "Could not convert %s to integer" % - old.inspect - end end - return value - end + end # If we're a directory, we need to be executable for all cases # that are readable. This should probably be selectable, but eh. @@ -99,7 +174,14 @@ module Puppet self.debug "Not managing symlink mode" return true else - return super(currentvalue) + retval = super(currentvalue) + if !retval then + if currentvalue == sym2oct(resource.stat,self.should) then + retval = true + end + end + + return retval end end @@ -120,8 +202,7 @@ module Puppet end def sync - mode = self.should - + mode = sym2oct(resource.stat,self.should) begin File.chmod(mode, @resource[:path]) rescue => detail diff --git a/spec/unit/type/file/mode.rb b/spec/unit/type/file/mode.rb new file mode 100755 index 0000000..4cdbc36 --- /dev/null +++ b/spec/unit/type/file/mode.rb @@ -0,0 +1,61 @@ +#!/usr/bin/env ruby + +Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } + +property = Puppet::Type.type(:file).attrclass(:mode) + +describe property do + before do + @resource = stub 'resource', :line => "foo", :file => "bar" + @mode = property.new :resource => @resource + end + + it "should have a method for converting symbolic modes to octal modes" do + @mode.must respond_to(:sym2oct) + end + it "should be able to apply three digit numeric octal modes" do + @mode.sym2oct("777",Integer("0640")).should == Integer("0640") + end + it "should be able to apply additive symbolic user modes" do + @mode.sym2oct("640","u+x").should == Integer("0740") + end + it "should be able to apply subtractive symbolic user modes" do + @mode.sym2oct("640","u-w").should == Integer("0440") + end + it "should be able to apply equality symbolic user modes" do + @mode.sym2oct("640","u=r").should == Integer("0440") + end + it "should be able to apply referential equality symbolic user modes" do + @mode.sym2oct("640","u=g").should == Integer("0440") + end + it "should be able to apply additive symbolic group modes" do + @mode.sym2oct("640","g+x").should == Integer("0650") + end + it "should be able to apply subtractive symbolic group modes" do + @mode.sym2oct("640","g-r").should == Integer("0600") + end + it "should be able to apply equality symbolic group modes" do + @mode.sym2oct("640","g=rwx").should == Integer("0670") + end + it "should be able to apply referential equality symbolic group modes" do + @mode.sym2oct("640","g=o").should == Integer("0600") + end + it "should be able to apply additive symbolic other modes" do + @mode.sym2oct("640","o+rx").should == Integer("0645") + end + it "should be able to apply subtractive symbolic other modes" do + @mode.sym2oct("647","o-rx").should == Integer("0642") + end + it "should be able to apply equality symbolic other modes" do + @mode.sym2oct("647","o-rx").should == Integer("0642") + end + it "should be able to apply referential equality symbolic other modes" do + @mode.sym2oct("647","o=u").should == Integer("0646") + end + it "should be able to apply multi-part modes" do + @mode.sym2oct("640","o=u,g=o,u-w").should == Integer("0466") + end + it "should not be able to apply invalid modes" do + @mode.sym2oct("640","go-write-a-letter").should == Integer("0640") + end +end -- 1.6.2.5 -- You received this message because you are subscribed to the Google Groups "Puppet Developers" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en.
