bin/imager.fuse
changeset 32 02ef2d1b190a
parent 31 221af7ffe050
parent 26 496ee9b0f488
child 35 bbdb8ea3079a
equal deleted inserted replaced
29:4a1820d504c4 32:02ef2d1b190a
    20     tmp    => undef,
    20     tmp    => undef,
    21 );
    21 );
    22 lock_keys %o;
    22 lock_keys %o;
    23 
    23 
    24 use constant ME => basename $0;
    24 use constant ME => basename $0;
       
    25 use constant BS => 4 * 1024;
       
    26 
    25 my ($DATA, $IDX);
    27 my ($DATA, $IDX);
    26 
    28 
    27 sub tie_vars;
    29 sub tie_vars;
       
    30 sub min { (sort {$a <=> $b} @_)[0] }
       
    31 sub max { (sort {$a <=> $b} @_)[-1] }
       
    32 my $debug = sub { print STDERR @_ };
       
    33    $debug = sub { };
       
    34 
       
    35 
       
    36 #$SIG{INT} = sub { warn "Got ^C or INT signal\n"; exit 1; };
    28 
    37 
    29 MAIN: {
    38 MAIN: {
    30 
    39 
    31     GetOptions(
    40     GetOptions(
    32         "d|debug!" => \$o{debug},
    41         "d|debug!" => \$o{debug},
    55     if (!$o{debug} and $o{detach}) {
    64     if (!$o{debug} and $o{detach}) {
    56         fork() and exit;
    65         fork() and exit;
    57         $0 = "FUSE $src $mp";
    66         $0 = "FUSE $src $mp";
    58         open(STDOUT => ">/dev/null");
    67         open(STDOUT => ">/dev/null");
    59         open(STDIN  => "/dev/null");
    68         open(STDIN  => "/dev/null");
    60 
       
    61         setpgid($$ => $$);
    69         setpgid($$ => $$);
    62     }
    70     }
    63 
    71 
    64     tie_vars $o{tmp};
    72     tie_vars $o{tmp};
    65 
    73 
    69         getattr    => \&getattr,
    77         getattr    => \&getattr,
    70         getdir     => \&getdir,
    78         getdir     => \&getdir,
    71         open       => \&openfile,
    79         open       => \&openfile,
    72         read       => \&readbuffer,
    80         read       => \&readbuffer,
    73         write      => \&writebuffer,
    81         write      => \&writebuffer,
       
    82 	release	   => \&release,
    74     );
    83     );
    75 
    84 
    76     exit;
    85     exit;
    77 
    86 
    78 }
    87 }
   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;