5 # buffer size for reading
6 my $bufsize = 4*1024*1024;
8 my ($opt_skip, $opt_disk, $opt_input, $opt_verbose);
11 if ($ARGV[0] eq '--skip') {
13 $opt_skip = shift @ARGV;
16 if ($ARGV[0] eq '--disk') {
18 $opt_disk = shift @ARGV;
21 if ($ARGV[0] eq '--input') {
23 $opt_input = shift @ARGV;
26 if ($ARGV[0] eq '--verbose' || $ARGV[0] eq '-v') {
34 die "need to specify disk image\n" unless $opt_disk;
36 open(F, '<', $opt_disk) || die "$opt_disk: $!\n";
39 open(S, '<', $opt_input) || die "$opt_input: $!\n";
41 open(S, '<&STDIN') || die "can't dup stdin: $!\n";
46 seek(S, $opt_skip, 0) || die "$!\n";
51 last unless length $_;
52 my ($file, $filesize, $blksize, @blocks) = split(/ /);
53 if($#blocks == -1 && $filesize) {
54 die "invalid input '$_'\n";
56 $filesize = int($filesize);
57 $blksize = int($blksize);
58 die "invalid block size" unless ($blksize > 0 && $blksize <= $bufsize);
59 my $maxblocks = int($bufsize/$blksize);
60 $file =~ s/.*\///; # ensure basename, also stops directory traversal
61 $file =~ s/[^[:print:]]/_/g; # no binary junk in file names
62 print "$file\n" if $opt_verbose;
63 open (O, '>', $file) or die "$file: $!";
64 for my $block (@blocks) {
65 my ($block, $end) = split(/-/, $block);
68 if($block == 0) { # a hole!
70 $filesize -= $blksize;
74 $end = $block unless $end;
76 seek(F, $block*$blksize, 0) || die "$file: seek: $!\n";
77 while($block <= $end && $filesize) {
82 } elsif($maxblocks >= $end-$block) {
83 $size = ($end-$block)*$blksize;
84 $block += $end-$block;
86 $size = $maxblocks*$blksize;
89 $size = $filesize if $size > $filesize;
91 if((sysread(F, $buf, $size) || 0) != $size) {
92 die "$file: read: $!\n";
100 die "$file: invalid file size ($filesize byes left)\n" if $filesize != 0;