63 use POSIX qw(:errno_h); |
63 use POSIX qw(:errno_h); |
64 use IO::Uncompress::Gunzip qw(gunzip $GunzipError); |
64 use IO::Uncompress::Gunzip qw(gunzip $GunzipError); |
65 use autodie qw(:all); |
65 use autodie qw(:all); |
66 |
66 |
67 our ($ROOT, $DATA, $IDX); |
67 our ($ROOT, $DATA, $IDX); |
68 my %FILE; |
68 my %IMAGE; |
69 my %CACHE; |
69 my %DIRTY; |
70 |
70 |
71 sub getattr { |
71 sub getattr { |
72 my $path = $IDX . shift; |
72 my $path = $IDX . shift; |
73 return stat $path if -d $path; |
73 return stat $path if -d $path; |
74 # rest are the idx |
74 # rest are the idx |
86 return (readdir($dh), 0); |
86 return (readdir($dh), 0); |
87 } |
87 } |
88 |
88 |
89 sub openfile { |
89 sub openfile { |
90 my $path = $IDX . shift; |
90 my $path = $IDX . shift; |
91 return 0 if exists $FILE{$path}; |
91 return 0 if exists $IMAGE{$path}; |
92 $FILE{$path}{meta} = { _get_meta($path) }; |
92 $IMAGE{$path}{meta} = { _get_meta($path) }; |
93 $FILE{$path}{blocklist} = {}; |
93 $IMAGE{$path}{blocklist} = {}; |
94 |
94 |
95 open(my $fh => $path); |
95 open(my $fh => $path); |
96 { # the file header |
96 { # the file header |
97 local $/ = ""; |
97 local $/ = ""; |
98 scalar <$fh>; |
98 scalar <$fh>; |
99 } |
99 } |
100 while (<$fh>) { |
100 while (<$fh>) { |
101 /^#/ and last; |
101 /^#/ and last; |
102 my ($block, $cs, $file) = split; |
102 my ($block, $cs, $file) = split; |
103 $block-- if not $FILE{$path}{meta}{format}; |
103 $block-- if not $IMAGE{$path}{meta}{format}; |
104 $FILE{$path}{blocklist}{$block} = $file; |
104 $IMAGE{$path}{blocklist}{$block} = $file; |
105 } |
105 } |
106 close $fh; |
106 close $fh; |
107 return 0; |
107 return 0; |
108 } |
108 } |
109 |
109 |
110 sub readbuffer { |
110 sub readbuffer { |
111 my $path = $IDX . shift; |
111 my $path = $IDX . shift; |
112 my ($size, $offset) = @_; |
112 my ($size, $offset) = @_; |
113 my $finfo = $FILE{$path} or die "File $path is not opened!"; |
113 my $finfo = $IMAGE{$path} or die "File $path is not opened!"; |
114 return "" if $offset >= $finfo->{meta}{devsize}; |
114 return "" if $offset >= $finfo->{meta}{devsize}; |
115 |
115 |
116 my $buffer = ""; |
116 my $buffer = ""; |
117 for (my $need = $size; $need > 0; $need = $size - length($buffer)) { |
117 for (my $need = $size; $need > 0; $need = $size - length($buffer)) { |
118 $buffer .= _readblock($finfo, $need, $offset + length($buffer)); |
118 $buffer .= _readblock($finfo, $need, $offset + length($buffer)); |
128 my $blockoffset = $offset % $finfo->{meta}{blocksize}; |
128 my $blockoffset = $offset % $finfo->{meta}{blocksize}; |
129 |
129 |
130 my $length = $finfo->{meta}{blocksize} - $blockoffset; |
130 my $length = $finfo->{meta}{blocksize} - $blockoffset; |
131 $length = $size if $size <= $length; |
131 $length = $size if $size <= $length; |
132 |
132 |
133 if (exists $CACHE{$finfo}{$block}) { |
133 if (exists $DIRTY{$finfo}{$block}) { |
134 return substr $CACHE{$finfo}{$block}, $blockoffset, $length; |
134 return substr $DIRTY{$finfo}{$block}, $blockoffset, $length; |
135 } |
135 } |
136 |
136 |
137 my $fn = "$DATA/" . $finfo->{blocklist}{$block}; |
137 my $fn = "$DATA/" . $finfo->{blocklist}{$block}; |
138 if (-e $fn) { |
138 if (-e $fn) { |
139 open(my $fh => $fn); |
139 open(my $fh => $fn); |
157 |
157 |
158 sub writebuffer { |
158 sub writebuffer { |
159 my $path = $IDX . shift; |
159 my $path = $IDX . shift; |
160 my ($buffer, $offset) = @_; |
160 my ($buffer, $offset) = @_; |
161 my $size = length($buffer); |
161 my $size = length($buffer); |
162 my $finfo = $FILE{$path} or die "File $path is not opened!"; |
162 my $finfo = $IMAGE{$path} or die "File $path is not opened!"; |
163 |
163 |
164 for (my $written = 0; $written < $size;) { |
164 for (my $written = 0; $written < $size;) { |
165 # OPTIMIZE: we should not ask for writing more than the |
165 # OPTIMIZE: we should not ask for writing more than the |
166 # blocksize |
166 # blocksize |
167 my $n = _writeblock($finfo, substr($buffer, $written), $offset + $written) |
167 my $n = _writeblock($finfo, substr($buffer, $written), $offset + $written) |
176 my $size = length($buffer); |
176 my $size = length($buffer); |
177 |
177 |
178 my $block = int($offset / $finfo->{meta}{blocksize}); |
178 my $block = int($offset / $finfo->{meta}{blocksize}); |
179 my $blockoffset = $offset % $finfo->{meta}{blocksize}; |
179 my $blockoffset = $offset % $finfo->{meta}{blocksize}; |
180 |
180 |
181 if (not exists $CACHE{$finfo}{$block}) { |
181 if (not exists $DIRTY{$finfo}{$block}) { |
182 #open(my $fh => "$DATA/" . $finfo->{blocklist}{$block}); |
182 $DIRTY{$finfo}{$block} = _readblock( |
183 #local $/ = undef; |
183 $finfo, |
184 #$CACHE{$finfo}{$block} = <$fh>; |
184 $finfo->{meta}{blocksize}, |
185 #close($fh); |
185 $block * $finfo->{meta}{blocksize}); |
186 $CACHE{$finfo}{$block} = _readblock($finfo, $finfo->{meta}{blocksize}, $block * $finfo->{meta}{blocksize}); |
|
187 } |
186 } |
188 |
187 |
189 my $length = $finfo->{meta}{blocksize} - $blockoffset; |
188 my $length = $finfo->{meta}{blocksize} - $blockoffset; |
190 $length = $size if $size < $length; |
189 $length = $size if $size < $length; |
191 |
190 |
192 substr($CACHE{$finfo}{$block}, $blockoffset, $length) |
191 substr($DIRTY{$finfo}{$block}, $blockoffset, $length) |
193 = substr($buffer, 0, $length); |
192 = substr($buffer, 0, $length); |
194 |
193 |
195 return $length; |
194 return $length; |
196 } |
195 } |
197 |
196 |