From 4f058f2f318a53974a8ffa18487754bc0e9610aa Mon Sep 17 00:00:00 2001 From: Caleb Gardner Date: Tue, 24 Nov 2020 22:26:16 -0600 Subject: [PATCH] Working on file reading (Not working right now) --- datareader.go | 44 ++++++++++++++++++++++++++++-- filereader.go | 74 ++++++++++++++++++++++++++++++++++++++++++++++++-- fragment.go | 10 ++----- squash_test.go | 15 +++++----- utils.go | 2 +- 5 files changed, 122 insertions(+), 23 deletions(-) diff --git a/datareader.go b/datareader.go index f2b342e..2ad09c8 100644 --- a/datareader.go +++ b/datareader.go @@ -3,7 +3,15 @@ package squashfs import ( "bytes" "errors" + "fmt" "io" + + "github.com/CalebQ42/GoSquashfs/internal/inode" +) + +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") ) //DataReader reads data from data blocks. @@ -24,8 +32,8 @@ type DataBlock struct { uncompressedSize uint32 } -//NewDataBlockSize creates a new squashfs.datablock from a given size. -func NewDataBlockSize(raw uint32) (dbs DataBlock) { +//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 if !dbs.compressed { @@ -40,7 +48,7 @@ func (r *Reader) NewDataReader(offset int64, sizes []uint32) (*DataReader, error dr.r = r dr.offset = offset for _, size := range sizes { - dr.blocks = append(dr.blocks, NewDataBlockSize(size)) + dr.blocks = append(dr.blocks, NewDataBlock(size)) } err := dr.readCurBlock() if err != nil { @@ -49,6 +57,32 @@ func (r *Reader) NewDataReader(offset int64, sizes []uint32) (*DataReader, error return &dr, nil } +//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 + switch i.Type { + case inode.BasicFileType: + fil := i.Info.(inode.BasicFile) + rdr.offset = int64(fil.Init.BlockStart) + for _, sizes := range fil.BlockSizes { + rdr.blocks = append(rdr.blocks, NewDataBlock(sizes)) + } + case inode.ExtFileType: + fil := i.Info.(inode.ExtendedFile) + rdr.offset = int64(fil.Init.BlockStart) + for _, sizes := range fil.BlockSizes { + rdr.blocks = append(rdr.blocks, NewDataBlock(sizes)) + } + default: + return nil, ErrInodeNotFile + } + err := rdr.readCurBlock() + if err != nil { + return nil, err + } + return &rdr, nil +} + func (d *DataReader) readNextBlock() error { d.curBlock++ if d.curBlock >= len(d.blocks) { @@ -94,10 +128,14 @@ 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) { for i := 0; i < len(p); i++ { p[i] = d.curData[d.curReadOffset+i] diff --git a/filereader.go b/filereader.go index 95d084c..e0f4f76 100644 --- a/filereader.go +++ b/filereader.go @@ -1,17 +1,85 @@ package squashfs +import ( + "bytes" + "errors" + "fmt" + "io" + + "github.com/CalebQ42/GoSquashfs/internal/inode" +) + +//FileReader provides a io.Reader interface for files within type FileReader struct { r *Reader data *DataReader fragmentData []byte + fragged bool + fragOnly bool + read int + FileSize int //FileSize is the total size of the given file } -//TODO: Yes +var ( + //ErrPathIsNotFile returns when trying to read from a file, but the given path is NOT a file. + ErrPathIsNotFile = errors.New("The given path is not a file") +) +//ReadFile provides a squashfs.FileReader for the file at the given location. func (r *Reader) ReadFile(location string) (*FileReader, error) { - + var rdr FileReader + rdr.r = r + in, err := r.GetInodeFromPath(location) + if err != nil { + return nil, err + } + 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 + 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 + } + 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) + } + return &rdr, nil } func (f *FileReader) Read(p []byte) (int, error) { - + fmt.Println("reading!") + var read int + n, err := f.data.Read(p) + read += n + if f.fragged && err == io.EOF { + n, err = bytes.NewBuffer(f.fragmentData).Read(p[read:]) + read += n + if err != nil { + return read, err + } + } else if err != nil { + return read, err + } + return read, nil } diff --git a/fragment.go b/fragment.go index 012a5db..915cdfc 100644 --- a/fragment.go +++ b/fragment.go @@ -1,7 +1,6 @@ package squashfs import ( - "bytes" "encoding/binary" "errors" "fmt" @@ -35,7 +34,6 @@ func (r *Reader) GetFragmentDataFromInode(in *inode.Inode) ([]byte, error) { } fragIndex = bf.Init.FragmentIndex fragOffset = bf.Init.FragmentOffset - fmt.Println(fragIndex, fragOffset, size) } else if in.Type == inode.ExtFileType { bf := in.Info.(inode.ExtendedFile) if !bf.Fragmented { @@ -51,6 +49,7 @@ 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)])) @@ -80,10 +79,5 @@ func (r *Reader) GetFragmentDataFromInode(in *inode.Inode) ([]byte, error) { if err != nil { return nil, err } - dataRdr := bytes.NewBuffer(tmp) - dta, err := r.decompressor.Decompress(dataRdr) - if err != nil { - return nil, err - } - return dta, nil + return tmp, nil } diff --git a/squash_test.go b/squash_test.go index 0391799..6f837a1 100644 --- a/squash_test.go +++ b/squash_test.go @@ -1,6 +1,7 @@ package squashfs import ( + "fmt" "io" "net/http" "os" @@ -35,23 +36,21 @@ func TestMain(t *testing.T) { if err != nil { t.Fatal(err) } - rdr.GetFileStructure() - extractionFil := ".DirIcon" - i, err := rdr.GetInodeFromPath(extractionFil) - if err != nil { - t.Fatal(err) - } + //testing code to print out the directory structure + // rdr.GetFileStructure() + extractionFil := "code-oss.desktop" os.Remove(wd + "/testing/" + extractionFil) desk, err := os.Create(wd + "/testing/" + extractionFil) if err != nil { t.Fatal(err) } - btys, err := rdr.GetFragmentDataFromInode(i) + ext, err := rdr.ReadFile(extractionFil) if err != nil { t.Fatal(err) } - _, err = desk.Write(btys) + n, err := io.Copy(desk, ext) if err != nil { + fmt.Println("Read", n) t.Fatal(err) } t.Fatal("No problems here!") diff --git a/utils.go b/utils.go index f78e428..b2d0a0d 100644 --- a/utils.go +++ b/utils.go @@ -76,7 +76,7 @@ func (r *Reader) GetInodeFromEntry(en *directory.Entry) (*inode.Inode, error) { } //GetInodeFromPath returns the inode at the given path, relative to root. -//The given path can start or without "/". +//The given path can start with or without "/" func (r *Reader) GetInodeFromPath(path string) (*inode.Inode, error) { path = strings.TrimSuffix(strings.TrimPrefix(path, "/"), "/") pathDirs := strings.Split(path, "/")