1#! /usr/bin/perl
2
3# ex:ts=8 sw=4:
4# $OpenBSD: extract_chunks,v 1.2 2014/09/20 09:35:54 espie Exp $
5#
6# Copyright (c) 2014 Marc Espie <espie@openbsd.org>
7#
8# Permission to use, copy, modify, and distribute this software for any
9# purpose with or without fee is hereby granted, provided that the above
10# copyright notice and this permission notice appear in all copies.
11#
12# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20# modern packages are "chunked" archives, composed of several gzip files
21# this script can extract each chunk for further analysis, as it is
22# difficult using plain old gunzip to do something like that.
23
24use strict;
25use warnings;
26use IO::Uncompress::AnyUncompress qw($AnyUncompressError);
27use File::Basename;
28
29for my $f (@ARGV) {
30	my $z;
31	unless ($z = IO::Uncompress::AnyUncompress->new($f)) {
32		print STDERR "Bad compressed file $f: $AnyUncompressError\n";
33		next;
34	}
35
36	my $buffer;
37	my $length = 1024 * 1024;
38	my $stem = basename($f, ".tgz");
39	my $i = 0;
40
41	while (1) {
42		$i++;
43		# build chunk name in the current directory
44		my $out ="$stem.tar.".sprintf("%04d", $i);
45		open my $fh, ">", $out or die "Can't open chunk $out: $!";
46		while (1) {
47			my $r = $z->read($buffer, $length);
48			if ($r < 0) {
49				print STDERR "Error reading from $f: ",
50				    $AnyUncompressError, "\n";
51			}
52			if ($r <= 0) {
53				last;
54			}
55			syswrite $fh, $buffer, $r;
56		}
57		close $fh;
58		my $s = $z->nextStream;
59		if ($s == -1) {
60			print STDERR "Error switching to next stream of $f:",
61			    $AnyUncompressError, "\n";
62		}
63		if ($s != 1) {
64			last;
65		}
66	}
67}
68
69