Hi fellow monks,
Winzip and Archive::Tar do not play well together. I hit a problem while writing a
small utility that among other things recursively 'tar and
gzips' a directory. To support systems that do not ship with a built-in 'tar'
utility (MS windows), the utility script falls back to using Archive::Tar. I
encountered a problem with my code and sought the help of monks on the
ChatterBox.
This writeup is intended to:
-
Ensure other monks using Archive::Tar do not end up repeating the same
mistakes.
- This is the important part. It highlights the fact that sometimes the problem may not always be in the code per se. You need to keep an open mind when investigating issue - do not prejudge the code.
The original problem:
I was able to successfully create a archive file 'data.tar.gz' but opening the
file in WinZip showed that the archive did not preserve the folder/path
structure. The archive was basically "flattened" out. I needed to preserve the
file structure inside the archive.
My Code:
The following is a stripped down version of the two approaches for creating the archive file:
#!/usr/bin/perl
#
# Sample test script
#
use strict;
use warnings;
use Archive::Tar;
use File::Find;
$Archive::Tar::DEBUG=1;
my $srcDir = 'C:\Temp\data';
## Attempt 1 - add the files to the archive in the callback code.
my $archive = Archive::Tar->new();
find(\&callback1, $srcDir);
$archive->write('one.tar.gz', 9);
print "---------ONE-------------------\n";
print join("\n", $archive->list_files());
print "---------ONE-------------------\n";
## Attempt 2 - prepare a list of files and add to the archive in one p
+lace
my @files = ();
# not using $archive->clear() - I want this to be independent of previ
+ous
# attempt
$archive = Archive::Tar->new();
find(\&callback2, $srcDir);
$archive->create_archive('two.tar.gz', 9, @files);
print "---------TWO-------------------\n";
print join("\n", @files);
print "---------TWO-------------------\n";
sub callback1() {
$archive->add_files($File::Find::name);
}
sub callback2() {
push(@files, $File::Find::name);
}
The output of above:
---------ONE-------------------
C:/Temp/data
C:/Temp/data/SpaceMonger.exe
C:/Temp/data/spacemonger_README.TXT
C:/Temp/data/tcpvcon.exe
C:/Temp/data/bar
C:/Temp/data/bar/Tcpview.exe
C:/Temp/data/bar/TCPVIEW.HLP
C:/Temp/data/bar/tcpview_README.TXT
C:/Temp/data/foo
C:/Temp/data/foo/nc.exe
C:/Temp/data/foo/nc_license.txt
C:/Temp/data/foo/nc_readme.txt---------ONE-------------------
---------TWO-------------------
C:\Temp\data
C:\Temp\data/SpaceMonger.exe
C:\Temp\data/spacemonger_README.TXT
C:\Temp\data/tcpvcon.exe
C:\Temp\data/bar
C:\Temp\data/bar/Tcpview.exe
C:\Temp\data/bar/TCPVIEW.HLP
C:\Temp\data/bar/tcpview_README.TXT
C:\Temp\data/foo
C:\Temp\data/foo/nc.exe
C:\Temp\data/foo/nc_license.txt
C:\Temp\data/foo/nc_readme.txt---------TWO-------------------
The learnings from this experience:
The code is very simple and still it did not work. I was sure I was missing
something obvious and trivial. I looked at the code, debugged it, went through the documentation, asked
monks on the CB and followed their suggestions. I could not make
progress towards resolving the problem until Corion pointed out a possible
issue. It seems that Winzip cannot correctly interpret the archives created
by Archive::Tar. It will
open up the tar file, but not interpret the file paths correctly and show
them as "blank". This gives the wrong impression that the archive does not
preserve file paths. This undocumented "feature" gives the wrong impression
that there is something wrong with the Perl code and misleads the developer. Testing the archive on a Unix machine showed the file structure correctly. The culprit was Winzip in this scenario.
When using Archive::Tar in a windows environment, test the created archive
using a non-Winzip utility (unxutils.sourceforge.net) or on a *nix
environment. Sometimes you may be looking at the issue in the wrong location.
It turned out that the verification step was defective. The code was OK and confirmed to the module documentation. I am not ruling out bugs in Archive::Tar but it was not immediately obvious to me **where** the problem was located.
This was a good lesson to learn.
Thanks to Zaxo, Corion, bart and Intrepid on CB for not only helping me out in identifying the problem but also for providing suggestions on how to improve the utility and alternate implementation ideas.
Regards,
Mahesh