Working
This commit is contained in:
parent
8b2f968c2d
commit
74ff05d9c9
71
archive.py
71
archive.py
|
|
@ -104,7 +104,7 @@ class TarSender(ArchiveSender):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def crc32(filename):
|
def crc32(filename) -> int:
|
||||||
with open(filename, 'rb') as fh:
|
with open(filename, 'rb') as fh:
|
||||||
hash = 0
|
hash = 0
|
||||||
while True:
|
while True:
|
||||||
|
|
@ -115,7 +115,7 @@ def crc32(filename):
|
||||||
return hash
|
return hash
|
||||||
|
|
||||||
|
|
||||||
def zip_local_file_header(filename: str, filepath: str, fileindex: int) -> bytes:
|
def zip_local_file_header(filename: str, filepath: str) -> bytes:
|
||||||
buffer_size = 30 + len(filename)
|
buffer_size = 30 + len(filename)
|
||||||
buffer = bytearray(buffer_size)
|
buffer = bytearray(buffer_size)
|
||||||
stat = os.stat(filepath)
|
stat = os.stat(filepath)
|
||||||
|
|
@ -145,7 +145,7 @@ def zip_local_file_header(filename: str, filepath: str, fileindex: int) -> bytes
|
||||||
buffer[22:26] = stat.st_size.to_bytes(4)
|
buffer[22:26] = stat.st_size.to_bytes(4)
|
||||||
|
|
||||||
# Field 9: filename length (buffer[26:28])
|
# Field 9: filename length (buffer[26:28])
|
||||||
buffer[26:29] = len(filename).to_bytes(4)
|
buffer[26:28] = len(filename).to_bytes(4)
|
||||||
|
|
||||||
# Field 10: extra field length (buffer[28:30])
|
# Field 10: extra field length (buffer[28:30])
|
||||||
|
|
||||||
|
|
@ -155,10 +155,73 @@ def zip_local_file_header(filename: str, filepath: str, fileindex: int) -> bytes
|
||||||
return buffer
|
return buffer
|
||||||
|
|
||||||
|
|
||||||
|
def zip_central_directory_file_header(filename: str, filepath: str) -> bytes:
|
||||||
|
buffer_size = 46 + len(filename)
|
||||||
|
buffer = bytearray(buffer_size)
|
||||||
|
stat = os.stat(filepath)
|
||||||
|
|
||||||
|
# Field 1: central directory file header signature (buffer[0:4])
|
||||||
|
buffer[0:4] = b'\x02\x01\x4b\x50'
|
||||||
|
|
||||||
|
# Field 2: version made by (buffer[4:6])
|
||||||
|
buffer[4:6] = b'\x0a'
|
||||||
|
|
||||||
|
# Field 3: version needed to extract (minimum) (buffer[6:8])
|
||||||
|
buffer[6:8] = b'\x0a'
|
||||||
|
|
||||||
|
# Field 3: general purpose bit flag (buffer[8:10]), leave at 0
|
||||||
|
|
||||||
|
# Field 4: compression mode (buffer[10:12]), leave at 0 (uncompressed)
|
||||||
|
|
||||||
|
# Field 5: file last modification time (buffer[12:16])
|
||||||
|
mtime = datetime.fromtimestramp(stat.st_mtime)
|
||||||
|
buffer[12:14] = (mtime.second // 2) | (mtime.minute << 5) | (mtime.hour << 11)
|
||||||
|
buffer[14:16] = mtime.day | (mtime.month << 5) | ((mtime.year - 1980) << 9)
|
||||||
|
|
||||||
|
# Field 6: crc-32 of uncompressed data (buffer[16:20])
|
||||||
|
buffer[16:20] = crc32(filepath).to_bytes(4)
|
||||||
|
|
||||||
|
# Field 7: compressed size (buffer[20:24])
|
||||||
|
buffer[20:24] = stat.st_size.to_bytes(4)
|
||||||
|
|
||||||
|
# Field 8: uncompressed size (buffer[24:28])
|
||||||
|
buffer[24:28] = stat.st_size.to_bytes(4)
|
||||||
|
|
||||||
|
# Field 9: filename length (buffer[28:30])
|
||||||
|
buffer[28:30] = len(filename).to_bytes(4)
|
||||||
|
|
||||||
|
# Field 10: extra field length (buffer[30:32])
|
||||||
|
|
||||||
|
# Field 11: file comment length (buffer[32:34])
|
||||||
|
|
||||||
|
# Field 12: disk number where file starts (buffer[34:36])
|
||||||
|
|
||||||
|
# Field 13: internal file attributes (buffer[36:38])
|
||||||
|
|
||||||
|
# Field 14: external file attributes (buffer[38:42])
|
||||||
|
|
||||||
|
# Field 15: relative offset of the local file header (buffer[42:46])
|
||||||
|
|
||||||
|
# Field 16: filename (buffer[46:46+len(filename)])
|
||||||
|
buffer[46:46+len(filename)] = filename.encode('ascii')
|
||||||
|
|
||||||
|
return buffer
|
||||||
|
|
||||||
|
|
||||||
class ZipSender(ArchiveSender):
|
class ZipSender(ArchiveSender):
|
||||||
def response(self):
|
def response(self):
|
||||||
def generate():
|
def generate():
|
||||||
yield 'oops'
|
for name, file in self.files.items():
|
||||||
|
yield zip_local_file_header(name, file)
|
||||||
|
|
||||||
|
with open(file, 'rb') as f:
|
||||||
|
while True:
|
||||||
|
bytes = f.read(CHUNK_SIZE)
|
||||||
|
|
||||||
|
if len(bytes) == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
yield bytes
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
generate(),
|
generate(),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue