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 }