/// <summary> /// Initializes a new instance of the <see cref="Syncless.Monitor.DTO.FileSystemEvent" /> class for non-rename event, given the specified path, the event change type and the file system change type. /// </summary> /// <param name="path">A <see cref="string" /> specifying the affected path.</param> /// <param name="eventType">A <see cref="Syncless.Monitor.DTO.EventChangeType" /> enum specifying the event change type.</param> /// <param name="fileSystemType">A <see cref="Syncless.Monitor.DTO.FileSystemType" /> enum specifying the file system change type.</param> public FileSystemEvent(string path, EventChangeType eventType, FileSystemType fileSystemType) { this._path = path; this._oldPath = null; this._watchPath = null; this._eventType = eventType; this._fileSystemType = fileSystemType; }
/// <summary> /// Initializes a new instance of the <see cref="Syncless.Monitor.DTO.FileSystemEvent" /> class for rename event only, given the old path, the new path and the file system change type. /// </summary> /// <param name="oldPath">A <see cref="string" /> class specifying the old path.</param> /// <param name="newPath">A <see cref="string" /> class specifying the new path.</param> /// <param name="fileSystemType">A <see cref="Syncless.Monitor.DTO.FileSystemType" /> enum specifying the file system change type.</param> public FileSystemEvent(string oldPath, string newPath, FileSystemType fileSystemType) { this._oldPath = oldPath; this._path = newPath; this._watchPath = null; this._eventType = EventChangeType.RENAMED; this._fileSystemType = fileSystemType; }
public GenericFileSystemProvider(FileSystemType type, Func<string, bool> isValidFileFunc, Func<string, bool> isContainerFunc, Func<string, IFile> createFunc) { Type = type; IsValidFileFunc = isValidFileFunc; IsContainerFunc = isContainerFunc; CreateFunc = createFunc; }
public Errno Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, Dictionary <string, string> options, string @namespace) { device = imagePlugin; this.partition = partition; Encoding = encoding ?? Encoding.GetEncoding("IBM437"); // As the identification is so complex, just call Identify() and relay on its findings if (!Identify(device, partition) || !cpmFound || workingDefinition == null || dpb == null) { return(Errno.InvalidArgument); } // Build the software interleaving sector mask if (workingDefinition.sides == 1) { sectorMask = new int[workingDefinition.side1.sectorIds.Length]; for (int m = 0; m < sectorMask.Length; m++) { sectorMask[m] = workingDefinition.side1.sectorIds[m] - workingDefinition.side1.sectorIds[0]; } } else { // Head changes after every track if (string.Compare(workingDefinition.order, "SIDES", StringComparison.InvariantCultureIgnoreCase) == 0) { sectorMask = new int[workingDefinition.side1.sectorIds.Length + workingDefinition.side2.sectorIds.Length]; for (int m = 0; m < workingDefinition.side1.sectorIds.Length; m++) { sectorMask[m] = workingDefinition.side1.sectorIds[m] - workingDefinition.side1.sectorIds[0]; } // Skip first track (first side) for (int m = 0; m < workingDefinition.side2.sectorIds.Length; m++) { sectorMask[m + workingDefinition.side1.sectorIds.Length] = workingDefinition.side2.sectorIds[m] - workingDefinition.side2.sectorIds[0] + workingDefinition.side1.sectorIds.Length; } } // Head changes after whole side else if (string.Compare(workingDefinition.order, "CYLINDERS", StringComparison.InvariantCultureIgnoreCase) == 0) { for (int m = 0; m < workingDefinition.side1.sectorIds.Length; m++) { sectorMask[m] = workingDefinition.side1.sectorIds[m] - workingDefinition.side1.sectorIds[0]; } // Skip first track (first side) and first track (second side) for (int m = 0; m < workingDefinition.side1.sectorIds.Length; m++) { sectorMask[m + workingDefinition.side1.sectorIds.Length] = workingDefinition.side1.sectorIds[m] - workingDefinition.side1.sectorIds[0] + workingDefinition.side1.sectorIds.Length + workingDefinition.side2.sectorIds.Length; } // TODO: Implement CYLINDERS ordering DicConsole.DebugWriteLine("CP/M Plugin", "CYLINDERS ordering not yet implemented."); return(Errno.NotImplemented); } // TODO: Implement COLUMBIA ordering else if (string.Compare(workingDefinition.order, "COLUMBIA", StringComparison.InvariantCultureIgnoreCase) == 0) { DicConsole.DebugWriteLine("CP/M Plugin", "Don't know how to handle COLUMBIA ordering, not proceeding with this definition."); return(Errno.NotImplemented); } // TODO: Implement EAGLE ordering else if (string.Compare(workingDefinition.order, "EAGLE", StringComparison.InvariantCultureIgnoreCase) == 0) { DicConsole.DebugWriteLine("CP/M Plugin", "Don't know how to handle EAGLE ordering, not proceeding with this definition."); return(Errno.NotImplemented); } else { DicConsole.DebugWriteLine("CP/M Plugin", "Unknown order type \"{0}\", not proceeding with this definition.", workingDefinition.order); return(Errno.NotSupported); } } // Deinterleave whole volume Dictionary <ulong, byte[]> deinterleavedSectors = new Dictionary <ulong, byte[]>(); if (workingDefinition.sides == 1 || string.Compare(workingDefinition.order, "SIDES", StringComparison.InvariantCultureIgnoreCase) == 0) { DicConsole.DebugWriteLine("CP/M Plugin", "Deinterleaving whole volume."); for (int p = 0; p <= (int)(partition.End - partition.Start); p++) { byte[] readSector = device.ReadSector((ulong)((int)partition.Start + p / sectorMask.Length * sectorMask.Length + sectorMask[p % sectorMask.Length])); if (workingDefinition.complement) { for (int b = 0; b < readSector.Length; b++) { readSector[b] = (byte)(~readSector[b] & 0xFF); } } deinterleavedSectors.Add((ulong)p, readSector); } } int blockSize = 128 << dpb.bsh; MemoryStream blockMs = new MemoryStream(); ulong blockNo = 0; int sectorsPerBlock = 0; Dictionary <ulong, byte[]> allocationBlocks = new Dictionary <ulong, byte[]>(); DicConsole.DebugWriteLine("CP/M Plugin", "Creating allocation blocks."); // For each volume sector for (ulong a = 0; a < (ulong)deinterleavedSectors.Count; a++) { deinterleavedSectors.TryGetValue(a, out byte[] sector); // May it happen? Just in case, CP/M blocks are smaller than physical sectors if (sector.Length > blockSize) { for (int i = 0; i < sector.Length / blockSize; i++) { byte[] tmp = new byte[blockSize]; Array.Copy(sector, blockSize * i, tmp, 0, blockSize); allocationBlocks.Add(blockNo++, tmp); } } // CP/M blocks are larger than physical sectors else if (sector.Length < blockSize) { blockMs.Write(sector, 0, sector.Length); sectorsPerBlock++; if (sectorsPerBlock != blockSize / sector.Length) { continue; } allocationBlocks.Add(blockNo++, blockMs.ToArray()); sectorsPerBlock = 0; blockMs = new MemoryStream(); } // CP/M blocks are same size than physical sectors else { allocationBlocks.Add(blockNo++, sector); } } DicConsole.DebugWriteLine("CP/M Plugin", "Reading directory."); int dirOff; int dirSectors = (dpb.drm + 1) * 32 / workingDefinition.bytesPerSector; if (workingDefinition.sofs > 0) { dirOff = workingDefinition.sofs; } else { dirOff = workingDefinition.ofs * workingDefinition.sectorsPerTrack; } // Read the whole directory blocks MemoryStream dirMs = new MemoryStream(); for (int d = 0; d < dirSectors; d++) { deinterleavedSectors.TryGetValue((ulong)(d + dirOff), out byte[] sector); dirMs.Write(sector, 0, sector.Length); } byte[] directory = dirMs.ToArray(); if (directory == null) { return(Errno.InvalidArgument); } int dirCnt = 0; string file1 = null; string file2 = null; string file3 = null; Dictionary <string, Dictionary <int, List <ushort> > > fileExtents = new Dictionary <string, Dictionary <int, List <ushort> > >(); statCache = new Dictionary <string, FileEntryInfo>(); cpmStat = new FileSystemInfo(); bool atime = false; dirList = new List <string>(); labelCreationDate = null; labelUpdateDate = null; passwordCache = new Dictionary <string, byte[]>(); DicConsole.DebugWriteLine("CP/M Plugin", "Traversing directory."); // For each directory entry for (int dOff = 0; dOff < directory.Length; dOff += 32) { // Describes a file (does not support PDOS entries with user >= 16, because they're identical to password entries if ((directory[dOff] & 0x7F) < 0x10) { if (allocationBlocks.Count > 256) { DirectoryEntry16 entry = Marshal.ByteArrayToStructureLittleEndian <DirectoryEntry16>(directory, dOff, 32); bool hidden = (entry.statusUser & 0x80) == 0x80; bool rdOnly = (entry.filename[0] & 0x80) == 0x80 || (entry.extension[0] & 0x80) == 0x80; bool system = (entry.filename[1] & 0x80) == 0x80 || (entry.extension[2] & 0x80) == 0x80; //bool backed = (entry.filename[3] & 0x80) == 0x80 || (entry.extension[3] & 0x80) == 0x80; int user = entry.statusUser & 0x0F; bool validEntry = true; for (int i = 0; i < 8; i++) { entry.filename[i] &= 0x7F; validEntry &= entry.filename[i] >= 0x20; } for (int i = 0; i < 3; i++) { entry.extension[i] &= 0x7F; validEntry &= entry.extension[i] >= 0x20; } if (!validEntry) { continue; } string filename = Encoding.ASCII.GetString(entry.filename).Trim(); string extension = Encoding.ASCII.GetString(entry.extension).Trim(); // If user is != 0, append user to name to have identical filenames if (user > 0) { filename = $"{user:X1}:{filename}"; } if (!string.IsNullOrEmpty(extension)) { filename = filename + "." + extension; } int entryNo = (32 * entry.extentCounter + entry.extentCounterHigh) / (dpb.exm + 1); // Do we have a stat for the file already? if (statCache.TryGetValue(filename, out FileEntryInfo fInfo)) { statCache.Remove(filename); } else { fInfo = new FileEntryInfo { Attributes = new FileAttributes() } }; // And any extent? if (fileExtents.TryGetValue(filename, out Dictionary <int, List <ushort> > extentBlocks)) { fileExtents.Remove(filename); } else { extentBlocks = new Dictionary <int, List <ushort> >(); } // Do we already have this extent? Should never happen if (extentBlocks.TryGetValue(entryNo, out List <ushort> blocks)) { extentBlocks.Remove(entryNo); } else { blocks = new List <ushort>(); } // Attributes if (hidden) { fInfo.Attributes |= FileAttributes.Hidden; } if (rdOnly) { fInfo.Attributes |= FileAttributes.ReadOnly; } if (system) { fInfo.Attributes |= FileAttributes.System; } // Supposedly there is a value in the directory entry telling how many blocks are designated in // this entry. However some implementations tend to do whatever they wish, but none will ever // allocate block 0 for a file because that's where the directory resides. // There is also a field telling how many bytes are used in the last block, but its meaning is // non-standard so we must ignore it. foreach (ushort blk in entry.allocations.Where(blk => !blocks.Contains(blk) && blk != 0)) { blocks.Add(blk); } // Save the file fInfo.UID = (ulong)user; extentBlocks.Add(entryNo, blocks); fileExtents.Add(filename, extentBlocks); statCache.Add(filename, fInfo); // Add the file to the directory listing if (!dirList.Contains(filename)) { dirList.Add(filename); } // Count entries 3 by 3 for timestamps switch (dirCnt % 3) { case 0: file1 = filename; break; case 1: file2 = filename; break; case 2: file3 = filename; break; } dirCnt++; } else { DirectoryEntry entry = Marshal.ByteArrayToStructureLittleEndian <DirectoryEntry>(directory, dOff, 32); bool hidden = (entry.statusUser & 0x80) == 0x80; bool rdOnly = (entry.filename[0] & 0x80) == 0x80 || (entry.extension[0] & 0x80) == 0x80; bool system = (entry.filename[1] & 0x80) == 0x80 || (entry.extension[2] & 0x80) == 0x80; //bool backed = (entry.filename[3] & 0x80) == 0x80 || (entry.extension[3] & 0x80) == 0x80; int user = entry.statusUser & 0x0F; bool validEntry = true; for (int i = 0; i < 8; i++) { entry.filename[i] &= 0x7F; validEntry &= entry.filename[i] >= 0x20; } for (int i = 0; i < 3; i++) { entry.extension[i] &= 0x7F; validEntry &= entry.extension[i] >= 0x20; } if (!validEntry) { continue; } string filename = Encoding.ASCII.GetString(entry.filename).Trim(); string extension = Encoding.ASCII.GetString(entry.extension).Trim(); // If user is != 0, append user to name to have identical filenames if (user > 0) { filename = $"{user:X1}:{filename}"; } if (!string.IsNullOrEmpty(extension)) { filename = filename + "." + extension; } int entryNo = (32 * entry.extentCounterHigh + entry.extentCounter) / (dpb.exm + 1); // Do we have a stat for the file already? if (statCache.TryGetValue(filename, out FileEntryInfo fInfo)) { statCache.Remove(filename); } else { fInfo = new FileEntryInfo { Attributes = new FileAttributes() } }; // And any extent? if (fileExtents.TryGetValue(filename, out Dictionary <int, List <ushort> > extentBlocks)) { fileExtents.Remove(filename); } else { extentBlocks = new Dictionary <int, List <ushort> >(); } // Do we already have this extent? Should never happen if (extentBlocks.TryGetValue(entryNo, out List <ushort> blocks)) { extentBlocks.Remove(entryNo); } else { blocks = new List <ushort>(); } // Attributes if (hidden) { fInfo.Attributes |= FileAttributes.Hidden; } if (rdOnly) { fInfo.Attributes |= FileAttributes.ReadOnly; } if (system) { fInfo.Attributes |= FileAttributes.System; } // Supposedly there is a value in the directory entry telling how many blocks are designated in // this entry. However some implementations tend to do whatever they wish, but none will ever // allocate block 0 for a file because that's where the directory resides. // There is also a field telling how many bytes are used in the last block, but its meaning is // non-standard so we must ignore it. foreach (ushort blk in entry.allocations.Cast <ushort>() .Where(blk => !blocks.Contains(blk) && blk != 0)) { blocks.Add(blk); } // Save the file fInfo.UID = (ulong)user; extentBlocks.Add(entryNo, blocks); fileExtents.Add(filename, extentBlocks); statCache.Add(filename, fInfo); // Add the file to the directory listing if (!dirList.Contains(filename)) { dirList.Add(filename); } // Count entries 3 by 3 for timestamps switch (dirCnt % 3) { case 0: file1 = filename; break; case 1: file2 = filename; break; case 2: file3 = filename; break; } dirCnt++; } } // A password entry (or a file entry in PDOS, but this does not handle that case) else if ((directory[dOff] & 0x7F) >= 0x10 && (directory[dOff] & 0x7F) < 0x20) { PasswordEntry entry = Marshal.ByteArrayToStructureLittleEndian <PasswordEntry>(directory, dOff, 32); int user = entry.userNumber & 0x0F; for (int i = 0; i < 8; i++) { entry.filename[i] &= 0x7F; } for (int i = 0; i < 3; i++) { entry.extension[i] &= 0x7F; } string filename = Encoding.ASCII.GetString(entry.filename).Trim(); string extension = Encoding.ASCII.GetString(entry.extension).Trim(); // If user is != 0, append user to name to have identical filenames if (user > 0) { filename = $"{user:X1}:{filename}"; } if (!string.IsNullOrEmpty(extension)) { filename = filename + "." + extension; } // Do not repeat passwords if (passwordCache.ContainsKey(filename)) { passwordCache.Remove(filename); } // Copy whole password entry byte[] tmp = new byte[32]; Array.Copy(directory, dOff, tmp, 0, 32); passwordCache.Add(filename, tmp); // Count entries 3 by 3 for timestamps switch (dirCnt % 3) { case 0: file1 = filename; break; case 1: file2 = filename; break; case 2: file3 = filename; break; } dirCnt++; } // Volume label and password entry. Volume password is ignored. else { switch (directory[dOff] & 0x7F) { case 0x20: LabelEntry labelEntry = Marshal.ByteArrayToStructureLittleEndian <LabelEntry>(directory, dOff, 32); // The volume label defines if one of the fields in CP/M 3 timestamp is a creation or an // access time atime |= (labelEntry.flags & 0x40) == 0x40; label = Encoding.ASCII.GetString(directory, dOff + 1, 11).Trim(); labelCreationDate = new byte[4]; labelUpdateDate = new byte[4]; Array.Copy(directory, dOff + 24, labelCreationDate, 0, 4); Array.Copy(directory, dOff + 28, labelUpdateDate, 0, 4); // Count entries 3 by 3 for timestamps switch (dirCnt % 3) { case 0: file1 = null; break; case 1: file2 = null; break; case 2: file3 = null; break; } dirCnt++; break; case 0x21: if (directory[dOff + 10] == 0x00 && directory[dOff + 20] == 0x00 && directory[dOff + 30] == 0x00 && directory[dOff + 31] == 0x00) { DateEntry dateEntry = Marshal.ByteArrayToStructureLittleEndian <DateEntry>(directory, dOff, 32); FileEntryInfo fInfo; // Entry contains timestamps for last 3 entries, whatever the kind they are. if (!string.IsNullOrEmpty(file1)) { if (statCache.TryGetValue(file1, out fInfo)) { statCache.Remove(file1); } else { fInfo = new FileEntryInfo(); } if (atime) { fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date1); } else { fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date1); } fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date2); statCache.Add(file1, fInfo); } if (!string.IsNullOrEmpty(file2)) { if (statCache.TryGetValue(file2, out fInfo)) { statCache.Remove(file2); } else { fInfo = new FileEntryInfo(); } if (atime) { fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date3); } else { fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date3); } fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date4); statCache.Add(file2, fInfo); } if (!string.IsNullOrEmpty(file3)) { if (statCache.TryGetValue(file3, out fInfo)) { statCache.Remove(file3); } else { fInfo = new FileEntryInfo(); } if (atime) { fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date5); } else { fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date5); } fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date6); statCache.Add(file3, fInfo); } file1 = null; file2 = null; file3 = null; dirCnt = 0; } // However, if this byte is 0, timestamp is in Z80DOS or DOS+ format else if (directory[dOff + 1] == 0x00) { TrdPartyDateEntry trdPartyDateEntry = Marshal.ByteArrayToStructureLittleEndian <TrdPartyDateEntry>(directory, dOff, 32); FileEntryInfo fInfo; // Entry contains timestamps for last 3 entries, whatever the kind they are. if (!string.IsNullOrEmpty(file1)) { if (statCache.TryGetValue(file1, out fInfo)) { statCache.Remove(file1); } else { fInfo = new FileEntryInfo(); } byte[] ctime = new byte[4]; ctime[0] = trdPartyDateEntry.create1[0]; ctime[1] = trdPartyDateEntry.create1[1]; fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access1); fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime); fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify1); statCache.Add(file1, fInfo); } if (!string.IsNullOrEmpty(file2)) { if (statCache.TryGetValue(file2, out fInfo)) { statCache.Remove(file2); } else { fInfo = new FileEntryInfo(); } byte[] ctime = new byte[4]; ctime[0] = trdPartyDateEntry.create2[0]; ctime[1] = trdPartyDateEntry.create2[1]; fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access2); fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime); fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify2); statCache.Add(file2, fInfo); } if (!string.IsNullOrEmpty(file3)) { if (statCache.TryGetValue(file1, out fInfo)) { statCache.Remove(file3); } else { fInfo = new FileEntryInfo(); } byte[] ctime = new byte[4]; ctime[0] = trdPartyDateEntry.create3[0]; ctime[1] = trdPartyDateEntry.create3[1]; fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access3); fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime); fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify3); statCache.Add(file3, fInfo); } file1 = null; file2 = null; file3 = null; dirCnt = 0; } break; } } } // Cache all files. As CP/M maximum volume size is 8 Mib // this should not be a problem DicConsole.DebugWriteLine("CP/M Plugin", "Reading files."); long usedBlocks = 0; fileCache = new Dictionary <string, byte[]>(); foreach (string filename in dirList) { MemoryStream fileMs = new MemoryStream(); if (statCache.TryGetValue(filename, out FileEntryInfo fInfo)) { statCache.Remove(filename); } fInfo.Blocks = 0; if (fileExtents.TryGetValue(filename, out Dictionary <int, List <ushort> > extents)) { for (int ex = 0; ex < extents.Count; ex++) { if (!extents.TryGetValue(ex, out List <ushort> alBlks)) { continue; } foreach (ushort alBlk in alBlks) { allocationBlocks.TryGetValue(alBlk, out byte[] blk); fileMs.Write(blk, 0, blk.Length); fInfo.Blocks++; } } } // If you insist to call CP/M "extent based" fInfo.Attributes |= FileAttributes.Extents; fInfo.BlockSize = blockSize; fInfo.Length = fileMs.Length; cpmStat.Files++; usedBlocks += fInfo.Blocks; statCache.Add(filename, fInfo); fileCache.Add(filename, fileMs.ToArray()); } decodedPasswordCache = new Dictionary <string, byte[]>(); // For each stored password, store a decoded version of it if (passwordCache.Count > 0) { foreach (KeyValuePair <string, byte[]> kvp in passwordCache) { byte[] tmp = new byte[8]; Array.Copy(kvp.Value, 16, tmp, 0, 8); for (int t = 0; t < 8; t++) { tmp[t] ^= kvp.Value[13]; } decodedPasswordCache.Add(kvp.Key, tmp); } } // Generate statfs. cpmStat.Blocks = (ulong)(dpb.dsm + 1); cpmStat.FilenameLength = 11; cpmStat.Files = (ulong)fileCache.Count; cpmStat.FreeBlocks = cpmStat.Blocks - (ulong)usedBlocks; cpmStat.PluginId = Id; cpmStat.Type = "CP/M filesystem"; // Generate XML info XmlFsType = new FileSystemType { Clusters = cpmStat.Blocks, ClusterSize = (uint)blockSize, Files = (ulong)fileCache.Count, FilesSpecified = true, FreeClusters = cpmStat.FreeBlocks, FreeClustersSpecified = true, Type = "CP/M filesystem" }; if (labelCreationDate != null) { XmlFsType.CreationDate = DateHandlers.CpmToDateTime(labelCreationDate); XmlFsType.CreationDateSpecified = true; } if (labelUpdateDate != null) { XmlFsType.ModificationDate = DateHandlers.CpmToDateTime(labelUpdateDate); XmlFsType.ModificationDateSpecified = true; } if (!string.IsNullOrEmpty(label)) { XmlFsType.VolumeName = label; } mounted = true; return(Errno.NoError); }
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(); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); information = ""; byte[] sector = imagePlugin.ReadSector(partition.Start + 1); if (sector.Length < 512) { return; } IntPtr sbPtr = Marshal.AllocHGlobal(512); Marshal.Copy(sector, 0, sbPtr, 512); QNX4_Superblock qnxSb = (QNX4_Superblock)Marshal.PtrToStructure(sbPtr, typeof(QNX4_Superblock)); Marshal.FreeHGlobal(sbPtr); // Too much useless information /* * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_fname = {0}", CurrentEncoding.GetString(qnxSb.rootDir.di_fname)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_size = {0}", qnxSb.rootDir.di_size); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_first_xtnt.block = {0}", qnxSb.rootDir.di_first_xtnt.block); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_first_xtnt.length = {0}", qnxSb.rootDir.di_first_xtnt.length); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_xblk = {0}", qnxSb.rootDir.di_xblk); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_ftime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.rootDir.di_ftime)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_mtime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.rootDir.di_mtime)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_atime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.rootDir.di_atime)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_ctime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.rootDir.di_ctime)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_num_xtnts = {0}", qnxSb.rootDir.di_num_xtnts); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_mode = {0}", Convert.ToString(qnxSb.rootDir.di_mode, 8)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_uid = {0}", qnxSb.rootDir.di_uid); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_gid = {0}", qnxSb.rootDir.di_gid); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_nlink = {0}", qnxSb.rootDir.di_nlink); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_zero = {0}", qnxSb.rootDir.di_zero); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_type = {0}", qnxSb.rootDir.di_type); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.rootDir.di_status = {0}", qnxSb.rootDir.di_status); * * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_fname = {0}", CurrentEncoding.GetString(qnxSb.inode.di_fname)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_size = {0}", qnxSb.inode.di_size); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_first_xtnt.block = {0}", qnxSb.inode.di_first_xtnt.block); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_first_xtnt.length = {0}", qnxSb.inode.di_first_xtnt.length); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_xblk = {0}", qnxSb.inode.di_xblk); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_ftime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.inode.di_ftime)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_mtime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.inode.di_mtime)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_atime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.inode.di_atime)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_ctime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.inode.di_ctime)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_num_xtnts = {0}", qnxSb.inode.di_num_xtnts); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_mode = {0}", Convert.ToString(qnxSb.inode.di_mode, 8)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_uid = {0}", qnxSb.inode.di_uid); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_gid = {0}", qnxSb.inode.di_gid); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_nlink = {0}", qnxSb.inode.di_nlink); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_zero = {0}", qnxSb.inode.di_zero); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_type = {0}", qnxSb.inode.di_type); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.inode.di_status = {0}", qnxSb.inode.di_status); * * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_fname = {0}", CurrentEncoding.GetString(qnxSb.boot.di_fname)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_size = {0}", qnxSb.boot.di_size); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_first_xtnt.block = {0}", qnxSb.boot.di_first_xtnt.block); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_first_xtnt.length = {0}", qnxSb.boot.di_first_xtnt.length); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_xblk = {0}", qnxSb.boot.di_xblk); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_ftime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.boot.di_ftime)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_mtime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.boot.di_mtime)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_atime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.boot.di_atime)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_ctime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.boot.di_ctime)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_num_xtnts = {0}", qnxSb.boot.di_num_xtnts); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_mode = {0}", Convert.ToString(qnxSb.boot.di_mode, 8)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_uid = {0}", qnxSb.boot.di_uid); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_gid = {0}", qnxSb.boot.di_gid); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_nlink = {0}", qnxSb.boot.di_nlink); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_zero = {0}", qnxSb.boot.di_zero); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_type = {0}", qnxSb.boot.di_type); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.boot.di_status = {0}", qnxSb.boot.di_status); * * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_fname = {0}", CurrentEncoding.GetString(qnxSb.altBoot.di_fname)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_size = {0}", qnxSb.altBoot.di_size); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_first_xtnt.block = {0}", qnxSb.altBoot.di_first_xtnt.block); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_first_xtnt.length = {0}", qnxSb.altBoot.di_first_xtnt.length); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_xblk = {0}", qnxSb.altBoot.di_xblk); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_ftime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.altBoot.di_ftime)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_mtime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.altBoot.di_mtime)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_atime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.altBoot.di_atime)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_ctime = {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.altBoot.di_ctime)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_num_xtnts = {0}", qnxSb.altBoot.di_num_xtnts); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_mode = {0}", Convert.ToString(qnxSb.altBoot.di_mode, 8)); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_uid = {0}", qnxSb.altBoot.di_uid); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_gid = {0}", qnxSb.altBoot.di_gid); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_nlink = {0}", qnxSb.altBoot.di_nlink); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_zero = {0}", qnxSb.altBoot.di_zero); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_type = {0}", qnxSb.altBoot.di_type); * DicConsole.DebugWriteLine("QNX4 plugin", "qnxSb.altBoot.di_status = {0}", qnxSb.altBoot.di_status); */ information = $"QNX4 filesystem\nCreated on {DateHandlers.UnixUnsignedToDateTime(qnxSb.rootDir.di_ftime)}\n"; XmlFsType = new FileSystemType { Type = "QNX4 filesystem", Clusters = (long)partition.Length, ClusterSize = 512, CreationDate = DateHandlers.UnixUnsignedToDateTime(qnxSb.rootDir.di_ftime), CreationDateSpecified = true, ModificationDate = DateHandlers.UnixUnsignedToDateTime(qnxSb.rootDir.di_mtime), ModificationDateSpecified = true }; XmlFsType.Bootable |= qnxSb.boot.di_size != 0 || qnxSb.altBoot.di_size != 0; }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = Encoding.BigEndianUnicode; information = ""; var vh = new VolumeHeader(); ulong hfspOffset; bool wrapped; uint sectorsToRead = 0x800 / imagePlugin.Info.SectorSize; if (0x800 % imagePlugin.Info.SectorSize > 0) { sectorsToRead++; } byte[] vhSector = imagePlugin.ReadSectors(partition.Start, sectorsToRead); ushort drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x400); if (drSigWord == AppleCommon.HFS_MAGIC) // "BD" { drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x47C); // Read embedded HFS+ signature if (drSigWord == AppleCommon.HFSP_MAGIC) // "H+" { ushort xdrStABNt = BigEndianBitConverter.ToUInt16(vhSector, 0x47E); uint drAlBlkSiz = BigEndianBitConverter.ToUInt32(vhSector, 0x414); ushort drAlBlSt = BigEndianBitConverter.ToUInt16(vhSector, 0x41C); hfspOffset = (ulong)(((drAlBlSt * 512) + (xdrStABNt * drAlBlkSiz)) / imagePlugin.Info.SectorSize); wrapped = true; } else { hfspOffset = 0; wrapped = false; } } else { hfspOffset = 0; wrapped = false; } vhSector = imagePlugin.ReadSectors(partition.Start + hfspOffset, sectorsToRead); // Read volume header vh.signature = BigEndianBitConverter.ToUInt16(vhSector, 0x400); if (vh.signature != AppleCommon.HFSP_MAGIC && vh.signature != AppleCommon.HFSX_MAGIC) { return; } var sb = new StringBuilder(); if (vh.signature == 0x482B) { sb.AppendLine("HFS+ filesystem."); } if (vh.signature == 0x4858) { sb.AppendLine("HFSX filesystem."); } if (wrapped) { sb.AppendLine("Volume is wrapped inside an HFS volume."); } byte[] tmp = new byte[0x400]; Array.Copy(vhSector, 0x400, tmp, 0, 0x400); vhSector = tmp; vh = Marshal.ByteArrayToStructureBigEndian <VolumeHeader>(vhSector); if (vh.version == 4 || vh.version == 5) { sb.AppendFormat("Filesystem version is {0}.", vh.version).AppendLine(); if ((vh.attributes & 0x80) == 0x80) { sb.AppendLine("Volume is locked on hardware."); } if ((vh.attributes & 0x100) == 0x100) { sb.AppendLine("Volume is unmounted."); } if ((vh.attributes & 0x200) == 0x200) { sb.AppendLine("There are bad blocks in the extents file."); } if ((vh.attributes & 0x400) == 0x400) { sb.AppendLine("Volume does not require cache."); } if ((vh.attributes & 0x800) == 0x800) { sb.AppendLine("Volume state is inconsistent."); } if ((vh.attributes & 0x1000) == 0x1000) { sb.AppendLine("CNIDs are reused."); } if ((vh.attributes & 0x2000) == 0x2000) { sb.AppendLine("Volume is journaled."); } if ((vh.attributes & 0x8000) == 0x8000) { sb.AppendLine("Volume is locked on software."); } sb.AppendFormat("Implementation that last mounted the volume: \"{0}\".", Encoding.ASCII.GetString(vh.lastMountedVersion)).AppendLine(); if ((vh.attributes & 0x2000) == 0x2000) { sb.AppendFormat("Journal starts at allocation block {0}.", vh.journalInfoBlock).AppendLine(); } sb.AppendFormat("Creation date: {0}", DateHandlers.MacToDateTime(vh.createDate)).AppendLine(); sb.AppendFormat("Last modification date: {0}", DateHandlers.MacToDateTime(vh.modifyDate)).AppendLine(); if (vh.backupDate > 0) { sb.AppendFormat("Last backup date: {0}", DateHandlers.MacToDateTime(vh.backupDate)).AppendLine(); } else { sb.AppendLine("Volume has never been backed up"); } if (vh.backupDate > 0) { sb.AppendFormat("Last check date: {0}", DateHandlers.MacToDateTime(vh.checkedDate)).AppendLine(); } else { sb.AppendLine("Volume has never been checked up"); } sb.AppendFormat("{0} files on volume.", vh.fileCount).AppendLine(); sb.AppendFormat("{0} folders on volume.", vh.folderCount).AppendLine(); sb.AppendFormat("{0} bytes per allocation block.", vh.blockSize).AppendLine(); sb.AppendFormat("{0} allocation blocks.", vh.totalBlocks).AppendLine(); sb.AppendFormat("{0} free blocks.", vh.freeBlocks).AppendLine(); sb.AppendFormat("Next allocation block: {0}.", vh.nextAllocation).AppendLine(); sb.AppendFormat("Resource fork clump size: {0} bytes.", vh.rsrcClumpSize).AppendLine(); sb.AppendFormat("Data fork clump size: {0} bytes.", vh.dataClumpSize).AppendLine(); sb.AppendFormat("Next unused CNID: {0}.", vh.nextCatalogID).AppendLine(); sb.AppendFormat("Volume has been mounted writable {0} times.", vh.writeCount).AppendLine(); sb.AppendFormat("Allocation File is {0} bytes.", vh.allocationFile_logicalSize).AppendLine(); sb.AppendFormat("Extents File is {0} bytes.", vh.extentsFile_logicalSize).AppendLine(); sb.AppendFormat("Catalog File is {0} bytes.", vh.catalogFile_logicalSize).AppendLine(); sb.AppendFormat("Attributes File is {0} bytes.", vh.attributesFile_logicalSize).AppendLine(); sb.AppendFormat("Startup File is {0} bytes.", vh.startupFile_logicalSize).AppendLine(); sb.AppendLine("Finder info:"); sb.AppendFormat("CNID of bootable system's directory: {0}", vh.drFndrInfo0).AppendLine(); sb.AppendFormat("CNID of first-run application's directory: {0}", vh.drFndrInfo1).AppendLine(); sb.AppendFormat("CNID of previously opened directory: {0}", vh.drFndrInfo2).AppendLine(); sb.AppendFormat("CNID of bootable Mac OS 8 or 9 directory: {0}", vh.drFndrInfo3).AppendLine(); sb.AppendFormat("CNID of bootable Mac OS X directory: {0}", vh.drFndrInfo5).AppendLine(); if (vh.drFndrInfo6 != 0 && vh.drFndrInfo7 != 0) { sb.AppendFormat("Mac OS X Volume ID: {0:X8}{1:X8}", vh.drFndrInfo6, vh.drFndrInfo7).AppendLine(); } XmlFsType = new FileSystemType(); if (vh.backupDate > 0) { XmlFsType.BackupDate = DateHandlers.MacToDateTime(vh.backupDate); XmlFsType.BackupDateSpecified = true; } XmlFsType.Bootable |= vh.drFndrInfo0 != 0 || vh.drFndrInfo3 != 0 || vh.drFndrInfo5 != 0; XmlFsType.Clusters = vh.totalBlocks; XmlFsType.ClusterSize = vh.blockSize; if (vh.createDate > 0) { XmlFsType.CreationDate = DateHandlers.MacToDateTime(vh.createDate); XmlFsType.CreationDateSpecified = true; } XmlFsType.Dirty = (vh.attributes & 0x100) != 0x100; XmlFsType.Files = vh.fileCount; XmlFsType.FilesSpecified = true; XmlFsType.FreeClusters = vh.freeBlocks; XmlFsType.FreeClustersSpecified = true; if (vh.modifyDate > 0) { XmlFsType.ModificationDate = DateHandlers.MacToDateTime(vh.modifyDate); XmlFsType.ModificationDateSpecified = true; } if (vh.signature == 0x482B) { XmlFsType.Type = "HFS+"; } if (vh.signature == 0x4858) { XmlFsType.Type = "HFSX"; } if (vh.drFndrInfo6 != 0 && vh.drFndrInfo7 != 0) { XmlFsType.VolumeSerial = $"{vh.drFndrInfo6:X8}{vh.drFndrInfo7:X8}"; } XmlFsType.SystemIdentifier = Encoding.ASCII.GetString(vh.lastMountedVersion); } else { sb.AppendFormat("Filesystem version is {0}.", vh.version).AppendLine(); sb.AppendLine("This version is not supported yet."); } information = sb.ToString(); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); information = ""; if (imagePlugin.Info.SectorSize < 512) { return; } XFS_Superblock xfsSb = new XFS_Superblock(); // Misaligned if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) { uint sbSize = (uint)((Marshal.SizeOf(xfsSb) + 0x400) / imagePlugin.Info.SectorSize); if ((Marshal.SizeOf(xfsSb) + 0x400) % imagePlugin.Info.SectorSize != 0) { sbSize++; } byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize); if (sector.Length < Marshal.SizeOf(xfsSb)) { return; } byte[] sbpiece = new byte[Marshal.SizeOf(xfsSb)]; foreach (int location in new[] { 0, 0x200, 0x400 }) { Array.Copy(sector, location, sbpiece, 0, Marshal.SizeOf(xfsSb)); xfsSb = BigEndianMarshal.ByteArrayToStructureBigEndian <XFS_Superblock>(sbpiece); DicConsole.DebugWriteLine("XFS plugin", "magic at 0x{0:X3} = 0x{1:X8} (expected 0x{2:X8})", location, xfsSb.magicnum, XFS_MAGIC); if (xfsSb.magicnum == XFS_MAGIC) { break; } } } else { foreach (int i in new[] { 0, 1, 2 }) { ulong location = (ulong)i; uint sbSize = (uint)(Marshal.SizeOf(xfsSb) / imagePlugin.Info.SectorSize); if (Marshal.SizeOf(xfsSb) % imagePlugin.Info.SectorSize != 0) { sbSize++; } byte[] sector = imagePlugin.ReadSectors(partition.Start + location, sbSize); if (sector.Length < Marshal.SizeOf(xfsSb)) { return; } xfsSb = BigEndianMarshal.ByteArrayToStructureBigEndian <XFS_Superblock>(sector); DicConsole.DebugWriteLine("XFS plugin", "magic at {0} = 0x{1:X8} (expected 0x{2:X8})", location, xfsSb.magicnum, XFS_MAGIC); if (xfsSb.magicnum == XFS_MAGIC) { break; } } } if (xfsSb.magicnum != XFS_MAGIC) { return; } StringBuilder sb = new StringBuilder(); sb.AppendLine("XFS filesystem"); sb.AppendFormat("Filesystem version {0}", xfsSb.version & 0xF).AppendLine(); sb.AppendFormat("{0} bytes per sector", xfsSb.sectsize).AppendLine(); sb.AppendFormat("{0} bytes per block", xfsSb.blocksize).AppendLine(); sb.AppendFormat("{0} bytes per inode", xfsSb.inodesize).AppendLine(); sb.AppendFormat("{0} data blocks in volume, {1} free", xfsSb.dblocks, xfsSb.fdblocks).AppendLine(); sb.AppendFormat("{0} blocks per allocation group", xfsSb.agblocks).AppendLine(); sb.AppendFormat("{0} allocation groups in volume", xfsSb.agcount).AppendLine(); sb.AppendFormat("{0} inodes in volume, {1} free", xfsSb.icount, xfsSb.ifree).AppendLine(); if (xfsSb.inprogress > 0) { sb.AppendLine("fsck in progress"); } sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(xfsSb.fname, Encoding)).AppendLine(); sb.AppendFormat("Volume UUID: {0}", xfsSb.uuid).AppendLine(); information = sb.ToString(); XmlFsType = new FileSystemType { Type = "XFS filesystem", ClusterSize = (int)xfsSb.blocksize, Clusters = (long)xfsSb.dblocks, FreeClusters = (long)xfsSb.fdblocks, FreeClustersSpecified = true, Files = (long)(xfsSb.icount - xfsSb.ifree), FilesSpecified = true, Dirty = xfsSb.inprogress > 0, VolumeName = StringHandlers.CToString(xfsSb.fname, Encoding), VolumeSerial = xfsSb.uuid.ToString() }; }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); information = ""; StringBuilder sb = new StringBuilder(); BeSuperBlock besb = new BeSuperBlock(); byte[] sbSector = imagePlugin.ReadSector(0 + partition.Start); bool littleEndian; besb.magic1 = BigEndianBitConverter.ToUInt32(sbSector, 0x20); if (besb.magic1 == BEFS_MAGIC1 || besb.magic1 == BEFS_CIGAM1) // Magic is at offset { littleEndian = besb.magic1 == BEFS_CIGAM1; } else { sbSector = imagePlugin.ReadSector(1 + partition.Start); besb.magic1 = BigEndianBitConverter.ToUInt32(sbSector, 0x20); if (besb.magic1 == BEFS_MAGIC1 || besb.magic1 == BEFS_CIGAM1) // There is a boot sector { littleEndian = besb.magic1 == BEFS_CIGAM1; } else if (sbSector.Length >= 0x400) { byte[] temp = imagePlugin.ReadSector(0 + partition.Start); besb.magic1 = BigEndianBitConverter.ToUInt32(temp, 0x220); if (besb.magic1 == BEFS_MAGIC1 || besb.magic1 == BEFS_CIGAM1) // There is a boot sector { littleEndian = besb.magic1 == BEFS_CIGAM1; sbSector = new byte[0x200]; Array.Copy(temp, 0x200, sbSector, 0, 0x200); } else { return; } } else { return; } } if (littleEndian) { GCHandle handle = GCHandle.Alloc(sbSector, GCHandleType.Pinned); besb = (BeSuperBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(BeSuperBlock)); handle.Free(); } else { besb = BigEndianMarshal.ByteArrayToStructureBigEndian <BeSuperBlock>(sbSector); } sb.AppendLine(littleEndian ? "Little-endian BeFS" : "Big-endian BeFS"); if (besb.magic1 != BEFS_MAGIC1 || besb.fs_byte_order != BEFS_ENDIAN || besb.magic2 != BEFS_MAGIC2 || besb.magic3 != BEFS_MAGIC3 || besb.root_dir_len != 1 || besb.indices_len != 1 || 1 << (int)besb.block_shift != besb.block_size) { sb.AppendLine("Superblock seems corrupt, following information may be incorrect"); sb.AppendFormat("Magic 1: 0x{0:X8} (Should be 0x42465331)", besb.magic1).AppendLine(); sb.AppendFormat("Magic 2: 0x{0:X8} (Should be 0xDD121031)", besb.magic2).AppendLine(); sb.AppendFormat("Magic 3: 0x{0:X8} (Should be 0x15B6830E)", besb.magic3).AppendLine(); sb.AppendFormat("Filesystem endianness: 0x{0:X8} (Should be 0x42494745)", besb.fs_byte_order) .AppendLine(); sb.AppendFormat("Root folder's i-node size: {0} blocks (Should be 1)", besb.root_dir_len).AppendLine(); sb.AppendFormat("Indices' i-node size: {0} blocks (Should be 1)", besb.indices_len).AppendLine(); sb.AppendFormat("1 << block_shift == block_size => 1 << {0} == {1} (Should be {2})", besb.block_shift, 1 << (int)besb.block_shift, besb.block_size).AppendLine(); } switch (besb.flags) { case BEFS_CLEAN: sb.AppendLine(besb.log_start == besb.log_end ? "Filesystem is clean" : "Filesystem is dirty"); break; case BEFS_DIRTY: sb.AppendLine("Filesystem is dirty"); break; default: sb.AppendFormat("Unknown flags: {0:X8}", besb.flags).AppendLine(); break; } sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(besb.name, Encoding)).AppendLine(); sb.AppendFormat("{0} bytes per block", besb.block_size).AppendLine(); sb.AppendFormat("{0} blocks in volume ({1} bytes)", besb.num_blocks, besb.num_blocks * besb.block_size) .AppendLine(); sb.AppendFormat("{0} used blocks ({1} bytes)", besb.used_blocks, besb.used_blocks * besb.block_size) .AppendLine(); sb.AppendFormat("{0} bytes per i-node", besb.inode_size).AppendLine(); sb.AppendFormat("{0} blocks per allocation group ({1} bytes)", besb.blocks_per_ag, besb.blocks_per_ag * besb.block_size).AppendLine(); sb.AppendFormat("{0} allocation groups in volume", besb.num_ags).AppendLine(); sb.AppendFormat("Journal resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes)", besb.log_blocks_start, besb.log_blocks_ag, besb.log_blocks_len, besb.log_blocks_len * besb.block_size).AppendLine(); sb.AppendFormat("Journal starts in byte {0} and ends in byte {1}", besb.log_start, besb.log_end) .AppendLine(); sb .AppendFormat("Root folder's i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes)", besb.root_dir_start, besb.root_dir_ag, besb.root_dir_len, besb.root_dir_len * besb.block_size).AppendLine(); sb .AppendFormat("Indices' i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes)", besb.indices_start, besb.indices_ag, besb.indices_len, besb.indices_len * besb.block_size) .AppendLine(); information = sb.ToString(); XmlFsType = new FileSystemType { Clusters = besb.num_blocks, ClusterSize = (int)besb.block_size, Dirty = besb.flags == BEFS_DIRTY, FreeClusters = besb.num_blocks - besb.used_blocks, FreeClustersSpecified = true, Type = "BeFS", VolumeName = StringHandlers.CToString(besb.name, Encoding) }; }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); information = ""; StringBuilder sb = new StringBuilder(); XmlFsType = new FileSystemType(); byte[] vbrSector = imagePlugin.ReadSector(0 + partition.Start); VolumeBootRecord vbr = Marshal.ByteArrayToStructureLittleEndian <VolumeBootRecord>(vbrSector); byte[] parametersSector = imagePlugin.ReadSector(9 + partition.Start); OemParameterTable parametersTable = Marshal.ByteArrayToStructureLittleEndian <OemParameterTable>(parametersSector); byte[] chkSector = imagePlugin.ReadSector(11 + partition.Start); ChecksumSector chksector = Marshal.ByteArrayToStructureLittleEndian <ChecksumSector>(chkSector); sb.AppendLine("Microsoft exFAT"); sb.AppendFormat("Partition offset: {0}", vbr.offset).AppendLine(); sb.AppendFormat("Volume has {0} sectors of {1} bytes each for a total of {2} bytes", vbr.sectors, 1 << vbr.sectorShift, vbr.sectors * (ulong)(1 << vbr.sectorShift)).AppendLine(); sb.AppendFormat("Volume uses clusters of {0} sectors ({1} bytes) each", 1 << vbr.clusterShift, (1 << vbr.sectorShift) * (1 << vbr.clusterShift)).AppendLine(); sb.AppendFormat("First FAT starts at sector {0} and runs for {1} sectors", vbr.fatOffset, vbr.fatLength) .AppendLine(); sb.AppendFormat("Volume uses {0} FATs", vbr.fats).AppendLine(); sb.AppendFormat("Cluster heap starts at sector {0}, contains {1} clusters and is {2}% used", vbr.clusterHeapOffset, vbr.clusterHeapLength, vbr.heapUsage).AppendLine(); sb.AppendFormat("Root directory starts at cluster {0}", vbr.rootDirectoryCluster).AppendLine(); sb.AppendFormat("Filesystem revision is {0}.{1:D2}", (vbr.revision & 0xFF00) >> 8, vbr.revision & 0xFF) .AppendLine(); sb.AppendFormat("Volume serial number: {0:X8}", vbr.volumeSerial).AppendLine(); sb.AppendFormat("BIOS drive is {0:X2}h", vbr.drive).AppendLine(); if (vbr.flags.HasFlag(VolumeFlags.SecondFatActive)) { sb.AppendLine("2nd FAT is in use"); } if (vbr.flags.HasFlag(VolumeFlags.VolumeDirty)) { sb.AppendLine("Volume is dirty"); } if (vbr.flags.HasFlag(VolumeFlags.MediaFailure)) { sb.AppendLine("Underlying media presented errors"); } int count = 1; foreach (OemParameter parameter in parametersTable.parameters) { if (parameter.OemParameterType == OEM_FLASH_PARAMETER_GUID) { sb.AppendFormat("OEM Parameters {0}:", count).AppendLine(); sb.AppendFormat("\t{0} bytes in erase block", parameter.eraseBlockSize).AppendLine(); sb.AppendFormat("\t{0} bytes per page", parameter.pageSize).AppendLine(); sb.AppendFormat("\t{0} spare blocks", parameter.spareBlocks).AppendLine(); sb.AppendFormat("\t{0} nanoseconds random access time", parameter.randomAccessTime).AppendLine(); sb.AppendFormat("\t{0} nanoseconds program time", parameter.programTime).AppendLine(); sb.AppendFormat("\t{0} nanoseconds read cycle time", parameter.readCycleTime).AppendLine(); sb.AppendFormat("\t{0} nanoseconds write cycle time", parameter.writeCycleTime).AppendLine(); } else if (parameter.OemParameterType != Guid.Empty) { sb.AppendFormat("Found unknown parameter type {0}", parameter.OemParameterType).AppendLine(); } count++; } sb.AppendFormat("Checksum 0x{0:X8}", chksector.checksum[0]).AppendLine(); XmlFsType.ClusterSize = (uint)((1 << vbr.sectorShift) * (1 << vbr.clusterShift)); XmlFsType.Clusters = vbr.clusterHeapLength; XmlFsType.Dirty = vbr.flags.HasFlag(VolumeFlags.VolumeDirty); XmlFsType.Type = "exFAT"; XmlFsType.VolumeSerial = $"{vbr.volumeSerial:X8}"; information = sb.ToString(); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = Encoding.Unicode; information = ""; if (imagePlugin.Info.SectorSize < F2FS_MIN_SECTOR || imagePlugin.Info.SectorSize > F2FS_MAX_SECTOR) { return; } uint sbAddr = F2FS_SUPER_OFFSET / imagePlugin.Info.SectorSize; if (sbAddr == 0) { sbAddr = 1; } uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize); if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0) { sbSize++; } byte[] sector = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize); if (sector.Length < Marshal.SizeOf <Superblock>()) { return; } Superblock f2fsSb = Marshal.ByteArrayToStructureLittleEndian <Superblock>(sector); if (f2fsSb.magic != F2FS_MAGIC) { return; } var sb = new StringBuilder(); sb.AppendLine("F2FS filesystem"); sb.AppendFormat("Version {0}.{1}", f2fsSb.major_ver, f2fsSb.minor_ver).AppendLine(); sb.AppendFormat("{0} bytes per sector", 1 << (int)f2fsSb.log_sectorsize).AppendLine(); sb.AppendFormat("{0} sectors ({1} bytes) per block", 1 << (int)f2fsSb.log_sectors_per_block, 1 << (int)f2fsSb.log_blocksize).AppendLine(); sb.AppendFormat("{0} blocks per segment", f2fsSb.log_blocks_per_seg).AppendLine(); sb.AppendFormat("{0} blocks in volume", f2fsSb.block_count).AppendLine(); sb.AppendFormat("{0} segments per section", f2fsSb.segs_per_sec).AppendLine(); sb.AppendFormat("{0} sections per zone", f2fsSb.secs_per_zone).AppendLine(); sb.AppendFormat("{0} sections", f2fsSb.section_count).AppendLine(); sb.AppendFormat("{0} segments", f2fsSb.segment_count).AppendLine(); sb.AppendFormat("Root directory resides on inode {0}", f2fsSb.root_ino).AppendLine(); sb.AppendFormat("Volume UUID: {0}", f2fsSb.uuid).AppendLine(); sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(f2fsSb.volume_name, Encoding.Unicode, true)). AppendLine(); sb.AppendFormat("Volume last mounted on kernel version: {0}", StringHandlers.CToString(f2fsSb.version)). AppendLine(); sb.AppendFormat("Volume created on kernel version: {0}", StringHandlers.CToString(f2fsSb.init_version)). AppendLine(); information = sb.ToString(); XmlFsType = new FileSystemType { Type = "F2FS filesystem", SystemIdentifier = Encoding.ASCII.GetString(f2fsSb.version), Clusters = f2fsSb.block_count, ClusterSize = (uint)(1 << (int)f2fsSb.log_blocksize), DataPreparerIdentifier = Encoding.ASCII.GetString(f2fsSb.init_version), VolumeName = StringHandlers.CToString(f2fsSb.volume_name, Encoding.Unicode, true), VolumeSerial = f2fsSb.uuid.ToString() }; }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = Encoding.Unicode; information = ""; var sb = new StringBuilder(); byte[] ntfsBpb = imagePlugin.ReadSector(0 + partition.Start); BiosParameterBlock ntfsBb = Marshal.ByteArrayToStructureLittleEndian <BiosParameterBlock>(ntfsBpb); sb.AppendFormat("{0} bytes per sector", ntfsBb.bps).AppendLine(); sb.AppendFormat("{0} sectors per cluster ({1} bytes)", ntfsBb.spc, ntfsBb.spc * ntfsBb.bps).AppendLine(); // sb.AppendFormat("{0} reserved sectors", ntfs_bb.rsectors).AppendLine(); // sb.AppendFormat("{0} FATs", ntfs_bb.fats_no).AppendLine(); // sb.AppendFormat("{0} entries in the root folder", ntfs_bb.root_ent).AppendLine(); // sb.AppendFormat("{0} sectors on volume (small)", ntfs_bb.sml_sectors).AppendLine(); sb.AppendFormat("Media descriptor: 0x{0:X2}", ntfsBb.media).AppendLine(); // sb.AppendFormat("{0} sectors per FAT", ntfs_bb.spfat).AppendLine(); sb.AppendFormat("{0} sectors per track", ntfsBb.sptrk).AppendLine(); sb.AppendFormat("{0} heads", ntfsBb.heads).AppendLine(); sb.AppendFormat("{0} hidden sectors before filesystem", ntfsBb.hsectors).AppendLine(); // sb.AppendFormat("{0} sectors on volume (big)", ntfs_bb.big_sectors).AppendLine(); sb.AppendFormat("BIOS drive number: 0x{0:X2}", ntfsBb.drive_no).AppendLine(); // sb.AppendFormat("NT flags: 0x{0:X2}", ntfs_bb.nt_flags).AppendLine(); // sb.AppendFormat("Signature 1: 0x{0:X2}", ntfs_bb.signature1).AppendLine(); sb.AppendFormat("{0} sectors on volume ({1} bytes)", ntfsBb.sectors, ntfsBb.sectors * ntfsBb.bps). AppendLine(); sb.AppendFormat("Cluster where $MFT starts: {0}", ntfsBb.mft_lsn).AppendLine(); sb.AppendFormat("Cluster where $MFTMirr starts: {0}", ntfsBb.mftmirror_lsn).AppendLine(); if (ntfsBb.mft_rc_clusters > 0) { sb.AppendFormat("{0} clusters per MFT record ({1} bytes)", ntfsBb.mft_rc_clusters, ntfsBb.mft_rc_clusters * ntfsBb.bps * ntfsBb.spc).AppendLine(); } else { sb.AppendFormat("{0} bytes per MFT record", 1 << -ntfsBb.mft_rc_clusters).AppendLine(); } if (ntfsBb.index_blk_cts > 0) { sb.AppendFormat("{0} clusters per Index block ({1} bytes)", ntfsBb.index_blk_cts, ntfsBb.index_blk_cts * ntfsBb.bps * ntfsBb.spc).AppendLine(); } else { sb.AppendFormat("{0} bytes per Index block", 1 << -ntfsBb.index_blk_cts).AppendLine(); } sb.AppendFormat("Volume serial number: {0:X16}", ntfsBb.serial_no).AppendLine(); // sb.AppendFormat("Signature 2: 0x{0:X4}", ntfs_bb.signature2).AppendLine(); XmlFsType = new FileSystemType(); if (ntfsBb.jump[0] == 0xEB && ntfsBb.jump[1] > 0x4E && ntfsBb.jump[1] < 0x80 && ntfsBb.signature2 == 0xAA55) { XmlFsType.Bootable = true; string bootChk = Sha1Context.Data(ntfsBb.boot_code, out _); sb.AppendLine("Volume is bootable"); sb.AppendFormat("Boot code's SHA1: {0}", bootChk).AppendLine(); } XmlFsType.ClusterSize = (uint)(ntfsBb.spc * ntfsBb.bps); XmlFsType.Clusters = (ulong)(ntfsBb.sectors / ntfsBb.spc); XmlFsType.VolumeSerial = $"{ntfsBb.serial_no:X16}"; XmlFsType.Type = "NTFS"; information = sb.ToString(); }
public Result OpenFileSystemWithPatch(out IFileSystem fileSystem, TitleId titleId, FileSystemType type) { throw new NotImplementedException(); }
public Result OpenFileSystemWithId(out IFileSystem fileSystem, ref FsPath path, TitleId titleId, FileSystemType type) { throw new NotImplementedException(); }
/// <summary> /// Initializes a new instance of the <see cref="Syncless.Monitor.DTO.FileSystemEvent" /> class for delete event with unknown file system type only, given the affected path and the path being monitored. /// </summary> /// <param name="path">A <see cref="string" /> specifying the affected path.</param> /// <param name="watchPath">A <see cref="string" /> specifying the path being monitored.</param> public FileSystemEvent(string path, string watchPath) { this._path = path; this._oldPath = null; this._watchPath = watchPath; this._eventType = EventChangeType.DELETED; this._fileSystemType = FileSystemType.UNKNOWN; }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.ASCII; information = ""; StringBuilder isoMetadata = new StringBuilder(); byte[] vdMagic = new byte[5]; // Volume Descriptor magic "CD001" byte[] hsMagic = new byte[5]; // Volume Descriptor magic "CDROM" string bootSpec = ""; PrimaryVolumeDescriptor?pvd = null; PrimaryVolumeDescriptor?jolietvd = null; BootRecord?bvd = null; HighSierraPrimaryVolumeDescriptor?hsvd = null; FileStructureVolumeDescriptor? fsvd = null; ElToritoBootRecord?torito = null; // ISO9660 is designed for 2048 bytes/sector devices if (imagePlugin.Info.SectorSize < 2048) { return; } // ISO9660 Primary Volume Descriptor starts at sector 16, so that's minimal size. if (partition.End < 16) { return; } ulong counter = 0; byte[] vdSector = imagePlugin.ReadSector(16 + counter + partition.Start); int xaOff = vdSector.Length == 2336 ? 8 : 0; Array.Copy(vdSector, 0x009 + xaOff, hsMagic, 0, 5); bool highSierra = Encoding.GetString(hsMagic) == HIGH_SIERRA_MAGIC; int hsOff = 0; if (highSierra) { hsOff = 8; } bool cdi = false; while (true) { DicConsole.DebugWriteLine("ISO9660 plugin", "Processing VD loop no. {0}", counter); // Seek to Volume Descriptor DicConsole.DebugWriteLine("ISO9660 plugin", "Reading sector {0}", 16 + counter + partition.Start); byte[] vdSectorTmp = imagePlugin.ReadSector(16 + counter + partition.Start); vdSector = new byte[vdSectorTmp.Length - xaOff]; Array.Copy(vdSectorTmp, xaOff, vdSector, 0, vdSector.Length); byte vdType = vdSector[0 + hsOff]; // Volume Descriptor Type, should be 1 or 2. DicConsole.DebugWriteLine("ISO9660 plugin", "VDType = {0}", vdType); if (vdType == 255) // Supposedly we are in the PVD. { if (counter == 0) { return; } break; } Array.Copy(vdSector, 0x001, vdMagic, 0, 5); Array.Copy(vdSector, 0x009, hsMagic, 0, 5); if (Encoding.GetString(vdMagic) != ISO_MAGIC && Encoding.GetString(hsMagic) != HIGH_SIERRA_MAGIC && Encoding.GetString(vdMagic) != CDI_MAGIC ) // Recognized, it is an ISO9660, now check for rest of data. { if (counter == 0) { return; } break; } cdi |= Encoding.GetString(vdMagic) == CDI_MAGIC; switch (vdType) { case 0: { bvd = Marshal.ByteArrayToStructureLittleEndian <BootRecord>(vdSector, hsOff, 2048 - hsOff); bootSpec = "Unknown"; if (Encoding.GetString(bvd.Value.system_id).Substring(0, 23) == "EL TORITO SPECIFICATION") { bootSpec = "El Torito"; torito = Marshal.ByteArrayToStructureLittleEndian <ElToritoBootRecord>(vdSector, hsOff, 2048 - hsOff); } break; } case 1: { if (highSierra) { hsvd = Marshal .ByteArrayToStructureLittleEndian <HighSierraPrimaryVolumeDescriptor>(vdSector); } else if (cdi) { fsvd = Marshal.ByteArrayToStructureBigEndian <FileStructureVolumeDescriptor>(vdSector); } else { pvd = Marshal.ByteArrayToStructureLittleEndian <PrimaryVolumeDescriptor>(vdSector); } break; } case 2: { PrimaryVolumeDescriptor svd = Marshal.ByteArrayToStructureLittleEndian <PrimaryVolumeDescriptor>(vdSector); // Check if this is Joliet if (svd.escape_sequences[0] == '%' && svd.escape_sequences[1] == '/') { if (svd.escape_sequences[2] == '@' || svd.escape_sequences[2] == 'C' || svd.escape_sequences[2] == 'E') { jolietvd = svd; } else { DicConsole.WriteLine("ISO9660 plugin", "Found unknown supplementary volume descriptor"); } } break; } } counter++; } DecodedVolumeDescriptor decodedVd; DecodedVolumeDescriptor decodedJolietVd = new DecodedVolumeDescriptor(); XmlFsType = new FileSystemType(); if (pvd == null && hsvd == null && fsvd == null) { information = "ERROR: Could not find primary volume descriptor"; return; } if (highSierra) { decodedVd = DecodeVolumeDescriptor(hsvd.Value); } else if (cdi) { decodedVd = DecodeVolumeDescriptor(fsvd.Value); } else { decodedVd = DecodeVolumeDescriptor(pvd.Value); } if (jolietvd != null) { decodedJolietVd = DecodeJolietDescriptor(jolietvd.Value); } uint rootLocation = 0; uint rootSize = 0; // No need to read root on CD-i, as extensions are not supported... if (!cdi) { rootLocation = highSierra ? hsvd.Value.root_directory_record.extent : pvd.Value.root_directory_record.extent; if (highSierra) { rootSize = hsvd.Value.root_directory_record.size / hsvd.Value.logical_block_size; if (hsvd.Value.root_directory_record.size % hsvd.Value.logical_block_size > 0) { rootSize++; } } else { rootSize = pvd.Value.root_directory_record.size / pvd.Value.logical_block_size; if (pvd.Value.root_directory_record.size % pvd.Value.logical_block_size > 0) { rootSize++; } } } byte[] rootDir = new byte[0]; int rootOff = 0; bool xaExtensions = false; bool apple = false; bool susp = false; bool rrip = false; bool ziso = false; bool amiga = false; bool aaip = false; List <ContinuationArea> contareas = new List <ContinuationArea>(); List <byte[]> refareas = new List <byte[]>(); StringBuilder suspInformation = new StringBuilder(); if (rootLocation + rootSize < imagePlugin.Info.Sectors) { rootDir = imagePlugin.ReadSectors(rootLocation, rootSize); } BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; // Walk thru root directory to see system area extensions in use while (rootOff + Marshal.SizeOf <DirectoryRecord>() < rootDir.Length && !cdi) { DirectoryRecord record = Marshal.ByteArrayToStructureLittleEndian <DirectoryRecord>(rootDir, rootOff, Marshal.SizeOf <DirectoryRecord>()); int saOff = Marshal.SizeOf <DirectoryRecord>() + record.name_len; saOff += saOff % 2; int saLen = record.length - saOff; if (saLen > 0 && rootOff + saOff + saLen <= rootDir.Length) { byte[] sa = new byte[saLen]; Array.Copy(rootDir, rootOff + saOff, sa, 0, saLen); saOff = 0; while (saOff < saLen) { bool noneFound = true; if (Marshal.SizeOf <CdromXa>() + saOff <= saLen) { CdromXa xa = Marshal.ByteArrayToStructureBigEndian <CdromXa>(sa); if (xa.signature == XA_MAGIC) { xaExtensions = true; saOff += Marshal.SizeOf <CdromXa>(); noneFound = false; } } if (saOff + 2 >= saLen) { break; } ushort nextSignature = BigEndianBitConverter.ToUInt16(sa, saOff); switch (nextSignature) { // Easy, contains size field case APPLE_MAGIC: apple = true; saOff += sa[saOff + 2]; noneFound = false; break; // Not easy, contains size field case APPLE_MAGIC_OLD: apple = true; AppleOldId appleId = (AppleOldId)sa[saOff + 2]; noneFound = false; switch (appleId) { case AppleOldId.ProDOS: saOff += Marshal.SizeOf <AppleProDOSOldSystemUse>(); break; case AppleOldId.TypeCreator: case AppleOldId.TypeCreatorBundle: saOff += Marshal.SizeOf <AppleHFSTypeCreatorSystemUse>(); break; case AppleOldId.TypeCreatorIcon: case AppleOldId.TypeCreatorIconBundle: saOff += Marshal.SizeOf <AppleHFSIconSystemUse>(); break; case AppleOldId.HFS: saOff += Marshal.SizeOf <AppleHFSOldSystemUse>(); break; } break; // IEEE-P1281 aka SUSP 1.12 case SUSP_INDICATOR: susp = true; saOff += sa[saOff + 2]; noneFound = false; while (saOff + 2 < saLen) { nextSignature = BigEndianBitConverter.ToUInt16(sa, saOff); switch (nextSignature) { case APPLE_MAGIC: if (sa[saOff + 3] == 1 && sa[saOff + 2] == 7) { apple = true; } else { apple |= sa[saOff + 3] != 1; } break; case SUSP_CONTINUATION when saOff + sa[saOff + 2] <= saLen: byte[] ce = new byte[sa[saOff + 2]]; Array.Copy(sa, saOff, ce, 0, ce.Length); ContinuationArea ca = Marshal.ByteArrayToStructureBigEndian <ContinuationArea>(ce); contareas.Add(ca); break; case SUSP_REFERENCE when saOff + sa[saOff + 2] <= saLen: byte[] er = new byte[sa[saOff + 2]]; Array.Copy(sa, saOff, er, 0, er.Length); refareas.Add(er); break; } rrip |= nextSignature == RRIP_MAGIC || nextSignature == RRIP_POSIX_ATTRIBUTES || nextSignature == RRIP_POSIX_DEV_NO || nextSignature == RRIP_SYMLINK || nextSignature == RRIP_NAME || nextSignature == RRIP_CHILDLINK || nextSignature == RRIP_PARENTLINK || nextSignature == RRIP_RELOCATED_DIR || nextSignature == RRIP_TIMESTAMPS || nextSignature == RRIP_SPARSE; ziso |= nextSignature == ZISO_MAGIC; amiga |= nextSignature == AMIGA_MAGIC; aaip |= nextSignature == AAIP_MAGIC || nextSignature == AAIP_MAGIC_OLD && sa[saOff + 3] == 1 && sa[saOff + 2] >= 9; saOff += sa[saOff + 2]; if (nextSignature == SUSP_TERMINATOR) { break; } } break; } if (noneFound) { break; } } } rootOff += record.length; if (record.length == 0) { break; } } foreach (ContinuationArea ca in contareas) { uint caLen = (ca.ca_length_be + ca.offset_be) / (highSierra ? hsvd.Value.logical_block_size : pvd.Value.logical_block_size); if ((ca.ca_length_be + ca.offset_be) % (highSierra ? hsvd.Value.logical_block_size : pvd.Value.logical_block_size) > 0) { caLen++; } byte[] caSectors = imagePlugin.ReadSectors(ca.block_be, caLen); byte[] caData = new byte[ca.ca_length_be]; Array.Copy(caSectors, ca.offset_be, caData, 0, ca.ca_length_be); int caOff = 0; while (caOff < ca.ca_length_be) { ushort nextSignature = BigEndianBitConverter.ToUInt16(caData, caOff); switch (nextSignature) { // Apple never said to include its extensions inside a continuation area, but just in case case APPLE_MAGIC: if (caData[caOff + 3] == 1 && caData[caOff + 2] == 7) { apple = true; } else { apple |= caData[caOff + 3] != 1; } break; case SUSP_REFERENCE when caOff + caData[caOff + 2] <= ca.ca_length_be: byte[] er = new byte[caData[caOff + 2]]; Array.Copy(caData, caOff, er, 0, er.Length); refareas.Add(er); break; } rrip |= nextSignature == RRIP_MAGIC || nextSignature == RRIP_POSIX_ATTRIBUTES || nextSignature == RRIP_POSIX_DEV_NO || nextSignature == RRIP_SYMLINK || nextSignature == RRIP_NAME || nextSignature == RRIP_CHILDLINK || nextSignature == RRIP_PARENTLINK || nextSignature == RRIP_RELOCATED_DIR || nextSignature == RRIP_TIMESTAMPS || nextSignature == RRIP_SPARSE; ziso |= nextSignature == ZISO_MAGIC; amiga |= nextSignature == AMIGA_MAGIC; aaip |= nextSignature == AAIP_MAGIC || nextSignature == AAIP_MAGIC_OLD && caData[caOff + 3] == 1 && caData[caOff + 2] >= 9; caOff += caData[caOff + 2]; } } if (refareas.Count > 0) { suspInformation.AppendLine("----------------------------------------"); suspInformation.AppendLine("SYSTEM USE SHARING PROTOCOL INFORMATION:"); suspInformation.AppendLine("----------------------------------------"); counter = 1; foreach (byte[] erb in refareas) { ReferenceArea er = Marshal.ByteArrayToStructureBigEndian <ReferenceArea>(erb); string extId = Encoding.GetString(erb, Marshal.SizeOf <ReferenceArea>(), er.id_len); string extDes = Encoding.GetString(erb, Marshal.SizeOf <ReferenceArea>() + er.id_len, er.des_len); string extSrc = Encoding.GetString(erb, Marshal.SizeOf <ReferenceArea>() + er.id_len + er.des_len, er.src_len); suspInformation.AppendFormat("Extension: {0}", counter).AppendLine(); suspInformation.AppendFormat("\tID: {0}, version {1}", extId, er.ext_ver).AppendLine(); suspInformation.AppendFormat("\tDescription: {0}", extDes).AppendLine(); suspInformation.AppendFormat("\tSource: {0}", extSrc).AppendLine(); counter++; } } byte[] ipbinSector = imagePlugin.ReadSector(0 + partition.Start); CD.IPBin? segaCd = CD.DecodeIPBin(ipbinSector); Saturn.IPBin? saturn = Saturn.DecodeIPBin(ipbinSector); Dreamcast.IPBin?dreamcast = Dreamcast.DecodeIPBin(ipbinSector); string fsFormat; if (highSierra) { fsFormat = "High Sierra Format"; } else if (cdi) { fsFormat = "CD-i"; } else { fsFormat = "ISO9660"; } isoMetadata.AppendFormat("{0} file system", fsFormat).AppendLine(); if (xaExtensions) { isoMetadata.AppendLine("CD-ROM XA extensions present."); } if (amiga) { isoMetadata.AppendLine("Amiga extensions present."); } if (apple) { isoMetadata.AppendLine("Apple extensions present."); } if (jolietvd != null) { isoMetadata.AppendLine("Joliet extensions present."); } if (susp) { isoMetadata.AppendLine("System Use Sharing Protocol present."); } if (rrip) { isoMetadata.AppendLine("Rock Ridge Interchange Protocol present."); } if (aaip) { isoMetadata.AppendLine("Arbitrary Attribute Interchange Protocol present."); } if (ziso) { isoMetadata.AppendLine("zisofs compression present."); } if (bvd != null) { isoMetadata.AppendFormat("Disc bootable following {0} specifications.", bootSpec).AppendLine(); } if (segaCd != null) { isoMetadata.AppendLine("This is a SegaCD / MegaCD disc."); isoMetadata.AppendLine(CD.Prettify(segaCd)); } if (saturn != null) { isoMetadata.AppendLine("This is a Sega Saturn disc."); isoMetadata.AppendLine(Saturn.Prettify(saturn)); } if (dreamcast != null) { isoMetadata.AppendLine("This is a Sega Dreamcast disc."); isoMetadata.AppendLine(Dreamcast.Prettify(dreamcast)); } isoMetadata.AppendFormat("{0}------------------------------", cdi ? "---------------" : "").AppendLine(); isoMetadata.AppendFormat("{0}VOLUME DESCRIPTOR INFORMATION:", cdi ? "FILE STRUCTURE " : "").AppendLine(); isoMetadata.AppendFormat("{0}------------------------------", cdi ? "---------------" : "").AppendLine(); isoMetadata.AppendFormat("System identifier: {0}", decodedVd.SystemIdentifier).AppendLine(); isoMetadata.AppendFormat("Volume identifier: {0}", decodedVd.VolumeIdentifier).AppendLine(); isoMetadata.AppendFormat("Volume set identifier: {0}", decodedVd.VolumeSetIdentifier).AppendLine(); isoMetadata.AppendFormat("Publisher identifier: {0}", decodedVd.PublisherIdentifier).AppendLine(); isoMetadata.AppendFormat("Data preparer identifier: {0}", decodedVd.DataPreparerIdentifier).AppendLine(); isoMetadata.AppendFormat("Application identifier: {0}", decodedVd.ApplicationIdentifier).AppendLine(); isoMetadata.AppendFormat("Volume creation date: {0}", decodedVd.CreationTime).AppendLine(); if (decodedVd.HasModificationTime) { isoMetadata.AppendFormat("Volume modification date: {0}", decodedVd.ModificationTime).AppendLine(); } else { isoMetadata.AppendFormat("Volume has not been modified.").AppendLine(); } if (decodedVd.HasExpirationTime) { isoMetadata.AppendFormat("Volume expiration date: {0}", decodedVd.ExpirationTime).AppendLine(); } else { isoMetadata.AppendFormat("Volume does not expire.").AppendLine(); } if (decodedVd.HasEffectiveTime) { isoMetadata.AppendFormat("Volume effective date: {0}", decodedVd.EffectiveTime).AppendLine(); } else { isoMetadata.AppendFormat("Volume has always been effective.").AppendLine(); } isoMetadata.AppendFormat("Volume has {0} blocks of {1} bytes each", decodedVd.Blocks, decodedVd.BlockSize) .AppendLine(); if (jolietvd != null) { isoMetadata.AppendLine("-------------------------------------"); isoMetadata.AppendLine("JOLIET VOLUME DESCRIPTOR INFORMATION:"); isoMetadata.AppendLine("-------------------------------------"); isoMetadata.AppendFormat("System identifier: {0}", decodedJolietVd.SystemIdentifier).AppendLine(); isoMetadata.AppendFormat("Volume identifier: {0}", decodedJolietVd.VolumeIdentifier).AppendLine(); isoMetadata.AppendFormat("Volume set identifier: {0}", decodedJolietVd.VolumeSetIdentifier) .AppendLine(); isoMetadata.AppendFormat("Publisher identifier: {0}", decodedJolietVd.PublisherIdentifier).AppendLine(); isoMetadata.AppendFormat("Data preparer identifier: {0}", decodedJolietVd.DataPreparerIdentifier) .AppendLine(); isoMetadata.AppendFormat("Application identifier: {0}", decodedJolietVd.ApplicationIdentifier) .AppendLine(); isoMetadata.AppendFormat("Volume creation date: {0}", decodedJolietVd.CreationTime).AppendLine(); if (decodedJolietVd.HasModificationTime) { isoMetadata.AppendFormat("Volume modification date: {0}", decodedJolietVd.ModificationTime) .AppendLine(); } else { isoMetadata.AppendFormat("Volume has not been modified.").AppendLine(); } if (decodedJolietVd.HasExpirationTime) { isoMetadata.AppendFormat("Volume expiration date: {0}", decodedJolietVd.ExpirationTime) .AppendLine(); } else { isoMetadata.AppendFormat("Volume does not expire.").AppendLine(); } if (decodedJolietVd.HasEffectiveTime) { isoMetadata.AppendFormat("Volume effective date: {0}", decodedJolietVd.EffectiveTime).AppendLine(); } else { isoMetadata.AppendFormat("Volume has always been effective.").AppendLine(); } } if (torito != null) { vdSector = imagePlugin.ReadSector(torito.Value.catalog_sector + partition.Start); int toritoOff = 0; if (vdSector[toritoOff] != 1) { goto exit_torito; } ElToritoValidationEntry valentry = Marshal.ByteArrayToStructureLittleEndian <ElToritoValidationEntry>(vdSector, toritoOff, EL_TORITO_ENTRY_SIZE); if (valentry.signature != EL_TORITO_MAGIC) { goto exit_torito; } toritoOff += EL_TORITO_ENTRY_SIZE; ElToritoInitialEntry initialEntry = Marshal.ByteArrayToStructureLittleEndian <ElToritoInitialEntry>(vdSector, toritoOff, EL_TORITO_ENTRY_SIZE); initialEntry.boot_type = (ElToritoEmulation)((byte)initialEntry.boot_type & 0xF); DicConsole.DebugWriteLine("DEBUG (ISO9660 plugin)", "initialEntry.load_rba = {0}", initialEntry.load_rba); DicConsole.DebugWriteLine("DEBUG (ISO9660 plugin)", "initialEntry.sector_count = {0}", initialEntry.sector_count); byte[] bootImage = initialEntry.load_rba + partition.Start + initialEntry.sector_count - 1 <= partition.End ? imagePlugin.ReadSectors(initialEntry.load_rba + partition.Start, initialEntry.sector_count) : null; isoMetadata.AppendLine("----------------------"); isoMetadata.AppendLine("EL TORITO INFORMATION:"); isoMetadata.AppendLine("----------------------"); isoMetadata.AppendLine("Initial entry:"); isoMetadata.AppendFormat("\tDeveloper ID: {0}", Encoding.GetString(valentry.developer_id)).AppendLine(); if (initialEntry.bootable == ElToritoIndicator.Bootable) { isoMetadata.AppendFormat("\tBootable on {0}", valentry.platform_id).AppendLine(); isoMetadata.AppendFormat("\tBootable image starts at sector {0} and runs for {1} sectors", initialEntry.load_rba, initialEntry.sector_count).AppendLine(); if (valentry.platform_id == ElToritoPlatform.x86) { isoMetadata.AppendFormat("\tBootable image will be loaded at segment {0:X4}h", initialEntry.load_seg == 0 ? 0x7C0 : initialEntry.load_seg) .AppendLine(); } else { isoMetadata.AppendFormat("\tBootable image will be loaded at 0x{0:X8}", (uint)initialEntry.load_seg * 10).AppendLine(); } switch (initialEntry.boot_type) { case ElToritoEmulation.None: isoMetadata.AppendLine("\tImage uses no emulation"); break; case ElToritoEmulation.Md2hd: isoMetadata.AppendLine("\tImage emulates a 5.25\" high-density (MD2HD, 1.2Mb) floppy"); break; case ElToritoEmulation.Mf2hd: isoMetadata.AppendLine("\tImage emulates a 3.5\" high-density (MF2HD, 1.44Mb) floppy"); break; case ElToritoEmulation.Mf2ed: isoMetadata.AppendLine("\tImage emulates a 3.5\" extra-density (MF2ED, 2.88Mb) floppy"); break; default: isoMetadata.AppendFormat("\tImage uses unknown emulation type {0}", (byte)initialEntry.boot_type).AppendLine(); break; } isoMetadata.AppendFormat("\tSystem type: 0x{0:X2}", initialEntry.system_type).AppendLine(); if (bootImage != null) { isoMetadata.AppendFormat("\tBootable image's SHA1: {0}", Sha1Context.Data(bootImage, out _)) .AppendLine(); } } else { isoMetadata.AppendLine("\tNot bootable"); } toritoOff += EL_TORITO_ENTRY_SIZE; const int SECTION_COUNTER = 2; while (toritoOff < vdSector.Length && (vdSector[toritoOff] == (byte)ElToritoIndicator.Header || vdSector[toritoOff] == (byte)ElToritoIndicator.LastHeader)) { ElToritoSectionHeaderEntry sectionHeader = Marshal.ByteArrayToStructureLittleEndian <ElToritoSectionHeaderEntry>(vdSector, toritoOff, EL_TORITO_ENTRY_SIZE); toritoOff += EL_TORITO_ENTRY_SIZE; isoMetadata.AppendFormat("Boot section {0}:", SECTION_COUNTER); isoMetadata.AppendFormat("\tSection ID: {0}", Encoding.GetString(sectionHeader.identifier)) .AppendLine(); for (int entryCounter = 1; entryCounter <= sectionHeader.entries && toritoOff < vdSector.Length; entryCounter++) { ElToritoSectionEntry sectionEntry = Marshal.ByteArrayToStructureLittleEndian <ElToritoSectionEntry>(vdSector, toritoOff, EL_TORITO_ENTRY_SIZE); toritoOff += EL_TORITO_ENTRY_SIZE; isoMetadata.AppendFormat("\tEntry {0}:", entryCounter); if (sectionEntry.bootable == ElToritoIndicator.Bootable) { bootImage = sectionEntry.load_rba + partition.Start + sectionEntry.sector_count - 1 <= partition.End ? imagePlugin.ReadSectors(sectionEntry.load_rba + partition.Start, sectionEntry.sector_count) : null; isoMetadata.AppendFormat("\t\tBootable on {0}", sectionHeader.platform_id).AppendLine(); isoMetadata.AppendFormat("\t\tBootable image starts at sector {0} and runs for {1} sectors", sectionEntry.load_rba, sectionEntry.sector_count).AppendLine(); if (valentry.platform_id == ElToritoPlatform.x86) { isoMetadata.AppendFormat("\t\tBootable image will be loaded at segment {0:X4}h", sectionEntry.load_seg == 0 ? 0x7C0 : sectionEntry.load_seg) .AppendLine(); } else { isoMetadata.AppendFormat("\t\tBootable image will be loaded at 0x{0:X8}", (uint)sectionEntry.load_seg * 10).AppendLine(); } switch ((ElToritoEmulation)((byte)sectionEntry.boot_type & 0xF)) { case ElToritoEmulation.None: isoMetadata.AppendLine("\t\tImage uses no emulation"); break; case ElToritoEmulation.Md2hd: isoMetadata .AppendLine("\t\tImage emulates a 5.25\" high-density (MD2HD, 1.2Mb) floppy"); break; case ElToritoEmulation.Mf2hd: isoMetadata .AppendLine("\t\tImage emulates a 3.5\" high-density (MF2HD, 1.44Mb) floppy"); break; case ElToritoEmulation.Mf2ed: isoMetadata .AppendLine("\t\tImage emulates a 3.5\" extra-density (MF2ED, 2.88Mb) floppy"); break; default: isoMetadata.AppendFormat("\t\tImage uses unknown emulation type {0}", (byte)initialEntry.boot_type).AppendLine(); break; } isoMetadata.AppendFormat("\t\tSelection criteria type: {0}", sectionEntry.selection_criteria_type).AppendLine(); isoMetadata.AppendFormat("\t\tSystem type: 0x{0:X2}", sectionEntry.system_type) .AppendLine(); if (bootImage != null) { isoMetadata.AppendFormat("\t\tBootable image's SHA1: {0}", Sha1Context.Data(bootImage, out _)).AppendLine(); } } else { isoMetadata.AppendLine("\t\tNot bootable"); } ElToritoFlags flags = (ElToritoFlags)((byte)sectionEntry.boot_type & 0xF0); if (flags.HasFlag(ElToritoFlags.ATAPI)) { isoMetadata.AppendLine("\t\tImage contains ATAPI drivers"); } if (flags.HasFlag(ElToritoFlags.SCSI)) { isoMetadata.AppendLine("\t\tImage contains SCSI drivers"); } if (!flags.HasFlag(ElToritoFlags.Continued)) { continue; } while (toritoOff < vdSector.Length) { ElToritoSectionEntryExtension sectionExtension = Marshal.ByteArrayToStructureLittleEndian <ElToritoSectionEntryExtension>(vdSector, toritoOff, EL_TORITO_ENTRY_SIZE); toritoOff += EL_TORITO_ENTRY_SIZE; if (!sectionExtension.extension_flags.HasFlag(ElToritoFlags.Continued)) { break; } } } if (sectionHeader.header_id == ElToritoIndicator.LastHeader) { break; } } } exit_torito: if (refareas.Count > 0) { isoMetadata.Append(suspInformation); } XmlFsType.Type = fsFormat; if (jolietvd != null) { XmlFsType.VolumeName = decodedJolietVd.VolumeIdentifier; if (string.IsNullOrEmpty(decodedJolietVd.SystemIdentifier) || decodedVd.SystemIdentifier.Length > decodedJolietVd.SystemIdentifier.Length) { XmlFsType.SystemIdentifier = decodedVd.SystemIdentifier; } else { XmlFsType.SystemIdentifier = string.IsNullOrEmpty(decodedJolietVd.SystemIdentifier) ? null : decodedJolietVd.SystemIdentifier; } if (string.IsNullOrEmpty(decodedJolietVd.VolumeSetIdentifier) || decodedVd.VolumeSetIdentifier.Length > decodedJolietVd.VolumeSetIdentifier.Length) { XmlFsType.VolumeSetIdentifier = decodedVd.VolumeSetIdentifier; } else { XmlFsType.VolumeSetIdentifier = string.IsNullOrEmpty(decodedJolietVd.VolumeSetIdentifier) ? null : decodedJolietVd.VolumeSetIdentifier; } if (string.IsNullOrEmpty(decodedJolietVd.PublisherIdentifier) || decodedVd.PublisherIdentifier.Length > decodedJolietVd.PublisherIdentifier.Length) { XmlFsType.PublisherIdentifier = decodedVd.PublisherIdentifier; } else { XmlFsType.PublisherIdentifier = string.IsNullOrEmpty(decodedJolietVd.PublisherIdentifier) ? null : decodedJolietVd.PublisherIdentifier; } if (string.IsNullOrEmpty(decodedJolietVd.DataPreparerIdentifier) || decodedVd.DataPreparerIdentifier.Length > decodedJolietVd.DataPreparerIdentifier.Length) { XmlFsType.DataPreparerIdentifier = decodedVd.DataPreparerIdentifier; } else { XmlFsType.DataPreparerIdentifier = string.IsNullOrEmpty(decodedJolietVd.DataPreparerIdentifier) ? null : decodedJolietVd.DataPreparerIdentifier; } if (string.IsNullOrEmpty(decodedJolietVd.ApplicationIdentifier) || decodedVd.ApplicationIdentifier.Length > decodedJolietVd.ApplicationIdentifier.Length) { XmlFsType.ApplicationIdentifier = decodedVd.ApplicationIdentifier; } else { XmlFsType.ApplicationIdentifier = string.IsNullOrEmpty(decodedJolietVd.ApplicationIdentifier) ? null : decodedJolietVd.ApplicationIdentifier; } XmlFsType.CreationDate = decodedJolietVd.CreationTime; XmlFsType.CreationDateSpecified = true; if (decodedJolietVd.HasModificationTime) { XmlFsType.ModificationDate = decodedJolietVd.ModificationTime; XmlFsType.ModificationDateSpecified = true; } if (decodedJolietVd.HasExpirationTime) { XmlFsType.ExpirationDate = decodedJolietVd.ExpirationTime; XmlFsType.ExpirationDateSpecified = true; } if (decodedJolietVd.HasEffectiveTime) { XmlFsType.EffectiveDate = decodedJolietVd.EffectiveTime; XmlFsType.EffectiveDateSpecified = true; } } else { XmlFsType.SystemIdentifier = decodedVd.SystemIdentifier; XmlFsType.VolumeName = decodedVd.VolumeIdentifier; XmlFsType.VolumeSetIdentifier = decodedVd.VolumeSetIdentifier; XmlFsType.PublisherIdentifier = decodedVd.PublisherIdentifier; XmlFsType.DataPreparerIdentifier = decodedVd.DataPreparerIdentifier; XmlFsType.ApplicationIdentifier = decodedVd.ApplicationIdentifier; XmlFsType.CreationDate = decodedVd.CreationTime; XmlFsType.CreationDateSpecified = true; if (decodedVd.HasModificationTime) { XmlFsType.ModificationDate = decodedVd.ModificationTime; XmlFsType.ModificationDateSpecified = true; } if (decodedVd.HasExpirationTime) { XmlFsType.ExpirationDate = decodedVd.ExpirationTime; XmlFsType.ExpirationDateSpecified = true; } if (decodedVd.HasEffectiveTime) { XmlFsType.EffectiveDate = decodedVd.EffectiveTime; XmlFsType.EffectiveDateSpecified = true; } } XmlFsType.Bootable |= bvd != null || segaCd != null || saturn != null || dreamcast != null; XmlFsType.Clusters = decodedVd.Blocks; XmlFsType.ClusterSize = decodedVd.BlockSize; information = isoMetadata.ToString(); }
public static void ServerSetup( FileSystemType fsType, SignState sutSignState, bool isSupportDfs, bool isSupportPreviousVersion, bool isMessageModePipe) { Condition.IsTrue(smbState == SmbState.ConnectionSuccess); if (Parameter.sutPlatform != Platform.NonWindows) { if (Parameter.sutPlatform == Platform.Win2K3) { // It is not possible to disable the DFS capability from the WS03 the SUT. Condition.IsTrue(isSupportDfs); } } if (Parameter.sutPlatform != Platform.NonWindows) { if (fsType == FileSystemType.Fat) { Parameter.isSupportQuota = false; // In Windows, the Generic file system (FAT) does not support File IDs. Parameter.isSupportUniqueFileId = false; // FAT does not support streams. Parameter.isSupportStream = false; // FAT does not support the previous version. Condition.IsTrue(!isSupportPreviousVersion); Requirement.AssumeCaptured("Server doesn't support stream"); } else { Parameter.isSupportQuota = true; // In Windows, the Generic file system (NTFS) file system supports File IDs. Parameter.isSupportUniqueFileId = true; // NTFS supports streams. Parameter.isSupportStream = true; // NTFS supports the previous version. Condition.IsTrue(isSupportPreviousVersion); Requirement.AssumeCaptured("Server doesn't support stream"); } } Parameter.isSupportPreviousVersion = isSupportPreviousVersion; Parameter.fsType = fsType; Parameter.isSupportDfs = isSupportDfs; Parameter.sutSignState = sutSignState; Parameter.isMessageModePipe = isMessageModePipe; smbState = SmbState.ServerSetupRequest; }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = new LisaRoman(); information = ""; StringBuilder sb = new StringBuilder(); try { if (imagePlugin.Info.ReadableSectorTags == null) { return; } if (!imagePlugin.Info.ReadableSectorTags.Contains(SectorTagType.AppleSectorTag)) { return; } // LisaOS is big-endian BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; // Minimal LisaOS disk is 3.5" single sided double density, 800 sectors if (imagePlugin.Info.Sectors < 800) { return; } int beforeMddf = -1; // LisaOS searches sectors until tag tells MDDF resides there, so we'll search 100 sectors for (int i = 0; i < 100; i++) { DecodeTag(imagePlugin.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag), out LisaTag.PriamTag searchTag); DicConsole.DebugWriteLine("LisaFS plugin", "Sector {0}, file ID 0x{1:X4}", i, searchTag.FileId); if (beforeMddf == -1 && searchTag.FileId == FILEID_LOADER_SIGNED) { beforeMddf = i - 1; } if (searchTag.FileId != FILEID_MDDF) { continue; } byte[] sector = imagePlugin.ReadSector((ulong)i); MDDF infoMddf = new MDDF(); byte[] pString = new byte[33]; infoMddf.fsversion = BigEndianBitConverter.ToUInt16(sector, 0x00); infoMddf.volid = BigEndianBitConverter.ToUInt64(sector, 0x02); infoMddf.volnum = BigEndianBitConverter.ToUInt16(sector, 0x0A); Array.Copy(sector, 0x0C, pString, 0, 33); infoMddf.volname = StringHandlers.PascalToString(pString, Encoding); infoMddf.unknown1 = sector[0x2D]; Array.Copy(sector, 0x2E, pString, 0, 33); // Prevent garbage infoMddf.password = pString[0] <= 32 ? StringHandlers.PascalToString(pString, Encoding) : ""; infoMddf.unknown2 = sector[0x4F]; infoMddf.machine_id = BigEndianBitConverter.ToUInt32(sector, 0x50); infoMddf.master_copy_id = BigEndianBitConverter.ToUInt32(sector, 0x54); uint lisaTime = BigEndianBitConverter.ToUInt32(sector, 0x58); infoMddf.dtvc = DateHandlers.LisaToDateTime(lisaTime); lisaTime = BigEndianBitConverter.ToUInt32(sector, 0x5C); infoMddf.dtcc = DateHandlers.LisaToDateTime(lisaTime); lisaTime = BigEndianBitConverter.ToUInt32(sector, 0x60); infoMddf.dtvb = DateHandlers.LisaToDateTime(lisaTime); lisaTime = BigEndianBitConverter.ToUInt32(sector, 0x64); infoMddf.dtvs = DateHandlers.LisaToDateTime(lisaTime); infoMddf.unknown3 = BigEndianBitConverter.ToUInt32(sector, 0x68); infoMddf.mddf_block = BigEndianBitConverter.ToUInt32(sector, 0x6C); infoMddf.volsize_minus_one = BigEndianBitConverter.ToUInt32(sector, 0x70); infoMddf.volsize_minus_mddf_minus_one = BigEndianBitConverter.ToUInt32(sector, 0x74); infoMddf.vol_size = BigEndianBitConverter.ToUInt32(sector, 0x78); infoMddf.blocksize = BigEndianBitConverter.ToUInt16(sector, 0x7C); infoMddf.datasize = BigEndianBitConverter.ToUInt16(sector, 0x7E); infoMddf.unknown4 = BigEndianBitConverter.ToUInt16(sector, 0x80); infoMddf.unknown5 = BigEndianBitConverter.ToUInt32(sector, 0x82); infoMddf.unknown6 = BigEndianBitConverter.ToUInt32(sector, 0x86); infoMddf.clustersize = BigEndianBitConverter.ToUInt16(sector, 0x8A); infoMddf.fs_size = BigEndianBitConverter.ToUInt32(sector, 0x8C); infoMddf.unknown7 = BigEndianBitConverter.ToUInt32(sector, 0x90); infoMddf.srec_ptr = BigEndianBitConverter.ToUInt32(sector, 0x94); infoMddf.unknown9 = BigEndianBitConverter.ToUInt16(sector, 0x98); infoMddf.srec_len = BigEndianBitConverter.ToUInt16(sector, 0x9A); infoMddf.unknown10 = BigEndianBitConverter.ToUInt32(sector, 0x9C); infoMddf.unknown11 = BigEndianBitConverter.ToUInt32(sector, 0xA0); infoMddf.unknown12 = BigEndianBitConverter.ToUInt32(sector, 0xA4); infoMddf.unknown13 = BigEndianBitConverter.ToUInt32(sector, 0xA8); infoMddf.unknown14 = BigEndianBitConverter.ToUInt32(sector, 0xAC); infoMddf.filecount = BigEndianBitConverter.ToUInt16(sector, 0xB0); infoMddf.unknown15 = BigEndianBitConverter.ToUInt32(sector, 0xB2); infoMddf.unknown16 = BigEndianBitConverter.ToUInt32(sector, 0xB6); infoMddf.freecount = BigEndianBitConverter.ToUInt32(sector, 0xBA); infoMddf.unknown17 = BigEndianBitConverter.ToUInt16(sector, 0xBE); infoMddf.unknown18 = BigEndianBitConverter.ToUInt32(sector, 0xC0); infoMddf.overmount_stamp = BigEndianBitConverter.ToUInt64(sector, 0xC4); infoMddf.serialization = BigEndianBitConverter.ToUInt32(sector, 0xCC); infoMddf.unknown19 = BigEndianBitConverter.ToUInt32(sector, 0xD0); infoMddf.unknown_timestamp = BigEndianBitConverter.ToUInt32(sector, 0xD4); infoMddf.unknown20 = BigEndianBitConverter.ToUInt32(sector, 0xD8); infoMddf.unknown21 = BigEndianBitConverter.ToUInt32(sector, 0xDC); infoMddf.unknown22 = BigEndianBitConverter.ToUInt32(sector, 0xE0); infoMddf.unknown23 = BigEndianBitConverter.ToUInt32(sector, 0xE4); infoMddf.unknown24 = BigEndianBitConverter.ToUInt32(sector, 0xE8); infoMddf.unknown25 = BigEndianBitConverter.ToUInt32(sector, 0xEC); infoMddf.unknown26 = BigEndianBitConverter.ToUInt32(sector, 0xF0); infoMddf.unknown27 = BigEndianBitConverter.ToUInt32(sector, 0xF4); infoMddf.unknown28 = BigEndianBitConverter.ToUInt32(sector, 0xF8); infoMddf.unknown29 = BigEndianBitConverter.ToUInt32(sector, 0xFC); infoMddf.unknown30 = BigEndianBitConverter.ToUInt32(sector, 0x100); infoMddf.unknown31 = BigEndianBitConverter.ToUInt32(sector, 0x104); infoMddf.unknown32 = BigEndianBitConverter.ToUInt32(sector, 0x108); infoMddf.unknown33 = BigEndianBitConverter.ToUInt32(sector, 0x10C); infoMddf.unknown34 = BigEndianBitConverter.ToUInt32(sector, 0x110); infoMddf.unknown35 = BigEndianBitConverter.ToUInt32(sector, 0x114); infoMddf.backup_volid = BigEndianBitConverter.ToUInt64(sector, 0x118); infoMddf.label_size = BigEndianBitConverter.ToUInt16(sector, 0x120); infoMddf.fs_overhead = BigEndianBitConverter.ToUInt16(sector, 0x122); infoMddf.result_scavenge = BigEndianBitConverter.ToUInt16(sector, 0x124); infoMddf.boot_code = BigEndianBitConverter.ToUInt16(sector, 0x126); infoMddf.boot_environ = BigEndianBitConverter.ToUInt16(sector, 0x6C); infoMddf.unknown36 = BigEndianBitConverter.ToUInt32(sector, 0x12A); infoMddf.unknown37 = BigEndianBitConverter.ToUInt32(sector, 0x12E); infoMddf.unknown38 = BigEndianBitConverter.ToUInt32(sector, 0x132); infoMddf.vol_sequence = BigEndianBitConverter.ToUInt16(sector, 0x136); infoMddf.vol_left_mounted = sector[0x138]; DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown1 = 0x{0:X2} ({0})", infoMddf.unknown1); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown2 = 0x{0:X2} ({0})", infoMddf.unknown2); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown3 = 0x{0:X8} ({0})", infoMddf.unknown3); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown4 = 0x{0:X4} ({0})", infoMddf.unknown4); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown5 = 0x{0:X8} ({0})", infoMddf.unknown5); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown6 = 0x{0:X8} ({0})", infoMddf.unknown6); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown7 = 0x{0:X8} ({0})", infoMddf.unknown7); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown9 = 0x{0:X4} ({0})", infoMddf.unknown9); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown10 = 0x{0:X8} ({0})", infoMddf.unknown10); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown11 = 0x{0:X8} ({0})", infoMddf.unknown11); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown12 = 0x{0:X8} ({0})", infoMddf.unknown12); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown13 = 0x{0:X8} ({0})", infoMddf.unknown13); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown14 = 0x{0:X8} ({0})", infoMddf.unknown14); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown15 = 0x{0:X8} ({0})", infoMddf.unknown15); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown16 = 0x{0:X8} ({0})", infoMddf.unknown16); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown17 = 0x{0:X4} ({0})", infoMddf.unknown17); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown18 = 0x{0:X8} ({0})", infoMddf.unknown18); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown19 = 0x{0:X8} ({0})", infoMddf.unknown19); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown20 = 0x{0:X8} ({0})", infoMddf.unknown20); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown21 = 0x{0:X8} ({0})", infoMddf.unknown21); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown22 = 0x{0:X8} ({0})", infoMddf.unknown22); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown23 = 0x{0:X8} ({0})", infoMddf.unknown23); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown24 = 0x{0:X8} ({0})", infoMddf.unknown24); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown25 = 0x{0:X8} ({0})", infoMddf.unknown25); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown26 = 0x{0:X8} ({0})", infoMddf.unknown26); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown27 = 0x{0:X8} ({0})", infoMddf.unknown27); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown28 = 0x{0:X8} ({0})", infoMddf.unknown28); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown29 = 0x{0:X8} ({0})", infoMddf.unknown29); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown30 = 0x{0:X8} ({0})", infoMddf.unknown30); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown31 = 0x{0:X8} ({0})", infoMddf.unknown31); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown32 = 0x{0:X8} ({0})", infoMddf.unknown32); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown33 = 0x{0:X8} ({0})", infoMddf.unknown33); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown34 = 0x{0:X8} ({0})", infoMddf.unknown34); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown35 = 0x{0:X8} ({0})", infoMddf.unknown35); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown36 = 0x{0:X8} ({0})", infoMddf.unknown36); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown37 = 0x{0:X8} ({0})", infoMddf.unknown37); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown38 = 0x{0:X8} ({0})", infoMddf.unknown38); DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown_timestamp = 0x{0:X8} ({0}, {1})", infoMddf.unknown_timestamp, DateHandlers.LisaToDateTime(infoMddf.unknown_timestamp)); if (infoMddf.mddf_block != i - beforeMddf) { return; } if (infoMddf.vol_size > imagePlugin.Info.Sectors) { return; } if (infoMddf.vol_size - 1 != infoMddf.volsize_minus_one) { return; } if (infoMddf.vol_size - i - 1 != infoMddf.volsize_minus_mddf_minus_one - beforeMddf) { return; } if (infoMddf.datasize > infoMddf.blocksize) { return; } if (infoMddf.blocksize < imagePlugin.Info.SectorSize) { return; } if (infoMddf.datasize != imagePlugin.Info.SectorSize) { return; } switch (infoMddf.fsversion) { case LISA_V1: sb.AppendLine("LisaFS v1"); break; case LISA_V2: sb.AppendLine("LisaFS v2"); break; case LISA_V3: sb.AppendLine("LisaFS v3"); break; default: sb.AppendFormat("Uknown LisaFS version {0}", infoMddf.fsversion).AppendLine(); break; } sb.AppendFormat("Volume name: \"{0}\"", infoMddf.volname).AppendLine(); sb.AppendFormat("Volume password: \"{0}\"", infoMddf.password).AppendLine(); sb.AppendFormat("Volume ID: 0x{0:X16}", infoMddf.volid).AppendLine(); sb.AppendFormat("Backup volume ID: 0x{0:X16}", infoMddf.backup_volid).AppendLine(); sb.AppendFormat("Master copy ID: 0x{0:X8}", infoMddf.master_copy_id).AppendLine(); sb.AppendFormat("Volume is number {0} of {1}", infoMddf.volnum, infoMddf.vol_sequence).AppendLine(); sb.AppendFormat("Serial number of Lisa computer that created this volume: {0}", infoMddf.machine_id) .AppendLine(); sb.AppendFormat("Serial number of Lisa computer that can use this volume's software {0}", infoMddf.serialization).AppendLine(); sb.AppendFormat("Volume created on {0}", infoMddf.dtvc).AppendLine(); sb.AppendFormat("Some timestamp, says {0}", infoMddf.dtcc).AppendLine(); sb.AppendFormat("Volume backed up on {0}", infoMddf.dtvb).AppendLine(); sb.AppendFormat("Volume scavenged on {0}", infoMddf.dtvs).AppendLine(); sb.AppendFormat("MDDF is in block {0}", infoMddf.mddf_block + beforeMddf).AppendLine(); sb.AppendFormat("There are {0} reserved blocks before volume", beforeMddf).AppendLine(); sb.AppendFormat("{0} blocks minus one", infoMddf.volsize_minus_one).AppendLine(); sb.AppendFormat("{0} blocks minus one minus MDDF offset", infoMddf.volsize_minus_mddf_minus_one) .AppendLine(); sb.AppendFormat("{0} blocks in volume", infoMddf.vol_size).AppendLine(); sb.AppendFormat("{0} bytes per sector (uncooked)", infoMddf.blocksize).AppendLine(); sb.AppendFormat("{0} bytes per sector", infoMddf.datasize).AppendLine(); sb.AppendFormat("{0} blocks per cluster", infoMddf.clustersize).AppendLine(); sb.AppendFormat("{0} blocks in filesystem", infoMddf.fs_size).AppendLine(); sb.AppendFormat("{0} files in volume", infoMddf.filecount).AppendLine(); sb.AppendFormat("{0} blocks free", infoMddf.freecount).AppendLine(); sb.AppendFormat("{0} bytes in LisaInfo", infoMddf.label_size).AppendLine(); sb.AppendFormat("Filesystem overhead: {0}", infoMddf.fs_overhead).AppendLine(); sb.AppendFormat("Scanvenger result code: 0x{0:X8}", infoMddf.result_scavenge).AppendLine(); sb.AppendFormat("Boot code: 0x{0:X8}", infoMddf.boot_code).AppendLine(); sb.AppendFormat("Boot environment: 0x{0:X8}", infoMddf.boot_environ).AppendLine(); sb.AppendFormat("Overmount stamp: 0x{0:X16}", infoMddf.overmount_stamp).AppendLine(); sb.AppendFormat("S-Records start at {0} and spans for {1} blocks", infoMddf.srec_ptr + infoMddf.mddf_block + beforeMddf, infoMddf.srec_len) .AppendLine(); sb.AppendLine(infoMddf.vol_left_mounted == 0 ? "Volume is clean" : "Volume is dirty"); information = sb.ToString(); XmlFsType = new FileSystemType(); if (DateTime.Compare(infoMddf.dtvb, DateHandlers.LisaToDateTime(0)) > 0) { XmlFsType.BackupDate = infoMddf.dtvb; XmlFsType.BackupDateSpecified = true; } XmlFsType.Clusters = infoMddf.vol_size; XmlFsType.ClusterSize = infoMddf.clustersize * infoMddf.datasize; if (DateTime.Compare(infoMddf.dtvc, DateHandlers.LisaToDateTime(0)) > 0) { XmlFsType.CreationDate = infoMddf.dtvc; XmlFsType.CreationDateSpecified = true; } XmlFsType.Dirty = infoMddf.vol_left_mounted != 0; XmlFsType.Files = infoMddf.filecount; XmlFsType.FilesSpecified = true; XmlFsType.FreeClusters = infoMddf.freecount; XmlFsType.FreeClustersSpecified = true; XmlFsType.Type = "LisaFS"; XmlFsType.VolumeName = infoMddf.volname; XmlFsType.VolumeSerial = $"{infoMddf.volid:X16}"; return; } } catch (Exception ex) { DicConsole.ErrorWriteLine("Exception {0}, {1}, {2}", ex.Message, ex.InnerException, ex.StackTrace); } }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); information = ""; if (imagePlugin.Info.SectorSize < 512) { return; } UNICOS_Superblock unicosSb = new UNICOS_Superblock(); uint sbSize = (uint)(Marshal.SizeOf(unicosSb) / imagePlugin.Info.SectorSize); if (Marshal.SizeOf(unicosSb) % imagePlugin.Info.SectorSize != 0) { sbSize++; } byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize); if (sector.Length < Marshal.SizeOf(unicosSb)) { return; } unicosSb = BigEndianMarshal.ByteArrayToStructureBigEndian <UNICOS_Superblock>(sector); if (unicosSb.s_magic != UNICOS_Magic) { return; } StringBuilder sb = new StringBuilder(); sb.AppendLine("UNICOS filesystem"); if (unicosSb.s_secure == UNICOS_Secure) { sb.AppendLine("Volume is secure"); } sb.AppendFormat("Volume contains {0} partitions", unicosSb.s_npart).AppendLine(); sb.AppendFormat("{0} bytes per sector", unicosSb.s_iounit).AppendLine(); sb.AppendLine("4096 bytes per block"); sb.AppendFormat("{0} data blocks in volume", unicosSb.s_fsize).AppendLine(); sb.AppendFormat("Root resides on inode {0}", unicosSb.s_root).AppendLine(); sb.AppendFormat("{0} inodes in volume", unicosSb.s_isize).AppendLine(); sb.AppendFormat("Volume last updated on {0}", DateHandlers.UnixToDateTime(unicosSb.s_time)).AppendLine(); if (unicosSb.s_error > 0) { sb.AppendFormat("Volume is dirty, error code = 0x{0:X16}", unicosSb.s_error).AppendLine(); } sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(unicosSb.s_fname, Encoding)).AppendLine(); information = sb.ToString(); XmlFsType = new FileSystemType { Type = "UNICOS filesystem", ClusterSize = 4096, Clusters = unicosSb.s_fsize, VolumeName = StringHandlers.CToString(unicosSb.s_fname, Encoding), ModificationDate = DateHandlers.UnixToDateTime(unicosSb.s_time), ModificationDateSpecified = true }; XmlFsType.Dirty |= unicosSb.s_error > 0; }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); StringBuilder sbInformation = new StringBuilder(); XmlFsType = new FileSystemType(); information = ""; ulong sbSectorOff = 0x10000 / imagePlugin.Info.SectorSize; uint sbSectorSize = 0x1000 / imagePlugin.Info.SectorSize; byte[] sector = imagePlugin.ReadSectors(sbSectorOff + partition.Start, sbSectorSize); GCHandle handle = GCHandle.Alloc(sector, GCHandleType.Pinned); SuperBlock btrfsSb = (SuperBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(SuperBlock)); handle.Free(); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.checksum = {0}", btrfsSb.checksum); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.uuid = {0}", btrfsSb.uuid); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.pba = {0}", btrfsSb.pba); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.flags = {0}", btrfsSb.flags); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.magic = {0}", btrfsSb.magic); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.generation = {0}", btrfsSb.generation); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.root_lba = {0}", btrfsSb.root_lba); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.chunk_lba = {0}", btrfsSb.chunk_lba); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.log_lba = {0}", btrfsSb.log_lba); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.log_root_transid = {0}", btrfsSb.log_root_transid); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.total_bytes = {0}", btrfsSb.total_bytes); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.bytes_used = {0}", btrfsSb.bytes_used); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.root_dir_objectid = {0}", btrfsSb.root_dir_objectid); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.num_devices = {0}", btrfsSb.num_devices); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.sectorsize = {0}", btrfsSb.sectorsize); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.nodesize = {0}", btrfsSb.nodesize); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.leafsize = {0}", btrfsSb.leafsize); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.stripesize = {0}", btrfsSb.stripesize); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.n = {0}", btrfsSb.n); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.chunk_root_generation = {0}", btrfsSb.chunk_root_generation); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.compat_flags = 0x{0:X16}", btrfsSb.compat_flags); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.compat_ro_flags = 0x{0:X16}", btrfsSb.compat_ro_flags); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.incompat_flags = 0x{0:X16}", btrfsSb.incompat_flags); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.csum_type = {0}", btrfsSb.csum_type); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.root_level = {0}", btrfsSb.root_level); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.chunk_root_level = {0}", btrfsSb.chunk_root_level); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.log_root_level = {0}", btrfsSb.log_root_level); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.id = 0x{0:X16}", btrfsSb.dev_item.id); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.bytes = {0}", btrfsSb.dev_item.bytes); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.used = {0}", btrfsSb.dev_item.used); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.optimal_align = {0}", btrfsSb.dev_item.optimal_align); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.optimal_width = {0}", btrfsSb.dev_item.optimal_width); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.minimal_size = {0}", btrfsSb.dev_item.minimal_size); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.type = {0}", btrfsSb.dev_item.type); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.generation = {0}", btrfsSb.dev_item.generation); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.start_offset = {0}", btrfsSb.dev_item.start_offset); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.dev_group = {0}", btrfsSb.dev_item.dev_group); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.seek_speed = {0}", btrfsSb.dev_item.seek_speed); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.bandwitdh = {0}", btrfsSb.dev_item.bandwitdh); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.device_uuid = {0}", btrfsSb.dev_item.device_uuid); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.dev_item.uuid = {0}", btrfsSb.dev_item.uuid); DicConsole.DebugWriteLine("BTRFS Plugin", "btrfsSb.label = {0}", btrfsSb.label); sbInformation.AppendLine("B-tree filesystem"); sbInformation.AppendFormat("UUID: {0}", btrfsSb.uuid).AppendLine(); sbInformation.AppendFormat("This superblock resides on physical block {0}", btrfsSb.pba).AppendLine(); sbInformation.AppendFormat("Root tree starts at LBA {0}", btrfsSb.root_lba).AppendLine(); sbInformation.AppendFormat("Chunk tree starts at LBA {0}", btrfsSb.chunk_lba).AppendLine(); sbInformation.AppendFormat("Log tree starts at LBA {0}", btrfsSb.log_lba).AppendLine(); sbInformation.AppendFormat("Volume has {0} bytes spanned in {1} devices", btrfsSb.total_bytes, btrfsSb.num_devices).AppendLine(); sbInformation.AppendFormat("Volume has {0} bytes used", btrfsSb.bytes_used).AppendLine(); sbInformation.AppendFormat("{0} bytes/sector", btrfsSb.sectorsize).AppendLine(); sbInformation.AppendFormat("{0} bytes/node", btrfsSb.nodesize).AppendLine(); sbInformation.AppendFormat("{0} bytes/leaf", btrfsSb.leafsize).AppendLine(); sbInformation.AppendFormat("{0} bytes/stripe", btrfsSb.stripesize).AppendLine(); sbInformation.AppendFormat("Flags: 0x{0:X}", btrfsSb.flags).AppendLine(); sbInformation.AppendFormat("Compatible flags: 0x{0:X}", btrfsSb.compat_flags).AppendLine(); sbInformation.AppendFormat("Read-only compatible flags: 0x{0:X}", btrfsSb.compat_ro_flags).AppendLine(); sbInformation.AppendFormat("Incompatible flags: 0x{0:X}", btrfsSb.incompat_flags).AppendLine(); sbInformation.AppendFormat("Device's UUID: {0}", btrfsSb.dev_item.uuid).AppendLine(); sbInformation.AppendFormat("Volume label: {0}", btrfsSb.label).AppendLine(); information = sbInformation.ToString(); XmlFsType = new FileSystemType { Clusters = (long)(btrfsSb.total_bytes / btrfsSb.sectorsize), ClusterSize = (int)btrfsSb.sectorsize, FreeClustersSpecified = true, VolumeName = btrfsSb.label, VolumeSerial = $"{btrfsSb.uuid}", VolumeSetIdentifier = $"{btrfsSb.dev_item.device_uuid}", Type = Name }; XmlFsType.FreeClusters = XmlFsType.Clusters - (long)(btrfsSb.bytes_used / btrfsSb.sectorsize); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("IBM437"); information = ""; var sb = new StringBuilder(); XmlFsType = new FileSystemType(); uint sectorsPerBpb = imagePlugin.Info.SectorSize < 512 ? 512 / imagePlugin.Info.SectorSize : 1; byte[] bpbSector = imagePlugin.ReadSectors(0 + partition.Start, sectorsPerBpb); BpbKind bpbKind = DetectBpbKind(bpbSector, imagePlugin, partition, out BiosParameterBlockEbpb fakeBpb, out HumanParameterBlock humanBpb, out AtariParameterBlock atariBpb, out byte minBootNearJump, out bool andosOemCorrect, out bool bootable); bool isFat12 = false; bool isFat16 = false; bool isFat32 = false; ulong rootDirectorySector = 0; string extraInfo = null; string bootChk = null; XmlFsType.Bootable = bootable; // This is needed because for FAT16, GEMDOS increases bytes per sector count instead of using big_sectors field. uint sectorsPerRealSector; // This is needed because some OSes don't put volume label as first entry in the root directory uint sectorsForRootDirectory = 0; switch (bpbKind) { case BpbKind.DecRainbow: case BpbKind.Hardcoded: case BpbKind.Msx: case BpbKind.Apricot: isFat12 = true; break; case BpbKind.ShortFat32: case BpbKind.LongFat32: { isFat32 = true; Fat32ParameterBlock fat32Bpb = Marshal.ByteArrayToStructureLittleEndian <Fat32ParameterBlock>(bpbSector); Fat32ParameterBlockShort shortFat32Bpb = Marshal.ByteArrayToStructureLittleEndian <Fat32ParameterBlockShort>(bpbSector); // This is to support FAT partitions on hybrid ISO/USB images if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) { fat32Bpb.bps *= 4; fat32Bpb.spc /= 4; fat32Bpb.big_spfat /= 4; fat32Bpb.hsectors /= 4; fat32Bpb.sptrk /= 4; } if (fat32Bpb.version != 0) { sb.AppendLine("FAT+"); XmlFsType.Type = "FAT+"; } else { sb.AppendLine("Microsoft FAT32"); XmlFsType.Type = "FAT32"; } if (fat32Bpb.oem_name != null) { if (fat32Bpb.oem_name[5] == 0x49 && fat32Bpb.oem_name[6] == 0x48 && fat32Bpb.oem_name[7] == 0x43) { sb.AppendLine("Volume has been modified by Windows 9x/Me Volume Tracker."); } else { XmlFsType.SystemIdentifier = StringHandlers.CToString(fat32Bpb.oem_name); } } if (!string.IsNullOrEmpty(XmlFsType.SystemIdentifier)) { sb.AppendFormat("OEM Name: {0}", XmlFsType.SystemIdentifier.Trim()).AppendLine(); } sb.AppendFormat("{0} bytes per sector.", fat32Bpb.bps).AppendLine(); sb.AppendFormat("{0} sectors per cluster.", fat32Bpb.spc).AppendLine(); XmlFsType.ClusterSize = (uint)(fat32Bpb.bps * fat32Bpb.spc); sb.AppendFormat("{0} sectors reserved between BPB and FAT.", fat32Bpb.rsectors).AppendLine(); if (fat32Bpb.big_sectors == 0 && fat32Bpb.signature == 0x28) { sb.AppendFormat("{0} sectors on volume ({1} bytes).", shortFat32Bpb.huge_sectors, shortFat32Bpb.huge_sectors * shortFat32Bpb.bps).AppendLine(); XmlFsType.Clusters = shortFat32Bpb.huge_sectors / shortFat32Bpb.spc; } else { sb.AppendFormat("{0} sectors on volume ({1} bytes).", fat32Bpb.big_sectors, fat32Bpb.big_sectors * fat32Bpb.bps).AppendLine(); XmlFsType.Clusters = fat32Bpb.big_sectors / fat32Bpb.spc; } sb.AppendFormat("{0} clusters on volume.", XmlFsType.Clusters).AppendLine(); sb.AppendFormat("Media descriptor: 0x{0:X2}", fat32Bpb.media).AppendLine(); sb.AppendFormat("{0} sectors per FAT.", fat32Bpb.big_spfat).AppendLine(); sb.AppendFormat("{0} sectors per track.", fat32Bpb.sptrk).AppendLine(); sb.AppendFormat("{0} heads.", fat32Bpb.heads).AppendLine(); sb.AppendFormat("{0} hidden sectors before BPB.", fat32Bpb.hsectors).AppendLine(); sb.AppendFormat("Cluster of root directory: {0}", fat32Bpb.root_cluster).AppendLine(); sb.AppendFormat("Sector of FSINFO structure: {0}", fat32Bpb.fsinfo_sector).AppendLine(); sb.AppendFormat("Sector of backup FAT32 parameter block: {0}", fat32Bpb.backup_sector).AppendLine(); sb.AppendFormat("Drive number: 0x{0:X2}", fat32Bpb.drive_no).AppendLine(); sb.AppendFormat("Volume Serial Number: 0x{0:X8}", fat32Bpb.serial_no).AppendLine(); XmlFsType.VolumeSerial = $"{fat32Bpb.serial_no:X8}"; if ((fat32Bpb.flags & 0xF8) == 0x00) { if ((fat32Bpb.flags & 0x01) == 0x01) { sb.AppendLine("Volume should be checked on next mount."); XmlFsType.Dirty = true; } if ((fat32Bpb.flags & 0x02) == 0x02) { sb.AppendLine("Disk surface should be on next mount."); } } if ((fat32Bpb.mirror_flags & 0x80) == 0x80) { sb.AppendFormat("FATs are out of sync. FAT #{0} is in use.", fat32Bpb.mirror_flags & 0xF). AppendLine(); } else { sb.AppendLine("All copies of FAT are the same."); } if ((fat32Bpb.mirror_flags & 0x6F20) == 0x6F20) { sb.AppendLine("DR-DOS will boot this FAT32 using CHS."); } else if ((fat32Bpb.mirror_flags & 0x4F20) == 0x4F20) { sb.AppendLine("DR-DOS will boot this FAT32 using LBA."); } if (fat32Bpb.signature == 0x29) { XmlFsType.VolumeName = Encoding.ASCII.GetString(fat32Bpb.volume_label); sb.AppendFormat("Filesystem type: {0}", Encoding.ASCII.GetString(fat32Bpb.fs_type)). AppendLine(); bootChk = Sha1Context.Data(fat32Bpb.boot_code, out _); } else { bootChk = Sha1Context.Data(shortFat32Bpb.boot_code, out _); } // Check that jumps to a correct boot code position and has boot signature set. // This will mean that the volume will boot, even if just to say "this is not bootable change disk"...... XmlFsType.Bootable = (fat32Bpb.jump[0] == 0xEB && fat32Bpb.jump[1] >= minBootNearJump && fat32Bpb.jump[1] < 0x80) || (fat32Bpb.jump[0] == 0xE9 && fat32Bpb.jump.Length >= 3 && BitConverter.ToUInt16(fat32Bpb.jump, 1) >= minBootNearJump && BitConverter.ToUInt16(fat32Bpb.jump, 1) <= 0x1FC); sectorsPerRealSector = fat32Bpb.bps / imagePlugin.Info.SectorSize; // First root directory sector rootDirectorySector = (ulong)(((fat32Bpb.root_cluster - 2) * fat32Bpb.spc) + (fat32Bpb.big_spfat * fat32Bpb.fats_no) + fat32Bpb.rsectors) * sectorsPerRealSector; sectorsForRootDirectory = 1; if (fat32Bpb.fsinfo_sector + partition.Start <= partition.End) { byte[] fsinfoSector = imagePlugin.ReadSector(fat32Bpb.fsinfo_sector + partition.Start); FsInfoSector fsInfo = Marshal.ByteArrayToStructureLittleEndian <FsInfoSector>(fsinfoSector); if (fsInfo.signature1 == FSINFO_SIGNATURE1 && fsInfo.signature2 == FSINFO_SIGNATURE2 && fsInfo.signature3 == FSINFO_SIGNATURE3) { if (fsInfo.free_clusters < 0xFFFFFFFF) { sb.AppendFormat("{0} free clusters", fsInfo.free_clusters).AppendLine(); XmlFsType.FreeClusters = fsInfo.free_clusters; XmlFsType.FreeClustersSpecified = true; } if (fsInfo.last_cluster > 2 && fsInfo.last_cluster < 0xFFFFFFFF) { sb.AppendFormat("Last allocated cluster {0}", fsInfo.last_cluster).AppendLine(); } } } break; } // Some fields could overflow fake BPB, those will be handled below case BpbKind.Atari: { ushort sum = 0; for (int i = 0; i < bpbSector.Length; i += 2) { sum += BigEndianBitConverter.ToUInt16(bpbSector, i); } // TODO: Check this if (sum == 0x1234) { XmlFsType.Bootable = true; var atariSb = new StringBuilder(); atariSb.AppendFormat("cmdload will be loaded with value {0:X4}h", BigEndianBitConverter.ToUInt16(bpbSector, 0x01E)).AppendLine(); atariSb.AppendFormat("Boot program will be loaded at address {0:X4}h", atariBpb.ldaaddr). AppendLine(); atariSb.AppendFormat("FAT and directory will be cached at address {0:X4}h", atariBpb.fatbuf). AppendLine(); if (atariBpb.ldmode == 0) { byte[] tmp = new byte[8]; Array.Copy(atariBpb.fname, 0, tmp, 0, 8); string fname = Encoding.ASCII.GetString(tmp).Trim(); tmp = new byte[3]; Array.Copy(atariBpb.fname, 8, tmp, 0, 3); string extension = Encoding.ASCII.GetString(tmp).Trim(); string filename; if (string.IsNullOrEmpty(extension)) { filename = fname; } else { filename = fname + "." + extension; } atariSb.AppendFormat("Boot program resides in file \"{0}\"", filename).AppendLine(); } else { atariSb. AppendFormat("Boot program starts in sector {0} and is {1} sectors long ({2} bytes)", atariBpb.ssect, atariBpb.sectcnt, atariBpb.sectcnt * atariBpb.bps). AppendLine(); } extraInfo = atariSb.ToString(); } break; } case BpbKind.Human: XmlFsType.Bootable = true; break; } if (!isFat32) { // This is to support FAT partitions on hybrid ISO/USB images if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) { fakeBpb.bps *= 4; fakeBpb.spc /= 4; fakeBpb.spfat /= 4; fakeBpb.hsectors /= 4; fakeBpb.sptrk /= 4; fakeBpb.rsectors /= 4; if (fakeBpb.spc == 0) { fakeBpb.spc = 1; } } // This assumes no sane implementation will violate cluster size rules // However nothing prevents this to happen // If first file on disk uses only one cluster there is absolutely no way to differentiate between FAT12 and FAT16, // so let's hope implementations use common sense? if (!isFat12 && !isFat16) { ulong clusters; if (fakeBpb.sectors == 0) { clusters = fakeBpb.spc == 0 ? fakeBpb.big_sectors : fakeBpb.big_sectors / fakeBpb.spc; } else { clusters = fakeBpb.spc == 0 ? fakeBpb.sectors : (ulong)fakeBpb.sectors / fakeBpb.spc; } if (clusters < 4089) { isFat12 = true; } else { isFat16 = true; } } if (isFat12) { switch (bpbKind) { case BpbKind.Atari: sb.AppendLine("Atari FAT12"); break; case BpbKind.Apricot: sb.AppendLine("Apricot FAT12"); break; case BpbKind.Human: sb.AppendLine("Human68k FAT12"); break; default: sb.AppendLine("Microsoft FAT12"); break; } XmlFsType.Type = "FAT12"; } else if (isFat16) { sb.AppendLine(bpbKind == BpbKind.Atari ? "Atari FAT16" : bpbKind == BpbKind.Human ? "Human68k FAT16" : "Microsoft FAT16"); XmlFsType.Type = "FAT16"; } if (bpbKind == BpbKind.Atari) { if (atariBpb.serial_no[0] == 0x49 && atariBpb.serial_no[1] == 0x48 && atariBpb.serial_no[2] == 0x43) { sb.AppendLine("Volume has been modified by Windows 9x/Me Volume Tracker."); } else { XmlFsType.VolumeSerial = $"{atariBpb.serial_no[0]:X2}{atariBpb.serial_no[1]:X2}{atariBpb.serial_no[2]:X2}"; } XmlFsType.SystemIdentifier = StringHandlers.CToString(atariBpb.oem_name); if (string.IsNullOrEmpty(XmlFsType.SystemIdentifier)) { XmlFsType.SystemIdentifier = null; } } else if (fakeBpb.oem_name != null) { if (fakeBpb.oem_name[5] == 0x49 && fakeBpb.oem_name[6] == 0x48 && fakeBpb.oem_name[7] == 0x43) { sb.AppendLine("Volume has been modified by Windows 9x/Me Volume Tracker."); } else { // Later versions of Windows create a DOS 3 BPB without OEM name on 8 sectors/track floppies // OEM ID should be ASCII, otherwise ignore it if (fakeBpb.oem_name[0] >= 0x20 && fakeBpb.oem_name[0] <= 0x7F && fakeBpb.oem_name[1] >= 0x20 && fakeBpb.oem_name[1] <= 0x7F && fakeBpb.oem_name[2] >= 0x20 && fakeBpb.oem_name[2] <= 0x7F && fakeBpb.oem_name[3] >= 0x20 && fakeBpb.oem_name[3] <= 0x7F && fakeBpb.oem_name[4] >= 0x20 && fakeBpb.oem_name[4] <= 0x7F && fakeBpb.oem_name[5] >= 0x20 && fakeBpb.oem_name[5] <= 0x7F && fakeBpb.oem_name[6] >= 0x20 && fakeBpb.oem_name[6] <= 0x7F && fakeBpb.oem_name[7] >= 0x20 && fakeBpb.oem_name[7] <= 0x7F) { XmlFsType.SystemIdentifier = StringHandlers.CToString(fakeBpb.oem_name); } else if (fakeBpb.oem_name[0] < 0x20 && fakeBpb.oem_name[1] >= 0x20 && fakeBpb.oem_name[1] <= 0x7F && fakeBpb.oem_name[2] >= 0x20 && fakeBpb.oem_name[2] <= 0x7F && fakeBpb.oem_name[3] >= 0x20 && fakeBpb.oem_name[3] <= 0x7F && fakeBpb.oem_name[4] >= 0x20 && fakeBpb.oem_name[4] <= 0x7F && fakeBpb.oem_name[5] >= 0x20 && fakeBpb.oem_name[5] <= 0x7F && fakeBpb.oem_name[6] >= 0x20 && fakeBpb.oem_name[6] <= 0x7F && fakeBpb.oem_name[7] >= 0x20 && fakeBpb.oem_name[7] <= 0x7F) { XmlFsType.SystemIdentifier = StringHandlers.CToString(fakeBpb.oem_name, Encoding, start: 1); } } if (fakeBpb.signature == 0x28 || fakeBpb.signature == 0x29) { XmlFsType.VolumeSerial = $"{fakeBpb.serial_no:X8}"; } } if (XmlFsType.SystemIdentifier != null) { sb.AppendFormat("OEM Name: {0}", XmlFsType.SystemIdentifier.Trim()).AppendLine(); } sb.AppendFormat("{0} bytes per sector.", fakeBpb.bps).AppendLine(); if (bpbKind != BpbKind.Human) { if (fakeBpb.sectors == 0) { sb.AppendFormat("{0} sectors on volume ({1} bytes).", fakeBpb.big_sectors, fakeBpb.big_sectors * fakeBpb.bps).AppendLine(); XmlFsType.Clusters = fakeBpb.spc == 0 ? fakeBpb.big_sectors : fakeBpb.big_sectors / fakeBpb.spc; } else { sb.AppendFormat("{0} sectors on volume ({1} bytes).", fakeBpb.sectors, fakeBpb.sectors * fakeBpb.bps).AppendLine(); XmlFsType.Clusters = (ulong)(fakeBpb.spc == 0 ? fakeBpb.sectors : fakeBpb.sectors / fakeBpb.spc); } } else { XmlFsType.Clusters = humanBpb.clusters == 0 ? humanBpb.big_clusters : humanBpb.clusters; sb.AppendFormat("{0} sectors on volume ({1} bytes).", (XmlFsType.Clusters * humanBpb.bpc) / imagePlugin.Info.SectorSize, XmlFsType.Clusters * humanBpb.bpc).AppendLine(); } sb.AppendFormat("{0} sectors per cluster.", fakeBpb.spc).AppendLine(); sb.AppendFormat("{0} clusters on volume.", XmlFsType.Clusters).AppendLine(); XmlFsType.ClusterSize = (uint)(fakeBpb.bps * fakeBpb.spc); sb.AppendFormat("{0} sectors reserved between BPB and FAT.", fakeBpb.rsectors).AppendLine(); sb.AppendFormat("{0} FATs.", fakeBpb.fats_no).AppendLine(); sb.AppendFormat("{0} entries on root directory.", fakeBpb.root_ent).AppendLine(); if (fakeBpb.media > 0) { sb.AppendFormat("Media descriptor: 0x{0:X2}", fakeBpb.media).AppendLine(); } sb.AppendFormat("{0} sectors per FAT.", fakeBpb.spfat).AppendLine(); if (fakeBpb.sptrk > 0 && fakeBpb.sptrk < 64 && fakeBpb.heads > 0 && fakeBpb.heads < 256) { sb.AppendFormat("{0} sectors per track.", fakeBpb.sptrk).AppendLine(); sb.AppendFormat("{0} heads.", fakeBpb.heads).AppendLine(); } if (fakeBpb.hsectors <= partition.Start) { sb.AppendFormat("{0} hidden sectors before BPB.", fakeBpb.hsectors).AppendLine(); } if (fakeBpb.signature == 0x28 || fakeBpb.signature == 0x29 || andosOemCorrect) { sb.AppendFormat("Drive number: 0x{0:X2}", fakeBpb.drive_no).AppendLine(); if (XmlFsType.VolumeSerial != null) { sb.AppendFormat("Volume Serial Number: {0}", XmlFsType.VolumeSerial).AppendLine(); } if ((fakeBpb.flags & 0xF8) == 0x00) { if ((fakeBpb.flags & 0x01) == 0x01) { sb.AppendLine("Volume should be checked on next mount."); XmlFsType.Dirty = true; } if ((fakeBpb.flags & 0x02) == 0x02) { sb.AppendLine("Disk surface should be on next mount."); } } if (fakeBpb.signature == 0x29 || andosOemCorrect) { XmlFsType.VolumeName = Encoding.ASCII.GetString(fakeBpb.volume_label); sb.AppendFormat("Filesystem type: {0}", Encoding.ASCII.GetString(fakeBpb.fs_type)).AppendLine(); } } else if (bpbKind == BpbKind.Atari && XmlFsType.VolumeSerial != null) { sb.AppendFormat("Volume Serial Number: {0}", XmlFsType.VolumeSerial).AppendLine(); } bootChk = Sha1Context.Data(fakeBpb.boot_code, out _); // Workaround that PCExchange jumps into "FAT16 "... if (XmlFsType.SystemIdentifier == "PCX 2.0 ") { fakeBpb.jump[1] += 8; } // Check that jumps to a correct boot code position and has boot signature set. // This will mean that the volume will boot, even if just to say "this is not bootable change disk"...... if (XmlFsType.Bootable == false && fakeBpb.jump != null) { XmlFsType.Bootable |= (fakeBpb.jump[0] == 0xEB && fakeBpb.jump[1] >= minBootNearJump && fakeBpb.jump[1] < 0x80) || (fakeBpb.jump[0] == 0xE9 && fakeBpb.jump.Length >= 3 && BitConverter.ToUInt16(fakeBpb.jump, 1) >= minBootNearJump && BitConverter.ToUInt16(fakeBpb.jump, 1) <= 0x1FC); } sectorsPerRealSector = fakeBpb.bps / imagePlugin.Info.SectorSize; // First root directory sector rootDirectorySector = (ulong)((fakeBpb.spfat * fakeBpb.fats_no) + fakeBpb.rsectors) * sectorsPerRealSector; sectorsForRootDirectory = (uint)((fakeBpb.root_ent * 32) / imagePlugin.Info.SectorSize); } if (extraInfo != null) { sb.Append(extraInfo); } if (rootDirectorySector + partition.Start < partition.End && imagePlugin.Info.XmlMediaType != XmlMediaType.OpticalDisc) { byte[] rootDirectory = imagePlugin.ReadSectors(rootDirectorySector + partition.Start, sectorsForRootDirectory); if (bpbKind == BpbKind.DecRainbow) { var rootMs = new MemoryStream(); foreach (byte[] tmp in from ulong rootSector in new[] { 0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20 } select imagePlugin.ReadSector(rootSector)) { rootMs.Write(tmp, 0, tmp.Length); } rootDirectory = rootMs.ToArray(); } for (int i = 0; i < rootDirectory.Length; i += 32) { // Not a correct entry if (rootDirectory[i] < DIRENT_MIN && rootDirectory[i] != DIRENT_E5) { continue; } // Deleted or subdirectory entry if (rootDirectory[i] == DIRENT_SUBDIR || rootDirectory[i] == DIRENT_DELETED) { continue; } // Not a volume label if (rootDirectory[i + 0x0B] != 0x08 && rootDirectory[i + 0x0B] != 0x28) { continue; } DirectoryEntry entry = Marshal.ByteArrayToStructureLittleEndian <DirectoryEntry>(rootDirectory, i, 32); byte[] fullname = new byte[11]; Array.Copy(entry.filename, 0, fullname, 0, 8); Array.Copy(entry.extension, 0, fullname, 8, 3); string volname = Encoding.GetString(fullname).Trim(); if (!string.IsNullOrEmpty(volname)) { XmlFsType.VolumeName = entry.caseinfo.HasFlag(CaseInfo.AllLowerCase) ? volname.ToLower() : volname; } if (entry.ctime > 0 && entry.cdate > 0) { XmlFsType.CreationDate = DateHandlers.DosToDateTime(entry.cdate, entry.ctime); if (entry.ctime_ms > 0) { XmlFsType.CreationDate = XmlFsType.CreationDate.AddMilliseconds(entry.ctime_ms * 10); } XmlFsType.CreationDateSpecified = true; sb.AppendFormat("Volume created on {0}", XmlFsType.CreationDate).AppendLine(); } if (entry.mtime > 0 && entry.mdate > 0) { XmlFsType.ModificationDate = DateHandlers.DosToDateTime(entry.mdate, entry.mtime); XmlFsType.ModificationDateSpecified = true; sb.AppendFormat("Volume last modified on {0}", XmlFsType.ModificationDate).AppendLine(); } if (entry.adate > 0) { sb.AppendFormat("Volume last accessed on {0:d}", DateHandlers.DosToDateTime(entry.adate, 0)). AppendLine(); } break; } } if (!string.IsNullOrEmpty(XmlFsType.VolumeName)) { sb.AppendFormat("Volume label: {0}", XmlFsType.VolumeName).AppendLine(); } if (XmlFsType.Bootable) { // Intel short jump if (bpbSector[0] == 0xEB && bpbSector[1] < 0x80) { int sigSize = bpbSector[510] == 0x55 && bpbSector[511] == 0xAA ? 2 : 0; byte[] bootCode = new byte[512 - sigSize - bpbSector[1] - 2]; Array.Copy(bpbSector, bpbSector[1] + 2, bootCode, 0, bootCode.Length); Sha1Context.Data(bootCode, out _); } // Intel big jump else if (bpbSector[0] == 0xE9 && BitConverter.ToUInt16(bpbSector, 1) < 0x1FC) { int sigSize = bpbSector[510] == 0x55 && bpbSector[511] == 0xAA ? 2 : 0; byte[] bootCode = new byte[512 - sigSize - BitConverter.ToUInt16(bpbSector, 1) - 3]; Array.Copy(bpbSector, BitConverter.ToUInt16(bpbSector, 1) + 3, bootCode, 0, bootCode.Length); Sha1Context.Data(bootCode, out _); } sb.AppendLine("Volume is bootable"); sb.AppendFormat("Boot code's SHA1: {0}", bootChk).AppendLine(); string bootName = _knownBootHashes.FirstOrDefault(t => t.hash == bootChk).name; if (string.IsNullOrWhiteSpace(bootName)) { sb.AppendLine("Unknown boot code."); } else { sb.AppendFormat("Boot code corresponds to {0}", bootName).AppendLine(); } } information = sb.ToString(); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.UTF8; information = ""; if (imagePlugin.Info.SectorSize < 512) { return; } uint sbAddr = NILFS2_SUPER_OFFSET / imagePlugin.Info.SectorSize; if (sbAddr == 0) { sbAddr = 1; } uint sbSize = (uint)(Marshal.SizeOf <NILFS2_Superblock>() / imagePlugin.Info.SectorSize); if (Marshal.SizeOf <NILFS2_Superblock>() % imagePlugin.Info.SectorSize != 0) { sbSize++; } byte[] sector = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize); if (sector.Length < Marshal.SizeOf <NILFS2_Superblock>()) { return; } NILFS2_Superblock nilfsSb = Marshal.ByteArrayToStructureLittleEndian <NILFS2_Superblock>(sector); if (nilfsSb.magic != NILFS2_MAGIC) { return; } var sb = new StringBuilder(); sb.AppendLine("NILFS2 filesystem"); sb.AppendFormat("Version {0}.{1}", nilfsSb.rev_level, nilfsSb.minor_rev_level).AppendLine(); sb.AppendFormat("{0} bytes per block", 1 << (int)(nilfsSb.log_block_size + 10)).AppendLine(); sb.AppendFormat("{0} bytes in volume", nilfsSb.dev_size).AppendLine(); sb.AppendFormat("{0} blocks per segment", nilfsSb.blocks_per_segment).AppendLine(); sb.AppendFormat("{0} segments", nilfsSb.nsegments).AppendLine(); if (nilfsSb.creator_os == 0) { sb.AppendLine("Filesystem created on Linux"); } else { sb.AppendFormat("Creator OS code: {0}", nilfsSb.creator_os).AppendLine(); } sb.AppendFormat("{0} bytes per inode", nilfsSb.inode_size).AppendLine(); sb.AppendFormat("Volume UUID: {0}", nilfsSb.uuid).AppendLine(); sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(nilfsSb.volume_name, Encoding)).AppendLine(); sb.AppendFormat("Volume created on {0}", DateHandlers.UnixUnsignedToDateTime(nilfsSb.ctime)).AppendLine(); sb.AppendFormat("Volume last mounted on {0}", DateHandlers.UnixUnsignedToDateTime(nilfsSb.mtime)). AppendLine(); sb.AppendFormat("Volume last written on {0}", DateHandlers.UnixUnsignedToDateTime(nilfsSb.wtime)). AppendLine(); information = sb.ToString(); XmlFsType = new FileSystemType { Type = "NILFS2 filesystem", ClusterSize = (uint)(1 << (int)(nilfsSb.log_block_size + 10)), VolumeName = StringHandlers.CToString(nilfsSb.volume_name, Encoding), VolumeSerial = nilfsSb.uuid.ToString(), CreationDate = DateHandlers.UnixUnsignedToDateTime(nilfsSb.ctime), CreationDateSpecified = true, ModificationDate = DateHandlers.UnixUnsignedToDateTime(nilfsSb.wtime), ModificationDateSpecified = true }; if (nilfsSb.creator_os == 0) { XmlFsType.SystemIdentifier = "Linux"; } XmlFsType.Clusters = nilfsSb.dev_size / XmlFsType.ClusterSize; }
/// <summary> /// Mounts an Apple Lisa filesystem /// </summary> public Errno Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, Dictionary <string, string> options, string @namespace) { XmlFsType = new FileSystemType(); if (options == null) { options = GetDefaultOptions(); } if (options.TryGetValue("debug", out string debugString)) { bool.TryParse(debugString, out debug); } // Default namespace if (@namespace is null) { @namespace = "ecs"; } switch (@namespace.ToLowerInvariant()) { case "dos": this.@namespace = Namespace.Dos; break; case "nt": this.@namespace = Namespace.Nt; break; case "os2": this.@namespace = Namespace.Os2; break; case "ecs": this.@namespace = Namespace.Ecs; break; case "lfn": this.@namespace = Namespace.Lfn; break; case "human": this.@namespace = Namespace.Human; break; default: return(Errno.InvalidArgument); } DicConsole.DebugWriteLine("FAT plugin", "Reading BPB"); uint sectorsPerBpb = imagePlugin.Info.SectorSize < 512 ? 512 / imagePlugin.Info.SectorSize : 1; byte[] bpbSector = imagePlugin.ReadSectors(0 + partition.Start, sectorsPerBpb); BpbKind bpbKind = DetectBpbKind(bpbSector, imagePlugin, partition, out BiosParameterBlockEbpb fakeBpb, out HumanParameterBlock humanBpb, out AtariParameterBlock atariBpb, out byte minBootNearJump, out bool andosOemCorrect, out bool bootable); fat12 = false; fat16 = false; fat32 = false; useFirstFat = true; XmlFsType.Bootable = bootable; statfs = new FileSystemInfo { Blocks = XmlFsType.Clusters, FilenameLength = 11, Files = 0, // Requires traversing all directories FreeFiles = 0, PluginId = Id, FreeBlocks = 0 // Requires traversing the FAT }; // This is needed because for FAT16, GEMDOS increases bytes per sector count instead of using big_sectors field. uint sectorsPerRealSector = 1; // This is needed because some OSes don't put volume label as first entry in the root directory uint sectorsForRootDirectory = 0; uint rootDirectoryCluster = 0; switch (bpbKind) { case BpbKind.DecRainbow: case BpbKind.Hardcoded: case BpbKind.Msx: case BpbKind.Apricot: fat12 = true; break; case BpbKind.ShortFat32: case BpbKind.LongFat32: { fat32 = true; Fat32ParameterBlock fat32Bpb = Marshal.ByteArrayToStructureLittleEndian <Fat32ParameterBlock>(bpbSector); Fat32ParameterBlockShort shortFat32Bpb = Marshal.ByteArrayToStructureLittleEndian <Fat32ParameterBlockShort>(bpbSector); rootDirectoryCluster = fat32Bpb.root_cluster; // This is to support FAT partitions on hybrid ISO/USB images if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) { fat32Bpb.bps *= 4; fat32Bpb.spc /= 4; fat32Bpb.big_spfat /= 4; fat32Bpb.hsectors /= 4; fat32Bpb.sptrk /= 4; } XmlFsType.Type = fat32Bpb.version != 0 ? "FAT+" : "FAT32"; if (fat32Bpb.oem_name != null && (fat32Bpb.oem_name[5] != 0x49 || fat32Bpb.oem_name[6] != 0x48 || fat32Bpb.oem_name[7] != 0x43)) { XmlFsType.SystemIdentifier = StringHandlers.CToString(fat32Bpb.oem_name); } sectorsPerCluster = fat32Bpb.spc; XmlFsType.ClusterSize = (uint)(fat32Bpb.bps * fat32Bpb.spc); reservedSectors = fat32Bpb.rsectors; if (fat32Bpb.big_sectors == 0 && fat32Bpb.signature == 0x28) { XmlFsType.Clusters = shortFat32Bpb.huge_sectors / shortFat32Bpb.spc; } else { XmlFsType.Clusters = fat32Bpb.big_sectors / fat32Bpb.spc; } sectorsPerFat = fat32Bpb.big_spfat; XmlFsType.VolumeSerial = $"{fat32Bpb.serial_no:X8}"; statfs.Id = new FileSystemId { IsInt = true, Serial32 = fat32Bpb.serial_no }; if ((fat32Bpb.flags & 0xF8) == 0x00) { if ((fat32Bpb.flags & 0x01) == 0x01) { XmlFsType.Dirty = true; } } if ((fat32Bpb.mirror_flags & 0x80) == 0x80) { useFirstFat = (fat32Bpb.mirror_flags & 0xF) != 1; } if (fat32Bpb.signature == 0x29) { XmlFsType.VolumeName = Encoding.ASCII.GetString(fat32Bpb.volume_label); } // Check that jumps to a correct boot code position and has boot signature set. // This will mean that the volume will boot, even if just to say "this is not bootable change disk"...... XmlFsType.Bootable = fat32Bpb.jump[0] == 0xEB && fat32Bpb.jump[1] >= minBootNearJump && fat32Bpb.jump[1] < 0x80 || fat32Bpb.jump[0] == 0xE9 && fat32Bpb.jump.Length >= 3 && BitConverter.ToUInt16(fat32Bpb.jump, 1) >= minBootNearJump && BitConverter.ToUInt16(fat32Bpb.jump, 1) <= 0x1FC; sectorsPerRealSector = fat32Bpb.bps / imagePlugin.Info.SectorSize; sectorsPerCluster *= sectorsPerRealSector; // First root directory sector firstClusterSector = (ulong)(fat32Bpb.big_spfat * fat32Bpb.fats_no + fat32Bpb.rsectors) * sectorsPerRealSector - 2 * sectorsPerCluster; if (fat32Bpb.fsinfo_sector + partition.Start <= partition.End) { byte[] fsinfoSector = imagePlugin.ReadSector(fat32Bpb.fsinfo_sector + partition.Start); FsInfoSector fsInfo = Marshal.ByteArrayToStructureLittleEndian <FsInfoSector>(fsinfoSector); if (fsInfo.signature1 == FSINFO_SIGNATURE1 && fsInfo.signature2 == FSINFO_SIGNATURE2 && fsInfo.signature3 == FSINFO_SIGNATURE3) { if (fsInfo.free_clusters < 0xFFFFFFFF) { XmlFsType.FreeClusters = fsInfo.free_clusters; XmlFsType.FreeClustersSpecified = true; } } } break; } // Some fields could overflow fake BPB, those will be handled below case BpbKind.Atari: { ushort sum = 0; for (int i = 0; i < bpbSector.Length; i += 2) { sum += BigEndianBitConverter.ToUInt16(bpbSector, i); } // TODO: Check this if (sum == 0x1234) { XmlFsType.Bootable = true; } break; } case BpbKind.Human: // If not debug set Human68k namespace and ShiftJIS codepage as defaults if (!debug) { this.@namespace = Namespace.Human; encoding = Encoding.GetEncoding("shift_jis"); } XmlFsType.Bootable = true; break; } Encoding = encoding ?? (bpbKind == BpbKind.Human ? Encoding.GetEncoding("shift_jis") : Encoding.GetEncoding("IBM437")); ulong firstRootSector = 0; if (!fat32) { // This is to support FAT partitions on hybrid ISO/USB images if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) { fakeBpb.bps *= 4; fakeBpb.spc /= 4; fakeBpb.spfat /= 4; fakeBpb.hsectors /= 4; fakeBpb.sptrk /= 4; fakeBpb.rsectors /= 4; if (fakeBpb.spc == 0) { fakeBpb.spc = 1; } } // This assumes no sane implementation will violate cluster size rules // However nothing prevents this to happen // If first file on disk uses only one cluster there is absolutely no way to differentiate between FAT12 and FAT16, // so let's hope implementations use common sense? if (!fat12 && !fat16) { ulong clusters; if (fakeBpb.sectors == 0) { clusters = fakeBpb.spc == 0 ? fakeBpb.big_sectors : fakeBpb.big_sectors / fakeBpb.spc; } else { clusters = fakeBpb.spc == 0 ? fakeBpb.sectors : (ulong)fakeBpb.sectors / fakeBpb.spc; } if (clusters < 4089) { fat12 = true; } else { fat16 = true; } } if (fat12) { XmlFsType.Type = "FAT12"; } else if (fat16) { XmlFsType.Type = "FAT16"; } if (bpbKind == BpbKind.Atari) { if (atariBpb.serial_no[0] != 0x49 || atariBpb.serial_no[1] != 0x48 || atariBpb.serial_no[2] != 0x43) { XmlFsType.VolumeSerial = $"{atariBpb.serial_no[0]:X2}{atariBpb.serial_no[1]:X2}{atariBpb.serial_no[2]:X2}"; statfs.Id = new FileSystemId { IsInt = true, Serial32 = (uint)((atariBpb.serial_no[0] << 16) + (atariBpb.serial_no[1] << 8) + atariBpb.serial_no[2]) }; } XmlFsType.SystemIdentifier = StringHandlers.CToString(atariBpb.oem_name); if (string.IsNullOrEmpty(XmlFsType.SystemIdentifier)) { XmlFsType.SystemIdentifier = null; } } else if (fakeBpb.oem_name != null) { if (fakeBpb.oem_name[5] != 0x49 || fakeBpb.oem_name[6] != 0x48 || fakeBpb.oem_name[7] != 0x43) { // Later versions of Windows create a DOS 3 BPB without OEM name on 8 sectors/track floppies // OEM ID should be ASCII, otherwise ignore it if (fakeBpb.oem_name[0] >= 0x20 && fakeBpb.oem_name[0] <= 0x7F && fakeBpb.oem_name[1] >= 0x20 && fakeBpb.oem_name[1] <= 0x7F && fakeBpb.oem_name[2] >= 0x20 && fakeBpb.oem_name[2] <= 0x7F && fakeBpb.oem_name[3] >= 0x20 && fakeBpb.oem_name[3] <= 0x7F && fakeBpb.oem_name[4] >= 0x20 && fakeBpb.oem_name[4] <= 0x7F && fakeBpb.oem_name[5] >= 0x20 && fakeBpb.oem_name[5] <= 0x7F && fakeBpb.oem_name[6] >= 0x20 && fakeBpb.oem_name[6] <= 0x7F && fakeBpb.oem_name[7] >= 0x20 && fakeBpb.oem_name[7] <= 0x7F) { XmlFsType.SystemIdentifier = StringHandlers.CToString(fakeBpb.oem_name); } else if (fakeBpb.oem_name[0] < 0x20 && fakeBpb.oem_name[1] >= 0x20 && fakeBpb.oem_name[1] <= 0x7F && fakeBpb.oem_name[2] >= 0x20 && fakeBpb.oem_name[2] <= 0x7F && fakeBpb.oem_name[3] >= 0x20 && fakeBpb.oem_name[3] <= 0x7F && fakeBpb.oem_name[4] >= 0x20 && fakeBpb.oem_name[4] <= 0x7F && fakeBpb.oem_name[5] >= 0x20 && fakeBpb.oem_name[5] <= 0x7F && fakeBpb.oem_name[6] >= 0x20 && fakeBpb.oem_name[6] <= 0x7F && fakeBpb.oem_name[7] >= 0x20 && fakeBpb.oem_name[7] <= 0x7F) { XmlFsType.SystemIdentifier = StringHandlers.CToString(fakeBpb.oem_name, Encoding, start: 1); } } if (fakeBpb.signature == 0x28 || fakeBpb.signature == 0x29) { XmlFsType.VolumeSerial = $"{fakeBpb.serial_no:X8}"; statfs.Id = new FileSystemId { IsInt = true, Serial32 = fakeBpb.serial_no }; } } if (bpbKind != BpbKind.Human) { if (fakeBpb.sectors == 0) { XmlFsType.Clusters = fakeBpb.spc == 0 ? fakeBpb.big_sectors : fakeBpb.big_sectors / fakeBpb.spc; } else { XmlFsType.Clusters = (ulong)(fakeBpb.spc == 0 ? fakeBpb.sectors : fakeBpb.sectors / fakeBpb.spc); } } else { XmlFsType.Clusters = humanBpb.clusters == 0 ? humanBpb.big_clusters : humanBpb.clusters; } sectorsPerCluster = fakeBpb.spc; XmlFsType.ClusterSize = (uint)(fakeBpb.bps * fakeBpb.spc); reservedSectors = fakeBpb.rsectors; sectorsPerFat = fakeBpb.spfat; if (fakeBpb.signature == 0x28 || fakeBpb.signature == 0x29 || andosOemCorrect) { if ((fakeBpb.flags & 0xF8) == 0x00) { if ((fakeBpb.flags & 0x01) == 0x01) { XmlFsType.Dirty = true; } } if (fakeBpb.signature == 0x29 || andosOemCorrect) { XmlFsType.VolumeName = Encoding.ASCII.GetString(fakeBpb.volume_label); } } // Workaround that PCExchange jumps into "FAT16 "... if (XmlFsType.SystemIdentifier == "PCX 2.0 ") { fakeBpb.jump[1] += 8; } // Check that jumps to a correct boot code position and has boot signature set. // This will mean that the volume will boot, even if just to say "this is not bootable change disk"...... if (XmlFsType.Bootable == false && fakeBpb.jump != null) { XmlFsType.Bootable |= fakeBpb.jump[0] == 0xEB && fakeBpb.jump[1] >= minBootNearJump && fakeBpb.jump[1] < 0x80 || fakeBpb.jump[0] == 0xE9 && fakeBpb.jump.Length >= 3 && BitConverter.ToUInt16(fakeBpb.jump, 1) >= minBootNearJump && BitConverter.ToUInt16(fakeBpb.jump, 1) <= 0x1FC; } // First root directory sector firstRootSector = (ulong)(fakeBpb.spfat * fakeBpb.fats_no + fakeBpb.rsectors) * sectorsPerRealSector + partition.Start; sectorsForRootDirectory = (uint)(fakeBpb.root_ent * 32 / imagePlugin.Info.SectorSize); sectorsPerRealSector = fakeBpb.bps / imagePlugin.Info.SectorSize; sectorsPerCluster *= sectorsPerRealSector; } firstClusterSector += partition.Start; image = imagePlugin; if (fat32) { fatEntriesPerSector = imagePlugin.Info.SectorSize / 4; } else if (fat16) { fatEntriesPerSector = imagePlugin.Info.SectorSize / 2; } else { fatEntriesPerSector = imagePlugin.Info.SectorSize * 2 / 3; } fatFirstSector = partition.Start + reservedSectors * sectorsPerRealSector; rootDirectoryCache = new Dictionary <string, CompleteDirectoryEntry>(); byte[] rootDirectory = null; if (!fat32) { firstClusterSector = firstRootSector + sectorsForRootDirectory - sectorsPerCluster * 2; rootDirectory = imagePlugin.ReadSectors(firstRootSector, sectorsForRootDirectory); if (bpbKind == BpbKind.DecRainbow) { MemoryStream rootMs = new MemoryStream(); foreach (byte[] tmp in from ulong rootSector in new[] { 0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20 } select imagePlugin.ReadSector(rootSector)) { rootMs.Write(tmp, 0, tmp.Length); } rootDirectory = rootMs.ToArray(); } } else { if (rootDirectoryCluster == 0) { return(Errno.InvalidArgument); } MemoryStream rootMs = new MemoryStream(); uint[] rootDirectoryClusters = GetClusters(rootDirectoryCluster); foreach (uint cluster in rootDirectoryClusters) { byte[] buffer = imagePlugin.ReadSectors(firstClusterSector + cluster * sectorsPerCluster, sectorsPerCluster); rootMs.Write(buffer, 0, buffer.Length); } rootDirectory = rootMs.ToArray(); // OS/2 FAT32.IFS uses LFN instead of .LONGNAME if (this.@namespace == Namespace.Os2) { this.@namespace = Namespace.Os2; } } if (rootDirectory is null) { return(Errno.InvalidArgument); } byte[] lastLfnName = null; byte lastLfnChecksum = 0; for (int i = 0; i < rootDirectory.Length; i += Marshal.SizeOf <DirectoryEntry>()) { DirectoryEntry entry = Marshal.ByteArrayToStructureLittleEndian <DirectoryEntry>(rootDirectory, i, Marshal.SizeOf <DirectoryEntry>()); if (entry.filename[0] == DIRENT_FINISHED) { break; } if (entry.attributes.HasFlag(FatAttributes.LFN)) { if (this.@namespace != Namespace.Lfn && this.@namespace != Namespace.Ecs) { continue; } LfnEntry lfnEntry = Marshal.ByteArrayToStructureLittleEndian <LfnEntry>(rootDirectory, i, Marshal.SizeOf <LfnEntry>()); int lfnSequence = lfnEntry.sequence & LFN_MASK; if ((lfnEntry.sequence & LFN_ERASED) > 0) { continue; } if ((lfnEntry.sequence & LFN_LAST) > 0) { lastLfnName = new byte[lfnSequence * 26]; lastLfnChecksum = lfnEntry.checksum; } if (lastLfnName is null) { continue; } if (lfnEntry.checksum != lastLfnChecksum) { continue; } lfnSequence--; Array.Copy(lfnEntry.name1, 0, lastLfnName, lfnSequence * 26, 10); Array.Copy(lfnEntry.name2, 0, lastLfnName, lfnSequence * 26 + 10, 12); Array.Copy(lfnEntry.name3, 0, lastLfnName, lfnSequence * 26 + 22, 4); continue; } // Not a correct entry if (entry.filename[0] < DIRENT_MIN && entry.filename[0] != DIRENT_E5) { continue; } // Self if (Encoding.GetString(entry.filename).TrimEnd() == ".") { continue; } // Parent if (Encoding.GetString(entry.filename).TrimEnd() == "..") { continue; } // Deleted if (entry.filename[0] == DIRENT_DELETED) { continue; } string filename; if (entry.attributes.HasFlag(FatAttributes.VolumeLabel)) { byte[] fullname = new byte[11]; Array.Copy(entry.filename, 0, fullname, 0, 8); Array.Copy(entry.extension, 0, fullname, 8, 3); string volname = Encoding.GetString(fullname).Trim(); if (!string.IsNullOrEmpty(volname)) { XmlFsType.VolumeName = entry.caseinfo.HasFlag(CaseInfo.AllLowerCase) && this.@namespace == Namespace.Nt ? volname.ToLower() : volname; } if (entry.ctime > 0 && entry.cdate > 0) { XmlFsType.CreationDate = DateHandlers.DosToDateTime(entry.cdate, entry.ctime); if (entry.ctime_ms > 0) { XmlFsType.CreationDate = XmlFsType.CreationDate.AddMilliseconds(entry.ctime_ms * 10); } XmlFsType.CreationDateSpecified = true; } if (entry.mtime > 0 && entry.mdate > 0) { XmlFsType.ModificationDate = DateHandlers.DosToDateTime(entry.mdate, entry.mtime); XmlFsType.ModificationDateSpecified = true; } continue; } CompleteDirectoryEntry completeEntry = new CompleteDirectoryEntry { Dirent = entry }; if ((this.@namespace == Namespace.Lfn || this.@namespace == Namespace.Ecs) && lastLfnName != null) { byte calculatedLfnChecksum = LfnChecksum(entry.filename, entry.extension); if (calculatedLfnChecksum == lastLfnChecksum) { filename = StringHandlers.CToString(lastLfnName, Encoding.Unicode, true); completeEntry.Lfn = filename; lastLfnName = null; lastLfnChecksum = 0; } } if (entry.filename[0] == DIRENT_E5) { entry.filename[0] = DIRENT_DELETED; } string name = Encoding.GetString(entry.filename).TrimEnd(); string extension = Encoding.GetString(entry.extension).TrimEnd(); if (this.@namespace == Namespace.Nt) { if (entry.caseinfo.HasFlag(CaseInfo.LowerCaseExtension)) { extension = extension.ToLower(CultureInfo.CurrentCulture); } if (entry.caseinfo.HasFlag(CaseInfo.LowerCaseBasename)) { name = name.ToLower(CultureInfo.CurrentCulture); } } if (extension != "") { filename = name + "." + extension; } else { filename = name; } completeEntry.Shortname = filename; if (this.@namespace == Namespace.Human) { HumanDirectoryEntry humanEntry = Marshal.ByteArrayToStructureLittleEndian <HumanDirectoryEntry>(rootDirectory, i, Marshal .SizeOf <HumanDirectoryEntry >()); completeEntry.HumanDirent = humanEntry; name = StringHandlers.CToString(humanEntry.name1, Encoding).TrimEnd(); extension = StringHandlers.CToString(humanEntry.extension, Encoding).TrimEnd(); string name2 = StringHandlers.CToString(humanEntry.name2, Encoding).TrimEnd(); if (extension != "") { filename = name + name2 + "." + extension; } else { filename = name + name2; } completeEntry.HumanName = filename; } if (!fat32 && filename == "EA DATA. SF") { eaDirEntry = entry; lastLfnName = null; lastLfnChecksum = 0; if (debug) { rootDirectoryCache[completeEntry.ToString()] = completeEntry; } continue; } rootDirectoryCache[completeEntry.ToString()] = completeEntry; lastLfnName = null; lastLfnChecksum = 0; } XmlFsType.VolumeName = XmlFsType.VolumeName?.Trim(); statfs.Blocks = XmlFsType.Clusters; switch (bpbKind) { case BpbKind.Hardcoded: statfs.Type = $"Microsoft FAT{(fat16 ? "16" : "12")}"; break; case BpbKind.Atari: statfs.Type = $"Atari FAT{(fat16 ? "16" : "12")}"; break; case BpbKind.Msx: statfs.Type = $"MSX FAT{(fat16 ? "16" : "12")}"; break; case BpbKind.Dos2: case BpbKind.Dos3: case BpbKind.Dos32: case BpbKind.Dos33: case BpbKind.ShortExtended: case BpbKind.Extended: statfs.Type = $"Microsoft FAT{(fat16 ? "16" : "12")}"; break; case BpbKind.ShortFat32: case BpbKind.LongFat32: statfs.Type = XmlFsType.Type == "FAT+" ? "FAT+" : "Microsoft FAT32"; break; case BpbKind.Andos: statfs.Type = $"ANDOS FAT{(fat16 ? "16" : "12")}"; break; case BpbKind.Apricot: statfs.Type = $"Apricot FAT{(fat16 ? "16" : "12")}"; break; case BpbKind.DecRainbow: statfs.Type = $"DEC FAT{(fat16 ? "16" : "12")}"; break; case BpbKind.Human: statfs.Type = $"Human68k FAT{(fat16 ? "16" : "12")}"; break; default: throw new ArgumentOutOfRangeException(); } bytesPerCluster = sectorsPerCluster * imagePlugin.Info.SectorSize; if (fat12) { byte[] fatBytes = imagePlugin.ReadSectors(fatFirstSector + (useFirstFat ? 0 : sectorsPerFat), sectorsPerFat); fatEntries = new ushort[statfs.Blocks]; int pos = 0; for (int i = 0; i + 3 < fatBytes.Length && pos < fatEntries.Length; i += 3) { fatEntries[pos++] = (ushort)(((fatBytes[i + 1] & 0xF) << 8) + fatBytes[i + 0]); fatEntries[pos++] = (ushort)(((fatBytes[i + 1] & 0xF0) >> 4) + (fatBytes[i + 2] << 4)); } } else if (fat16) { DicConsole.DebugWriteLine("FAT plugin", "Reading FAT16"); byte[] fatBytes = imagePlugin.ReadSectors(fatFirstSector + (useFirstFat ? 0 : sectorsPerFat), sectorsPerFat); DicConsole.DebugWriteLine("FAT plugin", "Casting FAT"); fatEntries = MemoryMarshal.Cast <byte, ushort>(fatBytes).ToArray(); } // TODO: Check how this affects international filenames cultureInfo = new CultureInfo("en-US", false); directoryCache = new Dictionary <string, Dictionary <string, CompleteDirectoryEntry> >(); // Check it is really an OS/2 EA file if (eaDirEntry.start_cluster != 0) { CacheEaData(); ushort eamagic = BitConverter.ToUInt16(cachedEaData, 0); if (eamagic != EADATA_MAGIC) { eaDirEntry = new DirectoryEntry(); cachedEaData = null; } else { eaCache = new Dictionary <string, Dictionary <string, byte[]> >(); } } else if (fat32) { eaCache = new Dictionary <string, Dictionary <string, byte[]> >(); } // Check OS/2 .LONGNAME if (eaCache != null && (this.@namespace == Namespace.Os2 || this.@namespace == Namespace.Ecs)) { List <KeyValuePair <string, CompleteDirectoryEntry> > rootFilesWithEas = rootDirectoryCache.Where(t => t.Value.Dirent.ea_handle != 0).ToList(); foreach (KeyValuePair <string, CompleteDirectoryEntry> fileWithEa in rootFilesWithEas) { Dictionary <string, byte[]> eas = GetEas(fileWithEa.Value.Dirent.ea_handle); if (eas is null) { continue; } if (!eas.TryGetValue("com.microsoft.os2.longname", out byte[] longnameEa))
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); information = ""; StringBuilder sb = new StringBuilder(); HammerSuperBlock hammerSb; uint run = HAMMER_VOLHDR_SIZE / imagePlugin.Info.SectorSize; if (HAMMER_VOLHDR_SIZE % imagePlugin.Info.SectorSize > 0) { run++; } ulong magic; byte[] sbSector = imagePlugin.ReadSectors(partition.Start, run); magic = BitConverter.ToUInt64(sbSector, 0); if (magic == HAMMER_FSBUF_VOLUME) { GCHandle handle = GCHandle.Alloc(sbSector, GCHandleType.Pinned); hammerSb = (HammerSuperBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(HammerSuperBlock)); handle.Free(); } else { hammerSb = BigEndianMarshal.ByteArrayToStructureBigEndian <HammerSuperBlock>(sbSector); } sb.AppendLine("HAMMER filesystem"); sb.AppendFormat("Volume version: {0}", hammerSb.vol_version).AppendLine(); sb.AppendFormat("Volume {0} of {1} on this filesystem", hammerSb.vol_no + 1, hammerSb.vol_count) .AppendLine(); sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(hammerSb.vol_label, Encoding)).AppendLine(); sb.AppendFormat("Volume serial: {0}", hammerSb.vol_fsid).AppendLine(); sb.AppendFormat("Filesystem type: {0}", hammerSb.vol_fstype).AppendLine(); sb.AppendFormat("Boot area starts at {0}", hammerSb.vol_bot_beg).AppendLine(); sb.AppendFormat("Memory log starts at {0}", hammerSb.vol_mem_beg).AppendLine(); sb.AppendFormat("First volume buffer starts at {0}", hammerSb.vol_buf_beg).AppendLine(); sb.AppendFormat("Volume ends at {0}", hammerSb.vol_buf_end).AppendLine(); XmlFsType = new FileSystemType { Clusters = (long)(partition.Size / HAMMER_BIGBLOCK_SIZE), ClusterSize = HAMMER_BIGBLOCK_SIZE, Dirty = false, Type = "HAMMER", VolumeName = StringHandlers.CToString(hammerSb.vol_label, Encoding), VolumeSerial = hammerSb.vol_fsid.ToString() }; if (hammerSb.vol_no == hammerSb.vol_rootvol) { sb.AppendFormat("Filesystem contains {0} \"big-blocks\" ({1} bytes)", hammerSb.vol0_stat_bigblocks, hammerSb.vol0_stat_bigblocks * HAMMER_BIGBLOCK_SIZE).AppendLine(); sb.AppendFormat("Filesystem has {0} \"big-blocks\" free ({1} bytes)", hammerSb.vol0_stat_freebigblocks, hammerSb.vol0_stat_freebigblocks * HAMMER_BIGBLOCK_SIZE).AppendLine(); sb.AppendFormat("Filesystem has {0} inode used", hammerSb.vol0_stat_inodes).AppendLine(); XmlFsType.Clusters = hammerSb.vol0_stat_bigblocks; XmlFsType.FreeClusters = hammerSb.vol0_stat_freebigblocks; XmlFsType.FreeClustersSpecified = true; XmlFsType.Files = hammerSb.vol0_stat_inodes; XmlFsType.FilesSpecified = true; } // 0 ? //sb.AppendFormat("Volume header CRC: 0x{0:X8}", afs_sb.vol_crc).AppendLine(); information = sb.ToString(); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); information = ""; StringBuilder sb = new StringBuilder(); uint sector = 2; uint offset = 0; if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) { sector = 0; offset = 0x400; } bool minix3 = false; int filenamesize; string minixVersion; byte[] minixSbSector = imagePlugin.ReadSector(sector + partition.Start); // Optical media if (offset > 0) { byte[] tmp = new byte[0x200]; Array.Copy(minixSbSector, offset, tmp, 0, 0x200); minixSbSector = tmp; } ushort magic = BitConverter.ToUInt16(minixSbSector, 0x018); XmlFsType = new FileSystemType(); bool littleEndian; if (magic == MINIX3_MAGIC || magic == MINIX3_CIGAM || magic == MINIX2_MAGIC || magic == MINIX2_CIGAM || magic == MINIX_MAGIC || magic == MINIX_CIGAM) { filenamesize = 60; littleEndian = magic != MINIX3_CIGAM || magic == MINIX2_CIGAM || magic == MINIX_CIGAM; switch (magic) { case MINIX3_MAGIC: case MINIX3_CIGAM: minixVersion = "Minix v3 filesystem"; XmlFsType.Type = "Minix v3"; break; case MINIX2_MAGIC: case MINIX2_CIGAM: minixVersion = "Minix 3 v2 filesystem"; XmlFsType.Type = "Minix 3 v2"; break; default: minixVersion = "Minix 3 v1 filesystem"; XmlFsType.Type = "Minix 3 v1"; break; } minix3 = true; } else { magic = BitConverter.ToUInt16(minixSbSector, 0x010); switch (magic) { case MINIX_MAGIC: filenamesize = 14; minixVersion = "Minix v1 filesystem"; littleEndian = true; XmlFsType.Type = "Minix v1"; break; case MINIX_MAGIC2: filenamesize = 30; minixVersion = "Minix v1 filesystem"; littleEndian = true; XmlFsType.Type = "Minix v1"; break; case MINIX2_MAGIC: filenamesize = 14; minixVersion = "Minix v2 filesystem"; littleEndian = true; XmlFsType.Type = "Minix v2"; break; case MINIX2_MAGIC2: filenamesize = 30; minixVersion = "Minix v2 filesystem"; littleEndian = true; XmlFsType.Type = "Minix v2"; break; case MINIX_CIGAM: filenamesize = 14; minixVersion = "Minix v1 filesystem"; littleEndian = false; XmlFsType.Type = "Minix v1"; break; case MINIX_CIGAM2: filenamesize = 30; minixVersion = "Minix v1 filesystem"; littleEndian = false; XmlFsType.Type = "Minix v1"; break; case MINIX2_CIGAM: filenamesize = 14; minixVersion = "Minix v2 filesystem"; littleEndian = false; XmlFsType.Type = "Minix v2"; break; case MINIX2_CIGAM2: filenamesize = 30; minixVersion = "Minix v2 filesystem"; littleEndian = false; XmlFsType.Type = "Minix v2"; break; default: return; } } if (minix3) { Minix3SuperBlock mnxSb; if (littleEndian) { GCHandle handle = GCHandle.Alloc(minixSbSector, GCHandleType.Pinned); mnxSb = (Minix3SuperBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(Minix3SuperBlock)); handle.Free(); } else { mnxSb = BigEndianMarshal.ByteArrayToStructureBigEndian <Minix3SuperBlock>(minixSbSector); } if (magic != MINIX3_MAGIC && magic != MINIX3_CIGAM) { mnxSb.s_blocksize = 1024; } sb.AppendLine(minixVersion); sb.AppendFormat("{0} chars in filename", filenamesize).AppendLine(); if (mnxSb.s_zones > 0) // On V2 { sb.AppendFormat("{0} zones on volume ({1} bytes)", mnxSb.s_zones, mnxSb.s_zones * 1024) .AppendLine(); } else { sb.AppendFormat("{0} zones on volume ({1} bytes)", mnxSb.s_nzones, mnxSb.s_nzones * 1024) .AppendLine(); } sb.AppendFormat("{0} bytes/block", mnxSb.s_blocksize).AppendLine(); sb.AppendFormat("{0} inodes on volume", mnxSb.s_ninodes).AppendLine(); sb.AppendFormat("{0} blocks on inode map ({1} bytes)", mnxSb.s_imap_blocks, mnxSb.s_imap_blocks * mnxSb.s_blocksize).AppendLine(); sb.AppendFormat("{0} blocks on zone map ({1} bytes)", mnxSb.s_zmap_blocks, mnxSb.s_zmap_blocks * mnxSb.s_blocksize).AppendLine(); sb.AppendFormat("First data zone: {0}", mnxSb.s_firstdatazone).AppendLine(); //sb.AppendFormat("log2 of blocks/zone: {0}", mnx_sb.s_log_zone_size).AppendLine(); // Apparently 0 sb.AppendFormat("{0} bytes maximum per file", mnxSb.s_max_size).AppendLine(); sb.AppendFormat("On-disk filesystem version: {0}", mnxSb.s_disk_version).AppendLine(); XmlFsType.ClusterSize = mnxSb.s_blocksize; XmlFsType.Clusters = mnxSb.s_zones > 0 ? mnxSb.s_zones : mnxSb.s_nzones; } else { MinixSuperBlock mnxSb; if (littleEndian) { GCHandle handle = GCHandle.Alloc(minixSbSector, GCHandleType.Pinned); mnxSb = (MinixSuperBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(MinixSuperBlock)); handle.Free(); } else { mnxSb = BigEndianMarshal.ByteArrayToStructureBigEndian <MinixSuperBlock>(minixSbSector); } sb.AppendLine(minixVersion); sb.AppendFormat("{0} chars in filename", filenamesize).AppendLine(); if (mnxSb.s_zones > 0) // On V2 { sb.AppendFormat("{0} zones on volume ({1} bytes)", mnxSb.s_zones, mnxSb.s_zones * 1024) .AppendLine(); } else { sb.AppendFormat("{0} zones on volume ({1} bytes)", mnxSb.s_nzones, mnxSb.s_nzones * 1024) .AppendLine(); } sb.AppendFormat("{0} inodes on volume", mnxSb.s_ninodes).AppendLine(); sb.AppendFormat("{0} blocks on inode map ({1} bytes)", mnxSb.s_imap_blocks, mnxSb.s_imap_blocks * 1024) .AppendLine(); sb.AppendFormat("{0} blocks on zone map ({1} bytes)", mnxSb.s_zmap_blocks, mnxSb.s_zmap_blocks * 1024) .AppendLine(); sb.AppendFormat("First data zone: {0}", mnxSb.s_firstdatazone).AppendLine(); //sb.AppendFormat("log2 of blocks/zone: {0}", mnx_sb.s_log_zone_size).AppendLine(); // Apparently 0 sb.AppendFormat("{0} bytes maximum per file", mnxSb.s_max_size).AppendLine(); sb.AppendFormat("Filesystem state: {0:X4}", mnxSb.s_state).AppendLine(); XmlFsType.ClusterSize = 1024; XmlFsType.Clusters = mnxSb.s_zones > 0 ? mnxSb.s_zones : mnxSb.s_nzones; } information = sb.ToString(); }
/// <summary> /// Mounts an Apple DOS filesystem /// </summary> public Errno Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, Dictionary <string, string> options, string @namespace) { device = imagePlugin; start = partition.Start; Encoding = encoding ?? new Apple2(); if (device.Info.Sectors != 455 && device.Info.Sectors != 560) { DicConsole.DebugWriteLine("Apple DOS plugin", "Incorrect device size."); return(Errno.InOutError); } if (start > 0) { DicConsole.DebugWriteLine("Apple DOS plugin", "Partitions are not supported."); return(Errno.InOutError); } if (device.Info.SectorSize != 256) { DicConsole.DebugWriteLine("Apple DOS plugin", "Incorrect sector size."); return(Errno.InOutError); } sectorsPerTrack = device.Info.Sectors == 455 ? 13 : 16; // Read the VTOC vtocBlocks = device.ReadSector((ulong)(17 * sectorsPerTrack)); vtoc = Marshal.ByteArrayToStructureLittleEndian <Vtoc>(vtocBlocks); track1UsedByFiles = false; track2UsedByFiles = false; usedSectors = 1; Errno error = ReadCatalog(); if (error != Errno.NoError) { DicConsole.DebugWriteLine("Apple DOS plugin", "Unable to read catalog."); return(error); } error = CacheAllFiles(); if (error != Errno.NoError) { DicConsole.DebugWriteLine("Apple DOS plugin", "Unable cache all files."); return(error); } // Create XML metadata for mounted filesystem XmlFsType = new FileSystemType { Bootable = true, Clusters = device.Info.Sectors, ClusterSize = vtoc.bytesPerSector, Files = (ulong)catalogCache.Count, FilesSpecified = true, FreeClustersSpecified = true, Type = "Apple DOS" }; XmlFsType.FreeClusters = XmlFsType.Clusters - usedSectors; if (options == null) { options = GetDefaultOptions(); } if (options.TryGetValue("debug", out string debugString)) { bool.TryParse(debugString, out debug); } mounted = true; return(Errno.NoError); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = Encoding.UTF8; information = ""; uint sbSize = (uint)(Marshal.SizeOf <RefsVolumeHeader>() / imagePlugin.Info.SectorSize); if (Marshal.SizeOf <RefsVolumeHeader>() % imagePlugin.Info.SectorSize != 0) { sbSize++; } if (partition.Start + sbSize >= partition.End) { return; } byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize); if (sector.Length < Marshal.SizeOf <RefsVolumeHeader>()) { return; } RefsVolumeHeader refsVhdr = Marshal.ByteArrayToStructureLittleEndian <RefsVolumeHeader>(sector); DicConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.jump empty? = {0}", ArrayHelpers.ArrayIsNullOrEmpty(refsVhdr.jump)); DicConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.signature = {0}", StringHandlers.CToString(refsVhdr.signature)); DicConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.mustBeZero empty? = {0}", ArrayHelpers.ArrayIsNullOrEmpty(refsVhdr.mustBeZero)); DicConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.identifier = {0}", StringHandlers.CToString(BitConverter.GetBytes(refsVhdr.identifier))); DicConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.length = {0}", refsVhdr.length); DicConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.checksum = 0x{0:X4}", refsVhdr.checksum); DicConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.sectors = {0}", refsVhdr.sectors); DicConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.bytesPerSector = {0}", refsVhdr.bytesPerSector); DicConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.sectorsPerCluster = {0}", refsVhdr.sectorsPerCluster); DicConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.unknown1 zero? = {0}", refsVhdr.unknown1 == 0); DicConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.unknown2 zero? = {0}", refsVhdr.unknown2 == 0); DicConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.unknown3 zero? = {0}", refsVhdr.unknown3 == 0); DicConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.unknown4 zero? = {0}", refsVhdr.unknown4 == 0); DicConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.unknown5 empty? = {0}", ArrayHelpers.ArrayIsNullOrEmpty(refsVhdr.unknown5)); if (refsVhdr.identifier != FSRS || !ArrayHelpers.ArrayIsNullOrEmpty(refsVhdr.mustBeZero) || !refsVhdr.signature.SequenceEqual(refsSignature)) { return; } StringBuilder sb = new StringBuilder(); sb.AppendLine("Microsoft Resilient File System"); sb.AppendFormat("Volume uses {0} bytes per sector", refsVhdr.bytesPerSector).AppendLine(); sb.AppendFormat("Volume uses {0} sectors per cluster ({1} bytes)", refsVhdr.sectorsPerCluster, refsVhdr.sectorsPerCluster * refsVhdr.bytesPerSector).AppendLine(); sb.AppendFormat("Volume has {0} sectors ({1} bytes)", refsVhdr.sectors, refsVhdr.sectors * refsVhdr.bytesPerSector).AppendLine(); information = sb.ToString(); XmlFsType = new FileSystemType { Type = "Resilient File System", ClusterSize = refsVhdr.bytesPerSector * refsVhdr.sectorsPerCluster, Clusters = refsVhdr.sectors / refsVhdr.sectorsPerCluster }; }
public Errno Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, Dictionary <string, string> options, string @namespace) { device = imagePlugin; Encoding = encoding ?? new Apple2(); if (options == null) { options = GetDefaultOptions(); } if (options.TryGetValue("debug", out string debugString)) { bool.TryParse(debugString, out debug); } if (device.Info.Sectors < 3) { return(Errno.InvalidArgument); } multiplier = (uint)(imagePlugin.Info.SectorSize == 256 ? 2 : 1); // Blocks 0 and 1 are boot code catalogBlocks = device.ReadSectors(multiplier * 2, multiplier); // On Apple //, it's little endian BigEndianBitConverter.IsLittleEndian = multiplier == 2 ? !BitConverter.IsLittleEndian : BitConverter.IsLittleEndian; mountedVolEntry.FirstBlock = BigEndianBitConverter.ToInt16(catalogBlocks, 0x00); mountedVolEntry.LastBlock = BigEndianBitConverter.ToInt16(catalogBlocks, 0x02); mountedVolEntry.EntryType = (PascalFileKind)BigEndianBitConverter.ToInt16(catalogBlocks, 0x04); mountedVolEntry.VolumeName = new byte[8]; Array.Copy(catalogBlocks, 0x06, mountedVolEntry.VolumeName, 0, 8); mountedVolEntry.Blocks = BigEndianBitConverter.ToInt16(catalogBlocks, 0x0E); mountedVolEntry.Files = BigEndianBitConverter.ToInt16(catalogBlocks, 0x10); mountedVolEntry.Dummy = BigEndianBitConverter.ToInt16(catalogBlocks, 0x12); mountedVolEntry.LastBoot = BigEndianBitConverter.ToInt16(catalogBlocks, 0x14); mountedVolEntry.Tail = BigEndianBitConverter.ToInt32(catalogBlocks, 0x16); if (mountedVolEntry.FirstBlock != 0 || mountedVolEntry.LastBlock <= mountedVolEntry.FirstBlock || (ulong)mountedVolEntry.LastBlock > device.Info.Sectors / multiplier - 2 || mountedVolEntry.EntryType != PascalFileKind.Volume && mountedVolEntry.EntryType != PascalFileKind.Secure || mountedVolEntry.VolumeName[0] > 7 || mountedVolEntry.Blocks < 0 || (ulong)mountedVolEntry.Blocks != device.Info.Sectors / multiplier || mountedVolEntry.Files < 0) { return(Errno.InvalidArgument); } catalogBlocks = device.ReadSectors(multiplier * 2, (uint)(mountedVolEntry.LastBlock - mountedVolEntry.FirstBlock - 2) * multiplier); int offset = 26; fileEntries = new List <PascalFileEntry>(); while (offset + 26 < catalogBlocks.Length) { PascalFileEntry entry = new PascalFileEntry { Filename = new byte[16], FirstBlock = BigEndianBitConverter.ToInt16(catalogBlocks, offset + 0x00), LastBlock = BigEndianBitConverter.ToInt16(catalogBlocks, offset + 0x02), EntryType = (PascalFileKind)BigEndianBitConverter.ToInt16(catalogBlocks, offset + 0x04), LastBytes = BigEndianBitConverter.ToInt16(catalogBlocks, offset + 0x16), ModificationTime = BigEndianBitConverter.ToInt16(catalogBlocks, offset + 0x18) }; Array.Copy(catalogBlocks, offset + 0x06, entry.Filename, 0, 16); if (entry.Filename[0] <= 15 && entry.Filename[0] > 0) { fileEntries.Add(entry); } offset += 26; } bootBlocks = device.ReadSectors(0, 2 * multiplier); XmlFsType = new FileSystemType { Bootable = !ArrayHelpers.ArrayIsNullOrEmpty(bootBlocks), Clusters = (ulong)mountedVolEntry.Blocks, ClusterSize = device.Info.SectorSize, Files = (ulong)mountedVolEntry.Files, FilesSpecified = true, Type = "UCSD Pascal", VolumeName = StringHandlers.PascalToString(mountedVolEntry.VolumeName, Encoding) }; mounted = true; return(Errno.NoError); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { // TODO: Find correct default encoding Encoding = Encoding.ASCII; information = ""; var superBlockMetadata = new StringBuilder(); byte[] sbSector = imagePlugin.ReadSector(0 + partition.Start); SuperBlock sb = Marshal.ByteArrayToStructureBigEndian <SuperBlock>(sbSector); if (sb.record_type != 1 || sb.record_version != 1) { return; } if (Encoding.ASCII.GetString(sb.sync_bytes) != SYNC) { return; } superBlockMetadata.AppendFormat("Opera filesystem disc.").AppendLine(); if (!string.IsNullOrEmpty(StringHandlers.CToString(sb.volume_label, Encoding))) { superBlockMetadata. AppendFormat("Volume label: {0}", StringHandlers.CToString(sb.volume_label, Encoding)).AppendLine(); } if (!string.IsNullOrEmpty(StringHandlers.CToString(sb.volume_comment, Encoding))) { superBlockMetadata. AppendFormat("Volume comment: {0}", StringHandlers.CToString(sb.volume_comment, Encoding)). AppendLine(); } superBlockMetadata.AppendFormat("Volume identifier: 0x{0:X8}", sb.volume_id).AppendLine(); superBlockMetadata.AppendFormat("Block size: {0} bytes", sb.block_size).AppendLine(); if (imagePlugin.Info.SectorSize == 2336 || imagePlugin.Info.SectorSize == 2352 || imagePlugin.Info.SectorSize == 2448) { if (sb.block_size != 2048) { superBlockMetadata. AppendFormat("WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/block", sb.block_size, 2048); } } else if (imagePlugin.Info.SectorSize != sb.block_size) { superBlockMetadata. AppendFormat("WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/block", sb.block_size, imagePlugin.Info.SectorSize); } superBlockMetadata. AppendFormat("Volume size: {0} blocks, {1} bytes", sb.block_count, sb.block_size * sb.block_count). AppendLine(); if (sb.block_count > imagePlugin.Info.Sectors) { superBlockMetadata. AppendFormat("WARNING: Filesystem indicates {0} blocks while device indicates {1} blocks", sb.block_count, imagePlugin.Info.Sectors); } superBlockMetadata.AppendFormat("Root directory identifier: 0x{0:X8}", sb.root_dirid).AppendLine(); superBlockMetadata.AppendFormat("Root directory block size: {0} bytes", sb.rootdir_bsize).AppendLine(); superBlockMetadata.AppendFormat("Root directory size: {0} blocks, {1} bytes", sb.rootdir_blocks, sb.rootdir_bsize * sb.rootdir_blocks).AppendLine(); superBlockMetadata.AppendFormat("Last root directory copy: {0}", sb.last_root_copy).AppendLine(); information = superBlockMetadata.ToString(); XmlFsType = new FileSystemType { Type = "Opera", VolumeName = StringHandlers.CToString(sb.volume_label, Encoding), ClusterSize = sb.block_size, Clusters = sb.block_count }; }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { // Technically everything on Plan 9 from Bell Labs is in UTF-8 Encoding = Encoding.UTF8; information = ""; if (imagePlugin.Info.SectorSize < 512) { return; } ulong hdrSector = HEADER_POS / imagePlugin.Info.SectorSize; byte[] sector = imagePlugin.ReadSector(partition.Start + hdrSector); Header hdr = Marshal.ByteArrayToStructureBigEndian <Header>(sector); AaruConsole.DebugWriteLine("Fossil plugin", "magic at 0x{0:X8} (expected 0x{1:X8})", hdr.magic, FOSSIL_HDR_MAGIC); var sb = new StringBuilder(); sb.AppendLine("Fossil"); sb.AppendFormat("Filesystem version {0}", hdr.version).AppendLine(); sb.AppendFormat("{0} bytes per block", hdr.blockSize).AppendLine(); sb.AppendFormat("Superblock resides in block {0}", hdr.super).AppendLine(); sb.AppendFormat("Labels resides in block {0}", hdr.label).AppendLine(); sb.AppendFormat("Data starts at block {0}", hdr.data).AppendLine(); sb.AppendFormat("Volume has {0} blocks", hdr.end).AppendLine(); ulong sbLocation = (hdr.super * (hdr.blockSize / imagePlugin.Info.SectorSize)) + partition.Start; XmlFsType = new FileSystemType { Type = "Fossil filesystem", ClusterSize = hdr.blockSize, Clusters = hdr.end }; if (sbLocation <= partition.End) { sector = imagePlugin.ReadSector(sbLocation); SuperBlock fsb = Marshal.ByteArrayToStructureBigEndian <SuperBlock>(sector); AaruConsole.DebugWriteLine("Fossil plugin", "magic 0x{0:X8} (expected 0x{1:X8})", fsb.magic, FOSSIL_SB_MAGIC); if (fsb.magic == FOSSIL_SB_MAGIC) { sb.AppendFormat("Epoch low {0}", fsb.epochLow).AppendLine(); sb.AppendFormat("Epoch high {0}", fsb.epochHigh).AppendLine(); sb.AppendFormat("Next QID {0}", fsb.qid).AppendLine(); sb.AppendFormat("Active root block {0}", fsb.active).AppendLine(); sb.AppendFormat("Next root block {0}", fsb.next).AppendLine(); sb.AppendFormat("Current root block {0}", fsb.current).AppendLine(); sb.AppendFormat("Volume label: \"{0}\"", StringHandlers.CToString(fsb.name, Encoding)).AppendLine(); XmlFsType.VolumeName = StringHandlers.CToString(fsb.name, Encoding); } } information = sb.ToString(); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { // ZFS is always UTF-8 Encoding = Encoding.UTF8; information = ""; if (imagePlugin.Info.SectorSize < 512) { return; } byte[] sector; ulong magic; ulong nvlistOff = 32; uint nvlistLen = 114688 / imagePlugin.Info.SectorSize; if (partition.Start + 31 < partition.End) { sector = imagePlugin.ReadSector(partition.Start + 31); magic = BitConverter.ToUInt64(sector, 0x1D8); if (magic == ZEC_MAGIC || magic == ZEC_CIGAM) { nvlistOff = 32; } } if (partition.Start + 16 < partition.End) { sector = imagePlugin.ReadSector(partition.Start + 16); magic = BitConverter.ToUInt64(sector, 0x1D8); if (magic == ZEC_MAGIC || magic == ZEC_CIGAM) { nvlistOff = 17; } } StringBuilder sb = new StringBuilder(); sb.AppendLine("ZFS filesystem"); byte[] nvlist = imagePlugin.ReadSectors(partition.Start + nvlistOff, nvlistLen); sb.AppendLine(!DecodeNvList(nvlist, out Dictionary <string, NVS_Item> decodedNvList) ? "Could not decode nvlist" : PrintNvList(decodedNvList)); information = sb.ToString(); XmlFsType = new FileSystemType { Type = "ZFS filesystem" }; if (decodedNvList.TryGetValue("name", out NVS_Item tmpObj)) { XmlFsType.VolumeName = (string)tmpObj.value; } if (decodedNvList.TryGetValue("guid", out tmpObj)) { XmlFsType.VolumeSerial = $"{(ulong)tmpObj.value}"; } if (decodedNvList.TryGetValue("pool_guid", out tmpObj)) { XmlFsType.VolumeSetIdentifier = $"{(ulong)tmpObj.value}"; } }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? new MacRoman(); information = ""; StringBuilder sb = new StringBuilder(); MFS_MasterDirectoryBlock mdb = new MFS_MasterDirectoryBlock(); MFS_BootBlock bb = new MFS_BootBlock(); byte[] pString = new byte[16]; byte[] mdbSector = imagePlugin.ReadSector(2 + partition.Start); byte[] bbSector = imagePlugin.ReadSector(0 + partition.Start); mdb.drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, 0x000); if (mdb.drSigWord != MFS_MAGIC) { return; } mdb.drCrDate = BigEndianBitConverter.ToUInt32(mdbSector, 0x002); mdb.drLsBkUp = BigEndianBitConverter.ToUInt32(mdbSector, 0x006); mdb.drAtrb = BigEndianBitConverter.ToUInt16(mdbSector, 0x00A); mdb.drNmFls = BigEndianBitConverter.ToUInt16(mdbSector, 0x00C); mdb.drDirSt = BigEndianBitConverter.ToUInt16(mdbSector, 0x00E); mdb.drBlLen = BigEndianBitConverter.ToUInt16(mdbSector, 0x010); mdb.drNmAlBlks = BigEndianBitConverter.ToUInt16(mdbSector, 0x012); mdb.drAlBlkSiz = BigEndianBitConverter.ToUInt32(mdbSector, 0x014); mdb.drClpSiz = BigEndianBitConverter.ToUInt32(mdbSector, 0x018); mdb.drAlBlSt = BigEndianBitConverter.ToUInt16(mdbSector, 0x01C); mdb.drNxtFNum = BigEndianBitConverter.ToUInt32(mdbSector, 0x01E); mdb.drFreeBks = BigEndianBitConverter.ToUInt16(mdbSector, 0x022); mdb.drVNSiz = mdbSector[0x024]; byte[] variableSize = new byte[mdb.drVNSiz + 1]; Array.Copy(mdbSector, 0x024, variableSize, 0, mdb.drVNSiz + 1); mdb.drVN = StringHandlers.PascalToString(variableSize, Encoding); bb.signature = BigEndianBitConverter.ToUInt16(bbSector, 0x000); if (bb.signature == MFSBB_MAGIC) { bb.branch = BigEndianBitConverter.ToUInt32(bbSector, 0x002); bb.boot_flags = bbSector[0x006]; bb.boot_version = bbSector[0x007]; bb.sec_sv_pages = BigEndianBitConverter.ToInt16(bbSector, 0x008); Array.Copy(mdbSector, 0x00A, pString, 0, 16); bb.system_name = StringHandlers.PascalToString(pString, Encoding); Array.Copy(mdbSector, 0x01A, pString, 0, 16); bb.finder_name = StringHandlers.PascalToString(pString, Encoding); Array.Copy(mdbSector, 0x02A, pString, 0, 16); bb.debug_name = StringHandlers.PascalToString(pString, Encoding); Array.Copy(mdbSector, 0x03A, pString, 0, 16); bb.disasm_name = StringHandlers.PascalToString(pString, Encoding); Array.Copy(mdbSector, 0x04A, pString, 0, 16); bb.stupscr_name = StringHandlers.PascalToString(pString, Encoding); Array.Copy(mdbSector, 0x05A, pString, 0, 16); bb.bootup_name = StringHandlers.PascalToString(pString, Encoding); Array.Copy(mdbSector, 0x06A, pString, 0, 16); bb.clipbrd_name = StringHandlers.PascalToString(pString, Encoding); bb.max_files = BigEndianBitConverter.ToUInt16(bbSector, 0x07A); bb.queue_size = BigEndianBitConverter.ToUInt16(bbSector, 0x07C); bb.heap_128k = BigEndianBitConverter.ToUInt32(bbSector, 0x07E); bb.heap_256k = BigEndianBitConverter.ToUInt32(bbSector, 0x082); bb.heap_512k = BigEndianBitConverter.ToUInt32(bbSector, 0x086); } else { bb.signature = 0x0000; } sb.AppendLine("Apple Macintosh File System"); sb.AppendLine(); sb.AppendLine("Master Directory Block:"); sb.AppendFormat("Creation date: {0}", DateHandlers.MacToDateTime(mdb.drCrDate)).AppendLine(); sb.AppendFormat("Last backup date: {0}", DateHandlers.MacToDateTime(mdb.drLsBkUp)).AppendLine(); if ((mdb.drAtrb & 0x80) == 0x80) { sb.AppendLine("Volume is locked by hardware."); } if ((mdb.drAtrb & 0x8000) == 0x8000) { sb.AppendLine("Volume is locked by software."); } sb.AppendFormat("{0} files on volume", mdb.drNmFls).AppendLine(); sb.AppendFormat("First directory sector: {0}", mdb.drDirSt).AppendLine(); sb.AppendFormat("{0} sectors in directory.", mdb.drBlLen).AppendLine(); sb.AppendFormat("{0} volume allocation blocks.", mdb.drNmAlBlks + 1).AppendLine(); sb.AppendFormat("Size of allocation blocks: {0} bytes", mdb.drAlBlkSiz).AppendLine(); sb.AppendFormat("{0} bytes to allocate.", mdb.drClpSiz).AppendLine(); sb.AppendFormat("First allocation block (#2) starts in sector {0}.", mdb.drAlBlSt).AppendLine(); sb.AppendFormat("Next unused file number: {0}", mdb.drNxtFNum).AppendLine(); sb.AppendFormat("{0} unused allocation blocks.", mdb.drFreeBks).AppendLine(); sb.AppendFormat("Volume name: {0}", mdb.drVN).AppendLine(); if (bb.signature == MFSBB_MAGIC) { sb.AppendLine("Volume is bootable."); sb.AppendLine(); sb.AppendLine("Boot Block:"); if ((bb.boot_flags & 0x40) == 0x40) { sb.AppendLine("Boot block should be executed."); } if ((bb.boot_flags & 0x80) == 0x80) { sb.AppendLine("Boot block is in new unknown format."); } else { if (bb.sec_sv_pages > 0) { sb.AppendLine("Allocate secondary sound buffer at boot."); } else if (bb.sec_sv_pages < 0) { sb.AppendLine("Allocate secondary sound and video buffers at boot."); } sb.AppendFormat("System filename: {0}", bb.system_name).AppendLine(); sb.AppendFormat("Finder filename: {0}", bb.finder_name).AppendLine(); sb.AppendFormat("Debugger filename: {0}", bb.debug_name).AppendLine(); sb.AppendFormat("Disassembler filename: {0}", bb.disasm_name).AppendLine(); sb.AppendFormat("Startup screen filename: {0}", bb.stupscr_name).AppendLine(); sb.AppendFormat("First program to execute at boot: {0}", bb.bootup_name).AppendLine(); sb.AppendFormat("Clipboard filename: {0}", bb.clipbrd_name).AppendLine(); sb.AppendFormat("Maximum opened files: {0}", bb.max_files * 4).AppendLine(); sb.AppendFormat("Event queue size: {0}", bb.queue_size).AppendLine(); sb.AppendFormat("Heap size with 128KiB of RAM: {0} bytes", bb.heap_128k).AppendLine(); sb.AppendFormat("Heap size with 256KiB of RAM: {0} bytes", bb.heap_256k).AppendLine(); sb.AppendFormat("Heap size with 512KiB of RAM or more: {0} bytes", bb.heap_512k).AppendLine(); } } else { sb.AppendLine("Volume is not bootable."); } information = sb.ToString(); XmlFsType = new FileSystemType(); if (mdb.drLsBkUp > 0) { XmlFsType.BackupDate = DateHandlers.MacToDateTime(mdb.drLsBkUp); XmlFsType.BackupDateSpecified = true; } XmlFsType.Bootable = bb.signature == MFSBB_MAGIC; XmlFsType.Clusters = mdb.drNmAlBlks; XmlFsType.ClusterSize = mdb.drAlBlkSiz; if (mdb.drCrDate > 0) { XmlFsType.CreationDate = DateHandlers.MacToDateTime(mdb.drCrDate); XmlFsType.CreationDateSpecified = true; } XmlFsType.Files = mdb.drNmFls; XmlFsType.FilesSpecified = true; XmlFsType.FreeClusters = mdb.drFreeBks; XmlFsType.FreeClustersSpecified = true; XmlFsType.Type = "MFS"; XmlFsType.VolumeName = mdb.drVN; }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("shift_jis"); StringBuilder sbInformation = new StringBuilder(); information = ""; XmlFsType = new FileSystemType(); NintendoFields fields = new NintendoFields(); BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; byte[] header = imagePlugin.ReadSectors(0, 0x50000 / imagePlugin.Info.SectorSize); bool wii = false; uint magicGc = BigEndianBitConverter.ToUInt32(header, 0x1C); uint magicWii = BigEndianBitConverter.ToUInt32(header, 0x18); if (magicWii == 0x5D1C9EA3) { wii = true; } else if (magicGc != 0xC2339F3D) { return; } fields.DiscType = Encoding.ASCII.GetString(header, 0, 1); fields.GameCode = Encoding.ASCII.GetString(header, 1, 2); fields.RegionCode = Encoding.ASCII.GetString(header, 3, 1); fields.PublisherCode = Encoding.ASCII.GetString(header, 4, 2); fields.DiscId = Encoding.ASCII.GetString(header, 0, 6); fields.DiscNumber = header[6]; fields.DiscVersion = header[7]; fields.Streaming |= header[8] > 0; fields.StreamBufferSize = header[9]; byte[] temp = new byte[64]; Array.Copy(header, 0x20, temp, 0, 64); fields.Title = StringHandlers.CToString(temp, Encoding); if (!wii) { fields.DebugOff = BigEndianBitConverter.ToUInt32(header, 0x0400); fields.DebugAddr = BigEndianBitConverter.ToUInt32(header, 0x0404); fields.DolOff = BigEndianBitConverter.ToUInt32(header, 0x0420); fields.FstOff = BigEndianBitConverter.ToUInt32(header, 0x0424); fields.FstSize = BigEndianBitConverter.ToUInt32(header, 0x0428); fields.FstMax = BigEndianBitConverter.ToUInt32(header, 0x042C); } if (wii) { uint offset1 = BigEndianBitConverter.ToUInt32(header, 0x40004) << 2; uint offset2 = BigEndianBitConverter.ToUInt32(header, 0x4000C) << 2; uint offset3 = BigEndianBitConverter.ToUInt32(header, 0x40014) << 2; uint offset4 = BigEndianBitConverter.ToUInt32(header, 0x4001C) << 2; fields.FirstPartitions = new NintendoPartition[BigEndianBitConverter.ToUInt32(header, 0x40000)]; fields.SecondPartitions = new NintendoPartition[BigEndianBitConverter.ToUInt32(header, 0x40008)]; fields.ThirdPartitions = new NintendoPartition[BigEndianBitConverter.ToUInt32(header, 0x40010)]; fields.FourthPartitions = new NintendoPartition[BigEndianBitConverter.ToUInt32(header, 0x40018)]; for (int i = 0; i < fields.FirstPartitions.Length; i++) { if (offset1 + i * 8 + 8 < 0x50000) { fields.FirstPartitions[i].Offset = BigEndianBitConverter.ToUInt32(header, (int)(offset1 + i * 8 + 0)) << 2; fields.FirstPartitions[i].Type = BigEndianBitConverter.ToUInt32(header, (int)(offset1 + i * 8 + 4)); } } for (int i = 0; i < fields.SecondPartitions.Length; i++) { if (offset1 + i * 8 + 8 < 0x50000) { fields.FirstPartitions[i].Offset = BigEndianBitConverter.ToUInt32(header, (int)(offset2 + i * 8 + 0)) << 2; fields.FirstPartitions[i].Type = BigEndianBitConverter.ToUInt32(header, (int)(offset2 + i * 8 + 4)); } } for (int i = 0; i < fields.ThirdPartitions.Length; i++) { if (offset1 + i * 8 + 8 < 0x50000) { fields.FirstPartitions[i].Offset = BigEndianBitConverter.ToUInt32(header, (int)(offset3 + i * 8 + 0)) << 2; fields.FirstPartitions[i].Type = BigEndianBitConverter.ToUInt32(header, (int)(offset3 + i * 8 + 4)); } } for (int i = 0; i < fields.FourthPartitions.Length; i++) { if (offset1 + i * 8 + 8 < 0x50000) { fields.FirstPartitions[i].Offset = BigEndianBitConverter.ToUInt32(header, (int)(offset4 + i * 8 + 0)) << 2; fields.FirstPartitions[i].Type = BigEndianBitConverter.ToUInt32(header, (int)(offset4 + i * 8 + 4)); } } fields.Region = header[0x4E000]; fields.JapanAge = header[0x4E010]; fields.UsaAge = header[0x4E011]; fields.GermanAge = header[0x4E013]; fields.PegiAge = header[0x4E014]; fields.FinlandAge = header[0x4E015]; fields.PortugalAge = header[0x4E016]; fields.UkAge = header[0x4E017]; fields.AustraliaAge = header[0x4E018]; fields.KoreaAge = header[0x4E019]; } else { fields.FirstPartitions = new NintendoPartition[0]; fields.SecondPartitions = new NintendoPartition[0]; fields.ThirdPartitions = new NintendoPartition[0]; fields.FourthPartitions = new NintendoPartition[0]; } DicConsole.DebugWriteLine("Nintendo plugin", "discType = {0}", fields.DiscType); DicConsole.DebugWriteLine("Nintendo plugin", "gameCode = {0}", fields.GameCode); DicConsole.DebugWriteLine("Nintendo plugin", "regionCode = {0}", fields.RegionCode); DicConsole.DebugWriteLine("Nintendo plugin", "publisherCode = {0}", fields.PublisherCode); DicConsole.DebugWriteLine("Nintendo plugin", "discID = {0}", fields.DiscId); DicConsole.DebugWriteLine("Nintendo plugin", "discNumber = {0}", fields.DiscNumber); DicConsole.DebugWriteLine("Nintendo plugin", "discVersion = {0}", fields.DiscVersion); DicConsole.DebugWriteLine("Nintendo plugin", "streaming = {0}", fields.Streaming); DicConsole.DebugWriteLine("Nintendo plugin", "streamBufferSize = {0}", fields.StreamBufferSize); DicConsole.DebugWriteLine("Nintendo plugin", "title = \"{0}\"", fields.Title); DicConsole.DebugWriteLine("Nintendo plugin", "debugOff = 0x{0:X8}", fields.DebugOff); DicConsole.DebugWriteLine("Nintendo plugin", "debugAddr = 0x{0:X8}", fields.DebugAddr); DicConsole.DebugWriteLine("Nintendo plugin", "dolOff = 0x{0:X8}", fields.DolOff); DicConsole.DebugWriteLine("Nintendo plugin", "fstOff = 0x{0:X8}", fields.FstOff); DicConsole.DebugWriteLine("Nintendo plugin", "fstSize = {0}", fields.FstSize); DicConsole.DebugWriteLine("Nintendo plugin", "fstMax = {0}", fields.FstMax); for (int i = 0; i < fields.FirstPartitions.Length; i++) { DicConsole.DebugWriteLine("Nintendo plugin", "firstPartitions[{1}].offset = {0}", fields.FirstPartitions[i].Offset, i); DicConsole.DebugWriteLine("Nintendo plugin", "firstPartitions[{1}].type = {0}", fields.FirstPartitions[i].Type, i); } for (int i = 0; i < fields.SecondPartitions.Length; i++) { DicConsole.DebugWriteLine("Nintendo plugin", "secondPartitions[{1}].offset = {0}", fields.SecondPartitions[i].Offset, i); DicConsole.DebugWriteLine("Nintendo plugin", "secondPartitions[{1}].type = {0}", fields.SecondPartitions[i].Type, i); } for (int i = 0; i < fields.ThirdPartitions.Length; i++) { DicConsole.DebugWriteLine("Nintendo plugin", "thirdPartitions[{1}].offset = {0}", fields.ThirdPartitions[i].Offset, i); DicConsole.DebugWriteLine("Nintendo plugin", "thirdPartitions[{1}].type = {0}", fields.ThirdPartitions[i].Type, i); } for (int i = 0; i < fields.FourthPartitions.Length; i++) { DicConsole.DebugWriteLine("Nintendo plugin", "fourthPartitions[{1}].offset = {0}", fields.FourthPartitions[i].Offset, i); DicConsole.DebugWriteLine("Nintendo plugin", "fourthPartitions[{1}].type = {0}", fields.FourthPartitions[i].Type, i); } DicConsole.DebugWriteLine("Nintendo plugin", "region = {0}", fields.Region); DicConsole.DebugWriteLine("Nintendo plugin", "japanAge = {0}", fields.JapanAge); DicConsole.DebugWriteLine("Nintendo plugin", "usaAge = {0}", fields.UsaAge); DicConsole.DebugWriteLine("Nintendo plugin", "germanAge = {0}", fields.GermanAge); DicConsole.DebugWriteLine("Nintendo plugin", "pegiAge = {0}", fields.PegiAge); DicConsole.DebugWriteLine("Nintendo plugin", "finlandAge = {0}", fields.FinlandAge); DicConsole.DebugWriteLine("Nintendo plugin", "portugalAge = {0}", fields.PortugalAge); DicConsole.DebugWriteLine("Nintendo plugin", "ukAge = {0}", fields.UkAge); DicConsole.DebugWriteLine("Nintendo plugin", "australiaAge = {0}", fields.AustraliaAge); DicConsole.DebugWriteLine("Nintendo plugin", "koreaAge = {0}", fields.KoreaAge); sbInformation.AppendLine("Nintendo optical filesystem"); sbInformation.AppendLine(wii ? "Nintendo Wii Optical Disc" : "Nintendo GameCube Optical Disc"); sbInformation.AppendFormat("Disc ID is {0}", fields.DiscId).AppendLine(); sbInformation.AppendFormat("Disc is a {0} disc", DiscTypeToString(fields.DiscType)).AppendLine(); sbInformation.AppendFormat("Disc region is {0}", RegionCodeToString(fields.RegionCode)).AppendLine(); sbInformation.AppendFormat("Published by {0}", PublisherCodeToString(fields.PublisherCode)).AppendLine(); if (fields.DiscNumber > 0) { sbInformation.AppendFormat("Disc number {0} of a multi-disc set", fields.DiscNumber + 1).AppendLine(); } if (fields.Streaming) { sbInformation.AppendLine("Disc is prepared for audio streaming"); } if (fields.StreamBufferSize > 0) { sbInformation.AppendFormat("Audio streaming buffer size is {0} bytes", fields.StreamBufferSize) .AppendLine(); } sbInformation.AppendFormat("Title: {0}", fields.Title).AppendLine(); if (wii) { for (int i = 0; i < fields.FirstPartitions.Length; i++) { sbInformation.AppendFormat("First {0} partition starts at sector {1}", PartitionTypeToString(fields.FirstPartitions[i].Type), fields.FirstPartitions[i].Offset / 2048).AppendLine(); } for (int i = 0; i < fields.SecondPartitions.Length; i++) { sbInformation.AppendFormat("Second {0} partition starts at sector {1}", PartitionTypeToString(fields.SecondPartitions[i].Type), fields.SecondPartitions[i].Offset / 2048).AppendLine(); } for (int i = 0; i < fields.ThirdPartitions.Length; i++) { sbInformation.AppendFormat("Third {0} partition starts at sector {1}", PartitionTypeToString(fields.ThirdPartitions[i].Type), fields.ThirdPartitions[i].Offset / 2048).AppendLine(); } for (int i = 0; i < fields.FourthPartitions.Length; i++) { sbInformation.AppendFormat("Fourth {0} partition starts at sector {1}", PartitionTypeToString(fields.FourthPartitions[i].Type), fields.FourthPartitions[i].Offset / 2048).AppendLine(); } // sbInformation.AppendFormat("Region byte is {0}", fields.region).AppendLine(); if ((fields.JapanAge & 0x80) != 0x80) { sbInformation.AppendFormat("Japan age rating is {0}", fields.JapanAge).AppendLine(); } if ((fields.UsaAge & 0x80) != 0x80) { sbInformation.AppendFormat("ESRB age rating is {0}", fields.UsaAge).AppendLine(); } if ((fields.GermanAge & 0x80) != 0x80) { sbInformation.AppendFormat("German age rating is {0}", fields.GermanAge).AppendLine(); } if ((fields.PegiAge & 0x80) != 0x80) { sbInformation.AppendFormat("PEGI age rating is {0}", fields.PegiAge).AppendLine(); } if ((fields.FinlandAge & 0x80) != 0x80) { sbInformation.AppendFormat("Finland age rating is {0}", fields.FinlandAge).AppendLine(); } if ((fields.PortugalAge & 0x80) != 0x80) { sbInformation.AppendFormat("Portugal age rating is {0}", fields.PortugalAge).AppendLine(); } if ((fields.UkAge & 0x80) != 0x80) { sbInformation.AppendFormat("UK age rating is {0}", fields.UkAge).AppendLine(); } if ((fields.AustraliaAge & 0x80) != 0x80) { sbInformation.AppendFormat("Australia age rating is {0}", fields.AustraliaAge).AppendLine(); } if ((fields.KoreaAge & 0x80) != 0x80) { sbInformation.AppendFormat("Korea age rating is {0}", fields.KoreaAge).AppendLine(); } } else { sbInformation.AppendFormat("FST starts at {0} and has {1} bytes", fields.FstOff, fields.FstSize) .AppendLine(); } information = sbInformation.ToString(); XmlFsType.Bootable = true; XmlFsType.Clusters = (long)(imagePlugin.Info.Sectors * imagePlugin.Info.SectorSize / 2048); XmlFsType.ClusterSize = 2048; XmlFsType.Type = wii ? "Nintendo Wii filesystem" : "Nintendo Gamecube filesystem"; XmlFsType.VolumeName = fields.Title; XmlFsType.VolumeSerial = fields.DiscId; }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); information = ""; if (imagePlugin.Info.SectorSize < 256) { return; } RBF_IdSector rbfSb = new RBF_IdSector(); RBF_NewIdSector rbf9000Sb = new RBF_NewIdSector(); foreach (int i in new[] { 0, 4, 15 }) { ulong location = (ulong)i; uint sbSize = (uint)(Marshal.SizeOf(rbfSb) / imagePlugin.Info.SectorSize); if (Marshal.SizeOf(rbfSb) % imagePlugin.Info.SectorSize != 0) { sbSize++; } byte[] sector = imagePlugin.ReadSectors(partition.Start + location, sbSize); if (sector.Length < Marshal.SizeOf(rbfSb)) { return; } rbfSb = BigEndianMarshal.ByteArrayToStructureBigEndian <RBF_IdSector>(sector); rbf9000Sb = BigEndianMarshal.ByteArrayToStructureBigEndian <RBF_NewIdSector>(sector); DicConsole.DebugWriteLine("RBF plugin", "magic at {0} = 0x{1:X8} or 0x{2:X8} (expected 0x{3:X8} or 0x{4:X8})", location, rbfSb.dd_sync, rbf9000Sb.rid_sync, RBF_SYNC, RBF_CNYS); if (rbfSb.dd_sync == RBF_SYNC || rbf9000Sb.rid_sync == RBF_SYNC || rbf9000Sb.rid_sync == RBF_CNYS) { break; } } if (rbfSb.dd_sync != RBF_SYNC && rbf9000Sb.rid_sync != RBF_SYNC && rbf9000Sb.rid_sync != RBF_CNYS) { return; } if (rbf9000Sb.rid_sync == RBF_CNYS) { rbf9000Sb = (RBF_NewIdSector)BigEndianMarshal.SwapStructureMembersEndian(rbf9000Sb); } StringBuilder sb = new StringBuilder(); sb.AppendLine("OS-9 Random Block File"); if (rbf9000Sb.rid_sync == RBF_SYNC) { sb.AppendFormat("Volume ID: {0:X8}", rbf9000Sb.rid_diskid).AppendLine(); sb.AppendFormat("{0} blocks in volume", rbf9000Sb.rid_totblocks).AppendLine(); sb.AppendFormat("{0} cylinders", rbf9000Sb.rid_cylinders).AppendLine(); sb.AppendFormat("{0} blocks in cylinder 0", rbf9000Sb.rid_cyl0size).AppendLine(); sb.AppendFormat("{0} blocks per cylinder", rbf9000Sb.rid_cylsize).AppendLine(); sb.AppendFormat("{0} heads", rbf9000Sb.rid_heads).AppendLine(); sb.AppendFormat("{0} bytes per block", rbf9000Sb.rid_blocksize).AppendLine(); // TODO: Convert to flags? sb.AppendLine((rbf9000Sb.rid_format & 0x01) == 0x01 ? "Disk is double sided" : "Disk is single sided"); sb.AppendLine((rbf9000Sb.rid_format & 0x02) == 0x02 ? "Disk is double density" : "Disk is single density"); if ((rbf9000Sb.rid_format & 0x10) == 0x10) { sb.AppendLine("Disk is 384 TPI"); } else if ((rbf9000Sb.rid_format & 0x08) == 0x08) { sb.AppendLine("Disk is 192 TPI"); } else if ((rbf9000Sb.rid_format & 0x04) == 0x04) { sb.AppendLine("Disk is 96 TPI or 135 TPI"); } else { sb.AppendLine("Disk is 48 TPI"); } sb.AppendFormat("Allocation bitmap descriptor starts at block {0}", rbf9000Sb.rid_bitmap == 0 ? 1 : rbf9000Sb.rid_bitmap).AppendLine(); if (rbf9000Sb.rid_firstboot > 0) { sb.AppendFormat("Debugger descriptor starts at block {0}", rbf9000Sb.rid_firstboot).AppendLine(); } if (rbf9000Sb.rid_bootfile > 0) { sb.AppendFormat("Boot file descriptor starts at block {0}", rbf9000Sb.rid_bootfile).AppendLine(); } sb.AppendFormat("Root directory descriptor starts at block {0}", rbf9000Sb.rid_rootdir).AppendLine(); sb.AppendFormat("Disk is owned by group {0} user {1}", rbf9000Sb.rid_group, rbf9000Sb.rid_owner) .AppendLine(); sb.AppendFormat("Volume was created on {0}", DateHandlers.UnixToDateTime(rbf9000Sb.rid_ctime)) .AppendLine(); sb.AppendFormat("Volume's identification block was last written on {0}", DateHandlers.UnixToDateTime(rbf9000Sb.rid_mtime)).AppendLine(); sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(rbf9000Sb.rid_name, Encoding)) .AppendLine(); XmlFsType = new FileSystemType { Type = "OS-9 Random Block File", Bootable = rbf9000Sb.rid_bootfile > 0, ClusterSize = rbf9000Sb.rid_blocksize, Clusters = rbf9000Sb.rid_totblocks, CreationDate = DateHandlers.UnixToDateTime(rbf9000Sb.rid_ctime), CreationDateSpecified = true, ModificationDate = DateHandlers.UnixToDateTime(rbf9000Sb.rid_mtime), ModificationDateSpecified = true, VolumeName = StringHandlers.CToString(rbf9000Sb.rid_name, Encoding), VolumeSerial = $"{rbf9000Sb.rid_diskid:X8}" }; } else { sb.AppendFormat("Volume ID: {0:X4}", rbfSb.dd_dsk).AppendLine(); sb.AppendFormat("{0} blocks in volume", LSNToUInt32(rbfSb.dd_tot)).AppendLine(); sb.AppendFormat("{0} tracks", rbfSb.dd_tks).AppendLine(); sb.AppendFormat("{0} sectors per track", rbfSb.dd_spt).AppendLine(); sb.AppendFormat("{0} bytes per sector", 256 << rbfSb.dd_lsnsize).AppendLine(); sb.AppendFormat("{0} sectors per cluster ({1} bytes)", rbfSb.dd_bit, rbfSb.dd_bit * (256 << rbfSb.dd_lsnsize)).AppendLine(); // TODO: Convert to flags? sb.AppendLine((rbfSb.dd_fmt & 0x01) == 0x01 ? "Disk is double sided" : "Disk is single sided"); sb.AppendLine((rbfSb.dd_fmt & 0x02) == 0x02 ? "Disk is double density" : "Disk is single density"); if ((rbfSb.dd_fmt & 0x10) == 0x10) { sb.AppendLine("Disk is 384 TPI"); } else if ((rbfSb.dd_fmt & 0x08) == 0x08) { sb.AppendLine("Disk is 192 TPI"); } else if ((rbfSb.dd_fmt & 0x04) == 0x04) { sb.AppendLine("Disk is 96 TPI or 135 TPI"); } else { sb.AppendLine("Disk is 48 TPI"); } sb.AppendFormat("Allocation bitmap descriptor starts at block {0}", rbfSb.dd_maplsn == 0 ? 1 : rbfSb.dd_maplsn).AppendLine(); sb.AppendFormat("{0} bytes in allocation bitmap", rbfSb.dd_map).AppendLine(); if (LSNToUInt32(rbfSb.dd_bt) > 0 && rbfSb.dd_bsz > 0) { sb.AppendFormat("Boot file starts at block {0} and has {1} bytes", LSNToUInt32(rbfSb.dd_bt), rbfSb.dd_bsz).AppendLine(); } sb.AppendFormat("Root directory descriptor starts at block {0}", LSNToUInt32(rbfSb.dd_dir)) .AppendLine(); sb.AppendFormat("Disk is owned by user {0}", rbfSb.dd_own).AppendLine(); sb.AppendFormat("Volume was created on {0}", DateHandlers.Os9ToDateTime(rbfSb.dd_dat)).AppendLine(); sb.AppendFormat("Volume attributes: {0:X2}", rbfSb.dd_att).AppendLine(); sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(rbfSb.dd_nam, Encoding)).AppendLine(); sb.AppendFormat("Path descriptor options: {0}", StringHandlers.CToString(rbfSb.dd_opt, Encoding)) .AppendLine(); XmlFsType = new FileSystemType { Type = "OS-9 Random Block File", Bootable = LSNToUInt32(rbfSb.dd_bt) > 0 && rbfSb.dd_bsz > 0, ClusterSize = rbfSb.dd_bit * (256 << rbfSb.dd_lsnsize), Clusters = LSNToUInt32(rbfSb.dd_tot), CreationDate = DateHandlers.Os9ToDateTime(rbfSb.dd_dat), CreationDateSpecified = true, VolumeName = StringHandlers.CToString(rbfSb.dd_nam, Encoding), VolumeSerial = $"{rbfSb.dd_dsk:X4}" }; } information = sb.ToString(); }
/// <summary> /// Config the SUT. /// </summary> /// <param name="fileSystemType">The file system type of the server.</param> /// <param name="serverSignState">Indicate what the message signing policy of server.</param> /// <param name="isSupportDfs">Indicate whether the server supports DFS.</param> /// <param name="isSupportPreviousVersion">Indicate whether the server will support previous version.</param> /// <param name="isMessageModePipe">Indicate the adapter to setup a message mode pipe or byte mode pipe</param> public void ServerSetup( FileSystemType fileSystemType, SignState serverSignState, bool isSupportDfs, bool isSupportPreviousVersion, bool isMessageModePipe) { bool isInteractiveAdapterUsed = bool.Parse(Site.Properties.Get("SutInteractiveAdapterIsUsed")); if (isInteractiveAdapterUsed) { IDeleteFilesInteractiveAdapter deleteFileAdapter = Site.GetAdapter<ISutInteractiveAdapter>(); deleteFileAdapter.DeleteFiles(); IConfigSignStateInteractiveAdapter configSignStateAdapter = Site.GetAdapter<ISutInteractiveAdapter>(); string sutName = Site.Properties["SutMachineName"]; switch (serverSignState) { case SignState.Disabled: configSignStateAdapter.ConfigSignState(sutName, "Disabled"); break; case SignState.Enabled: configSignStateAdapter.ConfigSignState(sutName, "Enabled"); break; case SignState.Required: configSignStateAdapter.ConfigSignState(sutName, "Required"); break; case SignState.DisabledUnlessRequired: configSignStateAdapter.ConfigSignState(sutName, "DisabledUnlessRequired"); break; } } else { IDeleteFilesAdapter deleteFileAdapter = Site.GetAdapter<IDeleteFilesAdapter>(); deleteFileAdapter.DeleteFiles(); IConfigSignStateAdapter configSignStateAdapter = Site.GetAdapter<IConfigSignStateAdapter>(); string sutName = Site.Properties["SutMachineName"]; switch (serverSignState) { case SignState.Disabled: configSignStateAdapter.ConfigSignState(sutName, "Disabled"); break; case SignState.Enabled: configSignStateAdapter.ConfigSignState(sutName, "Enabled"); break; case SignState.Required: configSignStateAdapter.ConfigSignState(sutName, "Required"); break; case SignState.DisabledUnlessRequired: configSignStateAdapter.ConfigSignState(sutName, "DisabledUnlessRequired"); break; } } int totalByteWritten = 1; bool isSupportResumeKey = true; bool isSupportCopyChunk = true; if (fileSystemType == FileSystemType.Ntfs) { SmbAdapter.FsType = "Ntfs"; } else { SmbAdapter.FsType = "Fat"; } SmbAdapter.state = serverSignState; SmbAdapter.fileSystemType = fileSystemType; SmbAdapter.isSupportDfs = isSupportDfs; SmbAdapter.isMessageModePipe = isMessageModePipe; SmbAdapter.isPreviousVersion = isSupportPreviousVersion; SmbAdapter.isSupportStream = true; SmbAdapter.isSupportInfoLevelPassThru = true; SmbAdapter.isSupportNtSmb = true; SmbAdapter.isRapServerActive = true; this.ServerSetupResponse( totalByteWritten, SmbAdapter.isSupportInfoLevelPassThru, SmbAdapter.isSupportNtSmb, SmbAdapter.isRapServerActive, isSupportResumeKey, isSupportCopyChunk); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-1"); byte[] rootBlockSector = imagePlugin.ReadSector(2 + partition.Start); RootBlock rootBlock = Marshal.ByteArrayToStructureBigEndian <RootBlock>(rootBlockSector); StringBuilder sbInformation = new StringBuilder(); XmlFsType = new FileSystemType(); switch (rootBlock.diskType) { case AFS_DISK: case MUAF_DISK: sbInformation.Append("Professional File System v1"); XmlFsType.Type = "PFS v1"; break; case PFS2_DISK: sbInformation.Append("Professional File System v2"); XmlFsType.Type = "PFS v2"; break; case PFS_DISK: case MUPFS_DISK: sbInformation.Append("Professional File System v3"); XmlFsType.Type = "PFS v3"; break; } if (rootBlock.diskType == MUAF_DISK || rootBlock.diskType == MUPFS_DISK) { sbInformation.Append(", with multi-user support"); } sbInformation.AppendLine(); sbInformation.AppendFormat("Volume name: {0}", StringHandlers.PascalToString(rootBlock.diskname, Encoding)) .AppendLine(); sbInformation.AppendFormat("Volume has {0} free sectors of {1}", rootBlock.blocksfree, rootBlock.diskSize) .AppendLine(); sbInformation.AppendFormat("Volume created on {0}", DateHandlers.AmigaToDateTime(rootBlock.creationday, rootBlock.creationminute, rootBlock.creationtick)).AppendLine(); if (rootBlock.extension > 0) { sbInformation.AppendFormat("Root block extension resides at block {0}", rootBlock.extension) .AppendLine(); } information = sbInformation.ToString(); XmlFsType.CreationDate = DateHandlers.AmigaToDateTime(rootBlock.creationday, rootBlock.creationminute, rootBlock.creationtick); XmlFsType.CreationDateSpecified = true; XmlFsType.FreeClusters = rootBlock.blocksfree; XmlFsType.FreeClustersSpecified = true; XmlFsType.Clusters = rootBlock.diskSize; XmlFsType.ClusterSize = imagePlugin.Info.SectorSize; XmlFsType.VolumeName = StringHandlers.PascalToString(rootBlock.diskname, Encoding); }