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
|
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
require 'openssl'
module AWS
class Glacier
class ArchiveCollection
include Core::Model
# @param [Vault] vault
# @param [Hash] options
# @option options [String] :account_id
def initialize vault, options = {}
@vault = vault
@account_id = options[:account_id] || '-'
super
end
# @return [Vault]
attr_reader :vault
# @return [String]
attr_reader :account_id
# Creates an archive by uploading a file to a vault.
# @param [File,Pathname,IO,String] data The data to upload.
# If `data` is a string, this is treated as a path to a file
# on disk.
# @param [Hash] options
# @option options [String] description
# @return [Archive]
def create data, options = {}
data = convert_to_io(data)
hash, tree_hash = compute_checksums(data)
upload_options = {}
upload_options[:vault_name] = vault.name
upload_options[:account_id] = account_id
upload_options[:body] = data
upload_options[:checksum] = tree_hash
upload_options[:content_sha256] = hash
upload_options[:archive_description] = options[:description] if
options[:description]
resp = client.upload_archive(upload_options)
self[resp[:archive_id]]
end
# @param [String] archive_id
# @return [Archive]
def [] archive_id
Archive.new(vault, archive_id, :config => config, :account_id => account_id)
end
protected
def convert_to_io data
return Core::ManagedFile.open(data) if
data.is_a?(Pathname) or data.is_a?(String)
return data if io_like?(data)
msg = "expected data to be IO-like or a file path (String/Pathanme)."
raise ArgumentError, msg
end
# @return [Boolean] Returns `tue` if data acts like a file.
def io_like? data
data.respond_to?(:read) and
data.respond_to?(:eof?) and
data.respond_to?(:rewind) and
data.respond_to?(:size)
end
# Computes two checksums in a single pass of the data:
# * a hash of the entire payload
# * a tree hash of the entire payload
#
# The tree hash is required by the streaming operations,
# the simple hash is required for generating the signature
# (via sigv4).
#
# The sigv4 module will compute the hash of the payload for us,
# but that requires reading the data a 2nd time. :(
def compute_checksums data
digest = OpenSSL::Digest.new('sha256')
tree_digest = OpenSSL::Digest.new('sha256')
tree_parts = []
until data.eof?
chunk = data.read(1024 * 1024) # read 1MB
tree_parts << tree_digest.update(chunk).digest
tree_digest.reset
digest.update(chunk)
end
data.rewind
[digest.to_s, compute_tree_hash(tree_parts)]
end
def compute_tree_hash hashes
digest = OpenSSL::Digest.new('sha256')
until hashes.count == 1
hashes = hashes.each_slice(2).map do |h1,h2|
digest.reset
if h2
digest.update(h1)
digest.update(h2)
digest.digest
else
h1
end
end
end
hashes.first.bytes.map{|x| x.to_i.to_s(16).rjust(2,'0')}.join('')
end
end
end
end
|