6224c4be41
Further removed multiple pointer instances Re-use decompression readers (except zstd due to bugs)
204 lines
6.5 KiB
Go
204 lines
6.5 KiB
Go
package squashfslow
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
|
|
"github.com/CalebQ42/squashfs/internal/metadata"
|
|
"github.com/CalebQ42/squashfs/internal/toreader"
|
|
"github.com/CalebQ42/squashfs/low/data"
|
|
"github.com/CalebQ42/squashfs/low/directory"
|
|
"github.com/CalebQ42/squashfs/low/inode"
|
|
)
|
|
|
|
type FileBase struct {
|
|
Inode inode.Inode
|
|
Name string
|
|
}
|
|
|
|
func (r Reader) BaseFromInode(i inode.Inode, name string) FileBase {
|
|
return FileBase{Inode: i, Name: name}
|
|
}
|
|
|
|
func (r Reader) BaseFromEntry(e directory.Entry) (FileBase, error) {
|
|
in, err := r.InodeFromEntry(e)
|
|
if err != nil {
|
|
return FileBase{}, err
|
|
}
|
|
return FileBase{Inode: in, Name: e.Name}, nil
|
|
}
|
|
|
|
func (r Reader) BaseFromRef(ref uint64, name string) (FileBase, error) {
|
|
in, err := r.InodeFromRef(ref)
|
|
if err != nil {
|
|
return FileBase{}, err
|
|
}
|
|
return FileBase{Inode: in, Name: name}, nil
|
|
}
|
|
|
|
func (b FileBase) Uid(r *Reader) (uint32, error) {
|
|
return r.Id(b.Inode.UidInd)
|
|
}
|
|
|
|
func (b FileBase) Gid(r *Reader) (uint32, error) {
|
|
return r.Id(b.Inode.GidInd)
|
|
}
|
|
|
|
func (b FileBase) IsDir() bool {
|
|
return b.Inode.Type == inode.Dir || b.Inode.Type == inode.EDir
|
|
}
|
|
|
|
func (b FileBase) ToDir(r Reader) (Directory, error) {
|
|
var blockStart uint32
|
|
var size uint32
|
|
var offset uint16
|
|
switch b.Inode.Type {
|
|
case inode.Dir:
|
|
blockStart = b.Inode.Data.(inode.Directory).BlockStart
|
|
size = uint32(b.Inode.Data.(inode.Directory).Size)
|
|
offset = b.Inode.Data.(inode.Directory).Offset
|
|
case inode.EDir:
|
|
blockStart = b.Inode.Data.(inode.EDirectory).BlockStart
|
|
size = b.Inode.Data.(inode.EDirectory).Size
|
|
offset = b.Inode.Data.(inode.EDirectory).Offset
|
|
default:
|
|
return Directory{}, errors.New("not a directory")
|
|
}
|
|
dirRdr := metadata.NewReader(toreader.NewReader(r.r, int64(r.Superblock.DirTableStart)+int64(blockStart)), r.d)
|
|
defer dirRdr.Close()
|
|
_, err := dirRdr.Read(make([]byte, offset))
|
|
if err != nil {
|
|
return Directory{}, err
|
|
}
|
|
entries, err := directory.ReadDirectory(&dirRdr, size)
|
|
if err != nil {
|
|
return Directory{}, err
|
|
}
|
|
return Directory{
|
|
FileBase: b,
|
|
Entries: entries,
|
|
}, nil
|
|
}
|
|
|
|
func (b FileBase) IsRegular() bool {
|
|
return b.Inode.Type == inode.Fil || b.Inode.Type == inode.EFil
|
|
}
|
|
|
|
func (b FileBase) GetRegFileReaders(r Reader) (data.Reader, data.FullReader, error) {
|
|
if !b.IsRegular() {
|
|
return data.Reader{}, data.FullReader{}, errors.New("not a regular file")
|
|
}
|
|
var blockStart uint64
|
|
var fragIndex uint32
|
|
var fragOffset uint32
|
|
var fragSize uint64
|
|
var sizes []uint32
|
|
if b.Inode.Type == inode.Fil {
|
|
blockStart = uint64(b.Inode.Data.(inode.File).BlockStart)
|
|
fragIndex = b.Inode.Data.(inode.File).FragInd
|
|
fragOffset = b.Inode.Data.(inode.File).FragOffset
|
|
sizes = b.Inode.Data.(inode.File).BlockSizes
|
|
fragSize = uint64(b.Inode.Data.(inode.File).Size % r.Superblock.BlockSize)
|
|
} else {
|
|
blockStart = b.Inode.Data.(inode.EFile).BlockStart
|
|
fragIndex = b.Inode.Data.(inode.EFile).FragInd
|
|
fragOffset = b.Inode.Data.(inode.EFile).FragOffset
|
|
sizes = b.Inode.Data.(inode.EFile).BlockSizes
|
|
fragSize = b.Inode.Data.(inode.EFile).Size % uint64(r.Superblock.BlockSize)
|
|
}
|
|
frag := func() (io.Reader, error) {
|
|
ent, err := r.fragEntry(fragIndex)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
frag := data.NewReader(toreader.NewReader(r.r, int64(ent.Start)), r.d, []uint32{ent.Size}, uint64(r.Superblock.BlockSize), r.Superblock.BlockSize)
|
|
frag.Read(make([]byte, fragOffset))
|
|
return io.LimitReader(&frag, int64(fragSize)), nil
|
|
}
|
|
outRdr := data.NewReader(toreader.NewReader(r.r, int64(blockStart)), r.d, sizes, fragSize, r.Superblock.BlockSize)
|
|
if fragIndex != 0xffffffff {
|
|
f, err := frag()
|
|
if err != nil {
|
|
return data.Reader{}, data.FullReader{}, err
|
|
}
|
|
outRdr.AddFrag(f)
|
|
}
|
|
outFull := data.NewFullReader(r.r, int64(blockStart), r.d, sizes, fragSize, r.Superblock.BlockSize)
|
|
if fragIndex != 0xffffffff {
|
|
outFull.AddFrag(frag)
|
|
}
|
|
return outRdr, outFull, nil
|
|
}
|
|
|
|
func (b FileBase) GetFullReader(r *Reader) (data.FullReader, error) {
|
|
if !b.IsRegular() {
|
|
return data.FullReader{}, errors.New("not a regular file")
|
|
}
|
|
var blockStart uint64
|
|
var fragIndex uint32
|
|
var fragOffset uint32
|
|
var fragSize uint64
|
|
var sizes []uint32
|
|
if b.Inode.Type == inode.Fil {
|
|
blockStart = uint64(b.Inode.Data.(inode.File).BlockStart)
|
|
fragIndex = b.Inode.Data.(inode.File).FragInd
|
|
fragOffset = b.Inode.Data.(inode.File).FragOffset
|
|
sizes = b.Inode.Data.(inode.File).BlockSizes
|
|
fragSize = uint64(b.Inode.Data.(inode.File).Size % r.Superblock.BlockSize)
|
|
} else {
|
|
blockStart = b.Inode.Data.(inode.EFile).BlockStart
|
|
fragIndex = b.Inode.Data.(inode.EFile).FragInd
|
|
fragOffset = b.Inode.Data.(inode.EFile).FragOffset
|
|
sizes = b.Inode.Data.(inode.EFile).BlockSizes
|
|
fragSize = b.Inode.Data.(inode.EFile).Size % uint64(r.Superblock.BlockSize)
|
|
}
|
|
outFull := data.NewFullReader(r.r, int64(blockStart), r.d, sizes, fragSize, r.Superblock.BlockSize)
|
|
if fragIndex != 0xffffffff {
|
|
outFull.AddFrag(func() (io.Reader, error) {
|
|
ent, err := r.fragEntry(fragIndex)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
frag := data.NewReader(toreader.NewReader(r.r, int64(ent.Start)), r.d, []uint32{ent.Size}, uint64(r.Superblock.BlockSize), r.Superblock.BlockSize)
|
|
frag.Read(make([]byte, fragOffset))
|
|
return io.LimitReader(&frag, int64(fragSize)), nil
|
|
})
|
|
}
|
|
return outFull, nil
|
|
}
|
|
|
|
func (b FileBase) GetReader(r *Reader) (data.Reader, error) {
|
|
if !b.IsRegular() {
|
|
return data.Reader{}, errors.New("not a regular file")
|
|
}
|
|
var blockStart uint64
|
|
var fragIndex uint32
|
|
var fragOffset uint32
|
|
var fragSize uint64
|
|
var sizes []uint32
|
|
if b.Inode.Type == inode.Fil {
|
|
blockStart = uint64(b.Inode.Data.(inode.File).BlockStart)
|
|
fragIndex = b.Inode.Data.(inode.File).FragInd
|
|
fragOffset = b.Inode.Data.(inode.File).FragOffset
|
|
sizes = b.Inode.Data.(inode.File).BlockSizes
|
|
fragSize = uint64(b.Inode.Data.(inode.File).Size % r.Superblock.BlockSize)
|
|
} else {
|
|
blockStart = b.Inode.Data.(inode.EFile).BlockStart
|
|
fragIndex = b.Inode.Data.(inode.EFile).FragInd
|
|
fragOffset = b.Inode.Data.(inode.EFile).FragOffset
|
|
sizes = b.Inode.Data.(inode.EFile).BlockSizes
|
|
fragSize = b.Inode.Data.(inode.EFile).Size % uint64(r.Superblock.BlockSize)
|
|
}
|
|
outRdr := data.NewReader(toreader.NewReader(r.r, int64(blockStart)), r.d, sizes, fragSize, r.Superblock.BlockSize)
|
|
if fragIndex != 0xffffffff {
|
|
ent, err := r.fragEntry(fragIndex)
|
|
if err != nil {
|
|
return data.Reader{}, err
|
|
}
|
|
frag := data.NewReader(toreader.NewReader(r.r, int64(ent.Start)), r.d, []uint32{ent.Size}, uint64(r.Superblock.BlockSize), r.Superblock.BlockSize)
|
|
frag.Read(make([]byte, fragOffset))
|
|
outRdr.AddFrag(io.LimitReader(&frag, int64(fragSize)))
|
|
}
|
|
return outRdr, nil
|
|
}
|