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( |
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); |