Skip to content

Commit

Permalink
Fix issues with reading damaged disks
Browse files Browse the repository at this point in the history
  • Loading branch information
dwildie committed Jun 22, 2021
1 parent 48aa801 commit 946e69a
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import au.wildie.m68k.cromixfs.disk.DiskInterface;
import au.wildie.m68k.cromixfs.disk.floppy.cromix.CromixFloppyInfo;
import au.wildie.m68k.cromixfs.disk.imd.IMDImage;
import au.wildie.m68k.cromixfs.disk.imd.IMDSector;
import au.wildie.m68k.cromixfs.disk.imd.IMDTrack;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;

import java.io.*;

Expand All @@ -15,10 +17,42 @@ public abstract class IMDFloppyImage implements DiskInterface {

public IMDFloppyImage(IMDImage image, PrintStream out) {
this.image = image;
this.formatLabel = CromixFloppyInfo.getFormatLabel(image.getSector(0,0,1).getData());
this.formatLabel = obtainFormatLabel();
this.out = out;
}

protected String obtainFormatLabel() {
IMDSector zero = image.getSector(0,0,1);
if (IMDImage.isValidEncoding(zero)) {
String formatLabel = CromixFloppyInfo.getFormatLabel(zero.getData());
if (StringUtils.isNotBlank(formatLabel)) {
return formatLabel;
}
}

// Sector is not available or no label, generate label from disk params
if (image.getTrack(0, 0).getSectorSize() == image.getTrack(0, 1).getSectorSize()) {
// Is uniform
return "";
}

String guess = "C";
if (image.getCylinders() == 77) {
// Large
guess += "L";
guess += image.getHeads() == 2 ? "DS" : "SS";
guess += image.getTrack(0, 1).getSectorCount() == 16 ? "DD" : "SD";
} else {
// Small
guess += "S";
guess += image.getHeads() == 2 ? "DS" : "SS";
guess += image.getTrack(0, 1).getSectorCount() == 10 ? "DD" : "SD";
}
guess += "?";

return guess;
}

@Override
public void writeImage(File file, boolean interleaved) throws IOException {
out.printf("Writing image to %s\n\n", file.getPath());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public class CromixFloppyInfo {
public static CromixFloppyInfo SMALL_SINGLE_DENSITY = new CromixFloppyInfo(40, 2, 5, 18, 512, 128, 13, x5s);

public static String getFormatLabel(byte[] sector) {
return new String(Arrays.copyOfRange(sector, LABEL_START, LABEL_END)).replaceAll("\\P{InBasic_Latin}", "").trim();
return new String(Arrays.copyOfRange(sector, LABEL_START, LABEL_END)).replaceAll("\\P{InBasic_Latin}", " ").trim();
}

public static void setFormatLabel(String formatLabel, byte[] sector) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import au.wildie.m68k.cromixfs.disk.imd.IMDImage;
import au.wildie.m68k.cromixfs.disk.imd.IMDSector;
import au.wildie.m68k.cromixfs.disk.imd.IMDTrack;
import org.apache.commons.lang3.StringUtils;

import java.io.*;

Expand All @@ -22,7 +23,7 @@ public CromixIMDFloppyDisk(IMDImage image, PrintStream out) {
uniform = true;
info = CromixFloppyInfo.getUniform(image.getCylinders(), image.getHeads(), image.getTrack(0, 0).getSectorCount(), track0SectorSize);
} else {
if (getFormatLabel().charAt(0) != 'C') {
if (StringUtils.isBlank(super.getFormatLabel()) || super.getFormatLabel().charAt(0) != 'C') {
throw new IMDFloppyException("Not a cromix disk");
}

Expand Down
37 changes: 36 additions & 1 deletion src/main/java/au/wildie/m68k/cromixfs/disk/imd/IMDImage.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class IMDImage extends DiskImage {
public static final int SECTOR_ENCODING_ERROR_COMPRESSED = 6;
public static final int SECTOR_ENCODING_DELETED_ERROR = 7;
public static final int SECTOR_ENCODING_DELETED_ERROR_COMPRESSED = 8;
public static final int SECTOR_ENCODING_UNKNOWN = 9;

private static final Set<Integer> SECTOR_ENCODING_VALID = new HashSet<>(Arrays.asList(
SECTOR_ENCODING_NORMAL,
Expand Down Expand Up @@ -203,6 +204,7 @@ public IMDImage(byte[] raw, PrintStream out) {

out.println(header);
out.printf("Read %d tracks%n", tracks.size());
out.printf("%n%s%n", getSectorErrorSummary());
}

public int size() {
Expand Down Expand Up @@ -354,6 +356,10 @@ public int getCylinders() {
return cylinders;
}

public static boolean isValidEncoding(IMDSector sector) {
return SECTOR_ENCODING_VALID.contains(sector.getEncoding());
}

public Integer getTrackCount(int head) {
return new Long(tracks.stream()
.filter(track -> track.getHead() == head)
Expand All @@ -363,10 +369,39 @@ public Integer getTrackCount(int head) {
public Integer getSectorErrorCount() {
return (int)tracks.stream()
.flatMap(track -> track.getSectors().stream())
.filter(sector -> !SECTOR_ENCODING_VALID.contains(sector.getEncoding()))
.filter(sector -> !isValidEncoding(sector))
.count();
}

public String getSectorErrorSummary() {
Integer[] counts = new Integer[]{0,0,0,0,0,0,0,0,0,0};
tracks.stream()
.flatMap(track -> track.getSectors().stream())
.filter(sector -> !isValidEncoding(sector))
.map(IMDSector::getEncoding)
.map(encoding -> encoding >= SECTOR_ENCODING_UNKNOWN ? SECTOR_ENCODING_UNKNOWN : encoding)
.forEach(encoding -> counts[encoding]++);

StringBuilder summary = new StringBuilder();
if (counts[SECTOR_ENCODING_UNAVAILABLE] > 0) {
summary.append(String.format(" Unavailable: %d\n", counts[SECTOR_ENCODING_UNAVAILABLE]));
}
if (counts[SECTOR_ENCODING_ERROR] > 0 || counts[SECTOR_ENCODING_ERROR_COMPRESSED] > 0) {
summary.append(String.format(" Errors: %d\n", counts[SECTOR_ENCODING_ERROR] + counts[SECTOR_ENCODING_ERROR_COMPRESSED]));

}
if (counts[SECTOR_ENCODING_DELETED_ERROR] > 0 || counts[SECTOR_ENCODING_DELETED_ERROR_COMPRESSED] > 0) {
summary.append(String.format(" Deleted Errors: %d\n", counts[SECTOR_ENCODING_DELETED_ERROR] + counts[SECTOR_ENCODING_DELETED_ERROR_COMPRESSED]));
}

if (summary.length() == 0) {
return "No sector errors";
}

summary.insert(0, "Sector errors:\n");
return summary.toString();
}

public void verify(PrintStream out) {

// Check for missing sectors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public class CromixFileSystem implements FileSystem {
@Getter
private final DiskInterface disk;

private final int versionMinor;
private final int versionMajor;
private final int inodeFirst;
private final int inodeCount;
private final int blockCount;
Expand Down Expand Up @@ -94,6 +96,8 @@ public CromixFileSystem(DiskInterface disk) throws IOException {
throw new CromixFileSystemException("Not a valid cromix filesystem");
}

versionMajor = superBlock[SUPER_VERSION_OFFSET];
versionMinor = superBlock[SUPER_VERSION_OFFSET + 1];
inodeFirst = readWord(superBlock, SUPER_INODE_FIRST_OFFSET);
inodeCount = readWord(superBlock, SUPER_INODE_COUNT_OFFSET);
blockCount = readDWord(superBlock, SUPER_BLOCK_COUNT_OFFSET);
Expand Down
10 changes: 7 additions & 3 deletions src/main/java/au/wildie/m68k/cromixfs/fs/FileSystems.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,13 @@ public static FileSystemOps getIMDFloppyFileSystem(IMDImage image, PrintStream o
}

// Could be uniform or ftar
DiskInterface disk = new CromixIMDFloppyDisk(image, out);
if (CromixFileSystem.isValid(disk)) {
return new CromixFileSystem(disk);
try {
DiskInterface disk = new CromixIMDFloppyDisk(image, out);
if (CromixFileSystem.isValid(disk)) {
return new CromixFileSystem(disk);
}
} catch (IMDFloppyException ignored) {
// swallow it
}

CromixFtar ftar = new CromixFtar(new FTarIMDDisk(image, out));
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/au/wildie/m68k/cromixfs/ftar/FTarDisk.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public FTarDisk(DiskImage image, FTarTrackInfo track0, FTarTrackInfo track1, Pri
formatLabel += image.getHeads() == 2 ? "DS" : "SS";
formatLabel += trackInfo[1].getSectorCount() == 10 ? "DD" : "SD";
}
formatLabel += "!";
formatLabel += "?";
}

initialBlockNumber = 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class CromixIMDFloppyDiskTest {
private static final String CLDSDD_IMAGE = "imd/848CR162.IMD";
private static final String UNIFORM_IMAGE = "imd/904C3140.IMD";
private static final String UNIFORM1_IMAGE = "imd/152C0241.IMD";
private static final String DAMAGED_FS_IMAGE = "imd/720CX172.IMD";

private static final String EXTRACT_PATH = "/tmp/extract";

Expand All @@ -31,24 +32,32 @@ public void scan() throws IOException {

@Test
public void writeImage() throws IOException {
InputStream src = this.getClass().getClassLoader().getResourceAsStream(CLDSDD_IMAGE);
InputStream src = getClass().getClassLoader().getResourceAsStream(CLDSDD_IMAGE);
FileSystem fs = (FileSystem)FileSystems.getIMDFloppyFileSystem(src, System.out);
File out = Paths.get(System.getProperty("java.io.tmpdir"), String.format("%s.%s", FilenameUtils.removeExtension(CLDSDD_IMAGE), "img")).toFile();
((DiskInterface)fs.getDisk()).writeImage(out, true);
System.out.println("done");
}

@Test
public void listDamaged() throws IOException {
InputStream src = getClass().getClassLoader().getResourceAsStream(DAMAGED_FS_IMAGE);
FileSystem fs = (FileSystem)FileSystems.getIMDFloppyFileSystem(src, System.out);
fs.list(System.out);
System.out.println("done");
}

@Test
public void listCLDSDD() throws IOException {
InputStream src = this.getClass().getClassLoader().getResourceAsStream(CLDSDD_IMAGE);
InputStream src = getClass().getClassLoader().getResourceAsStream(CLDSDD_IMAGE);
FileSystem fs = (FileSystem)FileSystems.getIMDFloppyFileSystem(src, System.out);
fs.list(System.out);
System.out.println("done");
}

@Test
public void listUniform() throws IOException {
InputStream src = this.getClass().getClassLoader().getResourceAsStream(UNIFORM1_IMAGE);
InputStream src = getClass().getClassLoader().getResourceAsStream(UNIFORM1_IMAGE);
FileSystem fs = (FileSystem)FileSystems.getIMDFloppyFileSystem(src, System.out);
fs.list(System.out);
System.out.println("done");
Expand Down
9 changes: 9 additions & 0 deletions src/test/java/au/wildie/m68k/cromixfs/fs/FileSystemsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class FileSystemsTest extends CromemcoTest {
private static final String CLDSDD_FTAR_IMAGE = "imd/093CR151.IMD";
private static final String CLDSDD_FS_IMAGE = "imd/094CR162.IMD";
private static final String UNIFORM_FS_IMAGE = "imd/904C3140.IMD";
private static final String DAMAGED_FS_IMAGE = "imd/720CX172.IMD";

@Test
public void getIMDFloppyFileSystem_ftar() throws IOException {
Expand All @@ -24,6 +25,14 @@ public void getIMDFloppyFileSystem_ftar() throws IOException {
assertThat(fs, instanceOf(CromixFtar.class));
}

@Test
public void getIMDFloppyFileSystem_damaged() throws IOException {
InputStream src = getClass().getClassLoader().getResourceAsStream(DAMAGED_FS_IMAGE);
FileSystemOps fs = FileSystems.getIMDFloppyFileSystem(src, getDummyPrintStream());
assertThat(fs, notNullValue());
assertThat(fs, instanceOf(CromixFileSystem.class));
}

@Test
public void getIMDFloppyFileSystem_fs() throws IOException {
InputStream src = getClass().getClassLoader().getResourceAsStream(CLDSDD_FS_IMAGE);
Expand Down
Binary file added src/test/resources/imd/720CX172.IMD
Binary file not shown.

0 comments on commit 946e69a

Please sign in to comment.