Compare commits

..

1 Commits

Author SHA1 Message Date
Belac Darkstorm a015b16293 Clean path before checking if valid. 2022-10-24 03:17:55 -05:00
3 changed files with 55 additions and 40 deletions
+24 -24
View File
@@ -14,7 +14,7 @@ import (
"github.com/CalebQ42/squashfs/internal/inode" "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 { type File struct {
i inode.Inode i inode.Inode
rdr io.Reader rdr io.Reader
@@ -52,12 +52,12 @@ func (r Reader) newFile(en directory.Entry, parent *FS) (*File, error) {
}, nil }, nil
} }
//Stat returns the File's fs.FileInfo // Stat returns the File's fs.FileInfo
func (f File) Stat() (fs.FileInfo, error) { func (f File) Stat() (fs.FileInfo, error) {
return newFileInfo(f.e, f.i), nil 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) { func (f File) Read(p []byte) (int, error) {
if f.i.Type != inode.Fil && f.i.Type != inode.EFil { if f.i.Type != inode.Fil && f.i.Type != inode.EFil {
return 0, ErrReadNotFile return 0, ErrReadNotFile
@@ -68,20 +68,20 @@ func (f File) Read(p []byte) (int, error) {
return f.rdr.Read(p) return f.rdr.Read(p)
} }
//WriteTo writes all data from the file to the writer. This is multi-threaded. // 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. // The underlying reader is seperate from the one used with Read and can be reused.
func (f File) WriteTo(w io.Writer) (int64, error) { func (f File) WriteTo(w io.Writer) (int64, error) {
return f.fullRdr.WriteTo(w) 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 { func (f *File) Close() error {
f.rdr = nil f.rdr = nil
return nil return nil
} }
//ReadDir returns n fs.DirEntry's that's contained in the File (if it's a directory). // 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. // If n <= 0 all fs.DirEntry's are returned.
func (f *File) ReadDir(n int) (out []fs.DirEntry, err error) { func (f *File) ReadDir(n int) (out []fs.DirEntry, err error) {
if !f.IsDir() { if !f.IsDir() {
return nil, errors.New("File is not a directory") 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 return
} }
//FS returns the File as a FS. // FS returns the File as a FS.
func (f *File) FS() (*FS, error) { func (f *File) FS() (*FS, error) {
if !f.IsDir() { if !f.IsDir() {
return nil, errors.New("File is not a directory") return nil, errors.New("File is not a directory")
@@ -126,22 +126,22 @@ func (f *File) FS() (*FS, error) {
}, nil }, nil
} }
//IsDir Yep. // IsDir Yep.
func (f File) IsDir() bool { func (f File) IsDir() bool {
return f.i.Type == inode.Dir || f.i.Type == inode.EDir return f.i.Type == inode.Dir || f.i.Type == inode.EDir
} }
//IsRegular yep. // IsRegular yep.
func (f File) IsRegular() bool { func (f File) IsRegular() bool {
return f.i.Type == inode.Fil || f.i.Type == inode.EFil return f.i.Type == inode.Fil || f.i.Type == inode.EFil
} }
//IsSymlink yep. // IsSymlink yep.
func (f File) IsSymlink() bool { func (f File) IsSymlink() bool {
return f.i.Type == inode.Sym || f.i.Type == inode.ESym 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 { func (f File) SymlinkPath() string {
switch f.i.Type { switch f.i.Type {
case inode.Sym: case inode.Sym:
@@ -159,8 +159,8 @@ func (f File) path() string {
return f.parent.path() + "/" + f.e.Name return f.parent.path() + "/" + f.e.Name
} }
//GetSymlinkFile returns the File the symlink is pointing to. // 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 // 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 { func (f File) GetSymlinkFile() *File {
if !f.IsSymlink() { if !f.IsSymlink() {
return nil return nil
@@ -175,7 +175,7 @@ func (f File) GetSymlinkFile() *File {
return sym.(*File) return sym.(*File)
} }
//ExtractionOptions are available options on how to extract. // ExtractionOptions are available options on how to extract.
type ExtractionOptions struct { type ExtractionOptions struct {
LogOutput io.Writer //Where error log should write. If nil, uses os.Stdout. Has no effect if verbose is false. 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 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 FolderPerm fs.FileMode //The permissions used when creating the extraction folder
} }
//DefaultOptions is the default ExtractionOptions. // DefaultOptions is the default ExtractionOptions.
func DefaultOptions() ExtractionOptions { func DefaultOptions() ExtractionOptions {
return ExtractionOptions{ return ExtractionOptions{
FolderPerm: 0755, FolderPerm: 0755,
} }
} }
//ExtractTo extracts the File to the given folder with the default options. // 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. // If the File is a directory, it instead extracts the directory's contents to the folder.
func (f File) ExtractTo(folder string) error { func (f File) ExtractTo(folder string) error {
return f.ExtractWithOptions(folder, DefaultOptions()) return f.ExtractWithOptions(folder, DefaultOptions())
} }
//ExtractSymlink extracts the File to the folder with the DereferenceSymlink option. // 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. // If the File is a directory, it instead extracts the directory's contents to the folder.
func (f File) ExtractSymlink(folder string) error { func (f File) ExtractSymlink(folder string) error {
return f.ExtractWithOptions(folder, ExtractionOptions{ return f.ExtractWithOptions(folder, ExtractionOptions{
DereferenceSymlink: true, 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. // 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. // 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 { func (f File) ExtractWithOptions(folder string, op ExtractionOptions) error {
if op.Verbose { if op.Verbose {
if op.LogOutput == nil { 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 { func (f File) realExtract(folder string, op ExtractionOptions) error {
err := os.MkdirAll(folder, op.FolderPerm) err := os.MkdirAll(folder, op.FolderPerm)
folder = filepath.Clean(folder)
if err != nil && !os.IsExist(err) { if err != nil && !os.IsExist(err) {
if op.Verbose { if op.Verbose {
log.Println("Error while creating extraction folder") log.Println("Error while creating extraction folder")
} }
return err return err
} }
folder = filepath.Clean(folder)
if f.IsDir() { if f.IsDir() {
filFS, _ := f.FS() filFS, _ := f.FS()
var ents []directory.Entry var ents []directory.Entry
+16 -16
View File
@@ -12,8 +12,8 @@ import (
"github.com/CalebQ42/squashfs/internal/inode" "github.com/CalebQ42/squashfs/internal/inode"
) )
//FS is a fs.FS representation of a squashfs directory. // FS is a fs.FS representation of a squashfs directory.
//Implements fs.GlobFS, fs.ReadDirFS, fs.ReadFileFS, fs.StatFS, and fs.SubFS // Implements fs.GlobFS, fs.ReadDirFS, fs.ReadFileFS, fs.StatFS, and fs.SubFS
type FS struct { type FS struct {
*File *File
e []directory.Entry e []directory.Entry
@@ -39,8 +39,9 @@ func (r Reader) newFS(e directory.Entry, parent *FS) (*FS, error) {
}, nil }, 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) { func (f FS) Open(name string) (fs.File, error) {
name = filepath.Clean(name)
if !fs.ValidPath(name) { if !fs.ValidPath(name) {
return nil, &fs.PathError{ return nil, &fs.PathError{
Op: "open", Op: "open",
@@ -48,7 +49,6 @@ func (f FS) Open(name string) (fs.File, error) {
Err: fs.ErrInvalid, Err: fs.ErrInvalid,
} }
} }
name = filepath.Clean(name)
if name == "." || name == "" { if name == "." || name == "" {
return f.File, nil 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. // Glob returns the name of the files at the given pattern.
//All paths are relative to the FS. // All paths are relative to the FS.
//Uses filepath.Match to compare names. // Uses filepath.Match to compare names.
func (f FS) Glob(pattern string) (out []string, err error) { func (f FS) Glob(pattern string) (out []string, err error) {
pattern = filepath.Clean(pattern)
if !fs.ValidPath(pattern) { if !fs.ValidPath(pattern) {
return nil, &fs.PathError{ return nil, &fs.PathError{
Op: "glob", Op: "glob",
@@ -107,7 +108,6 @@ func (f FS) Glob(pattern string) (out []string, err error) {
Err: fs.ErrInvalid, Err: fs.ErrInvalid,
} }
} }
pattern = filepath.Clean(pattern)
split := strings.Split(pattern, "/") split := strings.Split(pattern, "/")
for i := 0; i < len(f.e); i++ { for i := 0; i < len(f.e); i++ {
if match, _ := path.Match(split[0], f.e[i].Name); match { 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 return
} }
//ReadDir returns all the DirEntry returns all DirEntry's for the directory at name. // ReadDir returns all the DirEntry returns all DirEntry's for the directory at name.
//If name is not a directory, returns an error. // If name is not a directory, returns an error.
func (f FS) ReadDir(name string) ([]fs.DirEntry, error) { func (f FS) ReadDir(name string) ([]fs.DirEntry, error) {
name = filepath.Clean(name)
if !fs.ValidPath(name) { if !fs.ValidPath(name) {
return nil, &fs.PathError{ return nil, &fs.PathError{
Op: "readdir", Op: "readdir",
@@ -166,7 +167,6 @@ func (f FS) ReadDir(name string) ([]fs.DirEntry, error) {
Err: fs.ErrInvalid, Err: fs.ErrInvalid,
} }
} }
name = filepath.Clean(name)
if name == "." || name == "" { if name == "." || name == "" {
return f.File.ReadDir(-1) 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) { func (f FS) ReadFile(name string) ([]byte, error) {
fil, err := f.Open(name) fil, err := f.Open(name)
if err != nil { if err != nil {
@@ -256,8 +256,9 @@ func (f FS) ReadFile(name string) ([]byte, error) {
return buf.Bytes(), nil 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) { func (f FS) Stat(name string) (fs.FileInfo, error) {
name = filepath.Clean(strings.TrimPrefix(name, "/"))
if !fs.ValidPath(name) { if !fs.ValidPath(name) {
return nil, &fs.PathError{ return nil, &fs.PathError{
Op: "stat", Op: "stat",
@@ -265,7 +266,6 @@ func (f FS) Stat(name string) (fs.FileInfo, error) {
Err: fs.ErrInvalid, Err: fs.ErrInvalid,
} }
} }
name = filepath.Clean(strings.TrimPrefix(name, "/"))
if name == "." || name == "" { if name == "." || name == "" {
return f.File.Stat() 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) { func (f FS) Sub(dir string) (fs.FS, error) {
dir = filepath.Clean(dir)
if !fs.ValidPath(dir) { if !fs.ValidPath(dir) {
return nil, &fs.PathError{ return nil, &fs.PathError{
Op: "sub", Op: "sub",
@@ -334,7 +335,6 @@ func (f FS) Sub(dir string) (fs.FS, error) {
Err: fs.ErrInvalid, Err: fs.ErrInvalid,
} }
} }
dir = filepath.Clean(dir)
if dir == "." || dir == "" { if dir == "." || dir == "" {
return f, nil return f, nil
} }
+15
View File
@@ -57,6 +57,21 @@ func preTest(dir string) (fil *os.File, err error) {
return 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) { func BenchmarkRace(b *testing.B) {
// tmpDir := b.TempDir() // tmpDir := b.TempDir()
tmpDir := "testing" tmpDir := "testing"