Implement directory creation in ProDOS

Side effect: opened up the previously private 'Name' class in ui; this simplifies directory handling elsewhere, as it automatically creates a directory structure to a pathed file.
This commit is contained in:
2012-08-08 03:10:57 +00:00
parent 01fd44f8fd
commit 87eca0095c
14 changed files with 191 additions and 16 deletions

View File

@ -47,7 +47,7 @@ public interface DirectoryEntry {
/**
* Create a new DirectoryEntry.
*/
public DirectoryEntry createDirectory() throws DiskFullException;
public DirectoryEntry createDirectory(String name) throws DiskFullException;
/**
* Identify if additional directories can be created. This

View File

@ -537,4 +537,12 @@ public class CpmFormatDisk extends FormattedDisk {
public DirectoryEntry createDirectory() throws DiskFullException {
throw new UnsupportedOperationException(textBundle.get("DirectoryCreationNotSupported")); //$NON-NLS-1$
}
/**
* Create a new DirectoryEntry.
* @see com.webcodepro.applecommander.storage.DirectoryEntry#createDirectory()
*/
public DirectoryEntry createDirectory(String name) throws DiskFullException {
throw new UnsupportedOperationException(textBundle.get("DirectoryCreationNotSupported")); //$NON-NLS-1$
}
}

View File

@ -745,4 +745,12 @@ public class DosFormatDisk extends FormattedDisk {
public DirectoryEntry createDirectory() throws DiskFullException {
throw new UnsupportedOperationException(textBundle.get("DirectoryCreationNotSupported")); //$NON-NLS-1$
}
/**
* Create a new DirectoryEntry.
* @see com.webcodepro.applecommander.storage.DirectoryEntry#createDirectory()
*/
public DirectoryEntry createDirectory(String name) throws DiskFullException {
throw new UnsupportedOperationException(textBundle.get("DirectoryCreationNotSupported")); //$NON-NLS-1$
}
}

View File

@ -715,4 +715,12 @@ public class GutenbergFormatDisk extends FormattedDisk {
public DirectoryEntry createDirectory() throws DiskFullException {
throw new UnsupportedOperationException(textBundle.get("DirectoryCreationNotSupported")); //$NON-NLS-1$
}
/**
* Create a new DirectoryEntry.
* @see com.webcodepro.applecommander.storage.DirectoryEntry#createDirectory()
*/
public DirectoryEntry createDirectory(String name) throws DiskFullException {
throw new UnsupportedOperationException(textBundle.get("DirectoryCreationNotSupported")); //$NON-NLS-1$
}
}

View File

@ -532,4 +532,12 @@ public class NakedosFormatDisk extends FormattedDisk {
public DirectoryEntry createDirectory() throws DiskFullException {
throw new UnsupportedOperationException(textBundle.get("DirectoryCreationNotSupported")); //$NON-NLS-1$
}
/**
* Create a new DirectoryEntry.
* @see com.webcodepro.applecommander.storage.DirectoryEntry#createDirectory()
*/
public DirectoryEntry createDirectory(String name) throws DiskFullException {
throw new UnsupportedOperationException(textBundle.get("DirectoryCreationNotSupported")); //$NON-NLS-1$
}
}

View File

@ -664,4 +664,12 @@ public class PascalFormatDisk extends FormattedDisk {
public DirectoryEntry createDirectory() throws DiskFullException {
throw new UnsupportedOperationException(textBundle.get("DirectoryCreationNotSupported")); //$NON-NLS-1$
}
/**
* Create a new DirectoryEntry.
* @see com.webcodepro.applecommander.storage.DirectoryEntry#createDirectory()
*/
public DirectoryEntry createDirectory(String name) throws DiskFullException {
throw new UnsupportedOperationException(textBundle.get("DirectoryCreationNotSupported")); //$NON-NLS-1$
}
}

View File

