Ir para o conteúdo
AZ Tools

Inspetor de arquivos gzip (.gz)

Um .gz não é um pacote de arquivos: é um fluxo. Um ou mais membros concatenados, cada um com seu cabeçalho de 10 bytes, seu próprio fluxo deflate e seu trailer de 8 bytes com um CRC32 e o ISIZE, o comprimento descompactado módulo 2^32. Esta página percorre todos eles e mostra o que cada campo realmente diz: a assinatura 1f 8b e o método de compressão, os cinco bits do FLG (FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT) e quais campos opcionais eles prometem, o MTIME convertido em data — o 0 significa que nunca foi definido, e é o que uma compilação reproduzível grava —, o XFL (2 para compressão máxima, 4 para o algoritmo mais rápido) e o byte de sistema operacional pelo nome, além dos subcampos FEXTRA separados em identificadores de dois bytes e conteúdo, o nome original, o comentário e o CRC16 do cabeçalho. Depois ela verifica. Cada membro é descompactado pelo próprio navegador e o CRC32 é recalculado sobre o resultado, de modo que o trailer é conferido em vez de apenas repetido: um arquivo cujo CRC32 não bate está corrompido de um jeito que, de outra forma, só aparece no meio de uma restauração, quando o original já não existe mais. Do mesmo processo sai o tamanho real descompactado, e é por isso que o total aqui pode divergir do gzip -l. O gzip -l lê o ISIZE do último membro e o apresenta como o tamanho do arquivo inteiro; então, em qualquer coisa feita com cat a.gz b.gz, ou por um compressor paralelo como o pigz em blocos independentes, a resposta fica menor exatamente pelo que os membros anteriores guardam. O ISIZE tem 32 bits, portanto um membro maior que 4 GB grava o comprimento módulo 2^32 e nenhum leitor recupera o tamanho verdadeiro só com esse campo. Lixo depois do último trailer, um membro que termina no meio do fluxo e um arquivo que nem é gzip são identificados pelo nome, em vez de interpretados pela metade. E o nome guardado dentro do membro — aquele para o qual o gunzip -N restaura, que pode ser um caminho ou algo bem diferente do arquivo que você tem — aparece como está gravado: a norma diz ISO-8859-1, mas na prática ele carrega os bytes da codificação local, então as duas leituras aparecem sempre que divergem.

Como usar

  1. Solte um .gz, um .tgz ou qualquer fluxo gzip sobre a caixa. Tudo é analisado e descompactado na página; nada é enviado.
  2. Comece pelo resumo: quantos membros o arquivo realmente tem, o total real descompactado e se todos os CRC32 bateram.
  3. Abra um membro para ver o cabeçalho: os cinco bits de flag, o MTIME, o XFL, o byte de sistema operacional, o nome guardado, o comentário e os subcampos FEXTRA.
  4. Compare os dois pares do trailer: o CRC32 gravado contra o CRC32 real dos dados, e o ISIZE contra o tamanho real descompactado. Os dois conferindo é exatamente o que o gzip -t checa.
  5. Em um arquivo com vários membros, observe a diferença entre o número do gzip -l e o total real antes de citar um tamanho vindo do gzip -l.

Perguntas frequentes

