Discrepância estranha de tamanhos de arquivo de ls

3

Estou usando ls -sh para verificar o tamanho dos arquivos desde 1997, mas hoje aconteceu algo estranho:

ninja@vm:foo$ ls -sh
total 98M
1,0M app   
64M app_fake_signed.sbp  
800K loader  
804K loader_fake_signed.sbp  
1,0M web   
32M web_fake_signed.sbp

Os arquivos app e web não deveriam ser muito menores do que seus correspondentes assinados, e passei várias horas depurando o programa de assinatura. Depois de encontrar nada, por acaso eu olhei para os arquivos em um compartilhamento de Samba, para encontrá-los muito semelhantes em tamanho. Eu verifiquei novamente:

ninja@vm:foo$ ls -lh
total 98M
-rw-rw-r-- 1 ninja ninja  63M lut  4 14:13 app
-rw-rw-r-- 1 ninja ninja  64M lut  4 14:13 app_fake_signed.sbp
-rw-rw-r-- 1 ninja ninja 800K lut  4 14:13 loader
-rw-rw-r-- 1 ninja ninja 801K lut  4 14:13 loader_fake_signed.sbp
-rw-rw-r-- 1 ninja ninja  31M lut  4 14:13 web
-rw-rw-r-- 1 ninja ninja  32M lut  4 14:14 web_fake_signed.sbp

Estou sem palavras? Por que ls -s mostra o app e web com 1 MB, enquanto na verdade são 63 e 32 MB, respectivamente?

Este foi o Xubuntu 14.04 em execução no VirtualBox no Windows, se faz alguma diferença.

Editar: Os arquivos app , web e loader são todas criadas por um script bash (não de meu projeto) que corre dd if=/dev/urandom of=app bs=$BLOCK count=1 seek=... em um loop. O programa de assinatura, escrito em C, leva esses arquivos e escreve suas versões assinadas para o disco, antecedendo e anexando uma assinatura binário para cada um.

    
por neuviemeporte 04.02.2016 / 20:38

2 respostas

6

Você está usando a opção -s para ls .

O tamanho de um arquivo e a quantidade de espaço em disco ocupado podem ser diferentes. Considere, por exemplo, se você abrir um novo arquivo, procurar 1G nele e escrever algo, o sistema operacional não alocar 1G (mais o espaço para algo) no disco, ele aloca apenas o mesmo para algo - isso é chamado de " arquivo esparso ".

Eu escrevi um pequeno programa em C para criar esse arquivo:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(void)
{
    int fd = open("/tmp/foo.dat", O_CREAT | O_WRONLY, 0600);

    if (fd > 0) {
        const off_t GIG = 1024 * 1024 * 1024;

        // Seek 1G into the file
        lseek(fd, GIG, SEEK_SET);

        // Write something
        write(fd, "hello", sizeof "hello");

        close(fd);
    }

    return 0;
}

Executando esse programa eu recebo:

$ ls -lh /tmp/foo.dat
-rw------- 1 user group 1.1G Feb  4 15:25 /tmp/foo.dat

Mas usando -s , obtenho:

$ ls -sh /tmp/foo.dat
4.0K /tmp/foo.dat

Portanto, um bloco de 4K foi alocado no disco para armazenar "hello" (e 4K é a menor unidade de alocação para o meu sistema de arquivos).

No seu caso, parece que app e web são arquivos esparsos.

    
por 04.02.2016 / 21:34
1

ls -s lista a quantidade de espaço de armazenamento usado pelo conteúdo do arquivo (excluindo o espaço usado para metadados). Isso pode diferir do tamanho do arquivo de duas maneiras:

  • Na maioria dos casos, o tamanho do arquivo é arredondado para um número inteiro de blocos. O tamanho de um bloco é tipicamente de 512B a 4kB, mas depende do sistema de arquivos (e alguns sistemas de arquivos não possuem este conceito).
  • Se o arquivo estiver codificado de alguma forma, por exemplo se estiver compactado, o tamanho do arquivo poderá ser menor (ou mais).

Sistemas de arquivos Unix suportam uma forma bruta de compactação chamada arquivos esparsos : se um bloco em um arquivo consistir inteiramente de bytes nulos , não precisa ser armazenado de forma alguma; o sistema de arquivos coloca um marcador especial em vez de um número de bloco na lista de blocos que armazenam o conteúdo do arquivo. Esse método de compactação não é sistemático: se um programa gravar vários bytes nulos, eles serão armazenados. No entanto, o Unix também permite que um programa grave após o final de um arquivo. Nesse caso, o arquivo é expandido com bytes nulos, mas se esses bytes formam um bloco inteiro ou mais, esses blocos nulos inteiros não são armazenados.

Quando você escreve dd seek=… , o programa dd procura a posição dada antes de começar a escrever. No seu caso, tomando app como exemplo, a posição parece ter sido de cerca de 62 MB após o final do arquivo, então existem cerca de 62 MB de bytes nulos que são armazenados implicitamente, em blocos inexistentes. Esse detalhe de armazenamento não é exposto a aplicativos (a menos que eles usem interfaces não portáteis para descobrir, o que poucos fazem), então quando o programa de assinatura lê sua entrada, tudo o que sabe é que existem cerca de 63MB de dados e escreve 63MB, dos quais cerca de 62MB são bytes nulos, para o seu arquivo de saída.

Se você realmente precisar do espaço em disco, poderá torna o arquivo esparso após o fato . Isso raramente é feito porque a maioria dos arquivos não tem grandes blocos de zeros, então executar uma ferramenta para encontrá-los seria uma grande perda de tempo.

    
por 06.02.2016 / 01:21

Tags