131         }  | 
   140         }  | 
   132         close $fh;  | 
   141         close $fh;  | 
   133         return 0;  | 
   142         return 0;  | 
   134     }  | 
   143     }  | 
   135   | 
   144   | 
         | 
   145     sub release { | 
         | 
   146 	my $path = $IDX . shift;  | 
         | 
   147 	return 0 if not exists $IMAGE{$path}; | 
         | 
   148 	$debug->("Currently we have " . keys(%DIRTY) . " dirty blocks\n"); | 
         | 
   149 	return 0;  | 
         | 
   150     }  | 
         | 
   151   | 
   136     sub readbuffer { | 
   152     sub readbuffer { | 
   137         my $path = $IDX . shift;  | 
   153         my $path = $IDX . shift;  | 
   138         my ($size, $offset) = @_;  | 
   154         my ($size, $offset) = @_;  | 
   139         my $finfo = $IMAGE{$path} or die "File $path is not opened!"; | 
   155         my $finfo = $IMAGE{$path} or die "File $path is not opened!"; | 
   140         return "" if $offset >= $finfo->{meta}{devsize}; | 
   156         return "" if $offset >= $finfo->{meta}{devsize}; | 
   147         return $buffer;  | 
   163         return $buffer;  | 
   148     }  | 
   164     }  | 
   149   | 
   165   | 
   150     sub _readblock { | 
   166     sub _readblock { | 
   151         my ($finfo, $size, $offset) = @_;  | 
   167         my ($finfo, $size, $offset) = @_;  | 
   152   | 
   168 	my ($block, $blockoffset, $length);  | 
   153         my $block       = int($offset / $finfo->{meta}{blocksize}); | 
   169   | 
   154         my $blockoffset = $offset % $finfo->{meta}{blocksize}; | 
   170 	$debug->("<<< block offset:$offset size:$size\n"); | 
   155   | 
   171 	$debug->( "    block @{[int($offset/BS)]} + @{[$offset % BS]}\n"); | 
   156         my $length = $finfo->{meta}{blocksize} - $blockoffset; | 
   172   | 
   157         $length = $size if $size <= $length;  | 
   173 	# first check if it's an dirty block  | 
   158   | 
   174         $block       = int($offset / BS);  | 
   159         if (exists $DIRTY{ $finfo . $block }) { | 
   175         if (exists $DIRTY{ $finfo . $block }) { | 
         | 
   176 	    $blockoffset = $offset % BS;  | 
         | 
   177 	    $length = min(BS - $blockoffset, $size);  | 
         | 
   178   | 
         | 
   179 	    $debug->("+++ dirty offset:$block*@{[BS]} + $blockoffset size:$length\n"); | 
   160             return substr $DIRTY{ $finfo . $block }, $blockoffset, $length; | 
   180             return substr $DIRTY{ $finfo . $block }, $blockoffset, $length; | 
   161         }  | 
   181         }  | 
   162   | 
   182   | 
         | 
   183   | 
         | 
   184 	# if not dirty, we've to find it on disk  | 
         | 
   185   | 
         | 
   186 	$block = int($offset / $finfo->{meta}{blocksize}); | 
         | 
   187 	$blockoffset = $offset % $finfo->{meta}{blocksize}; | 
         | 
   188 	$length = min($finfo->{meta}{blocksize} - $blockoffset, $size); | 
         | 
   189   | 
         | 
   190 	# find the max length we can satisfy w/o colliding   | 
         | 
   191 	# with dirty blocks  | 
         | 
   192 	for (my $l = BS; $l < $length; $l += BS) { | 
         | 
   193 	    my $b = int(($offset + $l)/BS);  | 
         | 
   194 	    if ($DIRTY{$finfo . $b}) { | 
         | 
   195 		$length = $l;  | 
         | 
   196 		last;  | 
         | 
   197 	    }  | 
         | 
   198 	}  | 
         | 
   199   | 
         | 
   200 	$debug->("=== $length\n"); | 
         | 
   201 	$debug->("+++ disk offset:$block*$finfo->{meta}{blocksize} + $blockoffset size:$length\n"); | 
         | 
   202   | 
   163         my $fn = "$DATA/" . $finfo->{blocklist}{$block}; | 
   203         my $fn = "$DATA/" . $finfo->{blocklist}{$block}; | 
   164         if (-e $fn) { | 
   204   | 
   165             open(my $fh => $fn);  | 
   205 	state %cache;  | 
   166             binmode($fh);  | 
   206 	if (not defined $cache{fn}  | 
   167             seek($fh => $blockoffset, 0) or die "seek: $!";  | 
   207 	    or ($cache{fn} ne $fn)) { | 
   168             local $/ = \$length;  | 
   208   | 
   169             return scalar <$fh>;  | 
   209 	    if (-e $fn) { | 
   170         }  | 
   210 		open(my $fh => $fn);  | 
   171         elsif (-e "$fn.gz") { | 
   211 		binmode($fh);  | 
   172             open(my $fh => "$fn.gz");  | 
   212 		local $/ = undef;  | 
   173             binmode($fh);  | 
   213 		$cache{data} = <$fh>; | 
   174             my $buffer;  | 
   214 	    }  | 
   175             gunzip($fh => \$buffer)  | 
   215 	    elsif (-e "$fn.gz") { | 
   176               or die $GunzipError;  | 
   216 		open(my $fh => "$fn.gz");  | 
   177             close($fh);  | 
   217 		binmode($fh);  | 
   178             return substr($buffer, $blockoffset, $size);  | 
   218 		gunzip($fh => \$cache{data}) | 
   179         }  | 
   219 		      or die $GunzipError;  | 
   180   | 
   220 	    }  | 
   181         die "$fn: $!\n";  | 
   221 	    $cache{fn} = $fn; | 
         | 
   222 	}  | 
         | 
   223   | 
         | 
   224 	return substr($cache{data}, $blockoffset, $size); | 
         | 
   225 	die "$fn: $!\n";  | 
         | 
   226           | 
   182     }  | 
   227     }  | 
   183   | 
   228   | 
   184     sub writebuffer { | 
   229     sub writebuffer { | 
   185         my $path = $IDX . shift;  | 
   230         my $path = $IDX . shift;  | 
   186         my ($buffer, $offset) = @_;  | 
   231         my ($buffer, $offset) = @_;  | 
   199         return $size;  | 
   244         return $size;  | 
   200     }  | 
   245     }  | 
   201   | 
   246   | 
   202     sub _writeblock { | 
   247     sub _writeblock { | 
   203         my ($finfo, $buffer, $offset) = @_;  | 
   248         my ($finfo, $buffer, $offset) = @_;  | 
         | 
   249 	my ($block, $blockoffset, $length);  | 
   204         my $size = length($buffer);  | 
   250         my $size = length($buffer);  | 
   205   | 
   251   | 
   206         my $block       = int($offset / $finfo->{meta}{blocksize}); | 
   252 	$block = int($offset / BS);  | 
   207         my $blockoffset = $offset % $finfo->{meta}{blocksize}; | 
   253 	$blockoffset = $offset % BS;  | 
         | 
   254         $length = min(BS - $blockoffset, $size);  | 
         | 
   255   | 
         | 
   256 	$debug->(">>> offset:$offset size:$length of $size\n"); | 
         | 
   257 	$debug->("    block @{[int($offset/BS)]} + @{[$offset % BS]}\n"); | 
   208   | 
   258   | 
   209         if (not exists $DIRTY{ $finfo . $block }) { | 
   259         if (not exists $DIRTY{ $finfo . $block }) { | 
         | 
   260 	    $debug->("+++ missing $block+$blockoffset\n"); | 
   210             $DIRTY{ $finfo . $block } = _readblock( | 
   261             $DIRTY{ $finfo . $block } = _readblock( | 
   211                 $finfo,  | 
   262                 $finfo, BS, $block * BS);  | 
   212                 $finfo->{meta}{blocksize}, | 
   263         }  | 
   213                 $block * $finfo->{meta}{blocksize} | 
         | 
   214             );  | 
         | 
   215         }  | 
         | 
   216   | 
         | 
   217         my $length = $finfo->{meta}{blocksize} - $blockoffset; | 
         | 
   218         $length = $size if $size < $length;  | 
         | 
   219   | 
   264   | 
   220         substr($DIRTY{ $finfo . $block }, $blockoffset, $length) = | 
   265         substr($DIRTY{ $finfo . $block }, $blockoffset, $length) = | 
   221           substr($buffer, 0, $length);  | 
   266           substr($buffer, 0, $length);  | 
   222   | 
   267   | 
   223         return $length;  | 
   268         return $length;  |