# module Puppet::Util::SymbolicFileMode

### Constants

SetGIDBit
SetUIDBit
StickyBit
SymbolicMode
SymbolicSpecialToBit

### Public Instance Methods

normalize_symbolic_mode(value) click to toggle source

    # File lib/puppet/util/symbolic_file_mode.rb, line 20
    def normalize_symbolic_mode(value)
      return nil if value.nil?

      # We need to treat integers as octal numbers.
      if value.is_a? Numeric then
        return value.to_s(8)
      elsif value =~ /^0?[0-7]{1,4}$/ then
        return value.to_i(8).to_s(8)
      else
        return value
      end
    end

symbolic_mode_to_int(modification, to_mode = 0, is_a_directory = false) click to toggle source

    # File lib/puppet/util/symbolic_file_mode.rb, line 33
    def symbolic_mode_to_int(modification, to_mode = 0, is_a_directory = false)
      if modification.nil? or modification == '' then
        raise Puppet::Error, "An empty mode string is illegal"
      end
      if modification =~ /^[0-7]+$/ then return modification.to_i(8) end
      if modification =~ /^\d+$/ then
        raise Puppet::Error, "Numeric modes must be in octal, not decimal!"
      end

      fail "non-numeric current mode (#{to_mode.inspect})" unless to_mode.is_a?(Numeric)

      original_mode = {
        's' => (to_mode & 07000) >> 9,
        'u' => (to_mode & 00700) >> 6,
        'g' => (to_mode & 00070) >> 3,
        'o' => (to_mode & 00007) >> 0,
        # Are there any execute bits set in the original mode?
        'any x?' => (to_mode & 00111) != 0
      }
      final_mode = {
        's' => original_mode['s'],
        'u' => original_mode['u'],
        'g' => original_mode['g'],
        'o' => original_mode['o'],
      }

      modification.split(/\s*,\s*/).each do |part|
        begin
          _, to, dsl = /^([ugoa]*)([-+=].*)$/.match(part).to_a
          if dsl.nil? then raise Puppet::Error, 'Missing action' end
          to = "a" unless to and to.length > 0

          # We want a snapshot of the mode before we start messing with it to
          # make actions like 'a-g' atomic.  Various parts of the DSL refer to
          # the original mode, the final mode, or the current snapshot of the
          # mode, for added fun.
          snapshot_mode = {}
          final_mode.each {|k,v| snapshot_mode[k] = v }

          to.gsub('a', 'ugo').split('').uniq.each do |who|
            value = snapshot_mode[who]

            action = '!'
            actions = {
              '!' => lambda {|_,_| raise Puppet::Error, 'Missing operation (-, =, or +)' },
              '=' => lambda {|m,v| m | v },
              '+' => lambda {|m,v| m | v },
              '-' => lambda {|m,v| m & ~v },
            }

            dsl.split('').each do |op|
              case op
              when /[-+=]/ then
                action = op
                # Clear all bits, if this is assignment
                value  = 0 if op == '='

              when /[ugo]/ then
                value = actions[action].call(value, snapshot_mode[op])

              when /[rwx]/ then
                value = actions[action].call(value, SymbolicMode[op])

              when 'X' then
                # Only meaningful in combination with "set" actions.
                if action != '+' then
                  raise Puppet::Error, "X only works with the '+' operator"
                end

                # As per the BSD manual page, set if this is a directory, or if
                # any execute bit is set on the original (unmodified) mode.
                # Ignored otherwise; it is "add if", not "add or clear".
                if is_a_directory or original_mode['any x?'] then
                  value = actions[action].call(value, ExecBit)
                end

              when /[st]/ then
                bit = SymbolicSpecialToBit[op][who] or fail "internal error"
                final_mode['s'] = actions[action].call(final_mode['s'], bit)

              else
                raise Puppet::Error, 'Unknown operation'
              end
            end

            # Now, assign back the value.
            final_mode[who] = value
          end

        rescue Puppet::Error => e
          if part.inspect != modification.inspect then
            rest = " at #{part.inspect}"
          else
            rest = ''
          end

          raise Puppet::Error, "#{e}#{rest} in symbolic mode #{modification.inspect}"
        end
      end

      result =
        final_mode['s'] << 9 |
        final_mode['u'] << 6 |
        final_mode['g'] << 3 |
        final_mode['o'] << 0
      return result
    end

valid_symbolic_mode?(value) click to toggle source

    # File lib/puppet/util/symbolic_file_mode.rb, line 13
    def valid_symbolic_mode?(value)
      value = normalize_symbolic_mode(value)
      return true if value =~ /^0?[0-7]{1,4}$/
      return true if value =~ /^([ugoa]*[-=+][-=+rstwxXugo]*)(,[ugoa]*[-=+][-=+rstwxXugo]*)*$/
      return false
    end