ec2_amitools 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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