PROJECT_MOVED -> https://lab.nexedi.com/nexedi/slapos
[slapos.git] / component / rpm2cpio / rpm2cpio
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # Standalone RPM to CPIO converter
5 # Copyright (c) 2012 Rudá Moura
6 # https://github.com/ruda/rpm2cpio
7 #
8 # Impove gzip header detection thanks to
9 # http://afb.users.sourceforge.net/centos/rpm2cpio.py
10 #
11 # Copyright (C) 1997,1998,1999, Roger Espel Llima
12 # Copyright (C) 2000, Sergey Babkin
13 # Copyright (C) 2009, Alex Kozlov
14 # Copyright (C) 2010, Anders F Bjorklund
15 #
16 # Permission is hereby granted, free of charge, to any person obtaining a copy
17 # of this software and any associated documentation files (the "Software"), to
18 # deal in the Software without restriction, including without limitation the
19 # rights to use, copy, modify, merge, publish, distribute, sublicense,
20 # and/or sell copies of the Software, and to permit persons to whom the
21 # Software is furnished to do so, subject to the following conditions:
22 #
23 # The above copyright notice and this permission notice shall be included in
24 # all copies or substantial portions of the Software.
25 #
26 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
29 # SOFTWARE'S COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32 # THE SOFTWARE
33
34 '''Extract cpio archive from RPM package.
35
36 rpm2cpio converts the RPM on standard input or first parameter to a CPIO archive on standard output.
37
38 Usage:
39 rpm2cpio < adjtimex-1.20-2.1.i386.rpm  | cpio -it
40 ./sbin/adjtimex
41 ./usr/share/doc/adjtimex-1.20
42 ./usr/share/doc/adjtimex-1.20/COPYING
43 ./usr/share/doc/adjtimex-1.20/COPYRIGHT
44 ./usr/share/doc/adjtimex-1.20/README
45 ./usr/share/man/man8/adjtimex.8.gz
46 133 blocks
47 '''
48
49 import sys
50 import struct
51 import StringIO
52 import gzip
53
54 RPM_MAGIC = '\xed\xab\xee\xdb'
55 GZIP_MAGIC = '\x1f\x8b'
56
57 def rpm2cpio(stream_in=sys.stdin, stream_out=sys.stdout):
58     lead = stream_in.read(96)
59     if lead[0:4] != RPM_MAGIC:
60         raise IOError, 'the input is not a RPM package'
61     lead = stream_in.read(16)
62     if not lead:
63         raise IOError, 'No header'
64
65     while True:
66         (magic, ignore, sections, bytes) = struct.unpack("!LLLL", lead)
67         (smagic, smagic2) = struct.unpack("!HL", lead[0:6])
68
69         if smagic == 0x1f8b:
70             break
71
72         # skip the headers
73         stream_in.seek(16 * sections + bytes, 1)
74         while True:
75             lead = stream_in.read(1)
76             if lead == "":
77                 raise IOError, 'No header'
78             if (0,) == struct.unpack("B", lead):
79                 continue
80             break
81         lead += stream_in.read(15)
82         if lead == "":
83             raise IOError, 'No header'
84
85     stream_in.seek(-len(lead), 1)
86     gzipper = gzip.GzipFile(fileobj=stream_in)
87     data = gzipper.read()
88     stream_out.write(data)
89
90 if __name__ == '__main__':
91     if sys.argv[1:]:
92         try:
93             fin = open(sys.argv[1])
94             rpm2cpio(fin)
95             fin.close()
96         except IOError, e:
97             print 'Error:', sys.argv[1], e
98     else:
99         try:
100             rpm2cpio()
101         except IOError, e:
102             print 'Error:', e