unzipper.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. """Try and uncompress a source file to a dest dir"""
  2. import zipfile
  3. import os.path
  4. import subprocess
  5. USE_UNRAR = False
  6. def unar(source, dest_dir):
  7. """Split input into zip or rar and parse accordingly.
  8. Return source if it's not a zip or rar"""
  9. print("uncompressing %s to %s" % (source, dest_dir))
  10. if source.lower().endswith("zip"):
  11. return unzip(source, dest_dir)
  12. if source.lower().endswith("rar"):
  13. return unrar(source, dest_dir)
  14. print("NOT RAR? NOT ZIP? I'm panicking.")
  15. print("I got %s" % source)
  16. return [source]
  17. def unzip(source_filename, dest_dir):
  18. """Unzip source_filename to dest_dir"""
  19. print("Unzipping %s to %s" % (source_filename, dest_dir))
  20. out = []
  21. with zipfile.ZipFile(source_filename) as zfile:
  22. for member in zfile.infolist():
  23. # Path traversal defense copied from
  24. # http://hg.python.org/cpython/file/tip/Lib/http/server.py#l789
  25. words = member.filename.split('/')
  26. path = dest_dir
  27. for word in words[:-1]:
  28. _, word = os.path.splitdrive(word)
  29. _, word = os.path.split(word)
  30. if word in (os.curdir, os.pardir, ''):
  31. continue
  32. path = os.path.join(path, word)
  33. target = os.path.join(path, member.filename.split('/')[-1])
  34. out.append(target)
  35. print("Extracting %s" % target)
  36. zfile.extract(member, path)
  37. print("Extracted %s" % target)
  38. return out
  39. def unrar(source, dest_dir):
  40. """Unzip source to dest_dir. Might use unar or unrar
  41. print("Unraring %s to %s" % (source, dest_dir))
  42. based on the flag USE_UNRAR"""
  43. out = []
  44. list_files = []
  45. extract_files = []
  46. if USE_UNRAR:
  47. list_files = ["unrar", "lb", source]
  48. extract_files = ["unrar", "x", "-o+", source, dest_dir]
  49. else:
  50. list_files = ["lsar", source]
  51. extract_files = ["unar", "-f", "-o", dest_dir, source]
  52. with subprocess.Popen(list_files, stdout=subprocess.PIPE) as proc:
  53. out = proc.stdout.read().decode('utf-8').split("\n")
  54. if out[0].endswith(": RAR"):
  55. del out[0] # header
  56. if len(out[-1]) == 0:
  57. del out[-1]
  58. subprocess.run(extract_files, stdout=subprocess.DEVNULL)
  59. return [os.path.join(dest_dir, file) for file in out]