Finished?

Everything seems to extract fine (though more testing is needed)
This commit is contained in:
Caleb Gardner
2023-12-24 06:02:11 -06:00
parent 0449a03428
commit b2a3920c1f
10 changed files with 277 additions and 118 deletions
+5
View File
@@ -60,3 +60,8 @@ func (r *Reader) Read(b []byte) (int, error) {
}
return curRead, nil
}
func (r *Reader) Close() error {
r.dat = nil
return nil
}
+53 -14
View File
@@ -4,7 +4,6 @@ import (
"errors"
"io"
"github.com/CalebQ42/squashfs/internal/decompress"
"github.com/CalebQ42/squashfs/internal/metadata"
"github.com/CalebQ42/squashfs/internal/toreader"
"github.com/CalebQ42/squashfs/squashfs/data"
@@ -17,26 +16,35 @@ type Base struct {
Name string
}
func (r *Reader) baseFromInode(i *inode.Inode, name string) *Base {
func (r *Reader) BaseFromInode(i *inode.Inode, name string) *Base {
return &Base{Inode: i, Name: name}
}
func (r *Reader) baseFromEntry(e directory.Entry) (*Base, error) {
rdr := metadata.NewReader(toreader.NewReader(r.r, int64(r.sup.InodeTableStart)+int64(e.BlockStart)), r.d)
func (r *Reader) BaseFromEntry(e directory.Entry) (*Base, error) {
rdr := metadata.NewReader(toreader.NewReader(r.r, int64(r.Superblock.InodeTableStart)+int64(e.BlockStart)), r.d)
defer rdr.Close()
rdr.Read(make([]byte, e.Offset))
in, err := inode.Read(rdr, r.sup.BlockSize)
in, err := inode.Read(rdr, r.Superblock.BlockSize)
if err != nil {
return nil, err
}
return &Base{Inode: in, Name: e.Name}, nil
}
func (r *Reader) BaseFromRef(ref uint64, name string) (*Base, error) {
in, err := r.inodeFromRef(ref)
if err != nil {
return nil, err
}
return &Base{Inode: in, Name: name}, nil
}
func (b *Base) Uid(r *Reader) (uint32, error) {
return r.id(b.Inode.UidInd)
return r.Id(b.Inode.UidInd)
}
func (b *Base) Gid(r *Reader) (uint32, error) {
return r.id(b.Inode.GidInd)
return r.Id(b.Inode.GidInd)
}
func (b *Base) IsDir() bool {
@@ -44,7 +52,35 @@ func (b *Base) IsDir() bool {
}
func (b *Base) ToDir(r *Reader) (*Directory, error) {
return r.directoryFromInode(b.Inode, b.Name)
var blockStart uint32
var size uint32
var offset uint16
switch b.Inode.Type {
case inode.Dir:
blockStart = b.Inode.Data.(inode.Directory).BlockStart
size = uint32(b.Inode.Data.(inode.Directory).Size)
offset = b.Inode.Data.(inode.Directory).Offset
case inode.EDir:
blockStart = b.Inode.Data.(inode.EDirectory).BlockStart
size = b.Inode.Data.(inode.EDirectory).Size
offset = b.Inode.Data.(inode.EDirectory).Offset
default:
return nil, errors.New("not a directory")
}
dirRdr := metadata.NewReader(toreader.NewReader(r.r, int64(r.Superblock.DirTableStart)+int64(blockStart)), r.d)
defer dirRdr.Close()
_, err := dirRdr.Read(make([]byte, offset))
if err != nil {
return nil, err
}
entries, err := directory.ReadDirectory(dirRdr, size)
if err != nil {
return nil, err
}
return &Directory{
Base: *b,
Entries: entries,
}, nil
}
func (b *Base) IsRegular() bool {
@@ -58,36 +94,39 @@ func (b *Base) GetRegFileReaders(r *Reader) (*data.Reader, *data.FullReader, err
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)
}
frag := func(rdr io.ReaderAt, d decompress.Decompressor) (*data.Reader, error) {
frag := func() (io.Reader, error) {
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})
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))
return frag, nil
return io.LimitReader(frag, int64(fragSize)), nil
}
outRdr := data.NewReader(toreader.NewReader(r.r, int64(blockStart)), r.d, sizes)
outRdr := data.NewReader(toreader.NewReader(r.r, int64(blockStart)), r.d, sizes, fragSize, r.Superblock.BlockSize)
if fragIndex != 0xffffffff {
f, err := frag(r.r, r.d)
f, err := frag()
if err != nil {
return nil, nil, err
}
outRdr.AddFrag(f)
}
outFull := data.NewFullReader(r.r, int64(blockStart), r.d, sizes)
outFull := data.NewFullReader(r.r, int64(blockStart), r.d, sizes, fragSize, r.Superblock.BlockSize)
if fragIndex != 0xffffffff {
outFull.AddFrag(frag)
}
+24 -4
View File
@@ -4,13 +4,14 @@ import (
"encoding/binary"
"errors"
"io"
"math"
"sync"
"github.com/CalebQ42/squashfs/internal/decompress"
"github.com/CalebQ42/squashfs/internal/toreader"
)
type FragReaderConstructor func(io.ReaderAt, decompress.Decompressor) (*Reader, error)
type FragReaderConstructor func() (io.Reader, error)
type FullReader struct {
r io.ReaderAt
@@ -19,16 +20,20 @@ type FullReader struct {
retPool *sync.Pool
sizes []uint32
initialOffset int64
finalBlockSize uint64
blockSize uint32
goroutineLimit uint16
}
func NewFullReader(r io.ReaderAt, initialOffset int64, d decompress.Decompressor, sizes []uint32) *FullReader {
func NewFullReader(r io.ReaderAt, initialOffset int64, d decompress.Decompressor, sizes []uint32, finalBlockSize uint64, blockSize uint32) *FullReader {
return &FullReader{
r: r,
d: d,
sizes: sizes,
initialOffset: initialOffset,
goroutineLimit: 10,
finalBlockSize: finalBlockSize,
blockSize: blockSize,
retPool: &sync.Pool{
New: func() any {
return &retValue{}
@@ -55,6 +60,16 @@ func (r *FullReader) process(index uint64, fileOffset uint64, retChan chan *retV
ret := r.retPool.Get().(*retValue)
ret.index = index
realSize := r.sizes[index] &^ (1 << 24)
if realSize == 0 {
if index == uint64(len(r.sizes))-1 && r.frag == nil {
ret.data = make([]byte, r.finalBlockSize)
} else {
ret.data = make([]byte, r.blockSize)
}
ret.err = nil
retChan <- ret
return
}
ret.data = make([]byte, realSize)
ret.err = binary.Read(toreader.NewReader(r.r, int64(r.initialOffset)+int64(fileOffset)), binary.LittleEndian, &ret.data)
if r.sizes[index] == realSize {
@@ -71,7 +86,7 @@ func (r *FullReader) WriteTo(w io.Writer) (int64, error) {
cache := make(map[uint64]*retValue)
var errCache []error
retChan := make(chan *retValue, r.goroutineLimit)
for i := uint64(0); i < uint64(len(r.sizes))/uint64(r.goroutineLimit); i++ {
for i := uint64(0); i < uint64(math.Ceil(float64(len(r.sizes))/float64(r.goroutineLimit))); i++ {
toProcess = uint16(len(r.sizes)) - (uint16(i) * r.goroutineLimit)
if toProcess > r.goroutineLimit {
toProcess = r.goroutineLimit
@@ -139,12 +154,17 @@ func (r *FullReader) WriteTo(w io.Writer) (int64, error) {
}
}
if r.frag != nil {
rdr, err := r.frag(r.r, r.d)
rdr, err := r.frag()
if err != nil {
return wrote, err
}
wr, err := io.Copy(w, rdr)
wrote += wr
if l, ok := rdr.(*io.LimitedReader); ok {
if cl, ok := l.R.(io.Closer); ok {
cl.Close()
}
}
if err != nil {
return wrote, err
}
+37 -21
View File
@@ -8,24 +8,28 @@ import (
)
type Reader struct {
r io.Reader
d decompress.Decompressor
frag *Reader
sizes []uint32
dat []byte
curOffset uint16
curIndex uint64
r io.Reader
d decompress.Decompressor
frag io.Reader
sizes []uint32
dat []byte
curOffset int
curIndex uint64
finalBlockSize uint64
blockSize uint32
}
func NewReader(r io.Reader, d decompress.Decompressor, sizes []uint32) *Reader {
func NewReader(r io.Reader, d decompress.Decompressor, sizes []uint32, finalBlockSize uint64, blockSize uint32) *Reader {
return &Reader{
r: r,
d: d,
sizes: sizes,
r: r,
d: d,
sizes: sizes,
finalBlockSize: finalBlockSize,
blockSize: blockSize,
}
}
func (r *Reader) AddFrag(fragRdr *Reader) {
func (r *Reader) AddFrag(fragRdr io.Reader) {
r.frag = fragRdr
}
@@ -33,13 +37,21 @@ func (r *Reader) advance() error {
r.curOffset = 0
defer func() { r.curIndex++ }()
var err error
if r.curIndex == uint64(len(r.sizes))-1 && r.frag != nil {
if r.curIndex == uint64(len(r.sizes)) && r.frag != nil {
r.dat, err = io.ReadAll(r.frag)
return err
} else if r.curIndex >= uint64(len(r.sizes))-1 {
} else if r.curIndex >= uint64(len(r.sizes)) {
return io.EOF
}
realSize := r.sizes[r.curIndex] &^ 0x8000
realSize := r.sizes[r.curIndex] &^ (1 << 24)
if realSize == 0 {
if r.curIndex == uint64(len(r.sizes))-1 && r.frag == nil {
r.dat = make([]byte, r.finalBlockSize)
} else {
r.dat = make([]byte, r.blockSize)
}
return nil
}
r.dat = make([]byte, realSize)
err = binary.Read(r.r, binary.LittleEndian, &r.dat)
if err != nil {
@@ -56,17 +68,17 @@ func (r *Reader) Read(b []byte) (int, error) {
curRead := 0
var toRead int
for curRead < len(b) {
if r.curOffset >= uint16(len(r.dat)) {
if r.curOffset >= len(r.dat) {
if err := r.advance(); err != nil {
return curRead, err
}
}
toRead = len(b) - curRead
if toRead > len(r.dat)-int(r.curOffset) {
toRead = len(r.dat) - int(r.curOffset)
if toRead > len(r.dat)-r.curOffset {
toRead = len(r.dat) - r.curOffset
}
copy(b[curRead:], r.dat[r.curOffset:int(r.curOffset)+toRead])
r.curOffset += uint16(toRead)
toRead = copy(b[curRead:], r.dat[r.curOffset:r.curOffset+toRead])
r.curOffset += toRead
curRead += toRead
}
return curRead, nil
@@ -74,7 +86,11 @@ func (r *Reader) Read(b []byte) (int, error) {
func (r *Reader) Close() error {
if r.frag != nil {
return r.frag.Close()
if l, ok := r.frag.(*io.LimitedReader); ok {
if cl, ok := l.R.(io.Closer); ok {
cl.Close()
}
}
}
r.dat = nil
return nil
+12 -13
View File
@@ -2,6 +2,7 @@ package squashfs
import (
"errors"
"fmt"
"io/fs"
"path/filepath"
"slices"
@@ -18,7 +19,12 @@ type Directory struct {
Entries []directory.Entry
}
func (r *Reader) directoryFromInode(i *inode.Inode, name string) (*Directory, error) {
func (r *Reader) directoryFromRef(ref uint64, name string) (*Directory, error) {
i, err := r.inodeFromRef(ref)
if err != nil {
fmt.Println("yo")
return nil, err
}
var blockStart uint32
var size uint32
var offset uint16
@@ -34,8 +40,9 @@ func (r *Reader) directoryFromInode(i *inode.Inode, name string) (*Directory, er
default:
return nil, errors.New("not a directory")
}
dirRdr := metadata.NewReader(toreader.NewReader(r.r, int64(r.sup.DirTableStart)+int64(blockStart)), r.d)
_, err := dirRdr.Read(make([]byte, offset))
dirRdr := metadata.NewReader(toreader.NewReader(r.r, int64(r.Superblock.DirTableStart)+int64(blockStart)), r.d)
defer dirRdr.Close()
_, err = dirRdr.Read(make([]byte, offset))
if err != nil {
return nil, err
}
@@ -44,19 +51,11 @@ func (r *Reader) directoryFromInode(i *inode.Inode, name string) (*Directory, er
return nil, err
}
return &Directory{
Base: *r.baseFromInode(i, name),
Base: *r.BaseFromInode(i, name),
Entries: entries,
}, nil
}
func (r *Reader) directoryFromRef(ref uint64, name string) (*Directory, error) {
in, err := r.inodeFromRef(ref)
if err != nil {
return nil, err
}
return r.directoryFromInode(in, name)
}
func (d *Directory) Open(r *Reader, path string) (*Base, error) {
path = filepath.Clean(path)
if path == "." || path == "" {
@@ -69,7 +68,7 @@ func (d *Directory) Open(r *Reader, path string) (*Base, error) {
if !found {
return nil, fs.ErrNotExist
}
b, err := r.baseFromEntry(d.Entries[i])
b, err := r.BaseFromEntry(d.Entries[i])
if err != nil {
return nil, err
}
+2 -2
View File
@@ -1,7 +1,7 @@
package squashfs
type fragEntry struct {
start uint64
size uint32
Start uint64
Size uint32
_ uint32
}
+3 -2
View File
@@ -7,11 +7,12 @@ import (
)
func (r *Reader) inodeFromRef(ref uint64) (*inode.Inode, error) {
offset, meta := (ref>>16)+r.sup.InodeTableStart, ref&0xFFFF
offset, meta := (ref>>16)+r.Superblock.InodeTableStart, ref&0xFFFF
rdr := metadata.NewReader(toreader.NewReader(r.r, int64(offset)), r.d)
defer rdr.Close()
_, err := rdr.Read(make([]byte, meta))
if err != nil {
return nil, err
}
return inode.Read(rdr, r.sup.BlockSize)
return inode.Read(rdr, r.Superblock.BlockSize)
}
+68 -34
View File
@@ -8,7 +8,9 @@ import (
"time"
"github.com/CalebQ42/squashfs/internal/decompress"
"github.com/CalebQ42/squashfs/internal/metadata"
"github.com/CalebQ42/squashfs/internal/toreader"
"github.com/CalebQ42/squashfs/squashfs/inode"
)
// The types of compression supported by squashfs
@@ -31,30 +33,30 @@ var (
type Reader struct {
r io.ReaderAt
d decompress.Decompressor
root *Directory
Root *Directory
fragTable []fragEntry
idTable []uint32
exportTable []uint64
sup superblock
Superblock superblock
}
func NewReader(r io.ReaderAt) (rdr *Reader, err error) {
rdr = new(Reader)
rdr.r = r
err = binary.Read(toreader.NewReader(r, 0), binary.LittleEndian, &rdr.sup)
err = binary.Read(toreader.NewReader(r, 0), binary.LittleEndian, &rdr.Superblock)
if err != nil {
return nil, errors.Join(errors.New("failed to read superblock"), err)
}
if !rdr.sup.checkMagic() {
if !rdr.Superblock.ValidMagic() {
return nil, ErrorMagic
}
if !rdr.sup.checkBlockLog() {
if !rdr.Superblock.ValidBlockLog() {
return nil, ErrorLog
}
if !rdr.sup.checkVersion() {
if !rdr.Superblock.ValidVersion() {
return nil, ErrorVersion
}
switch rdr.sup.CompType {
switch rdr.Superblock.CompType {
case ZlibCompression:
rdr.d = decompress.Zlib{}
case LZMACompression:
@@ -70,7 +72,7 @@ func NewReader(r io.ReaderAt) (rdr *Reader, err error) {
default:
return nil, errors.New("invalid compression type. possible corrupted archive")
}
rdr.root, err = rdr.directoryFromRef(rdr.sup.RootInodeRef, "")
rdr.Root, err = rdr.directoryFromRef(rdr.Superblock.RootInodeRef, "")
if err != nil {
return nil, errors.Join(errors.New("failed to read root directory"), err)
}
@@ -79,36 +81,44 @@ func NewReader(r io.ReaderAt) (rdr *Reader, err error) {
// Returns the last time the archive was modified.
func (r *Reader) ModTime() time.Time {
return time.Unix(int64(r.sup.ModTime), 0)
return time.Unix(int64(r.Superblock.ModTime), 0)
}
// Get a uid/gid at the given index. Lazily populates the reader's id table as necessary.
func (r *Reader) id(i uint16) (uint32, error) {
// Get a uid/gid at the given index. Lazily populates the reader's Id table as necessary.
func (r *Reader) Id(i uint16) (uint32, error) {
if len(r.idTable) > int(i) {
return r.idTable[i], nil
} else if i >= r.sup.IdCount {
} else if i >= r.Superblock.IdCount {
return 0, errors.New("id out of bounds")
}
// Populate the id table as needed
blockNum := uint16(math.Ceil(float64(i) / 2048))
var blockNum uint32
if i != 0 { // If i == 0, we go negatives causing issues with uint32s
blockNum = uint32(math.Ceil(float64(i)/2048)) - 1
} else {
blockNum = 0
}
blocksRead := len(r.idTable) / 2048
blocksToRead := int(blockNum) - blocksRead
blocksToRead := int(blockNum) - blocksRead + 1
var offset uint64
var idsToRead uint16
var idsTmp []uint32
var err error
for i := blocksRead; i < int(blockNum)+blocksToRead; i++ {
err = binary.Read(toreader.NewReader(r.r, int64(r.sup.IdTableStart)+int64(8*i)), binary.LittleEndian, &offset)
var rdr *metadata.Reader
for i := blocksRead; i < int(blocksRead)+blocksToRead; i++ {
err = binary.Read(toreader.NewReader(r.r, int64(r.Superblock.IdTableStart)+int64(8*i)), binary.LittleEndian, &offset)
if err != nil {
return 0, err
}
idsToRead = r.sup.IdCount - uint16(len(r.idTable))
idsToRead = r.Superblock.IdCount - uint16(len(r.idTable))
if idsToRead > 2048 {
idsToRead = 2048
}
idsTmp = make([]uint32, idsToRead)
err = binary.Read(toreader.NewReader(r.r, int64(offset)), binary.LittleEndian, &idsTmp)
rdr = metadata.NewReader(toreader.NewReader(r.r, int64(offset)), r.d)
err = binary.Read(rdr, binary.LittleEndian, &idsTmp)
rdr.Close()
if err != nil {
return 0, err
}
@@ -121,29 +131,37 @@ func (r *Reader) id(i uint16) (uint32, error) {
func (r *Reader) fragEntry(i uint32) (fragEntry, error) {
if len(r.fragTable) > int(i) {
return r.fragTable[i], nil
} else if i >= r.sup.FragCount {
} else if i >= r.Superblock.FragCount {
return fragEntry{}, errors.New("fragment out of bounds")
}
// Populate the fragment table as needed
blockNum := uint32(math.Ceil(float64(i) / 512))
var blockNum uint32
if i != 0 { // If i == 0, we go negatives causing issues with uint32s
blockNum = uint32(math.Ceil(float64(i)/512)) - 1
} else {
blockNum = 0
}
blocksRead := len(r.fragTable) / 512
blocksToRead := int(blockNum) - blocksRead
blocksToRead := int(blockNum) - blocksRead + 1
var offset uint64
var fragsToRead uint32
var fragsTmp []fragEntry
var err error
for i := blocksRead; i < int(blockNum)+blocksToRead; i++ {
err = binary.Read(toreader.NewReader(r.r, int64(r.sup.FragTableStart)+int64(8*i)), binary.LittleEndian, &offset)
var rdr *metadata.Reader
for i := blocksRead; i < int(blocksRead)+blocksToRead; i++ {
err = binary.Read(toreader.NewReader(r.r, int64(r.Superblock.FragTableStart)+int64(8*i)), binary.LittleEndian, &offset)
if err != nil {
return fragEntry{}, err
}
fragsToRead = r.sup.FragCount - uint32(len(r.fragTable))
fragsToRead = r.Superblock.FragCount - uint32(len(r.fragTable))
if fragsToRead > 512 {
fragsToRead = 512
}
fragsTmp = make([]fragEntry, fragsToRead)
err = binary.Read(toreader.NewReader(r.r, int64(offset)), binary.LittleEndian, &fragsTmp)
rdr = metadata.NewReader(toreader.NewReader(r.r, int64(offset)), r.d)
err = binary.Read(rdr, binary.LittleEndian, &fragsTmp)
rdr.Close()
if err != nil {
return fragEntry{}, err
}
@@ -154,34 +172,42 @@ func (r *Reader) fragEntry(i uint32) (fragEntry, error) {
// Get an inode reference at the given index. Lazily populates the reader's export table as necessary.
func (r *Reader) inodeRef(i uint32) (uint64, error) {
if !r.sup.exportable() {
if !r.Superblock.Exportable() {
return 0, ErrorNotExportable
}
if len(r.exportTable) > int(i) {
return r.exportTable[i], nil
} else if i >= r.sup.InodeCount {
} else if i >= r.Superblock.InodeCount {
return 0, errors.New("inode out of bounds")
}
// Populate the export table as neede
blockNum := uint32(math.Ceil(float64(i) / 1024))
// Populate the export table as needed
var blockNum uint32
if i != 0 { // If i == 0, we go negatives causing issues with uint32s
blockNum = uint32(math.Ceil(float64(i)/1024)) - 1
} else {
blockNum = 0
}
blocksRead := len(r.exportTable) / 1024
blocksToRead := int(blockNum) - blocksRead
blocksToRead := int(blockNum) - blocksRead + 1
var offset uint64
var refsToRead uint32
var refsTmp []uint64
var err error
for i := blocksRead; i < int(blockNum)+blocksToRead; i++ {
err = binary.Read(toreader.NewReader(r.r, int64(r.sup.ExportTableStart)+int64(8*i)), binary.LittleEndian, &offset)
var rdr *metadata.Reader
for i := blocksRead; i < int(blocksRead)+blocksToRead; i++ {
err = binary.Read(toreader.NewReader(r.r, int64(r.Superblock.ExportTableStart)+int64(8*i)), binary.LittleEndian, &offset)
if err != nil {
return 0, err
}
refsToRead = r.sup.InodeCount - uint32(len(r.exportTable))
refsToRead = r.Superblock.InodeCount - uint32(len(r.exportTable))
if refsToRead > 1024 {
refsToRead = 1024
}
refsTmp = make([]uint64, refsToRead)
err = binary.Read(toreader.NewReader(r.r, int64(offset)), binary.LittleEndian, &refsTmp)
rdr = metadata.NewReader(toreader.NewReader(r.r, int64(offset)), r.d)
err = binary.Read(rdr, binary.LittleEndian, &refsTmp)
rdr.Close()
if err != nil {
return 0, err
}
@@ -189,3 +215,11 @@ func (r *Reader) inodeRef(i uint32) (uint64, error) {
}
return r.exportTable[i], nil
}
func (r *Reader) Inode(i uint32) (*inode.Inode, error) {
ref, err := r.inodeRef(i)
if err != nil {
return nil, err
}
return r.inodeFromRef(ref)
}
+59 -14
View File
@@ -1,21 +1,18 @@
package squashfs
import (
"fmt"
"io"
"net/http"
"os"
"os/exec"
"path/filepath"
"testing"
"github.com/CalebQ42/squashfs/squashfs/inode"
)
const (
squashfsURL = "https://darkstorm.tech/files/LinuxPATest.sfs"
squashfsName = "LinuxPATest.sfs"
// filePath = "PortableApps/Notepad++Portable/App/DefaultData/Config/contextMenu.xml"
)
func preTest(dir string) (fil *os.File, err error) {
@@ -62,26 +59,74 @@ func TestReader(t *testing.T) {
if err != nil {
t.Fatal(err)
}
err = checkDir(rdr, rdr.root)
path := filepath.Join(tmpDir, "extractTest")
os.RemoveAll(path)
os.MkdirAll(path, 0777)
err = extractToDir(rdr, &rdr.Root.Base, path)
t.Fatal(err)
}
func checkDir(rdr *Reader, d *Directory) error {
for _, e := range d.Entries {
if e.InodeType == inode.Dir {
b, err := d.Open(rdr, e.Name)
var singleFile = "PortableApps/CPU-X/CPU-X-v4.2.0-x86_64.AppImage"
func TestSingleFile(t *testing.T) {
tmpDir := "../testing"
fil, err := preTest(tmpDir)
if err != nil {
t.Fatal(err)
}
defer fil.Close()
rdr, err := NewReader(fil)
if err != nil {
t.Fatal(err)
}
path := filepath.Join(tmpDir, "extractTest")
os.RemoveAll(path)
os.MkdirAll(path, 0777)
b, err := rdr.Root.Open(rdr, singleFile)
if err != nil {
t.Fatal(err)
}
err = extractToDir(rdr, b, path)
t.Fatal(err)
}
func extractToDir(rdr *Reader, b *Base, folder string) error {
path := filepath.Join(folder, b.Name)
if b.IsDir() {
d, err := b.ToDir(rdr)
if err != nil {
return err
}
err = os.MkdirAll(path, 0777)
if err != nil {
return err
}
var nestBast *Base
for _, e := range d.Entries {
nestBast, err = rdr.BaseFromEntry(e)
if err != nil {
return err
}
d, err := b.ToDir(rdr)
if err != nil {
return err
}
err = checkDir(rdr, d)
err = extractToDir(rdr, nestBast, path)
if err != nil {
return err
}
}
} else if b.IsRegular() {
_, full, err := b.GetRegFileReaders(rdr)
if err != nil {
fmt.Println("yo", path)
return err
}
fil, err := os.Create(path)
if err != nil {
return err
}
_, err = full.WriteTo(fil)
if err != nil {
return err
}
fmt.Println("Successfully extracted file:", b.Name)
}
return nil
}
+14 -14
View File
@@ -24,57 +24,57 @@ type superblock struct {
ExportTableStart uint64
}
func (s superblock) checkMagic() bool {
func (s superblock) ValidMagic() bool {
return s.Magic == 0x73717368
}
func (s superblock) checkBlockLog() bool {
func (s superblock) ValidBlockLog() bool {
return s.BlockLog == uint16(math.Log2(float64(s.BlockSize)))
}
func (s superblock) checkVersion() bool {
func (s superblock) ValidVersion() bool {
return s.VerMaj == 4 && s.VerMin == 0
}
func (s superblock) uncompressedInodes() bool {
func (s superblock) UncompressedInodes() bool {
return s.Flags&0x1 == 0x1
}
func (s superblock) uncompressedData() bool {
func (s superblock) UncompressedData() bool {
return s.Flags&0x2 == 0x2
}
func (s superblock) uncompressedFragments() bool {
func (s superblock) UncompressedFragments() bool {
return s.Flags&0x8 == 0x8
}
func (s superblock) noFragments() bool {
func (s superblock) NoFragments() bool {
return s.Flags&0x10 == 0x10
}
func (s superblock) alwaysFragment() bool {
func (s superblock) AlwaysFragment() bool {
return s.Flags&0x20 == 0x20
}
func (s superblock) duplicates() bool {
func (s superblock) Duplicates() bool {
return s.Flags&0x40 == 0x40
}
func (s superblock) exportable() bool {
func (s superblock) Exportable() bool {
return s.Flags&0x80 == 0x80
}
func (s superblock) uncompressedXattrs() bool {
func (s superblock) UncompressedXattrs() bool {
return s.Flags&0x100 == 0x100
}
func (s superblock) noXattrs() bool {
func (s superblock) NoXattrs() bool {
return s.Flags&0x200 == 0x200
}
func (s superblock) compressionOptions() bool {
func (s superblock) CompressionOptions() bool {
return s.Flags&0x400 == 0x400
}
func (s superblock) uncompressedIDs() bool {
func (s superblock) UncompressedIDs() bool {
return s.Flags&0x800 == 0x800
}