Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
## Udf filesystem golang library

- Non-optimized
- Some functioal is broken
- Some features may be broken
- `recovery()` style error handling interface
- Work only with certain iso's
- Tested only with certain ISOs (e.g. Windows ISOs)

It's all because I has reached requried functional for me.
It's all because I has reached required functionality for me.

## Example

```go
package main

import (
"fmt"
"os"
"github.com/mogaika/udf"
"github.com/Xmister/udf"
)

func main() {
r, _ := os.Open("example.iso")
u := udf.NewUdfFromReader(r)
rdr, _ := os.Open("example.iso")
u, _ := udf.NewUdfFromReader(r)
for _, f := range u.ReadDir(nil) {
fmt.Printf("%s %-10d %-20s %v\n", f.Mode().String(), f.Size(), f.Name(), f.ModTime())
}
}

```
Output:
```
Expand All @@ -33,5 +36,8 @@ Output:
-r-xr-xr-x 15653 dbcman.irx 2005-10-18 00:00:00 +0000 UTC
```

See [isoinfo.go](isoinfo/isoinfo.go) for complete example.

## Specification

* http://www.osta.org/specs/pdf/udf260.pdf
167 changes: 154 additions & 13 deletions descr.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ const (
DESCRIPTOR_INDIRECT_ENTRY = 0x103
DESCRIPTOR_TERMINAL_ENTRY = 0x104
DESCRIPTOR_FILE_ENTRY = 0x105
UDF_EXTENT_FLAG_MASK = 0xC0000000
EXT_NOT_RECORDED_ALLOCATED = 0x40000000
EXT_NOT_RECORDED_NOT_ALLOCATED = 0x80000000
)

