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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
|
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
##
# The format class knows the guts of the ancient .gem file format and provides
# the capability to read such ancient gems.
#
# Please pretend this doesn't exist.
class Gem::Package::Old < Gem::Package
undef_method :spec=
##
# Creates a new old-format package reader for +gem+. Old-format packages
# cannot be written.
def initialize gem
require 'fileutils'
require 'zlib'
Gem.load_yaml
@contents = nil
@gem = gem
@security_policy = nil
@spec = nil
end
##
# A list of file names contained in this gem
def contents
verify
return @contents if @contents
@gem.with_read_io do |io|
read_until_dashes io # spec
header = file_list io
@contents = header.map { |file| file['path'] }
end
end
##
# Extracts the files in this package into +destination_dir+
def extract_files destination_dir
verify
errstr = "Error reading files from gem"
@gem.with_read_io do |io|
read_until_dashes io # spec
header = file_list io
raise Gem::Exception, errstr unless header
header.each do |entry|
full_name = entry['path']
destination = install_location full_name, destination_dir
file_data = ''
read_until_dashes io do |line|
file_data << line
end
file_data = file_data.strip.unpack("m")[0]
file_data = Zlib::Inflate.inflate file_data
raise Gem::Package::FormatError, "#{full_name} in #{@gem} is corrupt" if
file_data.length != entry['size'].to_i
FileUtils.rm_rf destination
FileUtils.mkdir_p File.dirname destination
open destination, 'wb', entry['mode'] do |out|
out.write file_data
end
verbose destination
end
end
rescue Zlib::DataError
raise Gem::Exception, errstr
end
##
# Reads the file list section from the old-format gem +io+
def file_list io # :nodoc:
header = ''
read_until_dashes io do |line|
header << line
end
YAML.load header
end
##
# Reads lines until a "---" separator is found
def read_until_dashes io # :nodoc:
while (line = io.gets) && line.chomp.strip != "---" do
yield line if block_given?
end
end
##
# Skips the Ruby self-install header in +io+.
def skip_ruby io # :nodoc:
loop do
line = io.gets
return if line.chomp == '__END__'
break unless line
end
raise Gem::Exception, "Failed to find end of ruby script while reading gem"
end
##
# The specification for this gem
def spec
verify
return @spec if @spec
yaml = ''
@gem.with_read_io do |io|
skip_ruby io
read_until_dashes io do |line|
yaml << line
end
end
yaml_error = if RUBY_VERSION < '1.9' then
YAML::ParseError
elsif YAML.const_defined?(:ENGINE) && YAML::ENGINE.yamler == 'syck' then
YAML::ParseError
else
YAML::SyntaxError
end
begin
@spec = Gem::Specification.from_yaml yaml
rescue yaml_error
raise Gem::Exception, "Failed to parse gem specification out of gem file"
end
rescue ArgumentError
raise Gem::Exception, "Failed to parse gem specification out of gem file"
end
##
# Raises an exception if a security policy that verifies data is active.
# Old format gems cannot be verified as signed.
def verify
return true unless @security_policy
raise Gem::Security::Exception,
'old format gems do not contain signatures and cannot be verified' if
@security_policy.verify_data
true
end
end
|