package squashfslow import ( "errors" "io/fs" "path/filepath" "slices" "strings" "github.com/CalebQ42/squashfs/internal/metadata" "github.com/CalebQ42/squashfs/internal/toreader" "github.com/CalebQ42/squashfs/low/directory" "github.com/CalebQ42/squashfs/low/inode" ) type Directory struct { FileBase Entries []directory.Entry } func (r Reader) directoryFromRef(ref uint64, name string) (Directory, error) { i, err := r.InodeFromRef(ref) if err != nil { return Directory{}, err } var blockStart uint32 var size uint32 var offset uint16 switch i.Type { case inode.Dir: blockStart = i.Data.(inode.Directory).BlockStart size = uint32(i.Data.(inode.Directory).Size) offset = i.Data.(inode.Directory).Offset case inode.EDir: blockStart = i.Data.(inode.EDirectory).BlockStart size = i.Data.(inode.EDirectory).Size offset = i.Data.(inode.EDirectory).Offset default: return Directory{}, errors.New("not a directory") } dirRdr := metadata.NewReader(toreader.NewReader(r.r, int64(r.Superblock.DirTableStart)+int64(blockStart)), r.d) defer dirRdr.Close() _, err = dirRdr.Read(make([]byte, offset)) if err != nil { return Directory{}, err } entries, err := directory.ReadDirectory(&dirRdr, size) if err != nil { return Directory{}, err } return Directory{ FileBase: r.BaseFromInode(i, name), Entries: entries, }, nil } func (d Directory) Open(r Reader, path string) (FileBase, error) { path = filepath.Clean(path) if path == "." || path == "" { return d.FileBase, nil } split := strings.Split(path, "/") i, found := slices.BinarySearchFunc(d.Entries, split[0], func(e directory.Entry, name string) int { return strings.Compare(e.Name, name) }) if !found { return FileBase{}, fs.ErrNotExist } b, err := r.BaseFromEntry(d.Entries[i]) if err != nil { return FileBase{}, err } if len(split) == 1 { return b, nil } else if !b.IsDir() { return FileBase{}, fs.ErrNotExist } dir, err := b.ToDir(r) if err != nil { return FileBase{}, err } return dir.Open(r, strings.Join(split[1:], "/")) }