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

change to dls in fstools

This change to dls allows the option '-n' which numbers blocks
as they come out.

It allows utilities that filter the blocks to spit out block
numbers without having to run dcalc on (sometimes) thousands
of block numbers.

I'm also including the perl script bgrep3 which uses the output
of the -n option to find blocks that are probable candidates for
indirect inodes -- It only works for partitions < 64GB, but is easily
modifiable for larger partitions (to a point).

and the script idtest which tries to sort out double and triple indirect

--- sleuthkit-2.03.orig/src/fstools/dls_lib.c
+++ sleuthkit-2.03/src/fstools/dls_lib.c
@@ -29,6 +29,7 @@
 #include "libfstools.h"
+int blog=1;
@@ -90,6 +91,14 @@
     if (verbose)
 	fprintf(stderr, "write block %" PRIuDADDR "\n", addr);
+    if(blog){
+	int blen=fs->block_size + sizeof(blen)  + sizeof(addr);
+	if( fwrite(&blen,sizeof(blen),1,stdout) != 1 ||
+	   fwrite(&addr,sizeof(addr),1,stdout) != 1){
+		error("dls_lib: error writing data to stdout: %m");
+	       return WALK_STOP	;
+	}
+    };
     if (fwrite(buf, fs->block_size, 1, stdout) != 1)
 	error("write stdout: %m");
--- sleuthkit-2.03.orig/src/fstools/dls.c
+++ sleuthkit-2.03/src/fstools/dls.c
@@ -1,7 +1,7 @@
 ** The Sleuth Kit
-** $Date: 2006/10/01 18:09:50 $
+** $Date: 2005/09/02 19:53:27 $
 ** Brian Carrier [carrier@sleuthkit.org]
 ** Copyright (c) 2003-2005 Brian Carrier.  All rights reserved 
@@ -29,6 +29,8 @@
 #include "libfstools.h"
+extern int blog;
 /* atoblock - convert string to block number */
@@ -66,6 +68,8 @@
 	    "\t-s: print slack space only (other flags are ignored\n");
     fprintf(stderr, "\t-v: verbose to stderr\n");
+    fprintf(stderr, "\t-n: Number the block (binary)\n");
     fprintf(stderr, "\t-V: print version\n");
     fprintf(stderr, "\t-f fstype: File system type\n");
     fprintf(stderr, "Supported file system types:\n");
@@ -100,7 +104,7 @@
     progname = argv[0];
     setlocale(LC_ALL, "");
