Renomear diretório dentro de um arquivo tar

14

É possível renomear um diretório dentro de um arquivo tar? Meu caso de uso é que tenho um arquivo de especificação RPM fornecido externamente que assume um tarball com uma certa estrutura de diretórios e um tarball fornecido externamente cujo nome de diretório de nível superior não corresponde ao que o arquivo spec espera. Eu não controlo o script que gera os tarballs ou o arquivo de especificação do RPM; portanto, não posso alterar nenhum deles para corresponder ao outro.

O que venho fazendo é desenfreado, alterando o nome do diretório e, em seguida, criando um novo tarball, mas fiquei imaginando se havia uma alternativa para isso.

Lorin Hochstein
fonte
3
Infelizmente eu duvido, mas eu estaria interessado em ver se mais alguém tem uma maneira. Acho que sua melhor aposta é escrever um script para descompactar, renomear e refazer o tar.
Kevin

Respostas:

8

Não deve ser muito difícil, pelo menos para arquivos compatíveis com o formato antigo, onde os nomes dos arquivos são armazenados em um campo de tamanho fixo (100 bytes), mas não conheço nenhuma ferramenta que possa renomear um arquivo. arquivo em um arquivo tar. Além disso, com um arquivo compactado, você precisará criar um novo arquivo de qualquer maneira.

Deve ser ainda mais fácil, mas não conheço nenhuma ferramenta existente que possa filtrar um arquivo morto, renomeando arquivos à medida que for sendo processada. Você pode criar uma sobre as bibliotecas tar nas linguagens de script; por exemplo, aqui está um script de prova de conceito para renomear um diretório em um arquivo tar usando o PerlArchive::Tar . O arquivo é carregado inteiramente na memória; essa é uma limitação intrínseca de Archive::Tar.

#!/usr/bin/env perl
## Usage: tar-rename OLDPREFIX NEWPREFIX
use strict;
use warnings;
use Archive::Tar;
my ($from, $to) = @ARGV;
my $tar = Archive::Tar->new(\*STDIN);
foreach my $file ($tar->get_files()) {
    my $name = $file->name;
    $name =~ s~\A\Q$from\E($|/)~$to$1~;
    $file->rename($name) unless $name eq $file->name;
}
$tar->write(\*STDOUT);

O tar do GNU não tem a capacidade de renomear membros rapidamente, mas pax(o substituto do POSIX para cpioe tar) possui. No entanto, você não pode fazer paxa leitura e gravação de um arquivo. O que você pode fazer é expor o arquivo morto como uma árvore comum por meio do AVFS e criar um novo arquivo mortopax . Isso mantém os nomes dos arquivos (exceto quando transformados), o conteúdo, os horários e os modos, mas redefine a propriedade do arquivo para você (a menos que seja executado como root).

mountavfs
cd "~/.avfs$PWD/old.tgz#"
pax -w -s '!bar!baz!' -s '!bar/!baz/' . | gzip >new.tgz
Gilles 'SO- parar de ser mau'
fonte
O GNU Tar tem --transformdesde pelo menos 2010 que permite renomear arquivos em tempo real. Por exemplo, consulte: scriptsandoneliners.blogspot.com/2019/11/…
A.Danischewski
@ A.Danischewski --transformpermite renomear arquivos quando você cria ou extrai um arquivo morto . Mas como você renomeia arquivos em um arquivo sem extraí-lo? (Extrair não é uma boa solução: você pode não ter espaço em disco suficiente; pode não ter permissões para preservar informações de propriedade; pode não ter a capacidade de preservar os carimbos de hora exatamente ...)
Gilles 'para de ser mau'
Ok, sim, acabei de ver seu post declarar que "o GNU tar não é capaz de renomear membros em tempo real" - sim, mas apenas na entrada / saída. Se você deseja alterar os nomes em um archive existente, pode usar o archivemount para montá-lo em um diretório, altere os nomes desejados e desmonte-os.
A.Danischewski
3

O hack do sr_ e a resposta do Gilles parecem muito bons, mas se o seu problema for apenas o nome do diretório raiz do tarball de destino, enquanto estiver executando o rpmbuild, uma solução diferente pode ser redefinir a %setupmacro para renomear o diretório necessário.

Algo como (você vai ter que se adaptar e refinar essa a sua configuração actual, em particular a substituição old-dire desired-dire usando a ferramenta de descompressão direita) esta na sua ~/.rpmmacros:

%setup cd ../BUILD \
rm -rf cd-player \
bunzip2 -dc ../SOURCES/%{name}-%{version}.tar.bz2 | tar -xvvf - \
if [ $? -ne 0 ]; then \
  exit $? \
fi \
mv <old-dir> <desired-dir> \
cd <desired-dir> \
cd ../BUILD/cd-player \
chmod -R a+rX,g-w,o-w .

Eu honestamente não faria isso se não estivesse na situação mais exótica, mas a sua poderia ser o caso :)

guido
fonte
1

Corte feio, mas talvez isso ajude você, enganando os tarlinks simbólicos:

$ mkdir a b
$ date >> b/foo
$ tar zcvf b-foo.tgz b/foo
$ rm -rf b
$ ln -s a b

$ tar zxvf b-foo.tgz                                                              
x b/foo: Cannot extract through symlink b
tar: Error exit delayed from previous errors.
$ tar zxvPf b-foo.tgz                                                             
x b/foo
$ ls a
foo

Pensando nisso, provavelmente não, pois rpmnão deixará você mexer com os argumentos tar, não é? (Edit: talvez algum tarscript de wrapper complicado $PATHpossa contornar isso.)

sr_
fonte