Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Is it possible to rename a directory inside of a tar archive? My use case is that I have an externally provided RPM spec file that assumes a tarball with a certain directory structure, and I have an externally provided tarball whose top-level directory name does not match what the spec file expects. I don't control either the script that generates the tarballs or the RPM spec file, so I can't make a change to either of those to match the other.

What I have been doing is untarring, changing the directory name, and then creating a new tarball, but I was wondering if there was an alternative to doing that.

share|improve this question
3  
Unfortunately I doubt it, but I'd be interested to see if anyone else has a way. I think your best bet is to write a script to untar, rename, and re-tar. –  Kevin Dec 5 '11 at 14:30
add comment

4 Answers

up vote 6 down vote accepted

It shouldn't be very difficult, at least for archives that are compatible with the old-style format where file names are stored in a fixed-size (100 bytes) field, but I don't know of any tool that can rename a file in place in a tar archive. Besides, with a compressed archive, you'd need to create a new file anyway.

It should be even easier, but I don't know of any existing tool that can filter an archive, renaming files as it goes. You can build one on top of tar libraries in scripting languages; for example, here's a proof-of-concept script to rename a directory in a tar archive using Perl with Archive::Tar. The archive is loaded entirely into memory; this is an intrinsic limitation of 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 doesn't have the ability to rename members on the fly, but pax (POSIX's replacement for cpio and tar) does. However, you can't make pax both read and write from an archive. What you can do is expose the archive as a regular tree through AVFS, and create a new archive with pax. This retains file names (except as transformed), contents, times and modes but resets file ownership to you (unless executed as root).

mountavfs
cd "~/.avfs$PWD/old.tgz#"
pax -w -s '!bar!baz!' -s '!bar/!baz/' . | gzip >new.tgz
share|improve this answer
add comment

Both sr_'s hack and Gilles' answer look very good, but if your problem is just the root directory name of the target tarball, while running rpmbuild, a different solution could be to re-define the %setup macro to do the needed dir renaming.

Something like (you'll have to adapt and refine this to your actual configuration, in particular replacing old-dir and desired-dir and using the right decompression tool) this in your ~/.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 .

I wouldn't honestly do that if not in the most exotic situation, but yours could be the case :)

share|improve this answer
add comment

Ugly hack, but maybe this helps you, fooling tar with symlinks:

$ 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

Thinking about it, it probably doesn't, as rpm won't let you mess with the arguments to tar, would it? (Edit: maybe some tricky tar wrapper script in $PATH could get you around this.)

share|improve this answer
add comment

Just view this page but found the proper answer elsewhere:

http://www.rpm.org/max-rpm/s1-rpm-inside-macros.html

It says that you can pass -n to the %setup macro to tell rpmbuild the name of the top level folder within the tarball

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.