1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
#!/usr/bin/perl -w
########################################################################
# safeunrar, safeunzip, safeuntar -- Extract archives, ensuring that #
# all files in each archive remain in a single subdirectory, without #
# overwriting anything. #
########################################################################
# The decompression program is called once for each argument. The #
# program to use is guessed, first by extension, and failing that #
# by the name of this program (which, in that case, must be one of #
# safeunrar, safeunzip, safeuntar). #
########################################################################
use File::Temp qw(tempdir);
use File::Basename;
use Cwd;
my %extension_map = (
'(tar\.gz|tgz|taz)' => 'tar -zxf',
'(tar\.Z|taZ)' => 'tar -Zxf',
'(tar\.bz2|tz2|tbz2|tbz)' => 'tar -jxf',
'(tar\.lzma|tlz)' => 'tar --use-compress-program=lzma -xf',
'(zip|xpi|jar)' => 'unzip',
'rar' => 'unrar x',
'tar' => 'tar -xf',
);
$cwd = getcwd or die "getcwd error: $!";
for $archive (@ARGV) {
chdir $cwd or die "chdir error: $!";
my ($base, @cmd);
keys %extension_map; # resets "each"
while (($rx, $cmd) = each %extension_map) {
$_ = basename $archive;
if (m/^(.*)\.$rx$/) {
@cmd = split / /, $cmd;
$base = $1;
last;
}
}
unless (@cmd) {
for (basename $0) {
$_ eq 'safeunzip' && (@cmd = qw'unzip')
|| $_ eq 'safeunrar' && (@cmd = qw'unrar x')
# don't use this because the current gnu tar's --auto-compress is
# guaranteed to fail if the current %extension_map failed.
# || $_ eq 'safeuntar' && (@cmd = qw'tar --auto-compress -xf')
|| $_ eq 'safeuntar' && (@cmd = qw'tar -zxf')
|| die;
}
($base = basename $archive) =~ s/\..{2,4}$//;
}
$tempdir = tempdir("$base.XXXXXX", DIR => ".")
or warn("tempdir error: $!; skipping $archive"), next;
chmod 0777 & ~ umask, $tempdir;
$ltd = "leaving temporary directory '$tempdir'";
# extract the files
chdir $tempdir
or warn("chdir error: $!; $ltd"), next;
$archive =~ s#^(?!/)#../#;
system(@cmd, $archive) == 0
or warn("$cmd[0] error: $?/$!; $ltd"), next;
# count the files
opendir(DIR, '.')
or warn("opendir error: $!; $ltd"), next;
@f = readdir(DIR)
or warn("readdir error: $!; $ltd"), next;
closedir(DIR)
or warn("closedir error: $!; ignoring");
# if only one file, delete the dir
@f = grep { ! m/^\.\.?$/ } @f;
if (1 == @f) {
! -e "$cwd/$f[0]"
or warn("not overwriting $f[0]; $ltd"), next;
rename $f[0], "$cwd/$f[0]"
or warn("rename error: $!; $ltd"), next;
chdir $cwd
or warn("chdir error: $!; $ltd"), next;
rmdir $tempdir
or warn("rmdir error: $!; $ltd"), next;
# if multiple files, rename the dir
} else {
rename "$cwd/$tempdir", "$cwd/$base"
or warn("rename error: $!; $ltd"), next;
}
}
|