public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-1"); information = ""; StringBuilder sb = new StringBuilder(); byte[] hbSector = imagePlugin.ReadSector(1 + partition.Start); GCHandle handle = GCHandle.Alloc(hbSector, GCHandleType.Pinned); OdsHomeBlock homeblock = (OdsHomeBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(OdsHomeBlock)); handle.Free(); // Optical disc if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc && StringHandlers.CToString(homeblock.format) != "DECFILE11A " && StringHandlers.CToString(homeblock.format) != "DECFILE11B ") { if (hbSector.Length < 0x400) { return; } byte[] tmp = imagePlugin.ReadSector(partition.Start); hbSector = new byte[0x200]; Array.Copy(tmp, 0x200, hbSector, 0, 0x200); handle = GCHandle.Alloc(hbSector, GCHandleType.Pinned); homeblock = (OdsHomeBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(OdsHomeBlock)); handle.Free(); if (StringHandlers.CToString(homeblock.format) != "DECFILE11A " && StringHandlers.CToString(homeblock.format) != "DECFILE11B ") { return; } } if ((homeblock.struclev & 0xFF00) != 0x0200 || (homeblock.struclev & 0xFF) != 1 || StringHandlers.CToString(homeblock.format) != "DECFILE11B ") { sb.AppendLine("The following information may be incorrect for this volume."); } if (homeblock.resfiles < 5 || homeblock.devtype != 0) { sb.AppendLine("This volume may be corrupted."); } sb.AppendFormat("Volume format is {0}", StringHandlers.SpacePaddedToString(homeblock.format, Encoding)) .AppendLine(); sb.AppendFormat("Volume is Level {0} revision {1}", (homeblock.struclev & 0xFF00) >> 8, homeblock.struclev & 0xFF).AppendLine(); sb.AppendFormat("Lowest structure in the volume is Level {0}, revision {1}", (homeblock.lowstruclev & 0xFF00) >> 8, homeblock.lowstruclev & 0xFF).AppendLine(); sb.AppendFormat("Highest structure in the volume is Level {0}, revision {1}", (homeblock.highstruclev & 0xFF00) >> 8, homeblock.highstruclev & 0xFF).AppendLine(); sb.AppendFormat("{0} sectors per cluster ({1} bytes)", homeblock.cluster, homeblock.cluster * 512) .AppendLine(); sb.AppendFormat("This home block is on sector {0} (VBN {1})", homeblock.homelbn, homeblock.homevbn) .AppendLine(); sb.AppendFormat("Secondary home block is on sector {0} (VBN {1})", homeblock.alhomelbn, homeblock.alhomevbn) .AppendLine(); sb.AppendFormat("Volume bitmap starts in sector {0} (VBN {1})", homeblock.ibmaplbn, homeblock.ibmapvbn) .AppendLine(); sb.AppendFormat("Volume bitmap runs for {0} sectors ({1} bytes)", homeblock.ibmapsize, homeblock.ibmapsize * 512).AppendLine(); sb.AppendFormat("Backup INDEXF.SYS;1 is in sector {0} (VBN {1})", homeblock.altidxlbn, homeblock.altidxvbn) .AppendLine(); sb.AppendFormat("{0} maximum files on the volume", homeblock.maxfiles).AppendLine(); sb.AppendFormat("{0} reserved files", homeblock.resfiles).AppendLine(); if (homeblock.rvn > 0 && homeblock.setcount > 0 && StringHandlers.CToString(homeblock.strucname) != " ") { sb.AppendFormat("Volume is {0} of {1} in set \"{2}\".", homeblock.rvn, homeblock.setcount, StringHandlers.SpacePaddedToString(homeblock.strucname, Encoding)).AppendLine(); } sb.AppendFormat("Volume owner is \"{0}\" (ID 0x{1:X8})", StringHandlers.SpacePaddedToString(homeblock.ownername, Encoding), homeblock.volowner) .AppendLine(); sb.AppendFormat("Volume label: \"{0}\"", StringHandlers.SpacePaddedToString(homeblock.volname, Encoding)) .AppendLine(); sb.AppendFormat("Drive serial number: 0x{0:X8}", homeblock.serialnum).AppendLine(); sb.AppendFormat("Volume was created on {0}", DateHandlers.VmsToDateTime(homeblock.credate)).AppendLine(); if (homeblock.revdate > 0) { sb.AppendFormat("Volume was last modified on {0}", DateHandlers.VmsToDateTime(homeblock.revdate)) .AppendLine(); } if (homeblock.copydate > 0) { sb.AppendFormat("Volume copied on {0}", DateHandlers.VmsToDateTime(homeblock.copydate)).AppendLine(); } sb.AppendFormat("Checksums: 0x{0:X4} and 0x{1:X4}", homeblock.checksum1, homeblock.checksum2).AppendLine(); sb.AppendLine("Flags:"); sb.AppendFormat("Window: {0}", homeblock.window).AppendLine(); sb.AppendFormat("Cached directores: {0}", homeblock.lru_lim).AppendLine(); sb.AppendFormat("Default allocation: {0} blocks", homeblock.extend).AppendLine(); if ((homeblock.volchar & 0x01) == 0x01) { sb.AppendLine("Readings should be verified"); } if ((homeblock.volchar & 0x02) == 0x02) { sb.AppendLine("Writings should be verified"); } if ((homeblock.volchar & 0x04) == 0x04) { sb.AppendLine("Files should be erased or overwritten when deleted"); } if ((homeblock.volchar & 0x08) == 0x08) { sb.AppendLine("Highwater mark is to be disabled"); } if ((homeblock.volchar & 0x10) == 0x10) { sb.AppendLine("Classification checks are enabled"); } sb.AppendLine("Volume permissions (r = read, w = write, c = create, d = delete)"); sb.AppendLine("System, owner, group, world"); // System sb.Append((homeblock.protect & 0x1000) == 0x1000 ? "-" : "r"); sb.Append((homeblock.protect & 0x2000) == 0x2000 ? "-" : "w"); sb.Append((homeblock.protect & 0x4000) == 0x4000 ? "-" : "c"); sb.Append((homeblock.protect & 0x8000) == 0x8000 ? "-" : "d"); // Owner sb.Append((homeblock.protect & 0x100) == 0x100 ? "-" : "r"); sb.Append((homeblock.protect & 0x200) == 0x200 ? "-" : "w"); sb.Append((homeblock.protect & 0x400) == 0x400 ? "-" : "c"); sb.Append((homeblock.protect & 0x800) == 0x800 ? "-" : "d"); // Group sb.Append((homeblock.protect & 0x10) == 0x10 ? "-" : "r"); sb.Append((homeblock.protect & 0x20) == 0x20 ? "-" : "w"); sb.Append((homeblock.protect & 0x40) == 0x40 ? "-" : "c"); sb.Append((homeblock.protect & 0x80) == 0x80 ? "-" : "d"); // World (other) sb.Append((homeblock.protect & 0x1) == 0x1 ? "-" : "r"); sb.Append((homeblock.protect & 0x2) == 0x2 ? "-" : "w"); sb.Append((homeblock.protect & 0x4) == 0x4 ? "-" : "c"); sb.Append((homeblock.protect & 0x8) == 0x8 ? "-" : "d"); sb.AppendLine(); sb.AppendLine("Unknown structures:"); sb.AppendFormat("Security mask: 0x{0:X8}", homeblock.sec_mask).AppendLine(); sb.AppendFormat("File protection: 0x{0:X4}", homeblock.fileprot).AppendLine(); sb.AppendFormat("Record protection: 0x{0:X4}", homeblock.recprot).AppendLine(); XmlFsType = new FileSystemType { Type = "FILES-11", ClusterSize = homeblock.cluster * 512, Clusters = (long)partition.Size / (homeblock.cluster * 512), VolumeName = StringHandlers.SpacePaddedToString(homeblock.volname, Encoding), VolumeSerial = $"{homeblock.serialnum:X8}" }; if (homeblock.credate > 0) { XmlFsType.CreationDate = DateHandlers.VmsToDateTime(homeblock.credate); XmlFsType.CreationDateSpecified = true; } if (homeblock.revdate > 0) { XmlFsType.ModificationDate = DateHandlers.VmsToDateTime(homeblock.revdate); XmlFsType.ModificationDateSpecified = true; } information = sb.ToString(); }