Files

189 lines
3.4 KiB
Go

package bom
import (
"bufio"
"encoding/binary"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"time"
"github.com/apex/log"
)
const (
TypeBad = 0
TypeFile = 1
TypeDir = 2
TypeSymLink = 3
TypeDevice = 4
TypeSocket = 5
)
const (
ArchNone = 0
ArchMachO = 1
ArchFat = 2
ArchCFM = 3
)
const (
CompressionNone = 0
CompressionZlib = 1
CompressionBZ2 = 2
CompressionAuto = 8
CompressionMask = 0xF
)
type pathInfo struct {
ID uint32
Index uint32
}
type pathDetail struct {
Type uint8
_ uint8 // unknown
Architecture uint16
Mode uint16
User uint32
Group uint32
ModTime uint32
Size uint32
_ uint8 // unknown
Checksum uint32
DevType uint32
}
type File struct {
id int
name string
size int64
mode os.FileMode
modTime time.Time
isDir bool
parent int
}
func (b *File) Name() string {
return b.name
}
func (b *File) Size() int64 {
return b.size
}
func (b *File) Mode() os.FileMode {
return b.mode
}
func (b *File) ModTime() time.Time {
return b.modTime
}
func (b *File) IsDir() bool {
return b.isDir
}
func (b *File) Sys() any {
return nil
}
func (b *BOM) GetPaths() ([]os.FileInfo, error) {
paths, err := b.ReadTree("Paths")
if err != nil {
return nil, err
}
fileInfo := make([]os.FileInfo, 0)
parents := make(map[uint32]uint32)
filepaths := make(map[uint32]string)
for {
for _, index := range paths.Indices {
var pinfo pathInfo
if err := binary.Read(index.ValueReader, binary.BigEndian, &pinfo); err != nil {
log.Errorf("failed to read path info: %v", err)
}
var parent uint32
if err := binary.Read(index.KeyReader, binary.BigEndian, &parent); err != nil {
log.Errorf("failed to read path detail: %v", err)
}
name, err := readString(index.KeyReader)
if err != nil {
log.Errorf("failed to read path name: %v", err)
}
name = fmt.Sprint(string(name))
var pdetail pathDetail
if err := b.lookup(int(pinfo.Index), &pdetail); err != nil {
return nil, err
}
if parent > 0 {
parents[pinfo.ID] = parent
filepaths[pinfo.ID] = name
}
for parentID := parent; parentID > 0; parentID = parents[parentID] {
name = filepath.Join(filepaths[parentID], name)
}
f := &File{
id: int(pinfo.ID),
name: name,
parent: int(parent),
mode: os.FileMode(pdetail.Mode),
isDir: pdetail.Type == TypeDir,
modTime: time.Unix(int64(pdetail.ModTime), 0),
size: int64(pdetail.Size),
}
fileInfo = append(fileInfo, f)
}
if paths.Forward == 0 {
break
} else {
paths, err = b.readTree(paths.Forward)
if err != nil {
return nil, err
}
paths.Indices = make([]TreeIndex, paths.Count)
for i := uint16(0); i < paths.Count; i++ {
var ti TreeIndex
if err := binary.Read(paths.r, binary.BigEndian, &ti.Value); err != nil {
return nil, err
}
if err := binary.Read(paths.r, binary.BigEndian, &ti.Key); err != nil {
return nil, err
}
ti.KeyReader, err = b.blockReader(ti.Key)
if err != nil {
return nil, err
}
ti.ValueReader, err = b.blockReader(ti.Value)
if err != nil {
return nil, err
}
paths.Indices[i] = ti
}
}
}
return fileInfo, nil
}
func readString(r io.Reader) (string, error) {
scanner := bufio.NewScanner(r)
for scanner.Scan() {
return strings.Trim(scanner.Text(), "\x00"), nil
}
return "", scanner.Err()
}