Skip to content

Commit c645ba1

Browse files
authored
add UDF file format reader to support solutions add-on installation (#647)
In this package a reader is implemented that supports extracting files from solutions add-on ISO without unpacking/mounting it advance. Motivation A new feature is being implemented where the vcd client and terraform provider should support installation of the VCD solution add-ons. Solution add-ons are packaged as an ISO media. To support larger files and avoid other issues with simple CDROM file format, the .iso file is packaged as UDF filesystem (specification: http://www.osta.org/specs/pdf/udf260.pdf ). udf internal package implements partially that specification and enables read. Specifically, the code allows only reading of top level objects within a .ISO file. Signed-off-by: Valentin Manasiev <vmanasiev@vmware.com>
1 parent 3741967 commit c645ba1

File tree

6 files changed

+1568
-0
lines changed

6 files changed

+1568
-0
lines changed

go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@ require (
1313
)
1414

1515
require (
16+
github.com/howeyc/crc16 v0.0.0-20171223171357-2b2a61e366a6
1617
github.com/kr/text v0.1.0 // indirect
1718
github.com/stretchr/testify v1.5.1 // indirect
19+
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a
20+
golang.org/x/text v0.14.0
1821
)
1922

2023
replace (

go.sum

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ github.com/go-yaml/yaml/v2 v2.2.2 h1:uw2m9KuKRscWGAkuyoBGQcZSdibhmuXKSJ3+9Tj3zXc
88
github.com/go-yaml/yaml/v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
99
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
1010
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
11+
github.com/howeyc/crc16 v0.0.0-20171223171357-2b2a61e366a6 h1:IIVxLyDUYErC950b8kecjoqDet8P5S4lcVRUOM6rdkU=
12+
github.com/howeyc/crc16 v0.0.0-20171223171357-2b2a61e366a6/go.mod h1:JslaLRrzGsOKJgFEPBP65Whn+rdwDQSk0I0MCRFe2Zw=
1113
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
1214
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
1315
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -20,3 +22,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
2022
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
2123
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
2224
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
25+
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
26+
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
27+
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
28+
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=

internal/udf/cdrom.go

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package udf
2+
3+
import (
4+
"fmt"
5+
"golang.org/x/exp/slices"
6+
)
7+
8+
const (
9+
cdromVolumeDescriptorSectorNumber = 16
10+
11+
cdromVolumeIdentifierBEA01 = "BEA01"
12+
cdromVolumeIdentifierBOOT2 = "BOOT2"
13+
cdromVolumeIdentifierCD001 = "CD001"
14+
cdromVolumeIdentifierCDW02 = "CDW02"
15+
cdromVolumeIdentifierNSR02 = "NSR02"
16+
cdromVolumeIdentifierNSR03 = "NSR03"
17+
cdromVolumeIdentifierTEA01 = "TEA01"
18+
)
19+
20+
type CdromDescriptor interface {
21+
GetHeader() *CdromVolumeDescriptorHeader
22+
}
23+
24+
type CdromDescriptorList []CdromDescriptor
25+
26+
func (list CdromDescriptorList) hasAnyIdentifier(identifiers ...string) bool {
27+
for idx := 0; idx < len(list); idx++ {
28+
identifier := list[idx].GetHeader().Identifier
29+
if slices.Contains(identifiers, identifier) {
30+
return true
31+
}
32+
}
33+
return false
34+
}
35+
36+
func (list CdromDescriptorList) getByType(descType uint8) CdromDescriptor {
37+
if desc := list.findByType(descType); desc != nil {
38+
return desc
39+
} else {
40+
panic(fmt.Sprintf("CDROM descriptor with type %d does not exist in sequence", descType))
41+
}
42+
}
43+
44+
func (list CdromDescriptorList) findByType(descType uint8) CdromDescriptor {
45+
for idx := 0; idx < len(list); idx++ {
46+
if list[idx].GetHeader().Type == descType {
47+
return list[idx]
48+
}
49+
}
50+
return nil
51+
}
52+
53+
func (list CdromDescriptorList) getByIdentifier(identifier string) CdromDescriptor {
54+
if desc := list.findByIdentifier(identifier); desc != nil {
55+
return desc
56+
} else {
57+
panic(fmt.Sprintf("CDROM descriptor with identifier %s does not exist in sequence", identifier))
58+
}
59+
}
60+
61+
func (list CdromDescriptorList) findByIdentifier(identifier string) CdromDescriptor {
62+
for idx := 0; idx < len(list); idx++ {
63+
if list[idx].GetHeader().Identifier == identifier {
64+
return list[idx]
65+
}
66+
}
67+
return nil
68+
}
69+
70+
type CdromVolumeDescriptorHeader struct {
71+
Type uint8
72+
Identifier string
73+
Version uint8
74+
}
75+
76+
type CdromExtendedAreaVolumeDescriptor struct {
77+
Header CdromVolumeDescriptorHeader
78+
}
79+
80+
func (d *CdromExtendedAreaVolumeDescriptor) GetHeader() *CdromVolumeDescriptorHeader {
81+
return &d.Header
82+
}
83+
84+
type CdromBootVolumeDescriptor struct {
85+
Header CdromVolumeDescriptorHeader
86+
}
87+
88+
func (d *CdromBootVolumeDescriptor) GetHeader() *CdromVolumeDescriptorHeader {
89+
return &d.Header
90+
}
91+
92+
type CdromCdwVolumeDescriptor struct {
93+
Header CdromVolumeDescriptorHeader
94+
}
95+
96+
func (d *CdromCdwVolumeDescriptor) GetHeader() *CdromVolumeDescriptorHeader {
97+
return &d.Header
98+
}
99+
100+
type CdromNsrVolumeDescriptor struct {
101+
Header CdromVolumeDescriptorHeader
102+
}
103+
104+
func (d *CdromNsrVolumeDescriptor) GetHeader() *CdromVolumeDescriptorHeader {
105+
return &d.Header
106+
}
107+
108+
type CdromTerminalVolumeDescriptor struct {
109+
Header CdromVolumeDescriptorHeader
110+
}
111+
112+
func (d *CdromTerminalVolumeDescriptor) GetHeader() *CdromVolumeDescriptorHeader {
113+
return &d.Header
114+
}

internal/udf/perms.go

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package udf
2+
3+
import "io/fs"
4+
5+
// Permissions (BP 44)
6+
// Bit 0: Other: If set to ZERO, shall mean that the user may not execute the file; If set to ONE, shall mean that
7+
// the user may execute the file.
8+
// Bit 1: Other: If set to ZERO, shall mean that the user may not write the file; If set to ONE, shall mean that
9+
// the user may write the file.
10+
// Bit 2: Other: If set to ZERO, shall mean that the user may not read the file; If set to ONE, shall mean that the
11+
// user may read the file.
12+
// Bit 3: Other: If set to ZERO, shall mean that the user may not change any attributes of the file; If set to
13+
// ONE, shall mean that the user may change attributes of the file.
14+
// Bit 4: Other: If set to ZERO, shall mean that the user may not delete the file; If set to ONE, shall mean that
15+
// the user may delete the file.
16+
// Bit 5: Group: If set to ZERO, shall mean that the user may not execute the file; If set to ONE, shall mean
17+
// that the user may execute the file.
18+
// Bit 6: Group: If set to ZERO, shall mean that the user may not write the file; If set to ONE, shall mean that
19+
// the user may write the file.
20+
// Bit 7: Group: If set to ZERO, shall mean that the user may not read the file; If set to ONE, shall mean that
21+
// the user may read the file.
22+
// Bit 8: Group: If set to ZERO, shall mean that the user may not change any attributes of the file; If set to
23+
// ONE, shall mean that the user may change attributes of the file.
24+
// Bit 9: Group: If set to ZERO, shall mean that the user may not delete the file; If set to ONE, shall mean that
25+
// the user may delete the file.
26+
// Bit 10: Owner: If set to ZERO, shall mean that the user may not execute the file; If set to ONE, shall mean
27+
// that the user may execute the file.
28+
// Bit 11: Owner: If set to ZERO, shall mean that the user may not write the file; If set to ONE, shall mean that
29+
// the user may write the file.
30+
// Bit 12: Owner: If set to ZERO, shall mean that the user may not read the file; If set to ONE, shall mean that
31+
// the user may read the file.
32+
// Bit 13: Owner: If set to ZERO, shall mean that the user may not change any attributes of the file; If set to
33+
// ONE, shall mean that the user may change attributes of the file.
34+
// Bit 14: Owner: If set to ZERO, shall mean that the user may not delete the file; If set to ONE, shall mean that
35+
// the user may delete the file.
36+
// 15-31 Reserved: Shall be set to ZERO.
37+
38+
type FilePerm uint32
39+
40+
const (
41+
FilePermExecute FilePerm = 1 << iota
42+
FilePermWrite
43+
FilePermRead
44+
FilePermChange
45+
FilePermDelete
46+
)
47+
48+
const (
49+
FileModeOtherOffset = 5 * iota
50+
FileModeGroupOffset
51+
FileModeOwnerOffset
52+
)
53+
54+
const (
55+
FileModeOtherMask = ((1 << 5) - 1) << (5 * iota)
56+
FileModeGroupMask
57+
FileModeOwnerMask
58+
)
59+
60+
type FileMode uint32
61+
62+
func ToFileMode(mode fs.FileMode) FileMode {
63+
mode = mode.Perm()
64+
var r FileMode
65+
r |= FileMode(mode & 7) // Other
66+
r |= FileMode((mode >> 3) & 7 << 5) // Group
67+
r |= FileMode((mode >> 6) & 7 << 10) // Owner
68+
return r
69+
}
70+
71+
func FromFileMode(mode FileMode) fs.FileMode {
72+
var r fs.FileMode
73+
r |= fs.FileMode(mode & 7) // Other
74+
r |= fs.FileMode(((mode >> 5) & 7) << 3) // Group
75+
r |= fs.FileMode(((mode >> 10) & 7) << 6) // Owner
76+
return r
77+
}
78+
79+
func (m FileMode) Other() FileMode {
80+
return m & FileModeOtherMask
81+
}
82+
83+
func (m FileMode) HasOther(perms FilePerm) bool {
84+
return (m>>FileModeOtherOffset)&FileMode(perms) == FileMode(perms)
85+
}
86+
87+
func (m FileMode) SetOther(perms FilePerm) FileMode {
88+
return m | (FileMode(perms) << FileModeOtherOffset)
89+
}
90+
91+
func (m FileMode) UnsetOther(perms FilePerm) FileMode {
92+
return m &^ (FileMode(perms) << FileModeOtherOffset)
93+
}
94+
95+
func (m FileMode) Group() FileMode {
96+
return m & FileModeGroupMask
97+
}
98+
99+
func (m FileMode) HasGroup(perms FilePerm) bool {
100+
return (m>>FileModeGroupOffset)&FileMode(perms) == FileMode(perms)
101+
}
102+
103+
func (m FileMode) SetGroup(perms FilePerm) FileMode {
104+
return m | (FileMode(perms) << FileModeGroupOffset)
105+
}
106+
107+
func (m FileMode) UnsetGroup(perms FilePerm) FileMode {
108+
return m &^ (FileMode(perms) << FileModeGroupOffset)
109+
}
110+
func (m FileMode) Owner() FileMode {
111+
return m & FileModeOwnerMask
112+
}
113+
114+
func (m FileMode) HasOwner(perms FilePerm) bool {
115+
return (m>>FileModeOwnerOffset)&FileMode(perms) == FileMode(perms)
116+
}
117+
118+
func (m FileMode) SetOwner(perms FilePerm) FileMode {
119+
return m | (FileMode(perms) << FileModeOwnerOffset)
120+
}
121+
122+
func (m FileMode) UnsetOwner(perms FilePerm) FileMode {
123+
return m &^ (FileMode(perms) << FileModeOwnerOffset)
124+
}

0 commit comments

Comments
 (0)