More efficient Table reading
This commit is contained in:
+3
-1
@@ -7,7 +7,9 @@ import (
|
|||||||
"github.com/CalebQ42/squashfs/low/inode"
|
"github.com/CalebQ42/squashfs/low/inode"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r Reader) InodeFromRef(ref uint64) (inode.Inode, error) {
|
type InodeRef = uint64
|
||||||
|
|
||||||
|
func (r Reader) InodeFromRef(ref InodeRef) (inode.Inode, error) {
|
||||||
offset, meta := (ref>>16)+r.Superblock.InodeTableStart, ref&0xFFFF
|
offset, meta := (ref>>16)+r.Superblock.InodeTableStart, ref&0xFFFF
|
||||||
rdr := metadata.NewReader(toreader.NewReader(r.r, int64(offset)), r.d)
|
rdr := metadata.NewReader(toreader.NewReader(r.r, int64(offset)), r.d)
|
||||||
defer rdr.Close()
|
defer rdr.Close()
|
||||||
|
|||||||
+35
-5
@@ -34,7 +34,7 @@ type Reader struct {
|
|||||||
d decompress.Decompressor
|
d decompress.Decompressor
|
||||||
fragTable *Table[fragEntry]
|
fragTable *Table[fragEntry]
|
||||||
idTable *Table[uint32]
|
idTable *Table[uint32]
|
||||||
exportTable *Table[uint64]
|
exportTable *Table[InodeRef]
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewReader(r io.ReaderAt) (rdr Reader, err error) {
|
func NewReader(r io.ReaderAt) (rdr Reader, err error) {
|
||||||
@@ -78,12 +78,42 @@ func NewReader(r io.ReaderAt) (rdr Reader, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return rdr, errors.Join(errors.New("failed to read root directory"), err)
|
return rdr, errors.Join(errors.New("failed to read root directory"), err)
|
||||||
}
|
}
|
||||||
rdr.fragTable = NewTable[fragEntry](&rdr, rdr.Superblock.FragTableStart, rdr.Superblock.FragCount)
|
rdr.fragTable = NewTable(&rdr, rdr.Superblock.FragTableStart, rdr.Superblock.FragCount, readFrag)
|
||||||
rdr.idTable = NewTable[uint32](&rdr, rdr.Superblock.IdTableStart, uint32(rdr.Superblock.IdCount))
|
rdr.idTable = NewTable(&rdr, rdr.Superblock.IdTableStart, uint32(rdr.Superblock.IdCount), readId)
|
||||||
rdr.exportTable = NewTable[uint64](&rdr, rdr.Superblock.ExportTableStart, rdr.Superblock.InodeCount)
|
rdr.exportTable = NewTable(&rdr, rdr.Superblock.ExportTableStart, rdr.Superblock.InodeCount, readRef)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readFrag(r io.Reader) (fragEntry, error) {
|
||||||
|
dat := make([]byte, 16)
|
||||||
|
_, err := r.Read(dat)
|
||||||
|
if err != nil {
|
||||||
|
return fragEntry{}, err
|
||||||
|
}
|
||||||
|
return fragEntry{
|
||||||
|
Start: binary.LittleEndian.Uint64(dat[0:8]),
|
||||||
|
Size: binary.LittleEndian.Uint32(dat[8:12]),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readId(r io.Reader) (uint32, error) {
|
||||||
|
dat := make([]byte, 4)
|
||||||
|
_, err := r.Read(dat)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return binary.LittleEndian.Uint32(dat), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readRef(r io.Reader) (InodeRef, error) {
|
||||||
|
dat := make([]byte, 8)
|
||||||
|
_, err := r.Read(dat)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return binary.LittleEndian.Uint64(dat), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Get a uid/gid at the given index. Lazily populates the reader's Id table as necessary.
|
// Get a uid/gid at the given index. Lazily populates the reader's Id table as necessary.
|
||||||
func (r *Reader) Id(i uint16) (uint32, error) {
|
func (r *Reader) Id(i uint16) (uint32, error) {
|
||||||
return r.idTable.Get(uint32(i))
|
return r.idTable.Get(uint32(i))
|
||||||
@@ -95,7 +125,7 @@ func (r *Reader) fragEntry(i uint32) (fragEntry, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get an inode reference at the given index. Lazily populates the reader's export table as necessary.
|
// Get an inode reference at the given index. Lazily populates the reader's export table as necessary.
|
||||||
func (r *Reader) inodeRef(i uint32) (uint64, error) {
|
func (r *Reader) inodeRef(i uint32) (InodeRef, error) {
|
||||||
return r.exportTable.Get(i)
|
return r.exportTable.Get(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ type superblock struct {
|
|||||||
IdCount uint16
|
IdCount uint16
|
||||||
VerMaj uint16
|
VerMaj uint16
|
||||||
VerMin uint16
|
VerMin uint16
|
||||||
RootInodeRef uint64
|
RootInodeRef InodeRef
|
||||||
Size uint64
|
Size uint64
|
||||||
IdTableStart uint64
|
IdTableStart uint64
|
||||||
XattrTableStart uint64
|
XattrTableStart uint64
|
||||||
|
|||||||
+14
-7
@@ -3,6 +3,7 @@ package squashfslow
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/CalebQ42/squashfs/internal/metadata"
|
"github.com/CalebQ42/squashfs/internal/metadata"
|
||||||
@@ -13,6 +14,8 @@ var errOutOfBounds = errors.New("out of bounds")
|
|||||||
var errUnexpectedOutOfBounds = errors.New("unexpected out of bounds")
|
var errUnexpectedOutOfBounds = errors.New("unexpected out of bounds")
|
||||||
var errNilCollection = errors.New("nil collection")
|
var errNilCollection = errors.New("nil collection")
|
||||||
|
|
||||||
|
type CreateFunction[T any] = func(io.Reader) (T, error)
|
||||||
|
|
||||||
type Table[T any] struct {
|
type Table[T any] struct {
|
||||||
totalItems uint32
|
totalItems uint32
|
||||||
itemsPerBlock uint32
|
itemsPerBlock uint32
|
||||||
@@ -20,9 +23,10 @@ type Table[T any] struct {
|
|||||||
mut sync.RWMutex
|
mut sync.RWMutex
|
||||||
currentItems []T
|
currentItems []T
|
||||||
rdr *Reader
|
rdr *Reader
|
||||||
|
createFunc CreateFunction[T]
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTable[T any](rdr *Reader, start uint64, totalItems uint32) *Table[T] {
|
func NewTable[T any](rdr *Reader, start uint64, totalItems uint32, createFunc CreateFunction[T]) *Table[T] {
|
||||||
var zero T
|
var zero T
|
||||||
return &Table[T]{
|
return &Table[T]{
|
||||||
totalItems: totalItems,
|
totalItems: totalItems,
|
||||||
@@ -30,6 +34,7 @@ func NewTable[T any](rdr *Reader, start uint64, totalItems uint32) *Table[T] {
|
|||||||
offset: start,
|
offset: start,
|
||||||
mut: sync.RWMutex{},
|
mut: sync.RWMutex{},
|
||||||
rdr: rdr,
|
rdr: rdr,
|
||||||
|
createFunc: createFunc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,14 +70,16 @@ func (t *Table[T]) fillAndGet(requestedItemIndex uint32) (T, error) {
|
|||||||
}
|
}
|
||||||
t.offset += 8
|
t.offset += 8
|
||||||
toRead = min(t.itemsPerBlock, t.totalItems-uint32(len(t.currentItems)))
|
toRead = min(t.itemsPerBlock, t.totalItems-uint32(len(t.currentItems)))
|
||||||
new := make([]T, toRead)
|
oldLen := uint32(len(t.currentItems))
|
||||||
|
t.currentItems = append(t.currentItems, make([]T, toRead)...)
|
||||||
metaRdr = metadata.NewReader(toreader.NewReader(t.rdr.r, int64(offset)), t.rdr.d)
|
metaRdr = metadata.NewReader(toreader.NewReader(t.rdr.r, int64(offset)), t.rdr.d)
|
||||||
err = binary.Read(&metaRdr, binary.LittleEndian, new)
|
for i := range toRead {
|
||||||
if err != nil {
|
t.currentItems[oldLen+i], err = t.createFunc(&metaRdr)
|
||||||
var zero T
|
if err != nil {
|
||||||
return zero, err
|
var zero T
|
||||||
|
return zero, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
t.currentItems = append(t.currentItems, new...)
|
|
||||||
}
|
}
|
||||||
return t.currentItems[requestedItemIndex], nil
|
return t.currentItems[requestedItemIndex], nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user