-
Notifications
You must be signed in to change notification settings - Fork 43
/
rockridge.go
99 lines (80 loc) · 2.25 KB
/
rockridge.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package iso9660
import (
"fmt"
"io/fs"
"os"
)
/* The following types of Rock Ridge records are being handled in some way:
* - [X] PX (RR 4.1.1: POSIX file attributes)
* - [ ] PN (RR 4.1.2: POSIX device number)
* - [ ] SL (RR 4.1.3: symbolic link)
* - [x] NM (RR 4.1.4: alternate name)
* - [ ] CL (RR 4.1.5.1: child link)
* - [ ] PL (RR 4.1.5.2: parent link)
* - [ ] RE (RR 4.1.5.3: relocated directory)
* - [ ] TF (RR 4.1.6: time stamp(s) for a file)
* - [ ] SF (RR 4.1.7: file data in sparse file format)
*/
const (
RockRidgeIdentifier = "RRIP_1991A"
RockRidgeVersion = 1
)
type RockRidgeNameEntry struct {
Flags byte
Name string
}
func suspHasRockRidge(se SystemUseEntrySlice) (bool, error) {
extensions, err := se.GetExtensionRecords()
if err != nil {
return false, err
}
for _, entry := range extensions {
if entry.Identifier == RockRidgeIdentifier && entry.Version == RockRidgeVersion {
return true, nil
}
}
return false, nil
}
func (s SystemUseEntrySlice) GetRockRidgeName() string {
var name string
for _, entry := range s {
// There is a continuation flag in the record, but we determine continuation
// by simply reading all NM entries.
if entry.Type() == "NM" {
nm := umarshalRockRidgeNameEntry(entry)
name += nm.Name
}
}
return name
}
func (s SystemUseEntrySlice) GetPosixAttr() (fs.FileMode, error) {
for _, entry := range s {
if entry.Type() == "PX" {
// BUG(kdomanski): If there are multiple RR PX entries (which is forbidden by the spec), the reader will use the first one.
return umarshalRockRidgeAttrEntry(entry)
}
}
return 0, fmt.Errorf("mandatory entry PX not found")
}
func umarshalRockRidgeAttrEntry(e SystemUseEntry) (fs.FileMode, error) {
rrMode, err := UnmarshalUint32LSBMSB(e.Data()[0:8])
if err != nil {
return 0, fmt.Errorf("unmarshall RR PX entry: %w", err)
}
S_IFLNK := (rrMode & 0170000) == 0120000
S_IFDIR := (rrMode & 0170000) == 0040000
mode := rrMode & uint32(fs.ModePerm) // UNIX permissions
if S_IFLNK {
mode |= uint32(os.ModeSymlink)
}
if S_IFDIR {
mode |= uint32(os.ModeDir)
}
return fs.FileMode(mode), nil
}
func umarshalRockRidgeNameEntry(e SystemUseEntry) *RockRidgeNameEntry {
return &RockRidgeNameEntry{
Flags: e.Data()[0],
Name: string(e.Data()[1:]),
}
}