From cde6a265a110a46bfbb9de6b6b8cdc6a254ce55d Mon Sep 17 00:00:00 2001 From: Caleb Gardner Date: Sat, 18 Jun 2022 01:32:51 -0500 Subject: [PATCH] Started work on proper tests. STILL HAVING STUPID UNEXPLAINABLE NIL POINTERS. --- reader_test.go => exp_test.go | 2 + reader.go | 10 ++-- reader_file.go | 9 ++-- reader_fileinfo.go | 23 +++++---- squashfs_test.go | 93 +++++++++++++++++++++++++++++++++++ superblock.go | 6 ++- 6 files changed, 121 insertions(+), 22 deletions(-) rename reader_test.go => exp_test.go (98%) create mode 100644 squashfs_test.go diff --git a/reader_test.go b/exp_test.go similarity index 98% rename from reader_test.go rename to exp_test.go index 47695f9..e5a3c83 100644 --- a/reader_test.go +++ b/exp_test.go @@ -1,5 +1,7 @@ package squashfs +//A place for temporary, expiremental tests. Not meant for actual testing purposes. + import ( "fmt" "io" diff --git a/reader.go b/reader.go index 4a90f1f..2998a08 100644 --- a/reader.go +++ b/reader.go @@ -25,8 +25,9 @@ type Reader struct { } var ( - ErrorMagic = errors.New("magic incorrect. probably not reading squashfs archive") - ErrorLog = errors.New("block log is incorrect. possible corrupted archive") + ErrorMagic = errors.New("magic incorrect. probably not reading squashfs archive") + ErrorLog = errors.New("block log is incorrect. possible corrupted archive") + ErrorVersion = errors.New("squashfs version of archive is not 4.0") ) const ( @@ -53,12 +54,15 @@ func NewReader(r io.ReaderAt) (*Reader, error) { if err != nil { return nil, err } - if !squash.s.hasMagic() { + if !squash.s.checkMagic() { return nil, ErrorMagic } if !squash.s.checkBlockLog() { return nil, ErrorLog } + if !squash.s.checkVersion() { + return nil, ErrorVersion + } switch squash.s.CompType { case GZipCompression: squash.d = decompress.GZip{} diff --git a/reader_file.go b/reader_file.go index d667451..d9b6f3b 100644 --- a/reader_file.go +++ b/reader_file.go @@ -101,7 +101,7 @@ func (f *File) ReadDir(n int) (out []fs.DirEntry, err error) { err = io.EOF } } - var fi FileInfo + var fi fileInfo for _, e := range ents[start:end] { fi, err = f.r.newFileInfo(e) if err != nil { @@ -190,10 +190,7 @@ type ExtractionOptions struct { //DefaultOptions is the default ExtractionOptions. func DefaultOptions() ExtractionOptions { return ExtractionOptions{ - DereferenceSymlink: false, - UnbreakSymlink: false, - Verbose: false, - FolderPerm: fs.ModePerm, + FolderPerm: 0755, } } @@ -208,7 +205,7 @@ func (f File) ExtractTo(folder string) error { func (f File) ExtractSymlink(folder string) error { return f.ExtractWithOptions(folder, ExtractionOptions{ DereferenceSymlink: true, - FolderPerm: fs.ModePerm, + FolderPerm: 0755, }) } diff --git a/reader_fileinfo.go b/reader_fileinfo.go index 0670db3..4fc875c 100644 --- a/reader_fileinfo.go +++ b/reader_fileinfo.go @@ -8,29 +8,29 @@ import ( "github.com/CalebQ42/squashfs/internal/inode" ) -type FileInfo struct { +type fileInfo struct { e directory.Entry size int64 perm uint32 modTime uint32 } -func (r Reader) newFileInfo(e directory.Entry) (FileInfo, error) { +func (r Reader) newFileInfo(e directory.Entry) (fileInfo, error) { i, err := r.inodeFromDir(e) if err != nil { - return FileInfo{}, err + return fileInfo{}, err } return newFileInfo(e, i), nil } -func newFileInfo(e directory.Entry, i inode.Inode) FileInfo { +func newFileInfo(e directory.Entry, i inode.Inode) fileInfo { var size int64 if i.Type == inode.Fil { size = int64(i.Data.(inode.File).Size) } else if i.Type == inode.EFil { size = int64(i.Data.(inode.EFile).Size) } - return FileInfo{ + return fileInfo{ e: e, size: size, perm: uint32(i.Perm), @@ -38,30 +38,29 @@ func newFileInfo(e directory.Entry, i inode.Inode) FileInfo { } } -func (f FileInfo) Name() string { +func (f fileInfo) Name() string { return f.e.Name } -func (f FileInfo) Size() int64 { +func (f fileInfo) Size() int64 { return f.size } -func (f FileInfo) Mode() fs.FileMode { +func (f fileInfo) Mode() fs.FileMode { if f.IsDir() { return fs.FileMode(f.perm | uint32(fs.ModeDir)) } return fs.FileMode(f.perm) } -func (f FileInfo) ModTime() time.Time { +func (f fileInfo) ModTime() time.Time { return time.Unix(int64(f.modTime), 0) } -func (f FileInfo) IsDir() bool { +func (f fileInfo) IsDir() bool { return f.e.Type == inode.Dir } -func (f FileInfo) Sys() any { - //TODO +func (f fileInfo) Sys() any { return nil } diff --git a/squashfs_test.go b/squashfs_test.go new file mode 100644 index 0000000..4a35f07 --- /dev/null +++ b/squashfs_test.go @@ -0,0 +1,93 @@ +package squashfs_test + +import ( + "io" + "io/fs" + "net/http" + "os" + "os/exec" + "path/filepath" + "testing" + + "github.com/CalebQ42/squashfs" +) + +const ( + squashfsURL = "https://darkstorm.tech/LinuxPATest.sfs" + squashfsName = "LinuxPATest.sfs" +) + +func preTest(dir string) (fil *os.File, err error) { + _, err = os.Open(filepath.Join(dir, squashfsName)) + if err != nil { + _, err = os.Open(dir) + if os.IsNotExist(err) { + err = os.Mkdir(dir, 0755) + } + if err != nil { + return + } + os.Remove(filepath.Join(dir, squashfsName)) + fil, err = os.Create(filepath.Join(dir, squashfsName)) + if err != nil { + return + } + var resp *http.Response + resp, err = http.DefaultClient.Get(squashfsURL) + if err != nil { + return + } + _, err = io.Copy(fil, resp.Body) + if err != nil { + return + } + } + _, err = exec.LookPath("unsquashfs") + if err != nil { + return + } + _, err = exec.LookPath("mksquashfs") + return +} + +func TestExtractQuick(t *testing.T) { + + //First, setup everything and extract the archive using the library and unsquashfs + + tmpDir := t.TempDir() + fil, err := preTest(tmpDir) + if err != nil { + t.Fatal(err) + } + libPath := filepath.Join(tmpDir, "ExtractLib") + unsquashPath := filepath.Join(tmpDir, "ExtractSquashfs") + os.Remove(libPath) + os.Remove(unsquashPath) + rdr, err := squashfs.NewReader(fil) + if err != nil { + t.Fatal(err) + } + err = rdr.ExtractTo(libPath) + if err != nil { + t.Fatal(err) + } + cmd := exec.Command("unsquashfs", "-d", unsquashPath, fil.Name()) + err = cmd.Run() + if err != nil { + t.Fatal(err) + } + + //Then compare the sizes and existance between the two (using unsquashfs as a reference). + //If the file doesn't exist, or the size is different, we exit. + //TODO: Add long test that checks contents. + + squashFils := os.DirFS(unsquashPath) + err = fs.WalkDir(squashFils, "", func(path string, d fs.DirEntry, err error) error { + t.Log(path) + return nil + }) + if err != nil { + t.Fatal(err) + } + t.Fatal("This is a test") +} diff --git a/superblock.go b/superblock.go index e0c8079..7916759 100644 --- a/superblock.go +++ b/superblock.go @@ -24,7 +24,7 @@ type superblock struct { ExportTableStart uint64 } -func (s superblock) hasMagic() bool { +func (s superblock) checkMagic() bool { return s.Magic == 0x73717368 } @@ -32,6 +32,10 @@ func (s superblock) checkBlockLog() bool { return s.BlockLog == uint16(math.Log2(float64(s.BlockSize))) } +func (s superblock) checkVersion() bool { + return s.VerMaj == 4 && s.VerMin == 0 +} + func (s superblock) uncompressedInodes() bool { return s.Flags&0x1 == 0x1 }