From 7a22538623d4f96715b40ab861e43e3fdcf825fd Mon Sep 17 00:00:00 2001 From: Caleb Gardner Date: Fri, 26 Aug 2022 05:01:17 -0500 Subject: [PATCH] Finishing touches? --- exp_test.go | 303 ---------------------------------------------------- go.mod | 11 +- go.sum | 43 +------- reader.go | 82 +++++++------- 4 files changed, 47 insertions(+), 392 deletions(-) delete mode 100644 exp_test.go diff --git a/exp_test.go b/exp_test.go deleted file mode 100644 index 9d6ac62..0000000 --- a/exp_test.go +++ /dev/null @@ -1,303 +0,0 @@ -package squashfs - -//A place for temporary, expiremental tests. Not meant for actual testing purposes. - -import ( - "fmt" - "io" - "net/http" - "os" - "os/exec" - "strconv" - "testing" - "time" - - goappimage "github.com/CalebQ42/GoAppImage" -) - -const ( - appImageURL = "https://github.com/srevinsaju/Firefox-Appimage/releases/download/firefox-v84.0.r20201221152838/firefox-84.0.r20201221152838-x86_64.AppImage" - appImageName = "firefox-84.0.r20201221152838-x86_64.AppImage" - squashfsURL = "https://darkstorm.tech/LinuxPATest.sfs" - squashfsName = "LinuxPATest.sfs" -) - -func TestSquashfs(t *testing.T) { - wd, err := os.Getwd() - if err != nil { - t.Fatal(err) - } - squashFil, err := os.Open(wd + "/testing/" + squashfsName) - if os.IsNotExist(err) { - err = downloadTestSquash(wd + "/testing") - if err != nil { - t.Fatal(err) - } - squashFil, err = os.Open(wd + "/testing/" + squashfsName) - } - if err != nil { - t.Fatal(err) - } - rdr, err := NewReader(squashFil) - if err != nil { - t.Fatal(err) - } - os.RemoveAll(wd + "/testing/" + squashfsName + ".d") - op := DefaultOptions() - op.Verbose = true - err = rdr.ExtractWithOptions(wd+"/testing/"+squashfsName+".d", op) - if err != nil { - t.Fatal(err) - } - t.Fatal("No Problems") -} - -func TestSquashfsFromReader(t *testing.T) { - resp, err := http.DefaultClient.Get(squashfsURL) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - rdr, err := NewReaderFromReader(resp.Body) - if err != nil { - t.Fatal(err) - } - os.RemoveAll("testing/" + squashfsName + ".d") - op := DefaultOptions() - op.Verbose = true - err = rdr.ExtractWithOptions("testing/"+squashfsName+".d", op) - if err != nil { - t.Fatal(err) - } - t.Fatal("No Problems") -} - -func TestAppImage(t *testing.T) { - t.Parallel() - wd, err := os.Getwd() - if err != nil { - t.Fatal(err) - } - aiFil, err := os.Open(wd + "/testing/" + appImageName) - if os.IsNotExist(err) { - err = downloadTestAppImage(wd + "/testing") - if err != nil { - t.Fatal(err) - } - aiFil, err = os.Open(wd + "/testing/" + appImageName) - if err != nil { - t.Fatal(err) - } - } else if err != nil { - t.Fatal(err) - } - defer aiFil.Close() - stat, _ := aiFil.Stat() - ai := goappimage.NewAppImage(wd + "/testing/" + appImageName) - rdr, err := NewReader(io.NewSectionReader(aiFil, ai.Offset, stat.Size()-ai.Offset)) - if err != nil { - t.Fatal(err) - } - os.RemoveAll(wd + "/testing/firefox") - op := DefaultOptions() - op.Verbose = true - err = rdr.ExtractWithOptions(wd+"/testing/firefox", op) - t.Fatal(err) -} - -func TestUnsquashfs(t *testing.T) { - t.Parallel() - wd, err := os.Getwd() - if err != nil { - t.Fatal(err) - } - aiFil, err := os.Open(wd + "/testing/" + appImageName) - if os.IsNotExist(err) { - err = downloadTestAppImage(wd + "/testing") - if err != nil { - t.Fatal(err) - } - aiFil, err = os.Open(wd + "/testing/" + appImageName) - if err != nil { - t.Fatal(err) - } - } else if err != nil { - t.Fatal(err) - } - os.RemoveAll(wd + "/testing/unsquashFirefox") - os.RemoveAll(wd + "/testing/firefox") - ai := goappimage.NewAppImage(wd + "/testing/" + appImageName) - fmt.Println("Command:", "unsquashfs", "-d", wd+"/testing/unsquashFirefox", "-o", strconv.Itoa(int(ai.Offset)), aiFil.Name()) - cmd := exec.Command("unsquashfs", "-d", wd+"/testing/unsquashFirefox", "-o", strconv.Itoa(int(ai.Offset)), aiFil.Name()) - start := time.Now() - err = cmd.Run() - if err != nil { - t.Fatal(err) - } - fmt.Println(time.Since(start)) - t.Fatal("HI") -} - -func BenchmarkDragRace(b *testing.B) { - wd, err := os.Getwd() - if err != nil { - b.Fatal(err) - } - aiFil, err := os.Open(wd + "/testing/" + appImageName) - if os.IsNotExist(err) { - err = downloadTestAppImage(wd + "/testing") - if err != nil { - b.Fatal(err) - } - aiFil, err = os.Open(wd + "/testing/" + appImageName) - if err != nil { - b.Fatal(err) - } - } else if err != nil { - b.Fatal(err) - } - stat, _ := aiFil.Stat() - ai := goappimage.NewAppImage(wd + "/testing/" + appImageName) - os.RemoveAll(wd + "/testing/unsquashFirefox") - os.RemoveAll(wd + "/testing/firefox") - cmd := exec.Command("unsquashfs", "-d", wd+"/testing/unsquashFirefox", "-o", strconv.Itoa(int(ai.Offset)), aiFil.Name()) - start := time.Now() - err = cmd.Run() - if err != nil { - b.Fatal(err) - } - unsquashTime := time.Since(start) - start = time.Now() - rdr, err := NewReader(io.NewSectionReader(aiFil, ai.Offset, stat.Size()-ai.Offset)) - if err != nil { - b.Fatal(err) - } - err = rdr.ExtractTo(wd + "/testing/firefox") - if err != nil { - b.Fatal(err) - } - libTime := time.Since(start) - b.Log("Unsqushfs:", unsquashTime.Round(time.Millisecond)) - b.Log("Library:", libTime.Round(time.Millisecond)) - b.Log("unsquashfs is", strconv.FormatFloat(float64(libTime.Milliseconds())/float64(unsquashTime.Milliseconds()), 'f', 2, 64)+"x faster") - b.Error("STOP ALREADY!") -} - -func downloadTestAppImage(dir string) error { - //seems to time out on slow connections. Might fix that at some point... or not. It's just a test... - os.Mkdir(dir, os.ModePerm) - appImage, err := os.Create(dir + "/" + appImageName) - if err != nil { - return err - } - defer appImage.Close() - check := http.Client{ - CheckRedirect: func(r *http.Request, _ []*http.Request) error { - r.URL.Opaque = r.URL.Path - return nil - }, - } - resp, err := check.Get(appImageURL) - if err != nil { - return err - } - defer resp.Body.Close() - _, err = io.Copy(appImage, resp.Body) - if err != nil { - return err - } - return nil -} - -func downloadTestSquash(dir string) error { - //seems to time out on slow connections. Might fix that at some point... or not. It's just a test... - os.Mkdir(dir, os.ModePerm) - sfs, err := os.Create(dir + "/" + squashfsName) - if err != nil { - return err - } - defer sfs.Close() - check := http.Client{ - CheckRedirect: func(r *http.Request, _ []*http.Request) error { - r.URL.Opaque = r.URL.Path - return nil - }, - } - resp, err := check.Get(squashfsURL) - if err != nil { - return err - } - defer resp.Body.Close() - _, err = io.Copy(sfs, resp.Body) - if err != nil { - return err - } - return nil -} - -func TestCreateSquashFromAppImage(t *testing.T) { - wd, err := os.Getwd() - if err != nil { - t.Fatal(err) - } - err = os.Mkdir(wd+"/testing", 0777) - if err != nil && !os.IsExist(err) { - t.Fatal(err) - } - _, err = os.Open(wd + "/testing/" + appImageName) - if os.IsNotExist(err) { - err = downloadTestAppImage(wd + "/testing") - if err != nil { - t.Fatal(err) - } - _, err = os.Open(wd + "/testing/" + appImageName) - if err != nil { - t.Fatal(err) - } - } else if err != nil { - t.Fatal(err) - } - ai := goappimage.NewAppImage(wd + "/testing/" + appImageName) - aiFil, err := os.Open(wd + "/testing/" + appImageName) - if err != nil { - t.Fatal(err) - } - defer aiFil.Close() - aiFil.Seek(ai.Offset, 0) - os.Remove(wd + "/testing/" + appImageName + ".squashfs") - aiSquash, err := os.Create(wd + "/testing/" + appImageName + ".squashfs") - if err != nil { - t.Fatal(err) - } - _, err = io.Copy(aiSquash, aiFil) - if err != nil { - t.Fatal(err) - } -} - -func TestSTUFF(t *testing.T) { - t.Parallel() - wd, err := os.Getwd() - if err != nil { - t.Fatal(err) - } - aiFil, err := os.Open(wd + "/testing/" + squashfsName) - if err != nil { - t.Fatal(err) - } - defer aiFil.Close() - rdr, err := NewReader(aiFil) - if err != nil { - t.Fatal(err) - } - os.Remove(wd + "/testing/test.ini") - testOut, _ := os.Create(wd + "/testing/test.ini") - testFil, err := rdr.Open("Documents/Pictures/Desktop.ini") - if err != nil { - t.Fatal(err) - } - _, err = io.Copy(testOut, testFil) - if err != nil { - t.Fatal(err) - } -} diff --git a/go.mod b/go.mod index a4a50a8..9d2ebef 100644 --- a/go.mod +++ b/go.mod @@ -1,18 +1,11 @@ module github.com/CalebQ42/squashfs -go 1.18 +go 1.19 require ( - github.com/CalebQ42/GoAppImage v0.5.0 - github.com/klauspost/compress v1.15.6 + github.com/klauspost/compress v1.15.9 github.com/pierrec/lz4/v4 v4.1.15 github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e github.com/therootcompany/xz v1.0.1 github.com/ulikunitz/xz v0.5.10 ) - -require ( - github.com/adrg/xdg v0.2.2 // indirect - go.lsp.dev/uri v0.3.0 // indirect - gopkg.in/ini.v1 v1.62.0 // indirect -) diff --git a/go.sum b/go.sum index 0b25bdb..4d3fc78 100644 --- a/go.sum +++ b/go.sum @@ -1,49 +1,10 @@ -github.com/CalebQ42/GoAppImage v0.5.0 h1:znoKNXtliH754tS9sYwyOIg/0wFDjFN5Twc7PAh1rSM= -github.com/CalebQ42/GoAppImage v0.5.0/go.mod h1:qHudJKAn/dlkNWNnH4h1YKXp29EZ7Bppsn7sNP2HuvU= -github.com/adrg/xdg v0.2.2 h1:A7ZHKRz5KGOLJX/bg7IPzStryhvCzAE1wX+KWawPiAo= -github.com/adrg/xdg v0.2.2/go.mod h1:7I2hH/IT30IsupOpKZ5ue7/qNi3CoKzD6tL3HwpaRMQ= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/klauspost/compress v1.15.6 h1:6D9PcO8QWu0JyaQ2zUMmu16T1T+zjjEpP91guRsvDfY= -github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0= github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e h1:dCWirM5F3wMY+cmRda/B1BiPsFtmzXqV9b0hLWtVBMs= github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e/go.mod h1:9leZcVcItj6m9/CfHY5Em/iBrCz7js8LcRQGTKEEv2M= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY= github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -go.lsp.dev/uri v0.3.0 h1:KcZJmh6nFIBeJzTugn5JTU6OOyG0lDOo3R9KwTxTYbo= -go.lsp.dev/uri v0.3.0/go.mod h1:P5sbO1IQR+qySTWOCnhnK7phBx+W3zbLqSMDJNTw88I= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/reader.go b/reader.go index a0dc1f0..225830d 100644 --- a/reader.go +++ b/reader.go @@ -20,8 +20,8 @@ type Reader struct { r io.ReaderAt fragEntries []fragEntry ids []uint32 - exportTable []uint64 - s superblock + // exportTable []uint64 + s superblock } var ( @@ -30,6 +30,7 @@ var ( ErrorVersion = errors.New("squashfs version of archive is not 4.0") ) +// The types of compression supported by squashfs const ( GZipCompression = uint16(iota + 1) LZMACompression @@ -39,6 +40,7 @@ const ( ZSTDCompression ) +// Creates a new squashfs.Reader from the given io.Reader. NOTE: All data from the io.Reader will be read and stored in memory. func NewReaderFromReader(r io.Reader) (*Reader, error) { rdr, err := toreader.NewReaderAt(r) if err != nil { @@ -47,6 +49,7 @@ func NewReaderFromReader(r io.Reader) (*Reader, error) { return NewReader(rdr) } +// Creates a new squashfs.Reader from the given io.ReaderAt. func NewReader(r io.ReaderAt) (*Reader, error) { var squash Reader squash.r = r @@ -176,45 +179,46 @@ func NewReader(r io.ReaderAt) (*Reader, error) { return &squash, nil } -func (r *Reader) initExport() (err error) { - num := int(math.Ceil(float64(r.s.InodeCount) / 1024)) - offsets := make([]uint64, num) - err = binary.Read(toreader.NewReader(r.r, int64(r.s.ExportTableStart)), binary.LittleEndian, &offsets) - if err != nil { - return - } - left := r.s.InodeCount - var toRead uint32 - var new []uint64 - var rdr *metadata.Reader - for i := range offsets { - rdr = metadata.NewReader(toreader.NewReader(r.r, int64(offsets[i])), r.d) - toRead = uint32(math.Min(1024, float64(left))) - new = make([]uint64, toRead) - err = binary.Read(rdr, binary.LittleEndian, &new) - if err != nil { - return - } - left -= toRead - r.exportTable = append(r.exportTable, new...) - } - return nil -} +// func (r *Reader) initExport() (err error) { +// num := int(math.Ceil(float64(r.s.InodeCount) / 1024)) +// offsets := make([]uint64, num) +// err = binary.Read(toreader.NewReader(r.r, int64(r.s.ExportTableStart)), binary.LittleEndian, &offsets) +// if err != nil { +// return +// } +// left := r.s.InodeCount +// var toRead uint32 +// var new []uint64 +// var rdr *metadata.Reader +// for i := range offsets { +// rdr = metadata.NewReader(toreader.NewReader(r.r, int64(offsets[i])), r.d) +// toRead = uint32(math.Min(1024, float64(left))) +// new = make([]uint64, toRead) +// err = binary.Read(rdr, binary.LittleEndian, &new) +// if err != nil { +// return +// } +// left -= toRead +// r.exportTable = append(r.exportTable, new...) +// } +// return nil +// } -func (r *Reader) inode(index uint32) (i inode.Inode, err error) { - if r.s.exportable() { - if r.exportTable == nil { - err = r.initExport() - if err != nil { - return - } - } - return r.inodeFromRef(r.exportTable[index-1]) - } - err = errors.New("archive is not exportable") - return -} +// func (r *Reader) inode(index uint32) (i inode.Inode, err error) { +// if r.s.exportable() { +// if r.exportTable == nil { +// err = r.initExport() +// if err != nil { +// return +// } +// } +// return r.inodeFromRef(r.exportTable[index-1]) +// } +// err = errors.New("archive is not exportable") +// return +// } +// Returns the last time the archive was modified. func (r Reader) ModTime() time.Time { return time.Unix(int64(r.s.ModTime), 0) }