mirror of
https://github.com/blacktop/ipsw.git
synced 2026-05-08 12:22:26 +00:00
189 lines
3.4 KiB
Go
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()
|
|
}
|