nenuscanner/tar.py

59 lines
1.6 KiB
Python

from flask import Response
import io
import os
import tarfile
# 4MiB chuns
CHUNK_SIZE = 4_194_304
def header_chunk(filename: str, filepath: str) -> bytes:
bytes = io.BytesIO()
stat = os.stat(filepath)
# Create dummy tar to extract tar header for file
with tarfile.open(fileobj=bytes, mode='w') as buffer:
tar_info = tarfile.TarInfo(filepath)
tar_info.name = filename
tar_info.size = stat.st_size
buffer.addfile(tar_info)
# TODO if we were able to build this chunk without tarfile, it would avoid
# whole file copy in memory
return bytes.getvalue()[:512]
class TarSender:
def __init__(self):
self.files: dict[str, str] = {}
def add_file(self, filename: str, filepath: str):
self.files[filename] = filepath
def response(self):
def generate():
for name, file in self.files.items():
yield header_chunk(name, file)
bytes_sent = 0
with open(file, 'rb') as f:
while True:
bytes = f.read(CHUNK_SIZE)
if len(bytes) == 0:
break
bytes_sent += len(bytes)
yield bytes
# 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 Response(
generate(),
mimetype='application/x-tar',
headers={'Content-Disposition': 'attachment; filename="archive.tar"'}
)