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:
|
||||
hash = 0
|
||||
while True:
|
||||
|
|
@ -115,7 +115,7 @@ def crc32(filename):
|
|||
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 = bytearray(buffer_size)
|
||||
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)
|
||||
|
||||
# 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])
|
||||
|
||||
|
|
@ -155,10 +155,73 @@ def zip_local_file_header(filename: str, filepath: str, fileindex: int) -> bytes
|
|||
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):
|
||||
def response(self):
|
||||
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(
|
||||
generate(),
|
||||
|
|
|
|||
Loading…
Reference in New Issue