summaryrefslogtreecommitdiff
path: root/computeblocklists
blob: f9300d6076e64a1d79ee6173b1bbac46082f36a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#!/usr/bin/perl -w
# compute the blocks used by a file
# usage:
# computeblocklists [options] <files...>
# options:
# --padstart NUM, --padend NUM, --verbose
#
# output:
# <file base name> <size> <blocksize> <block numbers...>
#
# a block is either a number or a range (start-end)
#
# TODO: instead of printing zeroes for each block in a hole use
# something like 0*num

use strict;

my ($opt_padstart, $opt_padend, $opt_verbose);

while (@ARGV)  {
  if ($ARGV[0] eq '--padstart') {
    shift @ARGV;
    $opt_padstart = shift @ARGV;
    next;
  }
  if ($ARGV[0] eq '--padend') {
    shift @ARGV;
    $opt_padend = shift @ARGV;
    next;
  }
  if ($ARGV[0] eq '--verbose' || $ARGV[0] eq '-v') {
    shift @ARGV;
    $opt_verbose = 1;
    next;
  }
  last;
}

if($opt_padstart) {
  print "\n"x$opt_padstart;
}

for my $file (@ARGV) {
  next unless -f $file;
  print STDERR "$file\n" if $opt_verbose;
  my $n = $file;
  $n =~ s/.*\///;

  if(!open(F, '<', $file)) {
    print STDERR "$file: $!";
    next;
  }

  my $bsize = 'xxxx';
  ioctl(F, 2, $bsize) || ioctl(F, 536870914, $bsize) || die("FIGETBSZ: $!\n");
  $bsize = unpack("L", $bsize);

  my @stat = stat(F);
  my ($st_size, $st_blocks) = ($stat[7], $stat[11], $stat[12]);

  my $blocks = int(($st_size+$bsize-1)/$bsize);

  print "$n $st_size $bsize ";

  my ($firstblock, $lastblock);
  for ($b = 0; $b < $blocks; ++$b) {
    my $block = pack('I', $b);
    if(not defined ioctl(F, 1, $block)) {
	if(not defined ioctl(F, 536870913, $block)) {
	    die "$file: $!";
	}
    }
    $block = unpack('I', $block);
    if($b == 0) {
      print "$block";
      $firstblock = $block;
    } else {
      # blocks are non-contiguous
      if($lastblock+1 != $block) {
	# check if we skipped some that form a range
	if($firstblock != $lastblock) {
	  printf "-$lastblock";
	}
	print " $block";
	$firstblock = $block;
      }
      # last block, check if contiguous
      if($b+1==$blocks && $lastblock+1 == $block) {
	print "-$block";
      }
    }
    $lastblock = $block;
  }
  close F;
  print "\n";
}

if($opt_padend) {
  print "\n"x$opt_padend;
}