Parent

Included Modules

Class Index [+]

Quicksearch

Gem::Package::TarInput

++

 Copyright (C) 2004 Mauricio Julio Fernández Pradier
 See LICENSE.txt for additional licensing information.

Attributes

metadata[R]

Public Class Methods

new(io, security_policy = nil) click to toggle source
     # File lib/rubygems/package/tar_input.rb, line 24
 24:   def initialize(io, security_policy = nil)
 25:     @io = io
 26:     @tarreader = Gem::Package::TarReader.new @io
 27:     has_meta = false
 28: 
 29:     data_sig, meta_sig, data_dgst, meta_dgst = nil, nil, nil, nil
 30:     dgst_algo = security_policy ? Gem::Security::OPT[:dgst_algo] : nil
 31: 
 32:     @tarreader.each do |entry|
 33:       case entry.full_name
 34:       when "metadata"
 35:         @metadata = load_gemspec entry.read
 36:         has_meta = true
 37:       when "metadata.gz"
 38:         begin
 39:           # if we have a security_policy, then pre-read the metadata file
 40:           # and calculate it's digest
 41:           sio = nil
 42:           if security_policy
 43:             Gem.ensure_ssl_available
 44:             sio = StringIO.new(entry.read)
 45:             meta_dgst = dgst_algo.digest(sio.string)
 46:             sio.rewind
 47:           end
 48: 
 49:           gzis = Zlib::GzipReader.new(sio || entry)
 50:           # YAML wants an instance of IO
 51:           @metadata = load_gemspec(gzis)
 52:           has_meta = true
 53:         ensure
 54:           gzis.close unless gzis.nil?
 55:         end
 56:       when 'metadata.gz.sig'
 57:         meta_sig = entry.read
 58:       when 'data.tar.gz.sig'
 59:         data_sig = entry.read
 60:       when 'data.tar.gz'
 61:         if security_policy
 62:           Gem.ensure_ssl_available
 63:           data_dgst = dgst_algo.digest(entry.read)
 64:         end
 65:       end
 66:     end
 67: 
 68:     if security_policy then
 69:       Gem.ensure_ssl_available
 70: 
 71:       # map trust policy from string to actual class (or a serialized YAML
 72:       # file, if that exists)
 73:       if String === security_policy then
 74:         if Gem::Security::Policies.key? security_policy then
 75:           # load one of the pre-defined security policies
 76:           security_policy = Gem::Security::Policies[security_policy]
 77:         elsif File.exist? security_policy then
 78:           # FIXME: this doesn't work yet
 79:           security_policy = YAML.load File.read(security_policy)
 80:         else
 81:           raise Gem::Exception, "Unknown trust policy '#{security_policy}'"
 82:         end
 83:       end
 84: 
 85:       if data_sig && data_dgst && meta_sig && meta_dgst then
 86:         # the user has a trust policy, and we have a signed gem
 87:         # file, so use the trust policy to verify the gem signature
 88: 
 89:         begin
 90:           security_policy.verify_gem(data_sig, data_dgst, @metadata.cert_chain)
 91:         rescue Exception => e
 92:           raise "Couldn't verify data signature: #{e}"
 93:         end
 94: 
 95:         begin
 96:           security_policy.verify_gem(meta_sig, meta_dgst, @metadata.cert_chain)
 97:         rescue Exception => e
 98:           raise "Couldn't verify metadata signature: #{e}"
 99:         end
100:       elsif security_policy.only_signed
101:         raise Gem::Exception, "Unsigned gem"
102:       else
103:         # FIXME: should display warning here (trust policy, but
104:         # either unsigned or badly signed gem file)
105:       end
106:     end
107: 
108:     @tarreader.rewind
109:     @fileops = Gem::FileOperations.new
110: 
111:     raise Gem::Package::FormatError, "No metadata found!" unless has_meta
112:   end
open(io, security_policy = nil, &block) click to toggle source
    # File lib/rubygems/package/tar_input.rb, line 16
16:   def self.open(io, security_policy = nil,  &block)
17:     is = new io, security_policy
18: 
19:     yield is
20:   ensure
21:     is.close if is
22:   end