Por que o gzip -l mostra um tamanho diferente do desta página?
Porque o gzip -l não descompacta nada. Ele pula para os últimos quatro bytes do arquivo, lê aquele ISIZE e o imprime como tamanho descompactado. Num arquivo de um único membro isso está certo. Já num arquivo feito concatenando membros — cat a.gz b.gz, um log rotacionado anexado a um pacote, o pigz ou o bgzip gravando blocos independentes — esses quatro bytes descrevem apenas o último membro, então o gzip -l deixa de fora tudo o que veio antes. Esta página, em vez disso, descompacta cada membro e soma o que de fato saiu, e por isso pode mostrar um total bem maior. Isso também significa que o gzip -l é instantâneo e esta página não é: o preço da resposta honesta é descompactar o arquivo.
O que significa um MTIME igual a 0 e que data esse campo guarda?
O MTIME é a data de modificação do arquivo original, em segundos desde a época Unix, em UTC — não é o momento em que a compressão rodou, nem a data do .gz no disco. Zero significa que não havia data disponível ou que ela não foi gravada: o gzip -n escreve 0 de propósito, e compilações reproduzíveis fazem o mesmo, porque um carimbo de tempo é o motivo clássico de duas compilações do mesmo conteúdo gerarem bytes diferentes. Comprimir a partir de um pipe também dá 0, já que não há arquivo de onde tirar a data. O campo tem quatro bytes, então uma data depois de 2106 não pode ser representada, e as implementações discordam sobre se um valor acima de 2^31 é um futuro distante ou um número negativo.
O nome original aparece todo estranho. O arquivo está corrompido?
Não: quem está errado é o formato. A RFC 1952 diz que o FNAME é uma cadeia ISO-8859-1 (Latin-1), mas o gzip no Linux e no macOS simplesmente grava os bytes do nome como a configuração regional os produziu, o que hoje quase sempre é UTF-8. Por isso qualquer nome fora do ASCII só viaja intacto entre sistemas com a mesma codificação: um nome escrito em UTF-8 e lido como Latin-1 volta com os acentos duplicados de sempre. Esta página mostra o campo decodificado como a norma manda e, quando os mesmos bytes também formam UTF-8 válido e resultam em outra leitura, exibe essa leitura ao lado — assim você vê os dois nomes candidatos e decide qual quem gravou quis dizer.
O que exatamente um CRC32 divergente prova, e o que um CRC32 correto não prova?
Divergir significa que os bytes que saíram do fluxo deflate não são os que entraram quando o arquivo foi escrito: um bit invertido no armazenamento, uma transferência cortada e remendada, uma edição nos dados compactados. É a mesma falha que o gunzip relata como "invalid compressed data — crc error", só que aqui você a vê sem gravar a saída em lugar nenhum. Já um CRC correto só prova que os dados são os que o compressor viu. O CRC32 é um código detector de erros de 32 bits, não uma assinatura: pega dano acidental com probabilidade altíssima, mas quem consegue alterar os dados também consegue recalcular o CRC. Para autenticidade é preciso um hash ou uma assinatura sobre o arquivo, não o trailer dele.
Dá para ver os arquivos dentro de um .tar.gz?
Não, e nada que leia apenas gzip consegue. O gzip compacta um único fluxo de bytes e não sabe o que há dentro dele: não existe índice, nem entrada por arquivo, nem como extrair um só arquivo sem descompactar tudo o que vem antes. Um .tar.gz é um pacote tar, que tem essa estrutura, passado inteiro pelo gzip. O que esta página pode contar é o que a camada gzip registra: quantos membros existem, o nome original em cada cabeçalho (muitas vezes archive.tar), o carimbo de tempo e quantos dados saem. Para listar as entradas você precisa de um leitor de tar operando sobre o fluxo já descompactado.
Para que servem os subcampos FEXTRA?
O FEXTRA é um ponto de extensão: uma sequência de subcampos precedida pelo seu tamanho, cada subcampo com um identificador de dois bytes, o próprio tamanho e o conteúdo, que um leitor deve pular quando não reconhece o identificador. Os usos reais quase sempre têm a ver com tornar um fluxo gzip navegável por posição. O BGZF, formato por trás do bgzip e de todo arquivo BAM em genômica, grava um subcampo "BC" com o tamanho de cada bloco para permitir saltar direto a uma fronteira de bloco; o dictzip guarda, pelo mesmo motivo, uma tabela de tamanhos sob "RA". Os dois continuam sendo arquivos gzip comuns que o gunzip lê normalmente, e é justamente esse o ponto do mecanismo. Um subcampo incomum costuma denunciar que o arquivo saiu de uma ferramenta dessas.

Ferramentas relacionadas