Working on fragments

This commit is contained in:
Caleb Gardner
2020-11-23 06:44:39 -06:00
parent de45fc927d
commit ae2cc5ab54
7 changed files with 51 additions and 86 deletions
+3 -3
View File
@@ -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
+2
View File
@@ -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
View File
@@ -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:
}
}
+24 -26
View File
@@ -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 { type FragmentEntry struct {
Start uint64 Start uint64
Size uint32 Size uint32
_unused uint32 Unused uint32
}
type FragmentEntry struct {
start uint64
size uint32
compressed bool
}
//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
} }
+12 -18
View File
@@ -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 fragBlocks > 0 {
offset := int64(rdr.super.FragTableStart)
for i := 0; i < fragBlocks; i++ {
tmp := make([]byte, 8)
_, 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
} }
for i := 0; i < int(rdr.super.FragCount); i++ { rdr.fragOffsets = append(rdr.fragOffsets, binary.LittleEndian.Uint64(tmp))
entry, err := rdr.NewFragmentEntry(br) offset += 8
if err != nil {
return &rdr, err
} }
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
}
-4
View File
@@ -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)