diff --git a/file.go b/file.go index 142c7f8..7b2fcdf 100644 --- a/file.go +++ b/file.go @@ -19,7 +19,7 @@ import ( // File represents a file inside a squashfs archive. type File struct { - b *squashfslow.Base + b *squashfslow.FileBase full *data.FullReader rdr *data.Reader parent *FS @@ -28,7 +28,7 @@ type File struct { } // Creates a new *File from the given *squashfs.Base -func (r *Reader) FileFromBase(b *squashfslow.Base, parent *FS) *File { +func (r *Reader) FileFromBase(b *squashfslow.FileBase, parent *FS) *File { return &File{ b: b, parent: parent, @@ -234,7 +234,7 @@ func (f *File) ExtractWithOptions(path string, op *ExtractionOptions) error { } return errors.Join(errors.New("failed to get base from entry: "+path), err) } - go func(b *squashfslow.Base, path string) { + go func(b *squashfslow.FileBase, path string) { i := op.manager.Lock() if b.IsDir() { extDir := filepath.Join(path, b.Name) diff --git a/fs.go b/fs.go index 4986790..43d9e1e 100644 --- a/fs.go +++ b/fs.go @@ -255,7 +255,7 @@ func (f *FS) ExtractWithOptions(folder string, op *ExtractionOptions) error { // Returns the FS as a *File func (f *FS) File() *File { return &File{ - b: &f.d.Base, + b: &f.d.FileBase, parent: f.parent, r: f.r, } diff --git a/low/directory.go b/low/directory.go index 6bdc248..b219d77 100644 --- a/low/directory.go +++ b/low/directory.go @@ -14,7 +14,7 @@ import ( ) type Directory struct { - Base + FileBase Entries []directory.Entry } @@ -49,15 +49,15 @@ func (r *Reader) directoryFromRef(ref uint64, name string) (*Directory, error) { return nil, err } return &Directory{ - Base: *r.BaseFromInode(i, name), - Entries: entries, + FileBase: *r.BaseFromInode(i, name), + Entries: entries, }, nil } -func (d *Directory) Open(r *Reader, path string) (*Base, error) { +func (d *Directory) Open(r *Reader, path string) (*FileBase, error) { path = filepath.Clean(path) if path == "." || path == "" { - return &d.Base, nil + return &d.FileBase, nil } split := strings.Split(path, "/") i, found := slices.BinarySearchFunc(d.Entries, split[0], func(e directory.Entry, name string) int { diff --git a/low/base.go b/low/file_base.go similarity index 67% rename from low/base.go rename to low/file_base.go index caf43fb..e87bc9e 100644 --- a/low/base.go +++ b/low/file_base.go @@ -11,44 +11,44 @@ import ( "github.com/CalebQ42/squashfs/low/inode" ) -type Base struct { +type FileBase struct { Inode *inode.Inode Name string } -func (r *Reader) BaseFromInode(i *inode.Inode, name string) *Base { - return &Base{Inode: i, Name: name} +func (r *Reader) BaseFromInode(i *inode.Inode, name string) *FileBase { + return &FileBase{Inode: i, Name: name} } -func (r *Reader) BaseFromEntry(e directory.Entry) (*Base, error) { +func (r *Reader) BaseFromEntry(e directory.Entry) (*FileBase, error) { in, err := r.InodeFromEntry(e) if err != nil { return nil, err } - return &Base{Inode: in, Name: e.Name}, nil + return &FileBase{Inode: in, Name: e.Name}, nil } -func (r *Reader) BaseFromRef(ref uint64, name string) (*Base, error) { +func (r *Reader) BaseFromRef(ref uint64, name string) (*FileBase, error) { in, err := r.InodeFromRef(ref) if err != nil { return nil, err } - return &Base{Inode: in, Name: name}, nil + return &FileBase{Inode: in, Name: name}, nil } -func (b *Base) Uid(r *Reader) (uint32, error) { +func (b *FileBase) Uid(r *Reader) (uint32, error) { return r.Id(b.Inode.UidInd) } -func (b *Base) Gid(r *Reader) (uint32, error) { +func (b *FileBase) Gid(r *Reader) (uint32, error) { return r.Id(b.Inode.GidInd) } -func (b *Base) IsDir() bool { +func (b *FileBase) IsDir() bool { return b.Inode.Type == inode.Dir || b.Inode.Type == inode.EDir } -func (b *Base) ToDir(r *Reader) (*Directory, error) { +func (b *FileBase) ToDir(r *Reader) (*Directory, error) { var blockStart uint32 var size uint32 var offset uint16 @@ -75,16 +75,16 @@ func (b *Base) ToDir(r *Reader) (*Directory, error) { return nil, err } return &Directory{ - Base: *b, - Entries: entries, + FileBase: *b, + Entries: entries, }, nil } -func (b *Base) IsRegular() bool { +func (b *FileBase) IsRegular() bool { return b.Inode.Type == inode.Fil || b.Inode.Type == inode.EFil } -func (b *Base) GetRegFileReaders(r *Reader) (*data.Reader, *data.FullReader, error) { +func (b *FileBase) GetRegFileReaders(r *Reader) (*data.Reader, *data.FullReader, error) { if !b.IsRegular() { return nil, nil, errors.New("not a regular file") } @@ -130,7 +130,7 @@ func (b *Base) GetRegFileReaders(r *Reader) (*data.Reader, *data.FullReader, err return outRdr, outFull, nil } -func (b *Base) GetFullReader(r *Reader) (*data.FullReader, error) { +func (b *FileBase) GetFullReader(r *Reader) (*data.FullReader, error) { if !b.IsRegular() { return nil, errors.New("not a regular file") } @@ -166,3 +166,38 @@ func (b *Base) GetFullReader(r *Reader) (*data.FullReader, error) { } return outFull, nil } + +func (b *FileBase) GetReader(r *Reader) (*data.Reader, error) { + if !b.IsRegular() { + return nil, errors.New("not a regular file") + } + var blockStart uint64 + var fragIndex uint32 + var fragOffset uint32 + var fragSize uint64 + var sizes []uint32 + if b.Inode.Type == inode.Fil { + blockStart = uint64(b.Inode.Data.(inode.File).BlockStart) + fragIndex = b.Inode.Data.(inode.File).FragInd + fragOffset = b.Inode.Data.(inode.File).FragOffset + sizes = b.Inode.Data.(inode.File).BlockSizes + fragSize = uint64(b.Inode.Data.(inode.File).Size % r.Superblock.BlockSize) + } else { + blockStart = b.Inode.Data.(inode.EFile).BlockStart + fragIndex = b.Inode.Data.(inode.EFile).FragInd + fragOffset = b.Inode.Data.(inode.EFile).FragOffset + sizes = b.Inode.Data.(inode.EFile).BlockSizes + fragSize = b.Inode.Data.(inode.EFile).Size % uint64(r.Superblock.BlockSize) + } + outRdr := data.NewReader(toreader.NewReader(r.r, int64(blockStart)), r.d, sizes, fragSize, r.Superblock.BlockSize) + if fragIndex != 0xffffffff { + ent, err := r.fragEntry(fragIndex) + if err != nil { + return nil, err + } + frag := data.NewReader(toreader.NewReader(r.r, int64(ent.Start)), r.d, []uint32{ent.Size}, uint64(r.Superblock.BlockSize), r.Superblock.BlockSize) + frag.Read(make([]byte, fragOffset)) + outRdr.AddFrag(io.LimitReader(frag, int64(fragSize))) + } + return outRdr, nil +} diff --git a/low/reader_test.go b/low/reader_test.go index 1edf591..7fe237f 100644 --- a/low/reader_test.go +++ b/low/reader_test.go @@ -64,7 +64,7 @@ func TestReader(t *testing.T) { path := filepath.Join(tmpDir, "extractTest") os.RemoveAll(path) os.MkdirAll(path, 0777) - err = extractToDir(rdr, &rdr.Root.Base, path) + err = extractToDir(rdr, &rdr.Root.FileBase, path) t.Fatal(err) } @@ -92,7 +92,7 @@ func TestSingleFile(t *testing.T) { t.Fatal(err) } -func extractToDir(rdr *squashfslow.Reader, b *squashfslow.Base, folder string) error { +func extractToDir(rdr *squashfslow.Reader, b *squashfslow.FileBase, folder string) error { path := filepath.Join(folder, b.Name) if b.IsDir() { d, err := b.ToDir(rdr) @@ -103,7 +103,7 @@ func extractToDir(rdr *squashfslow.Reader, b *squashfslow.Base, folder string) e if err != nil { return err } - var nestBast *squashfslow.Base + var nestBast *squashfslow.FileBase for _, e := range d.Entries { nestBast, err = rdr.BaseFromEntry(e) if err != nil {