type Descriptor struct {
Expand All @@ -38,10 +41,19 @@ func (d *Descriptor) Data() []byte {
return buf
}

func (d *Descriptor) Checksum() (checksum uint8) {
for i := 0; i < 16; i++ {
if i != 4 {
checksum += d.data[i]
}
}
return
}

func (d *Descriptor) FromBytes(b []byte) *Descriptor {
d.TagIdentifier = rl_u16(b[0:])
d.DescriptorVersion = rl_u16(b[2:])
d.TagChecksum = r_u8(b[3:])
d.TagChecksum = r_u8(b[4:])
d.TagSerialNumber = rl_u16(b[6:])
d.DescriptorCRC = rl_u16(b[8:])
d.DescriptorCRCLength = rl_u16(b[10:])
Expand Down Expand Up @@ -170,13 +182,24 @@ type PartitionMap struct {
PartitionMapLength uint8
VolumeSequenceNumber uint16
PartitionNumber uint16
PartitionStart uint32
}

func (pm *PartitionMap) FromBytes(b []byte) *PartitionMap {
pm.PartitionMapType = rb_u8(b[0:])
pm.PartitionMapLength = rb_u8(b[1:])
pm.VolumeSequenceNumber = rb_u16(b[2:])
pm.PartitionNumber = rb_u16(b[4:])
offset := 0
switch pm.PartitionMapType {
case 1:
offset = 2
case 2:
offset = 36
}
pm.VolumeSequenceNumber = rb_u16(b[offset:])
// XXX - For whatever reason, the Microsoft ISOs have a little endian partition
// number here???
pm.PartitionNumber = rl_u16(b[offset+2:])
pm.PartitionStart = uint32(pm.VolumeSequenceNumber)
return pm
}

Expand Down Expand Up @@ -208,7 +231,7 @@ func (lvd *LogicalVolumeDescriptor) FromBytes(b []byte) *LogicalVolumeDescriptor
lvd.ImplementationUse = b[304:432]
lvd.IntegritySequenceExtent = NewExtent(b[432:])
lvd.PartitionMaps = make([]PartitionMap, lvd.NumberOfPartitionMaps)
for i := range lvd.PartitionMaps {
for i := uint32(0); i < lvd.NumberOfPartitionMaps; i++ {
lvd.PartitionMaps[i].FromBytes(b[440+i*6:])
}
return lvd
Expand Down Expand Up @@ -304,6 +327,15 @@ func (d *Descriptor) FileIdentifierDescriptor() *FileIdentifierDescriptor {
return NewFileIdentifierDescriptor(d.data)
}

type FileEntryInterface interface {
GetAllocationDescriptors() []ExtentInterface
GetPermissions() uint32
GetInformationLength() uint64
GetModificationTime() time.Time
GetICBTag() *ICBTag
GetPartition() uint16
}

type FileEntry struct {
Descriptor Descriptor
ICBTag *ICBTag
Expand All @@ -326,7 +358,16 @@ type FileEntry struct {
LengthOfExtendedAttributes uint32
LengthOfAllocationDescriptors uint32
ExtendedAttributes []byte
AllocationDescriptors []Extent
AllocationDescriptors []byte
// Manual field
Partition uint16
}

type ExtendedFileEntry struct {
FileEntry
CreationTime time.Time
ObjectSize uint64
StreamDirectoryIcb ExtentLong
}

func (fe *FileEntry) FromBytes(b []byte) *FileEntry {
Expand All @@ -351,18 +392,118 @@ func (fe *FileEntry) FromBytes(b []byte) *FileEntry {
fe.LengthOfExtendedAttributes = rl_u32(b[168:])
fe.LengthOfAllocationDescriptors = rl_u32(b[172:])
allocDescStart := 176 + fe.LengthOfExtendedAttributes
fe.ExtendedAttributes = b[176:allocDescStart]
fe.AllocationDescriptors = make([]Extent, fe.LengthOfAllocationDescriptors/8)
for i := range fe.AllocationDescriptors {
fe.AllocationDescriptors[i] = NewExtent(b[allocDescStart+uint32(i)*8:])
if allocDescStart > uint32(len(b)) {
return nil
}
fe.ExtendedAttributes = b[176:allocDescStart]
fe.AllocationDescriptors = b[allocDescStart : allocDescStart+fe.LengthOfAllocationDescriptors]
return fe
}

func NewFileEntry(b []byte) *FileEntry {
return new(FileEntry).FromBytes(b)
func (fe *FileEntry) GetPartition() uint16 {
if fe.ICBTag.AllocationType == LongDescriptors {
return fe.GetAllocationDescriptors()[0].GetPartition()
}
return fe.Partition
}

func GetAllocationDescriptor(t AllocationType, b []byte) ExtentInterface {
switch t {
case ShortDescriptors:
return NewExtent(b)
case LongDescriptors:
return NewExtentLong(b)
case ExtendedDescriptors:
return NewExtentExtended(b)
}
return nil
}

func GetAllocationDescriptors(t AllocationType, b []byte, len uint32) (list []ExtentInterface) {
var descLen uint32
switch t {
case ShortDescriptors:
descLen = 8
case LongDescriptors:
descLen = 16
case ExtendedDescriptors:
descLen = 24
default:
return
}
list = make([]ExtentInterface, len/descLen)
for i := range list {
list[i] = GetAllocationDescriptor(t, b[uint32(i)*descLen:])
}

return
}

func (fe *FileEntry) GetAllocationDescriptors() (list []ExtentInterface) {
return GetAllocationDescriptors(fe.ICBTag.AllocationType, fe.AllocationDescriptors, fe.LengthOfAllocationDescriptors)
}

func (fe *FileEntry) GetPermissions() uint32 {
return fe.Permissions
}

func (fe *FileEntry) GetInformationLength() uint64 {
return fe.InformationLength
}

func (fe *FileEntry) GetModificationTime() time.Time {
return fe.ModificationTime
}

func (fe *FileEntry) GetICBTag() *ICBTag {
return fe.ICBTag
}

func NewFileEntry(partition uint16, b []byte) (fe FileEntryInterface) {
if e := new(FileEntry).FromBytes(b); e == nil {
ee := new(ExtendedFileEntry).FromBytes(b)
ee.Partition = partition
fe = ee
} else {
e.Partition = partition
fe = e
}
return
}

func (fe *ExtendedFileEntry) FromBytes(b []byte) *ExtendedFileEntry {
fe.Descriptor.FromBytes(b)
fe.ICBTag = NewICBTag(b[16:])
fe.Uid = rl_u32(b[36:])
fe.Gid = rl_u32(b[40:])
fe.Permissions = rl_u32(b[44:])
fe.FileLinkCount = rl_u16(b[48:])
fe.RecordFormat = r_u8(b[50:])
fe.RecordDisplayAttributes = r_u8(b[51:])
fe.RecordLength = rl_u32(b[52:])
fe.InformationLength = rl_u64(b[56:])
fe.ObjectSize = rl_u64(b[64:])
fe.LogicalBlocksRecorded = rl_u64(b[72:])
fe.AccessTime = r_timestamp(b[80:])
fe.ModificationTime = r_timestamp(b[92:])
fe.CreationTime = r_timestamp(b[104:])
fe.AttributeTime = r_timestamp(b[116:])
fe.Checkpoint = rl_u32(b[128:])
fe.ExtendedAttributeICB = NewExtentLong(b[136:])
fe.StreamDirectoryIcb = NewExtentLong(b[152:])
fe.ImplementationIdentifier = NewEntityID(b[168:])
fe.UniqueId = rl_u64(b[200:])
fe.LengthOfExtendedAttributes = rl_u32(b[208:])
fe.LengthOfAllocationDescriptors = rl_u32(b[212:])
allocDescStart := 216 + fe.LengthOfExtendedAttributes
if allocDescStart > uint32(len(b)) {
return nil
}
fe.ExtendedAttributes = b[216:allocDescStart]
fe.AllocationDescriptors = b[allocDescStart : allocDescStart+fe.LengthOfAllocationDescriptors]
return fe
}

func (d *Descriptor) FileEntry() *FileEntry {
return NewFileEntry(d.data)
func (d *Descriptor) FileEntry() FileEntryInterface {
return NewFileEntry(0, d.data)
}
Loading