diff --git a/archive.py b/archive.py index eaa6448..f0917de 100644 --- a/archive.py +++ b/archive.py @@ -76,7 +76,7 @@ class ArchiveSender: class TarSender(ArchiveSender): - def response(self): + def generator(self): def generate(): for name, file in self.files.items(): yield tar_header_chunk(name, file) @@ -96,9 +96,11 @@ class TarSender(ArchiveSender): # Because tar use records of 512 bytes, we need to pad the # file with zeroes to fill the last chunk yield b'\x00' * (512 - bytes_sent % 512) + return generate() + def response(self): return Response( - generate(), + self.generator(), mimetype='application/x-tar', headers={'Content-Disposition': 'attachment; filename="archive.tar"'} ) @@ -131,9 +133,9 @@ def zip_local_file_header(filename: str, filepath: str) -> bytes: # Field 4: compression mode (buffer[8:10]), leave at 0 (uncompressed) # Field 5: file last modification time (buffer[10:14]) - mtime = datetime.fromtimestramp(stat.st_mtime) - buffer[10:12] = (mtime.second // 2) | (mtime.minute << 5) | (mtime.hour << 11) - buffer[12:14] = mtime.day | (mtime.month << 5) | ((mtime.year - 1980) << 9) + mtime = datetime.fromtimestamp(stat.st_mtime) + buffer[10:12] = ((mtime.second // 2) | (mtime.minute << 5) | (mtime.hour << 11)).to_bytes(2, byteorder='little') + buffer[12:14] = (mtime.day | (mtime.month << 5) | ((mtime.year - 1980) << 9)).to_bytes(2, byteorder='little') # Field 6: crc-32 of uncompressed data (buffer[14:18]) buffer[14:18] = crc32(filepath).to_bytes(4, byteorder='little') @@ -161,7 +163,7 @@ def zip_central_directory_file_header(filename: str, filepath: str, offset: int) stat = os.stat(filepath) # Field 1: central directory file header signature (buffer[0:4]) - buffer[0:4] = b'\x02\x01\x4b\x50' + buffer[0:4] = b'\x50\x4b\x01\x02' # Field 2: version made by (buffer[4:6]) buffer[4:6] = b'\x0a' @@ -174,9 +176,9 @@ def zip_central_directory_file_header(filename: str, filepath: str, offset: int) # 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) + mtime = datetime.fromtimestamp(stat.st_mtime) + buffer[12:14] = ((mtime.second // 2) | (mtime.minute << 5) | (mtime.hour << 11)).to_bytes(2, byteorder='little') + buffer[14:16] = (mtime.day | (mtime.month << 5) | ((mtime.year - 1980) << 9)).to_bytes(2, byteorder='little') # Field 6: crc-32 of uncompressed data (buffer[16:20]) buffer[16:20] = crc32(filepath).to_bytes(4, byteorder='little') @@ -211,7 +213,7 @@ def zip_central_directory_file_header(filename: str, filepath: str, offset: int) def zip_end_of_central_directory(items_number: int, central_directory_size: int, central_directory_offset: int): buffer = bytearray(22) # Field 1: End of central directory signature = 0x06054b50 (buffer[0:4]) - buffer[0:4] = b'\x06\x05\x4b\x50' + buffer[0:4] = b'\x50\x4b\x05\x06' # Field 2: Number of this disk (buffer[4:6]) @@ -236,7 +238,7 @@ def zip_end_of_central_directory(items_number: int, central_directory_size: int, class ZipSender(ArchiveSender): - def response(self): + def generator(self): def generate(): local_offsets = dict() current_byte = 0 @@ -244,7 +246,7 @@ class ZipSender(ArchiveSender): for name, file in self.files.items(): local_offsets[name] = current_byte chunk = zip_local_file_header(name, file) - current_byte += chunk + current_byte += len(chunk) yield chunk @@ -269,8 +271,11 @@ class ZipSender(ArchiveSender): yield zip_end_of_central_directory(len(self.files.items()), central_directory_size, centra_directory_offset) + return generate() + + def response(self): return Response( - generate(), + self.generator(), mimetype='application/zip', headers={'Content-Disposition': 'attachment; filename="archive.zip"'} )