73 lines
1.6 KiB
Go
73 lines
1.6 KiB
Go
|
package cpio
|
||
|
|
||
|
import (
|
||
|
"io"
|
||
|
"io/ioutil"
|
||
|
)
|
||
|
|
||
|
// A Reader provides sequential access to the contents of a CPIO archive. A CPIO
|
||
|
// archive consists of a sequence of files. The Next method advances to the next
|
||
|
// file in the archive (including the first), and then it can be treated as an
|
||
|
// io.Reader to access the file's data.
|
||
|
type Reader struct {
|
||
|
r io.Reader // underlying file reader
|
||
|
hdr *Header // current Header
|
||
|
eof int64 // bytes until the end of the current file
|
||
|
}
|
||
|
|
||
|
// NewReader creates a new Reader reading from r.
|
||
|
func NewReader(r io.Reader) *Reader {
|
||
|
return &Reader{
|
||
|
r: r,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Read reads from the current entry in the CPIO archive. It returns 0, io.EOF
|
||
|
// when it reaches the end of that entry, until Next is called to advance to the
|
||
|
// next entry.
|
||
|
func (r *Reader) Read(p []byte) (n int, err error) {
|
||
|
if r.hdr == nil || r.eof == 0 {
|
||
|
return 0, io.EOF
|
||
|
}
|
||
|
rn := len(p)
|
||
|
if r.eof < int64(rn) {
|
||
|
rn = int(r.eof)
|
||
|
}
|
||
|
n, err = r.r.Read(p[0:rn])
|
||
|
r.eof -= int64(n)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Next advances to the next entry in the CPIO archive.
|
||
|
// io.EOF is returned at the end of the input.
|
||
|
func (r *Reader) Next() (*Header, error) {
|
||
|
if r.hdr == nil {
|
||
|
return r.next()
|
||
|
}
|
||
|
skp := r.eof + r.hdr.pad
|
||
|
if skp > 0 {
|
||
|
_, err := io.CopyN(ioutil.Discard, r.r, skp)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
return r.next()
|
||
|
}
|
||
|
|
||
|
func (r *Reader) next() (*Header, error) {
|
||
|
r.eof = 0
|
||
|
hdr, err := readHeader(r.r)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
r.hdr = hdr
|
||
|
r.eof = hdr.Size
|
||
|
return hdr, nil
|
||
|
}
|
||
|
|
||
|
// ReadHeader creates a new Header, reading from r.
|
||
|
func readHeader(r io.Reader) (*Header, error) {
|
||
|
// currently only SVR4 format is supported
|
||
|
return readSVR4Header(r)
|
||
|
}
|