-    while ((ch = getopt(argc, argv, "bef:i:lo:svV")) > 0) {
+    while ((ch = getopt(argc, argv, "bef:i:lo:snvV")) > 0) {
 	switch (ch) {
 	case '?':
@@ -128,6 +132,10 @@
 	case 's':
 	    lclflags |= DLS_SLACK;
+	case 'n':
+	    blog=1;
+	    break;
 	case 'v':


# reads in blocks presuming my changes to dls that prepend 
# a length and block number (in binary) to every block.
# this allows a very fast printing of raw block numbers of interest.
# by default, look for possible indirect inode blocks:

# This pattern looks for indirect inode blocks in a 'small' partition
# (less then 64GiB).
# if you have  a partition > 64Gib, then you will have to allow 
# the high order byte to be 0...(floor(size/64GiB) 
# This also presumes the file to be non-sparse, so a block number 
# of zero should be end of data, and the rest of the block should
# be zeroes. 

# also checks for replicated 'block numbers' as an indication that
# this really isn't an indirect block;

$pattern= '^(?:(?!\0\0\0\0)...\0)+(?:\0\0\0\0)*$';

if ($ARGV[0] =~ '-q'){
	shift @ARGV;;
	printf "quiet...\n";
}elsif ($ARGV[0] =~ '-v'){
	shift @ARGV;;
	printf "quiet...\n";
if( $ARGV[0] ){ $pattern=$argv[0]; }
printf "pattern=($pattern)\n" if $verbose;
shift ;
print "";

sub nextblock{
  # print "nextblock\n";
  unless( $gotten1){ return(0)};
  $thissize= (unpack("i",$lendata))[0];
  # printf "thissize=%d intlen=%d\n",$thissize,$intlen;
  # printf "metasize= %d\n", $metasize;
  # printf "reading more: %d\n", $metasize-$intlen;
  return(0) unless $gotten1;
# presumes little-endian word ordering
  if(defined($bnums[1])){ $blockno=$bnums[1] *  4294967296  + $bnums[0]  ;};

  $rn = read(STDIN,$block,$thissize-$metasize);
  # print "rn=$rn\n";
  return $rn;

while ( $gotten=nextblock() ){

	printf "got%d\n",$gotten if $verbose;
	if($lastbad){ print STDERR $lastbad unless $quiet; $lastbad='';};
	# print( ".")   unless $quiet;
	if ($gotten != $blocksize ) { $lastbad= sprintf "bad read len (%d) for block %d\n",$gotten,$blockno; }
	if( @match=($block =~ /$pattern/s ) ) {
		my (%used, @blocks);
		printf( "(%s)",join(")(",@blocks))   if $verbose;
		foreach $b (@blocks){
		#	printf "(%s)",$b;
			if($b &&  ! defined($used{$b}) ){
				printf ("BadHit at block %d -- %d\n",$blockno,$blockcount)   unless $quiet;
				$bad=1; last;
			printf "Hit at block %d -- %d ",$blockno,$blockcount  unless $quiet;
	#		printf "<%s> <%s>\n",$match[0],$match[1]   unless $quiet;
			printf "(%s)\n",join(") (",@match )  unless $quiet;
print "\n"   unless $quiet;
	printf "Had hit returning $rc\n";
	exit $rc; 
	printf "Had no hit\n";
	exit 1 


open IDL,"<$list" or die "couldn't open $list";
open DEV,$dev or die "couldn't open $dev";

# read the list of indirct candidates

# checks a block to see if it is a complete double  indirect
#  it is a complet double if every block it points to is unallocated and indirect
sub isind{
	my ($blockno)=@_;
	my ($n)= 0;
	seek DEV,$blockno*$bsize,0 or die "seek failed for block $$blockno";
	read( DEV,$block,$bsize) or die "read failed for block $$blockno"; 
	@inums= unpack("l*",$block);
 	foreach $p (@inums){
			if(! exists $inlist{$p}){

# mark all the double indirects
foreach $bnum ( keys %inlist ){

# checks a double indrect to see if it is actually a complete triple
sub isind2{
	seek DEV,$bnum*$bsize,0 or die "seek failed for block $$blockno";
	read( DEV,$block,$bsize) or die "read failed for block $$blockno";
	@inums= unpack("l*",$block);
 	foreach $p (@inums){
			if(! exists $double{$p}){
				return 0 ;

# check each doubles to see if they are actually triples
foreach $bnum ( keys %double ){

open TRIPLES,">Triples" or die "could not create Triples ($@)\n";

# for each triple memer, delete the  doubles and singles 
# from the appropriae list, then print the triple block number

foreach $bnum (keys %triple){
	printf TRIPLES "%d\t%d\n",$triple{$bnum},$bnum;
	seek DEV,$bnum*$bsize,0 or die "seek failed for block $$blockno";
	read( DEV,$block,$bsize) or die "read failed for block $$blockno";
	@inums= unpack("l*",$block);
	delete $double{$bnum};
 	foreach $p (@inums){
			delete $double{$p};
			delete $inlist{$p};
			seek DEV,$dbnum*$bsize,0 or die "seek failed for block $$blockno";
			read( DEV,$dblock,$bsize) or die "read failed for block $$blockno";
			@dnums= unpack("l*",$block);
			foreach $ind (@dnums){
				delete $inlist{$ind}
close TRIPLES;

open DOUBLES ,">Doubles" or die "could not create Doubles ($@)\n";
foreach $bnum (keys %double){
	printf DOUBLES "%d %d\n",$double{$bnum},$bnum;
	delete $inlist{$bnum};
	seek DEV,$bnum*$bsize,0 or die "seek failed for block $$blockno";
	read( DEV,$block,$bsize);
	@inums= unpack("l*",$block);
 	foreach $p (@inums){
			delete $inlist{$p};

open SINGLES ,">Singles" or die "could not create Doubles ($@)\n";
# Print remaining indirect block numbers, but only print
# COMPLETE indirects, as partial indirects point to files too small
# for our liking.

foreach $bnum (keys %inlist){
	if( ! exists( $partial{$bnum} )){
		printf SINGLES "%d\n",$bnum;

Reply to: