1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 import os
17 import sys
18 import struct
19 import tempfile
20 import functools
21
22 import rpm
23
24 from spacewalk.common.usix import raise_with_tb
25 from spacewalk.common.usix import next as usix_next
26 from spacewalk.common import checksum
27 from spacewalk.common.rhn_pkg import A_Package, InvalidPackageError
28 from rhn.i18n import sstr
29
30
31
32
33 if not hasattr(tempfile, 'SpooledTemporaryFile'):
34
35 tempfile.SpooledTemporaryFile = tempfile.NamedTemporaryFile
36
37
38
39 error = rpm.error
40
41 sym, val = None, None
42 for sym, val in rpm.__dict__.items():
43 if sym[:3] == 'RPM':
44
45 globals()[sym] = val
46 del sym, val
47
48
49 rpm.RPMTAG_FILEDIGESTALGO = 5011
50
51
52
53
54
55
56
57
58
59
60
61 PGPHASHALGO = {
62 1: 'md5',
63 2: 'sha1',
64 3: 'ripemd160',
65 5: 'md2',
66 6: 'tiger192',
67 7: 'haval-5-160',
68 8: 'sha256',
69 9: 'sha384',
70 10: 'sha512',
71 }
75
76 "Wrapper class for an rpm header - we need to store a flag is_source"
77
79 self.hdr = hdr
80 self.is_source = is_source
81 self.packaging = 'rpm'
82 self.signatures = []
83 self._extract_signatures()
84
86 item = self.hdr[name]
87 if isinstance(item, bytes):
88 item = sstr(item)
89 return item
90
93
96
98 item = getattr(self.hdr, name)
99 if isinstance(item, bytes):
100 item = sstr(item)
101 return item
102
105
107 return bool(self.hdr)
108
109 __bool__ = __nonzero__
110
118
120 if hasattr(rpm, "RPMTAG_DSAHEADER"):
121 dsaheader = self.hdr["dsaheader"]
122 else:
123 dsaheader = 0
124 if self.hdr["siggpg"] or self.hdr["sigpgp"] or dsaheader:
125 return 1
126 return 0
127
129 header_tags = [
130 [rpm.RPMTAG_DSAHEADER, "dsa"],
131 [rpm.RPMTAG_RSAHEADER, "rsa"],
132 [rpm.RPMTAG_SIGGPG, "gpg"],
133 [rpm.RPMTAG_SIGPGP, 'pgp'],
134 ]
135 for ht, sig_type in header_tags:
136 ret = self.hdr[ht]
137 if not ret:
138 continue
139 ret_len = len(ret)
140 if ret_len < 17:
141 continue
142
143 elif ret_len <= 65:
144 key_id = ret[9:17]
145 elif ret_len <= 72:
146 key_id = ret[18:26]
147 elif ret_len <= 280:
148 key_id = ret[10:18]
149 elif ret_len <= 287:
150 key_id = ret[19:27]
151 elif ret_len <= 536:
152 key_id = ret[10:18]
153 else:
154 key_id = ret[19:27]
155
156 key_id_len = len(key_id)
157 fmt = "%dB" % key_id_len
158 t = struct.unpack(fmt, key_id)
159 fmt = "%02x" * key_id_len
160 key_id = fmt % t
161 self.signatures.append({
162 'signature_type': sig_type,
163 'key_id': key_id,
164 'signature': ret,
165 })
166
169
170
172 A_Package.__init__(self, input_stream)
173 self.header = None
174 self.header_data = tempfile.SpooledTemporaryFile()
175 self.header_start = None
176 self.header_end = None
177 self.checksum_type = None
178 self.checksum = None
179 self.payload_stream = None
180 self.payload_size = None
181
195
197 """
198 Return the start and end bytes of the rpm header object.
199 Raw header data are then stored in self.header_data.
200
201 For details of the rpm file format, see:
202 http://www.rpm.org/max-rpm/s1-rpm-file-format-rpm-file-format.html
203 """
204
205 lead_size = 96
206 struct_lead_size = 16
207
208 buf = self._read_bytes(self.input_stream, lead_size)
209 self.header_data.write(buf)
210
211 buf = self._read_bytes(self.input_stream, struct_lead_size)
212 self.header_data.write(buf)
213
214 sig_size = self._get_header_struct_size(buf)
215
216
217 self.header_start = lead_size + sig_size
218
219 buf = self._read_bytes(self.input_stream, sig_size - struct_lead_size)
220 self.header_data.write(buf)
221
222 buf = self._read_bytes(self.input_stream, struct_lead_size)
223 self.header_data.write(buf)
224
225 header_size = self._get_header_struct_size(buf)
226 self.header_end = self.header_start + header_size
227
228 buf = self._read_bytes(self.input_stream, header_size - struct_lead_size)
229 self.header_data.write(buf)
230
231 @staticmethod
233 """
234 Compute the size in bytes of the rpm header struct starting at the current
235 position in package_file.
236 """
237
238 header_index = struct_lead[8:12]
239 (header_index_value, ) = struct.unpack('>I', header_index)
240
241
242 header_store = struct_lead[12:16]
243 (header_store_value, ) = struct.unpack('>I', header_store)
244
245
246 header_size = 8 + 4 + 4 + header_index_value * 16 + header_store_value
247
248
249 round_out = header_size % 8
250 if round_out != 0:
251 header_size = header_size + (8 - round_out)
252
253 return header_size
254
256 c_hash = checksum.getHashlibInstance(self.checksum_type, False)
257 if output_stream:
258 output_start = output_stream.tell()
259 self.header_data.seek(0, 0)
260 self._stream_copy(self.header_data, output_stream, c_hash)
261 self._stream_copy(self.input_stream, output_stream, c_hash)
262 self.checksum = c_hash.hexdigest()
263 self.header_data.close()
264 if output_stream:
265 self.payload_stream = output_stream
266 self.payload_size = output_stream.tell() - output_start
267
270 """
271 Return the start and end bytes of the rpm header object.
272
273 For details of the rpm file format, see:
274 http://www.rpm.org/max-rpm/s1-rpm-file-format-rpm-file-format.html
275 """
276
277 lead_size = 96
278
279
280 package_file.seek(lead_size)
281
282 sig_size = get_header_struct_size(package_file)
283
284
285 header_start = lead_size + sig_size
286
287 package_file.seek(header_start)
288
289 header_size = get_header_struct_size(package_file)
290
291 header_end = header_start + header_size
292
293 return (header_start, header_end)
294
297 """
298 Compute the size in bytes of the rpm header struct starting at the current
299 position in package_file.
300 """
301
302 package_file.seek(8, 1)
303
304
305 header_index = package_file.read(4)
306 (header_index_value, ) = struct.unpack('>I', header_index)
307
308
309 header_store = package_file.read(4)
310 (header_store_value, ) = struct.unpack('>I', header_store)
311
312
313 header_size = 8 + 4 + 4 + header_index_value * 16 + header_store_value
314
315
316 round_out = header_size % 8
317 if round_out != 0:
318 header_size = header_size + (8 - round_out)
319
320 return header_size
321
322 SHARED_TS = None
326 """ Loads the package header from a file / stream / file descriptor
327 Raises rpm.error if an error is found, or InvalidPacageError if package is
328 busted
329 """
330 global SHARED_TS
331
332 if (filename is None and file_obj is None and fd is None):
333 raise ValueError("No parameters passed")
334
335 if filename is not None:
336 f = open(filename, 'rb')
337 elif file_obj is not None:
338 f = file_obj
339 f.seek(0, 0)
340 else:
341 f = None
342
343 if f is None:
344 os.lseek(fd, 0, 0)
345 file_desc = fd
346 else:
347 file_desc = f.fileno()
348
349
350
351 if not SHARED_TS:
352 SHARED_TS = rpm.ts()
353 SHARED_TS.setVSFlags(-1)
354
355 rpm.addMacro('_dbpath', '/var/cache/rhn/rhnpush-rpmdb')
356 try:
357 hdr = SHARED_TS.hdrFromFdno(file_desc)
358 rpm.delMacro('_dbpath')
359 except:
360 rpm.delMacro('_dbpath')
361 raise
362
363 if hdr is None:
364 raise InvalidPackageError
365 is_source = hdr[rpm.RPMTAG_SOURCEPACKAGE]
366
367 return RPM_Header(hdr, is_source)
368
371
372 - def __init__(self, tag_name=None, value=None):
373
374 if not tag_name:
375 tag_name = "name"
376
377
378 self.ts = rpm.TransactionSet()
379 self.ts.setVSFlags(8)
380
381 m_args = (tag_name,)
382 if value:
383 m_args += (value,)
384
385 self.mi = self.ts.dbMatch(*m_args)
386
387 - def pattern(self, tag_name, mode, pattern):
389
391 try:
392 hdr = usix_next(self.mi)
393 except StopIteration:
394 hdr = None
395
396 if hdr is None:
397 return None
398 is_source = hdr[rpm.RPMTAG_SOURCEPACKAGE]
399 return RPM_Header(hdr, is_source)
400
406
410
413 def build_evr(p):
414 evr = [p[3], p[1], p[2]]
415 evr = list(map(str, evr))
416 if evr[0] == "":
417 evr[0] = None
418 return evr
419 if t1[0] != t2[0]:
420 raise ValueError("You should only compare packages with the same name")
421 evr1, evr2 = (build_evr(t1), build_evr(t2))
422 return rpm.labelCompare(evr1, evr2)
423
426 """ take two RPMs or headers and compare them for order """
427
428 if hdr1['name'] == hdr2['name']:
429 hdr1 = [hdr1['epoch'] or None, hdr1['version'], hdr1['release']]
430 hdr2 = [hdr2['epoch'] or None, hdr2['version'], hdr2['release']]
431 if hdr1[0]:
432 hdr1[0] = str(hdr1[0])
433 if hdr2[0]:
434 hdr2[0] = str(hdr2[0])
435 return rpm.labelCompare(hdr1, hdr2)
436 elif hdr1['name'] < hdr2['name']:
437 return -1
438 return 1
439
442 """ Sorts a list of RPM files. They *must* exist. """
443
444 assert isinstance(rpms, type([]))
445
446
447 helper = [(get_package_header(x), x) for x in rpms]
448
449
450 sort_cmp=lambda x, y: hdrLabelCompare(x[0], y[0])
451 try:
452 helper.sort(sort_cmp)
453 except TypeError:
454 helper.sort(key=functools.cmp_to_key(sort_cmp))
455
456
457 return [x[1] for x in helper]
458
461 """ quieries the RPM DB for a header matching rpmName. """
462
463 matchiter = MatchIterator("name")
464 matchiter.pattern("name", rpm.RPMMIRE_STRCMP, rpmName)
465 return matchiter.next()
466
467
468 if __name__ == '__main__':
469 pass
470