#!/usr/bin/perl use strict; use Math::BigInt; use File::Find; use IPC::System::Simple qw/capture/; sub find_damaged_files { my $lf = shift; my $mnt = shift; my $start_sector = shift; my $end_sector = shift; my $sector_size = shift; my %bad_sectors; open LF,"<$lf" or die("cannot open file: $lf\n"); foreach() { next if /^#/; /^(0x[0-9A-F]+) +(0x[0-9A-F]+) +([-+?\/])$/ or die("cannot parse line: $_\n"); my $status = $3; next if ($status eq '+'); my $start = new Math::BigInt($1)->bdiv($sector_size); my $size = new Math::BigInt($2)->bdiv($sector_size); my $end = $start + $size - 1; next if $start > $end_sector; next if $end < $start_sector; $start = $start_sector if $start < $start_sector; $end = $end_sector if $end > $end_sector; $start -= $start_sector; $end -= $start_sector; for (my $sector = $start; $sector <= $end; $sector++) { $bad_sectors{"$sector"} = 1 }; } close LF; find({ no_chdir=> 1, wanted => sub { return if !-f; my $file = $_; print "$file: "; my @blocks = capture('./fibmap', $_); my $status_line = shift @blocks; $status_line =~ /Blocksize: (\d+)/ or die("Bad status line from fibmap: $status_line\n"); my $block_size = $1; die("File block size and sector size differ\n") if $block_size != $sector_size; my @blocks_damaged; for(@blocks) { chomp; my ($idx, $block) = split /\t/, $_; push @blocks_damaged, $idx if defined $bad_sectors{$block}; } if (scalar @blocks_damaged == 0) { print "OK\n"; } else { print "DAMAGED: "; my $start = my $end = shift @blocks_damaged; while(my $val = shift @blocks_damaged) { if ($val == $end + 1) { $end = $val } else { print ($start == $end ? "$start," : "$start-$end,"); $start = $end = $val; } } print ($start == $end ? $start : "$start-$end"); print "\n"; } }}, $mnt); } die("Usage: $0 log_file mount_point start_sector end_sector [sector_size]\n") if @ARGV < 4; my $lf = $ARGV[0]; my $mnt = $ARGV[1]; my $start_sector = $ARGV[2]; my $end_sector = $ARGV[3]; my $sector_size = $ARGV[4] || 512; my @results = find_damaged_files($lf, $mnt, $start_sector, $end_sector, $sector_size);