Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a015b16293 |
+24
-24
@@ -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
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user