From a015b16293e19c4038c412001262ee7b5a96d4d9 Mon Sep 17 00:00:00 2001 From: Belac Darkstorm Date: Mon, 24 Oct 2022 03:17:55 -0500 Subject: [PATCH] Clean path before checking if valid. --- reader_file.go | 48 ++++++++++++++++++++++++------------------------ reader_fs.go | 32 ++++++++++++++++---------------- squashfs_test.go | 15 +++++++++++++++ 3 files changed, 55 insertions(+), 40 deletions(-) diff --git a/reader_file.go b/reader_file.go index b958e51..11389bb 100644 --- a/reader_file.go +++ b/reader_file.go @@ -14,7 +14,7 @@ import ( "github.com/CalebQ42/squashfs/internal/inode" ) -//File represents a file inside a squashfs archive. +// File represents a file inside a squashfs archive. type File struct { i inode.Inode rdr io.Reader @@ -52,12 +52,12 @@ func (r Reader) newFile(en directory.Entry, parent *FS) (*File, error) { }, nil } -//Stat returns the File's fs.FileInfo +// Stat returns the File's fs.FileInfo func (f File) Stat() (fs.FileInfo, error) { return newFileInfo(f.e, f.i), nil } -//Read reads the data from the file. Only works if file is a normal file. +// Read reads the data from the file. Only works if file is a normal file. func (f File) Read(p []byte) (int, error) { if f.i.Type != inode.Fil && f.i.Type != inode.EFil { return 0, ErrReadNotFile @@ -68,20 +68,20 @@ func (f File) Read(p []byte) (int, error) { return f.rdr.Read(p) } -//WriteTo writes all data from the file to the writer. This is multi-threaded. -//The underlying reader is seperate from the one used with Read and can be reused. +// WriteTo writes all data from the file to the writer. This is multi-threaded. +// The underlying reader is seperate from the one used with Read and can be reused. func (f File) WriteTo(w io.Writer) (int64, error) { return f.fullRdr.WriteTo(w) } -//Close simply nils the underlying reader. Here mostly to satisfy fs.File +// Close simply nils the underlying reader. Here mostly to satisfy fs.File func (f *File) Close() error { f.rdr = nil return nil } -//ReadDir returns n fs.DirEntry's that's contained in the File (if it's a directory). -//If n <= 0 all fs.DirEntry's are returned. +// ReadDir returns n fs.DirEntry's that's contained in the File (if it's a directory). +// If n <= 0 all fs.DirEntry's are returned. func (f *File) ReadDir(n int) (out []fs.DirEntry, err error) { if !f.IsDir() { return nil, errors.New("File is not a directory") @@ -111,7 +111,7 @@ func (f *File) ReadDir(n int) (out []fs.DirEntry, err error) { return } -//FS returns the File as a FS. +// FS returns the File as a FS. func (f *File) FS() (*FS, error) { if !f.IsDir() { return nil, errors.New("File is not a directory") @@ -126,22 +126,22 @@ func (f *File) FS() (*FS, error) { }, nil } -//IsDir Yep. +// IsDir Yep. func (f File) IsDir() bool { return f.i.Type == inode.Dir || f.i.Type == inode.EDir } -//IsRegular yep. +// IsRegular yep. func (f File) IsRegular() bool { return f.i.Type == inode.Fil || f.i.Type == inode.EFil } -//IsSymlink yep. +// IsSymlink yep. func (f File) IsSymlink() bool { return f.i.Type == inode.Sym || f.i.Type == inode.ESym } -//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. func (f File) SymlinkPath() string { switch f.i.Type { case inode.Sym: @@ -159,8 +159,8 @@ func (f File) path() string { return f.parent.path() + "/" + f.e.Name } -//GetSymlinkFile returns the File the symlink is pointing to. -//If not a symlink, or the target is unobtainable (such as it being outside the archive or it's absolute) returns nil +// GetSymlinkFile returns the File the symlink is pointing to. +// If not a symlink, or the target is unobtainable (such as it being outside the archive or it's absolute) returns nil func (f File) GetSymlinkFile() *File { if !f.IsSymlink() { return nil @@ -175,7 +175,7 @@ func (f File) GetSymlinkFile() *File { return sym.(*File) } -//ExtractionOptions are available options on how to extract. +// ExtractionOptions are available options on how to extract. type ExtractionOptions struct { LogOutput io.Writer //Where error log should write. If nil, uses os.Stdout. Has no effect if verbose is false. DereferenceSymlink bool //Replace symlinks with the target file @@ -184,21 +184,21 @@ type ExtractionOptions struct { FolderPerm fs.FileMode //The permissions used when creating the extraction folder } -//DefaultOptions is the default ExtractionOptions. +// DefaultOptions is the default ExtractionOptions. func DefaultOptions() ExtractionOptions { return ExtractionOptions{ FolderPerm: 0755, } } -//ExtractTo extracts the File to the given folder with the default options. -//If the File is a directory, it instead extracts the directory's contents to the folder. +// ExtractTo extracts the File to the given folder with the default options. +// If the File is a directory, it instead extracts the directory's contents to the folder. func (f File) ExtractTo(folder string) error { return f.ExtractWithOptions(folder, DefaultOptions()) } -//ExtractSymlink extracts the File to the folder with the DereferenceSymlink option. -//If the File is a directory, it instead extracts the directory's contents to the folder. +// ExtractSymlink extracts the File to the folder with the DereferenceSymlink option. +// If the File is a directory, it instead extracts the directory's contents to the folder. func (f File) ExtractSymlink(folder string) error { return f.ExtractWithOptions(folder, ExtractionOptions{ DereferenceSymlink: true, @@ -206,8 +206,8 @@ func (f File) ExtractSymlink(folder string) error { }) } -//ExtractWithOptions extracts the File to the given folder with the given ExtrationOptions. -//If the File is a directory, it instead extracts the directory's contents to the folder. +// ExtractWithOptions extracts the File to the given folder with the given ExtrationOptions. +// If the File is a directory, it instead extracts the directory's contents to the folder. func (f File) ExtractWithOptions(folder string, op ExtractionOptions) error { if op.Verbose { if op.LogOutput == nil { @@ -220,13 +220,13 @@ func (f File) ExtractWithOptions(folder string, op ExtractionOptions) error { func (f File) realExtract(folder string, op ExtractionOptions) error { err := os.MkdirAll(folder, op.FolderPerm) + folder = filepath.Clean(folder) if err != nil && !os.IsExist(err) { if op.Verbose { log.Println("Error while creating extraction folder") } return err } - folder = filepath.Clean(folder) if f.IsDir() { filFS, _ := f.FS() var ents []directory.Entry diff --git a/reader_fs.go b/reader_fs.go index 088e47a..469615e 100644 --- a/reader_fs.go +++ b/reader_fs.go @@ -12,8 +12,8 @@ import ( "github.com/CalebQ42/squashfs/internal/inode" ) -//FS is a fs.FS representation of a squashfs directory. -//Implements fs.GlobFS, fs.ReadDirFS, fs.ReadFileFS, fs.StatFS, and fs.SubFS +// FS is a fs.FS representation of a squashfs directory. +// Implements fs.GlobFS, fs.ReadDirFS, fs.ReadFileFS, fs.StatFS, and fs.SubFS type FS struct { *File e []directory.Entry @@ -39,8 +39,9 @@ func (r Reader) newFS(e directory.Entry, parent *FS) (*FS, error) { }, nil } -//Open opens the file at name. Returns a squashfs.File. +// Open opens the file at name. Returns a squashfs.File. func (f FS) Open(name string) (fs.File, error) { + name = filepath.Clean(name) if !fs.ValidPath(name) { return nil, &fs.PathError{ Op: "open", @@ -48,7 +49,6 @@ func (f FS) Open(name string) (fs.File, error) { Err: fs.ErrInvalid, } } - name = filepath.Clean(name) if name == "." || name == "" { return f.File, nil } @@ -96,10 +96,11 @@ func (f FS) Open(name string) (fs.File, error) { } } -//Glob returns the name of the files at the given pattern. -//All paths are relative to the FS. -//Uses filepath.Match to compare names. +// Glob returns the name of the files at the given pattern. +// All paths are relative to the FS. +// Uses filepath.Match to compare names. func (f FS) Glob(pattern string) (out []string, err error) { + pattern = filepath.Clean(pattern) if !fs.ValidPath(pattern) { return nil, &fs.PathError{ Op: "glob", @@ -107,7 +108,6 @@ func (f FS) Glob(pattern string) (out []string, err error) { Err: fs.ErrInvalid, } } - pattern = filepath.Clean(pattern) split := strings.Split(pattern, "/") for i := 0; i < len(f.e); i++ { if match, _ := path.Match(split[0], f.e[i].Name); match { @@ -156,9 +156,10 @@ func (f FS) Glob(pattern string) (out []string, err error) { return } -//ReadDir returns all the DirEntry returns all DirEntry's for the directory at name. -//If name is not a directory, returns an error. +// ReadDir returns all the DirEntry returns all DirEntry's for the directory at name. +// If name is not a directory, returns an error. func (f FS) ReadDir(name string) ([]fs.DirEntry, error) { + name = filepath.Clean(name) if !fs.ValidPath(name) { return nil, &fs.PathError{ Op: "readdir", @@ -166,7 +167,6 @@ func (f FS) ReadDir(name string) ([]fs.DirEntry, error) { Err: fs.ErrInvalid, } } - name = filepath.Clean(name) if name == "." || name == "" { return f.File.ReadDir(-1) } @@ -234,7 +234,7 @@ func (f FS) ReadDir(name string) ([]fs.DirEntry, error) { } } -//ReadFile returns the data (in []byte) for the file at name. +// ReadFile returns the data (in []byte) for the file at name. func (f FS) ReadFile(name string) ([]byte, error) { fil, err := f.Open(name) if err != nil { @@ -256,8 +256,9 @@ func (f FS) ReadFile(name string) ([]byte, error) { return buf.Bytes(), nil } -//Stat returns the fs.FileInfo for the file at name. +// Stat returns the fs.FileInfo for the file at name. func (f FS) Stat(name string) (fs.FileInfo, error) { + name = filepath.Clean(strings.TrimPrefix(name, "/")) if !fs.ValidPath(name) { return nil, &fs.PathError{ Op: "stat", @@ -265,7 +266,6 @@ func (f FS) Stat(name string) (fs.FileInfo, error) { Err: fs.ErrInvalid, } } - name = filepath.Clean(strings.TrimPrefix(name, "/")) if name == "." || name == "" { return f.File.Stat() } @@ -325,8 +325,9 @@ func (f FS) Stat(name string) (fs.FileInfo, error) { } } -//Sub returns the FS at dir +// Sub returns the FS at dir func (f FS) Sub(dir string) (fs.FS, error) { + dir = filepath.Clean(dir) if !fs.ValidPath(dir) { return nil, &fs.PathError{ Op: "sub", @@ -334,7 +335,6 @@ func (f FS) Sub(dir string) (fs.FS, error) { Err: fs.ErrInvalid, } } - dir = filepath.Clean(dir) if dir == "." || dir == "" { return f, nil } diff --git a/squashfs_test.go b/squashfs_test.go index 6d15bb8..7e71918 100644 --- a/squashfs_test.go +++ b/squashfs_test.go @@ -57,6 +57,21 @@ func preTest(dir string) (fil *os.File, err error) { return } +func TestMisc(t *testing.T) { + tmpDir := "testing" + fil, err := preTest(tmpDir) + if err != nil { + t.Fatal(err) + } + rdr, err := squashfs.NewReader(fil) + if err != nil { + t.Fatal(err) + } + _ = rdr + // Put testing here + t.Fatal("UM") +} + func BenchmarkRace(b *testing.B) { // tmpDir := b.TempDir() tmpDir := "testing"