Criando um tarball a partir de pipes nomeados usando o tar ou o módulo tarfile do python

1

Eu não sabia que isso seria tão difícil. Eu só estou usando tar. Eu tenho dois pedaços de dados, um grande payload de dados pcap, o outro é alguns metadados adicionais na forma de um arquivo em pickles python. Meu objetivo é criar um arquivo .tar contendo os dois arquivos e compactar com o XZ.

Eu quero poder indexar o tarball, para que eu possa extrair o arquivo de metadados rapidamente do arquivo .tar.xz. Estou usando o PIXZ para compactação xz, que indexa automaticamente os arquivos tar. Como os dados pcap que estou compactando são muito grandes, não quero tocar no disco até que ele seja compactado. Eu estou fazendo várias outras mudanças nele com o tcprewrite, mas elas não são importantes.

Eu tenho todas as minhas ferramentas configuradas para usar pipes nomeados, é lindo e muito rápido. O infeliz problema é que o tar não funciona com pipes nomeados. Toda vez que tento compactar um pipe nomeado, ele simplesmente escreve / dev / fd / # numbers no tarball. E eu não posso simplesmente escrever os dados pcap em disco ou / dev / shm para tar, é fundamental que os dados pcap não atinjam o disco até que ele seja comprimido.

Eu estou escrevendo todo este utilitário em python, então eu tentei usar o módulo tarfile do python. A documentação afirma que ele funciona com o FIFO, mas quando eu uso o tarfile.add () eu me deparo com o mesmo problema. Eu tentei investigar alternativas como o zip (que tem uma opção -FI para trabalhar com pipes nomeados), mas eu preciso usar o tar para a nossa infraestrutura existente.

Eu tentei o gnutar e o bsdtar e nenhum deles funcionará com canos. Em última análise, não importa quais ferramentas eu uso, desde que o resultado final seja um arquivo .tar.xz que seja indexado e permita acesso rápido aos metadados.

    
por user287582 24.04.2018 / 01:33

1 resposta

3

Não fique deprimido com isso ... tenho certeza que você conseguirá resolver esse problema!

Eu acho que o que está te atrapalhando com o tar é que "suporta pipes nomeados" significa que ele pode reconhecer os pipes nomeados e armazená-los como pipes nomeados dentro do arquivo, para que você possa restaurar mais tarde -los como pipes nomeados novamente ... O que não é realmente o que você quer.

Além disso, o formato dos arquivos tar não é muito adequado para o que você está fazendo, já que a entrada que descreve um arquivo é armazenada antes de seu conteúdo e a entrada do arquivo deve conter o tamanho do arquivo, a menos que você saiba o tamanho exato do arquivo. conteúdo com antecedência, é difícil fazer isso ...

Existe esta solução (veja TarFileStdin), que usa um hack para resolver o problema. Ele insere um TarInfo com tamanho de arquivo zero, depois armazena o conteúdo do arquivo e, finalmente, busca voltar ao offset do TarInfo original e o substitui pelo tamanho correto ... É um pouco hacky, mas deve funcionar ... Mas continue a ler.

Você mencionou "Eu quero poder indexar o tarball, para que eu possa extrair o arquivo de metadados rapidamente do arquivo .tar.xz", para que pareça mais um arquivo ZIP! O formato ZIP armazena o conteúdo de todos os arquivos primeiro e, em seguida, armazena uma tabela de informações de arquivos e compensações no final do CEP. Nesse sentido, é indexado, como você mencionou. A listagem do conteúdo do ZIP pode ser feita rapidamente, pois é fácil para as ferramentas encontrarem a tabela de arquivos começando do final do arquivo.

Você pode usar o formato de compactação nativo do ZIP ou usar o modo "armazenar" do ZIP (descompactado) e, em seguida, adicionar um arquivo xyz.pcap.xz dentro dele. Adicionar um arquivo * .xz ao ZIP teria a conveniência de usar um compressor externo, como um xz paralelo.

Os objetos zipfile.ZipFile do Python 3 têm um open() method que permite que você adicione um arquivo apenas por nome e receba um objeto de arquivo para o qual você pode escrever o conteúdo.

Você pode usar essa API e shutil.copyfileobj() para adicionar seu pcap compactado de um canal nomeado ao arquivo ZIP:

import shutil
import zipfile

with zipfile.ZipFile('mydata.zip', 'w') as zf:
    with zf.open('xyz.pcap.xz', 'w') as outputf:
        with open('/path/to/namedpipe', 'r') as inputf:
            shutil.copyfileobj(inputf, outputf)
    zf.write('metadata.pickle')  # from local directory

Este snippet de código supõe que você esteja gravando os dados pcap já comprimidos em xz no pipe nomeado e que você tenha os metadados já serializados em um arquivo chamado 'metadata.pickle' no diretório atual. (Claro, você poderia usar o open() do ZipFile para serializar os metadados de pickles diretamente em uma entrada no arquivo ZIP também!)

Se você quiser usar a compactação nativa do zipfile, você pode definir uma compactação padrão para o ZipFile:

with zipfile.ZipFile('mydata.zip', 'w', zipfile.ZIP_LZMA) as zf:

(O padrão é ZIP_STORED, o que significa que não há compactação, que é provavelmente o que você deseja se você estiver enviando dados comprimidos xz).

Consulte a documentação do zipfile para obter mais detalhes. Novos Python's têm ainda mais recursos, por exemplo, com o Python 3.5 você pode realmente escrever o arquivo zip em um pipe para que você possa, por exemplo, enviá-lo diretamente para um host remoto através do SSH.

Espero que você ache isso útil! Se você realmente precisa de um tarball, tente esta resposta , mas eu realmente acho que a solução zipfile usando Python 3 é melhor abordagem para o caso de uso que você descreve! Então, se esse formato é uma possibilidade, eu realmente recomendo.

    
por 24.04.2018 / 08:11