Class | Gem::Package::TarInput |
In: |
lib/rubygems/package/tar_input.rb
|
Parent: | Object |
metadata | [R] |
# File lib/rubygems/package/tar_input.rb, line 25 25: def initialize(io, security_policy = nil) 26: @io = io 27: @tarreader = Gem::Package::TarReader.new @io 28: has_meta = false 29: 30: data_sig, meta_sig, data_dgst, meta_dgst = nil, nil, nil, nil 31: dgst_algo = security_policy ? Gem::Security::OPT[:dgst_algo] : nil 32: 33: @tarreader.each do |entry| 34: case entry.full_name 35: when "metadata" 36: @metadata = load_gemspec entry.read 37: has_meta = true 38: when "metadata.gz" 39: begin 40: # if we have a security_policy, then pre-read the metadata file 41: # and calculate it's digest 42: sio = nil 43: if security_policy 44: Gem.ensure_ssl_available 45: sio = StringIO.new(entry.read) 46: meta_dgst = dgst_algo.digest(sio.string) 47: sio.rewind 48: end 49: 50: gzis = Zlib::GzipReader.new(sio || entry) 51: # YAML wants an instance of IO 52: @metadata = load_gemspec(gzis) 53: has_meta = true 54: ensure 55: gzis.close unless gzis.nil? 56: end 57: when 'metadata.gz.sig' 58: meta_sig = entry.read 59: when 'data.tar.gz.sig' 60: data_sig = entry.read 61: when 'data.tar.gz' 62: if security_policy 63: Gem.ensure_ssl_available 64: data_dgst = dgst_algo.digest(entry.read) 65: end 66: end 67: end 68: 69: if security_policy then 70: Gem.ensure_ssl_available 71: 72: # map trust policy from string to actual class (or a serialized YAML 73: # file, if that exists) 74: if String === security_policy then 75: if Gem::Security::Policy.key? security_policy then 76: # load one of the pre-defined security policies 77: security_policy = Gem::Security::Policy[security_policy] 78: elsif File.exist? security_policy then 79: # FIXME: this doesn't work yet 80: security_policy = YAML.load File.read(security_policy) 81: else 82: raise Gem::Exception, "Unknown trust policy '#{security_policy}'" 83: end 84: end 85: 86: if data_sig && data_dgst && meta_sig && meta_dgst then 87: # the user has a trust policy, and we have a signed gem 88: # file, so use the trust policy to verify the gem signature 89: 90: begin 91: security_policy.verify_gem(data_sig, data_dgst, @metadata.cert_chain) 92: rescue Exception => e 93: raise "Couldn't verify data signature: #{e}" 94: end 95: 96: begin 97: security_policy.verify_gem(meta_sig, meta_dgst, @metadata.cert_chain) 98: rescue Exception => e 99: raise "Couldn't verify metadata signature: #{e}" 100: end 101: elsif security_policy.only_signed 102: raise Gem::Exception, "Unsigned gem" 103: else 104: # FIXME: should display warning here (trust policy, but 105: # either unsigned or badly signed gem file) 106: end 107: end 108: 109: @tarreader.rewind 110: @fileops = Gem::FileOperations.new 111: 112: raise Gem::Package::FormatError, "No metadata found!" unless has_meta 113: end
# File lib/rubygems/package/tar_input.rb, line 17 17: def self.open(io, security_policy = nil, &block) 18: is = new io, security_policy 19: 20: yield is 21: ensure 22: is.close if is 23: end
# File lib/rubygems/package/tar_input.rb, line 115 115: def close 116: @io.close 117: @tarreader.close 118: end
# File lib/rubygems/package/tar_input.rb, line 120 120: def each(&block) 121: @tarreader.each do |entry| 122: next unless entry.full_name == "data.tar.gz" 123: is = zipped_stream entry 124: 125: begin 126: Gem::Package::TarReader.new is do |inner| 127: inner.each(&block) 128: end 129: ensure 130: is.close if is 131: end 132: end 133: 134: @tarreader.rewind 135: end
# File lib/rubygems/package/tar_input.rb, line 137 137: def extract_entry(destdir, entry, expected_md5sum = nil) 138: if entry.directory? then 139: dest = File.join(destdir, entry.full_name) 140: 141: if File.dir? dest then 142: @fileops.chmod entry.header.mode, dest, :verbose=>false 143: else 144: @fileops.mkdir_p dest, :mode => entry.header.mode, :verbose => false 145: end 146: 147: fsync_dir dest 148: fsync_dir File.join(dest, "..") 149: 150: return 151: end 152: 153: # it's a file 154: md5 = Digest::MD5.new if expected_md5sum 155: destdir = File.join destdir, File.dirname(entry.full_name) 156: @fileops.mkdir_p destdir, :mode => 0755, :verbose => false 157: destfile = File.join destdir, File.basename(entry.full_name) 158: @fileops.chmod 0600, destfile, :verbose => false rescue nil # Errno::ENOENT 159: 160: open destfile, "wb", entry.header.mode do |os| 161: loop do 162: data = entry.read 4096 163: break unless data 164: # HACK shouldn't we check the MD5 before writing to disk? 165: md5 << data if expected_md5sum 166: os.write(data) 167: end 168: 169: os.fsync 170: end 171: 172: @fileops.chmod entry.header.mode, destfile, :verbose => false 173: fsync_dir File.dirname(destfile) 174: fsync_dir File.join(File.dirname(destfile), "..") 175: 176: if expected_md5sum && expected_md5sum != md5.hexdigest then 177: raise Gem::Package::BadCheckSum 178: end 179: end
Attempt to YAML-load a gemspec from the given io parameter. Return nil if it fails.
# File lib/rubygems/package/tar_input.rb, line 183 183: def load_gemspec(io) 184: Gem::Specification.from_yaml io 185: rescue Gem::Exception 186: nil 187: end
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 203 203: def zipped_stream(entry) 204: if defined? Rubinius then 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