github.com/vmware/go-vcloud-director/v2@v2.24.0/internal/udf/udf.go (about)

     1  package udf
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"golang.org/x/exp/utf8string"
     8  	"golang.org/x/text/encoding/charmap"
     9  	"golang.org/x/text/encoding/unicode"
    10  	"golang.org/x/text/transform"
    11  )
    12  
    13  const (
    14  	sectorSize                         = 2048
    15  	anchorVolumeDescriptorSectorNumber = 256
    16  	tagSize                            = 16
    17  	tagVersion2                        = 2 // ECMA-167/2
    18  	entityIdSize                       = 32
    19  )
    20  
    21  const (
    22  	dcharEncodingType8  = 8
    23  	dcharEncodingType16 = 16
    24  )
    25  
    26  const (
    27  	// Indicates the contents of the specified logical volume or file set
    28  	// is complaint with domain defined by this document.
    29  	entityIdentifierOSTACompliant = "*OSTA UDF Compliant"
    30  	// Contains additional Logical Volume identification information.
    31  	entityIdentifierLVInfo = "*UDF LV Info"
    32  	// Contains free unused space within the implementation extended attribute space.
    33  	entityIdentifierFreeEASpace = "*UDF FreeEASpace"
    34  	entityIdentifierDvdCGMSInfo = "*UDF DVD CGMS Info"
    35  )
    36  
    37  const (
    38  	osClassUndefined uint8 = 0
    39  	osClassMac             = 3
    40  	osClassUnix            = 4
    41  	osClassWindows         = 6
    42  )
    43  
    44  const (
    45  	tagPrimaryVolumeDescriptor           = 0x0001
    46  	tagAnchorVolumeDescriptorPointer     = 0x0002
    47  	tagVolumeDescriptorPointer           = 0x0003
    48  	tagImplementationUseVolumeDescriptor = 0x0004
    49  	tagPartitionDescriptor               = 0x0005
    50  	tagLogicalVolumeDescriptor           = 0x0006
    51  	tagUnallocatedSpaceDescriptor        = 0x0007
    52  	tagTerminatingDescriptor             = 0x0008
    53  	tagLogicalVolumeIntegrityDescriptor  = 0x0009
    54  	tagFileSetDescriptor                 = 0x0100
    55  	tagFileIdentifierDescriptor          = 0x0101
    56  	tagAllocationExtentDescriptor        = 0x0102
    57  	tagIndirectEntry                     = 0x0103
    58  	tagTerminalEntry                     = 0x0104
    59  	tagFileEntry                         = 0x0105
    60  	tagExtendedAttributeHeaderDescriptor = 0x0106
    61  	tagUnallocatedSpaceEntry             = 0x0107
    62  	tagSpaceBitmapDescriptor             = 0x0108
    63  	tagPartitionIntegrityEntry           = 0x0109
    64  	tagExtendedFileEntry                 = 0x010a
    65  )
    66  
    67  const (
    68  	// Shall mean that this is an Unallocated Space Entry
    69  	fileTypeUnallocated uint8 = 1
    70  	// Shall mean that this is a Partition Integrity Entry
    71  	fileTypePartitionIntegrity = 2
    72  	// Shall mean that this is an Indirect Entry
    73  	fileTypeIndirect = 3
    74  	// Shall mean that the file is a directory
    75  	fileTypeDirectory = 4
    76  	// Shall mean that the file shall be interpreted as a sequence of bytes, each of which may be randomly accessed
    77  	fileTypeBytes = 5
    78  	// Shall mean that the file is a block special device file as specified by ISO/IEC 9945-1
    79  	fileTypeBlockDevice = 6
    80  )
    81  
    82  type FileCharacteristics uint8
    83  
    84  const (
    85  	// FileCharacteristicHidden If set to ZERO, shall mean that the existence of the file shall be made known
    86  	// to the user; If set to ONE, shall mean that the existence of the file need not be made known to the user.
    87  	FileCharacteristicHidden FileCharacteristics = 1 << (0 + iota)
    88  
    89  	// FileCharacteristicDirectory If set to ZERO, shall mean that the file is not a directory (see 4/14.6.6);
    90  	// If set to ONE, shall mean that the file is a directory.
    91  	FileCharacteristicDirectory
    92  
    93  	// FileCharacteristicDeleted If set to ONE, shall mean this File Identifier Descriptor identifies a file that
    94  	// has been deleted; If set to ZERO, shall mean that this File Identifier Descriptor identifies a file that
    95  	// has not been deleted.
    96  	FileCharacteristicDeleted
    97  
    98  	// FileCharacteristicParent If set to ONE, shall mean that the ICB field of this descriptor identifies the
    99  	// ICB associated with the file in which is recorded the parent directory of the directory that this
   100  	// descriptor is recorded in;
   101  	// If set to ZERO, shall mean that the ICB field identifies the ICB associated with the file specified
   102  	// by this descriptor
   103  	FileCharacteristicParent
   104  
   105  	// FileCharacteristicMetadata If this File Identifier Descriptor is not in a stream directory,
   106  	// this bit shall be set to ZERO. If this File Identifier Descriptor is in a stream directory,
   107  	// a value of ZERO shall indicate that this stream contains user data. A value of ONE shall indicate that the
   108  	// stream contains implementation use data.
   109  	FileCharacteristicMetadata
   110  )
   111  
   112  func (c FileCharacteristics) HasFlags(mask FileCharacteristics) bool {
   113  	return c&mask == mask
   114  }
   115  
   116  type Extent struct {
   117  	Length   uint32
   118  	Location uint32
   119  }
   120  
   121  type ExtentLong struct {
   122  	Length   uint32
   123  	Location uint64
   124  }
   125  
   126  type EntityID struct {
   127  	Flags            uint8
   128  	Identifier       string
   129  	IdentifierSuffix string
   130  }
   131  
   132  type ImplementationUse struct {
   133  	Entity EntityID
   134  	// Additional vendor-specific data
   135  	Implementation []byte
   136  }
   137  
   138  type Charspec struct {
   139  	// CharacterSetType field shall have the value of 0 to indicate the CS0 coded character set.
   140  	CharacterSetType uint8
   141  	// CharacterSetInfo field shall contain the following byte values with the remainder of the field set to a value of 0:
   142  	// #4F, #53, #54, #41, #20, #43, #6F, #6D, #70, #72, #65, #73, #73,
   143  	// #65, #64, #20, #55, #6E, #69, #63, #6F, #64, #65
   144  	CharacterSetInfo []byte
   145  }
   146  
   147  func NewDescriptor(tagId uint16) Descriptor {
   148  	switch tagId {
   149  	case tagPrimaryVolumeDescriptor:
   150  		return &PrimaryVolumeDescriptor{}
   151  	case tagAnchorVolumeDescriptorPointer:
   152  		return &AnchorVolumeDescriptorPointer{}
   153  	case tagVolumeDescriptorPointer:
   154  		return &VolumeDescriptorPointer{}
   155  	case tagImplementationUseVolumeDescriptor:
   156  		return &ImplementationUseVolumeDescriptor{}
   157  	case tagPartitionDescriptor:
   158  		return &PartitionDescriptor{}
   159  	case tagLogicalVolumeDescriptor:
   160  		return &LogicalVolumeDescriptor{}
   161  	case tagUnallocatedSpaceDescriptor:
   162  		return &UnallocatedSpaceDescriptor{}
   163  	case tagTerminatingDescriptor:
   164  		return &TerminatingDescriptor{}
   165  	case tagLogicalVolumeIntegrityDescriptor:
   166  		return &LogicalVolumeIntegrityDescriptor{}
   167  	case tagFileSetDescriptor:
   168  		return &FileSetDescriptor{}
   169  	case tagFileIdentifierDescriptor:
   170  		return &FileIdentifierDescriptor{}
   171  	case tagFileEntry:
   172  		return &FileEntryDescriptor{}
   173  	default:
   174  		panic(fmt.Errorf("unexpected tag identifier %d", tagId))
   175  	}
   176  }
   177  
   178  type Descriptor interface {
   179  	GetIdentifier() int
   180  	GetTag() *DescriptorTag
   181  }
   182  
   183  type DescriptorList []Descriptor
   184  
   185  func (list DescriptorList) get(tagId int) Descriptor {
   186  	if desc := list.find(tagId); desc != nil {
   187  		return desc
   188  	} else {
   189  		panic(fmt.Sprintf("descriptor with ID %d does not exist in sequence", tagId))
   190  	}
   191  }
   192  
   193  func (list DescriptorList) find(tagId int) Descriptor {
   194  	for idx := 0; idx < len(list); idx++ {
   195  		if list[idx].GetIdentifier() == tagId {
   196  			return list[idx]
   197  		}
   198  	}
   199  	return nil
   200  }
   201  
   202  // DescriptorTag Certain descriptors specified in Part 3 have a 16 byte structure, or tag,
   203  // recorded at the start of the descriptor.
   204  type DescriptorTag struct {
   205  	TagIdentifier     uint16
   206  	DescriptorVersion uint16
   207  	// This field shall specify the sum modulo 256 of bytes 0-3 and 5-15 of the tag.
   208  	TagChecksum     uint8
   209  	TagSerialNumber uint16
   210  	// This field shall specify the CRC of the bytes of the descriptor starting at the first byte after the descriptor tag.
   211  	// The CRC shall be 16 bits long and be generated by the CRC-ITU-T polynomial
   212  	DescriptorCRC uint16
   213  	// The number of bytes shall be specified by the Descriptor CRC Length field.
   214  	DescriptorCRCLength uint16
   215  	TagLocation         uint32
   216  }
   217  
   218  // AnchorVolumeDescriptorPointer structure shall only be recorded at 2 of the following 3 locations on the media:
   219  // * Logical Sector 256.
   220  // * Logical Sector (N - 256).
   221  // * N
   222  type AnchorVolumeDescriptorPointer struct {
   223  	Tag                             DescriptorTag
   224  	MainVolumeDescriptorSequence    Extent
   225  	ReserveVolumeDescriptorSequence Extent
   226  }
   227  
   228  func (d *AnchorVolumeDescriptorPointer) GetIdentifier() int {
   229  	return tagAnchorVolumeDescriptorPointer
   230  }
   231  
   232  func (d *AnchorVolumeDescriptorPointer) GetTag() *DescriptorTag {
   233  	return &d.Tag
   234  }
   235  
   236  type VolumeDescriptorPointer struct {
   237  	Tag DescriptorTag
   238  	// This field shall specify the Volume Descriptor Sequence Number for this descriptor.
   239  	VolumeDescriptorSequenceNumber uint32
   240  	// This field shall specify the next extent in the Volume Descriptor Sequence. If the extent's length is 0, no such
   241  	//extent is specified.
   242  	NextVolumeDescriptorSequenceExtent Extent
   243  }
   244  
   245  func (d *VolumeDescriptorPointer) GetIdentifier() int {
   246  	return tagVolumeDescriptorPointer
   247  }
   248  
   249  func (d *VolumeDescriptorPointer) GetTag() *DescriptorTag {
   250  	return &d.Tag
   251  }
   252  
   253  // PrimaryVolumeDescriptor There shall be exactly one prevailing Primary Volume Descriptor recorded per volume.
   254  type PrimaryVolumeDescriptor struct {
   255  	Tag                                         DescriptorTag
   256  	VolumeDescriptorSequenceNumber              uint32
   257  	PrimaryVolumeDescriptorNumber               uint32
   258  	VolumeIdentifier                            string
   259  	VolumeSequenceNumber                        uint16
   260  	MaximumVolumeSequenceNumber                 uint16
   261  	InterchangeLevel                            uint16
   262  	MaximumInterchangeLevel                     uint16
   263  	CharacterSetList                            uint32
   264  	MaximumCharacterSetList                     uint32
   265  	VolumeSetIdentifier                         string
   266  	DescriptorCharacterSet                      Charspec
   267  	ExplanatoryCharacterSet                     Charspec
   268  	VolumeAbstract                              Extent
   269  	VolumeCopyrightNoticeExtent                 Extent
   270  	ApplicationIdentifier                       EntityID
   271  	RecordingDateTime                           time.Time
   272  	ImplementationIdentifier                    EntityID
   273  	ImplementationUse                           []byte
   274  	PredecessorVolumeDescriptorSequenceLocation uint32
   275  	Flags                                       uint16
   276  }
   277  
   278  func (d *PrimaryVolumeDescriptor) GetIdentifier() int {
   279  	return tagPrimaryVolumeDescriptor
   280  }
   281  
   282  func (d *PrimaryVolumeDescriptor) GetTag() *DescriptorTag {
   283  	return &d.Tag
   284  }
   285  
   286  // ImplementationUseVolumeDescriptor shall be recorded on every Volume of a Volume Set.
   287  // The Volume may also contain additional Implementation Use Volume Descriptors which are implementation specific.
   288  // The intended purpose of this descriptor is to aid in the identification of a Volume within a Volume Set
   289  // that belongs to a specific Logical Volume.
   290  type ImplementationUseVolumeDescriptor struct {
   291  	Tag                            DescriptorTag
   292  	VolumeDescriptorSequenceNumber uint32
   293  	ImplementationIdentifier       EntityID
   294  	ImplementationUse              LVInformation
   295  }
   296  
   297  func (d *ImplementationUseVolumeDescriptor) GetIdentifier() int {
   298  	return tagImplementationUseVolumeDescriptor
   299  }
   300  
   301  func (d *ImplementationUseVolumeDescriptor) GetTag() *DescriptorTag {
   302  	return &d.Tag
   303  }
   304  
   305  type LVInformation struct {
   306  	LVICharset              Charspec
   307  	LogicalVolumeIdentifier string
   308  	LVInfo1                 string
   309  	LVInfo2                 string
   310  	LVInfo3                 string
   311  	ImplementationID        EntityID
   312  	ImplementationUse       []byte
   313  }
   314  
   315  // PartitionDescriptor A Partition Access Type of Read-Only , Rewritable, Overwritable and WORM shall be supported.
   316  // There shall be exactly one prevailing Partition Descriptor recorded per volume, with one exception.
   317  // For Volume Sets that consist of single volume, the  volume may contain 2 Partitions with 2 prevailing
   318  // Partition Descriptors only if one has an access type of read only and the other has an access type of Rewritable or Overwritable.
   319  // The Logical Volume for this volume would consist of the contents of both partitions.
   320  type PartitionDescriptor struct {
   321  	Tag                            DescriptorTag
   322  	VolumeDescriptorSequenceNumber uint32
   323  	PartitionFlags                 uint16
   324  	PartitionNumber                uint16
   325  	PartitionContents              EntityID
   326  	PartitionContentsUse           []byte
   327  	AccessType                     uint32
   328  	PartitionStartingLocation      uint32
   329  	PartitionLength                uint32
   330  	ImplementationIdentifier       EntityID
   331  	ImplementationUse              []byte
   332  }
   333  
   334  func (d *PartitionDescriptor) GetIdentifier() int {
   335  	return tagPartitionDescriptor
   336  }
   337  
   338  func (d *PartitionDescriptor) GetTag() *DescriptorTag {
   339  	return &d.Tag
   340  }
   341  
   342  type LogicalVolumeDescriptor struct {
   343  	Tag                            DescriptorTag
   344  	VolumeDescriptorSequenceNumber uint32
   345  	DescriptorCharacterSet         Charspec
   346  	LogicalVolumeIdentifier        string
   347  	LogicalBlockSize               uint32
   348  	DomainIdentifier               EntityID
   349  	LogicalVolumeContentsUse       []byte
   350  	MapTableLength                 uint32
   351  	NumberOfPartitionMaps          uint32
   352  	ImplementationIdentifier       EntityID
   353  	ImplementationUse              []byte
   354  	IntegritySequenceExtent        Extent
   355  	PartitionMaps                  []PartitionMap
   356  }
   357  
   358  func (d *LogicalVolumeDescriptor) GetIdentifier() int {
   359  	return tagLogicalVolumeDescriptor
   360  }
   361  
   362  func (d *LogicalVolumeDescriptor) GetTag() *DescriptorTag {
   363  	return &d.Tag
   364  }
   365  
   366  type LogicalVolumeHeaderDescriptor struct {
   367  	UniqueID uint64
   368  }
   369  
   370  type PartitionMap struct {
   371  	PartitionMapType     uint8
   372  	PartitionMapLength   uint8
   373  	VolumeSequenceNumber uint16
   374  	PartitionNumber      uint16
   375  }
   376  
   377  // UnallocatedSpaceDescriptor shall be recorded, even if there is no free volume space.
   378  // The first 32768 bytes of the Volume space shall not be used for the recording of ECMA 167 structures.
   379  // This area shall not be referenced by the Unallocated Space Descriptor or any other ECMA 167 descriptor.
   380  type UnallocatedSpaceDescriptor struct {
   381  	Tag                            DescriptorTag
   382  	VolumeDescriptorSequenceNumber uint32
   383  	NumberOfAllocationDescriptors  uint32
   384  	AllocationDescriptors          []Extent
   385  }
   386  
   387  func (d *UnallocatedSpaceDescriptor) GetIdentifier() int {
   388  	return tagUnallocatedSpaceDescriptor
   389  }
   390  
   391  func (d *UnallocatedSpaceDescriptor) GetTag() *DescriptorTag {
   392  	return &d.Tag
   393  }
   394  
   395  // TerminatingDescriptor may be recorded to terminate a Volume Descriptor Sequence
   396  type TerminatingDescriptor struct {
   397  	Tag DescriptorTag
   398  }
   399  
   400  func (d *TerminatingDescriptor) GetIdentifier() int {
   401  	return tagTerminatingDescriptor
   402  }
   403  
   404  func (d *TerminatingDescriptor) GetTag() *DescriptorTag {
   405  	return &d.Tag
   406  }
   407  
   408  type LogicalVolumeIntegrityDescriptor struct {
   409  	Tag                       DescriptorTag
   410  	RecordingDateTime         time.Time
   411  	IntegrityType             uint32
   412  	NextIntegrityExtent       Extent
   413  	LogicalVolumeContentsUse  LogicalVolumeHeaderDescriptor
   414  	NumberOfPartitions        uint32
   415  	LengthOfImplementationUse uint32
   416  	FreeSpaceTable            []uint32
   417  	SizeTable                 []uint32
   418  	ImplementationUse         ImplementationUse
   419  }
   420  
   421  func (d *LogicalVolumeIntegrityDescriptor) GetIdentifier() int {
   422  	return tagLogicalVolumeIntegrityDescriptor
   423  }
   424  
   425  func (d *LogicalVolumeIntegrityDescriptor) GetTag() *DescriptorTag {
   426  	return &d.Tag
   427  }
   428  
   429  // FileSetDescriptor Only one File Set Descriptor shall be recorded. On WORM media, multiple File Sets may be recorded.
   430  type FileSetDescriptor struct {
   431  	Tag                                 DescriptorTag
   432  	RecordingDateTime                   time.Time
   433  	InterchangeLevel                    uint16
   434  	MaximumInterchangeLevel             uint16
   435  	CharacterSetList                    uint32
   436  	MaximumCharacterSetList             uint32
   437  	FileSetNumber                       uint32
   438  	FileSetDescriptorNumber             uint32
   439  	LogicalVolumeIdentifierCharacterSet Charspec
   440  	LogicalVolumeIdentifier             string
   441  	FileSetCharacterSet                 Charspec
   442  	FileSetIdentifier                   string
   443  	CopyrightFileIdentifier             string
   444  	AbstractFileIdentifier              string
   445  	RootDirectoryICB                    ExtentLong
   446  	DomainIdentifier                    EntityID
   447  	NextExtent                          ExtentLong
   448  	SystemStreamDirectoryICB            ExtentLong
   449  }
   450  
   451  func (d *FileSetDescriptor) GetIdentifier() int {
   452  	return tagFileSetDescriptor
   453  }
   454  
   455  func (d *FileSetDescriptor) GetTag() *DescriptorTag {
   456  	return &d.Tag
   457  }
   458  
   459  type FileEntryDescriptor struct {
   460  	Tag                           DescriptorTag
   461  	ICBTag                        ICBTag
   462  	Uid                           uint32
   463  	Gid                           uint32
   464  	Permissions                   FileMode
   465  	FileLinkCount                 uint16
   466  	RecordFormat                  uint8
   467  	RecordDisplayAttributes       uint8
   468  	RecordLength                  uint32
   469  	InformationLength             uint64
   470  	LogicalBlocksRecorded         uint64
   471  	AccessTime                    time.Time
   472  	ModificationTime              time.Time
   473  	AttributeTime                 time.Time
   474  	Checkpoint                    uint32
   475  	ExtendedAttributeICB          ExtentLong
   476  	ImplementationIdentifier      EntityID
   477  	UniqueID                      uint64
   478  	LengthOfExtendedAttributes    uint32
   479  	LengthOfAllocationDescriptors uint32
   480  	ExtendedAttributes            []byte
   481  	AllocationDescriptors         []Extent
   482  }
   483  
   484  func (d *FileEntryDescriptor) GetIdentifier() int {
   485  	return tagFileEntry
   486  }
   487  
   488  func (d *FileEntryDescriptor) GetTag() *DescriptorTag {
   489  	return &d.Tag
   490  }
   491  
   492  type ICBTag struct {
   493  	PriorRecordedNumberOfDirectEntries uint32
   494  	StrategyType                       uint16
   495  	StrategyParameter                  uint16
   496  	MaximumNumberOfEntries             uint16
   497  	FileType                           uint8
   498  	ParentICBLocation                  LogicalBlockAddress
   499  	Flags                              uint16
   500  }
   501  
   502  type LogicalBlockAddress struct {
   503  	LogicalBlockNumber       uint32
   504  	PartitionReferenceNumber uint16
   505  }
   506  
   507  // FileIdentifierDescriptor ECMA 167 4/14.4
   508  type FileIdentifierDescriptor struct {
   509  	Tag                       DescriptorTag
   510  	FileVersionNumber         uint16
   511  	FileCharacteristics       FileCharacteristics
   512  	LengthOfFileIdentifier    uint8
   513  	ICB                       ExtentLong
   514  	LengthOfImplementationUse uint16
   515  	ImplementationUse         []byte
   516  	FileIdentifier            string
   517  }
   518  
   519  func (d *FileIdentifierDescriptor) GetIdentifier() int {
   520  	return tagFileIdentifierDescriptor
   521  }
   522  
   523  func (d *FileIdentifierDescriptor) GetTag() *DescriptorTag {
   524  	return &d.Tag
   525  }
   526  
   527  func (d *FileIdentifierDescriptor) calculateSize() int {
   528  	fileIdentifierLen := len(encodeDCharacters(d.FileIdentifier))
   529  	size := 38 + int(d.LengthOfImplementationUse) + fileIdentifierLen
   530  	paddingLen := 4*((size+3)/4) - size
   531  	if paddingLen > 0 {
   532  		size += paddingLen
   533  	}
   534  	return size
   535  }
   536  
   537  type ExtendedAttributeHeaderDescriptor struct {
   538  	Tag                              DescriptorTag
   539  	ImplementationAttributesLocation uint32
   540  	ApplicationAttributesLocation    uint32
   541  }
   542  
   543  func (d *ExtendedAttributeHeaderDescriptor) GetIdentifier() int {
   544  	return tagExtendedAttributeHeaderDescriptor
   545  }
   546  
   547  func (d *ExtendedAttributeHeaderDescriptor) GetTag() *DescriptorTag {
   548  	return &d.Tag
   549  }
   550  
   551  type ImplementationUseExtendedAttribute struct {
   552  	AttributeType            uint32
   553  	AttributeSubtype         uint8
   554  	AttributeLength          uint32
   555  	ImplementationUseLength  uint32
   556  	ImplementationIdentifier EntityID
   557  	ImplementationData       []byte
   558  }
   559  
   560  func encodeDCharacters(value string) []byte {
   561  	if len(value) == 0 {
   562  		return []byte{}
   563  	}
   564  	var encodingType int
   565  	var buf []byte
   566  	var err error
   567  	if utf8string.NewString(value).IsASCII() {
   568  		encodingType = dcharEncodingType8
   569  		win1252Enc := charmap.Windows1252.NewEncoder()
   570  		if buf, _, err = transform.Bytes(win1252Enc, []byte(value)); err != nil {
   571  			panic(err)
   572  		}
   573  	} else {
   574  		encodingType = dcharEncodingType16
   575  		utf16Enc := unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM).NewEncoder()
   576  		if buf, _, err = transform.Bytes(utf16Enc, []byte(value)); err != nil {
   577  			panic(err)
   578  		}
   579  	}
   580  
   581  	res := make([]byte, len(buf)+1)
   582  	res[0] = byte(encodingType)
   583  	copy(res[1:], buf)
   584  	return res
   585  }