1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """extensions to zipfile standard module that will hopefully get included in future..."""
23
24 from zipfile import ZipFile, struct, structCentralDir, stringCentralDir, structEndArchive, stringEndArchive
25
27 """a ZipFile that can handle replacing objects"""
29 """Delete the file from the archive. If it appears multiple
30 times only the first instance will be deleted."""
31 for i in range (0, len(self.filelist)):
32 if self.filelist[i].filename == name:
33 if self.debug:
34 print "Removing", name
35 deleted_offset = self.filelist[i].header_offset
36
37 if hasattr(self.filelist[i], "file_offset"):
38 deleted_size = (self.filelist[i].file_offset - self.filelist[i].header_offset) + self.filelist[i].compress_size
39 else:
40 deleted_size = (len(self.filelist[i].FileHeader()) - self.filelist[i].header_offset) + self.filelist[i].compress_size
41 zinfo_size = struct.calcsize(structCentralDir) + len(self.filelist[i].filename) + len(self.filelist[i].extra)
42
43 current_offset = self.fp.tell()
44
45 self.fp.seek(0, 2)
46 archive_size = self.fp.tell()
47 self.fp.seek(deleted_offset + deleted_size)
48 buf = self.fp.read()
49 self.fp.seek(deleted_offset)
50 self.fp.write(buf)
51 self.fp.truncate(archive_size - deleted_size - zinfo_size)
52
53 self.fp.seek(0, 2)
54 if self.debug >= 2:
55 if self.fp.tell() != archive_size - deleted_size - zinfo_size:
56 print "truncation failed: %r != %r" % (self.fp.tell(), archive_size - deleted_size - zinfo_size)
57 if current_offset > deleted_offset + deleted_size:
58 current_offset -= deleted_size
59 elif current_offset > deleted_offset:
60 current_offset = deleted_offset
61 self.fp.seek(current_offset, 0)
62
63 del self.filelist[i]
64
65 for j in range (i, len(self.filelist)):
66 if self.filelist[j].header_offset > deleted_offset:
67 self.filelist[j].header_offset -= deleted_size
68
69 if hasattr(self.filelist[i], "file_offset"):
70 if self.filelist[j].file_offset > deleted_offset:
71 self.filelist[j].file_offset -= deleted_size
72 del self.NameToInfo[name]
73 return
74 if self.debug:
75 print name, "not in archive"
76
78 """Close the file, and for mode "w" and "a" write the ending
79 records."""
80 if self.fp is None:
81 return
82 self.writeendrec()
83 if not self._filePassed:
84 self.fp.close()
85 self.fp = None
86
88 """Write the ending records (without neccessarily closing the file)"""
89 if self.mode in ("w", "a"):
90 count = 0
91 current_offset = self.fp.tell()
92 pos1 = self.fp.tell()
93 for zinfo in self.filelist:
94 count = count + 1
95 dt = zinfo.date_time
96 dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
97 dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2)
98 centdir = struct.pack(structCentralDir,
99 stringCentralDir, zinfo.create_version,
100 zinfo.create_system, zinfo.extract_version, zinfo.reserved,
101 zinfo.flag_bits, zinfo.compress_type, dostime, dosdate,
102 zinfo.CRC, zinfo.compress_size, zinfo.file_size,
103 len(zinfo.filename), len(zinfo.extra), len(zinfo.comment),
104 0, zinfo.internal_attr, zinfo.external_attr,
105 zinfo.header_offset)
106 self.fp.write(centdir)
107 self.fp.write(zinfo.filename)
108 self.fp.write(zinfo.extra)
109 self.fp.write(zinfo.comment)
110 pos2 = self.fp.tell()
111
112 endrec = struct.pack(structEndArchive, stringEndArchive,
113 0, 0, count, count, pos2 - pos1, pos1, 0)
114 self.fp.write(endrec)
115 self.fp.seek(pos1)
116