From a4d0372ae6e5ba506c3d15338643e21441b3ade8 Mon Sep 17 00:00:00 2001 From: Xmister Date: Wed, 27 Feb 2019 11:38:33 +0100 Subject: [PATCH 01/17] Preliminary support for BD50. Some other fixes --- descr.go | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- extent.go | 15 ++++++++-- file.go | 19 ++++++------ icb.go | 2 +- udf.go | 29 ++++++++++++------- 5 files changed, 124 insertions(+), 28 deletions(-) diff --git a/descr.go b/descr.go index daf829b..4cffafa 100644 --- a/descr.go +++ b/descr.go @@ -41,7 +41,7 @@ func (d *Descriptor) Data() []byte { 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:]) @@ -304,6 +304,14 @@ func (d *Descriptor) FileIdentifierDescriptor() *FileIdentifierDescriptor { return NewFileIdentifierDescriptor(d.data) } +type FileEntryInterface interface { + GetAllocationDescriptors() []Extent + GetPermissions() uint32 + GetInformationLength() uint64 + GetModificationTime() time.Time + GetICBTag() *ICBTag +} + type FileEntry struct { Descriptor Descriptor ICBTag *ICBTag @@ -329,6 +337,13 @@ type FileEntry struct { AllocationDescriptors []Extent } +type ExtendedFileEntry struct { + FileEntry + CreationTime time.Time + ObjectSize uint64 + StreamDirectoryIcb ExtentLong +} + func (fe *FileEntry) FromBytes(b []byte) *FileEntry { fe.Descriptor.FromBytes(b) fe.ICBTag = NewICBTag(b[16:]) @@ -351,6 +366,9 @@ func (fe *FileEntry) FromBytes(b []byte) *FileEntry { fe.LengthOfExtendedAttributes = rl_u32(b[168:]) fe.LengthOfAllocationDescriptors = rl_u32(b[172:]) allocDescStart := 176 + fe.LengthOfExtendedAttributes + if allocDescStart > uint32(len(b)) { + return nil + } fe.ExtendedAttributes = b[176:allocDescStart] fe.AllocationDescriptors = make([]Extent, fe.LengthOfAllocationDescriptors/8) for i := range fe.AllocationDescriptors { @@ -359,10 +377,71 @@ func (fe *FileEntry) FromBytes(b []byte) *FileEntry { return fe } -func NewFileEntry(b []byte) *FileEntry { - return new(FileEntry).FromBytes(b) +func (fe *FileEntry) GetAllocationDescriptors() []Extent { + return fe.AllocationDescriptors +} + +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(b []byte) (fe FileEntryInterface) { + if e := new(FileEntry).FromBytes(b); e == nil { + fe = new(ExtendedFileEntry).FromBytes(b) + } else { + 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 = make([]Extent, fe.LengthOfAllocationDescriptors/8) + for i := range fe.AllocationDescriptors { + fe.AllocationDescriptors[i] = NewExtent(b[allocDescStart+uint32(i)*8:]) + } + return fe } -func (d *Descriptor) FileEntry() *FileEntry { +func (d *Descriptor) FileEntry() FileEntryInterface { return NewFileEntry(d.data) } diff --git a/extent.go b/extent.go index 2551bbb..240e0b5 100644 --- a/extent.go +++ b/extent.go @@ -26,12 +26,23 @@ func NewExtentSmall(b []byte) ExtentSmall { type ExtentLong struct { Length uint32 - Location uint64 + Location LbAddr } func NewExtentLong(b []byte) ExtentLong { return ExtentLong{ Length: rl_u32(b[0:]), - Location: rl_u48(b[4:]), + Location: new(LbAddr).FromBytes(b[4:]), } } + +type LbAddr struct { + LogicalBlockNumber uint32 + PartitionReferenceNumber uint16 +} + +func (l *LbAddr) FromBytes(data []byte) LbAddr { + l.LogicalBlockNumber = rl_u32(data[0:]) + l.PartitionReferenceNumber = rl_u16(data[4:]) + return *l +} diff --git a/file.go b/file.go index 90367db..69ed028 100644 --- a/file.go +++ b/file.go @@ -9,7 +9,7 @@ import ( type File struct { Udf *Udf Fid *FileIdentifierDescriptor - fe *FileEntry + fe FileEntryInterface fileEntryPosition uint64 } @@ -18,13 +18,13 @@ func (f *File) GetFileEntryPosition() int64 { } func (f *File) GetFileOffset() int64 { - return SECTOR_SIZE * (int64(f.FileEntry().AllocationDescriptors[0].Location) + int64(f.Udf.PartitionStart())) + return SECTOR_SIZE * (int64(f.FileEntry().GetAllocationDescriptors()[0].Location) + int64(f.Udf.PartitionStart(0))) } -func (f *File) FileEntry() *FileEntry { +func (f *File) FileEntry() FileEntryInterface { if f.fe == nil { - f.fileEntryPosition = f.Fid.ICB.Location - f.fe = NewFileEntry(f.Udf.ReadSector(f.Udf.PartitionStart() + f.fileEntryPosition)) + f.fileEntryPosition = uint64(f.Fid.ICB.Location.LogicalBlockNumber) + f.fe = NewFileEntry(f.Udf.ReadSector(f.Udf.PartitionStart(0) + f.fileEntryPosition)) } return f.fe } @@ -40,7 +40,7 @@ func (f *File) Name() string { func (f *File) Mode() os.FileMode { var mode os.FileMode - perms := os.FileMode(f.FileEntry().Permissions) + perms := os.FileMode(f.FileEntry().GetPermissions()) mode |= ((perms >> 0) & 7) << 0 mode |= ((perms >> 5) & 7) << 3 mode |= ((perms >> 10) & 7) << 6 @@ -53,16 +53,15 @@ func (f *File) Mode() os.FileMode { } func (f *File) Size() int64 { - return int64(f.FileEntry().InformationLength) + return int64(f.FileEntry().GetInformationLength()) } func (f *File) ModTime() time.Time { - return f.FileEntry().ModificationTime + return f.FileEntry().GetModificationTime() } func (f *File) IsDir() bool { - // TODO :Fix! This field always 0 :( - return f.FileEntry().ICBTag.FileType == 4 + return f.FileEntry().GetICBTag().FileType == 4 } func (f *File) Sys() interface{} { diff --git a/icb.go b/icb.go index 0a21d81..bd7d783 100644 --- a/icb.go +++ b/icb.go @@ -15,7 +15,7 @@ func (itag *ICBTag) FromBytes(b []byte) *ICBTag { itag.StrategyType = rl_u16(b[4:]) itag.StrategyParameter = rl_u16(b[4:]) itag.MaximumNumberOfEntries = rl_u16(b[8:]) - itag.FileType = r_u8(b[1:]) + itag.FileType = r_u8(b[11:]) itag.ParentICBLocation = rl_u48(b[12:]) itag.Flags = rl_u16(b[18:]) return itag diff --git a/udf.go b/udf.go index 058862a..7915399 100644 --- a/udf.go +++ b/udf.go @@ -10,17 +10,21 @@ type Udf struct { r io.ReaderAt isInited bool pvd *PrimaryVolumeDescriptor - pd *PartitionDescriptor + pd map[uint16]*PartitionDescriptor lvd *LogicalVolumeDescriptor fsd *FileSetDescriptor - root_fe *FileEntry + root_fe FileEntryInterface } -func (udf *Udf) PartitionStart() uint64 { +func (udf *Udf) PartitionStart(partition uint16) uint64 { if udf.pd == nil { panic(udf) } else { - return uint64(udf.pd.PartitionStartingLocation) + metaFile := NewFileEntry(udf.ReadSector(uint64(udf.pd[partition].PartitionStartingLocation))) + if metaFile != nil && len(metaFile.GetAllocationDescriptors()) > 0 { + return uint64(metaFile.GetAllocationDescriptors()[0].Location + udf.pd[partition].PartitionStartingLocation) + } + return uint64(udf.pd[partition].PartitionStartingLocation) } } @@ -63,30 +67,32 @@ func (udf *Udf) init() { case DESCRIPTOR_PRIMARY_VOLUME: udf.pvd = desc.PrimaryVolumeDescriptor() case DESCRIPTOR_PARTITION: - udf.pd = desc.PartitionDescriptor() + pd := desc.PartitionDescriptor() + udf.pd[pd.PartitionNumber] = pd case DESCRIPTOR_LOGICAL_VOLUME: udf.lvd = desc.LogicalVolumeDescriptor() } } - partitionStart := udf.PartitionStart() + partitionStart := udf.PartitionStart(0) - udf.fsd = NewFileSetDescriptor(udf.ReadSector(partitionStart + udf.lvd.LogicalVolumeContentsUse.Location)) - udf.root_fe = NewFileEntry(udf.ReadSector(partitionStart + udf.fsd.RootDirectoryICB.Location)) + udf.fsd = NewFileSetDescriptor(udf.ReadSector(partitionStart + uint64(udf.lvd.LogicalVolumeContentsUse.Location.LogicalBlockNumber))) + udf.root_fe = NewFileEntry(udf.ReadSector(partitionStart + uint64(udf.fsd.RootDirectoryICB.Location.LogicalBlockNumber))) udf.isInited = true } -func (udf *Udf) ReadDir(fe *FileEntry) []File { +func (udf *Udf) ReadDir(fe FileEntryInterface) []File { udf.init() if fe == nil { fe = udf.root_fe } - ps := udf.PartitionStart() + ps := udf.PartitionStart(0) + - adPos := fe.AllocationDescriptors[0] + adPos := fe.GetAllocationDescriptors()[0] fdLen := uint64(adPos.Length) fdBuf := udf.ReadSectors(ps+uint64(adPos.Location), (fdLen+SECTOR_SIZE-1)/SECTOR_SIZE) @@ -112,6 +118,7 @@ func NewUdfFromReader(r io.ReaderAt) *Udf { udf := &Udf{ r: r, isInited: false, + pd: make(map[uint16]*PartitionDescriptor), } return udf From 1c10c1e54b272e87c52f8dda1e1f9a62fa2b0656 Mon Sep 17 00:00:00 2001 From: Xmister Date: Thu, 28 Feb 2019 13:10:10 +0100 Subject: [PATCH 02/17] Fixes --- descr.go | 30 ++++++++++++++++++------------ extent.go | 29 +++++++++++++++++++++++++++++ file.go | 14 +++++++++++--- icb.go | 11 +++++++++++ udf.go | 19 +++++++++++-------- 5 files changed, 80 insertions(+), 23 deletions(-) diff --git a/descr.go b/descr.go index 4cffafa..4591173 100644 --- a/descr.go +++ b/descr.go @@ -305,7 +305,7 @@ func (d *Descriptor) FileIdentifierDescriptor() *FileIdentifierDescriptor { } type FileEntryInterface interface { - GetAllocationDescriptors() []Extent + GetAllocationDescriptors() []ExtentInterface GetPermissions() uint32 GetInformationLength() uint64 GetModificationTime() time.Time @@ -334,7 +334,7 @@ type FileEntry struct { LengthOfExtendedAttributes uint32 LengthOfAllocationDescriptors uint32 ExtendedAttributes []byte - AllocationDescriptors []Extent + AllocationDescriptors []byte } type ExtendedFileEntry struct { @@ -370,15 +370,24 @@ func (fe *FileEntry) FromBytes(b []byte) *FileEntry { return nil } 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:]) - } + fe.AllocationDescriptors = b[allocDescStart:allocDescStart+fe.LengthOfAllocationDescriptors] return fe } -func (fe *FileEntry) GetAllocationDescriptors() []Extent { - return fe.AllocationDescriptors +func (fe *FileEntry) GetAllocationDescriptors() (list []ExtentInterface) { + switch fe.ICBTag.AllocationType { + case ShortDescriptors: + list = make([]ExtentInterface, fe.LengthOfAllocationDescriptors/8) + for i := range list { + list[i] = NewExtent(fe.AllocationDescriptors[uint32(i)*8:]) + } + case LongDescriptors: + list = make([]ExtentInterface, fe.LengthOfAllocationDescriptors/16) + for i := range list { + list[i] = NewExtentLong(fe.AllocationDescriptors[uint32(i)*16:]) + } + } + return } func (fe *FileEntry) GetPermissions() uint32 { @@ -435,10 +444,7 @@ func (fe *ExtendedFileEntry) FromBytes(b []byte) *ExtendedFileEntry { return nil } fe.ExtendedAttributes = b[216:allocDescStart] - fe.AllocationDescriptors = make([]Extent, fe.LengthOfAllocationDescriptors/8) - for i := range fe.AllocationDescriptors { - fe.AllocationDescriptors[i] = NewExtent(b[allocDescStart+uint32(i)*8:]) - } + fe.AllocationDescriptors = b[allocDescStart:allocDescStart+fe.LengthOfAllocationDescriptors] return fe } diff --git a/extent.go b/extent.go index 240e0b5..f8d62a6 100644 --- a/extent.go +++ b/extent.go @@ -1,10 +1,23 @@ package udf +type ExtentInterface interface { + GetLocation() uint64 + GetLength() uint32 +} + type Extent struct { Length uint32 Location uint32 } +func (e Extent) GetLocation() uint64 { + return uint64(e.Location) +} + +func (e Extent) GetLength() uint32 { + return e.Length +} + func NewExtent(b []byte) Extent { return Extent{ Length: rl_u32(b[0:]), @@ -17,6 +30,14 @@ type ExtentSmall struct { Location uint64 } +func (e ExtentSmall) GetLocation() uint64 { + return uint64(e.Location) +} + +func (e ExtentSmall) GetLength() uint32 { + return uint32(e.Length) +} + func NewExtentSmall(b []byte) ExtentSmall { return ExtentSmall{ Length: rl_u16(b[0:]), @@ -29,6 +50,14 @@ type ExtentLong struct { Location LbAddr } +func (e ExtentLong) GetLocation() uint64 { + return uint64(e.Location.LogicalBlockNumber) +} + +func (e ExtentLong) GetLength() uint32 { + return e.Length +} + func NewExtentLong(b []byte) ExtentLong { return ExtentLong{ Length: rl_u32(b[0:]), diff --git a/file.go b/file.go index 69ed028..5a66b7f 100644 --- a/file.go +++ b/file.go @@ -17,14 +17,22 @@ func (f *File) GetFileEntryPosition() int64 { return int64(f.fileEntryPosition) } -func (f *File) GetFileOffset() int64 { - return SECTOR_SIZE * (int64(f.FileEntry().GetAllocationDescriptors()[0].Location) + int64(f.Udf.PartitionStart(0))) +func (f *File) GetFileOffset() (res int64) { + physical, meta := f.Udf.PartitionStart(0) + res = int64(f.FileEntry().GetAllocationDescriptors()[0].GetLocation()) + if f.fe.GetICBTag().AllocationType == LongDescriptors { + res += int64(physical) + } else if f.fe.GetICBTag().AllocationType == ShortDescriptors { + res += int64(meta) + } + return SECTOR_SIZE * res } func (f *File) FileEntry() FileEntryInterface { if f.fe == nil { f.fileEntryPosition = uint64(f.Fid.ICB.Location.LogicalBlockNumber) - f.fe = NewFileEntry(f.Udf.ReadSector(f.Udf.PartitionStart(0) + f.fileEntryPosition)) + _, meta := f.Udf.PartitionStart(0) + f.fe = NewFileEntry(f.Udf.ReadSector(meta + f.fileEntryPosition)) } return f.fe } diff --git a/icb.go b/icb.go index bd7d783..d692cd0 100644 --- a/icb.go +++ b/icb.go @@ -1,5 +1,14 @@ package udf +type AllocationType int + +const ( + ShortDescriptors AllocationType = iota + LongDescriptors + ExtendedDescriptors + Embedded +) + type ICBTag struct { PriorRecordedNumberOfDirectEntries uint32 StrategyType uint16 @@ -8,6 +17,7 @@ type ICBTag struct { FileType uint8 ParentICBLocation uint64 Flags uint16 + AllocationType AllocationType } func (itag *ICBTag) FromBytes(b []byte) *ICBTag { @@ -18,6 +28,7 @@ func (itag *ICBTag) FromBytes(b []byte) *ICBTag { itag.FileType = r_u8(b[11:]) itag.ParentICBLocation = rl_u48(b[12:]) itag.Flags = rl_u16(b[18:]) + itag.AllocationType = (AllocationType)(itag.Flags & 0x3) return itag } diff --git a/udf.go b/udf.go index 7915399..05151e4 100644 --- a/udf.go +++ b/udf.go @@ -16,16 +16,19 @@ type Udf struct { root_fe FileEntryInterface } -func (udf *Udf) PartitionStart(partition uint16) uint64 { +func (udf *Udf) PartitionStart(partition uint16) (physical uint64, meta uint64) { if udf.pd == nil { panic(udf) } else { + physical = uint64(udf.pd[partition].PartitionStartingLocation) metaFile := NewFileEntry(udf.ReadSector(uint64(udf.pd[partition].PartitionStartingLocation))) if metaFile != nil && len(metaFile.GetAllocationDescriptors()) > 0 { - return uint64(metaFile.GetAllocationDescriptors()[0].Location + udf.pd[partition].PartitionStartingLocation) + meta = uint64(uint32(metaFile.GetAllocationDescriptors()[0].GetLocation()) + udf.pd[partition].PartitionStartingLocation) + } else { + meta = physical } - return uint64(udf.pd[partition].PartitionStartingLocation) } + return } func (udf *Udf) GetReader() io.ReaderAt { @@ -74,7 +77,7 @@ func (udf *Udf) init() { } } - partitionStart := udf.PartitionStart(0) + _, partitionStart := udf.PartitionStart(0) udf.fsd = NewFileSetDescriptor(udf.ReadSector(partitionStart + uint64(udf.lvd.LogicalVolumeContentsUse.Location.LogicalBlockNumber))) udf.root_fe = NewFileEntry(udf.ReadSector(partitionStart + uint64(udf.fsd.RootDirectoryICB.Location.LogicalBlockNumber))) @@ -89,18 +92,18 @@ func (udf *Udf) ReadDir(fe FileEntryInterface) []File { fe = udf.root_fe } - ps := udf.PartitionStart(0) + _, ps := udf.PartitionStart(0) adPos := fe.GetAllocationDescriptors()[0] - fdLen := uint64(adPos.Length) + fdLen := uint64(adPos.GetLength()) - fdBuf := udf.ReadSectors(ps+uint64(adPos.Location), (fdLen+SECTOR_SIZE-1)/SECTOR_SIZE) + fdBuf := udf.ReadSectors(ps+uint64(adPos.GetLocation()), (fdLen+SECTOR_SIZE-1)/SECTOR_SIZE) fdOff := uint64(0) result := make([]File, 0) - for uint32(fdOff) < adPos.Length { + for uint32(fdOff) < adPos.GetLength() { fid := NewFileIdentifierDescriptor(fdBuf[fdOff:]) if fid.FileIdentifier != "" { result = append(result, File{ From 3b76a4876b140d3843de9bcd647eabda8880b571 Mon Sep 17 00:00:00 2001 From: Xmister Date: Fri, 1 Mar 2019 14:42:25 +0100 Subject: [PATCH 03/17] Find sector size in init --- descr.go | 9 +++++++++ file.go | 2 +- udf.go | 48 +++++++++++++++++++++++++++++++++++++----------- 3 files changed, 47 insertions(+), 12 deletions(-) diff --git a/descr.go b/descr.go index 4591173..03dbffd 100644 --- a/descr.go +++ b/descr.go @@ -38,6 +38,15 @@ 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:]) diff --git a/file.go b/file.go index 5a66b7f..73a89fe 100644 --- a/file.go +++ b/file.go @@ -25,7 +25,7 @@ func (f *File) GetFileOffset() (res int64) { } else if f.fe.GetICBTag().AllocationType == ShortDescriptors { res += int64(meta) } - return SECTOR_SIZE * res + return int64(SECTOR_SIZE) * res } func (f *File) FileEntry() FileEntryInterface { diff --git a/udf.go b/udf.go index 05151e4..e6f4dfb 100644 --- a/udf.go +++ b/udf.go @@ -2,15 +2,18 @@ package udf import ( "io" + "errors" ) -const SECTOR_SIZE = 2048 +// uint64 so the type matches in most calculations +var SECTOR_SIZE uint64 type Udf struct { r io.ReaderAt isInited bool pvd *PrimaryVolumeDescriptor pd map[uint16]*PartitionDescriptor + pdl []*PartitionDescriptor lvd *LogicalVolumeDescriptor fsd *FileSetDescriptor root_fe FileEntryInterface @@ -20,10 +23,15 @@ func (udf *Udf) PartitionStart(partition uint16) (physical uint64, meta uint64) if udf.pd == nil { panic(udf) } else { - physical = uint64(udf.pd[partition].PartitionStartingLocation) - metaFile := NewFileEntry(udf.ReadSector(uint64(udf.pd[partition].PartitionStartingLocation))) + var part *PartitionDescriptor + var ok bool + if part, ok = udf.pd[partition]; !ok && partition == 0 { + part = udf.pdl[0] + } + physical = uint64(part.PartitionStartingLocation) + metaFile := NewFileEntry(udf.ReadSector(uint64(part.PartitionStartingLocation))) if metaFile != nil && len(metaFile.GetAllocationDescriptors()) > 0 { - meta = uint64(uint32(metaFile.GetAllocationDescriptors()[0].GetLocation()) + udf.pd[partition].PartitionStartingLocation) + meta = uint64(uint32(metaFile.GetAllocationDescriptors()[0].GetLocation()) + part.PartitionStartingLocation) } else { meta = physical } @@ -51,14 +59,25 @@ func (udf *Udf) ReadSector(sectorNumber uint64) []byte { return udf.ReadSectors(sectorNumber, 1) } -func (udf *Udf) init() { +func (udf *Udf) init() (err error) { if udf.isInited { return } - anchorDesc := NewAnchorVolumeDescriptorPointer(udf.ReadSector(256)) - if anchorDesc.Descriptor.TagIdentifier != DESCRIPTOR_ANCHOR_VOLUME_POINTER { - panic(anchorDesc.Descriptor.TagIdentifier) + var anchorDesc *AnchorVolumeDescriptorPointer + + for SECTOR_SIZE = 512; SECTOR_SIZE <= 32768; SECTOR_SIZE <<= 1 { + anchorDesc = NewAnchorVolumeDescriptorPointer(udf.ReadSector(256)) + if anchorDesc.Descriptor.TagIdentifier == DESCRIPTOR_ANCHOR_VOLUME_POINTER && + anchorDesc.Descriptor.TagChecksum == anchorDesc.Descriptor.Checksum() { + break + } + } + + if anchorDesc.Descriptor.TagIdentifier != DESCRIPTOR_ANCHOR_VOLUME_POINTER || + anchorDesc.Descriptor.TagChecksum != anchorDesc.Descriptor.Checksum() { + err = errors.New("couldn't find sector size") + return } for sector := uint64(anchorDesc.MainVolumeDescriptorSeq.Location); ; sector++ { @@ -72,6 +91,7 @@ func (udf *Udf) init() { case DESCRIPTOR_PARTITION: pd := desc.PartitionDescriptor() udf.pd[pd.PartitionNumber] = pd + udf.pdl = append(udf.pdl, pd) case DESCRIPTOR_LOGICAL_VOLUME: udf.lvd = desc.LogicalVolumeDescriptor() } @@ -79,10 +99,15 @@ func (udf *Udf) init() { _, partitionStart := udf.PartitionStart(0) + test := udf.ReadSector(partitionStart + 256) + + if (len(test) > 1) {} + udf.fsd = NewFileSetDescriptor(udf.ReadSector(partitionStart + uint64(udf.lvd.LogicalVolumeContentsUse.Location.LogicalBlockNumber))) udf.root_fe = NewFileEntry(udf.ReadSector(partitionStart + uint64(udf.fsd.RootDirectoryICB.Location.LogicalBlockNumber))) udf.isInited = true + return } func (udf *Udf) ReadDir(fe FileEntryInterface) []File { @@ -117,12 +142,13 @@ func (udf *Udf) ReadDir(fe FileEntryInterface) []File { return result } -func NewUdfFromReader(r io.ReaderAt) *Udf { - udf := &Udf{ +func NewUdfFromReader(r io.ReaderAt) (udf *Udf, err error) { + udf = &Udf{ r: r, isInited: false, pd: make(map[uint16]*PartitionDescriptor), } - return udf + err = udf.init() + return } From 8c285b374b6cb5a8712de8fe360b27374a07818c Mon Sep 17 00:00:00 2001 From: Xmister Date: Mon, 4 Mar 2019 11:00:09 +0100 Subject: [PATCH 04/17] WIP --- extent.go | 13 +++++++++++++ file.go | 2 +- udf.go | 18 +++++++----------- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/extent.go b/extent.go index f8d62a6..c007cf8 100644 --- a/extent.go +++ b/extent.go @@ -3,6 +3,7 @@ package udf type ExtentInterface interface { GetLocation() uint64 GetLength() uint32 + GetPartition() uint16 } type Extent struct { @@ -10,6 +11,10 @@ type Extent struct { Location uint32 } +func (e Extent) GetPartition() uint16 { + return 0 +} + func (e Extent) GetLocation() uint64 { return uint64(e.Location) } @@ -30,6 +35,10 @@ type ExtentSmall struct { Location uint64 } +func (e ExtentSmall) GetPartition() uint16 { + return 0 +} + func (e ExtentSmall) GetLocation() uint64 { return uint64(e.Location) } @@ -50,6 +59,10 @@ type ExtentLong struct { Location LbAddr } +func (e ExtentLong) GetPartition() uint16 { + return e.Location.PartitionReferenceNumber +} + func (e ExtentLong) GetLocation() uint64 { return uint64(e.Location.LogicalBlockNumber) } diff --git a/file.go b/file.go index 73a89fe..5e678ab 100644 --- a/file.go +++ b/file.go @@ -30,7 +30,7 @@ func (f *File) GetFileOffset() (res int64) { func (f *File) FileEntry() FileEntryInterface { if f.fe == nil { - f.fileEntryPosition = uint64(f.Fid.ICB.Location.LogicalBlockNumber) + f.fileEntryPosition = uint64(f.Fid.ICB.GetLocation()) _, meta := f.Udf.PartitionStart(0) f.fe = NewFileEntry(f.Udf.ReadSector(meta + f.fileEntryPosition)) } diff --git a/udf.go b/udf.go index e6f4dfb..71615cc 100644 --- a/udf.go +++ b/udf.go @@ -25,8 +25,9 @@ func (udf *Udf) PartitionStart(partition uint16) (physical uint64, meta uint64) } else { var part *PartitionDescriptor var ok bool - if part, ok = udf.pd[partition]; !ok && partition == 0 { - part = udf.pdl[0] + if part, ok = udf.pd[partition]; !ok { + + part = udf.pdl[partition] } physical = uint64(part.PartitionStartingLocation) metaFile := NewFileEntry(udf.ReadSector(uint64(part.PartitionStartingLocation))) @@ -99,10 +100,6 @@ func (udf *Udf) init() (err error) { _, partitionStart := udf.PartitionStart(0) - test := udf.ReadSector(partitionStart + 256) - - if (len(test) > 1) {} - udf.fsd = NewFileSetDescriptor(udf.ReadSector(partitionStart + uint64(udf.lvd.LogicalVolumeContentsUse.Location.LogicalBlockNumber))) udf.root_fe = NewFileEntry(udf.ReadSector(partitionStart + uint64(udf.fsd.RootDirectoryICB.Location.LogicalBlockNumber))) @@ -117,13 +114,13 @@ func (udf *Udf) ReadDir(fe FileEntryInterface) []File { fe = udf.root_fe } - _, ps := udf.PartitionStart(0) - - adPos := fe.GetAllocationDescriptors()[0] fdLen := uint64(adPos.GetLength()) - fdBuf := udf.ReadSectors(ps+uint64(adPos.GetLocation()), (fdLen+SECTOR_SIZE-1)/SECTOR_SIZE) + _, ps := udf.PartitionStart(0) + + + fdBuf := udf.ReadSectors(ps+adPos.GetLocation(), (fdLen+SECTOR_SIZE-1)/SECTOR_SIZE) fdOff := uint64(0) result := make([]File, 0) @@ -138,7 +135,6 @@ func (udf *Udf) ReadDir(fe FileEntryInterface) []File { } fdOff += fid.Len() } - return result } From ea9f17b17e197ba8f97907b003888e4a867beb65 Mon Sep 17 00:00:00 2001 From: Xmister Date: Mon, 4 Mar 2019 19:15:38 +0100 Subject: [PATCH 05/17] Follow partition specification a bit better --- descr.go | 34 ++++++++++++++++++++++++++++------ file.go | 13 ++++--------- udf.go | 45 ++++++++++++++++++++++++--------------------- 3 files changed, 56 insertions(+), 36 deletions(-) diff --git a/descr.go b/descr.go index 03dbffd..2939ffd 100644 --- a/descr.go +++ b/descr.go @@ -179,13 +179,22 @@ 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:]) + pm.PartitionNumber = rb_u16(b[offset+2:]) + pm.PartitionStart = uint32(pm.VolumeSequenceNumber) return pm } @@ -217,7 +226,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 @@ -319,6 +328,7 @@ type FileEntryInterface interface { GetInformationLength() uint64 GetModificationTime() time.Time GetICBTag() *ICBTag + GetPartition() uint16 } type FileEntry struct { @@ -344,6 +354,8 @@ type FileEntry struct { LengthOfAllocationDescriptors uint32 ExtendedAttributes []byte AllocationDescriptors []byte + // Manual field + Partition uint16 } type ExtendedFileEntry struct { @@ -383,6 +395,13 @@ func (fe *FileEntry) FromBytes(b []byte) *FileEntry { return fe } +func (fe *FileEntry) GetPartition() uint16 { + if fe.ICBTag.AllocationType == LongDescriptors { + return fe.GetAllocationDescriptors()[0].GetPartition() + } + return fe.Partition +} + func (fe *FileEntry) GetAllocationDescriptors() (list []ExtentInterface) { switch fe.ICBTag.AllocationType { case ShortDescriptors: @@ -415,10 +434,13 @@ func (fe *FileEntry) GetICBTag() *ICBTag { return fe.ICBTag } -func NewFileEntry(b []byte) (fe FileEntryInterface) { +func NewFileEntry(partition uint16, b []byte) (fe FileEntryInterface) { if e := new(FileEntry).FromBytes(b); e == nil { - fe = new(ExtendedFileEntry).FromBytes(b) + ee := new(ExtendedFileEntry).FromBytes(b) + ee.Partition = partition + fe = ee } else { + e.Partition = partition fe = e } return @@ -458,5 +480,5 @@ func (fe *ExtendedFileEntry) FromBytes(b []byte) *ExtendedFileEntry { } func (d *Descriptor) FileEntry() FileEntryInterface { - return NewFileEntry(d.data) + return NewFileEntry(0, d.data) } diff --git a/file.go b/file.go index 5e678ab..5b09787 100644 --- a/file.go +++ b/file.go @@ -18,21 +18,16 @@ func (f *File) GetFileEntryPosition() int64 { } func (f *File) GetFileOffset() (res int64) { - physical, meta := f.Udf.PartitionStart(0) - res = int64(f.FileEntry().GetAllocationDescriptors()[0].GetLocation()) - if f.fe.GetICBTag().AllocationType == LongDescriptors { - res += int64(physical) - } else if f.fe.GetICBTag().AllocationType == ShortDescriptors { - res += int64(meta) - } + asd := f.FileEntry().GetAllocationDescriptors()[0] + res = int64(f.Udf.LogicalPartitionStart(f.FileEntry().GetPartition())) + int64(asd.GetLocation()) return int64(SECTOR_SIZE) * res } func (f *File) FileEntry() FileEntryInterface { if f.fe == nil { f.fileEntryPosition = uint64(f.Fid.ICB.GetLocation()) - _, meta := f.Udf.PartitionStart(0) - f.fe = NewFileEntry(f.Udf.ReadSector(meta + f.fileEntryPosition)) + meta := f.Udf.LogicalPartitionStart(f.Fid.ICB.GetPartition()) + f.fe = NewFileEntry(f.Fid.ICB.GetPartition(), f.Udf.ReadSector(meta + f.fileEntryPosition)) } return f.fe } diff --git a/udf.go b/udf.go index 71615cc..533134d 100644 --- a/udf.go +++ b/udf.go @@ -13,31 +13,25 @@ type Udf struct { isInited bool pvd *PrimaryVolumeDescriptor pd map[uint16]*PartitionDescriptor - pdl []*PartitionDescriptor lvd *LogicalVolumeDescriptor fsd *FileSetDescriptor root_fe FileEntryInterface } -func (udf *Udf) PartitionStart(partition uint16) (physical uint64, meta uint64) { +func (udf *Udf) PhysicalPartitionStart(partition uint16) (physical uint64) { if udf.pd == nil { panic(udf) } else { - var part *PartitionDescriptor - var ok bool - if part, ok = udf.pd[partition]; !ok { + return uint64(udf.pd[partition].PartitionStartingLocation) + } +} - part = udf.pdl[partition] - } - physical = uint64(part.PartitionStartingLocation) - metaFile := NewFileEntry(udf.ReadSector(uint64(part.PartitionStartingLocation))) - if metaFile != nil && len(metaFile.GetAllocationDescriptors()) > 0 { - meta = uint64(uint32(metaFile.GetAllocationDescriptors()[0].GetLocation()) + part.PartitionStartingLocation) - } else { - meta = physical - } +func (udf *Udf) LogicalPartitionStart(partition uint16) (logical uint64) { + if udf.lvd == nil || len(udf.lvd.PartitionMaps) < 1 { + panic(udf) + } else { + return uint64(udf.lvd.PartitionMaps[partition].PartitionStart) } - return } func (udf *Udf) GetReader() io.ReaderAt { @@ -92,16 +86,27 @@ func (udf *Udf) init() (err error) { case DESCRIPTOR_PARTITION: pd := desc.PartitionDescriptor() udf.pd[pd.PartitionNumber] = pd - udf.pdl = append(udf.pdl, pd) case DESCRIPTOR_LOGICAL_VOLUME: udf.lvd = desc.LogicalVolumeDescriptor() } } - _, partitionStart := udf.PartitionStart(0) + for i, pMap := range udf.lvd.PartitionMaps { + if pMap.PartitionMapType != 2 { + udf.lvd.PartitionMaps[i].PartitionStart = udf.pd[pMap.PartitionNumber].PartitionStartingLocation + continue + } + metaFile := NewFileEntry(0, udf.ReadSector(uint64(udf.pd[pMap.PartitionNumber].PartitionStartingLocation))) + if metaFile != nil && len(metaFile.GetAllocationDescriptors()) > 0 { + udf.lvd.PartitionMaps[i].PartitionStart = uint32(metaFile.GetAllocationDescriptors()[0].GetLocation()) + udf.pd[pMap.PartitionNumber].PartitionStartingLocation + } + } + + partitionStart := udf.LogicalPartitionStart(udf.lvd.LogicalVolumeContentsUse.GetPartition()) udf.fsd = NewFileSetDescriptor(udf.ReadSector(partitionStart + uint64(udf.lvd.LogicalVolumeContentsUse.Location.LogicalBlockNumber))) - udf.root_fe = NewFileEntry(udf.ReadSector(partitionStart + uint64(udf.fsd.RootDirectoryICB.Location.LogicalBlockNumber))) + rootICB := udf.fsd.RootDirectoryICB + udf.root_fe = NewFileEntry(udf.lvd.LogicalVolumeContentsUse.GetPartition(), udf.ReadSector(udf.LogicalPartitionStart(rootICB.GetPartition()) + rootICB.GetLocation())) udf.isInited = true return @@ -109,16 +114,14 @@ func (udf *Udf) init() (err error) { func (udf *Udf) ReadDir(fe FileEntryInterface) []File { udf.init() - if fe == nil { fe = udf.root_fe } + ps := udf.LogicalPartitionStart(fe.GetPartition()) adPos := fe.GetAllocationDescriptors()[0] fdLen := uint64(adPos.GetLength()) - _, ps := udf.PartitionStart(0) - fdBuf := udf.ReadSectors(ps+adPos.GetLocation(), (fdLen+SECTOR_SIZE-1)/SECTOR_SIZE) fdOff := uint64(0) From a768e9ee29231278ef9cdd7eb04273dd8843231e Mon Sep 17 00:00:00 2001 From: Xmister Date: Tue, 5 Mar 2019 17:17:57 +0100 Subject: [PATCH 06/17] Proper handling of Allocationdescriptors --- file.go | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 5 deletions(-) diff --git a/file.go b/file.go index 5b09787..92c95d1 100644 --- a/file.go +++ b/file.go @@ -13,13 +13,106 @@ type File struct { fileEntryPosition uint64 } +type sectionReader struct { + *io.SectionReader + start int64 + size int64 +} + +func newSectionReader(base int64, reader io.ReaderAt, start int64, size int64) *sectionReader { + return §ionReader{ + io.NewSectionReader(reader, start, size), + start-base, + size, + } +} + +type multiSectionReader struct { + readers []*sectionReader + pos int64 + size int64 + index int +} + +func newMultiSectionReader(readers []*sectionReader) *multiSectionReader { + var start, end int64 + for _, reader := range readers { + if reader.start < start { + start = reader.start + } + if reader.size+reader.start > end { + end = reader.size+reader.start + } + } + return &multiSectionReader{ + readers: readers, + size: end-start, + } +} + +func (r *multiSectionReader) Read(p []byte) (n int, err error) { + var read int + n, err = io.ReadFull(r.readers[r.index], p) + if err == io.ErrUnexpectedEOF { + if r.index+1 < len(r.readers) { + r.index++ + read, err = r.Read(p[n:]) + n+=read + } + } + r.pos += int64(n) + return +} + +func (r *multiSectionReader) Seek(offset int64, whence int) (n int64, err error) { + switch whence { + case io.SeekStart: + n = offset + case io.SeekCurrent: + n = offset + r.pos + case io.SeekEnd: + n = offset + r.size + } + if n > r.size { + return 0, io.EOF + } + r.pos = n + for i, reader := range r.readers { + if reader.start <= n && reader.start+reader.size >= n { + _, err = reader.Seek(n-reader.start, io.SeekStart) + r.index = i + break + } + } + return +} + +func (r *multiSectionReader) ReadAt(p []byte, off int64) (n int, err error) { + var read int + err = os.ErrNotExist // No readers + for _, reader := range r.readers { + if reader.start <= off+int64(n) && reader.start+reader.size >= off+int64(n) { + read, err = reader.ReadAt(p[n:], off+int64(n)-reader.start) + n += read + if (err != nil && err != io.EOF) || cap(p) == n { + return + } + } + } + return +} + func (f *File) GetFileEntryPosition() int64 { return int64(f.fileEntryPosition) } -func (f *File) GetFileOffset() (res int64) { - asd := f.FileEntry().GetAllocationDescriptors()[0] - res = int64(f.Udf.LogicalPartitionStart(f.FileEntry().GetPartition())) + int64(asd.GetLocation()) +func (f *File) GetFileOffset(descriptor int) (res int64) { + asd := f.FileEntry().GetAllocationDescriptors()[descriptor] + partition := f.FileEntry().GetPartition() + if f.FileEntry().GetICBTag().AllocationType == LongDescriptors { + partition = asd.GetPartition() + } + res = int64(f.Udf.LogicalPartitionStart(partition) + asd.GetLocation()) return int64(SECTOR_SIZE) * res } @@ -32,8 +125,13 @@ func (f *File) FileEntry() FileEntryInterface { return f.fe } -func (f *File) NewReader() *io.SectionReader { - return io.NewSectionReader(f.Udf.r, f.GetFileOffset(), f.Size()) +func (f *File) NewReader() *multiSectionReader { + descs := f.FileEntry().GetAllocationDescriptors() + readers := make([]*sectionReader, len(descs)) + for i:=0; i Date: Wed, 6 Mar 2019 23:02:43 +0100 Subject: [PATCH 07/17] Implement Allocation Extent Descriptor --- descr.go | 43 ++++++++++++++++++++------ extent.go | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ file.go | 60 ++++++++++++++++++++---------------- udf.go | 6 ++-- 4 files changed, 162 insertions(+), 39 deletions(-) diff --git a/descr.go b/descr.go index 2939ffd..3a0cdf6 100644 --- a/descr.go +++ b/descr.go @@ -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 { @@ -402,22 +405,42 @@ func (fe *FileEntry) GetPartition() uint16 { return fe.Partition } -func (fe *FileEntry) GetAllocationDescriptors() (list []ExtentInterface) { - switch fe.ICBTag.AllocationType { +func GetAllocationDescriptor(t AllocationType, b []byte) ExtentInterface { + switch t { case ShortDescriptors: - list = make([]ExtentInterface, fe.LengthOfAllocationDescriptors/8) - for i := range list { - list[i] = NewExtent(fe.AllocationDescriptors[uint32(i)*8:]) - } + return NewExtent(b) case LongDescriptors: - list = make([]ExtentInterface, fe.LengthOfAllocationDescriptors/16) - for i := range list { - list[i] = NewExtentLong(fe.AllocationDescriptors[uint32(i)*16:]) - } + 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 } diff --git a/extent.go b/extent.go index c007cf8..7526920 100644 --- a/extent.go +++ b/extent.go @@ -3,7 +3,10 @@ package udf type ExtentInterface interface { GetLocation() uint64 GetLength() uint32 + SetLength(uint32) GetPartition() uint16 + IsNotRecorded() bool + HasExtended() bool } type Extent struct { @@ -23,6 +26,18 @@ func (e Extent) GetLength() uint32 { return e.Length } +func (e Extent) SetLength(length uint32) { + e.Length = length +} + +func (e Extent) IsNotRecorded() bool { + return (e.Length & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_ALLOCATED || (e.Length & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_NOT_ALLOCATED +} + +func (e Extent) HasExtended() bool { + return (e.Length >> 30) == 3 +} + func NewExtent(b []byte) Extent { return Extent{ Length: rl_u32(b[0:]), @@ -47,6 +62,18 @@ func (e ExtentSmall) GetLength() uint32 { return uint32(e.Length) } +func (e ExtentSmall) SetLength(length uint32) { + e.Length = uint16(length) +} + +func (e ExtentSmall) IsNotRecorded() bool { + return false +} + +func (e ExtentSmall) HasExtended() bool { + return (e.Length >> 30) == 3 +} + func NewExtentSmall(b []byte) ExtentSmall { return ExtentSmall{ Length: rl_u16(b[0:]), @@ -71,6 +98,18 @@ func (e ExtentLong) GetLength() uint32 { return e.Length } +func (e ExtentLong) SetLength(length uint32) { + e.Length = length +} + +func (e ExtentLong) HasExtended() bool { + return (e.Length >> 30) == 3 +} + +func (e ExtentLong) IsNotRecorded() bool { + return (e.Length & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_ALLOCATED || (e.Length & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_NOT_ALLOCATED +} + func NewExtentLong(b []byte) ExtentLong { return ExtentLong{ Length: rl_u32(b[0:]), @@ -78,6 +117,59 @@ func NewExtentLong(b []byte) ExtentLong { } } +type ExtentExtended struct { + ExtentLength uint32 + RecordedLength uint32 + InfoLength uint32 + Location LbAddr +} + +func (e ExtentExtended) GetPartition() uint16 { + return e.Location.PartitionReferenceNumber +} + +func (e ExtentExtended) GetLocation() uint64 { + return uint64(e.Location.LogicalBlockNumber) +} + +func (e ExtentExtended) GetLength() uint32 { + return e.InfoLength +} + +func (e ExtentExtended) SetLength(length uint32) { + e.InfoLength = length +} + +func (e ExtentExtended) HasExtended() bool { + return (e.GetLength() >> 30) == 3 +} + +func (e ExtentExtended) IsNotRecorded() bool { + return false +} + +func NewExtentExtended(b []byte) ExtentExtended { + return ExtentExtended{ + ExtentLength: rl_u32(b[0:]), + RecordedLength: rl_u32(b[4:]), + InfoLength: rl_u32(b[8:]), + Location: new(LbAddr).FromBytes(b[12:]), + } +} + +type AED struct { + Descriptor Descriptor + PreviousAllocationExtentLocation uint32 + LengthOfAllocationDescriptors uint32 +} + +func (a *AED) FromBytes(b []byte) AED { + a.Descriptor.FromBytes(b) + a.PreviousAllocationExtentLocation = rl_u32(b[16:]) + a.LengthOfAllocationDescriptors = rl_u32(b[20:]) + return *a +} + type LbAddr struct { LogicalBlockNumber uint32 PartitionReferenceNumber uint16 diff --git a/file.go b/file.go index 92c95d1..26532e3 100644 --- a/file.go +++ b/file.go @@ -19,10 +19,10 @@ type sectionReader struct { size int64 } -func newSectionReader(base int64, reader io.ReaderAt, start int64, size int64) *sectionReader { +func newSectionReader(inFileStart int64, reader io.ReaderAt, start int64, size int64) *sectionReader { return §ionReader{ io.NewSectionReader(reader, start, size), - start-base, + inFileStart, size, } } @@ -35,32 +35,32 @@ type multiSectionReader struct { } func newMultiSectionReader(readers []*sectionReader) *multiSectionReader { - var start, end int64 + var size int64 for _, reader := range readers { - if reader.start < start { - start = reader.start - } - if reader.size+reader.start > end { - end = reader.size+reader.start - } + size += reader.size } return &multiSectionReader{ readers: readers, - size: end-start, + size: size, } } func (r *multiSectionReader) Read(p []byte) (n int, err error) { var read int + // Recursing below could increase the pos multiple times for the same read, so we are saving the starting pos here + startpos := r.pos n, err = io.ReadFull(r.readers[r.index], p) - if err == io.ErrUnexpectedEOF { + if err == io.ErrUnexpectedEOF || err == io.EOF { if r.index+1 < len(r.readers) { r.index++ + r.readers[r.index].Seek(0,0) read, err = r.Read(p[n:]) n+=read + } else { + err = io.EOF } } - r.pos += int64(n) + r.pos = startpos + int64(n) return } @@ -102,18 +102,12 @@ func (r *multiSectionReader) ReadAt(p []byte, off int64) (n int, err error) { return } -func (f *File) GetFileEntryPosition() int64 { - return int64(f.fileEntryPosition) +func (r *multiSectionReader) Size() int64 { + return r.size } -func (f *File) GetFileOffset(descriptor int) (res int64) { - asd := f.FileEntry().GetAllocationDescriptors()[descriptor] - partition := f.FileEntry().GetPartition() - if f.FileEntry().GetICBTag().AllocationType == LongDescriptors { - partition = asd.GetPartition() - } - res = int64(f.Udf.LogicalPartitionStart(partition) + asd.GetLocation()) - return int64(SECTOR_SIZE) * res +func (f *File) GetFileEntryPosition() int64 { + return int64(f.fileEntryPosition) } func (f *File) FileEntry() FileEntryInterface { @@ -125,12 +119,26 @@ func (f *File) FileEntry() FileEntryInterface { return f.fe } -func (f *File) NewReader() *multiSectionReader { - descs := f.FileEntry().GetAllocationDescriptors() - readers := make([]*sectionReader, len(descs)) +func (f *File) getReaders(descs []ExtentInterface, filePos int64) (readers []*sectionReader, finalFilePos int64) { + finalFilePos = filePos for i:=0; i Date: Mon, 29 Jul 2019 12:18:12 +0200 Subject: [PATCH 08/17] Lazy reading --- file.go | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/file.go b/file.go index 26532e3..4b0a6a5 100644 --- a/file.go +++ b/file.go @@ -46,21 +46,23 @@ func newMultiSectionReader(readers []*sectionReader) *multiSectionReader { } func (r *multiSectionReader) Read(p []byte) (n int, err error) { - var read int - // Recursing below could increase the pos multiple times for the same read, so we are saving the starting pos here - startpos := r.pos - n, err = io.ReadFull(r.readers[r.index], p) - if err == io.ErrUnexpectedEOF || err == io.EOF { + if r.index > len(r.readers)-1 { + return 0, io.EOF + } + n, err = r.readers[r.index].Read(p) + r.pos += int64(n) + if err != nil { if r.index+1 < len(r.readers) { r.index++ - r.readers[r.index].Seek(0,0) - read, err = r.Read(p[n:]) - n+=read - } else { - err = io.EOF + r.readers[r.index].Seek(0, 0) + if n == 0 { + n, err = r.Read(p) + } } } - r.pos = startpos + int64(n) + if n > 0 { + err = nil + } return } From 220d0001a264935f3cd46905ae5ffa7cddc9b061 Mon Sep 17 00:00:00 2001 From: Xmister Date: Fri, 17 Jul 2020 01:14:23 +0200 Subject: [PATCH 09/17] Per-object sector size --- file.go | 2 +- udf.go | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/file.go b/file.go index 4b0a6a5..765e0f8 100644 --- a/file.go +++ b/file.go @@ -131,7 +131,7 @@ func (f *File) getReaders(descs []ExtentInterface, filePos int64) (readers []*se subReaders, finalFilePos = f.getReaders(GetAllocationDescriptors(f.FileEntry().GetICBTag().AllocationType, extendData[24:], aed.LengthOfAllocationDescriptors), finalFilePos) readers = append(readers, subReaders...) } else if !descs[i].IsNotRecorded() { - readers = append(readers, newSectionReader(finalFilePos, f.Udf.r, int64(SECTOR_SIZE)*int64(f.Udf.LogicalPartitionStart(descs[i].GetPartition()) + descs[i].GetLocation()), int64(descs[i].GetLength()))) + readers = append(readers, newSectionReader(finalFilePos, f.Udf.r, int64(f.Udf.SECTOR_SIZE)*int64(f.Udf.LogicalPartitionStart(descs[i].GetPartition()) + descs[i].GetLocation()), int64(descs[i].GetLength()))) } finalFilePos += int64(descs[i].GetLength()) } diff --git a/udf.go b/udf.go index 4eab09b..2ffaf32 100644 --- a/udf.go +++ b/udf.go @@ -1,13 +1,10 @@ package udf import ( - "io" "errors" + "io" ) -// uint64 so the type matches in most calculations -var SECTOR_SIZE uint64 - type Udf struct { r io.ReaderAt isInited bool @@ -16,6 +13,7 @@ type Udf struct { lvd *LogicalVolumeDescriptor fsd *FileSetDescriptor root_fe FileEntryInterface + SECTOR_SIZE uint64 } func (udf *Udf) PhysicalPartitionStart(partition uint16) (physical uint64) { @@ -39,15 +37,15 @@ func (udf *Udf) GetReader() io.ReaderAt { } func (udf *Udf) ReadSectors(sectorNumber uint64, sectorsCount uint64) []byte { - buf := make([]byte, SECTOR_SIZE*sectorsCount) - readed, err := udf.r.ReadAt(buf[:], int64(SECTOR_SIZE*sectorNumber)) + buf := make([]byte, udf.SECTOR_SIZE*sectorsCount) + read, err := udf.r.ReadAt(buf[:], int64(udf.SECTOR_SIZE*sectorNumber)) if err != nil { panic(err) } - /*if readed != int(SECTOR_SIZE*sectorsCount) { + /*if readed != int(udf.SECTOR_SIZE*sectorsCount) { panic(readed) }*/ - return buf[:readed] + return buf[:read] } func (udf *Udf) ReadSector(sectorNumber uint64) []byte { @@ -61,7 +59,7 @@ func (udf *Udf) init() (err error) { var anchorDesc *AnchorVolumeDescriptorPointer - for SECTOR_SIZE = 512; SECTOR_SIZE <= 32768; SECTOR_SIZE <<= 1 { + for udf.SECTOR_SIZE = 512; udf.SECTOR_SIZE <= 32768; udf.SECTOR_SIZE <<= 1 { anchorDesc = NewAnchorVolumeDescriptorPointer(udf.ReadSector(256)) if anchorDesc.Descriptor.TagIdentifier == DESCRIPTOR_ANCHOR_VOLUME_POINTER && anchorDesc.Descriptor.TagChecksum == anchorDesc.Descriptor.Checksum() { @@ -123,7 +121,7 @@ func (udf *Udf) ReadDir(fe FileEntryInterface) []File { fdLen := uint64(adPos.GetLength()) - fdBuf := udf.ReadSectors(ps+adPos.GetLocation(), (fdLen+SECTOR_SIZE-1)/SECTOR_SIZE) + fdBuf := udf.ReadSectors(ps+adPos.GetLocation(), (fdLen+udf.SECTOR_SIZE-1)/udf.SECTOR_SIZE) fdOff := uint64(0) result := make([]File, 0) From 62dcaddb468fa908fbe01f4534457d9180d560d0 Mon Sep 17 00:00:00 2001 From: Cedric Halbronn Date: Fri, 11 Dec 2020 12:52:20 +0000 Subject: [PATCH 10/17] reorder functions so easier to read --- file.go | 160 ++++++++++++++++++++++++++++---------------------------- udf.go | 95 +++++++++++++++++---------------- 2 files changed, 127 insertions(+), 128 deletions(-) diff --git a/file.go b/file.go index 765e0f8..18aa473 100644 --- a/file.go +++ b/file.go @@ -13,10 +13,85 @@ type File struct { fileEntryPosition uint64 } +func (f *File) IsDir() bool { + return f.FileEntry().GetICBTag().FileType == 4 +} + +func (f *File) ModTime() time.Time { + return f.FileEntry().GetModificationTime() +} + +func (f *File) Mode() os.FileMode { + var mode os.FileMode + + perms := os.FileMode(f.FileEntry().GetPermissions()) + mode |= ((perms >> 0) & 7) << 0 + mode |= ((perms >> 5) & 7) << 3 + mode |= ((perms >> 10) & 7) << 6 + + if f.IsDir() { + mode |= os.ModeDir + } + + return mode +} + +func (f *File) Name() string { + return f.Fid.FileIdentifier +} + +func (f *File) Size() int64 { + return int64(f.FileEntry().GetInformationLength()) +} + +func (f *File) Sys() interface{} { + return f.Fid +} + +func (f *File) ReadDir() []File { + return f.Udf.ReadDir(f.FileEntry()) +} + +func (f *File) GetFileEntryPosition() int64 { + return int64(f.fileEntryPosition) +} + +func (f *File) FileEntry() FileEntryInterface { + if f.fe == nil { + f.fileEntryPosition = uint64(f.Fid.ICB.GetLocation()) + meta := f.Udf.LogicalPartitionStart(f.Fid.ICB.GetPartition()) + f.fe = NewFileEntry(f.Fid.ICB.GetPartition(), f.Udf.ReadSector(meta+f.fileEntryPosition)) + } + return f.fe +} + +func (f *File) getReaders(descs []ExtentInterface, filePos int64) (readers []*sectionReader, finalFilePos int64) { + finalFilePos = filePos + for i := 0; i < len(descs); i++ { + if descs[i].HasExtended() { + extendData := f.Udf.ReadSector(f.Udf.LogicalPartitionStart(descs[i].GetPartition()) + descs[i].GetLocation()) + aed := new(AED).FromBytes(extendData) + var subReaders []*sectionReader + subReaders, finalFilePos = f.getReaders(GetAllocationDescriptors(f.FileEntry().GetICBTag().AllocationType, extendData[24:], aed.LengthOfAllocationDescriptors), finalFilePos) + readers = append(readers, subReaders...) + } else if !descs[i].IsNotRecorded() { + readers = append(readers, newSectionReader(finalFilePos, f.Udf.r, int64(f.Udf.SECTOR_SIZE)*int64(f.Udf.LogicalPartitionStart(descs[i].GetPartition())+descs[i].GetLocation()), int64(descs[i].GetLength()))) + } + finalFilePos += int64(descs[i].GetLength()) + } + return +} + +func (f *File) NewReader() *multiSectionReader { + descs := f.FileEntry().GetAllocationDescriptors() + readers, _ := f.getReaders(descs, 0) + return newMultiSectionReader(readers) +} + type sectionReader struct { *io.SectionReader start int64 - size int64 + size int64 } func newSectionReader(inFileStart int64, reader io.ReaderAt, start int64, size int64) *sectionReader { @@ -29,9 +104,9 @@ func newSectionReader(inFileStart int64, reader io.ReaderAt, start int64, size i type multiSectionReader struct { readers []*sectionReader - pos int64 - size int64 - index int + pos int64 + size int64 + index int } func newMultiSectionReader(readers []*sectionReader) *multiSectionReader { @@ -41,7 +116,7 @@ func newMultiSectionReader(readers []*sectionReader) *multiSectionReader { } return &multiSectionReader{ readers: readers, - size: size, + size: size, } } @@ -107,78 +182,3 @@ func (r *multiSectionReader) ReadAt(p []byte, off int64) (n int, err error) { func (r *multiSectionReader) Size() int64 { return r.size } - -func (f *File) GetFileEntryPosition() int64 { - return int64(f.fileEntryPosition) -} - -func (f *File) FileEntry() FileEntryInterface { - if f.fe == nil { - f.fileEntryPosition = uint64(f.Fid.ICB.GetLocation()) - meta := f.Udf.LogicalPartitionStart(f.Fid.ICB.GetPartition()) - f.fe = NewFileEntry(f.Fid.ICB.GetPartition(), f.Udf.ReadSector(meta + f.fileEntryPosition)) - } - return f.fe -} - -func (f *File) getReaders(descs []ExtentInterface, filePos int64) (readers []*sectionReader, finalFilePos int64) { - finalFilePos = filePos - for i:=0; i> 0) & 7) << 0 - mode |= ((perms >> 5) & 7) << 3 - mode |= ((perms >> 10) & 7) << 6 - - if f.IsDir() { - mode |= os.ModeDir - } - - return mode -} - -func (f *File) Size() int64 { - return int64(f.FileEntry().GetInformationLength()) -} - -func (f *File) ModTime() time.Time { - return f.FileEntry().GetModificationTime() -} - -func (f *File) IsDir() bool { - return f.FileEntry().GetICBTag().FileType == 4 -} - -func (f *File) Sys() interface{} { - return f.Fid -} - -func (f *File) ReadDir() []File { - return f.Udf.ReadDir(f.FileEntry()) -} diff --git a/udf.go b/udf.go index 2ffaf32..21d7d9c 100644 --- a/udf.go +++ b/udf.go @@ -6,50 +6,25 @@ import ( ) type Udf struct { - r io.ReaderAt - isInited bool - pvd *PrimaryVolumeDescriptor - pd map[uint16]*PartitionDescriptor - lvd *LogicalVolumeDescriptor - fsd *FileSetDescriptor - root_fe FileEntryInterface + r io.ReaderAt + isInited bool + pvd *PrimaryVolumeDescriptor + pd map[uint16]*PartitionDescriptor + lvd *LogicalVolumeDescriptor + fsd *FileSetDescriptor + root_fe FileEntryInterface SECTOR_SIZE uint64 } -func (udf *Udf) PhysicalPartitionStart(partition uint16) (physical uint64) { - if udf.pd == nil { - panic(udf) - } else { - return uint64(udf.pd[partition].PartitionStartingLocation) - } -} - -func (udf *Udf) LogicalPartitionStart(partition uint16) (logical uint64) { - if udf.lvd == nil || len(udf.lvd.PartitionMaps) < 1 { - panic(udf) - } else { - return uint64(udf.lvd.PartitionMaps[partition].PartitionStart) - } -} - -func (udf *Udf) GetReader() io.ReaderAt { - return udf.r -} - -func (udf *Udf) ReadSectors(sectorNumber uint64, sectorsCount uint64) []byte { - buf := make([]byte, udf.SECTOR_SIZE*sectorsCount) - read, err := udf.r.ReadAt(buf[:], int64(udf.SECTOR_SIZE*sectorNumber)) - if err != nil { - panic(err) +func NewUdfFromReader(r io.ReaderAt) (udf *Udf, err error) { + udf = &Udf{ + r: r, + isInited: false, + pd: make(map[uint16]*PartitionDescriptor), } - /*if readed != int(udf.SECTOR_SIZE*sectorsCount) { - panic(readed) - }*/ - return buf[:read] -} -func (udf *Udf) ReadSector(sectorNumber uint64) []byte { - return udf.ReadSectors(sectorNumber, 1) + err = udf.init() + return } func (udf *Udf) init() (err error) { @@ -104,12 +79,28 @@ func (udf *Udf) init() (err error) { udf.fsd = NewFileSetDescriptor(udf.ReadSector(partitionStart + uint64(udf.lvd.LogicalVolumeContentsUse.Location.LogicalBlockNumber))) rootICB := udf.fsd.RootDirectoryICB - udf.root_fe = NewFileEntry(udf.lvd.LogicalVolumeContentsUse.GetPartition(), udf.ReadSector(udf.LogicalPartitionStart(rootICB.GetPartition()) + rootICB.GetLocation())) + udf.root_fe = NewFileEntry(udf.lvd.LogicalVolumeContentsUse.GetPartition(), udf.ReadSector(udf.LogicalPartitionStart(rootICB.GetPartition())+rootICB.GetLocation())) udf.isInited = true return } +func (udf *Udf) ReadSector(sectorNumber uint64) []byte { + return udf.ReadSectors(sectorNumber, 1) +} + +func (udf *Udf) ReadSectors(sectorNumber uint64, sectorsCount uint64) []byte { + buf := make([]byte, udf.SECTOR_SIZE*sectorsCount) + read, err := udf.r.ReadAt(buf[:], int64(udf.SECTOR_SIZE*sectorNumber)) + if err != nil { + panic(err) + } + /*if readed != int(udf.SECTOR_SIZE*sectorsCount) { + panic(readed) + }*/ + return buf[:read] +} + func (udf *Udf) ReadDir(fe FileEntryInterface) []File { udf.init() if fe == nil { @@ -120,7 +111,6 @@ func (udf *Udf) ReadDir(fe FileEntryInterface) []File { adPos := fe.GetAllocationDescriptors()[0] fdLen := uint64(adPos.GetLength()) - fdBuf := udf.ReadSectors(ps+adPos.GetLocation(), (fdLen+udf.SECTOR_SIZE-1)/udf.SECTOR_SIZE) fdOff := uint64(0) @@ -139,13 +129,22 @@ func (udf *Udf) ReadDir(fe FileEntryInterface) []File { return result } -func NewUdfFromReader(r io.ReaderAt) (udf *Udf, err error) { - udf = &Udf{ - r: r, - isInited: false, - pd: make(map[uint16]*PartitionDescriptor), +func (udf *Udf) PhysicalPartitionStart(partition uint16) (physical uint64) { + if udf.pd == nil { + panic(udf) + } else { + return uint64(udf.pd[partition].PartitionStartingLocation) } +} - err = udf.init() - return +func (udf *Udf) LogicalPartitionStart(partition uint16) (logical uint64) { + if udf.lvd == nil || len(udf.lvd.PartitionMaps) < 1 { + panic(udf) + } else { + return uint64(udf.lvd.PartitionMaps[partition].PartitionStart) + } +} + +func (udf *Udf) GetReader() io.ReaderAt { + return udf.r } From 2c300cb1e512ae052899b58297bb96ae28408c13 Mon Sep 17 00:00:00 2001 From: Cedric Halbronn Date: Fri, 11 Dec 2020 12:56:02 +0000 Subject: [PATCH 11/17] document functions --- file.go | 7 +++++++ udf.go | 20 ++++++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/file.go b/file.go index 18aa473..ba38f04 100644 --- a/file.go +++ b/file.go @@ -6,6 +6,7 @@ import ( "time" ) +// File is a os.FileInfo-compatible wrapper around an ISO-13346 "UDF" directory entry type File struct { Udf *Udf Fid *FileIdentifierDescriptor @@ -13,14 +14,17 @@ type File struct { fileEntryPosition uint64 } +// IsDir returns true if the entry is a directory or false otherwise func (f *File) IsDir() bool { return f.FileEntry().GetICBTag().FileType == 4 } +// ModTime returns the entry's recording time func (f *File) ModTime() time.Time { return f.FileEntry().GetModificationTime() } +// Mode returns os.FileMode flag set with the os.ModeDir flag enabled in case of directories func (f *File) Mode() os.FileMode { var mode os.FileMode @@ -36,10 +40,12 @@ func (f *File) Mode() os.FileMode { return mode } +// Name returns the base name of the given entry func (f *File) Name() string { return f.Fid.FileIdentifier } +// Size returns the size in bytes of the extent occupied by the file or directory func (f *File) Size() int64 { return int64(f.FileEntry().GetInformationLength()) } @@ -48,6 +54,7 @@ func (f *File) Sys() interface{} { return f.Fid } +// ReadDir returns the children entries in case of a directory func (f *File) ReadDir() []File { return f.Udf.ReadDir(f.FileEntry()) } diff --git a/udf.go b/udf.go index 21d7d9c..c3c08bf 100644 --- a/udf.go +++ b/udf.go @@ -5,6 +5,7 @@ import ( "io" ) +// Udf is a wrapper around an .iso file that allows reading its ISO-13346 "UDF" data type Udf struct { r io.ReaderAt isInited bool @@ -16,20 +17,22 @@ type Udf struct { SECTOR_SIZE uint64 } -func NewUdfFromReader(r io.ReaderAt) (udf *Udf, err error) { - udf = &Udf{ +// NewUdfFromReader returns an Udf reader reading from a given file +func NewUdfFromReader(r io.ReaderAt) (*Udf, error) { + udf := &Udf{ r: r, isInited: false, pd: make(map[uint16]*PartitionDescriptor), } - err = udf.init() - return + err := udf.init() + return udf, err } -func (udf *Udf) init() (err error) { +func (udf *Udf) init() error { + var err error if udf.isInited { - return + return nil } var anchorDesc *AnchorVolumeDescriptorPointer @@ -45,7 +48,7 @@ func (udf *Udf) init() (err error) { if anchorDesc.Descriptor.TagIdentifier != DESCRIPTOR_ANCHOR_VOLUME_POINTER || anchorDesc.Descriptor.TagChecksum != anchorDesc.Descriptor.Checksum() { err = errors.New("couldn't find sector size") - return + return err } for sector := uint64(anchorDesc.MainVolumeDescriptorSeq.Location); ; sector++ { @@ -82,7 +85,7 @@ func (udf *Udf) init() (err error) { udf.root_fe = NewFileEntry(udf.lvd.LogicalVolumeContentsUse.GetPartition(), udf.ReadSector(udf.LogicalPartitionStart(rootICB.GetPartition())+rootICB.GetLocation())) udf.isInited = true - return + return nil } func (udf *Udf) ReadSector(sectorNumber uint64) []byte { @@ -129,6 +132,7 @@ func (udf *Udf) ReadDir(fe FileEntryInterface) []File { return result } +// XXX - unused func (udf *Udf) PhysicalPartitionStart(partition uint16) (physical uint64) { if udf.pd == nil { panic(udf) From 2174a09f35729d3495277f98cdab10581208d40f Mon Sep 17 00:00:00 2001 From: Cedric Halbronn Date: Fri, 11 Dec 2020 13:00:51 +0000 Subject: [PATCH 12/17] Add debugging functions showing structures content --- descr.go | 94 +++++++++++++++++++++++++++++++++++++++++++++++-------- entity.go | 6 ++++ udf.go | 9 ++++++ 3 files changed, 96 insertions(+), 13 deletions(-) diff --git a/descr.go b/descr.go index 3a0cdf6..50698d7 100644 --- a/descr.go +++ b/descr.go @@ -1,6 +1,7 @@ package udf import ( + "fmt" "time" ) @@ -41,13 +42,13 @@ 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] - } +func (d *Descriptor) Checksum() (checksum uint8) { + for i := 0; i < 16; i++ { + if i != 4 { + checksum += d.data[i] } - return + } + return } func (d *Descriptor) FromBytes(b []byte) *Descriptor { @@ -132,6 +133,29 @@ func (pvd *PrimaryVolumeDescriptor) FromBytes(b []byte) *PrimaryVolumeDescriptor return pvd } +func (pvd *PrimaryVolumeDescriptor) Show() { + fmt.Printf("----- PrimaryVolumeDescriptor ----\n") + fmt.Printf("VolumeDescriptorSequenceNumber: %d\n", pvd.VolumeDescriptorSequenceNumber) + fmt.Printf("PrimaryVolumeDescriptorNumber: %d\n", pvd.PrimaryVolumeDescriptorNumber) + fmt.Printf("VolumeIdentifier: %s\n", pvd.VolumeIdentifier) + fmt.Printf("VolumeSequenceNumber: %d\n", pvd.VolumeSequenceNumber) + fmt.Printf("MaximumVolumeSequenceNumber: %d\n", pvd.MaximumVolumeSequenceNumber) + fmt.Printf("InterchangeLevel: %d\n", pvd.InterchangeLevel) + fmt.Printf("MaximumInterchangeLevel: %d\n", pvd.MaximumInterchangeLevel) + fmt.Printf("CharacterSetList: %d\n", pvd.CharacterSetList) + fmt.Printf("MaximumCharacterSetList: %d\n", pvd.MaximumCharacterSetList) + fmt.Printf("VolumeSetIdentifier: %s\n", pvd.VolumeSetIdentifier) + fmt.Printf("VolumeAbstract: %v\n", pvd.VolumeAbstract) + fmt.Printf("VolumeCopyrightNoticeExtent: %v\n", pvd.VolumeCopyrightNoticeExtent) + pvd.ApplicationIdentifier.Show("ApplicationIdentifier") + fmt.Printf("RecordingDateTime: %v\n", pvd.RecordingDateTime) + pvd.ImplementationIdentifier.Show("ImplementationIdentifier") + fmt.Printf("ImplementationUse: %v\n", pvd.ImplementationUse) + fmt.Printf("PredecessorVolumeDescriptorSequenceLocation: %v\n", pvd.PredecessorVolumeDescriptorSequenceLocation) + fmt.Printf("Flags: %d\n", pvd.Flags) + fmt.Printf("----- PrimaryVolumeDescriptor (end) ----\n") +} + func NewPrimaryVolumeDescriptor(b []byte) *PrimaryVolumeDescriptor { return new(PrimaryVolumeDescriptor).FromBytes(b) } @@ -169,6 +193,21 @@ func (pd *PartitionDescriptor) FromBytes(b []byte) *PartitionDescriptor { return pd } +func (pd *PartitionDescriptor) Show(i uint16) { + fmt.Printf("----- PartitionDescriptor %d ----\n", i) + fmt.Printf("VolumeDescriptorSequenceNumber: %d\n", pd.VolumeDescriptorSequenceNumber) + fmt.Printf("PartitionFlags: %d\n", pd.PartitionFlags) + fmt.Printf("PartitionNumber: %d\n", pd.PartitionNumber) + pd.ImplementationIdentifier.Show("PartitionContents") + fmt.Printf("PartitionContentsUse: %v\n", pd.PartitionContentsUse) + fmt.Printf("AccessType: %d\n", pd.AccessType) + fmt.Printf("PartitionStartingLocation: %d\n", pd.PartitionStartingLocation) + fmt.Printf("PartitionLength: %d\n", pd.PartitionLength) + pd.ImplementationIdentifier.Show("ImplementationIdentifier") + fmt.Printf("ImplementationUse: %v\n", pd.ImplementationUse) + fmt.Printf("----- PartitionDescriptor %d (end) ----\n", i) +} + func NewPartitionDescriptor(b []byte) *PartitionDescriptor { return new(PartitionDescriptor).FromBytes(b) } @@ -188,7 +227,7 @@ type PartitionMap struct { func (pm *PartitionMap) FromBytes(b []byte) *PartitionMap { pm.PartitionMapType = rb_u8(b[0:]) pm.PartitionMapLength = rb_u8(b[1:]) - offset:=0 + offset := 0 switch pm.PartitionMapType { case 1: offset = 2 @@ -201,6 +240,16 @@ func (pm *PartitionMap) FromBytes(b []byte) *PartitionMap { return pm } +func (pm *PartitionMap) Show(i uint32) { + fmt.Printf("----- PartitionMap %d ----\n", i) + fmt.Printf("PartitionMapType: %d\n", pm.PartitionMapType) + fmt.Printf("PartitionMapLength: %d\n", pm.PartitionMapLength) + fmt.Printf("VolumeSequenceNumber: %d\n", pm.VolumeSequenceNumber) + fmt.Printf("PartitionNumber: %d\n", pm.PartitionNumber) + fmt.Printf("PartitionStart: %d\n", pm.PartitionStart) + fmt.Printf("----- PartitionMap %d (end) ----\n", i) +} + type LogicalVolumeDescriptor struct { Descriptor Descriptor VolumeDescriptorSequenceNumber uint32 @@ -235,6 +284,25 @@ func (lvd *LogicalVolumeDescriptor) FromBytes(b []byte) *LogicalVolumeDescriptor return lvd } +func (lvd *LogicalVolumeDescriptor) Show() { + fmt.Printf("----- LogicalVolumeDescriptor ----\n") + fmt.Printf("VolumeDescriptorSequenceNumber: %v\n", lvd.VolumeDescriptorSequenceNumber) + fmt.Printf("LogicalVolumeIdentifier: %v\n", lvd.LogicalVolumeIdentifier) + fmt.Printf("LogicalBlockSize: %v\n", lvd.LogicalBlockSize) + lvd.DomainIdentifier.Show("DomainIdentifier") + fmt.Printf("LogicalVolumeContentsUse: %v\n", lvd.LogicalVolumeContentsUse) + fmt.Printf("MapTableLength: %v\n", lvd.MapTableLength) + fmt.Printf("NumberOfPartitionMaps: %v\n", lvd.NumberOfPartitionMaps) + lvd.ImplementationIdentifier.Show("ImplementationIdentifier") + fmt.Printf("ImplementationUse: %v\n", lvd.ImplementationUse) + fmt.Printf("IntegritySequenceExtent: %v\n", lvd.IntegritySequenceExtent) + fmt.Printf("PartitionMaps: %v\n", lvd.PartitionMaps) + for i := uint32(0); i < lvd.NumberOfPartitionMaps; i++ { + lvd.PartitionMaps[i].Show(i) + } + fmt.Printf("----- LogicalVolumeDescriptor (end) ----\n") +} + func NewLogicalVolumeDescriptor(b []byte) *LogicalVolumeDescriptor { return new(LogicalVolumeDescriptor).FromBytes(b) } @@ -358,14 +426,14 @@ type FileEntry struct { ExtendedAttributes []byte AllocationDescriptors []byte // Manual field - Partition uint16 + Partition uint16 } type ExtendedFileEntry struct { FileEntry - CreationTime time.Time - ObjectSize uint64 - StreamDirectoryIcb ExtentLong + CreationTime time.Time + ObjectSize uint64 + StreamDirectoryIcb ExtentLong } func (fe *FileEntry) FromBytes(b []byte) *FileEntry { @@ -394,7 +462,7 @@ func (fe *FileEntry) FromBytes(b []byte) *FileEntry { return nil } fe.ExtendedAttributes = b[176:allocDescStart] - fe.AllocationDescriptors = b[allocDescStart:allocDescStart+fe.LengthOfAllocationDescriptors] + fe.AllocationDescriptors = b[allocDescStart : allocDescStart+fe.LengthOfAllocationDescriptors] return fe } @@ -498,7 +566,7 @@ func (fe *ExtendedFileEntry) FromBytes(b []byte) *ExtendedFileEntry { return nil } fe.ExtendedAttributes = b[216:allocDescStart] - fe.AllocationDescriptors = b[allocDescStart:allocDescStart+fe.LengthOfAllocationDescriptors] + fe.AllocationDescriptors = b[allocDescStart : allocDescStart+fe.LengthOfAllocationDescriptors] return fe } diff --git a/entity.go b/entity.go index 3f9ef0f..1f68006 100644 --- a/entity.go +++ b/entity.go @@ -1,11 +1,17 @@ package udf +import "fmt" + type EntityID struct { Flags uint8 Identifier [23]byte IdentifierSuffix [8]byte } +func (e *EntityID) Show(name string) { + fmt.Printf("%s: %d - %s - %v\n", name, e.Flags, string(e.Identifier[:]), e.IdentifierSuffix) +} + func NewEntityID(b []byte) EntityID { e := EntityID{Flags: b[0]} copy(e.Identifier[:], b[1:24]) diff --git a/udf.go b/udf.go index c3c08bf..ac3f131 100644 --- a/udf.go +++ b/udf.go @@ -44,6 +44,7 @@ func (udf *Udf) init() error { break } } + //fmt.Printf("udf.SECTOR_SIZE = %d\n", udf.SECTOR_SIZE) if anchorDesc.Descriptor.TagIdentifier != DESCRIPTOR_ANCHOR_VOLUME_POINTER || anchorDesc.Descriptor.TagChecksum != anchorDesc.Descriptor.Checksum() { @@ -67,6 +68,14 @@ func (udf *Udf) init() error { } } + // DEBUGGING ONLY + // udf.pvd.Show() + // for i, pd := range udf.pd { + // pd.Show(i) + // } + // udf.lvd.Show() + // DEBUGGING ONLY - end + for i, pMap := range udf.lvd.PartitionMaps { if pMap.PartitionMapType != 2 { udf.lvd.PartitionMaps[i].PartitionStart = udf.pd[pMap.PartitionNumber].PartitionStartingLocation From 5bcccfa623fa1d75b8e50fff4955ae95732efca8 Mon Sep 17 00:00:00 2001 From: Cedric Halbronn Date: Fri, 11 Dec 2020 13:16:06 +0000 Subject: [PATCH 13/17] fixes to be able to parse Microsoft Windows ISOs --- descr.go | 4 +++- udf.go | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/descr.go b/descr.go index 50698d7..f1d7ec3 100644 --- a/descr.go +++ b/descr.go @@ -235,7 +235,9 @@ func (pm *PartitionMap) FromBytes(b []byte) *PartitionMap { offset = 36 } pm.VolumeSequenceNumber = rb_u16(b[offset:]) - pm.PartitionNumber = rb_u16(b[offset+2:]) + // 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 } diff --git a/udf.go b/udf.go index ac3f131..00a8456 100644 --- a/udf.go +++ b/udf.go @@ -2,7 +2,9 @@ package udf import ( "errors" + "fmt" "io" + "unsafe" ) // Udf is a wrapper around an .iso file that allows reading its ISO-13346 "UDF" data @@ -78,6 +80,12 @@ func (udf *Udf) init() error { for i, pMap := range udf.lvd.PartitionMaps { if pMap.PartitionMapType != 2 { + // Check to error early if there is no match with a partition number + if _, ok := udf.pd[pMap.PartitionNumber]; !ok { + msg := fmt.Sprintf("could not find partition number: %d\n", pMap.PartitionNumber) + err = errors.New(msg) + return err + } udf.lvd.PartitionMaps[i].PartitionStart = udf.pd[pMap.PartitionNumber].PartitionStartingLocation continue } @@ -127,8 +135,14 @@ func (udf *Udf) ReadDir(fe FileEntryInterface) []File { fdOff := uint64(0) result := make([]File, 0) - + var dummy *FileIdentifierDescriptor + fidSize := int(unsafe.Sizeof(*dummy)) for uint32(fdOff) < adPos.GetLength() { + // Some Windows ISOs have some padding data that we can ignore? + if len(fdBuf[fdOff:]) < fidSize { + //fmt.Printf("WARNING: skipping incomplete data\n") + break + } fid := NewFileIdentifierDescriptor(fdBuf[fdOff:]) if fid.FileIdentifier != "" { result = append(result, File{ From 5b86d625579ac85f6297e1caa800b0cd297e05f5 Mon Sep 17 00:00:00 2001 From: Cedric Halbronn Date: Fri, 11 Dec 2020 13:16:23 +0000 Subject: [PATCH 14/17] fix test example + readme --- README.md | 18 ++++++++++++------ isoinfo/isoinfo.go | 7 +++++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 5389cb0..053107a 100644 --- a/README.md +++ b/README.md @@ -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/saidelike/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: ``` @@ -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 diff --git a/isoinfo/isoinfo.go b/isoinfo/isoinfo.go index 84e53f5..452c57d 100644 --- a/isoinfo/isoinfo.go +++ b/isoinfo/isoinfo.go @@ -5,7 +5,7 @@ import ( "fmt" "os" - "github.com/mogaika/udf" + "github.com/saidelike/udf" ) func printDir(spaces string, files []udf.File) { @@ -24,7 +24,10 @@ func main() { panic(err) } - u := udf.NewUdfFromReader(rdr) + u, err := udf.NewUdfFromReader(rdr) + if err != nil { + panic(err) + } printDir("", u.ReadDir(nil)) } From 3426b1fa5a7e1a860ac005a8bd12a09a487d6b05 Mon Sep 17 00:00:00 2001 From: Cedric Halbronn Date: Fri, 11 Dec 2020 13:48:38 +0000 Subject: [PATCH 15/17] make the Reader available outside of the lib so we can do memory-only data reading of files --- file.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/file.go b/file.go index ba38f04..cf8a76e 100644 --- a/file.go +++ b/file.go @@ -89,7 +89,7 @@ func (f *File) getReaders(descs []ExtentInterface, filePos int64) (readers []*se return } -func (f *File) NewReader() *multiSectionReader { +func (f *File) NewReader() *MultiSectionReader { descs := f.FileEntry().GetAllocationDescriptors() readers, _ := f.getReaders(descs, 0) return newMultiSectionReader(readers) @@ -109,25 +109,25 @@ func newSectionReader(inFileStart int64, reader io.ReaderAt, start int64, size i } } -type multiSectionReader struct { +type MultiSectionReader struct { readers []*sectionReader pos int64 size int64 index int } -func newMultiSectionReader(readers []*sectionReader) *multiSectionReader { +func newMultiSectionReader(readers []*sectionReader) *MultiSectionReader { var size int64 for _, reader := range readers { size += reader.size } - return &multiSectionReader{ + return &MultiSectionReader{ readers: readers, size: size, } } -func (r *multiSectionReader) Read(p []byte) (n int, err error) { +func (r *MultiSectionReader) Read(p []byte) (n int, err error) { if r.index > len(r.readers)-1 { return 0, io.EOF } @@ -148,7 +148,7 @@ func (r *multiSectionReader) Read(p []byte) (n int, err error) { return } -func (r *multiSectionReader) Seek(offset int64, whence int) (n int64, err error) { +func (r *MultiSectionReader) Seek(offset int64, whence int) (n int64, err error) { switch whence { case io.SeekStart: n = offset @@ -171,7 +171,7 @@ func (r *multiSectionReader) Seek(offset int64, whence int) (n int64, err error) return } -func (r *multiSectionReader) ReadAt(p []byte, off int64) (n int, err error) { +func (r *MultiSectionReader) ReadAt(p []byte, off int64) (n int, err error) { var read int err = os.ErrNotExist // No readers for _, reader := range r.readers { @@ -186,6 +186,6 @@ func (r *multiSectionReader) ReadAt(p []byte, off int64) (n int, err error) { return } -func (r *multiSectionReader) Size() int64 { +func (r *MultiSectionReader) Size() int64 { return r.size } From d17585b6ebc3d5602ac673273499d878bcd862db Mon Sep 17 00:00:00 2001 From: Xmister Date: Sat, 16 Jan 2021 17:54:38 +0100 Subject: [PATCH 16/17] Remove unnecessary bloat --- README.md | 2 +- descr.go | 68 ---------------------------------------------- entity.go | 6 ---- isoinfo/isoinfo.go | 2 +- udf.go | 14 ++++------ 5 files changed, 7 insertions(+), 85 deletions(-) diff --git a/README.md b/README.md index 053107a..654b34f 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ package main import ( "fmt" "os" - "github.com/saidelike/udf" + "github.com/Xmister/udf" ) func main() { diff --git a/descr.go b/descr.go index f1d7ec3..c6b61ed 100644 --- a/descr.go +++ b/descr.go @@ -1,7 +1,6 @@ package udf import ( - "fmt" "time" ) @@ -133,29 +132,6 @@ func (pvd *PrimaryVolumeDescriptor) FromBytes(b []byte) *PrimaryVolumeDescriptor return pvd } -func (pvd *PrimaryVolumeDescriptor) Show() { - fmt.Printf("----- PrimaryVolumeDescriptor ----\n") - fmt.Printf("VolumeDescriptorSequenceNumber: %d\n", pvd.VolumeDescriptorSequenceNumber) - fmt.Printf("PrimaryVolumeDescriptorNumber: %d\n", pvd.PrimaryVolumeDescriptorNumber) - fmt.Printf("VolumeIdentifier: %s\n", pvd.VolumeIdentifier) - fmt.Printf("VolumeSequenceNumber: %d\n", pvd.VolumeSequenceNumber) - fmt.Printf("MaximumVolumeSequenceNumber: %d\n", pvd.MaximumVolumeSequenceNumber) - fmt.Printf("InterchangeLevel: %d\n", pvd.InterchangeLevel) - fmt.Printf("MaximumInterchangeLevel: %d\n", pvd.MaximumInterchangeLevel) - fmt.Printf("CharacterSetList: %d\n", pvd.CharacterSetList) - fmt.Printf("MaximumCharacterSetList: %d\n", pvd.MaximumCharacterSetList) - fmt.Printf("VolumeSetIdentifier: %s\n", pvd.VolumeSetIdentifier) - fmt.Printf("VolumeAbstract: %v\n", pvd.VolumeAbstract) - fmt.Printf("VolumeCopyrightNoticeExtent: %v\n", pvd.VolumeCopyrightNoticeExtent) - pvd.ApplicationIdentifier.Show("ApplicationIdentifier") - fmt.Printf("RecordingDateTime: %v\n", pvd.RecordingDateTime) - pvd.ImplementationIdentifier.Show("ImplementationIdentifier") - fmt.Printf("ImplementationUse: %v\n", pvd.ImplementationUse) - fmt.Printf("PredecessorVolumeDescriptorSequenceLocation: %v\n", pvd.PredecessorVolumeDescriptorSequenceLocation) - fmt.Printf("Flags: %d\n", pvd.Flags) - fmt.Printf("----- PrimaryVolumeDescriptor (end) ----\n") -} - func NewPrimaryVolumeDescriptor(b []byte) *PrimaryVolumeDescriptor { return new(PrimaryVolumeDescriptor).FromBytes(b) } @@ -193,21 +169,6 @@ func (pd *PartitionDescriptor) FromBytes(b []byte) *PartitionDescriptor { return pd } -func (pd *PartitionDescriptor) Show(i uint16) { - fmt.Printf("----- PartitionDescriptor %d ----\n", i) - fmt.Printf("VolumeDescriptorSequenceNumber: %d\n", pd.VolumeDescriptorSequenceNumber) - fmt.Printf("PartitionFlags: %d\n", pd.PartitionFlags) - fmt.Printf("PartitionNumber: %d\n", pd.PartitionNumber) - pd.ImplementationIdentifier.Show("PartitionContents") - fmt.Printf("PartitionContentsUse: %v\n", pd.PartitionContentsUse) - fmt.Printf("AccessType: %d\n", pd.AccessType) - fmt.Printf("PartitionStartingLocation: %d\n", pd.PartitionStartingLocation) - fmt.Printf("PartitionLength: %d\n", pd.PartitionLength) - pd.ImplementationIdentifier.Show("ImplementationIdentifier") - fmt.Printf("ImplementationUse: %v\n", pd.ImplementationUse) - fmt.Printf("----- PartitionDescriptor %d (end) ----\n", i) -} - func NewPartitionDescriptor(b []byte) *PartitionDescriptor { return new(PartitionDescriptor).FromBytes(b) } @@ -242,16 +203,6 @@ func (pm *PartitionMap) FromBytes(b []byte) *PartitionMap { return pm } -func (pm *PartitionMap) Show(i uint32) { - fmt.Printf("----- PartitionMap %d ----\n", i) - fmt.Printf("PartitionMapType: %d\n", pm.PartitionMapType) - fmt.Printf("PartitionMapLength: %d\n", pm.PartitionMapLength) - fmt.Printf("VolumeSequenceNumber: %d\n", pm.VolumeSequenceNumber) - fmt.Printf("PartitionNumber: %d\n", pm.PartitionNumber) - fmt.Printf("PartitionStart: %d\n", pm.PartitionStart) - fmt.Printf("----- PartitionMap %d (end) ----\n", i) -} - type LogicalVolumeDescriptor struct { Descriptor Descriptor VolumeDescriptorSequenceNumber uint32 @@ -286,25 +237,6 @@ func (lvd *LogicalVolumeDescriptor) FromBytes(b []byte) *LogicalVolumeDescriptor return lvd } -func (lvd *LogicalVolumeDescriptor) Show() { - fmt.Printf("----- LogicalVolumeDescriptor ----\n") - fmt.Printf("VolumeDescriptorSequenceNumber: %v\n", lvd.VolumeDescriptorSequenceNumber) - fmt.Printf("LogicalVolumeIdentifier: %v\n", lvd.LogicalVolumeIdentifier) - fmt.Printf("LogicalBlockSize: %v\n", lvd.LogicalBlockSize) - lvd.DomainIdentifier.Show("DomainIdentifier") - fmt.Printf("LogicalVolumeContentsUse: %v\n", lvd.LogicalVolumeContentsUse) - fmt.Printf("MapTableLength: %v\n", lvd.MapTableLength) - fmt.Printf("NumberOfPartitionMaps: %v\n", lvd.NumberOfPartitionMaps) - lvd.ImplementationIdentifier.Show("ImplementationIdentifier") - fmt.Printf("ImplementationUse: %v\n", lvd.ImplementationUse) - fmt.Printf("IntegritySequenceExtent: %v\n", lvd.IntegritySequenceExtent) - fmt.Printf("PartitionMaps: %v\n", lvd.PartitionMaps) - for i := uint32(0); i < lvd.NumberOfPartitionMaps; i++ { - lvd.PartitionMaps[i].Show(i) - } - fmt.Printf("----- LogicalVolumeDescriptor (end) ----\n") -} - func NewLogicalVolumeDescriptor(b []byte) *LogicalVolumeDescriptor { return new(LogicalVolumeDescriptor).FromBytes(b) } diff --git a/entity.go b/entity.go index 1f68006..3f9ef0f 100644 --- a/entity.go +++ b/entity.go @@ -1,17 +1,11 @@ package udf -import "fmt" - type EntityID struct { Flags uint8 Identifier [23]byte IdentifierSuffix [8]byte } -func (e *EntityID) Show(name string) { - fmt.Printf("%s: %d - %s - %v\n", name, e.Flags, string(e.Identifier[:]), e.IdentifierSuffix) -} - func NewEntityID(b []byte) EntityID { e := EntityID{Flags: b[0]} copy(e.Identifier[:], b[1:24]) diff --git a/isoinfo/isoinfo.go b/isoinfo/isoinfo.go index 452c57d..010a9ba 100644 --- a/isoinfo/isoinfo.go +++ b/isoinfo/isoinfo.go @@ -5,7 +5,7 @@ import ( "fmt" "os" - "github.com/saidelike/udf" + "github.com/Xmister/udf" ) func printDir(spaces string, files []udf.File) { diff --git a/udf.go b/udf.go index 00a8456..aded3e1 100644 --- a/udf.go +++ b/udf.go @@ -2,7 +2,6 @@ package udf import ( "errors" - "fmt" "io" "unsafe" ) @@ -31,10 +30,9 @@ func NewUdfFromReader(r io.ReaderAt) (*Udf, error) { return udf, err } -func (udf *Udf) init() error { - var err error +func (udf *Udf) init() (err error) { if udf.isInited { - return nil + return } var anchorDesc *AnchorVolumeDescriptorPointer @@ -51,7 +49,7 @@ func (udf *Udf) init() error { if anchorDesc.Descriptor.TagIdentifier != DESCRIPTOR_ANCHOR_VOLUME_POINTER || anchorDesc.Descriptor.TagChecksum != anchorDesc.Descriptor.Checksum() { err = errors.New("couldn't find sector size") - return err + return } for sector := uint64(anchorDesc.MainVolumeDescriptorSeq.Location); ; sector++ { @@ -82,9 +80,7 @@ func (udf *Udf) init() error { if pMap.PartitionMapType != 2 { // Check to error early if there is no match with a partition number if _, ok := udf.pd[pMap.PartitionNumber]; !ok { - msg := fmt.Sprintf("could not find partition number: %d\n", pMap.PartitionNumber) - err = errors.New(msg) - return err + return errors.New("could not find partition number") } udf.lvd.PartitionMaps[i].PartitionStart = udf.pd[pMap.PartitionNumber].PartitionStartingLocation continue @@ -102,7 +98,7 @@ func (udf *Udf) init() error { udf.root_fe = NewFileEntry(udf.lvd.LogicalVolumeContentsUse.GetPartition(), udf.ReadSector(udf.LogicalPartitionStart(rootICB.GetPartition())+rootICB.GetLocation())) udf.isInited = true - return nil + return } func (udf *Udf) ReadSector(sectorNumber uint64) []byte { From 6c18325874a7a6c9a10afc1737bcf6b42b50002c Mon Sep 17 00:00:00 2001 From: Xmister Date: Sat, 16 Jan 2021 18:17:53 +0100 Subject: [PATCH 17/17] Fix reads --- file.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/file.go b/file.go index cf8a76e..b7d8e14 100644 --- a/file.go +++ b/file.go @@ -127,10 +127,7 @@ func newMultiSectionReader(readers []*sectionReader) *MultiSectionReader { } } -func (r *MultiSectionReader) Read(p []byte) (n int, err error) { - if r.index > len(r.readers)-1 { - return 0, io.EOF - } +func (r *MultiSectionReader) actualRead(p []byte) (n int, err error) { n, err = r.readers[r.index].Read(p) r.pos += int64(n) if err != nil { @@ -138,7 +135,7 @@ func (r *MultiSectionReader) Read(p []byte) (n int, err error) { r.index++ r.readers[r.index].Seek(0, 0) if n == 0 { - n, err = r.Read(p) + n, err = r.actualRead(p) } } } @@ -148,6 +145,13 @@ func (r *MultiSectionReader) Read(p []byte) (n int, err error) { return } +func (r *MultiSectionReader) Read(p []byte) (n int, err error) { + if r.index > len(r.readers)-1 { + return 0, io.EOF + } + return r.actualRead(p) +} + func (r *MultiSectionReader) Seek(offset int64, whence int) (n int64, err error) { switch whence { case io.SeekStart: