Working on fragments
This commit is contained in:
@@ -17,17 +17,17 @@ Thanks also to [distri's squashfs library](https://github.com/distr1/distri/tree
|
|||||||
|
|
||||||
# Not Working (Yet). Roughly in order.
|
# Not Working (Yet). Roughly in order.
|
||||||
|
|
||||||
* Give a list of files
|
|
||||||
* In io.FileStat (?) form
|
|
||||||
* Figure out fragments
|
* Figure out fragments
|
||||||
* Extracting files
|
* Extracting files
|
||||||
* from inodes.
|
* from inodes.
|
||||||
* from path.
|
* from path.
|
||||||
* from file info.
|
* from file info.
|
||||||
|
* Give a list of files
|
||||||
|
* In io.FileStat (?) form
|
||||||
* Reading the UID, GUID, Xatt, Compression Options, Export, and Fragment tables.
|
* Reading the UID, GUID, Xatt, Compression Options, Export, and Fragment tables.
|
||||||
* Implement other compression types (Should be relatively easy)
|
* Implement other compression types (Should be relatively easy)
|
||||||
* Squashing
|
* Squashing
|
||||||
|
|
||||||
# Where I'm at.
|
# Where I'm at.
|
||||||
|
|
||||||
* Working on reading data blocks
|
* Reading fragments does not seem to be working right now
|
||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -67,6 +68,7 @@ func (br *BlockReader) parseMetadata() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (br *BlockReader) readNextDataBlock() error {
|
func (br *BlockReader) readNextDataBlock() error {
|
||||||
|
fmt.Println("reading new block")
|
||||||
meta := br.headers[len(br.headers)-1]
|
meta := br.headers[len(br.headers)-1]
|
||||||
r := io.NewSectionReader(br.s.r, br.offset, int64(meta.size))
|
r := io.NewSectionReader(br.s.r, br.offset, int64(meta.size))
|
||||||
if meta.compressed {
|
if meta.compressed {
|
||||||
|
|||||||
+7
-32
@@ -6,6 +6,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//DataReader reads data from data blocks.
|
||||||
type DataReader struct {
|
type DataReader struct {
|
||||||
r *Reader
|
r *Reader
|
||||||
offset int64 //offset relative to the beginning of the squash file
|
offset int64 //offset relative to the beginning of the squash file
|
||||||
@@ -13,9 +14,9 @@ type DataReader struct {
|
|||||||
curBlock int //Which block in sizes is currently cached
|
curBlock int //Which block in sizes is currently cached
|
||||||
curData []byte
|
curData []byte
|
||||||
curReadOffset int //offset relative to the currently cached data
|
curReadOffset int //offset relative to the currently cached data
|
||||||
readOffset int //offset relative to the beginning
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//DataBlock holds info about a given data block from it's size
|
||||||
type DataBlock struct {
|
type DataBlock struct {
|
||||||
begOffset int64 //The offset relative to the beginning of the squash file. Makes it easier to seek to it.
|
begOffset int64 //The offset relative to the beginning of the squash file. Makes it easier to seek to it.
|
||||||
size uint32
|
size uint32
|
||||||
@@ -23,6 +24,7 @@ type DataBlock struct {
|
|||||||
uncompressedSize uint32
|
uncompressedSize uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//NewDataBlockSize creates a new squashfs.datablock from a given size.
|
||||||
func NewDataBlockSize(raw uint32) (dbs DataBlock) {
|
func NewDataBlockSize(raw uint32) (dbs DataBlock) {
|
||||||
dbs.compressed = raw&1<<24 != 1<<24
|
dbs.compressed = raw&1<<24 != 1<<24
|
||||||
dbs.size = raw &^ 1 << 24
|
dbs.size = raw &^ 1 << 24
|
||||||
@@ -32,6 +34,7 @@ func NewDataBlockSize(raw uint32) (dbs DataBlock) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//NewDataReader creates a new data reader at the given offset, with the blocks defined by sizes
|
||||||
func (r *Reader) NewDataReader(offset int64, sizes []uint32) (*DataReader, error) {
|
func (r *Reader) NewDataReader(offset int64, sizes []uint32) (*DataReader, error) {
|
||||||
var dr DataReader
|
var dr DataReader
|
||||||
dr.r = r
|
dr.r = r
|
||||||
@@ -62,6 +65,9 @@ func (d *DataReader) readNextBlock() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DataReader) readCurBlock() error {
|
func (d *DataReader) readCurBlock() error {
|
||||||
|
if d.curBlock >= len(d.blocks) {
|
||||||
|
return io.EOF
|
||||||
|
}
|
||||||
if d.blocks[d.curBlock].size == 0 {
|
if d.blocks[d.curBlock].size == 0 {
|
||||||
d.curData = make([]byte, d.r.super.BlockSize)
|
d.curData = make([]byte, d.r.super.BlockSize)
|
||||||
d.blocks[d.curBlock].uncompressedSize = d.r.super.BlockSize
|
d.blocks[d.curBlock].uncompressedSize = d.r.super.BlockSize
|
||||||
@@ -96,7 +102,6 @@ func (d *DataReader) Read(p []byte) (int, error) {
|
|||||||
for i := 0; i < len(p); i++ {
|
for i := 0; i < len(p); i++ {
|
||||||
p[i] = d.curData[d.curReadOffset+i]
|
p[i] = d.curData[d.curReadOffset+i]
|
||||||
}
|
}
|
||||||
d.readOffset += len(p)
|
|
||||||
d.curReadOffset += len(p)
|
d.curReadOffset += len(p)
|
||||||
return len(p), nil
|
return len(p), nil
|
||||||
}
|
}
|
||||||
@@ -106,7 +111,6 @@ func (d *DataReader) Read(p []byte) (int, error) {
|
|||||||
if d.curReadOffset == len(d.curData) {
|
if d.curReadOffset == len(d.curData) {
|
||||||
err := d.readNextBlock()
|
err := d.readNextBlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.readOffset += read
|
|
||||||
return read, err
|
return read, err
|
||||||
}
|
}
|
||||||
curRead = 0
|
curRead = 0
|
||||||
@@ -120,37 +124,8 @@ func (d *DataReader) Read(p []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
d.readOffset += read
|
|
||||||
if read != len(p) {
|
if read != len(p) {
|
||||||
return read, errors.New("Didn't read enough data")
|
return read, errors.New("Didn't read enough data")
|
||||||
}
|
}
|
||||||
return read, nil
|
return read, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DataReader) Seek(offset int64, whence int) (int, error) {
|
|
||||||
if whence == io.SeekStart {
|
|
||||||
d.readOffset = int(offset)
|
|
||||||
d.curReadOffset = int(offset)
|
|
||||||
d.curBlock = 0
|
|
||||||
read := int64(0)
|
|
||||||
for i, block := range d.blocks {
|
|
||||||
if block.uncompressedSize == 0 {
|
|
||||||
d.curBlock = i
|
|
||||||
err := d.readCurBlock()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
read += int64(block.uncompressedSize)
|
|
||||||
if offset-read < 0 {
|
|
||||||
d.curReadOffset = int((offset - read) + int64(block.uncompressedSize))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch whence {
|
|
||||||
case io.SeekCurrent:
|
|
||||||
d.readOffset += int(offset)
|
|
||||||
d.curReadOffset += int(offset)
|
|
||||||
case io.SeekEnd:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+25
-27
@@ -3,35 +3,16 @@ package squashfs
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/CalebQ42/GoSquashfs/internal/inode"
|
"github.com/CalebQ42/GoSquashfs/internal/inode"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FragmentEntryRaw struct {
|
|
||||||
Start uint64
|
|
||||||
Size uint32
|
|
||||||
_unused uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type FragmentEntry struct {
|
type FragmentEntry struct {
|
||||||
start uint64
|
Start uint64
|
||||||
size uint32
|
Size uint32
|
||||||
compressed bool
|
Unused uint32
|
||||||
}
|
|
||||||
|
|
||||||
//NewFragmentEntry reads a fragment entry from the given io.Reader.
|
|
||||||
func (r *Reader) NewFragmentEntry(rdr io.Reader) (*FragmentEntry, error) {
|
|
||||||
var entry FragmentEntry
|
|
||||||
var raw FragmentEntryRaw
|
|
||||||
err := binary.Read(rdr, binary.LittleEndian, &raw)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
entry.start = raw.Start
|
|
||||||
entry.compressed = raw.Size&0x1000000 == 0x1000000
|
|
||||||
entry.size = raw.Size &^ 0x1000000
|
|
||||||
return &entry, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetFragmentDataFromInode returns the fragment data for a given inode.
|
//GetFragmentDataFromInode returns the fragment data for a given inode.
|
||||||
@@ -52,6 +33,7 @@ func (r *Reader) GetFragmentDataFromInode(in *inode.Inode) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
fragIndex = bf.Init.FragmentIndex
|
fragIndex = bf.Init.FragmentIndex
|
||||||
fragOffset = bf.Init.FragmentOffset
|
fragOffset = bf.Init.FragmentOffset
|
||||||
|
fmt.Println(fragIndex, fragOffset, size)
|
||||||
} else if in.Type == inode.ExtFileType {
|
} else if in.Type == inode.ExtFileType {
|
||||||
bf := in.Info.(inode.ExtendedFile)
|
bf := in.Info.(inode.ExtendedFile)
|
||||||
if !bf.Fragmented {
|
if !bf.Fragmented {
|
||||||
@@ -67,17 +49,33 @@ func (r *Reader) GetFragmentDataFromInode(in *inode.Inode) ([]byte, error) {
|
|||||||
} else {
|
} else {
|
||||||
return nil, errors.New("Inode type not supported")
|
return nil, errors.New("Inode type not supported")
|
||||||
}
|
}
|
||||||
frag := r.fragEntries[fragIndex]
|
fmt.Println("fragment index", fragIndex)
|
||||||
datRdr, err := r.NewDataReader(int64(frag.start), []uint32{frag.size})
|
//reading the fragment entry first
|
||||||
|
fragBlockIndex := int(fragIndex / 512)
|
||||||
|
fragEntryRdr, err := r.NewBlockReader(int64(r.fragOffsets[fragBlockIndex]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, err = datRdr.Seek(int64(fragOffset), io.SeekStart)
|
_, err = fragEntryRdr.Seek(int64(16*fragIndex), io.SeekStart)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var entry FragmentEntry
|
||||||
|
err = binary.Read(fragEntryRdr, binary.LittleEndian, &entry)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
//now reading the actual fragment
|
||||||
|
dr, err := r.NewDataReader(int64(entry.Start), []uint32{entry.Size})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, err = dr.Read(make([]byte, fragOffset))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tmp := make([]byte, size)
|
tmp := make([]byte, size)
|
||||||
_, err = datRdr.Read(tmp)
|
err = binary.Read(dr, binary.LittleEndian, &tmp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"math"
|
||||||
|
|
||||||
"github.com/CalebQ42/GoSquashfs/internal/inode"
|
"github.com/CalebQ42/GoSquashfs/internal/inode"
|
||||||
)
|
)
|
||||||
@@ -33,7 +33,7 @@ type Reader struct {
|
|||||||
super Superblock
|
super Superblock
|
||||||
flags SuperblockFlags
|
flags SuperblockFlags
|
||||||
decompressor Decompressor
|
decompressor Decompressor
|
||||||
fragEntries []*FragmentEntry
|
fragOffsets []uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewSquashfsReader returns a new squashfs.Reader from an io.ReaderAt
|
//NewSquashfsReader returns a new squashfs.Reader from an io.ReaderAt
|
||||||
@@ -58,16 +58,19 @@ func NewSquashfsReader(r io.ReaderAt) (*Reader, error) {
|
|||||||
//TODO: parse compressor options
|
//TODO: parse compressor options
|
||||||
return nil, ErrCompressorOptions
|
return nil, ErrCompressorOptions
|
||||||
}
|
}
|
||||||
br, err := rdr.NewBlockReader(int64(rdr.super.FragTableStart))
|
fragBlocks := int(math.Ceil(float64(rdr.super.FragCount) / 512.0))
|
||||||
if err != nil {
|
if fragBlocks > 0 {
|
||||||
return &rdr, err
|
offset := int64(rdr.super.FragTableStart)
|
||||||
}
|
for i := 0; i < fragBlocks; i++ {
|
||||||
for i := 0; i < int(rdr.super.FragCount); i++ {
|
tmp := make([]byte, 8)
|
||||||
entry, err := rdr.NewFragmentEntry(br)
|
_, err = r.ReadAt(tmp, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &rdr, err
|
fmt.Println("Error while reading fragment block offsets")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rdr.fragOffsets = append(rdr.fragOffsets, binary.LittleEndian.Uint64(tmp))
|
||||||
|
offset += 8
|
||||||
}
|
}
|
||||||
rdr.fragEntries = append(rdr.fragEntries, entry)
|
|
||||||
}
|
}
|
||||||
return &rdr, nil
|
return &rdr, nil
|
||||||
}
|
}
|
||||||
@@ -119,12 +122,3 @@ func (r *Reader) readDir(i *inode.Inode) (paths []string, err error) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reader) readDirTable() error {
|
|
||||||
paths, err := r.GetFilesList()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Println(strings.Join(paths, "\n"))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -35,10 +35,6 @@ func TestMain(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = rdr.readDirTable()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
i, err := rdr.GetInodeFromPath("code-oss.desktop")
|
i, err := rdr.GetInodeFromPath("code-oss.desktop")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
Reference in New Issue
Block a user