Got all the bugs out of the directory handling and also removed a lot of bugs and side-effects through code refactoring

This commit is contained in:
Brendan Robert 2015-12-28 20:58:48 -06:00
parent 59ab31f433
commit 8bcf3a922a
6 changed files with 81 additions and 74 deletions

View File

@ -37,21 +37,23 @@ public class DirectoryNode extends DiskNode implements FileFilter {
// public static int FILE_ENTRY_SIZE = 38;
public static int FILE_ENTRY_SIZE = 0x027;
public DirectoryNode(ProdosVirtualDisk ownerFilesystem, File physicalDir, int baseBlock) throws IOException {
setBaseBlock(baseBlock);
init(ownerFilesystem, physicalDir);
private boolean isRoot;
public DirectoryNode(ProdosVirtualDisk ownerFilesystem, File physicalDir, int baseBlock, boolean root) throws IOException {
super(ownerFilesystem, baseBlock);
init(ownerFilesystem, physicalDir, root);
}
public DirectoryNode(ProdosVirtualDisk ownerFilesystem, File physicalDir) throws IOException {
init(ownerFilesystem, physicalDir);
public DirectoryNode(ProdosVirtualDisk ownerFilesystem, File physicalDir, boolean root) throws IOException {
super(ownerFilesystem);
init(ownerFilesystem, physicalDir, root);
}
private void init(ProdosVirtualDisk ownerFilesystem, File physicalFile) throws IOException {
private void init(ProdosVirtualDisk ownerFilesystem, File physicalFile, boolean root) throws IOException {
isRoot = root;
setPhysicalFile(physicalFile);
setType(EntryType.SUBDIRECTORY);
setName(physicalFile.getName());
setOwnerFilesystem(ownerFilesystem);
}
@Override
@ -59,15 +61,15 @@ public class DirectoryNode extends DiskNode implements FileFilter {
}
@Override
public void doAllocate() {
public void doAllocate() throws IOException {
File[] files = physicalFile.listFiles(this);
int numEntries = files.length;
int numBlocks = 1;
// First block has 12 entries, subsequent blocks have 13 entries
if (numEntries > 12) {
numBlocks += (numEntries - 12) / 13;
int numBlocks = 1 + numEntries / 13;
for (int i=1; i < numBlocks; i++) {
new SubNode(i, this, getOwnerFilesystem().getNextFreeBlock());
}
for (File f : files) {
addFile(f);
}
@ -126,6 +128,7 @@ public class DirectoryNode extends DiskNode implements FileFilter {
generateFileEntry(buffer, 4 + (i + 1) * FILE_ENTRY_SIZE, i);
}
} else {
generatePointers(buffer, additionalNodes.get(block-1).getBaseBlock(), block < (additionalNodes.size()-1) ? additionalNodes.get(block+1).getBaseBlock() : 0);
int start = (block * 13) - 1;
int end = start + 13;
int offset = 4;
@ -150,6 +153,13 @@ public class DirectoryNode extends DiskNode implements FileFilter {
return !file.isHidden();
}
private void generatePointers(byte[] buffer, int prevBlock, int nextBlock) {
// Previous block = 0
generateWord(buffer, 0, prevBlock);
// Next block
generateWord(buffer, 0x02, nextBlock);
}
/**
* Generate the directory header found in the base block of a directory
*
@ -157,21 +167,17 @@ public class DirectoryNode extends DiskNode implements FileFilter {
*/
@SuppressWarnings("static-access")
private void generateHeader(byte[] buffer) {
// Previous block = 0
generateWord(buffer, 0, 0);
// Next block
int nextBlock = 0;
if (!additionalNodes.isEmpty()) {
nextBlock = additionalNodes.get(0).baseBlock;
}
generateWord(buffer, 0x02, nextBlock);
generatePointers(buffer, 0, additionalNodes.size()>1 ? additionalNodes.get(1).getBaseBlock() : 0);
// Directory header + name length
// Volumme header = 0x0f0; Subdirectory header = 0x0e0
buffer[4] = (byte) ((baseBlock == 0x02 ? 0x0f0 : 0x0E0) + getName().length());
buffer[4] = (byte) ((isRoot ? 0x0F0 : 0x0E0) | getName().length());
generateName(buffer, 5, this);
for (int i = 0x014; i <= 0x01b; i++) {
buffer[i] = 0;
}
if (!isRoot) {
buffer[0x014] = 0x075;
}
generateTimestamp(buffer, 0x01c, getPhysicalFile().lastModified());
// Prodos 1.9
buffer[0x020] = 0x019;
@ -185,10 +191,17 @@ public class DirectoryNode extends DiskNode implements FileFilter {
buffer[0x024] = (byte) 0x0d;
// Directory items count
generateWord(buffer, 0x025, children.size());
// Volume bitmap pointer
generateWord(buffer, 0x027, ownerFilesystem.freespaceBitmap.baseBlock);
// Total number of blocks
generateWord(buffer, 0x029, ownerFilesystem.MAX_BLOCK);
if (isRoot) {
// Volume bitmap pointer
generateWord(buffer, 0x027, ownerFilesystem.freespaceBitmap.getBaseBlock());
// Total number of blocks
generateWord(buffer, 0x029, ownerFilesystem.MAX_BLOCK);
} else {
// Parent pointer
generateWord(buffer, 0x027, getParent().getBaseBlock());
buffer[0x029] = (byte) (getParent().getChildren().indexOf(this) + 1);
buffer[0x02a] = 0x027;
}
}
/**
@ -200,7 +213,6 @@ public class DirectoryNode extends DiskNode implements FileFilter {
*/
private void generateFileEntry(byte[] buffer, int offset, int fileNumber) throws IOException {
DiskNode child = children.get(fileNumber);
child.allocate();
// Entry Type and length
buffer[offset] = (byte) ((child.getType().code << 4) + child.getName().length());
// Name
@ -261,7 +273,7 @@ public class DirectoryNode extends DiskNode implements FileFilter {
private void addFile(File file) {
try {
if (file.isDirectory()) {
addChild(new DirectoryNode(getOwnerFilesystem(), file));
addChild(new DirectoryNode(getOwnerFilesystem(), file, false));
} else {
addChild(new FileNode(getOwnerFilesystem(), file));
}

View File

@ -33,7 +33,6 @@ import java.util.List;
public abstract class DiskNode {
public enum EntryType {
DELETED(0),
SEEDLING(1),
SAPLING(2),
@ -50,7 +49,7 @@ public abstract class DiskNode {
boolean allocated = false;
long allocationTime = -1L;
long lastCheckTime = -1L;
int baseBlock = -1;
private int baseBlock = -1;
List<DiskNode> additionalNodes;
ProdosVirtualDisk ownerFilesystem;
File physicalFile;
@ -59,13 +58,23 @@ public abstract class DiskNode {
private EntryType type;
private String name;
public DiskNode() {
public DiskNode(ProdosVirtualDisk fs) throws IOException {
init(fs);
setBaseBlock(fs.getNextFreeBlock());
}
public DiskNode(ProdosVirtualDisk fs, int blockNumber) throws IOException {
init(fs);
setBaseBlock(blockNumber);
}
private void init(ProdosVirtualDisk fs) throws IOException {
additionalNodes = new ArrayList<>();
children = new ArrayList<>();
setOwnerFilesystem(fs);
}
public boolean checkFile() throws IOException {
allocate();
if (physicalFile == null) {
return false;
}
@ -80,9 +89,9 @@ public abstract class DiskNode {
public void allocate() throws IOException {
if (!allocated) {
doAllocate();
getOwnerFilesystem().physicalMap.put(baseBlock, this);
allocationTime = System.currentTimeMillis();
allocated = true;
ownerFilesystem.allocateEntry(this);
}
}
@ -101,11 +110,9 @@ public abstract class DiskNode {
}
public void refresh() throws IOException {
ownerFilesystem.deallocateEntry(this);
deallocate();
doRefresh();
allocationTime = System.currentTimeMillis();
allocated = true;
ownerFilesystem.allocateEntry(this);
allocate();
}
/**
@ -139,8 +146,9 @@ public abstract class DiskNode {
/**
* @param baseBlock the baseBlock to set
*/
public void setBaseBlock(int baseBlock) {
private void setBaseBlock(int baseBlock) {
this.baseBlock = baseBlock;
ownerFilesystem.physicalMap.put(baseBlock, this);
}
/**
@ -154,12 +162,8 @@ public abstract class DiskNode {
* @param ownerFilesystem the ownerFilesystem to set
* @throws IOException
*/
public void setOwnerFilesystem(ProdosVirtualDisk ownerFilesystem) throws IOException {
private void setOwnerFilesystem(ProdosVirtualDisk ownerFilesystem) throws IOException {
this.ownerFilesystem = ownerFilesystem;
if (baseBlock == -1) {
setBaseBlock(ownerFilesystem.getNextFreeBlock());
}
ownerFilesystem.allocateEntry(this);
}
/**
@ -206,6 +210,7 @@ public abstract class DiskNode {
}
public void addChild(DiskNode child) {
child.setParent(this);
children.add(child);
}

View File

@ -125,7 +125,7 @@ public class FileNode extends DiskNode {
}
public FileNode(ProdosVirtualDisk ownerFilesystem, File file) throws IOException {
setOwnerFilesystem(ownerFilesystem);
super(ownerFilesystem);
setPhysicalFile(file);
setName(file.getName());
}
@ -141,10 +141,9 @@ public class FileNode extends DiskNode {
if (treeBlocks > 1) {
treeBlocks++;
}
for (int i = 0; i < dataBlocks + treeBlocks; i++) {
for (int i = 1; i < dataBlocks + treeBlocks; i++) {
new SubNode(i, this);
}
setBaseBlock(additionalNodes.get(0).getBaseBlock());
}
@Override
@ -153,6 +152,7 @@ public class FileNode extends DiskNode {
@Override
public void readBlock(int block, byte[] buffer) throws IOException {
allocate();
int dataBlocks = (int) ((getPhysicalFile().length() + ProdosVirtualDisk.BLOCK_SIZE - 1) / ProdosVirtualDisk.BLOCK_SIZE);
int treeBlocks = (((dataBlocks * 2) + (ProdosVirtualDisk.BLOCK_SIZE - 2)) / ProdosVirtualDisk.BLOCK_SIZE);
if (treeBlocks > 1) {
@ -167,7 +167,7 @@ public class FileNode extends DiskNode {
readFile(buffer, (block - 1));
} else {
// Generate seedling index block
generateIndex(buffer, 1, treeBlocks + dataBlocks);
generateIndex(buffer, 1, dataBlocks+1);
}
break;
case TREE:
@ -193,8 +193,8 @@ public class FileNode extends DiskNode {
private void generateIndex(byte[] buffer, int indexStart, int indexLimit) {
Arrays.fill(buffer, (byte) 0);
for (int i = indexStart, count = 0; count < 256 && i < indexLimit && i < additionalNodes.size(); i++, count++) {
int base = additionalNodes.get(i).baseBlock;
for (int i = indexStart, count = 0; count < 256 && i < indexLimit && i <= additionalNodes.size(); i++, count++) {
int base = additionalNodes.get(i-1).getBaseBlock();
buffer[count] = (byte) (base & 0x0ff);
buffer[count + 256] = (byte) (base >> 8);
}

View File

@ -27,8 +27,7 @@ import java.io.IOException;
public class FreespaceBitmap extends DiskNode {
int size = (ProdosVirtualDisk.MAX_BLOCK + 1) / 8 / ProdosVirtualDisk.BLOCK_SIZE;
public FreespaceBitmap(ProdosVirtualDisk fs, int start) throws IOException {
setBaseBlock(start);
setOwnerFilesystem(fs);
super(fs, start);
for (int i=1; i < size; i++) {
SubNode subNode = new SubNode(i, this, start+i);

View File

@ -52,6 +52,7 @@ public class ProdosVirtualDisk implements IDisk {
public ProdosVirtualDisk(File rootPath) throws IOException {
ioBuffer = new byte[BLOCK_SIZE];
initDiskStructure();
setPhysicalPath(rootPath);
}
@ -131,25 +132,14 @@ public class ProdosVirtualDisk implements IDisk {
throw new IOException("Virtual Disk Full!");
}
// Mark space occupied by node
public void allocateEntry(DiskNode node) throws IOException {
physicalMap.put(node.baseBlock, node);
for (DiskNode subnode : node.additionalNodes) {
int blockNum = getNextFreeBlock();
subnode.setBaseBlock(blockNum);
physicalMap.put(blockNum, subnode);
}
}
// Mark space occupied by nodes as free (remove allocation mapping)
public void deallocateEntry(DiskNode node) {
// Only de-map nodes if the allocation table is actually pointing to the nodes!
if (physicalMap.get(node.baseBlock) != null && physicalMap.get(node.baseBlock).equals(node)) {
physicalMap.remove(node.baseBlock);
if (physicalMap.get(node.getBaseBlock()) != null && physicalMap.get(node.getBaseBlock()).equals(node)) {
physicalMap.remove(node.getBaseBlock());
}
node.additionalNodes.stream().filter((sub)
-> (physicalMap.get(sub.getBaseBlock()) != null && physicalMap.get(sub.baseBlock).equals(sub))).
-> (physicalMap.get(sub.getBaseBlock()) != null && physicalMap.get(sub.getBaseBlock()).equals(sub))).
forEach((sub) -> {
physicalMap.remove(sub.getBaseBlock());
});
@ -183,12 +173,16 @@ public class ProdosVirtualDisk implements IDisk {
return physicalRoot;
}
public void setPhysicalPath(File f) throws IOException {
private void initDiskStructure() throws IOException {
physicalMap = new HashMap<>();
freespaceBitmap = new FreespaceBitmap(this, FREESPACE_BITMAP_START);
}
private void setPhysicalPath(File f) throws IOException {
if (physicalRoot != null && physicalRoot.equals(f)) {
return;
}
physicalRoot = f;
physicalMap = new HashMap<>();
if (!physicalRoot.exists() || !physicalRoot.isDirectory()) {
try {
throw new IOException("Root path must be a directory that exists!");
@ -197,12 +191,9 @@ public class ProdosVirtualDisk implements IDisk {
}
}
// Root directory ALWAYS starts on block 2!
rootDirectory = new DirectoryNode(this, physicalRoot, VOLUME_START);
rootDirectory = new DirectoryNode(this, physicalRoot, VOLUME_START, true);
rootDirectory.setName("VIRTUAL");
allocateEntry(rootDirectory);
freespaceBitmap = new FreespaceBitmap(this, FREESPACE_BITMAP_START);
allocateEntry(freespaceBitmap);
rootDirectory.allocate();
}
@Override

View File

@ -33,18 +33,18 @@ public class SubNode extends DiskNode {
int sequenceNumber;
public SubNode(int seq, DiskNode parent) throws IOException {
super(parent.getOwnerFilesystem());
init(seq, parent);
}
public SubNode(int seq, DiskNode parent, int baseBlock) throws IOException {
setBaseBlock(baseBlock);
super(parent.getOwnerFilesystem(), baseBlock);
init(seq, parent);
}
private void init(int seq, DiskNode parent) throws IOException {
sequenceNumber = seq;
setParent(parent);
setOwnerFilesystem(parent.getOwnerFilesystem());
parent.additionalNodes.add(this);
}