ec2_amitools 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +54 -0
  3. data/bin/console +14 -0
  4. data/bin/ec2-ami-tools-version +6 -0
  5. data/bin/ec2-bundle-image +6 -0
  6. data/bin/ec2-bundle-vol +6 -0
  7. data/bin/ec2-delete-bundle +6 -0
  8. data/bin/ec2-download-bundle +6 -0
  9. data/bin/ec2-migrate-bundle +6 -0
  10. data/bin/ec2-migrate-manifest +6 -0
  11. data/bin/ec2-unbundle +6 -0
  12. data/bin/ec2-upload-bundle +6 -0
  13. data/bin/setup +8 -0
  14. data/etc/ec2/amitools/cert-ec2-cn-north-1.pem +28 -0
  15. data/etc/ec2/amitools/cert-ec2-gov.pem +17 -0
  16. data/etc/ec2/amitools/cert-ec2.pem +23 -0
  17. data/etc/ec2/amitools/mappings.csv +9 -0
  18. data/lib/ec2/amitools/bundle.rb +251 -0
  19. data/lib/ec2/amitools/bundle_base.rb +58 -0
  20. data/lib/ec2/amitools/bundleimage.rb +94 -0
  21. data/lib/ec2/amitools/bundleimageparameters.rb +42 -0
  22. data/lib/ec2/amitools/bundlemachineparameters.rb +60 -0
  23. data/lib/ec2/amitools/bundleparameters.rb +120 -0
  24. data/lib/ec2/amitools/bundlevol.rb +240 -0
  25. data/lib/ec2/amitools/bundlevolparameters.rb +164 -0
  26. data/lib/ec2/amitools/crypto.rb +379 -0
  27. data/lib/ec2/amitools/decryptmanifest.rb +20 -0
  28. data/lib/ec2/amitools/defaults.rb +12 -0
  29. data/lib/ec2/amitools/deletebundle.rb +212 -0
  30. data/lib/ec2/amitools/deletebundleparameters.rb +78 -0
  31. data/lib/ec2/amitools/downloadbundle.rb +161 -0
  32. data/lib/ec2/amitools/downloadbundleparameters.rb +84 -0
  33. data/lib/ec2/amitools/exception.rb +86 -0
  34. data/lib/ec2/amitools/fileutil.rb +219 -0
  35. data/lib/ec2/amitools/format.rb +127 -0
  36. data/lib/ec2/amitools/instance-data.rb +97 -0
  37. data/lib/ec2/amitools/manifest_wrapper.rb +132 -0
  38. data/lib/ec2/amitools/manifestv20070829.rb +361 -0
  39. data/lib/ec2/amitools/manifestv20071010.rb +403 -0
  40. data/lib/ec2/amitools/manifestv3.rb +331 -0
  41. data/lib/ec2/amitools/mapids.rb +148 -0
  42. data/lib/ec2/amitools/migratebundle.rb +222 -0
  43. data/lib/ec2/amitools/migratebundleparameters.rb +173 -0
  44. data/lib/ec2/amitools/migratemanifest.rb +225 -0
  45. data/lib/ec2/amitools/migratemanifestparameters.rb +118 -0
  46. data/lib/ec2/amitools/minimalec2.rb +116 -0
  47. data/lib/ec2/amitools/parameter_exceptions.rb +34 -0
  48. data/lib/ec2/amitools/parameters_base.rb +168 -0
  49. data/lib/ec2/amitools/region.rb +93 -0
  50. data/lib/ec2/amitools/s3toolparameters.rb +183 -0
  51. data/lib/ec2/amitools/showversion.rb +12 -0
  52. data/lib/ec2/amitools/syschecks.rb +27 -0
  53. data/lib/ec2/amitools/tool_base.rb +224 -0
  54. data/lib/ec2/amitools/unbundle.rb +107 -0
  55. data/lib/ec2/amitools/unbundleparameters.rb +65 -0
  56. data/lib/ec2/amitools/uploadbundle.rb +361 -0
  57. data/lib/ec2/amitools/uploadbundleparameters.rb +108 -0
  58. data/lib/ec2/amitools/util.rb +532 -0
  59. data/lib/ec2/amitools/version.rb +33 -0
  60. data/lib/ec2/amitools/xmlbuilder.rb +237 -0
  61. data/lib/ec2/amitools/xmlutil.rb +55 -0
  62. data/lib/ec2/common/constants.rb +16 -0
  63. data/lib/ec2/common/curl.rb +110 -0
  64. data/lib/ec2/common/headers.rb +95 -0
  65. data/lib/ec2/common/headersv4.rb +173 -0
  66. data/lib/ec2/common/http.rb +333 -0
  67. data/lib/ec2/common/s3support.rb +231 -0
  68. data/lib/ec2/common/signature.rb +68 -0
  69. data/lib/ec2/oem/LICENSE.txt +58 -0
  70. data/lib/ec2/oem/open4.rb +399 -0
  71. data/lib/ec2/platform/base/architecture.rb +26 -0
  72. data/lib/ec2/platform/base/constants.rb +54 -0
  73. data/lib/ec2/platform/base/pipeline.rb +181 -0
  74. data/lib/ec2/platform/base.rb +57 -0
  75. data/lib/ec2/platform/current.rb +55 -0
  76. data/lib/ec2/platform/linux/architecture.rb +35 -0
  77. data/lib/ec2/platform/linux/constants.rb +23 -0
  78. data/lib/ec2/platform/linux/fstab.rb +99 -0
  79. data/lib/ec2/platform/linux/identity.rb +16 -0
  80. data/lib/ec2/platform/linux/image.rb +811 -0
  81. data/lib/ec2/platform/linux/mtab.rb +74 -0
  82. data/lib/ec2/platform/linux/pipeline.rb +40 -0
  83. data/lib/ec2/platform/linux/rsync.rb +114 -0
  84. data/lib/ec2/platform/linux/tar.rb +124 -0
  85. data/lib/ec2/platform/linux/uname.rb +50 -0
  86. data/lib/ec2/platform/linux.rb +83 -0
  87. data/lib/ec2/platform/solaris/architecture.rb +28 -0
  88. data/lib/ec2/platform/solaris/constants.rb +30 -0
  89. data/lib/ec2/platform/solaris/fstab.rb +43 -0
  90. data/lib/ec2/platform/solaris/identity.rb +16 -0
  91. data/lib/ec2/platform/solaris/image.rb +327 -0
  92. data/lib/ec2/platform/solaris/mtab.rb +29 -0
  93. data/lib/ec2/platform/solaris/pipeline.rb +40 -0
  94. data/lib/ec2/platform/solaris/rsync.rb +24 -0
  95. data/lib/ec2/platform/solaris/tar.rb +36 -0
  96. data/lib/ec2/platform/solaris/uname.rb +21 -0
  97. data/lib/ec2/platform/solaris.rb +38 -0
  98. data/lib/ec2/platform.rb +69 -0
  99. data/lib/ec2/version.rb +8 -0
  100. data/lib/ec2_amitools +1 -0
  101. data/lib/ec2_amitools.rb +7 -0
  102. metadata +184 -0
