From 02b60e20ce49029df3fdc0931f479941e72681d5 Mon Sep 17 00:00:00 2001 From: dwildie Date: Tue, 10 Jan 2023 18:18:36 +1000 Subject: [PATCH] Add support for ST partitions --- pom.xml | 2 +- src/main/java/au/wildie/m68k/App.java | 46 ++++++++++++-- .../m68k/cromixfs/disk/st/CromixStDisk.java | 24 +++++--- .../cromixfs/disk/st/STDCPartitionTable.java | 61 +++++++++++++++++++ .../wildie/m68k/cromixfs/fs/FileSystems.java | 4 +- .../wildie/m68k/cromixfs/fs/cromix/Inode.java | 17 +++--- src/test/java/au/wildie/m68k/AppTest.java | 10 +++ .../cromixfs/disk/st/CromixStDiskTest.java | 17 +++--- 8 files changed, 149 insertions(+), 32 deletions(-) create mode 100644 src/main/java/au/wildie/m68k/cromixfs/disk/st/STDCPartitionTable.java diff --git a/pom.xml b/pom.xml index bb63332..72c6bee 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ au.wildie.m68k cromix-fs - 2.6 + 2.7 cromix-fs diff --git a/src/main/java/au/wildie/m68k/App.java b/src/main/java/au/wildie/m68k/App.java index eb5f2e1..3a75084 100644 --- a/src/main/java/au/wildie/m68k/App.java +++ b/src/main/java/au/wildie/m68k/App.java @@ -34,6 +34,15 @@ public static void main(String[] args ) throws IOException, STDiskException, Inv } get(args[1]).list(System.out); return; + } else if (args.length == 4 && args[0].equalsIgnoreCase("-l") && args[1].equalsIgnoreCase("-p")) { + // List partition files + if (!new File(args[3]).exists()) { + System.out.printf("Cannot open image file %s\n", args[3]); + return; + } + int partitionIndex = Integer.parseInt(args[2]); + get(args[3], partitionIndex).list(System.out); + return; } else if (args.length == 2 && args[0].equalsIgnoreCase("-c")) { // Check filesystem if (!new File(args[1]).exists()) { @@ -45,6 +54,18 @@ public static void main(String[] args ) throws IOException, STDiskException, Inv ((CromixFileSystem)fs).check(System.out); } return; + } else if (args.length == 4 && args[0].equalsIgnoreCase("-c") && args[1].equalsIgnoreCase("-p")) { + // Check filesystem + if (!new File(args[3]).exists()) { + System.out.printf("Cannot open image file %s\n", args[3]); + return; + } + int partitionIndex = Integer.parseInt(args[2]); + FileSystemOps fs = get(args[3], partitionIndex); + if (fs instanceof CromixFileSystem) { + ((CromixFileSystem)fs).check(System.out); + } + return; } else if (args.length == 2 && args[0].equalsIgnoreCase("-di")) { // Dump inodes if (!new File(args[1]).exists()) { @@ -68,6 +89,19 @@ public static void main(String[] args ) throws IOException, STDiskException, Inv } get(args[1]).extract(args[2], System.out); return; + } else if (args.length == 5 && args[0].equalsIgnoreCase("-x") && args[1].equalsIgnoreCase("-p")) { + // Extract files + if (!new File(args[3]).exists()) { + System.out.printf("Cannot open image file %s\n", args[3]); + return; + } + File target = new File(args[4]); + if (!target.exists()) { + target.mkdirs(); + } + int partitionIndex = Integer.parseInt(args[2]); + get(args[3], partitionIndex).extract(args[4], System.out); + return; } else if (args.length == 3 && args[0].equalsIgnoreCase("-f")) { // Create new ftar image if (!new File(args[2]).exists()) { @@ -157,6 +191,10 @@ public static void main(String[] args ) throws IOException, STDiskException, Inv } private static FileSystemOps get(String filename) throws IOException, InvalidVFDImageException, STDiskException { + return get(filename, null); + } + + private static FileSystemOps get(String filename, Integer partitionIndex) throws IOException, InvalidVFDImageException, STDiskException { FileSystemOps fs; if (filename.toLowerCase().trim().endsWith(".imd")) { fs = FileSystems.getIMDFloppyFileSystem(filename, System.out); @@ -165,7 +203,7 @@ private static FileSystemOps get(String filename) throws IOException, InvalidVFD } else if (filename.toLowerCase().trim().endsWith(".hfe")) { fs = FileSystems.getHFEFloppyFileSystem(filename, System.out); } else { - fs = FileSystems.getSTFileSystem(filename, System.out); + fs = FileSystems.getSTFileSystem(filename, partitionIndex, System.out); } return fs; } @@ -176,16 +214,16 @@ private static void showUsage() { String jarName = getJarName(); System.out.print("\nCheck a cromix image:\n"); - System.out.printf(" java -jar %s -c file.imd\n", jarName); + System.out.printf(" java -jar %s -c [-p partitionIndex] file.imd|file.img\n", jarName); System.out.print("\nDump cromix inodes:\n"); System.out.printf(" java -jar %s -di file.imd\n", jarName); System.out.print("\nList files in an image:\n"); - System.out.printf(" java -jar %s -l file.imd\n", jarName); + System.out.printf(" java -jar %s -l [-p partitionIndex] file.imd|file.img\n", jarName); System.out.print("\nExtract files from an image to path:\n"); - System.out.printf(" java -jar %s -x file.imd path\n", jarName); + System.out.printf(" java -jar %s -x [-p partitionIndex] file.imd|file.img path\n", jarName); System.out.print("\nCreate a new Cromix ftar image containing files from path:\n"); System.out.printf(" java -jar %s -f file.imd path\n", jarName); diff --git a/src/main/java/au/wildie/m68k/cromixfs/disk/st/CromixStDisk.java b/src/main/java/au/wildie/m68k/cromixfs/disk/st/CromixStDisk.java index c028e21..f440235 100644 --- a/src/main/java/au/wildie/m68k/cromixfs/disk/st/CromixStDisk.java +++ b/src/main/java/au/wildie/m68k/cromixfs/disk/st/CromixStDisk.java @@ -2,8 +2,11 @@ import au.wildie.m68k.cromixfs.disk.DiskInterface; import au.wildie.m68k.cromixfs.fs.cromix.CromixFileSystem; +import lombok.Getter; +import lombok.Setter; import java.io.*; +import java.util.Optional; public class CromixStDisk implements DiskInterface { private static final int SECTOR_SIZE = 512; // Disks are always 512 byte sectors @@ -11,7 +14,14 @@ public class CromixStDisk implements DiskInterface { private final byte[][][][] media; private final STDCDiskInfo info; - public CromixStDisk(String fileName) throws STDiskException { + @Getter + private final STDCPartitionTable partitionTable; + +// @Setter + @Getter + private int currentPartition = 0; + + public CromixStDisk(String fileName, Integer partitionIndex) throws STDiskException { byte[] sector = new byte[SECTOR_SIZE]; try (InputStream in = new FileInputStream(fileName)) { @@ -48,8 +58,10 @@ public CromixStDisk(String fileName) throws STDiskException { } catch (IOException e) { throw new STDiskException(String.format("Error reading disk image file \"%s\"\n", fileName), e); } - } + partitionTable = new STDCPartitionTable(info, media); + currentPartition = Optional.ofNullable(partitionIndex).orElse(0); + } public void list(PrintStream out) throws IOException { new CromixFileSystem(this).list(out); @@ -60,7 +72,6 @@ public void extract(String path, PrintStream out) throws IOException { new CromixFileSystem(this).extract(path, out); } - public void check(PrintStream out) throws IOException { new CromixFileSystem(this).check(out); } @@ -77,10 +88,7 @@ public void flushSuperBlock(byte[] data) { @Override public byte[] getBlock(int block) { - if (block == 0x0095) { - System.out.print("stop"); - } - int c = getCylinderForBlock(0, block); + int c = getCylinderForBlock(this.currentPartition, block); int h = getHeadForBlock(block); int s = getSectorForBlock(block); return media[c][h][s]; @@ -121,7 +129,7 @@ private int getCylinderForBlock(int unit, int block) { } private int getStartingCylinder(int unit) { - return 1; // Changes when partition table is present + return partitionTable.getStartCylinder(unit).orElse(1); } private int getHeadForBlock(int block) { diff --git a/src/main/java/au/wildie/m68k/cromixfs/disk/st/STDCPartitionTable.java b/src/main/java/au/wildie/m68k/cromixfs/disk/st/STDCPartitionTable.java new file mode 100644 index 0000000..04855e5 --- /dev/null +++ b/src/main/java/au/wildie/m68k/cromixfs/disk/st/STDCPartitionTable.java @@ -0,0 +1,61 @@ +package au.wildie.m68k.cromixfs.disk.st; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import java.io.PrintStream; +import java.util.Optional; + +public class STDCPartitionTable { + public static final int TABLE_SIZE = 32; + private final STDCDiskInfo info; + private final Entry[] table = new Entry[TABLE_SIZE]; + + public STDCPartitionTable(STDCDiskInfo info, byte[][][][] media) { + this(info, media[0][0][info.getStartOfPartitionTable() / info.getBytesPerSector()]); + } + + public STDCPartitionTable(STDCDiskInfo info, byte[] sector) { + this.info = info; + + table[0] = new Entry(1, info.getCylinderCount() - 1); + table[TABLE_SIZE - 1] = new Entry(0, info.getCylinderCount()); + + for (int i = 0 ; i < TABLE_SIZE; i++) { + int startCylinder = ((0xFF & sector[i * 2]) << 8) + (0xFF & sector[i * 2 + 1]); + if (startCylinder == 0xe5e5) { + break; + } + table[i + 1] = new Entry(startCylinder, info.getCylinderCount() - startCylinder); + table[i].numberOfCylinders = startCylinder - table[i].startCylinder; + } + } + + public Optional getStartCylinder(int partitionIndex) { + return Optional.ofNullable(table[partitionIndex]).map(Entry::getStartCylinder); + } + + @ToString + @Getter + @AllArgsConstructor + @NoArgsConstructor + public static final class Entry { + private int startCylinder; + private int numberOfCylinders; + } + + public void logTable(PrintStream out) { + out.println("Partition # Starting Cylinder Number of cylinders Size (Kbytes)"); + for (int i = 0; i < TABLE_SIZE; i++) { + if (table[i] != null) { + out.printf(" %2d %5d %5d %,10d \n", + i, + table[i].startCylinder, + table[i].numberOfCylinders, + (table[i].numberOfCylinders * info.getSurfaceCount() * info.getSectorsPerTrack() * info.getBytesPerSector()) / 1024); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/au/wildie/m68k/cromixfs/fs/FileSystems.java b/src/main/java/au/wildie/m68k/cromixfs/fs/FileSystems.java index c2d63f6..2d48c76 100644 --- a/src/main/java/au/wildie/m68k/cromixfs/fs/FileSystems.java +++ b/src/main/java/au/wildie/m68k/cromixfs/fs/FileSystems.java @@ -121,7 +121,7 @@ protected static FileSystem getVFDFloppyFileSystem(VFDImage image, PrintStream o throw new VFDFloppyException(String.format("Unrecognised disk, format label: \"%s\"", formatLabel)); } - public static FileSystem getSTFileSystem(String fileName, PrintStream out) throws STDiskException, IOException { - return new CromixFileSystem(new CromixStDisk(fileName)); + public static FileSystem getSTFileSystem(String fileName, Integer partitionIndex, PrintStream out) throws STDiskException, IOException { + return new CromixFileSystem(new CromixStDisk(fileName, partitionIndex)); } } diff --git a/src/main/java/au/wildie/m68k/cromixfs/fs/cromix/Inode.java b/src/main/java/au/wildie/m68k/cromixfs/fs/cromix/Inode.java index 5e5ac69..3cd2f27 100644 --- a/src/main/java/au/wildie/m68k/cromixfs/fs/cromix/Inode.java +++ b/src/main/java/au/wildie/m68k/cromixfs/fs/cromix/Inode.java @@ -1,19 +1,18 @@ package au.wildie.m68k.cromixfs.fs.cromix; -import static au.wildie.m68k.cromixfs.fs.CromixTime.TIME_SIZE; -import static au.wildie.m68k.cromixfs.fs.cromix.InodeType.*; -import static au.wildie.m68k.cromixfs.fs.cromix.PointerBlock.BLOCK_POINTER_COUNT; -import static au.wildie.m68k.cromixfs.utils.BinUtils.*; +import au.wildie.m68k.cromixfs.disk.DiskInterface; +import au.wildie.m68k.cromixfs.fs.CromixTime; +import lombok.Getter; +import lombok.Setter; -import java.io.IOException; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; -import au.wildie.m68k.cromixfs.disk.DiskInterface; -import au.wildie.m68k.cromixfs.fs.CromixTime; -import lombok.Getter; -import lombok.Setter; +import static au.wildie.m68k.cromixfs.fs.CromixTime.TIME_SIZE; +import static au.wildie.m68k.cromixfs.fs.cromix.InodeType.*; +import static au.wildie.m68k.cromixfs.fs.cromix.PointerBlock.BLOCK_POINTER_COUNT; +import static au.wildie.m68k.cromixfs.utils.BinUtils.*; @Getter @Setter diff --git a/src/test/java/au/wildie/m68k/AppTest.java b/src/test/java/au/wildie/m68k/AppTest.java index d6ae6c0..1914605 100644 --- a/src/test/java/au/wildie/m68k/AppTest.java +++ b/src/test/java/au/wildie/m68k/AppTest.java @@ -45,6 +45,16 @@ public void testCreateSmall() throws InvalidVFDImageException, STDiskException, App.main(new String[]{"-ms", "/tmp/5se.IMD"}); } + @Test + public void testListPartition() throws InvalidVFDImageException, STDiskException, IOException { + App.main(new String[]{"-l", "-p", "7", "/home/dwildie/mfm/20220705.D45.C1536.H16.master.img"}); + } + + @Test + public void testCheckPartition() throws InvalidVFDImageException, STDiskException, IOException { + App.main(new String[]{"-c", "-p", "0", "/home/dwildie/mfm/20220705.D45.C1536.H16.master.img"}); + } + @Test public void testListSmall() throws InvalidVFDImageException, STDiskException, IOException { App.main(new String[]{"-l", "/tmp/5s.IMD"}); diff --git a/src/test/java/au/wildie/m68k/cromixfs/disk/st/CromixStDiskTest.java b/src/test/java/au/wildie/m68k/cromixfs/disk/st/CromixStDiskTest.java index bf047f2..c3b840f 100644 --- a/src/test/java/au/wildie/m68k/cromixfs/disk/st/CromixStDiskTest.java +++ b/src/test/java/au/wildie/m68k/cromixfs/disk/st/CromixStDiskTest.java @@ -14,7 +14,7 @@ public class CromixStDiskTest { // private static final String LIST_FILE = "/home/dwildie/m68000/cromix/disk0_848.list"; // private static final String EXTRACT_PATH = "/home/dwildie/m68000/cromix/disk0_848.dump"; - private static final String IMG_FILE = "/home/dwildie/ide/idecromix.img"; + private static final String IMG_FILE = "/home/dwildie/mfm/20220705.D45.C1536.H16.master.img"; // private static final String LIST_FILE = "/home/dwildie/ide/idecromix.list"; // private static final String EXTRACT_PATH = "/home/dwildie/ide/idecromix.dump"; @@ -26,11 +26,12 @@ public void list() throws IOException, STDiskException { throw new IllegalArgumentException(String.format("Image file %s does not exist", IMG_FILE)); } - String listFile = String.format("%s.%s", FilenameUtils.removeExtension(IMG_FILE), "list"); - try (FileOutputStream out = new FileOutputStream(listFile)) { - CromixStDisk stDisk = new CromixStDisk(IMG_FILE); - stDisk.list(new PrintStream(out)); - } +// String listFile = String.format("%s.%s", FilenameUtils.removeExtension(IMG_FILE), "list"); +// try (FileOutputStream out = new FileOutputStream(listFile)) { + CromixStDisk stDisk = new CromixStDisk(IMG_FILE, 7); + stDisk.getPartitionTable().logTable(new PrintStream(System.out)); + stDisk.list(new PrintStream(System.out)); +// } System.out.println("done"); } @@ -50,7 +51,7 @@ public void extract() throws IOException, STDiskException { } extractDir.mkdirs(); - CromixStDisk stDisk = new CromixStDisk(IMG_FILE); + CromixStDisk stDisk = new CromixStDisk(IMG_FILE, 0); stDisk.extract(extractPath, System.out); System.out.println("done"); } @@ -63,7 +64,7 @@ public void check() throws IOException, STDiskException { throw new IllegalArgumentException(String.format("Image file %s does not exist", IMG_FILE)); } - CromixStDisk stDisk = new CromixStDisk(IMG_FILE); + CromixStDisk stDisk = new CromixStDisk(IMG_FILE, null); stDisk.check(System.out); System.out.println("done");