#!perl use Archive::Tar; my $t = Archive::Tar->new(); $t->read($ARGV[0]) or die "Must specify valid input file - $!\n"; # this regex can be changed to fit the platform specific # illegal characters to watch for. my $BAD_CHARACTERS = '[?]'; my %sig; my $i; foreach my $h ($t->data()) { # typeflag 5 is a folder. if ($h->{typeflag} == 5) { my @folders = split '/', $h->{name}; my @newf = (); foreach (@folders) { my $new; if (/$BAD_CHARACTERS/) { if ($sig{$_}) { # this happens if we step on a previously # recovered folder. $new = $sig{$_}; } else { $new = "_recovered_folder" . ++$i; $sig{$_} = $new; } } else { $new = $_; } push @newf, $new; } $sig{$h->{name}} = join '/', @newf; foreach (@newf) { mkdir $_; # actually there would be a lot of errors here # had it been possible, # an mkdir -p $_ would have been better. chdir $_; } $out = '../' x @newf; chdir $out or die "I must have overdone myself. $!\n"; } else { my $name = $h->{name}; my ($nm) = (split '/', $name)[-1]; $new = $nm; if ($nm =~ /$BAD_CHARACTERS/) { my ($ext) = $nm =~ /\.(.*)$/; # pickup extension. $new = "_recovered_file" . ++$i . ".$ext"; } my $folder = $name; $folder =~ s/\Q$nm\E//; $folder = $sig{$folder}; my @times = split '/', $folder; chdir $folder or die "where did that '$folder' go? $!\n"; open OUT, ">$new" or die "$!\n"; binmode (OUT); print OUT $h->{data}; close OUT; $myout = '../' x @times; chdir $myout or die "again? $!\n"; } }