1#!/usr/bin/perl -w 2# This Source Code Form is subject to the terms of the Mozilla Public 3# License, v. 2.0. If a copy of the MPL was not distributed with this 4# file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 6# 7# This tool extracts a mar file, changes the compression of the files contained 8# by the mar file either from bzip2 to lzma or lzma to bzip2, and then recreates 9# the mar file. The script determines whether the files are compressed with 10# bzip2 or lzma to determine what compression should be used. The permissions 11# of the files will be retained as long as the script is run on a system such 12# as Linux or Mac OS X but not on Windows. The mar file will be created with the 13# same MAR channel and Product version information as the original mar file. 14# If a mar signature is required the converted mar files will need to be 15# re-signed afterwards. 16# Author: Robert Strong 17# 18 19# ----------------------------------------------------------------------------- 20# By default just assume that these tools exist in our path 21 22use Getopt::Std; 23use Cwd 'abs_path'; 24use File::Basename; 25 26$|++; 27 28my ($MAR, $XZ, $BZIP2, $MAR_OLD_FORMAT, $FILES, $CHANNEL, $VERSION, $REPLACE, $archive, $tmparchive, @marentries, @marfiles); 29 30if (defined($ENV{"MAR"})) { 31 $MAR = $ENV{"MAR"}; 32} 33else { 34 $MAR = "mar"; 35} 36 37if (defined($ENV{"BZIP2"})) { 38 $BZIP2 = $ENV{"BZIP2"}; 39} 40else { 41 $BZIP2 = "bzip2"; 42} 43 44if (defined($ENV{"XZ"})) { 45 $XZ = $ENV{"XZ"}; 46} 47else { 48 $XZ = "xz"; 49} 50 51sub print_usage 52{ 53 print "Usage: change_mar_compression.pl [OPTIONS] ARCHIVE\n"; 54 print "\n"; 55 print "The ARCHIVE will be recreated using either bzip2 for mar file contents that\n"; 56 print "are compressed with lzma or lzma for mar file contents that are compressed\n"; 57 print "with bzip2. The new mar file that is created will not be signed but all other\n"; 58 print "attributes that should be retained will be retained.\n"; 59 print "\n"; 60 print "Options:\n"; 61 print " -h show this help text\n"; 62 print " -r replace the original mar file with the new mar file\n"; 63} 64 65my %opts; 66getopts("hr", \%opts); 67 68if (defined($opts{'h'}) || scalar(@ARGV) != 1) { 69 print_usage(); 70 exit 1; 71} 72 73if ($opts{'r'}) { 74 $REPLACE = 1; 75} 76 77$archive = $ARGV[0]; 78@marentries = `"$MAR" -T "$archive"`; 79$? && die("Couldn't run \"$MAR\" -t"); 80 81system("$MAR -x \"$archive\"") == 0 || 82 die "Couldn't run $MAR -x"; 83 84open(my $testfilename, "updatev3.manifest") or die $!; 85binmode($testfilename); 86read($testfilename, my $bytes, 3); 87if ($bytes eq "BZh") { 88 $MAR_OLD_TO_NEW = 1; 89 print "Converting mar file from bzip2 to lzma compression\n"; 90} else { 91 undef $MAR_OLD_TO_NEW; 92 print "Converting mar file from lzma to bzip2 compression\n"; 93} 94close $testfilename; 95 96print "\n"; 97 98# The channel is the 4th line of the output 99shift @marentries; 100shift @marentries; 101shift @marentries; 102$CHANNEL = substr($marentries[0], 24, -1); 103print "MAR channel name: " . $CHANNEL . "\n"; 104 105# The version is the 5th line of the output 106shift @marentries; 107$VERSION = substr($marentries[0], 23, -1); 108print "Product version: " . $VERSION . "\n"; 109 110# The file entries start on the 8th line of the output 111shift @marentries; 112shift @marentries; 113shift @marentries; 114 115print "\n"; 116# Decompress the extracted files 117foreach (@marentries) { 118 tr/\n\r//d; 119 my @splits = split(/\t/,$_); 120 my $file = $splits[2]; 121 122 print "Decompressing: " . $file . "\n"; 123 if ($MAR_OLD_TO_NEW) { 124 system("mv \"$file\" \"$file.bz2\"") == 0 || 125 print "\n" && die "Couldn't mv \"$file\""; 126 system("\"$BZIP2\" -d \"$file.bz2\"") == 0 || 127 print "\n" && die "Couldn't decompress \"$file\""; 128 } 129 else { 130 system("mv \"$file\" \"$file.xz\"") == 0 || 131 print "\n" && die "Couldn't mv \"$file\""; 132 system("\"$XZ\" -d \"$file.xz\"") == 0 || 133 print "\n" && die "Couldn't decompress \"$file\""; 134 } 135} 136print "All files decompressed\n"; 137 138print "\n"; 139# Compress the files in the requested format 140$FILES = ""; 141foreach (@marentries) { 142 tr/\n\r//d; 143 my @splits = split(/\t/,$_); 144 my $mod = $splits[1]; 145 my $file = $splits[2]; 146 147 print "Compressing: " . $file . "\n"; 148 if ($MAR_OLD_TO_NEW) { 149 system("\"$XZ\" --compress --x86 --lzma2 --format=xz --check=crc64 --force --stdout \"$file\" > \"$file.xz\"") == 0 || 150 die "Couldn't compress \"$file\""; 151 system("mv \"$file.xz\" \"$file\"") == 0 || 152 die "Couldn't mv \"$file.xz\""; 153 } 154 else { 155 system("\"$BZIP2\" -z9 \"$file\"") == 0 || 156 die "Couldn't compress \"$file\""; 157 system("mv \"$file.bz2\" \"$file\"") == 0 || 158 die "Couldn't mv \"$file.bz2\""; 159 } 160 $FILES = $FILES . "\"$file\" "; 161 chmod oct($mod), $file; 162} 163print "All files compressed\n"; 164 165my $filesuffix = ".bz"; 166if ($MAR_OLD_TO_NEW) { 167 $filesuffix = ".xz"; 168} 169$tmparchive = $archive . $filesuffix; 170 171system("$MAR -H $CHANNEL -V $VERSION -c \"$tmparchive\" $FILES") == 0 || 172 die "Couldn't run $MAR -c"; 173 174if ($REPLACE) { 175 print "\n"; 176 print "Replacing mar file with the converted mar file\n"; 177 unlink $archive; 178 system("mv \"$tmparchive\" \"$archive\"") == 0 || 179 die "Couldn't mv \"$tmparchive\""; 180} 181 182print "\n"; 183print "Removing extracted files\n"; 184foreach (@marentries) { 185 tr/\n\r//d; 186 my @splits = split(/\t/,$_); 187 my $file = $splits[2]; 188 189 unlink $file; 190 my $dirpath = $file; 191 while (1) { 192 if (index($dirpath, '/') < 0) { 193 last; 194 } 195 $dirpath = substr($dirpath, 0, rindex($dirpath, '/')); 196 rmdir($dirpath); 197 if (-d $dirpath) { 198 last; 199 } 200 } 201} 202 203print "\n"; 204if ($MAR_OLD_TO_NEW) { 205 print "Finished converting mar file from bzip2 to lzma compression\n"; 206} else { 207 print "Finished converting mar file from lzma to bzip2 compression\n"; 208} 209