Permalink
Browse files

- update example code

  • Loading branch information...
1 parent c6695bb commit bcc3c5aada2a60cd2832710b897434bdd53d1558 @jordansissel committed Feb 19, 2012
Showing with 81 additions and 18 deletions.
  1. +2 −5 README.md
  2. +71 −0 header-verify.rb
  3. +8 −13 printrpm.rb
View
@@ -19,7 +19,7 @@ especially without requiring root access to get things going.
It should be possible to do a read+modify+write on an RPM.
-### Creating an RPM
+### Creating an RPM (proposed API)
rpm = RPM.new
@@ -43,7 +43,7 @@ It should be possible to do a read+modify+write on an RPM.
rpm.write(output_file_name)
-### Reading an RPM
+### Reading an RPM (proposed API)
rpm = RPM.read(file)
@@ -66,6 +66,3 @@ Maybe something like:
# file.io could give a nice IO-like thing that let you read the file out
# of the rpm
end
-
-
-
View
@@ -0,0 +1,71 @@
+HEADER_MAGIC = "\x8e\xad\xe8\x01\x00\x00\x00\x00"
+TAG_ENTRY_SIZE = 16 # tag id, type, offset, count == 16 bytes
+
+def read_header(io)
+ # RPM 'header' section looks like:
+ #
+ # MAGIC (8 bytes) index_count (4 bytes), data_length (4 bytes )
+ #
+ # * index_count is the number of 'tags' in this header.
+ # * data_length is a blob containing all the values for the tags
+ #
+ # Header has a header of 'magic' + index_count (4 bytes) + data_length (4 bytes)
+ #p "start of header" => io.pos
+ data = io.read(16).unpack("a8NN")
+
+ # TODO(sissel): @index_count is really a count, rename?
+ @magic, @index_count, @data_length = data
+ if @magic != HEADER_MAGIC
+ puts "Magic value in header was wrong. Expected #{HEADER_MAGIC.inspect}, but got #{@magic.inspect}"
+ exit 1
+ end
+
+ @index_size = @index_count * TAG_ENTRY_SIZE
+ tag_data = io.read(@index_size)
+ data = io.read(@data_length)
+ #p "end of header" => io.pos
+
+ (0 ... @index_count).each do |i|
+ offset = i * TAG_ENTRY_SIZE
+ entry_data = tag_data[i * TAG_ENTRY_SIZE, TAG_ENTRY_SIZE]
+ tag, tag_type, offset, count = entry_data.unpack("NNNN")
+ if block_given?
+ yield :tag => tag, :type => tag_type, :offset => offset, :count => count
+ end
+ #entry << data
+ end # each index
+ return 16 + @index_size + @data_length
+end
+
+if ARGV.length != 1
+ puts "Usage: #{$0} blah.rpm"
+ exit 1
+end
+
+rpm = File.new(ARGV[0])
+
+# Read the 'lead' - it's mostly an ignored part of the rpm file.
+lead = rpm.read(96)
+magic, major, minor, type, archnum, name, osnum, signature_type, reserved = lead.unpack("A4CCnnA66nnA16")
+
+puts "RPM file version #{major}.#{minor} (#{signature_type == 5 ? "signed" : "unsigned"})"
+
+if signature_type == 5
+ # Read a header for the rpm signature. This has the same format as a normal
+ # rpm header
+ puts "Checking signature"
+ length = read_header(rpm) do |tag|
+ # print each tag in this header
+ p tag
+ end
+
+ # 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.
+ rpm.read((length % 8))
+end
+
+# Read the rpm header
+puts "Checking header"
+read_header(rpm)
+p rpm.read(4)
View
@@ -5,20 +5,15 @@
rpm = RPM::File.new(ARGV[0])
p rpm.lead
-p rpm.signature
-#rpm.signature.tags.each do |tag|
- #p :signature => [tag.tag, tag.type, tag.value]
-#end
-p rpm.header
+rpm.signature.tags.each do |tag|
+ #p :tag => [tag.tag, tag.type, tag.count, tag.value]
+end
rpm.header.tags.each do |tag|
- #next unless tag.tag.to_s =~ /(require|provide)/
- p tag.tag => tag.value
+ next unless tag.tag.to_s =~ /(require|provide|payload)/
+ #p tag.tag => tag.value
end
-#rpm.header.tags[-3..-1].each do |tag|
- #p :header => [tag.tag, tag.type, tag.value]
-#end
-#payload = rpm.payload
-#fd = File.new("/tmp/x.cpio.gz", "w")
-#fd.write(rpm.payload.read)
+payload = rpm.payload
+fd = File.new("/tmp/rpm.payload", "w")
+fd.write(rpm.payload.read)

0 comments on commit bcc3c5a

Please sign in to comment.