diff --git a/oval/dpkginfo.go b/oval/dpkginfo.go new file mode 100644 index 0000000..12b3988 --- /dev/null +++ b/oval/dpkginfo.go @@ -0,0 +1,49 @@ +package oval + +import ( + "encoding/xml" +) + +// DpkgInfoTest : >tests>dpkginfo_test +type DpkgInfoTest struct { + XMLName xml.Name `xml:"dpkginfo_test"` + ID string `xml:"id,attr"` + Comment string `xml:"comment,attr"` + Check string `xml:"check,attr"` + Version int `xml:"version,attr"` + ObjectRefs []ObjectRef `xml:"object"` + StateRefs []StateRef `xml:"state"` +} + +// DpkgName : >objects>dpkginfo_object>name +// +// when parsing ubuntu var_ref is a reference +// to the section of the document +// +// when parsing debian var_ref is empty and +// the Body field is used directly +type DpkgName struct { + XMLName xml.Name `xml:"name"` + Ref string `xml:"var_ref,attr"` + Body string `xml:",chardata"` +} + +// DpkgInfoObject : >objects>dpkginfo_object +type DpkgInfoObject struct { + XMLName xml.Name `xml:"dpkginfo_object"` + ID string `xml:"id,attr"` + Version int `xml:"version,attr"` + Name *DpkgName `xml:"name"` +} + +// DpkgInfoState : >states>dpkginfo_state +type DpkgInfoState struct { + XMLName xml.Name `xml:"dpkginfo_state"` + ID string `xml:"id,attr"` + Version int `xml:"version,attr"` + Arch *Arch `xml:"arch"` + Epoch *Epoch `xml:"epoch"` + Release *Release `xml:"release"` + DpkgVersion *Version `xml:"version"` + EVR *EVR `xml:"evr"` +} diff --git a/oval/objects.go b/oval/objects.go index 222eded..a73d4a8 100644 --- a/oval/objects.go +++ b/oval/objects.go @@ -7,7 +7,7 @@ import ( func (o *Objects) init() { var wg sync.WaitGroup - wg.Add(3) + wg.Add(4) go func() { defer wg.Done() @@ -33,6 +33,14 @@ func (o *Objects) init() { } }() + go func() { + defer wg.Done() + o.dpkginfoMemo = make(map[string]int, len(o.DpkgInfoObjects)) + for i, v := range o.DpkgInfoObjects { + o.dpkginfoMemo[v.ID] = i + } + }() + wg.Wait() } @@ -43,13 +51,15 @@ func (o *Objects) Lookup(ref string) (kind string, index int, err error) { if i, ok := o.lineMemo[ref]; ok { return o.LineObjects[i].XMLName.Local, i, nil } - if i, ok := o.version55Memo[ref]; ok { return o.Version55Objects[i].XMLName.Local, i, nil } if i, ok := o.rpminfoMemo[ref]; ok { return o.RPMInfoObjects[i].XMLName.Local, i, nil } + if i, ok := o.dpkginfoMemo[ref]; ok { + return o.DpkgInfoObjects[i].XMLName.Local, i, nil + } // We didn't find it, maybe we can say why. id, err := ParseID(ref) diff --git a/oval/rpminfo.go b/oval/rpminfo.go index 56d96b8..e2b2f25 100644 --- a/oval/rpminfo.go +++ b/oval/rpminfo.go @@ -39,39 +39,14 @@ type RPMInfoState struct { XMLName xml.Name `xml:"rpminfo_state"` ID string `xml:"id,attr"` Version int `xml:"version,attr"` - Arch *RPMArch `xml:"arch"` - Epoch *RPMEpoch `xml:"epoch"` - Release *RPMRelease `xml:"release"` - RPMVersion *RPMVersion `xml:"version"` - EVR *RPMEVR `xml:"evr"` + Arch *Arch `xml:"arch"` + Epoch *Epoch `xml:"epoch"` + Release *Release `xml:"release"` + RPMVersion *Version `xml:"version"` + EVR *EVR `xml:"evr"` SignatureKeyID *RPMSignatureKeyID `xml:"signature_keyid"` } -type RPMArch struct { - XMLName xml.Name `xml:"arch"` - Operation Operation `xml:"operation,attr"` - Body string `xml:",chardata"` -} -type RPMEpoch struct { - XMLName xml.Name `xml:"epoch"` - Operation Operation `xml:"operation,attr"` - Body string `xml:",chardata"` -} -type RPMRelease struct { - XMLName xml.Name `xml:"release"` - Operation Operation `xml:"operation,attr"` - Body string `xml:",chardata"` -} -type RPMVersion struct { - XMLName xml.Name `xml:"version"` - Operation Operation `xml:"operation,attr"` - Body string `xml:",chardata"` -} -type RPMEVR struct { - XMLName xml.Name `xml:"evr"` - Operation Operation `xml:"operation,attr"` - Body string `xml:",chardata"` -} type RPMSignatureKeyID struct { XMLName xml.Name `xml:"signature_keyid"` Operation Operation `xml:"operation,attr"` diff --git a/oval/states.go b/oval/states.go index 0199a7d..601dc8c 100644 --- a/oval/states.go +++ b/oval/states.go @@ -7,7 +7,7 @@ import ( func (s *States) init() { var wg sync.WaitGroup - wg.Add(3) + wg.Add(4) go func() { defer wg.Done() @@ -33,6 +33,14 @@ func (s *States) init() { } }() + go func() { + defer wg.Done() + s.dpkginfoMemo = make(map[string]int, len(s.DpkgInfoStates)) + for i, v := range s.DpkgInfoStates { + s.dpkginfoMemo[v.ID] = i + } + }() + wg.Wait() } @@ -50,6 +58,9 @@ func (s *States) Lookup(ref string) (kind string, index int, err error) { if i, ok := s.rpminfoMemo[ref]; ok { return s.RPMInfoStates[i].XMLName.Local, i, nil } + if i, ok := s.dpkginfoMemo[ref]; ok { + return s.DpkgInfoStates[i].XMLName.Local, i, nil + } // We didn't find it, maybe we can say why. id, err := ParseID(ref) diff --git a/oval/tests.go b/oval/tests.go index b973b12..cb17ad2 100644 --- a/oval/tests.go +++ b/oval/tests.go @@ -8,7 +8,7 @@ import ( // Init sets up the memoization maps. func (t *Tests) init() { var wg sync.WaitGroup - wg.Add(6) + wg.Add(7) go func() { defer wg.Done() @@ -34,6 +34,14 @@ func (t *Tests) init() { } }() + go func() { + defer wg.Done() + t.dpkginfoMemo = make(map[string]int, len(t.DpkgInfoTests)) + for i, v := range t.DpkgInfoTests { + t.dpkginfoMemo[v.ID] = i + } + }() + go func() { defer wg.Done() t.rpmverifyfileMemo = make(map[string]int, len(t.RPMVerifyFileTests)) @@ -76,6 +84,9 @@ func (t *Tests) Lookup(ref string) (kind string, index int, err error) { if i, ok := t.rpminfoMemo[ref]; ok { return t.RPMInfoTests[i].XMLName.Local, i, nil } + if i, ok := t.dpkginfoMemo[ref]; ok { + return t.DpkgInfoTests[i].XMLName.Local, i, nil + } if i, ok := t.rpmverifyfileMemo[ref]; ok { return t.RPMVerifyFileTests[i].XMLName.Local, i, nil } diff --git a/oval/types.go b/oval/types.go index b5cf5f1..fd51c09 100644 --- a/oval/types.go +++ b/oval/types.go @@ -23,6 +23,7 @@ type Root struct { Tests Tests `xml:"tests"` Objects Objects `xml:"objects"` States States `xml:"states"` + Variables Variables `xml:"variables"` } // Generator : >generator @@ -229,12 +230,14 @@ type Tests struct { LineTests []LineTest `xml:"line_test"` Version55Tests []Version55Test `xml:"version55_test"` RPMInfoTests []RPMInfoTest `xml:"rpminfo_test"` + DpkgInfoTests []DpkgInfoTest `xml:"dpkginfo_test"` RPMVerifyFileTests []RPMVerifyFileTest `xml:"rpmverifyfile_test"` UnameTests []UnameTest `xml:"uname_test"` TextfileContent54Tests []TextfileContent54Test `xml:"textfilecontent54_test"` lineMemo map[string]int version55Memo map[string]int rpminfoMemo map[string]int + dpkginfoMemo map[string]int rpmverifyfileMemo map[string]int unameMemo map[string]int textfilecontent54Memo map[string]int @@ -261,9 +264,11 @@ type Objects struct { LineObjects []LineObject `xml:"line_object"` Version55Objects []Version55Object `xml:"version55_object"` RPMInfoObjects []RPMInfoObject `xml:"rpminfo_object"` + DpkgInfoObjects []DpkgInfoObject `xml:"dpkginfo_object"` lineMemo map[string]int version55Memo map[string]int rpminfoMemo map[string]int + dpkginfoMemo map[string]int } // States : >states @@ -273,7 +278,68 @@ type States struct { LineStates []LineState `xml:"line_state"` Version55States []Version55State `xml:"version55_state"` RPMInfoStates []RPMInfoState `xml:"rpminfo_state"` + DpkgInfoStates []DpkgInfoState `xml:"dpkginfo_state"` lineMemo map[string]int version55Memo map[string]int rpminfoMemo map[string]int + dpkginfoMemo map[string]int +} + +// Value +type Value struct { + XMLName xml.Name `xml:"value"` + Body string `xml:",chardata"` +} + +// ConstantVariable +type ConstantVariable struct { + XMLName xml.Name `xml:"constant_variable"` + ID string `xml:"id,attr"` + Version string `xml:"version,attr"` + Datatype string `xml:"datatype,attr"` + Comment string `xml:"comment,attr"` + Values []Value `xml:"value"` +} + +// Variables : >variables +type Variables struct { + once sync.Once + XMLName xml.Name `xml:"variables"` + ConstantVariables []ConstantVariable `xml:"constant_variable"` + dpkginfoMemo map[string]int +} + +// Arch +type Arch struct { + XMLName xml.Name `xml:"arch"` + Operation Operation `xml:"operation,attr"` + Body string `xml:",chardata"` +} + +// Epoch +type Epoch struct { + XMLName xml.Name `xml:"epoch"` + Operation Operation `xml:"operation,attr"` + Body string `xml:",chardata"` +} + +// Release +type Release struct { + XMLName xml.Name `xml:"release"` + Operation Operation `xml:"operation,attr"` + Body string `xml:",chardata"` +} + +// Version +type Version struct { + XMLName xml.Name `xml:"version"` + Operation Operation `xml:"operation,attr"` + Body string `xml:",chardata"` +} + +// EVR +type EVR struct { + XMLName xml.Name `xml:"evr"` + Operation Operation `xml:"operation,attr"` + Body string `xml:",chardata"` } diff --git a/oval/variables.go b/oval/variables.go new file mode 100644 index 0000000..e4eae22 --- /dev/null +++ b/oval/variables.go @@ -0,0 +1,40 @@ +package oval + +import ( + "fmt" + "sync" +) + +func (o *Variables) init() { + var wg sync.WaitGroup + wg.Add(1) + + go func() { + defer wg.Done() + o.dpkginfoMemo = make(map[string]int, len(o.ConstantVariables)) + for i, v := range o.ConstantVariables { + o.dpkginfoMemo[v.ID] = i + } + }() + + wg.Wait() +} + +// Lookup returns the kind of object and index into that kind-specific slice, if +// found. +func (o *Variables) Lookup(ref string) (kind string, index int, err error) { + o.once.Do(o.init) + if i, ok := o.dpkginfoMemo[ref]; ok { + return o.ConstantVariables[i].XMLName.Local, i, nil + } + + // We didn't find it, maybe we can say why. + id, err := ParseID(ref) + if err != nil { + return "", -1, err + } + if id.Type != OvalVariable { + return "", -1, fmt.Errorf("oval: wrong identifier type %q", id.Type) + } + return "", -1, ErrNotFound(ref) +}