@@ -0,0 +1,84 @@
1
+ # Copyright 2008-2014 Amazon.com, Inc. or its affiliates. All Rights
2
+ # Reserved. Licensed under the Amazon Software License (the
3
+ # "License"). You may not use this file except in compliance with the
4
+ # License. A copy of the License is located at
5
+ # http://aws.amazon.com/asl or in the "license" file accompanying this
6
+ # file. This file is distributed on an "AS IS" BASIS, WITHOUT
7
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
8
+ # the License for the specific language governing permissions and
9
+ # limitations under the License.
10
+
11
+ require 'ec2/amitools/s3toolparameters'
12
+
13
+ #------------------------------------------------------------------------------#
14
+
15
+ class DownloadBundleParameters < S3ToolParameters
16
+
17
+ PREFIX_DESCRIPTION = "The filename prefix for bundled AMI files. Defaults to 'image'."
18
+ DIRECTORY_DESCRIPTION = ['The directory into which to download the bundled AMI parts.',
19
+ "Defaults to the current working directory."]
20
+ MANIFEST_DESCRIPTION = ["The local manifest filename. Required only for manifests that",
21
+ "pre-date the version 3 manifest file format."]
22
+ RETRY_DESCRIPTION = "Automatically retry failed downloads."
23
+
24
+ attr_accessor :manifest,
25
+ :prefix,
26
+ :privatekey,
27
+ :directory,
28
+ :retry
29
+
30
+ #----------------------------------------------------------------------------#
31
+
32
+ def mandatory_params()
33
+ super()
34
+
35
+ on('-k', '--privatekey KEY', String, USER_PK_PATH_DESCRIPTION) do |privatekey|
36
+ assert_file_exists(privatekey, '--privatekey')
37
+ @privatekey = privatekey
38
+ end
39
+ end
40
+
41
+ #----------------------------------------------------------------------------#
42
+
43
+ def optional_params()
44
+ super()
45
+
46
+ on('-m', '--manifest FILE', String, *MANIFEST_DESCRIPTION) do |manifest|
47
+ assert_good_key(manifest, '--manifest')
48
+ @manifest = manifest
49
+ end
50
+
51
+ on('-p', '--prefix PREFIX', String, PREFIX_DESCRIPTION) do |prefix|
52
+ assert_good_key(prefix, '--prefix')
53
+ @prefix = prefix
54
+ end
55
+
56
+ on('-d', '--directory DIRECTORY', String, *DIRECTORY_DESCRIPTION) do |directory|
57
+ assert_directory_exists(directory, '--directory')
58
+ @directory = directory
59
+ end
60
+
61
+ on('--retry', RETRY_DESCRIPTION) do
62
+ @retry = true
63
+ end
64
+ end
65
+
66
+ #----------------------------------------------------------------------------#
67
+
68
+ def validate_params()
69
+ super()
70
+ raise MissingMandatory.new('--privatekey') unless @privatekey
71
+ raise InvalidCombination.new('--prefix', '--manifest') if (@prefix and @manifest)
72
+ end
73
+
74
+ #----------------------------------------------------------------------------#
75
+
76
+ def set_defaults()
77
+ super()
78
+ @directory = Dir::pwd() unless @directory
79
+ @prefix = @manifest.split('.')[0..-2].join('.') if (@manifest)
80
+ @prefix = 'image' unless @prefix
81
+ @manifest = "#{@prefix}.manifest.xml" unless @manifest
82
+ end
83
+
84
+ end
@@ -0,0 +1,86 @@
1
+ # Copyright 2008-2014 Amazon.com, Inc. or its affiliates. All Rights
2
+ # Reserved. Licensed under the Amazon Software License (the
3
+ # "License"). You may not use this file except in compliance with the
4
+ # License. A copy of the License is located at
5
+ # http://aws.amazon.com/asl or in the "license" file accompanying this
6
+ # file. This file is distributed on an "AS IS" BASIS, WITHOUT
7
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
8
+ # the License for the specific language governing permissions and
9
+ # limitations under the License.
10
+
11
+ ##
12
+ # An exception thrown to indicate an unrecoverable error has been encountered.
13
+ # The process should be terminated and the exception's message should be
14
+ # displayed to the user.
15
+ #
16
+ class FatalError < Exception
17
+ ##
18
+ # ((|message|)) The message that should be displayed to the user.
19
+ # ((|cause|)) The exception that caused the fatal error.
20
+ #
21
+ def initialize(message, cause = nil)
22
+ super(message)
23
+ @cause = cause
24
+ end
25
+ end
26
+
27
+ #------------------------------------------------------------------------------#
28
+
29
+ ##
30
+ # File access error.
31
+ #
32
+ class FileError < FatalError
33
+ def initialize(filename, error_description, sys_call_err = nil)
34
+ message = "File Error: #{error_description} \n" +
35
+ "File name: #{filename}\n"
36
+ super(message, sys_call_err)
37
+ end
38
+ end
39
+
40
+ #------------------------------------------------------------------------------#
41
+
42
+ ##
43
+ # Directory access exception.
44
+ #
45
+ class DirectoryError < FatalError
46
+ def initialize(dirname, error_description, sys_call_err = nil)
47
+ message = "Directory Error: #{error_description} \n" +
48
+ "Directory name: #{dirname} \n"
49
+ super(message, sys_call_error)
50
+ end
51
+ end
52
+
53
+ #----------------------------------------------------------------------------#
54
+
55
+ class DownloadError < FatalError
56
+ def initialize(resource, addr, port, path, error=nil)
57
+ super("could not download #{resource} from #{addr}/#{path} on #{port}", error)
58
+ end
59
+ end
60
+
61
+ #----------------------------------------------------------------------------#
62
+
63
+ class UploadError < FatalError
64
+ def initialize(resource, addr, port, path, error=nil)
65
+ super("could not upload #{resource} to #{addr}/#{path} on #{port}", error)
66
+ end
67
+ end
68
+
69
+ #------------------------------------------------------------------------------#
70
+
71
+ ##
72
+ # Parameter error.
73
+ #
74
+ class ParameterError < FatalError
75
+ def initialize(message)
76
+ super(message)
77
+ end
78
+ end
79
+
80
+ #------------------------------------------------------------------------------#
81
+
82
+ class AMIInvalid < FatalError
83
+ def initialize(message)
84
+ super(message)
85
+ end
86
+ end
@@ -0,0 +1,219 @@
1
+ # Copyright 2008-2014 Amazon.com, Inc. or its affiliates. All Rights
2
+ # Reserved. Licensed under the Amazon Software License (the
3
+ # "License"). You may not use this file except in compliance with the
4
+ # License. A copy of the License is located at
5
+ # http://aws.amazon.com/asl or in the "license" file accompanying this
6
+ # file. This file is distributed on an "AS IS" BASIS, WITHOUT
7
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
8
+ # the License for the specific language governing permissions and
9
+ # limitations under the License.
10
+
11
+ # Utility class and methods.
12
+
13
+ require 'ec2/amitools/exception'
14
+ require 'tmpdir'
15
+ require 'fileutils'
16
+ require 'pathname'
17
+ require 'tempfile'
18
+ require 'zlib'
19
+
20
+ ##
21
+ # Module containing file utility methods.
22
+ #
23
+ module FileUtil
24
+ include Zlib
25
+ BUFFER_SIZE = 1024 * 1024 # Buffer size in bytes.
26
+ PART_SUFFIX = '.part.'
27
+
28
+ #----------------------------------------------------------------------------#
29
+
30
+ ##
31
+ # Assert the specified file exists.
32
+ # An exception is raised if it does not.
33
+ #
34
+ def FileUtil.assert_exists(filename)
35
+ raise FileError(filename, 'a required file could not be found') unless exists?(filename)
36
+ end
37
+
38
+ #----------------------------------------------------------------------------#
39
+
40
+ ##
41
+ # Compress the specified file and return the path to the temporary compressed
42
+ # file that will be deleted upon termination of the process.
43
+ #
44
+ def FileUtil.compress(filename)
45
+ outfilename = filename+'.gz'
46
+ GzipWriter.open(outfilename) do |outfile|
47
+ begin
48
+ File.open(filename, 'r') do |infile|
49
+ while not (infile.eof)
50
+ outfile.write(infile.read(BUFFER_SIZE))
51
+ end
52
+ end
53
+ ensure
54
+
55
+ end
56
+ end
57
+ outfilename
58
+ end
59
+
60
+ #----------------------------------------------------------------------------#
61
+
62
+ ##
63
+ # Expand ((|src_filename|)) to ((|dst_filename|)).
64
+ #
65
+ def FileUtil.expand(src_filename, dst_filename)
66
+ GzipReader.open(src_filename) do |gzfile|
67
+ File.open(dst_filename, 'w') do |file|
68
+ while not (gzfile.eof?)
69
+ file.write(gzfile.read(BUFFER_SIZE))
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ #----------------------------------------------------------------------------#
76
+
77
+ ##
78
+ # Split the specified file into chunks of the specified size.
79
+ # yields the <file,chunk,chunk size> to a block which writes the actual chunks
80
+ # The chunks are output to the local directory.
81
+ # Typical invocation looks like:
82
+ # FileUtil.split('file',5){|sf,cf,cs| ChunkWriter.write_chunk(sf,cf,cs)}
83
+ #
84
+ # ((|filename|)) The file to split.
85
+ # ((|part_name_prefix|)) The prefix for the parts filenames.
86
+ # ((|cb_size|)) The chunk size in bytes.
87
+ # ((|dst_dir|)) The destination to create the file parts in.
88
+ #
89
+ # Returns a list of the created filenames.
90
+ #
91
+ def FileUtil.split(filename, part_name_prefix, cb_size, dst_dir)
92
+ begin
93
+ # Check file exists and is accessible.
94
+ begin
95
+ file = File.new(filename, File::RDONLY)
96
+ rescue SystemCallError => e
97
+ raise FileError.new(filename, "could not open file to split", e)
98
+ end
99
+
100
+ # Create the part file upfront to catch any creation/access errors
101
+ # before writing out data.
102
+ nr_parts = (Float(File.size(filename)) / Float(cb_size)).ceil
103
+ part_names = []
104
+ nr_parts.times do |i|
105
+ begin
106
+ nr_parts_digits = nr_parts.to_s.length
107
+ part_name_suffix = PART_SUFFIX + i.to_s.rjust(nr_parts_digits).gsub(' ', '0')
108
+ part_names[i] = part_name = part_name_prefix + part_name_suffix
109
+ FileUtils.touch File.join(dst_dir, part_name)
110
+ rescue SystemCallError => e
111
+ raise FileError.new(filename, "could not create part file", e)
112
+ end
113
+ end
114
+
115
+ # Write parts to files.
116
+ part_names.each do |part_file_name|
117
+ File.open(File.join(dst_dir, part_file_name), 'w+') do |pf|
118
+ write_chunk(file, pf, cb_size)
119
+ end
120
+ end
121
+
122
+ part_names
123
+ ensure
124
+ file.close if not file.nil?
125
+ end
126
+ end
127
+
128
+ #----------------------------------------------------------------------------#
129
+
130
+ ##
131
+ # Concatenate the specified files into a single file.
132
+ # If the specified output file already exists it will be overwritten.
133
+ # ((|filenames|)) An ordered collection of the names of split files.
134
+ # ((|out_filename|)) The output filename.
135
+ #
136
+ def FileUtil.cat(filenames, out_filename)
137
+ File.open(out_filename, 'w') do |of|
138
+ filenames.each do |filename|
139
+ File.open(filename) do |file|
140
+ while not (file.eof?)
141
+ of.write(file.read(BUFFER_SIZE))
142
+ of.flush
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
148
+
149
+ #----------------------------------------------------------------------------#
150
+
151
+ def FileUtil.exists?(fullname)
152
+ FileTest.exists?(fullname)
153
+ end
154
+
155
+ #----------------------------------------------------------------------------#
156
+
157
+ def FileUtil.directory?(fullname)
158
+ File::Stat.new(fullname).directory?
159
+ end
160
+
161
+ #----------------------------------------------------------------------------#
162
+
163
+ def FileUtil.symlink?(fullname)
164
+ File::Stat.new(fullname).symlink?
165
+ end
166
+
167
+ #----------------------------------------------------------------------------#
168
+
169
+ def FileUtil.tempdir(basename, tmpdir=Dir::tmpdir, tries=10)
170
+ tmpdir = '/tmp' if $SAFE > 0 and tmpdir.tainted?
171
+ fail = 0
172
+ tmpname = nil
173
+ begin
174
+ begin
175
+ tmpname = File.join(tmpdir, sprintf('%s%d.%s', basename, $$, Time.now.to_f.to_s))
176
+ end until !File.exist? tmpname
177
+ rescue
178
+ fail += 1
179
+ retry if fail < tries
180
+ raise "failed to generate a temporary directory name '%s'" % tmpname
181
+ end
182
+ tmpname
183
+ end
184
+
185
+
186
+ #----------------------------------------------------------------------------#
187
+
188
+ def FileUtil.size(f)
189
+ total = `du -s #{f}`.split[0].to_i rescue nil
190
+ if total.nil? or $?.exitstatus != 0
191
+ total = 0
192
+ Find.find(f) do |s|
193
+ total += File.directory?(s) ? 0 : File.size(s)
194
+ end
195
+ end
196
+ total
197
+ end
198
+
199
+ #----------------------------------------------------------------------------#
200
+
201
+ ##
202
+ # Write chunk to file.
203
+ # ((|sf|)) Source file.
204
+ # ((|cf|)) Chunk file.
205
+ # ((|cs|)) Chunk size in bytes.
206
+ # Returns true if eof was encountered.
207
+ #
208
+ def FileUtil.write_chunk(sf, cf, cs)
209
+ cb_written = 0 # Bytes written.
210
+ cb_left = cs # Bytes left to write in this chunk.
211
+ while (!sf.eof? && cb_left > 0) do
212
+ buf = sf.read(BUFFER_SIZE < cb_left ? BUFFER_SIZE : cb_left)
213
+ cf.write(buf)
214
+ cb_written += buf.length
215
+ cb_left = cs - cb_written
216
+ end
217
+ sf.eof
218
+ end
219
+ end
@@ -0,0 +1,127 @@
1
+ # Copyright 2008-2014 Amazon.com, Inc. or its affiliates. All Rights
2
+ # Reserved. Licensed under the Amazon Software License (the
3
+ # "License"). You may not use this file except in compliance with the
4
+ # License. A copy of the License is located at
5
+ # http://aws.amazon.com/asl or in the "license" file accompanying this
6
+ # file. This file is distributed on an "AS IS" BASIS, WITHOUT
7
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
8
+ # the License for the specific language governing permissions and
9
+ # limitations under the License.
10
+
11
+ require 'stringio'
12
+
13
+ module Format
14
+
15
+ #----------------------------------------------------------------------------#
16
+
17
+ ##
18
+ # Convert the binary data ((|data|)) to an ASCII string of hexadecimal digits
19
+ # that represents it.
20
+ #
21
+ # E.g. if ((|data|)) is the string of bytes 0x1, 0x1A, 0xFF, it is converted
22
+ # to the string "011AFF".
23
+ #
24
+ def Format.bin2hex(data)
25
+ hex = StringIO.new
26
+ data.unpack('H*').each {|digit| hex.write(digit)}
27
+ hex.string
28
+ end
29
+
30
+ #----------------------------------------------------------------------------#
31
+
32
+ ##
33
+ # Breaks ((|data|)) into blocks of size ((|blocksize|)). The last block maybe
34
+ # less than ((|blocksize||).
35
+ #
36
+ def Format.block(data, blocksize)
37
+ blocks = Array.new
38
+ read = 0
39
+ while read < data.size
40
+ left = data.size - read
41
+ blocks << data[read, (left < blocksize) ? left : blocksize]
42
+ read += (left < blocksize ? left : blocksize)
43
+ end
44
+
45
+ blocks
46
+ end
47
+
48
+ #----------------------------------------------------------------------------#
49
+
50
+ ##
51
+ # Convert ASCII string of hexadecimal digits ((|hex|)) into the binary data it
52
+ # represents. If there are an odd number of hexedecimal digits in ((|hex|)) it
53
+ # is left padded with a leading '0' character.
54
+ #
55
+ # E.g. if ((|hex|)) is "11AFF", it is converted to the string of bytes 0x1,
56
+ # 0x1A, 0xFF.
57
+ #
58
+ def Format.hex2bin(hex)
59
+ hex = '0' + hex unless (hex.size % 2) == 0
60
+ data = StringIO.new
61
+ [[hex].pack('H*')].each {|digit| data.write(digit)}
62
+ data.string
63
+ end
64
+
65
+ #----------------------------------------------------------------------------#
66
+
67
+ ##
68
+ # Return a single character string containing ((|int|)) converted to a single
69
+ # byte unsigned integer. The operand must be less than 256.
70
+ #
71
+ def Format.int2byte int
72
+ raise ArgumentError.new('argument greater than 255') unless int < 256
73
+ int.chr
74
+ end
75
+
76
+ #----------------------------------------------------------------------------#
77
+
78
+ # Convert integer _i_ to an unsigned 16 bit int packed into two bytes in big
79
+ # endian order.
80
+ def Format::int2int16( i )
81
+ raise ArgumentError.new( 'argument greater than 65535' ) unless i < 65536
82
+ hi_byte = ( i >> 8 ).chr
83
+ lo_byte = ( i & 0xFF).chr
84
+ return [ hi_byte, lo_byte ]
85
+ end
86
+
87
+ #----------------------------------------------------------------------------#
88
+
89
+ ##
90
+ # Pad data string ((|data|)) according to the PKCS #7 padding scheme.
91
+ #
92
+ def Format.pad_pkcs7(data, blocksize)
93
+ raise ArgumentError.new("invalid data: #{data.to_s}") unless data and data.kind_of? String
94
+ raise ArgumentError.new("illegal blocksize: #{blocksize}") unless blocksize > 0x0 and blocksize < 0xFF
95
+
96
+ # Determine the number of padding characters required. If the data size is
97
+ # divisible by the blocksize, a block of padding is required.
98
+ nr_padchars = blocksize - (data.size % blocksize)
99
+ nr_padchars = blocksize unless nr_padchars != 0
100
+
101
+ # Create padding, where the padding byte is the number of padding bytes.
102
+ padchar = nr_padchars.chr
103
+ padding = padchar * nr_padchars
104
+
105
+ data + padding
106
+ end
107
+
108
+ #----------------------------------------------------------------------------#
109
+
110
+ ##
111
+ # Pad ((|data|)) according to the PKCS #7 padding scheme.
112
+ #
113
+ def Format.unpad_pkcs7(data, blocksize)
114
+ raise ArgumentError.new("illegal blocksize: #{blocksize}") unless blocksize > 0x0 and blocksize < 0xFF
115
+ raise ArgumentError.new("invalid data: #{data.to_s}") unless data and data.kind_of? String
116
+ raise ArgumentError.new("invalid data size: #{data.size}") unless data.size > 0 and (data.size % blocksize) == 0
117
+
118
+ nr_padchars = data[data.size - 1]
119
+ raise ArgumentError.new("data padding character invalid: #{nr_padchars}") unless (nr_padchars > 0 and nr_padchars <= blocksize)
120
+
121
+ data[0, data.size - nr_padchars]
122
+ end
123
+
124
+
125
+
126
+
127
+ end