Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f242de2710 | |||
| 88315ee384 | |||
| 1e2a8f4b75 | |||
| 863b03fb19 | |||
| d3f84344d1 | |||
| ad24995b7b | |||
| 638355ab71 | |||
| 04d914d403 | |||
| 7323fe56f6 | |||
| 6286da31e1 | |||
| 77c87a9653 | |||
| e6b0b83dcb | |||
| cef9090210 | |||
| 24a9457c6b | |||
| e0c1309ed4 | |||
| 8b475b6cc4 | |||
| 3a48a0bcdc | |||
| f11416493e | |||
| 619bb023b1 | |||
| 38e4761d21 | |||
| 06d2ef3056 | |||
| 446f29df70 | |||
| d6c8efcfe6 | |||
| d890932d5c | |||
| 87b5ac7f5d |
@@ -11,6 +11,10 @@ Currently has support for reading squashfs files and extracting files and folder
|
|||||||
Special thanks to <https://dr-emann.github.io/squashfs/> for some VERY important information in an easy to understand format.
|
Special thanks to <https://dr-emann.github.io/squashfs/> for some VERY important information in an easy to understand format.
|
||||||
Thanks also to [distri's squashfs library](https://github.com/distr1/distri/tree/master/internal/squashfs) as I referenced it to figure some things out (and double check others).
|
Thanks also to [distri's squashfs library](https://github.com/distr1/distri/tree/master/internal/squashfs) as I referenced it to figure some things out (and double check others).
|
||||||
|
|
||||||
|
## Build tags
|
||||||
|
|
||||||
|
As of `v1.1.0` this library has two optional build tags: `no_gpl` and `no_obsolete`. `no_gpl` disables the ability to read archives with lzo compression due to the library's gpl license. `no_obsolete` removes "obsolete" compression types for a reduced compilation size; currently this only disable lzma compression since it's superseded by xz.
|
||||||
|
|
||||||
## FUSE
|
## FUSE
|
||||||
|
|
||||||
As of `v1.0`, FUSE capabilities has been moved to [a separate library](https://github.com/CalebQ42/squashfuse).
|
As of `v1.0`, FUSE capabilities has been moved to [a separate library](https://github.com/CalebQ42/squashfuse).
|
||||||
|
|||||||
@@ -3,14 +3,62 @@ package main
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
"os/user"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/CalebQ42/squashfs"
|
"github.com/CalebQ42/squashfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func userName(uid int, numeric bool) string {
|
||||||
|
us := strconv.Itoa(uid)
|
||||||
|
if numeric {
|
||||||
|
return us
|
||||||
|
}
|
||||||
|
if u, err := user.LookupId(us); err == nil {
|
||||||
|
return u.Username
|
||||||
|
}
|
||||||
|
return us
|
||||||
|
}
|
||||||
|
|
||||||
|
func groupName(gid int, numeric bool) string {
|
||||||
|
gs := strconv.Itoa(gid)
|
||||||
|
if numeric {
|
||||||
|
return gs
|
||||||
|
}
|
||||||
|
if g, err := user.LookupGroupId(gs); err == nil {
|
||||||
|
return g.Name
|
||||||
|
}
|
||||||
|
return gs
|
||||||
|
}
|
||||||
|
|
||||||
|
func printEntry(root, path string, d fs.DirEntry, numeric bool) {
|
||||||
|
fi, _ := d.Info()
|
||||||
|
sfi := fi.(squashfs.FileInfo)
|
||||||
|
owner := fmt.Sprintf("%s/%s",
|
||||||
|
userName(sfi.Uid(), numeric),
|
||||||
|
groupName(sfi.Gid(), numeric))
|
||||||
|
link := ""
|
||||||
|
if sfi.IsSymlink() {
|
||||||
|
link = " -> " + sfi.SymlinkPath()
|
||||||
|
}
|
||||||
|
fmt.Printf("%s %s %*d %s %s%s\n",
|
||||||
|
strings.ToLower(fi.Mode().String()),
|
||||||
|
owner, 26-len(owner), fi.Size(),
|
||||||
|
fi.ModTime().Format("2006-01-02 15:04"),
|
||||||
|
filepath.Join(root, path), link)
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
verbose := flag.Bool("v", false, "Verbose")
|
verbose := flag.Bool("v", false, "Verbose")
|
||||||
|
list := flag.Bool("l", false, "List")
|
||||||
|
long := flag.Bool("ll", false, "List with attributes")
|
||||||
|
numeric := flag.Bool("lln", false, "List with attributes and numeric ids")
|
||||||
|
offset := flag.Int64("o", 0, "Offset")
|
||||||
ignore := flag.Bool("ip", false, "Ignore Permissions and extract all files/folders with 0755")
|
ignore := flag.Bool("ip", false, "Ignore Permissions and extract all files/folders with 0755")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if len(flag.Args()) < 2 {
|
if len(flag.Args()) < 2 {
|
||||||
@@ -21,10 +69,25 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
r, err := squashfs.NewReader(f)
|
r, err := squashfs.NewReaderAtOffset(f, *offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
if *list || *long || *numeric {
|
||||||
|
root := flag.Arg(1)
|
||||||
|
fs.WalkDir(r, ".", func(path string, d fs.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if *long || *numeric {
|
||||||
|
printEntry(root, path, d, *numeric)
|
||||||
|
} else {
|
||||||
|
fmt.Println(filepath.Join(root, path))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
op := squashfs.DefaultOptions()
|
op := squashfs.DefaultOptions()
|
||||||
op.Verbose = *verbose
|
op.Verbose = *verbose
|
||||||
op.IgnorePerm = *ignore
|
op.IgnorePerm = *ignore
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ func (f *File) ReadDir(n int) ([]fs.DirEntry, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var out []fs.DirEntry
|
var out []fs.DirEntry
|
||||||
var fi fileInfo
|
var fi FileInfo
|
||||||
for _, e := range d.Entries[start:end] {
|
for _, e := range d.Entries[start:end] {
|
||||||
fi, err = f.r.newFileInfo(e)
|
fi, err = f.r.newFileInfo(e)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -142,7 +142,15 @@ func (f *File) ReadDir(n int) ([]fs.DirEntry, error) {
|
|||||||
|
|
||||||
// Returns the file's fs.FileInfo
|
// Returns the file's fs.FileInfo
|
||||||
func (f *File) Stat() (fs.FileInfo, error) {
|
func (f *File) Stat() (fs.FileInfo, error) {
|
||||||
return newFileInfo(f.b.Name, &f.b.Inode), nil
|
uid, err := f.b.Uid(&f.r.Low)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
gid, err := f.b.Gid(&f.r.Low)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newFileInfo(f.b.Name, uid, gid, &f.b.Inode), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SymlinkPath returns the symlink's target path. Is the File isn't a symlink, returns an empty string.
|
// SymlinkPath returns the symlink's target path. Is the File isn't a symlink, returns an empty string.
|
||||||
@@ -179,9 +187,10 @@ func (f *File) initializeReaders() error {
|
|||||||
|
|
||||||
func (f *File) deviceDevices() (maj uint32, min uint32) {
|
func (f *File) deviceDevices() (maj uint32, min uint32) {
|
||||||
var dev uint32
|
var dev uint32
|
||||||
if f.b.Inode.Type == inode.Char || f.b.Inode.Type == inode.Block {
|
switch f.b.Inode.Type {
|
||||||
|
case inode.Char, inode.Block:
|
||||||
dev = f.b.Inode.Data.(inode.Device).Dev
|
dev = f.b.Inode.Data.(inode.Device).Dev
|
||||||
} else if f.b.Inode.Type == inode.EChar || f.b.Inode.Type == inode.EBlock {
|
case inode.EChar, inode.EBlock:
|
||||||
dev = f.b.Inode.Data.(inode.EDevice).Dev
|
dev = f.b.Inode.Data.(inode.EDevice).Dev
|
||||||
}
|
}
|
||||||
return dev >> 8, dev & 0x000FF
|
return dev >> 8, dev & 0x000FF
|
||||||
@@ -266,7 +275,7 @@ func (f *File) ExtractWithOptions(path string, op *ExtractionOptions) error {
|
|||||||
}(b, path)
|
}(b, path)
|
||||||
}
|
}
|
||||||
var errCache []error
|
var errCache []error
|
||||||
for i := 0; i < len(d.Entries); i++ {
|
for range d.Entries {
|
||||||
err := <-errChan
|
err := <-errChan
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errCache = append(errCache, err)
|
errCache = append(errCache, err)
|
||||||
@@ -363,11 +372,12 @@ func (f *File) ExtractWithOptions(path string, op *ExtractionOptions) error {
|
|||||||
}
|
}
|
||||||
path = filepath.Join(path, f.b.Name)
|
path = filepath.Join(path, f.b.Name)
|
||||||
var typ string
|
var typ string
|
||||||
if f.b.Inode.Type == inode.Char || f.b.Inode.Type == inode.EChar {
|
switch f.b.Inode.Type {
|
||||||
|
case inode.Char, inode.EChar:
|
||||||
typ = "c"
|
typ = "c"
|
||||||
} else if f.b.Inode.Type == inode.Block || f.b.Inode.Type == inode.EBlock {
|
case inode.Block, inode.EBlock:
|
||||||
typ = "b"
|
typ = "b"
|
||||||
} else { //Fifo IPC
|
default: //Fifo IPC
|
||||||
if runtime.GOOS == "darwin" {
|
if runtime.GOOS == "darwin" {
|
||||||
if op.Verbose {
|
if op.Verbose {
|
||||||
log.Println(f.path(), "ignored. A Fifo file and can't be created on Darwin.")
|
log.Println(f.path(), "ignored. A Fifo file and can't be created on Darwin.")
|
||||||
|
|||||||
+74
-16
@@ -8,61 +8,119 @@ import (
|
|||||||
"github.com/CalebQ42/squashfs/low/inode"
|
"github.com/CalebQ42/squashfs/low/inode"
|
||||||
)
|
)
|
||||||
|
|
||||||
type fileInfo struct {
|
type FileInfo struct {
|
||||||
name string
|
name string
|
||||||
|
uid uint32
|
||||||
|
gid uint32
|
||||||
size int64
|
size int64
|
||||||
|
target string
|
||||||
perm uint32
|
perm uint32
|
||||||
modTime uint32
|
modTime uint32
|
||||||
fileType uint16
|
fileType uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Reader) newFileInfo(e directory.Entry) (fileInfo, error) {
|
func (r Reader) newFileInfo(e directory.Entry) (FileInfo, error) {
|
||||||
i, err := r.Low.InodeFromEntry(e)
|
b, err := r.Low.BaseFromEntry(e)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fileInfo{}, err
|
return FileInfo{}, err
|
||||||
}
|
}
|
||||||
return newFileInfo(e.Name, &i), nil
|
uid, err := b.Uid(&r.Low)
|
||||||
|
if err != nil {
|
||||||
|
return FileInfo{}, err
|
||||||
|
}
|
||||||
|
gid, err := b.Gid(&r.Low)
|
||||||
|
if err != nil {
|
||||||
|
return FileInfo{}, err
|
||||||
|
}
|
||||||
|
return newFileInfo(e.Name, uid, gid, &b.Inode), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFileInfo(name string, i *inode.Inode) fileInfo {
|
func newFileInfo(name string, uid, gid uint32, i *inode.Inode) FileInfo {
|
||||||
var size int64
|
var size int64
|
||||||
if i.Type == inode.Fil {
|
var target string
|
||||||
|
switch i.Type {
|
||||||
|
case inode.Fil:
|
||||||
size = int64(i.Data.(inode.File).Size)
|
size = int64(i.Data.(inode.File).Size)
|
||||||
} else if i.Type == inode.EFil {
|
case inode.EFil:
|
||||||
size = int64(i.Data.(inode.EFile).Size)
|
size = int64(i.Data.(inode.EFile).Size)
|
||||||
|
case inode.Sym:
|
||||||
|
target = string(i.Data.(inode.Symlink).Target)
|
||||||
|
case inode.ESym:
|
||||||
|
target = string(i.Data.(inode.ESymlink).Target)
|
||||||
}
|
}
|
||||||
return fileInfo{
|
return FileInfo{
|
||||||
name: name,
|
name: name,
|
||||||
|
uid: uid,
|
||||||
|
gid: gid,
|
||||||
size: size,
|
size: size,
|
||||||
|
target: target,
|
||||||
perm: uint32(i.Perm),
|
perm: uint32(i.Perm),
|
||||||
modTime: i.ModTime,
|
modTime: i.ModTime,
|
||||||
fileType: i.Type,
|
fileType: i.Type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f fileInfo) Name() string {
|
func (f FileInfo) Name() string {
|
||||||
return f.name
|
return f.name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f fileInfo) Size() int64 {
|
func (f FileInfo) Uid() int {
|
||||||
|
return int(f.uid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FileInfo) Gid() int {
|
||||||
|
return int(f.gid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FileInfo) Size() int64 {
|
||||||
return f.size
|
return f.size
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f fileInfo) Mode() fs.FileMode {
|
func (f FileInfo) SymlinkPath() string {
|
||||||
if f.IsDir() {
|
return f.target
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FileInfo) Mode() fs.FileMode {
|
||||||
|
switch f.fileType {
|
||||||
|
case inode.Dir, inode.EDir:
|
||||||
return fs.FileMode(f.perm | uint32(fs.ModeDir))
|
return fs.FileMode(f.perm | uint32(fs.ModeDir))
|
||||||
|
case inode.Sym, inode.ESym:
|
||||||
|
return fs.FileMode(f.perm | uint32(fs.ModeSymlink))
|
||||||
|
case inode.Char, inode.EChar, inode.Block, inode.EBlock:
|
||||||
|
return fs.FileMode(f.perm | uint32(fs.ModeDevice))
|
||||||
|
case inode.Fifo, inode.EFifo:
|
||||||
|
return fs.FileMode(f.perm | uint32(fs.ModeNamedPipe))
|
||||||
|
case inode.Sock, inode.ESock:
|
||||||
|
return fs.FileMode(f.perm | uint32(fs.ModeSocket))
|
||||||
}
|
}
|
||||||
return fs.FileMode(f.perm)
|
return fs.FileMode(f.perm)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f fileInfo) ModTime() time.Time {
|
func (f FileInfo) ModTime() time.Time {
|
||||||
return time.Unix(int64(f.modTime), 0)
|
return time.Unix(int64(f.modTime), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f fileInfo) IsDir() bool {
|
func (f FileInfo) IsDir() bool {
|
||||||
return f.fileType == inode.Dir || f.fileType == inode.EDir
|
return f.fileType == inode.Dir || f.fileType == inode.EDir
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f fileInfo) Sys() any {
|
func (f FileInfo) IsSymlink() bool {
|
||||||
|
return f.fileType == inode.Sym || f.fileType == inode.ESym
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FileInfo) IsDevice() bool {
|
||||||
|
return f.fileType == inode.Block || f.fileType == inode.EBlock ||
|
||||||
|
f.fileType == inode.Char || f.fileType == inode.EChar
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FileInfo) IsFifo() bool {
|
||||||
|
return f.fileType == inode.Fifo || f.fileType == inode.EFifo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FileInfo) IsSocket() bool {
|
||||||
|
return f.fileType == inode.Sock || f.fileType == inode.ESock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FileInfo) Sys() any {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func (f *FS) Glob(pattern string) (out []string, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
split := strings.Split(pattern, "/")
|
split := strings.Split(pattern, "/")
|
||||||
for i := 0; i < len(f.d.Entries); i++ {
|
for i := range f.d.Entries {
|
||||||
if match, _ := path.Match(split[0], f.d.Entries[i].Name); match {
|
if match, _ := path.Match(split[0], f.d.Entries[i].Name); match {
|
||||||
if len(split) == 1 {
|
if len(split) == 1 {
|
||||||
out = append(out, f.d.Entries[i].Name)
|
out = append(out, f.d.Entries[i].Name)
|
||||||
@@ -80,7 +80,7 @@ func (f *FS) Glob(pattern string) (out []string, err error) {
|
|||||||
Err: err,
|
Err: err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := 0; i < len(subGlob); i++ {
|
for i := range subGlob {
|
||||||
subGlob[i] = f.d.Name + "/" + subGlob[i]
|
subGlob[i] = f.d.Name + "/" + subGlob[i]
|
||||||
}
|
}
|
||||||
out = append(out, subGlob...)
|
out = append(out, subGlob...)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
module github.com/CalebQ42/squashfs
|
module github.com/CalebQ42/squashfs
|
||||||
|
|
||||||
go 1.22.5
|
go 1.24.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/klauspost/compress v1.17.9
|
github.com/klauspost/compress v1.18.0
|
||||||
github.com/pierrec/lz4/v4 v4.1.21
|
github.com/pierrec/lz4/v4 v4.1.22
|
||||||
github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e
|
github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e
|
||||||
github.com/therootcompany/xz v1.0.1
|
github.com/therootcompany/xz v1.0.1
|
||||||
github.com/ulikunitz/xz v0.5.12
|
github.com/ulikunitz/xz v0.5.12
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||||
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
|
||||||
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e h1:dCWirM5F3wMY+cmRda/B1BiPsFtmzXqV9b0hLWtVBMs=
|
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/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e/go.mod h1:9leZcVcItj6m9/CfHY5Em/iBrCz7js8LcRQGTKEEv2M=
|
||||||
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
|
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build !no_obsolete
|
||||||
|
|
||||||
package decompress
|
package decompress
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -9,6 +11,10 @@ import (
|
|||||||
|
|
||||||
type Lzma struct{}
|
type Lzma struct{}
|
||||||
|
|
||||||
|
func NewLzma() (Lzma, error) {
|
||||||
|
return Lzma{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (l Lzma) Decompress(data []byte) ([]byte, error) {
|
func (l Lzma) Decompress(data []byte) ([]byte, error) {
|
||||||
rdr, err := lzma.NewReader(bytes.NewReader(data))
|
rdr, err := lzma.NewReader(bytes.NewReader(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
//go:build no_obsolete
|
||||||
|
|
||||||
|
package decompress
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Lzma struct{}
|
||||||
|
|
||||||
|
func NewLzma() (Lzma, error) {
|
||||||
|
return Lzma{}, errors.New("lzma compression is disable in this build with no_obsolete")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l Lzma) Decompress(data []byte) ([]byte, error) {
|
||||||
|
return nil, errors.New("lzma compression is disable in this build with no_obsolete")
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build !no_gpl
|
||||||
|
|
||||||
package decompress
|
package decompress
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -8,6 +10,10 @@ import (
|
|||||||
|
|
||||||
type Lzo struct{}
|
type Lzo struct{}
|
||||||
|
|
||||||
|
func NewLzo() (Lzo, error) {
|
||||||
|
return Lzo{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (l Lzo) Decompress(data []byte) ([]byte, error) {
|
func (l Lzo) Decompress(data []byte) ([]byte, error) {
|
||||||
return lzo.Decompress1X(bytes.NewReader(data), len(data), 0)
|
return lzo.Decompress1X(bytes.NewReader(data), len(data), 0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
//go:build no_gpl
|
||||||
|
|
||||||
|
package decompress
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
type Lzo struct{}
|
||||||
|
|
||||||
|
func NewLzo() (Lzo, error) {
|
||||||
|
return Lzo{}, errors.New("lzo compression is disable in this build with no_gpl")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l Lzo) Decompress(data []byte) ([]byte, error) {
|
||||||
|
return nil, errors.New("lzo compression is disable in this build with no_gpl")
|
||||||
|
}
|
||||||
@@ -50,10 +50,7 @@ func (r *Reader) Read(b []byte) (int, error) {
|
|||||||
return curRead, err
|
return curRead, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
toRead = len(b) - curRead
|
toRead = min(len(b)-curRead, len(r.dat)-int(r.curOffset))
|
||||||
if toRead > len(r.dat)-int(r.curOffset) {
|
|
||||||
toRead = len(r.dat) - int(r.curOffset)
|
|
||||||
}
|
|
||||||
copy(b[curRead:], r.dat[r.curOffset:int(r.curOffset)+toRead])
|
copy(b[curRead:], r.dat[r.curOffset:int(r.curOffset)+toRead])
|
||||||
r.curOffset += uint16(toRead)
|
r.curOffset += uint16(toRead)
|
||||||
curRead += toRead
|
curRead += toRead
|
||||||
|
|||||||
+90
-16
@@ -18,7 +18,6 @@ type FullReader struct {
|
|||||||
r io.ReaderAt
|
r io.ReaderAt
|
||||||
d decompress.Decompressor
|
d decompress.Decompressor
|
||||||
frag FragReaderConstructor
|
frag FragReaderConstructor
|
||||||
retPool *sync.Pool
|
|
||||||
sizes []uint32
|
sizes []uint32
|
||||||
initialOffset int64
|
initialOffset int64
|
||||||
finalBlockSize uint64
|
finalBlockSize uint64
|
||||||
@@ -35,11 +34,6 @@ func NewFullReader(r io.ReaderAt, initialOffset int64, d decompress.Decompressor
|
|||||||
goroutineLimit: uint16(runtime.NumCPU()),
|
goroutineLimit: uint16(runtime.NumCPU()),
|
||||||
finalBlockSize: finalBlockSize,
|
finalBlockSize: finalBlockSize,
|
||||||
blockSize: blockSize,
|
blockSize: blockSize,
|
||||||
retPool: &sync.Pool{
|
|
||||||
New: func() any {
|
|
||||||
return &retValue{}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,6 +42,9 @@ func (r *FullReader) AddFrag(frag FragReaderConstructor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *FullReader) SetGoroutineLimit(limit uint16) {
|
func (r *FullReader) SetGoroutineLimit(limit uint16) {
|
||||||
|
if limit <= 0 {
|
||||||
|
r.goroutineLimit = 1
|
||||||
|
}
|
||||||
r.goroutineLimit = limit
|
r.goroutineLimit = limit
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,8 +54,8 @@ type retValue struct {
|
|||||||
index uint64
|
index uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FullReader) process(index uint64, fileOffset uint64, retChan chan *retValue) {
|
func (r FullReader) process(index uint64, fileOffset uint64, pool *sync.Pool, retChan chan *retValue) {
|
||||||
ret := r.retPool.Get().(*retValue)
|
ret := pool.Get().(*retValue)
|
||||||
ret.index = index
|
ret.index = index
|
||||||
realSize := r.sizes[index] &^ (1 << 24)
|
realSize := r.sizes[index] &^ (1 << 24)
|
||||||
if realSize == 0 {
|
if realSize == 0 {
|
||||||
@@ -79,7 +76,10 @@ func (r *FullReader) process(index uint64, fileOffset uint64, retChan chan *retV
|
|||||||
retChan <- ret
|
retChan <- ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FullReader) WriteTo(w io.Writer) (int64, error) {
|
func (r FullReader) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
// if wa, is := w.(io.WriterAt); is {
|
||||||
|
// return r.writeToWriteAt(wa)
|
||||||
|
// }
|
||||||
var curIndex uint64
|
var curIndex uint64
|
||||||
var curOffset uint64
|
var curOffset uint64
|
||||||
var toProcess uint16
|
var toProcess uint16
|
||||||
@@ -87,14 +87,16 @@ func (r *FullReader) WriteTo(w io.Writer) (int64, error) {
|
|||||||
cache := make(map[uint64]*retValue)
|
cache := make(map[uint64]*retValue)
|
||||||
var errCache []error
|
var errCache []error
|
||||||
retChan := make(chan *retValue, r.goroutineLimit)
|
retChan := make(chan *retValue, r.goroutineLimit)
|
||||||
for i := uint64(0); i < uint64(math.Ceil(float64(len(r.sizes))/float64(r.goroutineLimit))); i++ {
|
pool := &sync.Pool{
|
||||||
toProcess = uint16(len(r.sizes)) - (uint16(i) * r.goroutineLimit)
|
New: func() any {
|
||||||
if toProcess > r.goroutineLimit {
|
return &retValue{}
|
||||||
toProcess = r.goroutineLimit
|
},
|
||||||
}
|
}
|
||||||
|
for i := uint64(0); i < uint64(math.Ceil(float64(len(r.sizes))/float64(r.goroutineLimit))); i++ {
|
||||||
|
toProcess = min(uint16(len(r.sizes))-(uint16(i)*r.goroutineLimit), r.goroutineLimit)
|
||||||
// Start all the goroutines
|
// Start all the goroutines
|
||||||
for j := uint16(0); j < toProcess; j++ {
|
for j := uint16(0); j < toProcess; j++ {
|
||||||
go r.process((i*uint64(r.goroutineLimit))+uint64(j), curOffset, retChan)
|
go r.process((i*uint64(r.goroutineLimit))+uint64(j), curOffset, pool, retChan)
|
||||||
curOffset += uint64(r.sizes[(i*uint64(r.goroutineLimit))+uint64(j)]) &^ (1 << 24)
|
curOffset += uint64(r.sizes[(i*uint64(r.goroutineLimit))+uint64(j)]) &^ (1 << 24)
|
||||||
}
|
}
|
||||||
// Then consume the results on retChan
|
// Then consume the results on retChan
|
||||||
@@ -128,7 +130,7 @@ func (r *FullReader) WriteTo(w io.Writer) (int64, error) {
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
r.retPool.Put(res)
|
pool.Put(res)
|
||||||
curIndex++
|
curIndex++
|
||||||
// Now we recursively try to clear the cache
|
// Now we recursively try to clear the cache
|
||||||
for len(cache) > 0 {
|
for len(cache) > 0 {
|
||||||
@@ -146,7 +148,7 @@ func (r *FullReader) WriteTo(w io.Writer) (int64, error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
delete(cache, curIndex)
|
delete(cache, curIndex)
|
||||||
r.retPool.Put(res)
|
pool.Put(res)
|
||||||
curIndex++
|
curIndex++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,3 +174,75 @@ func (r *FullReader) WriteTo(w io.Writer) (int64, error) {
|
|||||||
}
|
}
|
||||||
return wrote, nil
|
return wrote, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// func (r FullReader) writeToWriteAt(w io.WriterAt) (out int64, outErr error) {
|
||||||
|
// wait := &sync.WaitGroup{}
|
||||||
|
// wait.Add(len(r.sizes))
|
||||||
|
// mgr := routinemanager.NewManager(r.goroutineLimit)
|
||||||
|
// curOffset := r.initialOffset
|
||||||
|
// for i := uint64(0); i < uint64(len(r.sizes)); i++ {
|
||||||
|
// go func(index uint64, fileOffset int64) {
|
||||||
|
// lckNum := mgr.Lock()
|
||||||
|
// defer mgr.Unlock(lckNum)
|
||||||
|
// defer wait.Done()
|
||||||
|
// realSize := r.sizes[index] &^ (1 << 24)
|
||||||
|
// if realSize == 0 {
|
||||||
|
// if index == uint64(len(r.sizes))-1 && r.frag == nil {
|
||||||
|
// _, err := w.WriteAt([]byte{0}, int64((uint64(r.blockSize)*index)+r.finalBlockSize)-1)
|
||||||
|
// if err != nil {
|
||||||
|
// outErr = errors.Join(outErr, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// out = max(out, int64((uint64(r.blockSize)*index)+r.finalBlockSize))
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// data := make([]byte, realSize)
|
||||||
|
// err := binary.Read(toreader.NewReader(r.r, int64(fileOffset)), binary.LittleEndian, &data)
|
||||||
|
// if err != nil {
|
||||||
|
// outErr = errors.Join(outErr, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// if r.sizes[index] == realSize {
|
||||||
|
// data, err = r.d.Decompress(data)
|
||||||
|
// }
|
||||||
|
// if err != nil {
|
||||||
|
// outErr = errors.Join(outErr, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// _, err = w.WriteAt(data, int64(uint64(r.blockSize)*index))
|
||||||
|
// if err != nil {
|
||||||
|
// outErr = errors.Join(outErr, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// out = max(out, int64(uint64(r.blockSize)*(index+1)))
|
||||||
|
// }(i, curOffset)
|
||||||
|
// curOffset += int64(r.sizes[i]) &^ (1 << 24)
|
||||||
|
// }
|
||||||
|
// if r.frag != nil {
|
||||||
|
// wait.Add(1)
|
||||||
|
// go func() {
|
||||||
|
// lckNum := mgr.Lock()
|
||||||
|
// defer mgr.Unlock(lckNum)
|
||||||
|
// defer wait.Done()
|
||||||
|
// rdr, err := r.frag()
|
||||||
|
// if err != nil {
|
||||||
|
// outErr = errors.Join(outErr, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// dat, err := io.ReadAll(rdr)
|
||||||
|
// if err != nil {
|
||||||
|
// outErr = errors.Join(outErr, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// _, err = w.WriteAt(dat, int64(int(r.blockSize)*len(r.sizes)))
|
||||||
|
// if err != nil {
|
||||||
|
// outErr = errors.Join(outErr, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// out = int64(int(r.blockSize)*len(r.sizes)) + int64(r.finalBlockSize)
|
||||||
|
// }()
|
||||||
|
// }
|
||||||
|
// wait.Wait()
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|||||||
+2
-4
@@ -41,6 +41,7 @@ func (r *Reader) advance() error {
|
|||||||
r.dat, err = io.ReadAll(r.frag)
|
r.dat, err = io.ReadAll(r.frag)
|
||||||
return err
|
return err
|
||||||
} else if r.curIndex >= uint64(len(r.sizes)) {
|
} else if r.curIndex >= uint64(len(r.sizes)) {
|
||||||
|
r.dat = []byte{}
|
||||||
return io.EOF
|
return io.EOF
|
||||||
}
|
}
|
||||||
realSize := r.sizes[r.curIndex] &^ (1 << 24)
|
realSize := r.sizes[r.curIndex] &^ (1 << 24)
|
||||||
@@ -73,10 +74,7 @@ func (r *Reader) Read(b []byte) (int, error) {
|
|||||||
return curRead, err
|
return curRead, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
toRead = len(b) - curRead
|
toRead = min(len(b)-curRead, len(r.dat)-r.curOffset)
|
||||||
if toRead > len(r.dat)-r.curOffset {
|
|
||||||
toRead = len(r.dat) - r.curOffset
|
|
||||||
}
|
|
||||||
toRead = copy(b[curRead:], r.dat[r.curOffset:r.curOffset+toRead])
|
toRead = copy(b[curRead:], r.dat[r.curOffset:r.curOffset+toRead])
|
||||||
r.curOffset += toRead
|
r.curOffset += toRead
|
||||||
curRead += toRead
|
curRead += toRead
|
||||||
|
|||||||
+7
-13
@@ -81,23 +81,17 @@ func Read(r io.Reader, blockSize uint32) (i Inode, err error) {
|
|||||||
|
|
||||||
func (i Inode) Mode() (out fs.FileMode) {
|
func (i Inode) Mode() (out fs.FileMode) {
|
||||||
out = fs.FileMode(i.Perm)
|
out = fs.FileMode(i.Perm)
|
||||||
switch i.Data.(type) {
|
switch i.Type {
|
||||||
case Directory:
|
case Dir, EDir:
|
||||||
out |= fs.ModeDir
|
out |= fs.ModeDir
|
||||||
case EDirectory:
|
case Sym, ESym:
|
||||||
out |= fs.ModeDir
|
|
||||||
case Symlink:
|
|
||||||
out |= fs.ModeSymlink
|
out |= fs.ModeSymlink
|
||||||
case ESymlink:
|
case Char, EChar, Block, EBlock:
|
||||||
out |= fs.ModeSymlink
|
|
||||||
case Device:
|
|
||||||
out |= fs.ModeDevice
|
out |= fs.ModeDevice
|
||||||
case EDevice:
|
case Fifo, EFifo:
|
||||||
out |= fs.ModeDevice
|
|
||||||
case IPC:
|
|
||||||
out |= fs.ModeNamedPipe
|
|
||||||
case EIPC:
|
|
||||||
out |= fs.ModeNamedPipe
|
out |= fs.ModeNamedPipe
|
||||||
|
case Sock, ESock:
|
||||||
|
out |= fs.ModeSocket
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-15
@@ -59,15 +59,21 @@ func NewReader(r io.ReaderAt) (rdr *Reader, err error) {
|
|||||||
case ZlibCompression:
|
case ZlibCompression:
|
||||||
rdr.d = decompress.Zlib{}
|
rdr.d = decompress.Zlib{}
|
||||||
case LZMACompression:
|
case LZMACompression:
|
||||||
rdr.d = decompress.Lzma{}
|
rdr.d, err = decompress.NewLzma()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
case LZOCompression:
|
case LZOCompression:
|
||||||
rdr.d = decompress.Lzo{}
|
rdr.d, err = decompress.NewLzo()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
case XZCompression:
|
case XZCompression:
|
||||||
rdr.d = decompress.Xz{}
|
rdr.d = decompress.Xz{}
|
||||||
case LZ4Compression:
|
case LZ4Compression:
|
||||||
rdr.d = decompress.Lz4{}
|
rdr.d = decompress.Lz4{}
|
||||||
case ZSTDCompression:
|
case ZSTDCompression:
|
||||||
rdr.d = &decompress.Zstd{}
|
rdr.d = decompress.Zstd{}
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("invalid compression type. possible corrupted archive")
|
return nil, errors.New("invalid compression type. possible corrupted archive")
|
||||||
}
|
}
|
||||||
@@ -105,10 +111,7 @@ func (r *Reader) Id(i uint16) (uint32, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
idsToRead = r.Superblock.IdCount - uint16(len(r.idTable))
|
idsToRead = min(r.Superblock.IdCount-uint16(len(r.idTable)), 2048)
|
||||||
if idsToRead > 2048 {
|
|
||||||
idsToRead = 2048
|
|
||||||
}
|
|
||||||
idsTmp = make([]uint32, idsToRead)
|
idsTmp = make([]uint32, idsToRead)
|
||||||
rdr = metadata.NewReader(toreader.NewReader(r.r, int64(offset)), r.d)
|
rdr = metadata.NewReader(toreader.NewReader(r.r, int64(offset)), r.d)
|
||||||
err = binary.Read(rdr, binary.LittleEndian, &idsTmp)
|
err = binary.Read(rdr, binary.LittleEndian, &idsTmp)
|
||||||
@@ -148,10 +151,7 @@ func (r *Reader) fragEntry(i uint32) (fragEntry, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fragEntry{}, err
|
return fragEntry{}, err
|
||||||
}
|
}
|
||||||
fragsToRead = r.Superblock.FragCount - uint32(len(r.fragTable))
|
fragsToRead = min(r.Superblock.FragCount-uint32(len(r.fragTable)), 512)
|
||||||
if fragsToRead > 512 {
|
|
||||||
fragsToRead = 512
|
|
||||||
}
|
|
||||||
fragsTmp = make([]fragEntry, fragsToRead)
|
fragsTmp = make([]fragEntry, fragsToRead)
|
||||||
rdr = metadata.NewReader(toreader.NewReader(r.r, int64(offset)), r.d)
|
rdr = metadata.NewReader(toreader.NewReader(r.r, int64(offset)), r.d)
|
||||||
err = binary.Read(rdr, binary.LittleEndian, &fragsTmp)
|
err = binary.Read(rdr, binary.LittleEndian, &fragsTmp)
|
||||||
@@ -194,10 +194,7 @@ func (r *Reader) inodeRef(i uint32) (uint64, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
refsToRead = r.Superblock.InodeCount - uint32(len(r.exportTable))
|
refsToRead = min(r.Superblock.InodeCount-uint32(len(r.exportTable)), 1024)
|
||||||
if refsToRead > 1024 {
|
|
||||||
refsToRead = 1024
|
|
||||||
}
|
|
||||||
refsTmp = make([]uint64, refsToRead)
|
refsTmp = make([]uint64, refsToRead)
|
||||||
rdr = metadata.NewReader(toreader.NewReader(r.r, int64(offset)), r.d)
|
rdr = metadata.NewReader(toreader.NewReader(r.r, int64(offset)), r.d)
|
||||||
err = binary.Read(rdr, binary.LittleEndian, &refsTmp)
|
err = binary.Read(rdr, binary.LittleEndian, &refsTmp)
|
||||||
|
|||||||
+16
-17
@@ -1,4 +1,4 @@
|
|||||||
package squashfs_test
|
package squashfs
|
||||||
|
|
||||||
//Actually proper tests go here.
|
//Actually proper tests go here.
|
||||||
|
|
||||||
@@ -13,13 +13,11 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/CalebQ42/squashfs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
squashfsURL = "https://darkstorm.tech/files/LinuxPATest.sfs"
|
squashfsURL = "https://darkstorm.tech/files/LinuxPATest.sfs"
|
||||||
squashfsName = "airootfs.sfs"
|
squashfsName = "LinuxPATest.sfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
func preTest(dir string) (fil *os.File, err error) {
|
func preTest(dir string) (fil *os.File, err error) {
|
||||||
@@ -61,7 +59,7 @@ func TestMisc(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
rdr, err := squashfs.NewReader(fil)
|
rdr, err := NewReader(fil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -81,10 +79,10 @@ func BenchmarkRace(b *testing.B) {
|
|||||||
os.RemoveAll(libPath)
|
os.RemoveAll(libPath)
|
||||||
os.RemoveAll(unsquashPath)
|
os.RemoveAll(unsquashPath)
|
||||||
var libTime, unsquashTime time.Duration
|
var libTime, unsquashTime time.Duration
|
||||||
op := squashfs.FastOptions()
|
op := FastOptions()
|
||||||
op.IgnorePerm = true
|
op.IgnorePerm = true
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
rdr, err := squashfs.NewReader(fil)
|
rdr, err := NewReader(fil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -102,15 +100,15 @@ func BenchmarkRace(b *testing.B) {
|
|||||||
b.Log("Unsquashfs error:", err)
|
b.Log("Unsquashfs error:", err)
|
||||||
}
|
}
|
||||||
unsquashTime = time.Since(start)
|
unsquashTime = time.Since(start)
|
||||||
// b.Log("Library took:", libTime.Round(time.Millisecond))
|
b.Log("Library took:", libTime.Round(time.Millisecond))
|
||||||
// b.Log("unsquashfs took:", unsquashTime.Round(time.Millisecond))
|
b.Log("unsquashfs took:", unsquashTime.Round(time.Millisecond))
|
||||||
b.Fatal("unsquashfs is", strconv.FormatFloat(float64(libTime.Milliseconds())/float64(unsquashTime.Milliseconds()), 'f', 2, 64), "times faster")
|
b.Log("unsquashfs is", strconv.FormatFloat(float64(libTime.Milliseconds())/float64(unsquashTime.Milliseconds()), 'f', 2, 64), "times faster")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractQuick(t *testing.T) {
|
func TestExtractQuick(t *testing.T) {
|
||||||
//First, setup everything and extract the archive using the library and unsquashfs
|
//First, setup everything and extract the archive using the library and unsquashfs
|
||||||
|
|
||||||
// tmpDir := b.TempDir()
|
// tmpDir := bTempDir()
|
||||||
tmpDir := "testing"
|
tmpDir := "testing"
|
||||||
fil, err := preTest(tmpDir)
|
fil, err := preTest(tmpDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -120,13 +118,13 @@ func TestExtractQuick(t *testing.T) {
|
|||||||
unsquashPath := filepath.Join(tmpDir, "ExtractSquashfs")
|
unsquashPath := filepath.Join(tmpDir, "ExtractSquashfs")
|
||||||
os.RemoveAll(libPath)
|
os.RemoveAll(libPath)
|
||||||
os.RemoveAll(unsquashPath)
|
os.RemoveAll(unsquashPath)
|
||||||
rdr, err := squashfs.NewReader(fil)
|
rdr, err := NewReader(fil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
os.RemoveAll(filepath.Join(tmpDir, "testLog.txt"))
|
os.RemoveAll(filepath.Join(tmpDir, "testLog.txt"))
|
||||||
logFil, _ := os.Create(filepath.Join(tmpDir, "testLog.txt"))
|
logFil, _ := os.Create(filepath.Join(tmpDir, "testLog.txt"))
|
||||||
op := squashfs.DefaultOptions()
|
op := FastOptions()
|
||||||
op.Verbose = true
|
op.Verbose = true
|
||||||
op.IgnorePerm = true
|
op.IgnorePerm = true
|
||||||
op.LogOutput = logFil
|
op.LogOutput = logFil
|
||||||
@@ -169,7 +167,7 @@ func TestExtractQuick(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var filePath = "bin"
|
var filePath = "Start.exe"
|
||||||
|
|
||||||
func TestSingleFile(t *testing.T) {
|
func TestSingleFile(t *testing.T) {
|
||||||
tmpDir := "testing"
|
tmpDir := "testing"
|
||||||
@@ -178,7 +176,7 @@ func TestSingleFile(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
os.Remove(filepath.Join(tmpDir, filePath))
|
os.Remove(filepath.Join(tmpDir, filePath))
|
||||||
rdr, err := squashfs.NewReader(fil)
|
rdr, err := NewReader(fil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -186,9 +184,10 @@ func TestSingleFile(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = f.(*squashfs.File).ExtractWithOptions("testing", &squashfs.ExtractionOptions{Verbose: true})
|
op := DefaultOptions()
|
||||||
|
op.Verbose = true
|
||||||
|
err = f.(*File).ExtractWithOptions("testing", op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Fatal("HI")
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user