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