scripts/x

branch
trunk
changeset 16
29794d4d41aa
parent 15
28dbd52a8bb8
child 17
481a2b4be471
equal deleted inserted replaced
15:28dbd52a8bb8 16:29794d4d41aa
45 45
46 MATCHING_DIRECTORY = 1 46 MATCHING_DIRECTORY = 1
47 # ONE_DIRECTORY = 2 47 # ONE_DIRECTORY = 2
48 BOMB = 3 48 BOMB = 3
49 EMPTY = 4 49 EMPTY = 4
50 DECOMPRESSED = 5 50 COMPRESSED = 5
51 51
52 mimetypes.encodings_map.setdefault('.bz2', 'bzip2') 52 mimetypes.encodings_map.setdefault('.bz2', 'bzip2')
53 mimetypes.types_map['.exe'] = 'application/x-msdos-program' 53 mimetypes.types_map['.exe'] = 'application/x-msdos-program'
54 54
55 def run_command(command, description, stdout=None, stderr=None, stdin=None): 55 def run_command(command, description, stdout=None, stderr=None, stdin=None):
306 306
307 def get_filenames(self): 307 def get_filenames(self):
308 yield self.basename() 308 yield self.basename()
309 309
310 def check_contents(self): 310 def check_contents(self):
311 return DECOMPRESSED 311 return COMPRESSED
312 312
313 def extract(self, path): 313 def extract(self, path):
314 output = open(path, 'w') 314 output = open(path, 'w')
315 self.run(['cat'], "output write", stdin=self.archive, stdout=output) 315 self.run(['cat'], "output write", stdin=self.archive, stdout=output)
316 output.close() 316 output.close()
321 self.logger = logging.getLogger('x-log') 321 self.logger = logging.getLogger('x-log')
322 self.extractor = extractor 322 self.extractor = extractor
323 self.contents = contents 323 self.contents = contents
324 self.options = options 324 self.options = options
325 325
326 ## def extract(self):
327 ## raise NotImplementedError
328 ## checker = self.extractor.name_checker(self.extractor.basename())
329 ## if self.options.flat:
330 ## self.target = '.'
331 ## return self.do_extract('.')
332 ## elif self.options.overwrite or checker.is_free():
333 ## self.target = self.extractor.basename()
334 ## return self.overwrite()
335 ## else:
336 ## self.target = checker.check()
337 ## return self.safe_extract()
338
326 def extract(self): 339 def extract(self):
327 checker = self.extractor.name_checker(self.extractor.basename()) 340 try:
328 if self.options.flat: 341 self.extractor.extract(self.target)
329 self.target = '.'
330 return self.do_extract('.')
331 elif self.options.overwrite or checker.is_free():
332 self.target = self.extractor.basename()
333 return self.overwrite()
334 else:
335 self.target = checker.check()
336 return self.safe_extract()
337
338 def do_extract(self, directory):
339 try:
340 self.extractor.extract(directory)
341 except ExtractorError, error: 342 except ExtractorError, error:
342 return str(error) 343 return str(error)
343 344
344 def cleanup(self): 345 def cleanup(self):
346 raise NotImplementedError
345 if self.options.flat: 347 if self.options.flat:
346 self.cleanup_files() 348 self.cleanup_files()
347 else: 349 else:
348 self.cleanup_directory() 350 self.cleanup_directory()
349 351
364 status = subprocess.call(['chmod', '-R', 'u+rw', self.target]) 366 status = subprocess.call(['chmod', '-R', 'u+rw', self.target])
365 if status != 0: 367 if status != 0:
366 return "%s returned with exit status %s" % (command, status) 368 return "%s returned with exit status %s" % (command, status)
367 369
368 370
371 # The "where to extract" table, with options and archive types.
372 # This dictates the contents of each can_handle method.
373 #
374 # Flat Overwrite None
375 # File basename basename FilenameChecked
376 # Match . . tempdir + checked
377 # Bomb . basename DirectoryChecked
378
379
380 class FlatHandler(BaseHandler):
381 def can_handle(contents, options):
382 return ((options.flat and (contents != COMPRESSED)) or
383 (options.overwrite and (contents == MATCHING_DIRECTORY)))
384 can_handle = staticmethod(can_handle)
385
386 target = '.'
387 cleanup = BaseHandler.cleanup_files
388
389
390 class OverwriteHandler(BaseHandler):
391 def can_handle(contents, options):
392 return ((options.flat and (contents == COMPRESSED)) or
393 (options.overwrite and (contents != MATCHING_DIRECTORY)))
394 can_handle = staticmethod(can_handle)
395
396 def __init__(self, extractor, contents, options):
397 BaseHandler.__init__(self, extractor, contents, options)
398 self.target = self.extractor.basename()
399
400 cleanup = BaseHandler.cleanup_directory
401
402
369 class MatchHandler(BaseHandler): 403 class MatchHandler(BaseHandler):
370 def overwrite(self): 404 def can_handle(contents, options):
371 return self.do_extract('.') 405 return contents == MATCHING_DIRECTORY
372 406 can_handle = staticmethod(can_handle)
373 def safe_extract(self): 407
374 tempdir = tempfile.mkdtemp() 408 def extract(self):
375 result = self.do_extract(tempdir) 409 basename = self.extractor.basename()
410 self.target = tempfile.mkdtemp()
411 result = BaseHandler.extract(self)
376 if result is None: 412 if result is None:
377 os.rename(os.path.join(tempdir, self.extractor.basename()), 413 tempdir = self.target
378 self.target) 414 checker = self.extractor.name_checker(basename)
415 self.target = checker.check()
416 os.rename(os.path.join(tempdir, basename), self.target)
379 os.rmdir(tempdir) 417 os.rmdir(tempdir)
380 return result 418 return result
381 419
382 420 cleanup = BaseHandler.cleanup_directory
383 class BombHandler(BaseHandler):
384 def safe_extract(self):
385 return self.do_extract(self.target)
386
387 def overwrite(self):
388 self.target = self.extractor.basename()
389 return self.do_extract(self.target)
390 421
391 422
392 class EmptyHandler(object): 423 class EmptyHandler(object):
424 def can_handle(contents, options):
425 return contents == EMPTY
426 can_handle = staticmethod(can_handle)
427
393 def __init__(self, extractor, contents, options): pass 428 def __init__(self, extractor, contents, options): pass
394 def extract(self): pass 429 def extract(self): pass
395 def cleanup(self): pass 430 def cleanup(self): pass
431
432
433 class BombHandler(BaseHandler):
434 def can_handle(contents, options):
435 return True
436 can_handle = staticmethod(can_handle)
437
438 def __init__(self, extractor, contents, options):
439 BaseHandler.__init__(self, extractor, contents, options)
440 checker = self.extractor.name_checker(self.extractor.basename())
441 self.target = checker.check()
442
443 cleanup = BaseHandler.cleanup_directory
444
445
446 ## class BombHandler(BaseHandler):
447 ## def safe_extract(self):
448 ## return self.do_extract(self.target)
449
450 ## def overwrite(self):
451 ## self.target = self.extractor.basename()
452 ## return self.do_extract(self.target)
396 453
397 454
398 extractor_map = {'application/x-tar': TarExtractor, 455 extractor_map = {'application/x-tar': TarExtractor,
399 'application/zip': ZipExtractor, 456 'application/zip': ZipExtractor,
400 'application/x-msdos-program': ZipExtractor, 457 'application/x-msdos-program': ZipExtractor,
401 'application/x-debian-package': DebExtractor, 458 'application/x-debian-package': DebExtractor,
402 'application/x-redhat-package-manager': RPMExtractor, 459 'application/x-redhat-package-manager': RPMExtractor,
403 'application/x-rpm': RPMExtractor, 460 'application/x-rpm': RPMExtractor,
404 'application/x-cpio': CpioExtractor} 461 'application/x-cpio': CpioExtractor}
405 462
406 handler_map = {EMPTY: EmptyHandler, 463 handlers = [FlatHandler, OverwriteHandler, MatchHandler, EmptyHandler,
407 MATCHING_DIRECTORY: MatchHandler, 464 BombHandler]
408 DECOMPRESSED: BombHandler}
409 465
410 class ExtractorApplication(object): 466 class ExtractorApplication(object):
411 def __init__(self, arguments): 467 def __init__(self, arguments):
412 self.parse_options(arguments) 468 self.parse_options(arguments)
413 self.setup_logger() 469 self.setup_logger()
457 try: 513 try:
458 extractor = extractor_map[mimetype] 514 extractor = extractor_map[mimetype]
459 except KeyError: 515 except KeyError:
460 if encoding: 516 if encoding:
461 extractor = CompressionExtractor 517 extractor = CompressionExtractor
518 contents = COMPRESSED
462 else: 519 else:
463 return "not a known archive type" 520 return "not a known archive type"
464 try: 521 try:
465 self.current_extractor = extractor(self.current_filename, mimetype, 522 self.current_extractor = extractor(self.current_filename, mimetype,
466 encoding) 523 encoding)
467 content = self.current_extractor.check_contents() 524 content = self.current_extractor.check_contents()
468 handler = handler_map.get(content, BombHandler) 525 for handler in handlers:
469 self.current_handler = handler(self.current_extractor, content, 526 if handler.can_handle(content, self.options):
470 self.options) 527 self.current_handler = handler(self.current_extractor,
528 content, self.options)
529 break
471 except ExtractorError, error: 530 except ExtractorError, error:
472 return str(error) 531 return str(error)
473 532
474 def recurse(self): 533 def recurse(self):
475 if not self.options.recursive: 534 if not self.options.recursive:

mercurial