Package backend :: Package common :: Module rhn_mpm
[hide private]
[frames] | no frames]

Source Code for Module backend.common.rhn_mpm

  1  # 
  2  # Copyright (c) 2008--2016 Red Hat, Inc. 
  3  # 
  4  # This software is licensed to you under the GNU General Public License, 
  5  # version 2 (GPLv2). There is NO WARRANTY for this software, express or 
  6  # implied, including the implied warranties of MERCHANTABILITY or FITNESS 
  7  # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 
  8  # along with this software; if not, see 
  9  # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 
 10  # 
 11  # Red Hat trademarks are not licensed under GPLv2. No permission is 
 12  # granted to use or replicate Red Hat trademarks that are incorporated 
 13  # in this software or its documentation. 
 14  # 
 15   
 16  import os 
 17  import gzip 
 18  try: 
 19      #  python 2 
 20      import cStringIO 
 21  except ImportError: 
 22      #  python3 
 23      import io as cStringIO 
 24  import tempfile 
 25  try: 
 26      #  python 2 
 27      import xmlrpclib 
 28  except ImportError: 
 29      #  python3 
 30      import xmlrpc.client as xmlrpclib # pylint: disable=F0401 
 31  import struct 
 32  import sys 
 33  from spacewalk.common import fileutils 
 34   
 35  from spacewalk.common.usix import ListType, TupleType 
 36   
 37  from spacewalk.common.usix import raise_with_tb 
 38  from spacewalk.common import checksum 
 39  from spacewalk.common.rhn_pkg import A_Package, InvalidPackageError 
 40   
 41  # bare-except and broad-except 
 42  # pylint: disable=W0702,W0703 
 43   
 44  MPM_CHECKSUM_TYPE = 'md5'       # FIXME: this should be a configuration option 
