public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { // UDF is always UTF-8 Encoding = Encoding.UTF8; byte[] sector; StringBuilder sbInformation = new StringBuilder(); sbInformation.AppendLine("Universal Disk Format"); AnchorVolumeDescriptorPointer anchor = new AnchorVolumeDescriptorPointer(); // All positions where anchor may reside ulong[] positions = { 256, 512, partition.End - 256, partition.End }; foreach (ulong position in positions) { sector = imagePlugin.ReadSector(position); anchor = new AnchorVolumeDescriptorPointer(); IntPtr anchorPtr = Marshal.AllocHGlobal(Marshal.SizeOf(anchor)); Marshal.Copy(sector, 0, anchorPtr, Marshal.SizeOf(anchor)); anchor = (AnchorVolumeDescriptorPointer)Marshal.PtrToStructure(anchorPtr, typeof(AnchorVolumeDescriptorPointer)); Marshal.FreeHGlobal(anchorPtr); if (anchor.tag.tagIdentifier == TagIdentifier.AnchorVolumeDescriptorPointer && anchor.tag.tagLocation == position && anchor.mainVolumeDescriptorSequenceExtent.location + partition.Start < partition.End) { break; } } ulong count = 0; PrimaryVolumeDescriptor pvd = new PrimaryVolumeDescriptor(); LogicalVolumeDescriptor lvd = new LogicalVolumeDescriptor(); LogicalVolumeIntegrityDescriptor lvid = new LogicalVolumeIntegrityDescriptor(); LogicalVolumeIntegrityDescriptorImplementationUse lvidiu = new LogicalVolumeIntegrityDescriptorImplementationUse(); while (count < 256) { sector = imagePlugin.ReadSector(partition.Start + anchor.mainVolumeDescriptorSequenceExtent.location + count); TagIdentifier tagId = (TagIdentifier)BitConverter.ToUInt16(sector, 0); uint location = BitConverter.ToUInt32(sector, 0x0C); if (location == partition.Start + anchor.mainVolumeDescriptorSequenceExtent.location + count) { if (tagId == TagIdentifier.TerminatingDescriptor) { break; } switch (tagId) { case TagIdentifier.LogicalVolumeDescriptor: IntPtr lvdPtr = Marshal.AllocHGlobal(Marshal.SizeOf(lvd)); Marshal.Copy(sector, 0, lvdPtr, Marshal.SizeOf(lvd)); lvd = (LogicalVolumeDescriptor) Marshal.PtrToStructure(lvdPtr, typeof(LogicalVolumeDescriptor)); Marshal.FreeHGlobal(lvdPtr); break; case TagIdentifier.PrimaryVolumeDescriptor: IntPtr pvdPtr = Marshal.AllocHGlobal(Marshal.SizeOf(pvd)); Marshal.Copy(sector, 0, pvdPtr, Marshal.SizeOf(pvd)); pvd = (PrimaryVolumeDescriptor) Marshal.PtrToStructure(pvdPtr, typeof(PrimaryVolumeDescriptor)); Marshal.FreeHGlobal(pvdPtr); break; } } else { break; } count++; } sector = imagePlugin.ReadSector(lvd.integritySequenceExtent.location); IntPtr lvidPtr = Marshal.AllocHGlobal(Marshal.SizeOf(lvid)); Marshal.Copy(sector, 0, lvidPtr, Marshal.SizeOf(lvid)); lvid = (LogicalVolumeIntegrityDescriptor) Marshal.PtrToStructure(lvidPtr, typeof(LogicalVolumeIntegrityDescriptor)); Marshal.FreeHGlobal(lvidPtr); if (lvid.tag.tagIdentifier == TagIdentifier.LogicalVolumeIntegrityDescriptor && lvid.tag.tagLocation == lvd.integritySequenceExtent.location) { IntPtr lvidiuPtr = Marshal.AllocHGlobal(Marshal.SizeOf(lvidiu)); Marshal.Copy(sector, (int)(lvid.numberOfPartitions * 8 + 80), lvidiuPtr, Marshal.SizeOf(lvidiu)); lvidiu = (LogicalVolumeIntegrityDescriptorImplementationUse)Marshal.PtrToStructure(lvidiuPtr, typeof( LogicalVolumeIntegrityDescriptorImplementationUse )); Marshal.FreeHGlobal(lvidiuPtr); } else { lvid = new LogicalVolumeIntegrityDescriptor(); } sbInformation.AppendFormat("Volume is number {0} of {1}", pvd.volumeSequenceNumber, pvd.maximumVolumeSequenceNumber).AppendLine(); sbInformation.AppendFormat("Volume set identifier: {0}", StringHandlers.DecompressUnicode(pvd.volumeSetIdentifier)).AppendLine(); sbInformation .AppendFormat("Volume name: {0}", StringHandlers.DecompressUnicode(lvd.logicalVolumeIdentifier)) .AppendLine(); sbInformation.AppendFormat("Volume uses {0} bytes per block", lvd.logicalBlockSize).AppendLine(); sbInformation.AppendFormat("Volume was las written in {0}", EcmaToDateTime(lvid.recordingDateTime)) .AppendLine(); sbInformation.AppendFormat("Volume contains {0} partitions", lvid.numberOfPartitions).AppendLine(); sbInformation .AppendFormat("Volume contains {0} files and {1} directories", lvidiu.files, lvidiu.directories) .AppendLine(); sbInformation.AppendFormat("Volume conforms to {0}", Encoding.GetString(lvd.domainIdentifier.identifier).TrimEnd('\u0000')) .AppendLine(); sbInformation.AppendFormat("Volume was last written by: {0}", Encoding.GetString(pvd.implementationIdentifier.identifier).TrimEnd('\u0000')) .AppendLine(); sbInformation.AppendFormat("Volume requires UDF version {0}.{1:X2} to be read", Convert.ToInt32($"{(lvidiu.minimumReadUDF & 0xFF00) >> 8}", 10), Convert.ToInt32($"{lvidiu.minimumReadUDF & 0xFF}", 10)).AppendLine(); sbInformation.AppendFormat("Volume requires UDF version {0}.{1:X2} to be written to", Convert.ToInt32($"{(lvidiu.minimumWriteUDF & 0xFF00) >> 8}", 10), Convert.ToInt32($"{lvidiu.minimumWriteUDF & 0xFF}", 10)).AppendLine(); sbInformation.AppendFormat("Volume cannot be written by any UDF version higher than {0}.{1:X2}", Convert.ToInt32($"{(lvidiu.maximumWriteUDF & 0xFF00) >> 8}", 10), Convert.ToInt32($"{lvidiu.maximumWriteUDF & 0xFF}", 10)).AppendLine(); XmlFsType = new FileSystemType { Type = $"UDF v{Convert.ToInt32($"{(lvidiu.maximumWriteUDF & 0xFF00) >> 8}", 10)}.{Convert.ToInt32($"{lvidiu.maximumWriteUDF & 0xFF}", 10):X2}", ApplicationIdentifier = Encoding.GetString(pvd.implementationIdentifier.identifier).TrimEnd('\u0000'), ClusterSize = (int)lvd.logicalBlockSize, ModificationDate = EcmaToDateTime(lvid.recordingDateTime), ModificationDateSpecified = true, Files = lvidiu.files, FilesSpecified = true, VolumeName = StringHandlers.DecompressUnicode(lvd.logicalVolumeIdentifier), VolumeSetIdentifier = StringHandlers.DecompressUnicode(pvd.volumeSetIdentifier), SystemIdentifier = Encoding.GetString(pvd.implementationIdentifier.identifier).TrimEnd('\u0000') }; XmlFsType.Clusters = (long)((partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / (ulong)XmlFsType.ClusterSize); information = sbInformation.ToString(); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { // UDF is always UTF-8 Encoding = Encoding.UTF8; byte[] sector; var sbInformation = new StringBuilder(); sbInformation.AppendLine("Universal Disk Format"); var anchor = new AnchorVolumeDescriptorPointer(); // All positions where anchor may reside, with the ratio between 512 and 2048bps ulong[][] positions = { new ulong[] { 256, 1 }, new ulong[] { 512, 1 }, new ulong[] { partition.End - 256, 1 }, new ulong[] { partition.End, 1 }, new ulong[] { 1024, 4 }, new ulong[] { 2048, 4 }, new ulong[] { partition.End - 1024, 4 }, new ulong[] { partition.End - 4, 4 } }; uint ratio = 1; foreach(ulong[] position in positions) { sector = imagePlugin.ReadSectors(position[0], (uint)position[1]); anchor = Marshal.ByteArrayToStructureLittleEndian<AnchorVolumeDescriptorPointer>(sector); if(anchor.tag.tagIdentifier != TagIdentifier.AnchorVolumeDescriptorPointer || anchor.tag.tagLocation != position[0] / position[1] || anchor.mainVolumeDescriptorSequenceExtent.location + partition.Start >= partition.End) continue; ratio = (uint)position[1]; break; } ulong count = 0; var pvd = new PrimaryVolumeDescriptor(); var lvd = new LogicalVolumeDescriptor(); var lvid = new LogicalVolumeIntegrityDescriptor(); var lvidiu = new LogicalVolumeIntegrityDescriptorImplementationUse(); while(count < 256) { sector = imagePlugin. ReadSectors(partition.Start + (anchor.mainVolumeDescriptorSequenceExtent.location * ratio) + (count * ratio), ratio); var tagId = (TagIdentifier)BitConverter.ToUInt16(sector, 0); uint location = BitConverter.ToUInt32(sector, 0x0C); if(location == (partition.Start / ratio) + anchor.mainVolumeDescriptorSequenceExtent.location + count) { if(tagId == TagIdentifier.TerminatingDescriptor) break; switch(tagId) { case TagIdentifier.LogicalVolumeDescriptor: lvd = Marshal.ByteArrayToStructureLittleEndian<LogicalVolumeDescriptor>(sector); break; case TagIdentifier.PrimaryVolumeDescriptor: pvd = Marshal.ByteArrayToStructureLittleEndian<PrimaryVolumeDescriptor>(sector); break; } } else break; count++; } sector = imagePlugin.ReadSectors(lvd.integritySequenceExtent.location * ratio, ratio); lvid = Marshal.ByteArrayToStructureLittleEndian<LogicalVolumeIntegrityDescriptor>(sector); if(lvid.tag.tagIdentifier == TagIdentifier.LogicalVolumeIntegrityDescriptor && lvid.tag.tagLocation == lvd.integritySequenceExtent.location) lvidiu = Marshal.ByteArrayToStructureLittleEndian<LogicalVolumeIntegrityDescriptorImplementationUse>(sector, (int)((lvid.numberOfPartitions * 8) + 80), System.Runtime.InteropServices.Marshal.SizeOf(lvidiu)); else lvid = new LogicalVolumeIntegrityDescriptor(); sbInformation.AppendFormat("Volume is number {0} of {1}", pvd.volumeSequenceNumber, pvd.maximumVolumeSequenceNumber).AppendLine(); sbInformation.AppendFormat("Volume set identifier: {0}", StringHandlers.DecompressUnicode(pvd.volumeSetIdentifier)).AppendLine(); sbInformation. AppendFormat("Volume name: {0}", StringHandlers.DecompressUnicode(lvd.logicalVolumeIdentifier)). AppendLine(); sbInformation.AppendFormat("Volume uses {0} bytes per block", lvd.logicalBlockSize).AppendLine(); sbInformation.AppendFormat("Volume was last written in {0}", EcmaToDateTime(lvid.recordingDateTime)). AppendLine(); sbInformation.AppendFormat("Volume contains {0} partitions", lvid.numberOfPartitions).AppendLine(); sbInformation. AppendFormat("Volume contains {0} files and {1} directories", lvidiu.files, lvidiu.directories). AppendLine(); sbInformation.AppendFormat("Volume conforms to {0}", Encoding.GetString(lvd.domainIdentifier.identifier).TrimEnd('\u0000')). AppendLine(); sbInformation.AppendFormat("Volume was last written by: {0}", Encoding.GetString(pvd.implementationIdentifier.identifier).TrimEnd('\u0000')). AppendLine(); sbInformation.AppendFormat("Volume requires UDF version {0}.{1:X2} to be read", Convert.ToInt32($"{(lvidiu.minimumReadUDF & 0xFF00) >> 8}", 10), Convert.ToInt32($"{lvidiu.minimumReadUDF & 0xFF}", 10)).AppendLine(); sbInformation.AppendFormat("Volume requires UDF version {0}.{1:X2} to be written to", Convert.ToInt32($"{(lvidiu.minimumWriteUDF & 0xFF00) >> 8}", 10), Convert.ToInt32($"{lvidiu.minimumWriteUDF & 0xFF}", 10)).AppendLine(); sbInformation.AppendFormat("Volume cannot be written by any UDF version higher than {0}.{1:X2}", Convert.ToInt32($"{(lvidiu.maximumWriteUDF & 0xFF00) >> 8}", 10), Convert.ToInt32($"{lvidiu.maximumWriteUDF & 0xFF}", 10)).AppendLine(); XmlFsType = new FileSystemType { Type = $"UDF v{Convert.ToInt32($"{(lvidiu.maximumWriteUDF & 0xFF00) >> 8}", 10)}.{Convert.ToInt32($"{lvidiu.maximumWriteUDF & 0xFF}", 10):X2}", ApplicationIdentifier = Encoding.GetString(pvd.implementationIdentifier.identifier).TrimEnd('\u0000'), ClusterSize = lvd.logicalBlockSize, ModificationDate = EcmaToDateTime(lvid.recordingDateTime), ModificationDateSpecified = true, Files = lvidiu.files, FilesSpecified = true, VolumeName = StringHandlers.DecompressUnicode(lvd.logicalVolumeIdentifier), VolumeSetIdentifier = StringHandlers.DecompressUnicode(pvd.volumeSetIdentifier), VolumeSerial = StringHandlers.DecompressUnicode(pvd.volumeSetIdentifier), SystemIdentifier = Encoding.GetString(pvd.implementationIdentifier.identifier).TrimEnd('\u0000') }; XmlFsType.Clusters = (partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / XmlFsType.ClusterSize; information = sbInformation.ToString(); }