4
4
XXX references to utf-8 need further investigation.
6
6
import struct, os, time, sys, shutil
7
import binascii, io, stat
10
10
import zlib # We may need its compression method
29
29
error = BadZipfile # The exception raised by this module
31
ZIP64_LIMIT= (1 << 31) - 1
31
ZIP64_LIMIT = (1 << 31) - 1
32
32
ZIP_FILECOUNT_LIMIT = 1 << 16
33
33
ZIP_MAX_COMMENT = (1 << 16) - 1
198
198
# Append a blank comment and record start offset
199
199
endrec.append(b"")
200
200
endrec.append(filesize - sizeEndCentDir)
201
if endrec[_ECD_OFFSET] == 0xffffffff:
202
# the value for the "offset of the start of the central directory"
203
# indicates that there is a "Zip64 end of central directory"
204
# structure present, so go look for it
205
return _EndRecData64(fpin, -sizeEndCentDir, endrec)
202
# Try to read the "Zip64 end of central directory" structure
203
return _EndRecData64(fpin, -sizeEndCentDir, endrec)
209
205
# Either this is not a ZIP file, or it is a ZIP file with an archive
210
206
# comment. Search the end of the file for the "end of central directory"
225
221
# Append the archive comment and start offset
226
222
endrec.append(comment)
227
223
endrec.append(maxCommentStart + start)
228
if endrec[_ECD_OFFSET] == 0xffffffff:
229
# There is apparently a "Zip64 end of central directory"
230
# structure present, so go look for it
231
return _EndRecData64(fpin, start - filesize, endrec)
225
# Try to read the "Zip64 end of central directory" structure
226
return _EndRecData64(fpin, maxCommentStart + start - filesize,
234
229
# Unable to find a valid end of central directory structure
953
948
# build the destination pathname, replacing
954
949
# forward slashes to platform specific separators.
955
if targetpath[-1:] == "/":
950
if targetpath[-1:] in (os.path.sep, os.path.altsep):
956
951
targetpath = targetpath[:-1]
958
953
# don't include leading "/" from file name if present
959
if os.path.isabs(member.filename):
954
if member.filename[0] == '/':
960
955
targetpath = os.path.join(targetpath, member.filename[1:])
962
957
targetpath = os.path.join(targetpath, member.filename)
968
963
if upperdirs and not os.path.exists(upperdirs):
969
964
os.makedirs(upperdirs)
966
if member.filename[-1] == '/':
971
970
source = self.open(member, pwd=pwd)
972
971
target = open(targetpath, "wb")
973
972
shutil.copyfileobj(source, target)
1015
1015
arcname = os.path.normpath(os.path.splitdrive(arcname)[1])
1016
1016
while arcname[0] in (os.sep, os.altsep):
1017
1017
arcname = arcname[1:]
1018
1020
zinfo = ZipInfo(arcname, date_time)
1019
1021
zinfo.external_attr = (st[0] & 0xFFFF) << 16 # Unix attributes
1020
1022
if compress_type is None:
1029
1031
self._writecheck(zinfo)
1030
1032
self._didModify = True
1036
zinfo.compress_size = 0
1038
self.filelist.append(zinfo)
1039
self.NameToInfo[zinfo.filename] = zinfo
1040
self.fp.write(zinfo.FileHeader())
1031
1043
fp = io.open(filename, "rb")
1032
1044
# Must overwrite CRC and sizes with correct data later
1033
1045
zinfo.CRC = CRC = 0
1187
1199
pos2 = self.fp.tell()
1188
1200
# Write end-of-zip-archive record
1201
centDirCount = count
1202
centDirSize = pos2 - pos1
1189
1203
centDirOffset = pos1
1190
if pos1 > ZIP64_LIMIT:
1204
if (centDirCount >= ZIP_FILECOUNT_LIMIT or
1205
centDirOffset > ZIP64_LIMIT or
1206
centDirSize > ZIP64_LIMIT):
1191
1207
# Need to write the ZIP64 end-of-archive records
1192
1208
zip64endrec = struct.pack(
1193
1209
structEndArchive64, stringEndArchive64,
1194
44, 45, 45, 0, 0, count, count, pos2 - pos1, pos1)
1210
44, 45, 45, 0, 0, centDirCount, centDirCount,
1211
centDirSize, centDirOffset)
1195
1212
self.fp.write(zip64endrec)
1197
1214
zip64locrec = struct.pack(
1198
1215
structEndArchive64Locator,
1199
1216
stringEndArchive64Locator, 0, pos2, 1)
1200
1217
self.fp.write(zip64locrec)
1201
centDirOffset = 0xFFFFFFFF
1218
centDirCount = min(centDirCount, 0xFFFF)
1219
centDirSize = min(centDirSize, 0xFFFFFFFF)
1220
centDirOffset = min(centDirOffset, 0xFFFFFFFF)
1203
1222
# check for valid comment length
1204
1223
if len(self.comment) >= ZIP_MAX_COMMENT:
1208
1227
self.comment = self.comment[:ZIP_MAX_COMMENT]
1210
1229
endrec = struct.pack(structEndArchive, stringEndArchive,
1211
0, 0, count % ZIP_FILECOUNT_LIMIT,
1212
count % ZIP_FILECOUNT_LIMIT, pos2 - pos1,
1213
centDirOffset, len(self.comment))
1230
0, 0, centDirCount, centDirCount,
1231
centDirSize, centDirOffset, len(self.comment))
1214
1232
self.fp.write(endrec)
1215
1233
self.fp.write(self.comment)
1216
1234
self.fp.flush()