unzipper.py 2.1 KB

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