diff --git a/.idea/.idea.DiscImageChef/.idea/contentModel.xml b/.idea/.idea.DiscImageChef/.idea/contentModel.xml index 1ab96201..283708d5 100644 --- a/.idea/.idea.DiscImageChef/.idea/contentModel.xml +++ b/.idea/.idea.DiscImageChef/.idea/contentModel.xml @@ -509,6 +509,7 @@ + @@ -824,6 +825,7 @@ + diff --git a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj index d0e1efef..936891b4 100644 --- a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj +++ b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj @@ -41,6 +41,7 @@ + diff --git a/DiscImageChef.Filesystems/HPOFS.cs b/DiscImageChef.Filesystems/HPOFS.cs new file mode 100644 index 00000000..49d9a7f8 --- /dev/null +++ b/DiscImageChef.Filesystems/HPOFS.cs @@ -0,0 +1,361 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : HPOFS.cs +// Author(s) : Natalia Portillo +// +// Component : High Performance Optical File System plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the High Performance Optical File System and shows +// information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2018 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using DiscImageChef.CommonTypes; +using DiscImageChef.Console; +using DiscImageChef.DiscImages; +using Schemas; + +namespace DiscImageChef.Filesystems +{ + // Information from test floppy images created with OS/2 HPOFS 2.0 + // Need to get IBM document GA32-0224 -> IBM 3995 Optical Library Dataserver Products: Optical Disk Format + public class HPOFS : IFilesystem + { + readonly byte[] hpofsType = {0x48, 0x50, 0x4F, 0x46, 0x53, 0x00, 0x00, 0x00}; + readonly byte[] medinfoSignature = {0x4D, 0x45, 0x44, 0x49, 0x4E, 0x46, 0x4F, 0x20}; + readonly byte[] volinfoSignature = {0x56, 0x4F, 0x4C, 0x49, 0x4E, 0x46, 0x4F, 0x20}; + + public FileSystemType XmlFsType { get; private set; } + public Encoding Encoding { get; private set; } + public string Name => "High Performance Optical File System"; + public Guid Id => new Guid("1b72dcd5-d031-4757-8a9f-8d2fb18c59e2"); + + public bool Identify(IMediaImage imagePlugin, Partition partition) + { + if(16 + partition.Start >= partition.End) return false; + + byte[] hpofsBpbSector = + imagePlugin.ReadSector(0 + partition.Start); // Seek to BIOS parameter block, on logical sector 0 + + IntPtr bpbPtr = Marshal.AllocHGlobal(512); + Marshal.Copy(hpofsBpbSector, 0, bpbPtr, 512); + BiosParameterBlock bpb = (BiosParameterBlock)Marshal.PtrToStructure(bpbPtr, typeof(BiosParameterBlock)); + Marshal.FreeHGlobal(bpbPtr); + + return bpb.fs_type.SequenceEqual(hpofsType); + } + + public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, + Encoding encoding) + { + Encoding = encoding ?? Encoding.GetEncoding("ibm850"); + information = ""; + + StringBuilder sb = new StringBuilder(); + + byte[] hpofsBpbSector = + imagePlugin.ReadSector(0 + partition.Start); // Seek to BIOS parameter block, on logical sector 0 + byte[] medInfoSector = + imagePlugin.ReadSector(13 + partition.Start); // Seek to media information block, on logical sector 13 + byte[] volInfoSector = + imagePlugin.ReadSector(14 + partition.Start); // Seek to volume information block, on logical sector 14 + + IntPtr bpbPtr = Marshal.AllocHGlobal(512); + Marshal.Copy(hpofsBpbSector, 0, bpbPtr, 512); + BiosParameterBlock bpb = (BiosParameterBlock)Marshal.PtrToStructure(bpbPtr, typeof(BiosParameterBlock)); + Marshal.FreeHGlobal(bpbPtr); + + MediaInformationBlock mib = + BigEndianMarshal.ByteArrayToStructureBigEndian(medInfoSector); + VolumeInformationBlock vib = + BigEndianMarshal.ByteArrayToStructureBigEndian(volInfoSector); + + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.oem_name = \"{0}\"", + StringHandlers.CToString(bpb.oem_name)); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.bps = {0}", bpb.bps); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.spc = {0}", bpb.spc); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.rsectors = {0}", bpb.rsectors); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.fats_no = {0}", bpb.fats_no); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.root_ent = {0}", bpb.root_ent); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.sectors = {0}", bpb.sectors); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.media = 0x{0:X2}", bpb.media); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.spfat = {0}", bpb.spfat); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.sptrk = {0}", bpb.sptrk); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.heads = {0}", bpb.heads); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.hsectors = {0}", bpb.hsectors); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.big_sectors = {0}", bpb.big_sectors); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.drive_no = 0x{0:X2}", bpb.drive_no); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.nt_flags = {0}", bpb.nt_flags); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.signature = 0x{0:X2}", bpb.signature); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.serial_no = 0x{0:X8}", bpb.serial_no); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.volume_label = \"{0}\"", + StringHandlers.SpacePaddedToString(bpb.volume_label)); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.fs_type = \"{0}\"", StringHandlers.CToString(bpb.fs_type)); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.boot_code is empty? = {0}", + ArrayHelpers.ArrayIsNullOrEmpty(bpb.boot_code)); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.unknown = {0}", bpb.unknown); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.unknown2 = {0}", bpb.unknown2); + DicConsole.DebugWriteLine("HPOFS Plugin", "bpb.signature2 = {0}", bpb.signature2); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.blockId = \"{0}\"", StringHandlers.CToString(mib.blockId)); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.volumeLabel = \"{0}\"", + StringHandlers.SpacePaddedToString(mib.volumeLabel)); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.comment = \"{0}\"", + StringHandlers.SpacePaddedToString(mib.comment)); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.serial = 0x{0:X8}", mib.serial); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.creationTimestamp = {0}", + DateHandlers.DosToDateTime(mib.creationDate, mib.creationTime)); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.codepageType = {0}", mib.codepageType); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.codepage = {0}", mib.codepage); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.rps = {0}", mib.rps); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.bps = {0}", mib.bps); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.bpc = {0}", mib.bpc); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.unknown2 = {0}", mib.unknown2); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.sectors = {0}", mib.sectors); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.unknown3 = {0}", mib.unknown3); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.unknown4 = {0}", mib.unknown4); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.major = {0}", mib.major); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.minor = {0}", mib.minor); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.unknown5 = {0}", mib.unknown5); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.unknown6 = {0}", mib.unknown6); + DicConsole.DebugWriteLine("HPOFS Plugin", "mib.filler is empty? = {0}", + ArrayHelpers.ArrayIsNullOrEmpty(mib.filler)); + DicConsole.DebugWriteLine("HPOFS Plugin", "vib.blockId = \"{0}\"", StringHandlers.CToString(vib.blockId)); + DicConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown = {0}", vib.unknown); + DicConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown2 = {0}", vib.unknown2); + DicConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown3 is empty? = {0}", + ArrayHelpers.ArrayIsNullOrEmpty(vib.unknown3)); + DicConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown4 = \"{0}\"", + StringHandlers.SpacePaddedToString(vib.unknown4)); + DicConsole.DebugWriteLine("HPOFS Plugin", "vib.owner = \"{0}\"", + StringHandlers.SpacePaddedToString(vib.owner)); + DicConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown5 = \"{0}\"", + StringHandlers.SpacePaddedToString(vib.unknown5)); + DicConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown6 = {0}", vib.unknown6); + DicConsole.DebugWriteLine("HPOFS Plugin", "vib.percentFull = {0}", vib.percentFull); + DicConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown7 = {0}", vib.unknown7); + DicConsole.DebugWriteLine("HPOFS Plugin", "vib.filler is empty? = {0}", + ArrayHelpers.ArrayIsNullOrEmpty(vib.filler)); + + sb.AppendLine("High Performance Optical File System"); + sb.AppendFormat("OEM name: {0}", StringHandlers.SpacePaddedToString(bpb.oem_name)) + .AppendLine(); + sb.AppendFormat("{0} bytes per sector", bpb.bps).AppendLine(); + sb.AppendFormat("{0} sectors per cluster", bpb.spc).AppendLine(); + sb.AppendFormat("Media descriptor: 0x{0:X2}", bpb.media).AppendLine(); + sb.AppendFormat("{0} sectors per track", bpb.sptrk).AppendLine(); + sb.AppendFormat("{0} heads", bpb.heads).AppendLine(); + sb.AppendFormat("{0} sectors hidden before BPB", bpb.hsectors).AppendLine(); + sb.AppendFormat("{0} sectors on volume ({1} bytes)", mib.sectors, mib.sectors * bpb.bps).AppendLine(); + sb.AppendFormat("BIOS Drive Number: 0x{0:X2}", bpb.drive_no).AppendLine(); + sb.AppendFormat("Serial number: 0x{0:X8}", mib.serial).AppendLine(); + sb.AppendFormat("Volume label: {0}", + StringHandlers.SpacePaddedToString(mib.volumeLabel, Encoding)) + .AppendLine(); + sb.AppendFormat("Volume comment: {0}", StringHandlers.SpacePaddedToString(mib.comment, Encoding)) + .AppendLine(); + sb.AppendFormat("Volume owner: {0}", StringHandlers.SpacePaddedToString(vib.owner, Encoding)) + .AppendLine(); + sb.AppendFormat("Volume created on {0}", DateHandlers.DosToDateTime(mib.creationDate, mib.creationTime)) + .AppendLine(); + sb.AppendFormat("Volume uses {0} codepage {1}", mib.codepageType > 0 && mib.codepageType < 3 + ? mib.codepageType == 2 + ? "EBCDIC" + : "ASCII" + : "Unknown", mib.codepage).AppendLine(); + sb.AppendFormat("RPS level: {0}", mib.rps).AppendLine(); + sb.AppendFormat("Filesystem version: {0}.{1}", mib.major, mib.minor).AppendLine(); + sb.AppendFormat("Volume can be filled up to {0}%", vib.percentFull).AppendLine(); + + XmlFsType = new FileSystemType + { + Clusters = mib.sectors / bpb.spc, + ClusterSize = bpb.bps * bpb.spc, + CreationDate = DateHandlers.DosToDateTime(mib.creationDate, mib.creationTime), + CreationDateSpecified = true, + DataPreparerIdentifier = StringHandlers.SpacePaddedToString(vib.owner, Encoding), + Type = "HPOFS", + VolumeName = StringHandlers.SpacePaddedToString(mib.volumeLabel, Encoding), + VolumeSerial = $"{mib.serial:X8}", + SystemIdentifier = StringHandlers.SpacePaddedToString(bpb.oem_name) + }; + + information = sb.ToString(); + } + + /// + /// BIOS Parameter Block, at sector 0, little-endian + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct BiosParameterBlock + { + /// 0x000, Jump to boot code + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] jump; + /// 0x003, OEM Name, 8 bytes, space-padded + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] oem_name; + /// 0x00B, Bytes per sector + public ushort bps; + /// 0x00D, Sectors per cluster + public byte spc; + /// 0x00E, Reserved sectors between BPB and... does it have sense in HPFS? + public ushort rsectors; + /// 0x010, Number of FATs... seriously? + public byte fats_no; + /// 0x011, Number of entries on root directory... ok + public ushort root_ent; + /// 0x013, Sectors in volume... doubt it + public ushort sectors; + /// 0x015, Media descriptor + public byte media; + /// 0x016, Sectors per FAT... again + public ushort spfat; + /// 0x018, Sectors per track... you're kidding + public ushort sptrk; + /// 0x01A, Heads... stop! + public ushort heads; + /// 0x01C, Hidden sectors before BPB + public uint hsectors; + /// 0x024, Sectors in volume if > 65535... + public uint big_sectors; + /// 0x028, Drive number + public byte drive_no; + /// 0x029, Volume flags? + public byte nt_flags; + /// 0x02A, EPB signature, 0x29 + public byte signature; + /// 0x02B, Volume serial number + public uint serial_no; + /// 0x02F, Volume label, 11 bytes, space-padded + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public byte[] volume_label; + /// 0x03A, Filesystem type, 8 bytes, space-padded ("HPFS ") + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] fs_type; + /// Boot code. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 442)] + public byte[] boot_code; + /// 0x1F8, Unknown + public uint unknown; + /// 0x1FC, Unknown + public ushort unknown2; + /// 0x1FE, 0xAA55 + public ushort signature2; + } + + /// + /// Media Information Block, at sector 13, big-endian + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct MediaInformationBlock + { + /// Block identifier "MEDINFO " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] blockId; + /// Volume label + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public byte[] volumeLabel; + /// Volume comment + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 160)] + public byte[] comment; + /// Volume serial number + public uint serial; + /// Volume creation date, DOS format + public ushort creationDate; + /// Volume creation time, DOS format + public ushort creationTime; + /// + /// Codepage type: 1 ASCII, 2 EBCDIC + /// + public ushort codepageType; + /// Codepage + public ushort codepage; + /// RPS level + public uint rps; + /// Coincides with bytes per sector, and bytes per cluster, need more media + public ushort bps; + /// Coincides with bytes per sector, and bytes per cluster, need more media + public ushort bpc; + /// Unknown, empty + public uint unknown2; + /// Sectors (or clusters) + public uint sectors; + /// Unknown, coincides with bps but changing it makes nothing + public uint unknown3; + /// Empty? + public ulong unknown4; + /// Format major version + public ushort major; + /// Format minor version + public ushort minor; + /// Empty? + public uint unknown5; + /// Unknown, non-empty + public uint unknown6; + /// Empty + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 260)] + public byte[] filler; + } + + /// + /// Volume Information Block, at sector 14, big-endian + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct VolumeInformationBlock + { + /// Block identifier "VOLINFO " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] blockId; + /// Unknown + public uint unknown; + /// Unknown + public uint unknown2; + /// Unknown + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)] + public byte[] unknown3; + /// Unknown, space-padded string + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public byte[] unknown4; + /// Owner, space-padded string + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public byte[] owner; + /// Unknown, space-padded string + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] unknown5; + /// Unknown, empty? + public uint unknown6; + /// Maximum percent full + public ushort percentFull; + /// Unknown, empty? + public ushort unknown7; + /// Empty + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 384)] + public byte[] filler; + } + } +} \ No newline at end of file diff --git a/DiscImageChef.Tests/DiscImageChef.Tests.csproj b/DiscImageChef.Tests/DiscImageChef.Tests.csproj index 6d343ef8..10efbc40 100644 --- a/DiscImageChef.Tests/DiscImageChef.Tests.csproj +++ b/DiscImageChef.Tests/DiscImageChef.Tests.csproj @@ -52,6 +52,7 @@ + diff --git a/DiscImageChef.Tests/Filesystems/HPOFS.cs b/DiscImageChef.Tests/Filesystems/HPOFS.cs new file mode 100644 index 00000000..19998412 --- /dev/null +++ b/DiscImageChef.Tests/Filesystems/HPOFS.cs @@ -0,0 +1,91 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : HPOFS.cs +// Author(s) : Natalia Portillo +// +// Component : DiscImageChef unit testing. +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2018 Natalia Portillo +// ****************************************************************************/ + +using System.IO; +using DiscImageChef.CommonTypes; +using DiscImageChef.DiscImages; +using DiscImageChef.Filesystems; +using DiscImageChef.Filters; +using NUnit.Framework; + +namespace DiscImageChef.Tests.Filesystems +{ + [TestFixture] + public class Hpofs + { + readonly string[] testfiles = {"rid1.img.lz", "rid10.img.lz", "rid66percent.img.lz", "rid266.img.lz"}; + + readonly MediaType[] mediatypes = + {MediaType.DOS_35_HD, MediaType.DOS_35_HD, MediaType.DOS_35_HD, MediaType.DOS_35_HD}; + + readonly ulong[] sectors = {2880, 2880, 2880, 2880}; + + readonly uint[] sectorsize = {512, 512, 512, 512}; + + readonly long[] clusters = {2880, 2880, 2880, 2880}; + + readonly int[] clustersize = {512, 512, 512, 512}; + + readonly string[] volumename = {"VOLUME LABEL", "VOLUME LABEL", "VOLUME LABEL", "VOLUME LABEL"}; + + readonly string[] volumeserial = {"AC226814", "AC160814", "AC306C14", "ABEF2C14"}; + + readonly string[] oemid = {"IBM 10.2", "IBM 10.2", "IBM 10.2", "IBM 10.2"}; + + [Test] + public void Test() + { + for(int i = 0; i < testfiles.Length; i++) + { + string location = Path.Combine(Consts.TestFilesRoot, "filesystems", "hpofs", testfiles[i]); + IFilter filter = new LZip(); + filter.Open(location); + IMediaImage image = new ZZZRawImage(); + Assert.AreEqual(true, image.Open(filter), testfiles[i]); + Assert.AreEqual(mediatypes[i], image.Info.MediaType, testfiles[i]); + Assert.AreEqual(sectors[i], image.Info.Sectors, testfiles[i]); + Assert.AreEqual(sectorsize[i], image.Info.SectorSize, testfiles[i]); + IFilesystem fs = new HPOFS(); + Partition wholePart = new Partition + { + Name = "Whole device", + Length = image.Info.Sectors, + Size = image.Info.Sectors * image.Info.SectorSize + }; + Assert.AreEqual(true, fs.Identify(image, wholePart), testfiles[i]); + fs.GetInformation(image, wholePart, out _, null); + Assert.AreEqual(clusters[i], fs.XmlFsType.Clusters, testfiles[i]); + Assert.AreEqual(clustersize[i], fs.XmlFsType.ClusterSize, testfiles[i]); + Assert.AreEqual("HPOFS", fs.XmlFsType.Type, testfiles[i]); + Assert.AreEqual(volumename[i], fs.XmlFsType.VolumeName, testfiles[i]); + Assert.AreEqual(volumeserial[i], fs.XmlFsType.VolumeSerial, testfiles[i]); + Assert.AreEqual(oemid[i], fs.XmlFsType.SystemIdentifier, testfiles[i]); + } + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index 704a25bd..93f6d7e5 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,7 @@ Supported file systems for identification and information only * Flash-Friendly File System (F2FS) * Fossil file system (from Plan9) * HAMMER file system +* High Performance Optical File System (HPOFS) * High Sierra Format * HP Logical Interchange Format * IBM Journaling File System (JFS)