45 46 47 -def labelCompare(l1, l2):
48 try: 49 from spacewalk.common import rhn_rpm 50 except ImportError: 51 # rhn_rpm not avalable; return a dummy comparison function 52 return -1 53 return rhn_rpm.labelCompare(l1, l2)
54
55 56 -def get_package_header(filename=None, file_obj=None, fd=None):
57 return load(filename=filename, file_obj=file_obj, fd=fd)[0]
58
59 60 -def load(filename=None, file_obj=None, fd=None):
61 """ Loads an MPM and returns its header and its payload """ 62 if (filename is None and file_obj is None and fd is None): 63 raise ValueError("No parameters passed") 64 65 if filename is not None: 66 f = open(filename) 67 elif file_obj is not None: 68 f = file_obj 69 else: # fd is not None 70 f = os.fdopen(os.dup(fd), "r") 71 72 f.seek(0, 0) 73 74 p = MPM_Package() 75 try: 76 p.load(f) 77 except InvalidPackageError: 78 e = sys.exc_info()[1] 79 try: 80 return load_rpm(f) 81 except InvalidPackageError: 82 raise_with_tb(e, sys.exc_info()[2]) 83 except: 84 raise_with_tb(e, sys.exc_info()[2]) 85 86 return p.header, p.payload_stream
87
88 89 -def load_rpm(stream):
90 # Hmm, maybe an rpm 91 92 try: 93 from spacewalk.common import rhn_rpm 94 except ImportError: 95 raise_with_tb(InvalidPackageError, sys.exc_info()[2]) 96 97 # Dup the file descriptor, we don't want it to get closed before we read 98 # the payload 99 newfd = os.dup(stream.fileno()) 100 stream = os.fdopen(newfd, "r") 101 102 stream.flush() 103 stream.seek(0, 0) 104 105 try: 106 header = rhn_rpm.get_package_header(file_obj=stream) 107 except InvalidPackageError: 108 e = sys.exc_info()[1] 109 raise_with_tb(InvalidPackageError(*e.args), sys.exc_info()[2]) 110 except rhn_rpm.error: 111 e = sys.exc_info()[1] 112 raise_with_tb(InvalidPackageError(e), sys.exc_info()[2]) 113 except: 114 raise_with_tb(InvalidPackageError, sys.exc_info()[2]) 115 stream.seek(0, 0) 116 117 return header, stream
118
119 120 -class MPM_Header:
121 122 "Wrapper class for an mpm header - we need to store a flag is_source" 123
124 - def __init__(self, hdr):
125 self.hdr = hdr 126 self.is_source = hdr.get('is_source') 127 self.packaging = 'mpm' 128 self.signatures = []
129
130 - def __getitem__(self, name):
131 return self.hdr.get(name)
132
133 - def __setitem__(self, name, item):
134 self.hdr[name] = item
135
136 - def __delitem__(self, name):
137 del self.hdr[name]
138
139 - def __getattr__(self, name):
140 return getattr(self.hdr, name)
141
142 - def __len__(self):
143 return len(self.hdr)
144 145 @staticmethod
146 - def is_signed():
147 return 0
148 149 @staticmethod
150 - def checksum_type():
151 return MPM_CHECKSUM_TYPE
152 153 @staticmethod
154 - def unload():
155 return None
156 157 MPM_HEADER_COMPRESSED_GZIP = 1 158 MPM_PAYLOAD_COMPRESSED_GZIP = 1
159 160 161 -class MPM_Package(A_Package):
162 # pylint: disable=R0902 163 _lead_format = '!16sB3s4L92s' 164 _magic = 'mpmpackage012345' 165
166 - def __init__(self, input_stream=None):
167 A_Package.__init__(self, input_stream) 168 self.header_flags = MPM_HEADER_COMPRESSED_GZIP 169 self.header_size = 0 170 self.payload_flags = 0 171 assert(len(self._magic) == 16) 172 self._buffer_size = 16384 173 self.file_size = 0
174
175 - def read_header(self):
176 arr = self._read_lead(self.input_stream) 177 magic = arr[0] 178 if magic != self._magic: 179 raise InvalidPackageError() 180 header_len, payload_len = int(arr[5]), int(arr[6]) 181 self.header_flags, self.payload_flags = arr[3], arr[4] 182 self.file_size = 128 + header_len + payload_len 183 header_data = self._read_bytes(self.input_stream, header_len) 184 self._read_header(header_data, self.header_flags) 185 self.checksum_type = self.header.checksum_type()
186
187 - def _read_lead(self, stream):
188 # Lead has the following format: 189 # 16 bytes magic 190 # 1 bytes version 191 # 3 bytes unused 192 # 4 bytes header flags 193 # 4 bytes payload flags 194 # 4 bytes header length 195 # 4 bytes payload length 196 # 92 bytes padding to 128 bytes 197 lead = self._read_bytes(stream, 128) 198 if len(lead) != 128: 199 raise InvalidPackageError() 200 201 arr = struct.unpack(self._lead_format, lead) 202 return arr
203
204 - def load(self, input_stream):
205 # Clean up 206 self.__init__() 207 self.input_stream = input_stream 208 # Read the header 209 self.read_header() 210 211 payload_stream = fileutils.payload(input_stream.name, input_stream.tell()) 212 input_stream.seek(self.file_size) 213 if self.file_size != input_stream.tell(): 214 raise InvalidPackageError() 215 216 self._read_payload(payload_stream, self.payload_flags)
217
218 - def _read_header(self, header_data, header_flags):
219 if header_flags & MPM_HEADER_COMPRESSED_GZIP: 220 t = cStringIO.StringIO(header_data) 221 g = gzip.GzipFile(None, "r", 0, t) 222 header_data = g.read() 223 g.close() 224 t.close() 225 226 try: 227 params, _x = xmlrpclib.loads(header_data) 228 except: 229 # XXX 230 raise 231 232 self.header = MPM_Header(params[0])
233
234 - def _read_payload(self, payload_stream, payload_flags):
235 payload_stream.seek(0, 0) 236 if payload_flags & MPM_PAYLOAD_COMPRESSED_GZIP: 237 g = gzip.GzipFile(None, "r", 0, payload_stream) 238 t = tempfile.TemporaryFile() 239 self._stream_copy(g, t) 240 g.close() 241 payload_stream = t 242 243 self.payload_stream = payload_stream
244
245 - def write(self, output_stream):
246 if self.header is None: 247 raise Exception() 248 249 output_stream.seek(128, 0) 250 self._encode_header(output_stream) 251 self._encode_payload(output_stream) 252 253 # pylint: disable=E0012,W1401 254 # now we know header and payload size so rewind back and write lead 255 lead_arr = (self._magic, 1, "\0" * 3, self.header_flags, 256 self.payload_flags, self.header_size, self.payload_size, '\0' * 92) 257 # lead 258 lead = struct.pack(self._lead_format, *lead_arr) 259 output_stream.seek(0, 0) 260 output_stream.write(lead) 261 output_stream.seek(0, 2)
262
263 - def _encode_header(self, stream):
264 assert(self.header is not None) 265 data = xmlrpclib.dumps((_replace_null(self.header), )) 266 start = stream.tell() 267 if self.header_flags & MPM_HEADER_COMPRESSED_GZIP: 268 f = gzip.GzipFile(None, "wb", 9, stream) 269 f.write(data) 270 f.close() 271 else: 272 stream.write(data) 273 stream.flush() 274 self.header_size = stream.tell() - start
275
276 - def _encode_payload(self, stream, c_hash=None):
277 assert(self.payload_stream is not None) 278 if stream: 279 start = stream.tell() 280 if stream and self.payload_flags & MPM_PAYLOAD_COMPRESSED_GZIP: 281 f = gzip.GzipFile(None, "wb", 9, stream) 282 self._stream_copy(self.payload_stream, f, c_hash) 283 f.close() 284 else: 285 self._stream_copy(self.payload_stream, stream, c_hash) 286 if stream: 287 self.payload_size = stream.tell() - start
288
289 - def save_payload(self, output_stream):
290 self.payload_stream = self.input_stream 291 c_hash = checksum.getHashlibInstance(self.header.checksum_type(), False) 292 self._encode_payload(output_stream, c_hash) 293 self.checksum = c_hash.hexdigest() 294 if output_stream: 295 self.payload_stream = output_stream
296
297 298 -def _replace_null(obj):
299 if obj is None: 300 return '' 301 if isinstance(obj, ListType): 302 return list(map(_replace_null, obj)) 303 if isinstance(obj, TupleType): 304 return tuple(_replace_null(list(obj))) 305 if hasattr(obj, 'items'): 306 obj_dict = {} 307 for k, v in obj.items(): 308 obj_dict[_replace_null(k)] = _replace_null(v) 309 return obj_dict 310 return obj
311