class Fog::AWS::Glacier::TreeHash

Public Class Methods

digest(body) click to toggle source
# File lib/fog/aws/glacier.rb, line 38
def self.digest(body)
  new.add_part(body)
end
new() click to toggle source
# File lib/fog/aws/glacier.rb, line 42
def initialize
  @last_chunk_digest = nil      # Digest OBJECT for last chunk (Digest::SHA256)
  @last_chunk_digest_temp = nil # Digest VALUE for last chunk
  @last_chunk_length = 0        # Length of last chunk, always smaller than 1MB.
  @digest_stack = []
  # First position on stack corresponds to 1MB, second 2MB, third 4MB, fourt 8MB and so on.
  # In any time, the size of all already added parts is equal to sum of all existing (non-nil)
  # positions multiplied by that number, plus last_chunk_length for the remainder smaller than
  # one megabyte. So, if last_chunk_length is half megabyte, stack[0] is filled, stack[1] and
  # stack[2] empty and stack[3] filled, the size is 0.5MB + 1x1MB + 0x2MB + 0x4MB + 1x8MB = 9.5MB.
end

Public Instance Methods

add_part(bytes) click to toggle source
# File lib/fog/aws/glacier.rb, line 81
def add_part(bytes)
  part = self.digest_for_part(bytes)
  part.unpack('H*').first
end
digest() click to toggle source
# File lib/fog/aws/glacier.rb, line 144
def digest
  reduce_digest_stack(@last_chunk_digest_temp, @digest_stack)
end
digest_for_part(body) click to toggle source
# File lib/fog/aws/glacier.rb, line 102
def digest_for_part(body)
  part_stack = []
  part_temp = nil
  body_size = body.bytesize
  prepare_body_for_slice(body) {|body, slice|
    start_offset = 0
    if @last_chunk_length != 0
      start_offset = MEGABYTE - @last_chunk_length
      @last_chunk_hash.update(body.send(slice, 0, start_offset))
      hash = @last_chunk_hash.digest
      @last_chunk_digest_temp = hash
      if body_size > start_offset
        @last_chunk_length = 0
        @last_chunk_hash = nil
        @last_chunk_digest_temp = nil
        update_digest_stack(hash, @digest_stack)
      else
        part_temp = hash
        @last_chunk_digest_temp = hash
        @last_chunk_length += body_size
        next
      end
    end
    whole_chunk_count = (body_size - start_offset) / MEGABYTE
    whole_chunk_count.times.each {|chunk_index|
      hash = Digest::SHA256.digest(body.send(slice, start_offset + chunk_index * MEGABYTE, MEGABYTE))
      update_digest_stack(hash, part_stack)
      update_digest_stack(hash, @digest_stack)
    }
    rest_size = body_size - start_offset - whole_chunk_count * MEGABYTE
    if rest_size > 0 || whole_chunk_count == 0
      @last_chunk_hash = Digest::SHA256.new
      @last_chunk_length = rest_size
      @last_chunk_hash.update(body.send(slice, start_offset + whole_chunk_count * MEGABYTE, rest_size))
      hash = @last_chunk_hash.digest
      @last_chunk_digest_temp = hash
      part_temp = hash
    end
  }
  reduce_digest_stack(part_temp, part_stack)
end
hexdigest() click to toggle source
# File lib/fog/aws/glacier.rb, line 148
def hexdigest
  digest.unpack('H*').first
end
prepare_body_for_slice(body) { |body, :byteslice| ... } click to toggle source
# File lib/fog/aws/glacier.rb, line 86
def prepare_body_for_slice(body)
  if body.respond_to? :byteslice
    r = yield(body, :byteslice)
  else
    if body.respond_to? :encoding
      old_encoding = body.encoding
      body.force_encoding('BINARY')
    end
    r = yield(body, :slice)
    if body.respond_to? :encoding
      body.force_encoding(old_encoding)
    end
  end
  r
end
reduce_digest_stack(digest, stack) click to toggle source
# File lib/fog/aws/glacier.rb, line 68
def reduce_digest_stack(digest, stack)
  stack.each_with_index{|s,i|
    unless digest
      digest = stack[i]
      next
    end
    if stack[i]
      digest = Digest::SHA256.digest(stack[i] + digest)
    end
  }
  digest
end
update_digest_stack(digest, stack) click to toggle source
# File lib/fog/aws/glacier.rb, line 54
def update_digest_stack(digest, stack)
  stack.each_with_index{|s,i|
    if s
      digest = Digest::SHA256.digest(s + digest)
      stack[i] = nil
    else
      stack[i] = digest # Update this position with value obtained in previous run of cycle.
      digest = nil
      break
    end
  }
  stack << digest if digest
end