Renommer le répertoire à l'intérieur d'une archive tar

14

Est-il possible de renommer un répertoire à l'intérieur d'une archive tar? Mon cas d'utilisation est que j'ai un fichier de spécifications RPM fourni en externe qui suppose une archive tar avec une certaine structure de répertoires, et j'ai une archive tar fournie en externe dont le nom de répertoire de niveau supérieur ne correspond pas à ce que le fichier de spécifications attend. Je ne contrôle ni le script qui génère les tarballs ni le fichier de spécifications RPM, je ne peux donc pas modifier l'un de ceux-ci pour qu'ils correspondent à l'autre.

Ce que j'ai fait, c'est de décompresser, de changer le nom du répertoire, puis de créer une nouvelle archive tar, mais je me demandais s'il y avait une alternative à cela.

Lorin Hochstein
la source
3
Malheureusement, j'en doute, mais je serais intéressé de voir si quelqu'un d'autre a un moyen. Je pense que votre meilleur pari est d'écrire un script pour décompresser, renommer et recalculer.
Kevin

Réponses:

8

Cela ne devrait pas être très difficile, du moins pour les archives qui sont compatibles avec l'ancien format où les noms de fichiers sont stockés dans un champ de taille fixe (100 octets), mais je ne connais aucun outil capable de renommer un fichier en place dans une archive tar. De plus, avec une archive compressée, vous devrez de toute façon créer un nouveau fichier.

Cela devrait être encore plus facile, mais je ne connais aucun outil existant qui puisse filtrer une archive, renommer les fichiers au fur et à mesure. Vous pouvez en créer une au-dessus des bibliothèques tar dans les langages de script; par exemple, voici un script de preuve de concept pour renommer un répertoire dans une archive tar en utilisant Perl avecArchive::Tar . L'archive est entièrement chargée en mémoire; il s'agit d'une limitation intrinsèque 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);

GNU tar n'a pas la possibilité de renommer les membres à la volée, mais pax(le remplacement de POSIX pour cpioet tar) le fait. Cependant, vous ne pouvez pas faire à la paxfois lire et écrire à partir d'une archive. Ce que vous pouvez faire est d'exposer l'archive sous forme d'arborescence régulière via AVFS et de créer une nouvelle archive avec pax. Cela conserve les noms de fichiers (sauf tels qu'ils ont été transformés), le contenu, les heures et les modes, mais réinitialise la propriété des fichiers (sauf s'ils sont exécutés en tant que root).

mountavfs
cd "~/.avfs$PWD/old.tgz#"
pax -w -s '!bar!baz!' -s '!bar/!baz/' . | gzip >new.tgz
Gilles 'SO- arrête d'être méchant'
la source
GNU Tar a --transformdepuis au moins 2010 qui permet de renommer les fichiers à la volée. Pour un exemple, voir: scriptsandoneliners.blogspot.com/2019/11/…
A.Danischewski
@ A.Danischewski --transformvous permet de renommer des fichiers lorsque vous créez ou extrayez une archive. Mais comment renommer des fichiers dans une archive sans l'extraire? (L'extraction n'est pas une bonne solution: vous n'avez peut-être pas assez d'espace disque; vous n'avez peut-être pas les autorisations pour conserver les informations de propriété; vous n'avez peut-être pas la possibilité de conserver les horodatages exactement ...)
Gilles 'SO- arrête d'être mauvais'
D'accord, oui, je viens de voir votre article déclarer que "GNU tar n'a pas la capacité de renommer les membres à la volée" - il le fait, mais seulement en entrant / sortant. Si vous souhaitez modifier les noms dans une archive existante, vous pouvez utiliser archivemount pour la monter dans un répertoire, modifier les noms que vous souhaitez et démonter.
A.Danischewski
3

Le hack de sr_ et la réponse de Gilles semblent très bons, mais si votre problème est simplement le nom du répertoire racine de l'archive cible, lors de l'exécution de rpmbuild, une autre solution pourrait être de redéfinir la %setupmacro pour effectuer le changement de nom de dir nécessaire.

Quelque chose comme (vous devrez adapter et affiner votre configuration réelle, en particulier le remplacement old-diret desired-diret en utilisant l'outil de décompression à droite) dans votre ~/.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 .

Je ne le ferais pas honnêtement si ce n'est dans la situation la plus exotique, mais la vôtre pourrait être le cas :)

guido
la source
1

Hack laid, mais peut-être que cela vous aide, en vous trompant taravec les liens symboliques:

$ 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

En y réfléchissant, ce n'est probablement pas le cas, car rpmcela ne vous laissera pas jouer avec les arguments tar, n'est-ce pas? (Edit: peut-être qu'un tarscript wrapper délicat $PATHpourrait vous aider à contourner ce problème.)

sr_
la source