Gzip grande quantidade de arquivos com links simbólicos

4

Eu tenho uma pasta contendo uma grande quantidade de arquivos com links simbólicos. Esses arquivos são cada um da ordem de 10 a 11 GB (os arquivos fastq são específicos). Eles vêm de uma variedade de pastas de origem, mas eu garanti que há apenas um nível de links simbólicos.

Estou tentando compactuá-los simplesmente fazendo:

gzip *.fastq

Isso resulta em um monte de

too many levels of symbolic links

E assim falha.

No entanto, quando faço:

for i in 'ls | egrep *.fastq$'; do gzip -c $i > $i.gz; done;

funciona. Minha pergunta é simples. Qual é a diferença entre aqueles? AFAIK, a única diferença é que a segunda abordagem inicia um novo processo de gzip para cada arquivo, enquanto a primeira deve fazer tudo em um processo. O gzip só pode manipular um arquivo com link simbólico de cada vez? Fazer o mesmo em uma pasta de teste com arquivos normais funciona nos dois sentidos.

    
por Gx1sptDTDa 16.06.2014 / 17:51

2 respostas

4

Uma verificação rápida da fonte gzip (especificamente, o gzip 1.6 como incluído no Ubuntu 14.04), mostra que o comportamento observado vem da função open_and_stat , começando na linha 1037 do gzip.c:

static int
open_and_stat (char *name, int flags, mode_t mode, struct stat *st)
{
  int fd;

  /* Refuse to follow symbolic links unless -c or -f.  */
  if (!to_stdout && !force)
    {
      if (HAVE_WORKING_O_NOFOLLOW)
        flags |= O_NOFOLLOW;
      else
        {
#if HAVE_LSTAT || defined lstat
          if (lstat (name, st) != 0)
            return -1;
          else if (S_ISLNK (st->st_mode))
            {
              errno = ELOOP;
              return -1;
            }
#endif
        }
    }

  fd = OPEN (name, flags, mode);
  if (0 <= fd && fstat (fd, st) != 0)
    {
      int e = errno;
      close (fd);
      errno = e;
      return -1;
    }
  return fd;
}

Note que a linha de comentário afirma que o gzip não seguirá links simbólicos a menos que seja chamado com os sinalizadores -c ou -f, e dentro do #if ... #endif a variável errno está configurada para ELOOP (muitos links simbólicos encontrado) se o arquivo a ser compactado é realmente um link simbólico.

Agora, na página man gzip (1), os sinalizadores -c e -f são:

   -c --stdout --to-stdout
         Write  output  on  standard output; keep original files unchanged.  If there are
         several input files, the output consists of a  sequence  of  independently  com‐
         pressed  members.  To  obtain  better  compression,  concatenate all input files
         before compressing them.


  -f --force
         Force compression or decompression even if the file has multiple  links  or  the
         corresponding  file  already  exists,  or if the compressed data is read from or
         written to a terminal. If the input data is not in a format recognized by  gzip,
         and  if the option --stdout is also given, copy the input data without change to
         the standard output: let zcat behave as cat.  If -f is not given, and  when  not
         running  in  the  background,  gzip  prompts  to verify whether an existing file
         should be overwritten.

Colocando todos juntos e voltando à pergunta original:

  • O primeiro exemplo falha porque está tentando compactar o symlink real (mesmo que seja não um loop de link real)
  • O segundo usa o sinalizador -c, portanto, ele está lendo o conteúdo do arquivo original e, em seguida, gravando a saída compactada para stdout, portanto, é bem-sucedido.
  • Um terceiro cenário é usar -f em vez de -c. Neste caso, o gzip não reclama ao tentar compactar um symlink, mas na descompactação ele se torna um arquivo regular, como mostrado:
$ ls -l
total 4
-rw-rw-r-- 1 x86tux x86tux 13 Jun 16 13:10 realfile.txt
lrwxrwxrwx 1 x86tux x86tux 12 Jun 16 23:40 symlink.txt -> realfile.txt
$ gzip symlink.txt
gzip: symlink.txt: Too many levels of symbolic links
$ gzip -f symlink.txt
$ ls -l
total 8
-rw-rw-r-- 1 x86tux x86tux 13 Jun 16 13:10 realfile.txt
-rw-rw-r-- 1 x86tux x86tux 45 Jun 16 13:10 symlink.txt.gz
$ gunzip symlink.txt.gz
$ ls -l
total 8
-rw-rw-r-- 1 x86tux x86tux 13 Jun 16 13:10 realfile.txt
-rw-rw-r-- 1 x86tux x86tux 13 Jun 16 13:10 symlink.txt
$ md5sum *
618f486e0225d305d16d0648ed44b1eb  realfile.txt
618f486e0225d305d16d0648ed44b1eb  symlink.txt
    
por 17.06.2014 / 06:39
1

O processo único por parte do arquivo pode prejudicar alguns se houver qualquer possibilidade de controlar sua operação, mas com 10-11 gigabytes é muito difícil imaginar qualquer cenário em que seja a exec chamada em gzip que dificulta o progresso.

Nesse mesmo sentido, se fossem um monte de arquivos pequenos, gzip provavelmente não conseguiria compactá-los, além de ter menos dados para comparar por arquivo, mas, novamente, a 10-11 gigabytes por operação de compactação isso não será um problema.

Descobrir a causa do erro seria interessante, penso eu. Eu sugeriria tentar aplicar lsof a um gzip pid em background e descobrir o que está acontecendo.

    
por 17.06.2014 / 01:43