rockridge.go 2.3 KB

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