mjd-lists-plug on Tue, 10 Dec 2002 12:10:06 -0500


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

[PLUG] How to tell if a file has holes


I present this small program for your amusement and education.

Typical run:

      perl dumpbitmap.pl  sparse dumpbitmap.pl   testfile 

Typical output:

        Configurator ran OK; FIBMAP is 1; BLOCK_SIZE is 4096
        sparse: *........................................................................................................................................................................................................................................................*
        dumpbitmap.pl: *
        testfile: ****

This means that 'sparse' is many blocks long, but only the first and
last blocks are actually allocated; the intervening blocks are holes.
'dumpbitmap.pl' itself is one block long, and 'testfile' contains four
blocks, all of which are allocated.

The code follows.  To run it, you must be root.  It should be clear
how to write an equivalent C program.  In fact, the C program would
probably be shorter.

################################################################

#!/usr/bin/perl

configure();


for (@ARGV) {
  my $bm = bitmap($_);
  print "$_: $bm\n";
}

sub bitmap {
  my $result = "";
  for (blockmap(@_)) {
    $result .= $_ ? "*" : ".";
  }
  $result;
}

sub blockmap {
  my @res;
  my $f = shift;
  unless (open F, "<", $f) {
    warn "Couldn't open file '$f': $!; skipping\n";
    next;
  }
  my $extent = -s F;
  for (0 .. int(($extent-1)/$BLOCK_SIZE)) {
    my $absblock = block_no(\*F, $_);
    push @res, $absblock;
  }
  @res;
}

sub block_no {
  my ($fh, $ibn) = @_;
  my $arg = pack "I", $ibn;
  ioctl $fh, $FIBMAP, $arg or die "ioctl failed: $!";
  unpack "I", $arg;
}

sub configure {
  unless (eval {require "fibmap.ph"}) {
    open C, "> fibmap.c" or die "Couldn't write configurator: $!; aborting";
    print C while <DATA>;
    close C;
    system("cc -o fibmap fibmap.c") == 0 or die "Couldn't run C compiler.\n";
    system("./fibmap > fibmap.ph") == 0 or die "Couldn't run configurator.\n";
    unless (eval {require "fibmap.ph"}) {
      die "Couldn't load configurator: $@.\n";
    }
    unlink "fibmap", "fibmap.c";
  }
  ioctl(\*DATA, $FIGETBSZ, my $arg)
    or die "Couldn't get block size: $!";
  $BLOCK_SIZE = unpack "I", $arg;
  print "Configurator ran OK; FIBMAP is $FIBMAP; BLOCK_SIZE is $BLOCK_SIZE\n";
}



__DATA__
#include <stdio.h>
#include <linux/fs.h>

int main(void)
{
  printf("$FIBMAP = %d;\n", FIBMAP);
  printf("$FIGETBSZ = %d;\n1;\n", FIGETBSZ);
  return 0;
}



_________________________________________________________________________
Philadelphia Linux Users Group        --       http://www.phillylinux.org
Announcements - http://lists.netisland.net/mailman/listinfo/plug-announce
General Discussion  --   http://lists.netisland.net/mailman/listinfo/plug