Files
squashfs/filereader.go
T
Caleb Gardner 23ec7ea6dd First version of File interface.
This will allow you to easily find and extract files.
Extraction of whole folders coming next. (Maybe)
2020-11-27 00:36:21 -06:00

95 lines
2.2 KiB
Go

package squashfs
import (
"bytes"
"errors"
"io"
"github.com/CalebQ42/squashfs/internal/inode"
)
//FileReader provides a io.Reader interface for files within a squashfs archive
type fileReader struct {
r *Reader
data *dataReader
in *inode.Inode
fragmentData []byte
fragged bool
fragOnly bool
read int
FileSize int //FileSize is the total size of the given file
}
var (
//ErrPathIsNotFile returns when trying to read from a file, but the given path is NOT a file.
ErrPathIsNotFile = errors.New("The given path is not a file")
)
//ReadFile provides a squashfs.FileReader for the file at the given location.
func (r *Reader) newFileReader(in *inode.Inode) (*fileReader, error) {
var rdr fileReader
rdr.in = in
if in.Type != inode.BasicFileType && in.Type != inode.ExtFileType {
return nil, ErrPathIsNotFile
}
switch in.Type {
case inode.BasicFileType:
fil := in.Info.(inode.BasicFile)
rdr.fragged = fil.Fragmented
rdr.fragOnly = fil.Init.BlockStart == 0
rdr.FileSize = int(fil.Init.Size)
case inode.ExtFileType:
fil := in.Info.(inode.ExtendedFile)
rdr.fragged = fil.Fragmented
rdr.fragOnly = fil.Init.BlockStart == 0
rdr.FileSize = int(fil.Init.Size)
}
var err error
if rdr.fragged {
rdr.fragmentData, err = r.getFragmentDataFromInode(in)
if err != nil {
return nil, err
}
}
if !rdr.fragOnly {
rdr.data, err = r.newDataReaderFromInode(in)
}
return &rdr, nil
}
//Close runs Close on the data reader and frees the fragmentdata
func (f *fileReader) Close() error {
if f.data != nil {
f.data.Close()
}
f.fragmentData = nil
return nil
}
func (f *fileReader) Read(p []byte) (int, error) {
if f.fragOnly {
n, err := bytes.NewBuffer(f.fragmentData[f.read:]).Read(p)
f.read += n
if err != nil {
return n, err
}
return n, nil
}
var read int
n, err := f.data.Read(p)
read += n
if f.fragged && err == io.EOF {
if f.fragmentData == nil {
f.fragmentData, err = f.r.getFragmentDataFromInode(f.in)
}
n, err = bytes.NewBuffer(f.fragmentData).Read(p[read:])
read += n
if err != nil {
return read, err
}
} else if err != nil {
return read, err
}
return read, nil
}