@ -69,14 +69,14 @@ public class ProdosCommonDirectoryHeader extends ProdosCommonEntry {
}
/**
* Get the number of active entries in the volume directory.
* Get the number of active entries in the directory.
*/
public int getFileCount() {
return AppleUtil.getWordValue(readFileEntry(), 0x21);
}
/**
* Set the number of active entries in the volume directory.
* Set the number of active entries in the directory.
*/
public void setFileCount(int fileCount) {
byte[] data = readFileEntry();
@ -119,14 +119,14 @@ public class ProdosCommonDirectoryHeader extends ProdosCommonEntry {
}
/**
* Get the total number of blocks on this volume.
* Get the total number of blocks on this volume (only valid for volume directory block).
*/
public int getTotalBlocks() {
return AppleUtil.getWordValue(readFileEntry(), 0x25);
}
/**
* Set the total number of blocks on this volume.
* Set the total number of blocks on this volume (only valid for volume directory block).
*/
public void setTotalBlocks(int totalBlocks) {
byte[] data = readFileEntry();

View File

@ -81,7 +81,7 @@ public class ProdosCommonEntry {
System.arraycopy(data, offset, entry, 0, ENTRY_LENGTH);
return entry;
}
/**
* Indicates if this entry is empty - filled with $00.
*/
@ -162,6 +162,20 @@ public class ProdosCommonEntry {
setStorageType(0x03);
}
/**
* Indicates if this is a subdirectory entry.
*/
public boolean isSubdirectory() {
return getStorageType() == 0x0d;
}
/**
* Sets the storage type to a subdirectory entry.
*/
public void setSubdirectory() {
setStorageType(0x0d);
}
/**
* Indicates if this is a subdirectory header entry.
*/

View File

@ -95,7 +95,7 @@ public class ProdosDirectoryEntry extends ProdosFileEntry implements DirectoryEn
* Create a new DirectoryEntry.
* @see com.webcodepro.applecommander.storage.DirectoryEntry#createDirectory()
*/
public DirectoryEntry createDirectory() throws DiskFullException {
return getDisk().createDirectory();
public DirectoryEntry createDirectory(String name) throws DiskFullException {
return getDisk().createDirectory(getSubdirectoryHeader(), name);
}
}

View File

@ -1315,7 +1315,7 @@ public class ProdosFormatDisk extends FormattedDisk {
public void setFileData(FileEntry fileEntry, byte[] fileData) throws DiskFullException {
setFileData((ProdosFileEntry)fileEntry, fileData);
}
protected ProdosVolumeDirectoryHeader getVolumeHeader() {
return volumeHeader;
}
@ -1324,7 +1324,81 @@ public class ProdosFormatDisk extends FormattedDisk {
* Create a new DirectoryEntry.
* @see com.webcodepro.applecommander.storage.DirectoryEntry#createDirectory()
*/
public DirectoryEntry createDirectory() throws DiskFullException {
throw new UnsupportedOperationException(textBundle.get("DirectoryCreationNotSupported")); //$NON-NLS-1$
public DirectoryEntry createDirectory(String name) throws DiskFullException {
return createDirectory(getVolumeHeader(), name);
}
/**
* Create a new DirectoryEntry.
* @see com.webcodepro.applecommander.storage.DirectoryEntry#createDirectory()
*/
public DirectoryEntry createDirectory(ProdosCommonDirectoryHeader directory, String name) throws DiskFullException {
int blockNumber = directory.getFileEntryBlock();
while (blockNumber != 0) {
byte[] block = readBlock(blockNumber);
int offset = 4;
while (offset+ProdosCommonEntry.ENTRY_LENGTH < BLOCK_SIZE) {
int value = AppleUtil.getUnsignedByte(block[offset]);
if ((value & 0xf0) == 0) {
// First, create a new block to contain our subdirectory
byte[] volumeBitmap = readVolumeBitMap();
int newDirBlockNumber = findFreeBlock(volumeBitmap);
setBlockUsed(volumeBitmap, newDirBlockNumber);
// Clean out the block - it may have been recycled, and control structures need to be gone
byte[] cleanBlock = new byte[512];
for (int i = 0;i<512;i++)
cleanBlock[i] = 0;
writeBlock(newDirBlockNumber, cleanBlock);
writeVolumeBitMap(volumeBitmap);
ProdosSubdirectoryHeader newHeader = new ProdosSubdirectoryHeader(this, newDirBlockNumber);
ProdosFileEntry subdirEntry = (ProdosFileEntry)createFile(newHeader);
subdirEntry.setFilename(name);
newHeader.setHousekeeping();
newHeader.setCreationDate(new Date());
newHeader.setParentPointer(blockNumber);
// Now, add an entry for this subdirectory
ProdosDirectoryEntry fileEntry =
new ProdosDirectoryEntry(this, blockNumber, offset, newHeader);
fileEntry.setBlocksUsed(1); // Mark ourselves as the one block in use in this new subdirectory
fileEntry.setEofPosition(BLOCK_SIZE);
fileEntry.setKeyPointer(newDirBlockNumber);
fileEntry.setCreationDate(new Date());
fileEntry.setLastModificationDate(new Date());
fileEntry.setProdosVersion(0);
fileEntry.setMinimumProdosVersion(0);
fileEntry.setCanDestroy(true);
fileEntry.setCanRead(true);
fileEntry.setCanRename(true);
fileEntry.setCanWrite(true);
fileEntry.setSubdirectory();
fileEntry.setHeaderPointer(blockNumber);
fileEntry.setFilename(name);
fileEntry.setFiletype(0x0f); // Filetype = subdirectory
directory.incrementFileCount();
return fileEntry;
}
offset+= ProdosCommonEntry.ENTRY_LENGTH;
}
int nextBlockNumber = AppleUtil.getWordValue(block, NEXT_BLOCK_POINTER);
if (nextBlockNumber == 0 && directory instanceof ProdosSubdirectoryHeader) {
byte[] volumeBitmap = readVolumeBitMap();
nextBlockNumber = findFreeBlock(volumeBitmap);
setBlockUsed(volumeBitmap, nextBlockNumber);
writeVolumeBitMap(volumeBitmap);
byte[] oldBlock = readBlock(blockNumber);
AppleUtil.setWordValue(oldBlock, NEXT_BLOCK_POINTER, nextBlockNumber);
writeBlock(blockNumber, oldBlock);
byte[] nextBlock = new byte[BLOCK_SIZE];
AppleUtil.setWordValue(nextBlock, PREV_BLOCK_POINTER, blockNumber);
writeBlock(nextBlockNumber, nextBlock);
ProdosSubdirectoryHeader header = (ProdosSubdirectoryHeader) directory;
int blockCount = header.getProdosDirectoryEntry().getBlocksUsed();
blockCount++;
header.getProdosDirectoryEntry().setBlocksUsed(blockCount);
header.getProdosDirectoryEntry().setEofPosition(blockCount * BLOCK_SIZE);
}
blockNumber = nextBlockNumber;
}
throw new DiskFullException(textBundle.get("ProdosFormatDisk.UnableToAllocateSpaceError")); //$NON-NLS-1$
}
}

View File

@ -22,7 +22,7 @@ package com.webcodepro.applecommander.storage.os.prodos;
import com.webcodepro.applecommander.util.AppleUtil;
/**
* Provides commone subdirectory attributes.
* Provides common subdirectory attributes.
* <p>
* Date created: Oct 5, 2002 11:17:57 PM
* @author Rob Greene
@ -52,6 +52,15 @@ public class ProdosSubdirectoryHeader extends ProdosCommonDirectoryHeader {
return AppleUtil.getWordValue(readFileEntry(), 0x23);
}
/**
* Set the block number of the parent directory which contains the
* file entry for this subdirectory.
*/
public void setParentPointer(int block) {
byte[] data = readFileEntry();
AppleUtil.setWordValue(data, 0x23, block);
}
/**
* Return the number of the file entry within the parent block.
*/
@ -79,4 +88,17 @@ public class ProdosSubdirectoryHeader extends ProdosCommonDirectoryHeader {
public ProdosDirectoryEntry getProdosDirectoryEntry() {
return directoryEntry;
}
/**
* Set up some housekeeping bits
*/
public void setHousekeeping() {
byte[] data = readFileEntry();
data[0x00] = (byte) (0xe0 | (data[0x00] & 0x0f)); // Subdirectories have the high nibble set to 0x0e
data[0x10] = 0x75; // Reserved - must be $75
data[0x1f] = (byte) ENTRY_LENGTH;
data[0x20] = 0x0d;
AppleUtil.setWordValue(data, 0x21, 0); // Set file count to zero
writeFileEntry(data);
}
}

View File

@ -509,4 +509,12 @@ public class RdosFormatDisk extends FormattedDisk {
public DirectoryEntry createDirectory() throws DiskFullException {
throw new UnsupportedOperationException(textBundle.get("DirectoryCreationNotSupported")); //$NON-NLS-1$
}
/**
* Create a new DirectoryEntry.
* @see com.webcodepro.applecommander.storage.DirectoryEntry#createDirectory()
*/
public DirectoryEntry createDirectory(String name) throws DiskFullException {
throw new UnsupportedOperationException(textBundle.get("DirectoryCreationNotSupported")); //$NON-NLS-1$
}
}

View File

@ -574,7 +574,7 @@ public class ac {
"CommandLineHelp", AppleCommander.VERSION)); //$NON-NLS-1$
}
private static class Name {
public static class Name {
private String fullName;
private String name;
private String[] path;
@ -616,17 +616,31 @@ public class ac {
return formattedDisk.createFile();
}
List files = formattedDisk.getFiles();
DirectoryEntry dir = null;
DirectoryEntry dir = null, parentDir = null;
for (int i = 0; i < path.length - 1; i++) {
String dirName = path[i];
dir = null;
for (int j = 0; j < files.size(); j++) {
FileEntry entry = (FileEntry) files.get(j);
String entryName = entry.getFilename();
if (entry.isDirectory() && dirName.equalsIgnoreCase(entryName)) {
if (!entry.isDeleted() && entry.isDirectory() && dirName.equalsIgnoreCase(entryName)) {
dir = (DirectoryEntry) entry;
parentDir = dir;
files = dir.getFiles();
}
}
if (dir == null) {
if (parentDir != null) {
// If there's a parent directory in the mix, add
// the new child directory to that.
dir = parentDir.createDirectory(dirName);
parentDir = dir;
} else {
// Add the directory to the root of the filesystem
dir = formattedDisk.createDirectory(dirName);
parentDir = dir;
}
}
}
if (dir != null) {
return dir.createFile();

View File

@ -25,6 +25,7 @@ import java.io.IOException;
import java.io.InputStream;
import com.webcodepro.applecommander.storage.Disk;
import com.webcodepro.applecommander.storage.FileEntry;
import com.webcodepro.applecommander.storage.FormattedDisk;
import com.webcodepro.applecommander.storage.StorageBundle;
import com.webcodepro.applecommander.storage.os.prodos.ProdosFileEntry;
@ -32,6 +33,7 @@ import com.webcodepro.applecommander.storage.os.prodos.ProdosFormatDisk;
import com.webcodepro.applecommander.storage.physical.ByteArrayImageLayout;
import com.webcodepro.applecommander.storage.physical.ImageOrder;
import com.webcodepro.applecommander.storage.physical.ProdosOrder;
import com.webcodepro.applecommander.ui.ac.Name;
import com.webcodepro.applecommander.util.TextBundle;
import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
@ -118,7 +120,8 @@ public class Utilities
{
if (dataFork != null)
{
newFile = (ProdosFileEntry) pdDisk.createFile();
Name name = new Name(b.getFilename());
newFile = (ProdosFileEntry)name.createEntry(pdDisk);
if (newFile != null)
{
if (resourceFork != null)