Class: RPM::File
- Inherits:
-
Object
- Object
- RPM::File
- Defined in:
- lib/arr-pm/file.rb,
lib/arr-pm/namespace.rb
Overview
Much of the code here is derived from knowledge gained by reading the rpm source code, but mostly it started making more sense after reading this site: www.rpm.org/max-rpm/s1-rpm-file-format-rpm-file-format.html
Defined Under Namespace
Constant Summary collapse
- FLAG_LESS =
RPMSENSE_LESS = (1 << 1),
(1 << 1)
- FLAG_GREATER =
RPMSENSE_GREATER = (1 << 2),
(1 << 2)
- FLAG_EQUAL =
RPMSENSE_EQUAL = (1 << 3),
(1 << 3)
- FLAG_CONFIG_FILE =
from rpm/rpmfi.h
(1 << 0)
Instance Attribute Summary collapse
-
#file ⇒ Object
readonly
Returns the value of attribute file.
Instance Method Summary collapse
-
#config_files ⇒ Object
Get an array of config files.
-
#conflicts ⇒ Object
Get an array of conflicts defined in this package.
-
#extract(target) ⇒ Object
Extract this RPM to a target directory.
-
#files ⇒ Object
List the files in this RPM.
-
#header ⇒ Object
Return the header for this rpm.
-
#initialize(file) ⇒ File
constructor
A new instance of File.
-
#lead ⇒ Object
Return the lead for this rpm.
-
#mask?(value, mask) ⇒ Boolean
def files.
-
#operator(flag) ⇒ Object
def mask?.
-
#payload ⇒ Object
Returns a file descriptor for the payload.
-
#provides ⇒ Object
Get an array of provides defined in this package.
-
#relation(type) ⇒ Object
Get all relations of a given type to this package.
-
#requires ⇒ Object
Get an array of requires defined in this package.
-
#signature ⇒ Object
Return the signature header for this rpm.
-
#tags ⇒ Object
def extract.
-
#valid_compressor?(name) ⇒ Boolean
def payload.
Constructor Details
Instance Attribute Details
#file ⇒ Object (readonly)
Returns the value of attribute file.
13 14 15 |
# File 'lib/arr-pm/file.rb', line 13 def file @file end |
Instance Method Details
#config_files ⇒ Object
Get an array of config files
191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/arr-pm/file.rb', line 191 def config_files # this stuff seems to be in the 'enum rpmfileAttrs_e' from rpm/rpmfi.h results = [] # short-circuit if there's no :fileflags tag return results unless .include?(:fileflags) if ![:fileflags].nil? [:fileflags].each_with_index do |flag, i| # The :fileflags (and other :file... tags) are an array, in order of # files in the rpm payload, we want a list of paths of config files. results << files[i] if mask?(flag, FLAG_CONFIG_FILE) end end return results end |
#conflicts ⇒ Object
Get an array of conflicts defined in this package.
179 180 181 |
# File 'lib/arr-pm/file.rb', line 179 def conflicts return relation(:conflict) end |
#extract(target) ⇒ Object
Extract this RPM to a target directory.
This should have roughly the same effect as:
% rpm2cpio blah.rpm | (cd {target}; cpio -i --make-directories)
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 |
# File 'lib/arr-pm/file.rb', line 105 def extract(target) if !File.directory?(target) raise Errno::ENOENT.new(target) end compressor = [:payloadcompressor] if !valid_compressor?(compressor) raise "Cannot decompress. This RPM uses an invalid compressor '#{compressor}'" end extractor = IO.popen("#{compressor} -d | (cd #{Shellwords.escape(target)}; cpio -i --quiet --make-directories)", "w") buffer = "" begin buffer.force_encoding("BINARY") rescue NoMethodError # Do Nothing end payload_fd = payload.clone loop do data = payload_fd.read(16384, buffer) break if data.nil? # eof extractor.write(data) end payload_fd.close extractor.close end |
#files ⇒ Object
List the files in this RPM.
This should have roughly the same effect as:
% rpm2cpio blah.rpm | cpio -it
211 212 213 214 215 216 217 218 219 |
# File 'lib/arr-pm/file.rb', line 211 def files # RPM stores the file metadata split across multiple tags. # A single path's filename (with no directories) is stored in the "basename" tag. # The directory a file lives in is stored in the "dirnames" tag # We can find out what directory a file is in using the "dirindexes" tag. # # We can join each entry of dirnames and basenames to make the full filename. return [:basenames].zip([:dirindexes]).map { |name, i| File.join([:dirnames][i], name) } end |
#header ⇒ Object
Return the header for this rpm.
68 69 70 71 72 73 74 75 76 |
# File 'lib/arr-pm/file.rb', line 68 def header signature if @header.nil? @header = ::RPM::File::Header.new(@file) @header.read end return @header end |
#lead ⇒ Object
Return the lead for this rpm
This ‘lead’ structure is almost entirely deprecated in the RPM file format.
32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/arr-pm/file.rb', line 32 def lead if @lead.nil? # Make sure we're at the beginning of the file. @file.seek(0, IO::SEEK_SET) @lead = ::RPM::File::Lead.new(@file) # TODO(sissel): have 'read' return number of bytes read? @lead.read end return @lead end |
#mask?(value, mask) ⇒ Boolean
def files
221 222 223 |
# File 'lib/arr-pm/file.rb', line 221 def mask?(value, mask) return (value & mask) == mask end |
#operator(flag) ⇒ Object
def mask?
225 226 227 228 229 230 231 |
# File 'lib/arr-pm/file.rb', line 225 def operator(flag) return "<=" if mask?(flag, FLAG_LESS | FLAG_EQUAL) return ">=" if mask?(flag, FLAG_GREATER | FLAG_EQUAL) return "=" if mask?(flag, FLAG_EQUAL) return "<" if mask?(flag, FLAG_LESS) return ">" if mask?(flag, FLAG_GREATER) end |
#payload ⇒ Object
Returns a file descriptor for the payload. On first invocation, it seeks to the start of the payload
80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/arr-pm/file.rb', line 80 def payload header if @payload.nil? @payload = @file.clone # The payload starts after the lead, signature, and header. Remember the signature has an # 8-byte boundary-rounding. end @payload.seek(@lead.length + @signature.length + @signature.length % 8 + @header.length, IO::SEEK_SET) return @payload end |
#provides ⇒ Object
Get an array of provides defined in this package.
186 187 188 |
# File 'lib/arr-pm/file.rb', line 186 def provides return relation(:provide) end |
#relation(type) ⇒ Object
Get all relations of a given type to this package.
Examples:
rpm.relation(:require)
rpm.relation(:conflict)
rpm.relation(:provide)
In the return array-of-arrays, the elements are:
- name (string), operator (string), version (string)
-
operator will be “>=”, “>”, “=”, “<”, or “<=”
156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/arr-pm/file.rb', line 156 def relation(type) name = "#{type}name".to_sym flags = "#{type}flags".to_sym version = "#{type}version".to_sym # There is no data if we are missing all 3 tag types (name/flags/version) # FYI: 'tags.keys' is an array, Array#& does set intersection. return [] if (.keys & [name, flags, version]).size != 3 # Find tags <type>name, <type>flags, and <type>version, and return # an array of "name operator version" return [name].zip([flags], [version]) \ .reduce([]) { |memo, (n,o,v)| memo << [n, operator(o), v] } end |
#requires ⇒ Object
Get an array of requires defined in this package.
172 173 174 |
# File 'lib/arr-pm/file.rb', line 172 def requires return relation(:require) end |
#signature ⇒ Object
Return the signature header for this rpm
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/arr-pm/file.rb', line 45 def signature lead # Make sure we've parsed the lead... # If signature_type is not 5 (HEADER_SIGNED_TYPE), no signature. if @lead.signature_type != Header::HEADER_SIGNED_TYPE @signature = false return end if @signature.nil? @signature = ::RPM::File::Header.new(@file) @signature.read # signature headers are padded up to an 8-byte boundar, details here: # http://rpm.org/gitweb?p=rpm.git;a=blob;f=lib/signature.c;h=63e59c00f255a538e48cbc8b0cf3b9bd4a4dbd56;hb=HEAD#l204 # Throw away the pad. @file.read(@signature.length % 8) end return @signature end |
#tags ⇒ Object
def extract
132 133 134 135 136 137 138 139 140 |
# File 'lib/arr-pm/file.rb', line 132 def if @tags.nil? @tags = {} header..each do |tag| [tag.tag] = tag.value end end @tags end |
#valid_compressor?(name) ⇒ Boolean
def payload
92 93 94 95 96 97 98 |
# File 'lib/arr-pm/file.rb', line 92 def valid_compressor?(name) # I scanned rpm's rpmio.c for payload implementation names and found the following. # sed -rne '/struct FDIO_s \w+ *= *\{/{ n; s/^.*"(\w+)",$/\1/p }' rpmio/rpmio.c # It's possible this misses some supported rpm payload compressors. [ "gzip", "bzip2", "xz", "lzma", "zstd" ].include?(name) end |