1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
require_relative '../../puppet/util'
module Puppet
module Util
module SymbolicFileMode
SetUIDBit = ReadBit = 4
SetGIDBit = WriteBit = 2
StickyBit = ExecBit = 1
SymbolicMode = { 'x' => ExecBit, 'w' => WriteBit, 'r' => ReadBit }
SymbolicSpecialToBit = {
't' => { 'u' => StickyBit, 'g' => StickyBit, 'o' => StickyBit },
's' => { 'u' => SetUIDBit, 'g' => SetGIDBit, 'o' => StickyBit }
}
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
def display_mode(value)
if value =~ /^0?[0-7]{1,4}$/
value.rjust(4, "0")
else
value
end
end
def normalize_symbolic_mode(value)
return nil if value.nil?
# We need to treat integers as octal numbers.
#
# "A numeric mode is from one to four octal digits (0-7), derived by adding
# up the bits with values 4, 2, and 1. Omitted digits are assumed to be
# leading zeros."
if value.is_a? Numeric
value.to_s(8)
elsif value =~ /^0?[0-7]{1,4}$/
value.to_i(8).to_s(8) # strip leading 0's
else
value
end
end
def symbolic_mode_to_int(modification, to_mode = 0, is_a_directory = false)
if modification.nil? or modification == ''
raise Puppet::Error, _("An empty mode string is illegal")
elsif modification =~ /^[0-7]+$/
return modification.to_i(8)
elsif modification =~ /^\d+$/
raise Puppet::Error, _("Numeric modes must be in octal, not decimal!")
end
fail _("non-numeric current mode (%{mode})") % { 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 /[-+=]/
action = op
# Clear all bits, if this is assignment
value = 0 if op == '='
when /[ugo]/
value = actions[action].call(value, snapshot_mode[op])
when /[rwx]/
value = actions[action].call(value, SymbolicMode[op])
when 'X'
# Only meaningful in combination with "set" actions.
if action != '+'
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?']
value = actions[action].call(value, ExecBit)
end
when /[st]/
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
rest = " at #{part.inspect}"
else
rest = ''
end
raise Puppet::Error, _("%{error}%{rest} in symbolic mode %{modification}") % { error: e, rest: rest, modification: modification.inspect }, e.backtrace
end
end
result =
final_mode['s'] << 9 |
final_mode['u'] << 6 |
final_mode['g'] << 3 |
final_mode['o'] << 0
return result
end
end
end
end
|