Class: RPM::File

Inherits:
Object
  • Object
show all
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

Classes: Header, Lead, Tag

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)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file) ⇒ File

Returns a new instance of File.



17
18
19
20
21
22
23
# File 'lib/arr-pm/file.rb', line 17

def initialize(file)
  if file.is_a?(String)
    file = File.new(file, "r")
  end
  @file = file

end

Instance Attribute Details

#fileObject (readonly)

Returns the value of attribute file.



11
12
13
# File 'lib/arr-pm/file.rb', line 11

def file
  @file
end

Instance Method Details

#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)


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
# File 'lib/arr-pm/file.rb', line 93

def extract(target)
  if !File.directory?(target)
    raise Errno::ENOENT.new(target)
  end

  tags = {}
  header.tags.each do |tag|
    tags[tag.tag] = tag.value
  end 
  
  # Extract to the 'target' path
  #tags[:payloadcompressor] # "xz" or "gzip" or ..?
  #tags[:payloadformat] # "cpio"

  extractor = IO.popen("#{tags[:payloadcompressor]} -d | (cd #{target}; cpio -i --make-directories)", "w")
  buffer = ""
  buffer.force_encoding("BINARY")
  payload_fd = payload
  loop do
    data = payload.read(16384, buffer)
    break if data.nil? # eof
    extractor.write(data)
  end
  extractor.close
end

#headerObject

Return the header for this rpm.



64
65
66
67
68
69
70
71
72
# File 'lib/arr-pm/file.rb', line 64

def header
  signature

  if @header.nil?
    @header = ::RPM::File::Header.new(@file)
    @header.read
  end
  return @header
end

#leadObject

Return the lead for this rpm

This ‘lead’ structure is almost entirely deprecated in the RPM file format.



28
29
30
31
32
33
34
35
36
37
38
# File 'lib/arr-pm/file.rb', line 28

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

#operator(flag) ⇒ Object

def requires



133
134
135
136
137
138
139
140
141
142
143
# File 'lib/arr-pm/file.rb', line 133

def operator(flag)
  have = lambda do |mask|
    return (flag & mask) == mask
  end

  return "<=" if have.call(FLAG_LESS | FLAG_EQUAL)
  return ">=" if have.call(FLAG_GREATER | FLAG_EQUAL)
  return "=" if have.call(FLAG_EQUAL)
  return "<" if have.call(FLAG_LESS)
  return ">" if have.call(FLAG_GREATER)
end

#payloadObject

Returns a file descriptor for the payload. On first invocation, it seeks to the start of the payload



76
77
78
79
80
81
82
83
84
85
86
# File 'lib/arr-pm/file.rb', line 76

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.
    @payload.seek(@lead.length + @signature.length + @signature.length % 8 + @header.length, IO::SEEK_SET)
  end

  return @payload
end

#requiresObject

def extract



119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/arr-pm/file.rb', line 119

def requires
  tags = {}
  header.tags.each do |tag|
    tags[tag.tag] = tag.value
  end

  result = []
  reqs = tags[:requirename].zip(tags[:requireflags], tags[:requireversion])
  reqs.each do |name, flag, version|
    result << [name, operator(flag), version]
  end
  return result
end

#signatureObject

Return the signature header for this rpm



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/arr-pm/file.rb', line 41

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