#!/usr/bin/perl
print "\n----------------------------------------------------------------------------\n";
print "Allocation Map:  David Hoelzer 2005, Cyber-Defense (www.cyber-defense.org)\n";
print "  Free for use but not inclusion into commercial products.\n";
print "  Contact us for licensing information for other uses.\n\n";
if(!$ARGV[1]) { &usage; exit; }

$spacer = "        ";
%tags = ('unallocated', '-', 'allocated', 'a', 'no metadata', '!', 'metadata', 'm', 'unknown', '*');

print "Key:\n";
foreach(keys(%tags))
{
	printf("%3s:%20s\n", $tags{$_}, $_);
}

$filesystem=$ARGV[0];
$image=$ARGV[1];
$width=$ARGV[2];
$columns = 80;
if($width > 50) { $columns = (int($width/10))*10; }
print "Analyzing image $image using filesystem $filesystem\n$spacer";
for($x=0;$x!=$columns/10;$x++){print "".($x%10)."         ";}
print "\n$spacer";
for($x=0;$x!=$columns;$x++){print $x % 10;}
print "\n      0:";
for($x=0;;$x++)
{
	open(FILE, "dstat -f $filesystem $image $x |");
	@results = <FILE>;
	close(FILE);
	$result = join(//,@results);
	$_ = $result;
	$val = $tags{"unknown"};
	if(/too large/) { 
		print "\n\nTotal blocks: $x\n";
		print "$i blocks found marked as allocated with no metadata associated:\n$interesting\n";
		print "Blocks extracted below:\n";
		&extract_blocks($interesting);
		exit;
		}
	if(/Not Allocated/) { $val=$tags{"unallocated"}; }
	if(/1Allocated/) {
		if(/Meta/) { $val = $tags{"metadata"}; }
		else { 
			open(FILE, "ifind -f $filesystem $image -d $x |");
			@results = <FILE>;
			close(FILE);
			$result = join(//,@results);
			$_ = $result;
			if(/[0-9]+/){ $val = $tags{"allocated"}; }
			if(/Inode not/){ $val = $tags{"no metadata"}; $interesting .= "$x "; $i++; }
			}
		}
	print "$val";
	if(($x+1) % $columns == 0) { printf ("\n%7d:",($x+1)); }
}

sub extract_blocks
{
	$block_list = $_[0];
	@block_list = split(/ /, $block_list);
	foreach(@block_list)
	{
		print"-------------------------\n";
		print" Block $_\n";
		print"-------------------------\n";
		open(FILE, "dcat -f $filesystem $image $_|");
		@results = <FILE>;
		close(FILE);
		$result = join(//,@results);
		$hold = $_;
		$_ = $result;
		$result =~ s/[^a-zA-Z0-9 \-_+=]/./g;
		print"$result\n";
		$_ = $hold;
	}
}

sub usage
{
	print "Usage:\n\n  allocationmap filesystemtype imagename [columns]\n";
	print "\n    Column width is optional but must be greater than 50 and divisible by 10.\n";
}
