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