mirror of
https://github.com/rwinkhart/go-winio.git
synced 2026-09-06 00:57:19 -04:00
WIM: Parse XML data
This parses the XML data so that callers do not have to.
This commit is contained in:
@@ -20,6 +20,9 @@ func main() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%#v\n%#v\n", w.Image[0], w.Image[0].Windows)
|
||||||
|
|
||||||
dir, err := w.Image[0].Open()
|
dir, err := w.Image[0].Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|||||||
+119
-13
@@ -9,10 +9,12 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/xml"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf16"
|
"unicode/utf16"
|
||||||
)
|
)
|
||||||
@@ -39,6 +41,23 @@ const (
|
|||||||
FILE_ATTRIBUTE_EA = 0x00040000
|
FILE_ATTRIBUTE_EA = 0x00040000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Windows processor architectures.
|
||||||
|
const (
|
||||||
|
PROCESSOR_ARCHITECTURE_INTEL = 0
|
||||||
|
PROCESSOR_ARCHITECTURE_MIPS = 1
|
||||||
|
PROCESSOR_ARCHITECTURE_ALPHA = 2
|
||||||
|
PROCESSOR_ARCHITECTURE_PPC = 3
|
||||||
|
PROCESSOR_ARCHITECTURE_SHX = 4
|
||||||
|
PROCESSOR_ARCHITECTURE_ARM = 5
|
||||||
|
PROCESSOR_ARCHITECTURE_IA64 = 6
|
||||||
|
PROCESSOR_ARCHITECTURE_ALPHA64 = 7
|
||||||
|
PROCESSOR_ARCHITECTURE_MSIL = 8
|
||||||
|
PROCESSOR_ARCHITECTURE_AMD64 = 9
|
||||||
|
PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 = 10
|
||||||
|
PROCESSOR_ARCHITECTURE_NEUTRAL = 11
|
||||||
|
PROCESSOR_ARCHITECTURE_ARM64 = 12
|
||||||
|
)
|
||||||
|
|
||||||
var wimImageTag = [...]byte{'M', 'S', 'W', 'I', 'M', 0, 0, 0}
|
var wimImageTag = [...]byte{'M', 'S', 'W', 'I', 'M', 0, 0, 0}
|
||||||
|
|
||||||
type guid struct {
|
type guid struct {
|
||||||
@@ -150,9 +169,9 @@ type direntry struct {
|
|||||||
SecurityID uint32
|
SecurityID uint32
|
||||||
SubdirOffset int64
|
SubdirOffset int64
|
||||||
Unused1, Unused2 int64
|
Unused1, Unused2 int64
|
||||||
CreationTime filetime
|
CreationTime Filetime
|
||||||
LastAccessTime filetime
|
LastAccessTime Filetime
|
||||||
LastWriteTime filetime
|
LastWriteTime Filetime
|
||||||
Hash SHA1Hash
|
Hash SHA1Hash
|
||||||
Padding uint32
|
Padding uint32
|
||||||
ReparseHardLink int64
|
ReparseHardLink int64
|
||||||
@@ -172,12 +191,14 @@ type streamentry struct {
|
|||||||
|
|
||||||
const streamentrySize = 38
|
const streamentrySize = 38
|
||||||
|
|
||||||
type filetime struct {
|
// Filetime represents a Windows time.
|
||||||
|
type Filetime struct {
|
||||||
LowDateTime uint32
|
LowDateTime uint32
|
||||||
HighDateTime uint32
|
HighDateTime uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ft *filetime) Time() time.Time {
|
// Time returns the time as time.Time.
|
||||||
|
func (ft *Filetime) Time() time.Time {
|
||||||
// 100-nanosecond intervals since January 1, 1601
|
// 100-nanosecond intervals since January 1, 1601
|
||||||
nsec := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime)
|
nsec := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime)
|
||||||
// change starting time to the Epoch (00:00:00 UTC, January 1, 1970)
|
// change starting time to the Epoch (00:00:00 UTC, January 1, 1970)
|
||||||
@@ -187,6 +208,67 @@ func (ft *filetime) Time() time.Time {
|
|||||||
return time.Unix(0, nsec)
|
return time.Unix(0, nsec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnmarshalXML unmarshals the time from a WIM XML blob.
|
||||||
|
func (ft *Filetime) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||||
|
type time struct {
|
||||||
|
Low string `xml:"LOWPART"`
|
||||||
|
High string `xml:"HIGHPART"`
|
||||||
|
}
|
||||||
|
var t time
|
||||||
|
err := d.DecodeElement(&t, &start)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
low, err := strconv.ParseUint(t.Low, 0, 32)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
high, err := strconv.ParseUint(t.High, 0, 32)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ft.LowDateTime = uint32(low)
|
||||||
|
ft.HighDateTime = uint32(high)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type info struct {
|
||||||
|
Image []ImageInfo `xml:"IMAGE"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageInfo contains information about the image.
|
||||||
|
type ImageInfo struct {
|
||||||
|
Name string `xml:"NAME"`
|
||||||
|
Index int `xml:"INDEX,attr"`
|
||||||
|
CreationTime Filetime `xml:"CREATIONTIME"`
|
||||||
|
ModTime Filetime `xml:"LASTMODIFICATIONTIME"`
|
||||||
|
Windows *WindowsInfo `xml:"WINDOWS"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// WindowsInfo contains information about the Windows installation in the image.
|
||||||
|
type WindowsInfo struct {
|
||||||
|
Arch byte `xml:"ARCH"`
|
||||||
|
ProductName string `xml:"PRODUCTNAME"`
|
||||||
|
EditionID string `xml:"EDITIONID"`
|
||||||
|
InstallationType string `xml:"INSTALLATIONTYPE"`
|
||||||
|
ProductType string `xml:"PRODUCTTYPE"`
|
||||||
|
Languages []string `xml:"LANGUAGES>LANGUAGE"`
|
||||||
|
DefaultLanguage string `xml:"LANGUAGES>DEFAULT"`
|
||||||
|
Version Version `xml:"VERSION"`
|
||||||
|
SystemRoot string `xml:"SYSTEMROOT"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version represents a Windows build version.
|
||||||
|
type Version struct {
|
||||||
|
Major int `xml:"MAJOR"`
|
||||||
|
Minor int `xml:"MINOR"`
|
||||||
|
Build int `xml:"BUILD"`
|
||||||
|
SPBuild int `xml:"SPBUILD"`
|
||||||
|
SPLevel int `xml:"SPLEVEL"`
|
||||||
|
}
|
||||||
|
|
||||||
// ParseError is returned when the WIM cannot be parsed.
|
// ParseError is returned when the WIM cannot be parsed.
|
||||||
type ParseError struct {
|
type ParseError struct {
|
||||||
Oper string
|
Oper string
|
||||||
@@ -207,6 +289,7 @@ type Reader struct {
|
|||||||
r io.ReaderAt
|
r io.ReaderAt
|
||||||
fileData map[SHA1Hash]resourceDescriptor
|
fileData map[SHA1Hash]resourceDescriptor
|
||||||
|
|
||||||
|
XMLInfo string // The XML information about the WIM.
|
||||||
Image []*Image // The WIM's images.
|
Image []*Image // The WIM's images.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,6 +299,8 @@ type Image struct {
|
|||||||
offset resourceDescriptor
|
offset resourceDescriptor
|
||||||
sds [][]byte
|
sds [][]byte
|
||||||
rootOffset int64
|
rootOffset int64
|
||||||
|
|
||||||
|
ImageInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// StreamHeader contains alternate data stream metadata.
|
// StreamHeader contains alternate data stream metadata.
|
||||||
@@ -238,9 +323,9 @@ type FileHeader struct {
|
|||||||
ShortName string
|
ShortName string
|
||||||
Attributes uint32
|
Attributes uint32
|
||||||
SecurityDescriptor []byte
|
SecurityDescriptor []byte
|
||||||
CreationTime time.Time
|
CreationTime Filetime
|
||||||
LastAccessTime time.Time
|
LastAccessTime Filetime
|
||||||
LastWriteTime time.Time
|
LastWriteTime Filetime
|
||||||
Hash SHA1Hash
|
Hash SHA1Hash
|
||||||
Size int64
|
Size int64
|
||||||
LinkID int64
|
LinkID int64
|
||||||
@@ -286,8 +371,30 @@ func NewReader(f io.ReaderAt) (*Reader, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xmlinfo, err := r.readXML()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var info info
|
||||||
|
err = xml.Unmarshal([]byte(xmlinfo), &info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &ParseError{Oper: "XML info", Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, img := range images {
|
||||||
|
for _, imgInfo := range info.Image {
|
||||||
|
if imgInfo.Index == i+1 {
|
||||||
|
img.ImageInfo = imgInfo
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
r.fileData = fileData
|
r.fileData = fileData
|
||||||
r.Image = images
|
r.Image = images
|
||||||
|
r.XMLInfo = xmlinfo
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,8 +428,7 @@ func (r *Reader) readResource(hdr *resourceDescriptor) ([]byte, error) {
|
|||||||
return ioutil.ReadAll(rsrc)
|
return ioutil.ReadAll(rsrc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadXML reads the XML metadata from a WIM.
|
func (r *Reader) readXML() (string, error) {
|
||||||
func (r *Reader) ReadXML() (string, error) {
|
|
||||||
if r.hdr.XMLData.CompressedSize() == 0 {
|
if r.hdr.XMLData.CompressedSize() == 0 {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
@@ -552,9 +658,9 @@ func (img *Image) readNextEntry(r *bufio.Reader) (*File, error) {
|
|||||||
f := &File{
|
f := &File{
|
||||||
FileHeader: FileHeader{
|
FileHeader: FileHeader{
|
||||||
Attributes: dentry.Attributes,
|
Attributes: dentry.Attributes,
|
||||||
CreationTime: dentry.CreationTime.Time(),
|
CreationTime: dentry.CreationTime,
|
||||||
LastAccessTime: dentry.LastAccessTime.Time(),
|
LastAccessTime: dentry.LastAccessTime,
|
||||||
LastWriteTime: dentry.LastWriteTime.Time(),
|
LastWriteTime: dentry.LastWriteTime,
|
||||||
Hash: dentry.Hash,
|
Hash: dentry.Hash,
|
||||||
Size: offset.OriginalSize,
|
Size: offset.OriginalSize,
|
||||||
Name: name,
|
Name: name,
|
||||||
|
|||||||
Reference in New Issue
Block a user