Public Instance Methods

close() click to toggle source
     # File lib/rubygems/package/tar_input.rb, line 114
114:   def close
115:     @io.close
116:     @tarreader.close
117:   end
each(&block) click to toggle source
     # File lib/rubygems/package/tar_input.rb, line 119
119:   def each(&block)
120:     @tarreader.each do |entry|
121:       next unless entry.full_name == "data.tar.gz"
122:       is = zipped_stream entry
123: 
124:       begin
125:         Gem::Package::TarReader.new is do |inner|
126:           inner.each(&block)
127:         end
128:       ensure
129:         is.close if is
130:       end
131:     end
132: 
133:     @tarreader.rewind
134:   end
extract_entry(destdir, entry, expected_md5sum = nil) click to toggle source
     # File lib/rubygems/package/tar_input.rb, line 136
136:   def extract_entry(destdir, entry, expected_md5sum = nil)
137:     if entry.directory? then
138:       dest = File.join destdir, entry.full_name
139: 
140:       if File.directory? dest then
141:         @fileops.chmod entry.header.mode, dest, :verbose => false
142:       else
143:         @fileops.mkdir_p dest, :mode => entry.header.mode, :verbose => false
144:       end
145: 
146:       fsync_dir dest
147:       fsync_dir File.join(dest, "..")
148: 
149:       return
150:     end
151: 
152:     # it's a file
153:     md5 = Digest::MD5.new if expected_md5sum
154:     destdir = File.join destdir, File.dirname(entry.full_name)
155:     @fileops.mkdir_p destdir, :mode => 0755, :verbose => false
156:     destfile = File.join destdir, File.basename(entry.full_name)
157:     @fileops.chmod 0600, destfile, :verbose => false rescue nil # Errno::ENOENT
158: 
159:     open destfile, "wb", entry.header.mode do |os|
160:       loop do
161:         data = entry.read 4096
162:         break unless data
163:         # HACK shouldn't we check the MD5 before writing to disk?
164:         md5 << data if expected_md5sum
165:         os.write(data)
166:       end
167: 
168:       os.fsync
169:     end
170: 
171:     @fileops.chmod entry.header.mode, destfile, :verbose => false
172:     fsync_dir File.dirname(destfile)
173:     fsync_dir File.join(File.dirname(destfile), "..")
174: 
175:     if expected_md5sum && expected_md5sum != md5.hexdigest then
176:       raise Gem::Package::BadCheckSum
177:     end
178:   end
load_gemspec(io) click to toggle source

Attempt to YAML-load a gemspec from the given io parameter. Return nil if it fails.

     # File lib/rubygems/package/tar_input.rb, line 182
182:   def load_gemspec(io)
183:     Gem::Specification.from_yaml io
184:   rescue Gem::Exception
185:     nil
186:   end
zipped_stream(entry) click to toggle source

Return an IO stream for the zipped entry.

NOTE: Originally this method used two approaches, Return a GZipReader directly, or read the GZipReader into a string and return a StringIO on the string. The string IO approach was used for versions of ZLib before 1.2.1 to avoid buffer errors on windows machines. Then we found that errors happened with 1.2.1 as well, so we changed the condition. Then we discovered errors occurred with versions as late as 1.2.3. At this point (after some benchmarking to show we weren’t seriously crippling the unpacking speed) we threw our hands in the air and declared that this method would use the String IO approach on all platforms at all times. And that’s the way it is.

     # File lib/rubygems/package/tar_input.rb, line 202
202:   def zipped_stream(entry)
203:     if defined? Rubinius or defined? Maglev then
204:       # these implementations have working Zlib
205:       zis = Zlib::GzipReader.new entry
206:       dis = zis.read
207:       is = StringIO.new(dis)
208:     else
209:       # This is Jamis Buck's Zlib workaround for some unknown issue
210:       entry.read(10) # skip the gzip header
211:       zis = Zlib::Inflate.new(-Zlib::MAX_WBITS)
212:       is = StringIO.new(zis.inflate(entry.read))
213:     end
214:   ensure
215:     zis.finish if zis
216:   end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.