]> git.phdru.name Git - dotfiles.git/blob - bin/unzip.py
Feat(zip): Save and restore symlinks
[dotfiles.git] / bin / unzip.py
1 #! /usr/bin/env python3
2 """Unzip with encoded filenames
3
4    Written by Oleg Broytman. Copyright (C) 2009-2024 PhiloSoft Design.
5 """
6
7 import sys, os, time
8 from getopt import getopt, GetoptError
9 from shutil import copyfileobj
10 from zipfile import ZipFile
11 from m_lib.defenc import default_encoding
12
13 def usage():
14     sys.exit('Usage: %s file.zip' % sys.argv[0])
15
16 try:
17     options, arguments = getopt(sys.argv[1:], '')
18 except GetoptError:
19     usage()
20
21 if len(arguments) != 1:
22     usage()
23
24 zf = ZipFile(arguments[0], 'r')
25 out = '.'
26
27 for zinfo in zf.infolist():
28     path = zinfo.filename
29     if isinstance(path, bytes):
30         recoded_path = path.decode('cp866').encode(default_encoding)
31     else:
32         recoded_path = path
33     print(recoded_path)
34
35     if path.startswith('./'):
36         recoded_path = recoded_path[2:]
37     tgt = os.path.join(out, recoded_path)
38
39     tgtdir = os.path.dirname(tgt)
40     if not os.path.exists(tgtdir):
41         os.makedirs(tgtdir)
42
43     if not tgt.endswith('/'):
44         infile = zf.open(zinfo.filename)
45         if zinfo.external_attr == 0xA1ED0000:
46             os.symlink(infile.read(), tgt)
47         else:  # regular file
48             fp = open(tgt, 'wb')
49             copyfileobj(infile, fp)
50             fp.close()
51         infile.close()
52     if zinfo.external_attr != 0xA1ED0000:
53         # set timestamp for directories and files but not symlinks
54         dt = time.mktime(zinfo.date_time + (0, 0, -1))
55         os.utime(tgt, (dt, dt))
56 zf.close()