@@ -78,20 +78,21 @@ func getOptions(opts []Option) *options {
7878 return opt
7979}
8080
81- // volume extends a archiveBlockReader to be used across multiple
82- // files in a multi-volume archive
83- type volume struct {
81+ type volume interface {
82+ byteReader
83+ nextBlock () (* fileBlockHeader , error )
84+ }
85+
86+ type readerVolume struct {
8487 br * bufVolumeReader // buffered reader for current volume file
8588 n int64 // bytes left in current block
8689 num int // current volume number
8790 ver int // archive file format version
88- cl io.Closer
8991 arc archiveBlockReader
90- vm * volumeManager
9192 opt * options
9293}
9394
94- func (v * volume ) init (r io.Reader , volnum int ) error {
95+ func (v * readerVolume ) init (r io.Reader , volnum int ) error {
9596 var err error
9697 if v .br == nil {
9798 v .br , err = newBufVolumeReader (r , v .opt .bsize )
@@ -125,73 +126,25 @@ func (v *volume) init(r io.Reader, volnum int) error {
125126 return nil
126127}
127128
128- func (v * volume ) Close () error {
129- if v .cl != nil {
130- err := v .cl .Close ()
131- v .cl = nil
132- return err
133- }
134- return nil
135- }
136-
137- func (v * volume ) open (volnum int ) error {
138- if v .vm == nil {
139- return ErrFileNameRequired
140- }
141- err := v .Close ()
142- if err != nil {
143- return err
144- }
145- f , err := v .vm .openVolumeFile (volnum )
146- if err != nil {
147- return err
148- }
149- err = v .init (f , volnum )
150- if err != nil {
151- f .Close ()
152- return err
153- }
154- v .cl = f
155- return nil
156- }
157-
158- func (v * volume ) nextBlock () (* fileBlockHeader , error ) {
129+ func (v * readerVolume ) nextBlock () (* fileBlockHeader , error ) {
159130 if v .n > 0 {
160131 err := v .br .Discard (v .n )
161132 if err != nil {
162133 return nil , err
163134 }
135+ v .n = 0
164136 }
165- for {
166- f , err := v .arc .nextBlock (v .br )
167- if err == nil {
168- f .volnum = v .num
169- f .dataOff = v .br .off
170- v .n = f .PackedSize
171- return f , nil
172- }
173- nextVol := v .num + 1
174- if err == errVolumeEnd {
175- err = v .open (nextVol )
176- if err != nil {
177- return nil , err
178- }
179- } else if err == errVolumeOrArchiveEnd {
180- err = v .open (nextVol )
181- if err != nil {
182- // new volume doesnt exist, assume end of archive
183- if errors .Is (err , fs .ErrNotExist ) {
184- return nil , io .EOF
185- }
186- return nil , err
187- }
188- } else {
189- return nil , err
190- }
137+ f , err := v .arc .nextBlock (v .br )
138+ if err != nil {
139+ return nil , err
191140 }
141+ f .volnum = v .num
142+ f .dataOff = v .br .off
143+ v .n = f .PackedSize
144+ return f , nil
192145}
193146
194- func (v * volume ) Read (p []byte ) (int , error ) {
147+ func (v * readerVolume ) Read (p []byte ) (int , error ) {
195148 if v .n == 0 {
196149 return 0 , io .EOF
197150 }
@@ -206,7 +159,7 @@ func (v *volume) Read(p []byte) (int, error) {
206159 return n , err
207160}
208161
209- func (v * volume ) ReadByte () (byte , error ) {
162+ func (v * readerVolume ) ReadByte () (byte , error ) {
210163 if v .n == 0 {
211164 return 0 , io .EOF
212165 }
@@ -219,15 +172,69 @@ func (v *volume) ReadByte() (byte, error) {
219172 return b , err
220173}
221174
222- func newVolume (r io.Reader , opt * options , volnum int ) (* volume , error ) {
223- v := & volume {opt : opt }
175+ func newVolume (r io.Reader , opt * options , volnum int ) (* readerVolume , error ) {
176+ v := & readerVolume {opt : opt }
224177 err := v .init (r , volnum )
225178 if err != nil {
226179 return nil , err
227180 }
228181 return v , nil
229182}
230183
184+ type fileVolume struct {
185+ * readerVolume
186+ f fs.File
187+ vm * volumeManager
188+ }
189+
190+ func (v * fileVolume ) Close () error { return v .f .Close () }
191+
192+ func (v * fileVolume ) open (volnum int ) error {
193+ err := v .Close ()
194+ if err != nil {
195+ return err
196+ }
197+ f , err := v .vm .openVolumeFile (volnum )
198+ if err != nil {
199+ return err
200+ }
201+ err = v .readerVolume .init (f , volnum )
202+ if err != nil {
203+ f .Close ()
204+ return err
205+ }
206+ v .f = f
207+ return nil
208+ }
209+
210+ func (v * fileVolume ) openNext () error { return v .open (v .num + 1 ) }
211+
212+ func (v * fileVolume ) nextBlock () (* fileBlockHeader , error ) {
213+ for {
214+ h , err := v .readerVolume .nextBlock ()
215+ if err == nil {
216+ return h , nil
217+ }
218+ if err == ErrMultiVolume {
219+ err = v .openNext ()
220+ if err != nil {
221+ return nil , err
222+ }
223+ } else if err == errVolumeOrArchiveEnd {
224+ err = v .openNext ()
225+ if err != nil {
226+ // new volume doesnt exist, assume end of archive
227+ if errors .Is (err , fs .ErrNotExist ) {
228+ return nil , io .EOF
229+ }
230+ return nil , err
231+ }
232+ } else {
233+ return nil , err
234+ }
235+ }
236+ }
237+
231238func nextNewVolName (file string ) string {
232239 var inDigit bool
233240 var m []int
@@ -385,7 +392,7 @@ func (vm *volumeManager) openVolumeFile(volnum int) (fs.File, error) {
385392 return vm .opt .fs .Open (vm .dir + file )
386393}
387394
388- func (vm * volumeManager ) newVolume (volnum int ) (* volume , error ) {
395+ func (vm * volumeManager ) newVolume (volnum int ) (* fileVolume , error ) {
389396 f , err := vm .openVolumeFile (volnum )
390397 if err != nil {
391398 return nil , err
@@ -395,12 +402,15 @@ func (vm *volumeManager) newVolume(volnum int) (*volume, error) {
395402 f .Close ()
396403 return nil , err
397404 }
398- v .cl = f
399- v .vm = vm
400- return v , nil
405+ mv := & fileVolume {
406+ readerVolume : v ,
407+ f : f ,
408+ vm : vm ,
409+ }
410+ return mv , nil
401411}
402412
403- func (vm * volumeManager ) openBlockOffset (h * fileBlockHeader , offset int64 ) (* volume , error ) {
413+ func (vm * volumeManager ) openBlockOffset (h * fileBlockHeader , offset int64 ) (* fileVolume , error ) {
404414 v , err := vm .newVolume (h .volnum )
405415 if err != nil {
406416 return nil , err
@@ -436,7 +446,7 @@ func (vm *volumeManager) openArchiveFile(blocks *fileBlockList) (archiveFile, er
436446 return f , nil
437447}
438448
439- func openVolume (filename string , opts * options ) (* volume , error ) {
449+ func openVolume (filename string , opts * options ) (* fileVolume , error ) {
440450 dir , file := filepath .Split (filename )
441451 vm := & volumeManager {
442452 dir : dir ,
0 commit comments