diff options
Diffstat (limited to 'dot/local/bin/safeunrar')
-rwxr-xr-x | dot/local/bin/safeunrar | 90 |
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 | ######################################################################## | ||
12 | use File::Temp qw(tempdir); | ||
13 | use File::Basename; | ||
14 | use Cwd; | ||
15 | |||
16 | my %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: $!"; | ||
27 | for $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 | } | ||