diff --git a/datareader.go b/datareader.go index 842795f..94c4eb5 100644 --- a/datareader.go +++ b/datareader.go @@ -12,6 +12,8 @@ import ( var ( //ErrInodeNotFile is given when giving an inode, but the function requires a file inode. ErrInodeNotFile = errors.New("Given inode is NOT a file type") + //ErrInodeOnlyFragment is given when trying to make a DataReader from an inode, but the inode only had data in a fragment + ErrInodeOnlyFragment = errors.New("Given inode ONLY has fragment data") ) //DataReader reads data from data blocks. @@ -34,8 +36,8 @@ type DataBlock struct { //NewDataBlock creates a new squashfs.datablock from a given size. func NewDataBlock(raw uint32) (dbs DataBlock) { - dbs.compressed = raw&1<<24 != 1<<24 - dbs.size = raw &^ 1 << 24 + dbs.compressed = raw&(1<<24) != (1 << 24) + dbs.size = raw &^ (1 << 24) if !dbs.compressed { dbs.uncompressedSize = dbs.size } @@ -60,19 +62,32 @@ func (r *Reader) NewDataReader(offset int64, sizes []uint32) (*DataReader, error //NewDataReaderFromInode creates a new DataReader from a given inode. Inode must be of BasicFile or ExtendedFile types func (r *Reader) NewDataReaderFromInode(i *inode.Inode) (*DataReader, error) { var rdr DataReader + rdr.r = r switch i.Type { case inode.BasicFileType: fil := i.Info.(inode.BasicFile) + if fil.Init.BlockStart == 0 { + return nil, ErrInodeOnlyFragment + } rdr.offset = int64(fil.Init.BlockStart) for _, sizes := range fil.BlockSizes { rdr.blocks = append(rdr.blocks, NewDataBlock(sizes)) } + if fil.Fragmented { + rdr.blocks = rdr.blocks[:len(rdr.blocks)-1] + } case inode.ExtFileType: fil := i.Info.(inode.ExtendedFile) + if fil.Init.BlockStart == 0 { + return nil, ErrInodeOnlyFragment + } rdr.offset = int64(fil.Init.BlockStart) for _, sizes := range fil.BlockSizes { rdr.blocks = append(rdr.blocks, NewDataBlock(sizes)) } + if fil.Fragmented { + rdr.blocks = rdr.blocks[:len(rdr.blocks)-1] + } default: return nil, ErrInodeNotFile } @@ -87,18 +102,21 @@ func (d *DataReader) readNextBlock() error { d.curBlock++ if d.curBlock >= len(d.blocks) { d.curBlock-- - return errors.New("Ran out of blocks") + return io.EOF } err := d.readCurBlock() if err != nil { d.curBlock-- d.readCurBlock() + fmt.Println("running back because of issues") return err } + fmt.Println("Read block success!") return nil } func (d *DataReader) readCurBlock() error { + fmt.Println("reading into block", d.curBlock, "out of", len(d.blocks)) if d.curBlock >= len(d.blocks) { return io.EOF } @@ -106,22 +124,21 @@ func (d *DataReader) readCurBlock() error { d.curData = make([]byte, d.r.super.BlockSize) d.blocks[d.curBlock].uncompressedSize = d.r.super.BlockSize d.blocks[d.curBlock].begOffset = d.offset - fmt.Println("dat red") - fmt.Println(len(d.curData)) return nil } sec := io.NewSectionReader(d.r.r, d.offset, int64(d.blocks[d.curBlock].size)) + fmt.Println("block size", d.r.super.BlockSize) + fmt.Println("compressed size", int64(d.blocks[d.curBlock].size)) if d.blocks[d.curBlock].compressed { btys, err := d.r.decompressor.Decompress(sec) if err != nil { + fmt.Println("HERE!") return err } d.blocks[d.curBlock].uncompressedSize = uint32(len(btys)) d.curData = btys d.blocks[d.curBlock].begOffset = d.offset d.offset += int64(d.blocks[d.curBlock].size) - fmt.Println("dat red") - fmt.Println(len(d.curData)) return nil } var buf bytes.Buffer @@ -132,15 +149,12 @@ func (d *DataReader) readCurBlock() error { d.curData = buf.Bytes() d.blocks[d.curBlock].begOffset = d.offset d.offset += int64(d.blocks[d.curBlock].size) - fmt.Println("dat red") - fmt.Println(len(d.curData)) return err } func (d *DataReader) Read(p []byte) (int, error) { - fmt.Println("dat") - fmt.Println(len(d.curData)) if d.curReadOffset+len(p) < len(d.curData) { + fmt.Println("Enough data in cache for direct read") for i := 0; i < len(p); i++ { p[i] = d.curData[d.curReadOffset+i] } @@ -148,20 +162,21 @@ func (d *DataReader) Read(p []byte) (int, error) { return len(p), nil } read := 0 - curRead := 0 for read < len(p) { if d.curReadOffset == len(d.curData) { + fmt.Println("reading new block...") err := d.readNextBlock() if err != nil { return read, err } - curRead = 0 + d.curReadOffset = 0 } for ; read < len(p); read++ { - curRead++ - if d.curReadOffset+curRead < len(d.curData) { - p[read] = d.curData[d.curReadOffset+curRead] + d.curReadOffset++ + if d.curReadOffset < len(d.curData) { + p[read] = d.curData[d.curReadOffset] } else { + fmt.Println("breaking out!") break } } diff --git a/filereader.go b/filereader.go index e0f4f76..76eeb53 100644 --- a/filereader.go +++ b/filereader.go @@ -36,43 +36,46 @@ func (r *Reader) ReadFile(location string) (*FileReader, error) { if in.Type != inode.BasicFileType && in.Type != inode.ExtFileType { return nil, ErrPathIsNotFile } - var offset uint32 - var sizes []uint32 switch in.Type { case inode.BasicFileType: - rdr.fragged = in.Info.(inode.BasicFile).Fragmented - rdr.fragOnly = in.Info.(inode.BasicFile).Init.BlockStart == 0 - rdr.FileSize = int(in.Info.(inode.BasicFile).Init.Size) - offset = in.Info.(inode.BasicFile).Init.BlockStart - sizes = in.Info.(inode.BasicFile).BlockSizes + fil := in.Info.(inode.BasicFile) + rdr.fragged = fil.Fragmented + rdr.fragOnly = fil.Init.BlockStart == 0 + rdr.FileSize = int(fil.Init.Size) case inode.ExtFileType: - rdr.fragged = in.Info.(inode.ExtendedFile).Fragmented - rdr.fragOnly = in.Info.(inode.ExtendedFile).Init.BlockStart == 0 - rdr.FileSize = int(in.Info.(inode.ExtendedFile).Init.Size) - offset = in.Info.(inode.ExtendedFile).Init.BlockStart - sizes = in.Info.(inode.ExtendedFile).BlockSizes + fil := in.Info.(inode.ExtendedFile) + rdr.fragged = fil.Fragmented + rdr.fragOnly = fil.Init.BlockStart == 0 + rdr.FileSize = int(fil.Init.Size) } - fmt.Println("HIIII") if rdr.fragged { rdr.fragmentData, err = r.GetFragmentDataFromInode(in) if err != nil { return nil, err } } - if rdr.fragged { - rdr.data, err = r.NewDataReader(int64(offset), sizes[:len(sizes)-1]) - } else { - rdr.data, err = r.NewDataReader(int64(offset), sizes) + if !rdr.fragOnly { + rdr.data, err = r.NewDataReaderFromInode(in) } return &rdr, nil } func (f *FileReader) Read(p []byte) (int, error) { - fmt.Println("reading!") + fmt.Println("reading!", len(p)) + if f.fragOnly { + fmt.Println("HII") + 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 { + fmt.Println("Trying to read fragment AFTER main data") n, err = bytes.NewBuffer(f.fragmentData).Read(p[read:]) read += n if err != nil { @@ -81,5 +84,6 @@ func (f *FileReader) Read(p []byte) (int, error) { } else if err != nil { return read, err } + fmt.Println("read", n) return read, nil } diff --git a/fragment.go b/fragment.go index 915cdfc..d42e6b8 100644 --- a/fragment.go +++ b/fragment.go @@ -49,8 +49,6 @@ func (r *Reader) GetFragmentDataFromInode(in *inode.Inode) ([]byte, error) { } else { return nil, errors.New("Inode type not supported") } - fmt.Println(fragIndex, fragOffset, size) - fmt.Println("fragment index", fragIndex) //reading the fragment entry first fragEntryRdr, err := r.NewMetadataReader(int64(r.fragOffsets[int(fragIndex/512)])) if err != nil { @@ -79,5 +77,6 @@ func (r *Reader) GetFragmentDataFromInode(in *inode.Inode) ([]byte, error) { if err != nil { return nil, err } + fmt.Println("read fragment with size", len(tmp)) return tmp, nil } diff --git a/squash_test.go b/squash_test.go index 6f837a1..4c24ef9 100644 --- a/squash_test.go +++ b/squash_test.go @@ -13,7 +13,7 @@ import ( const ( downloadURL = "https://github.com/zilti/code-oss.AppImage/releases/download/continuous/Code_OSS-x86_64.AppImage" appImageName = "Code_OSS.AppImage" - squashfsName = "Code_OSS.Squashfs" + squashfsName = "testing.squashfs" ) func TestMain(t *testing.T) { @@ -38,7 +38,7 @@ func TestMain(t *testing.T) { } //testing code to print out the directory structure // rdr.GetFileStructure() - extractionFil := "code-oss.desktop" + extractionFil := "Proton-5.9-GE-8-ST.tar.gz" os.Remove(wd + "/testing/" + extractionFil) desk, err := os.Create(wd + "/testing/" + extractionFil) if err != nil { @@ -48,7 +48,8 @@ func TestMain(t *testing.T) { if err != nil { t.Fatal(err) } - n, err := io.Copy(desk, ext) + fmt.Println("Size!", ext.FileSize) + n, err := io.CopyBuffer(desk, ext, make([]byte, rdr.super.BlockSize/2)) if err != nil { fmt.Println("Read", n) t.Fatal(err)