require "elif" # The class to output a compiled set of protections back into a protections table class Outputter attr_accessor :pt def initialize(calculated_ft) @pt = calculated_ft end # The main loop for processing the task at hand # @param [Protections_Table] prot The current protections_table object # @param [Dir_Tree] dt A directory tree object, for use of its methods # @param [True, False] elif Should the header file be pre-pended to the output table? For testing purposes # @return [Array] The optimised protections table def output_tree(prot, dt, elif = true) p_table = [] users_groups = prot.find_users_and_groups users_groups.each{ |user| @pt.each{ |node| prot_node = Tree::TreeNode.new(user[1]) if node.content if node.content[user[1]][user[0]] prot_node << Tree::TreeNode.new(user[0]) << node.content[user[1]][user[0]][0] # Work with this protection begin if node.is_root? users_node = nil else users_node = prot_node_for_user(node.parent.content[user[1]], user) end if users_node == nil path = dt.tree_to_path(node) prot_line = output_prot_line(prot_node, correct_path(path, node), "") p_table << prot_line next end comp = trees_same?(users_node, prot_node) case comp when 5, 3, 2, 1, -2 path = dt.tree_to_path(node) p_table << output_prot_line(prot_node, correct_path(path, node), "") when 4, 0, -3 next else # -1 path = dt.tree_to_path(node) p_table << output_prot_line(prot_node, correct_path(path, node), "-") p_table << output_prot_line(prot_node, correct_path(path, node), "") end rescue #if node.parent # path = dt.tree_to_path(node.parent) #else # path = dt.tree_to_path(node) #end #prot_line = output_prot_line(prot_node, correct_path(path, node), "") #p_table << prot_line end end end } } if elif Elif.open("./optimiser/header.txt").each { |line| p_table.unshift(line) } end File.open("p_table.txt", "w") do |f| p_table.each { |row| f.puts(row) } end return p_table end # For a given node, create the protection tree for the given user/group # @param [Tree::TreeNode] node The node to search # @param [Array] user_group The user to search for # @return [Tree::TreeNode] Returns the protection tree or nil def prot_node_for_user(node, user_group) new_node = node if new_node.kind_of?(Array) new_node = new_node[user_group[1]] end prot_node = Tree::TreeNode.new(user_group[1]) if new_node if new_node[user_group[0]] prot_node << new_node[user_group[0]] end end if prot_node.size == 4 return prot_node else return nil end end # Appends wildcards to paths as necessary # @param [String] path The path to work with # @param [Tree::TreeNode] node The node in the file tree corresponding to path # @return [String] The recalculated path def correct_path(path, node) out_path = path if path =~ /\/$/ out_path = out_path + "..." return out_path end if node.has_children? if node.children[0].has_children? #Child is a dir not file out_path = out_path + "/..." else out_path = out_path + "/*" end end return out_path end # Calculates which tree (l or r) prevails, and returns a integer indcating the relationship between l and r # L(*) < R(n) :: 5 # L(n) == R(*) :: 4 # L(n) < R(*) :: 3 # L != R :: 2 # L < R :: 1 # L == R :: 0 # L > R :: -1 # L(n) > R(*) :: -2 # L(*) > R(n) :: -3 # @param [Tree::TreeNode] l The previous node (left) # @param [Tree::TreeNode] r The current node (right) # @return [Integer] the corresponding value from above def trees_same?(l, r) #No previous nodes if l == nil return 1 end begin # L(*) < R(n) :: 5 # L(n) == R(*) :: 4 # L(n) < R(*) :: 3 # L != R :: 2 # L < R :: 1 # L == R :: 0 # L > R :: -1 # L(n) > R(*) :: -2 # L(*) > R(n) :: -3 # 5 # 0 # -3 if l[0].name == '*' && r[0].name != '*' if l[0][0].name == r[0][0].name if l[0][0][0].name.to_i < r[0][0][0].name.to_i return 5 elsif l[0][0][0].name.to_i == r[0][0][0].name.to_i return 0 elsif l[0][0][0].name.to_i > r[0][0][0].name.to_i return -3 end end end # 3 # 4 # -2 if r[0].name == '*' && l[0].name != '*' if l[0][0].name == r[0][0].name if l[0][0][0].name.to_i < r[0][0][0].name.to_i return 3 elsif l[0][0][0].name.to_i == r[0][0][0].name.to_i return 4 elsif l[0][0][0].name.to_i > r[0][0][0].name.to_i return -2 end end end # 2 # 1 # 0 # -1 if l[0].name == r[0].name if l[0][0].name == r[0][0].name if l[0][0][0].name.to_i < r[0][0][0].name.to_i return 1 elsif l[0][0][0].name.to_i == r[0][0][0].name.to_i return 0 elsif l[0][0][0].name.to_i > r[0][0][0].name.to_i return -1 end else return 2 end else return 2 end rescue => e e return 0 end end # Convert a protections tree into a protections entry # @param [Tree::TreeNode] prot_tree A protections tree # @param [String] current_path The current path (node_to_path of the file node) # @param [String] charge + or - to indicate charge # @return [String] a fully formed protection entry def output_prot_line(prot_tree, current_path, charge) # A.pline= "" # B.convert bitmask to string concat to pline # C.convert type to string concat to pline # D.concat user name to pline # E.concat host to pline # F.convert current ft node to pat type = prot_tree.name name = prot_tree.children[0].name host = prot_tree[name].children[0].name mask = prot_tree[name][host].children[0].name prot_line = " #{charge}" prot_line = prot_line + "#{bitmask_to_level(mask)} " prot_line = prot_line + "#{int_to_type(type)} " prot_line = prot_line + "#{name} " prot_line = prot_line + "#{host} " prot_line = prot_line + current_path return prot_line end # Converts 0 to "User" and 1 to "Group" # @param [Integer] int 0 or 1 # @return [String] group or user def int_to_type(int) case int when 0 return "user" else return "group" end end # Convert the access level binary value into string form # @param [Integer] bitmask The integer value of the access level # @return [String] String version of the access level def bitmask_to_level(bitmask) #0x0001 Grants list access #0x0002 Grants read access #0x0004 Grants ability to branch/integ from #0x0008 Grants open access #0x0010 Grants write access #0x0020 Grants review access #0x0080 Grants admin access #0x0040 Grants super-user access case bitmask.to_i #TODO #Need to figure out when its =open, =write etc when 1 return "list" when 2 return "=read" when 3 return "read" when 4 return "=branch" when 7 return "read" when 15 return "open" when 16 return "=open" when 31 return "write" when 32 return "=write" when 127 return "review" when 255 return "super" when 191 return "admin" else return "fk" end end end