bin/imager.fuse
changeset 118 8c2cc26d45fc
parent 115 0d4074ac2eee
equal deleted inserted replaced
117:136d6b9b5a67 118:8c2cc26d45fc
    12 use Hash::Util qw(lock_keys);
    12 use Hash::Util qw(lock_keys);
    13 use File::Temp;
    13 use File::Temp;
    14 use DB_File;
    14 use DB_File;
    15 use File::Basename;
    15 use File::Basename;
    16 use Imager;
    16 use Imager;
       
    17 use Smart::Comments;
    17 
    18 
    18 my %o = (
    19 my %o = (
    19     debug  => undef,
    20     debug  => undef,
    20     detach => 1,
    21     detach => 1,
    21     tmp    => undef,
    22     tmp    => undef,
    36 }
    37 }
    37 
    38 
    38 sub max {
    39 sub max {
    39     (sort { $a <=> $b } @_)[-1];
    40     (sort { $a <=> $b } @_)[-1];
    40 }
    41 }
    41 my $debug = sub { print STDERR @_ };
    42 
    42 $debug = sub { };
    43 sub nop_debug { }
       
    44 sub yes_debug { print STDERR @_ }
       
    45 
       
    46 *{main::debug} = \&nop_debug;
    43 
    47 
    44 #$SIG{INT} = sub { warn "Got ^C or INT signal\n"; exit 1; };
    48 #$SIG{INT} = sub { warn "Got ^C or INT signal\n"; exit 1; };
    45 
    49 
    46 MAIN: {
    50 MAIN: {
    47 
    51 
    48     GetOptions(
    52     GetOptions(
    49         "d|debug!" => \$o{debug},
    53         "d|debug!" => \$o{debug},
    50         "detach!"  => \$o{detach},
    54         "detach!"   => \$o{detach},
    51         "tmp:s" => sub { $o{tmp} = length $_[1] ? $_[1] : $ENV{TMP} // "/tmp" },
    55         "tmp:s" => sub { $o{tmp} = length $_[1] ? $_[1] : $ENV{TMP} // "/tmp" },
    52         "h|help"   => sub { pod2usage(-verbose => 1, -exit => 0) },
    56         "h|help"   => sub { pod2usage(-verbose => 1, -exit => 0) },
    53         "p|pass=s" => \$o{pass},
    57         "p|pass=s" => \$o{pass},
    54         "m|man"    => sub {
    58         "m|man"    => sub {
    55             pod2usage(
    59             pod2usage(
    60         },
    64         },
    61       )
    65       )
    62       and @ARGV == 2
    66       and @ARGV == 2
    63       or pod2usage;
    67       or pod2usage;
    64 
    68 
       
    69     if ($o{debug}) {
       
    70         undef &{main::debug};
       
    71         *{main::debug} = \&yes_debug;
       
    72     }
       
    73 
    65     my ($src, $mp) = @ARGV;
    74     my ($src, $mp) = @ARGV;
    66 
    75 
    67     $DATA = "$src/data";
    76     $DATA = "$src/data";
    68     $IDX  = "$src/idx";
    77     $IDX  = "$src/idx";
    69 
    78 
    80 
    89 
    81     tie_vars $o{tmp};
    90     tie_vars $o{tmp};
    82 
    91 
    83     Fuse::main(
    92     Fuse::main(
    84         mountpoint => $mp,
    93         mountpoint => $mp,
    85         debug      => $o{debug} // 0,
    94 
    86         getattr    => \&getattr,
    95         #   debug      => $o{debug} // 0,
    87         getdir     => \&getdir,
    96         getattr => \&getattr,
    88         open       => \&openfile,
    97         getdir  => \&getdir,
    89         read       => \&readbuffer,
    98         open    => \&openfile,
    90         write      => \&writebuffer,
    99         read    => \&readbuffer,
    91         release    => \&release,
   100         write   => \&writebuffer,
       
   101         release => \&release,
    92     );
   102     );
    93 
   103 
    94     exit;
   104     exit;
    95 
   105 
    96 }
   106 }
   152     }
   162     }
   153 
   163 
   154     sub release {
   164     sub release {
   155         my $path = $IDX . shift;
   165         my $path = $IDX . shift;
   156         return 0 if not exists $IMAGE{$path};
   166         return 0 if not exists $IMAGE{$path};
   157         $debug->("Currently we have " . keys(%DIRTY) . " dirty blocks\n");
   167         debug("Currently we have " . keys(%DIRTY) . " dirty blocks\n");
   158         return 0;
   168         return 0;
   159     }
   169     }
   160 
   170 
   161     sub readbuffer {
   171     sub readbuffer {
   162         my $path = $IDX . shift;
   172         my $path = $IDX . shift;
   163         my ($size, $offset) = @_;
   173         my ($size, $offset) = @_;
   164         my $finfo = $IMAGE{$path} or die "File $path is not opened!";
   174         my $finfo = $IMAGE{$path} or die "File $path is not opened!";
   165         return "" if $offset >= $finfo->{meta}{devsize};
   175         return "" if $offset >= $finfo->{meta}{devsize};
   166 
   176 
       
   177 	debug("<<< REQUESTED: offset:$offset size:$size\n");
       
   178 
   167         my $buffer = "";
   179         my $buffer = "";
   168         for (my $need = $size ; $need > 0 ; $need = $size - length($buffer)) {
   180         for (my $need = $size ; $need > 0 ; $need = $size - length($buffer)) {
       
   181 	    debug("<<<            offset:@{[$offset + length($buffer)]} size:$need\n");
   169             $buffer .= _readblock($finfo, $need, $offset + length($buffer));
   182             $buffer .= _readblock($finfo, $need, $offset + length($buffer));
   170         }
   183 	    debug("<<< missing: ", $size - length($buffer), "\n") if $size - length($buffer);
   171 
   184         }
       
   185 
       
   186 	debug("<<< SENDING " . length($buffer) . "\n\n");
   172         return $buffer;
   187         return $buffer;
   173     }
   188     }
   174 
   189 
   175     sub _readblock {
   190     sub _readblock {
   176         my ($finfo, $size, $offset) = @_;
   191         my ($finfo, $size, $offset) = @_;
   177         my ($block, $blockoffset, $length);
   192         my ($block, $blockoffset, $length);
   178 
   193 
   179         $debug->("<<< block offset:$offset size:$size\n");
   194         debug("<<< requested: offset:$offset size:$size"
   180         $debug->("    block @{[int($offset/BS)]} + @{[$offset % BS]}\n");
   195 	    . "\tfrom $finfo->{meta}{filesystem}\n");
       
   196         debug("    mapped to:  block:@{[int($offset/BS)]}+@{[$offset % BS]}\n");
   181 
   197 
   182         # first check if it's an dirty block
   198         # first check if it's an dirty block
   183         $block = int($offset / BS);
   199         $block = int($offset / BS);
   184         if (exists $DIRTY{ $finfo . $block }) {
   200         if (exists $DIRTY{ $finfo . $block }) {
   185             $blockoffset = $offset % BS;
   201             $blockoffset = $offset % BS;
   186             $length = min(BS - $blockoffset, $size);
   202             $length = min(BS - $blockoffset, $size);
   187 
   203 
   188             $debug->(
   204             debug(
   189                 "+++ dirty offset:$block*@{[BS]} + $blockoffset size:$length\n"
   205                 "+++ dirty offset:$block*@{[BS]} + $blockoffset size:$length\n"
   190             );
   206             );
   191             return substr $DIRTY{ $finfo . $block }, $blockoffset, $length;
   207             return substr $DIRTY{ $finfo . $block }, $blockoffset, $length;
   192         }
   208         }
   193 
   209 
   205                 $length = $l;
   221                 $length = $l;
   206                 last;
   222                 last;
   207             }
   223             }
   208         }
   224         }
   209 
   225 
   210         $debug->("=== $length\n");
   226         debug("+++ disk  offset:$block*$finfo->{meta}{blocksize}"
   211         $debug->(
   227             . " + $blockoffset size:$length\n");
   212 "+++ disk offset:$block*$finfo->{meta}{blocksize} + $blockoffset size:$length\n"
   228 
   213         );
   229 #    die if $blockoffset == 417792;
   214 
   230 
   215         my $fn = "$DATA/" . $finfo->{blocklist}{$block};
   231         my $fn = "$DATA/" . $finfo->{blocklist}{$block};
       
   232 	debug("    fn:$fn\n");
   216 
   233 
   217         state %cache;
   234         state %cache;
   218         if (not defined $cache{fn}
   235         if (not defined $cache{fn}
   219             or ($cache{fn} ne $fn))
   236             or ($cache{fn} ne $fn))
   220         {
   237         {
   221 	    Imager::get_block("$fn*" => \$cache{data});
   238             Imager::get_block("$fn*" => \$cache{data});
   222             $cache{fn} = $fn;
   239             $cache{fn} = $fn;
   223         }
   240         }
   224 
   241 
   225         return substr($cache{data}, $blockoffset, $length);
   242         return substr($cache{data}, $blockoffset, $length);
   226 
   243 
   251 
   268 
   252         $block       = int($offset / BS);
   269         $block       = int($offset / BS);
   253         $blockoffset = $offset % BS;
   270         $blockoffset = $offset % BS;
   254         $length      = min(BS - $blockoffset, $size);
   271         $length      = min(BS - $blockoffset, $size);
   255 
   272 
   256         $debug->(">>> offset:$offset size:$length of $size\n");
   273         debug(">>> offset:$offset size:$length of $size\n");
   257         $debug->("    block @{[int($offset/BS)]} + @{[$offset % BS]}\n");
   274         debug("    block @{[int($offset/BS)]} + @{[$offset % BS]}\n");
   258 
   275 
   259         if (not exists $DIRTY{ $finfo . $block }) {
   276         if (not exists $DIRTY{ $finfo . $block }) {
   260             $debug->("+++ missing $block+$blockoffset\n");
   277             debug("+++ missing $block+$blockoffset\n");
   261             $DIRTY{ $finfo . $block } = _readblock($finfo, BS, $block * BS);
   278             $DIRTY{ $finfo . $block } = _readblock($finfo, BS, $block * BS);
   262         }
   279         }
   263 
   280 
   264         substr($DIRTY{ $finfo . $block }, $blockoffset, $length) =
   281         substr($DIRTY{ $finfo . $block }, $blockoffset, $length) =
   265           substr($buffer, 0, $length);
   282           substr($buffer, 0, $length);
   272         my %meta;
   289         my %meta;
   273         open(my $fh => $path);
   290         open(my $fh => $path);
   274         while (<$fh>) {
   291         while (<$fh>) {
   275             last if /^$/;
   292             last if /^$/;
   276             /^(?<k>\S+):\s+(?:(?<n>\d+)|(?<v>.*?))\s*$/
   293             /^(?<k>\S+):\s+(?:(?<n>\d+)|(?<v>.*?))\s*$/
   277               and do { 
   294               and do {
   278 	      	# na sowas, die Zeitstempel dürfen nicht als Zeichenkette reinkommen!
   295 
   279 	      	$meta{ $+{k} } = defined $+{n} ? (0+$+{n}) : $+{v};
   296           # na sowas, die Zeitstempel dürfen nicht als Zeichenkette reinkommen!
   280 		next; 
   297                 $meta{ $+{k} } = defined $+{n} ? (0 + $+{n}) : $+{v};
   281 	      };
   298                 next;
       
   299               };
   282         }
   300         }
   283         return %meta;
   301         return %meta;
   284     }
   302     }
   285 
   303 
   286 }
   304 }