public class WinDrive
extends java.lang.Object
A windrive is just a file in the native file system, upon which a certain structure is superimposed. It mimics a physical hard drive, so there is a "physical" structure and a "logical" structure.
The physical structure is as follows:
The basic subdivision of a drive is a sector. Each sector is 512 bytes long. Sectors are numbered from 0 upwards. Sector 0 is at the very beginning of the drive, sector 1 is the following sector and so on.
Sectors are nominally grouped into tracks - each track may contain a certain number of sectors. The number of sectors in a track is supposed to remain constant across the entire drive. Tracks are grouped in cylinders (normally platters or read/write heads). A drive may have several cylinders. Since a qxl.win drive is NOT a real hard disk, these physical details may be neglected, except for sector size.
The logical structure is as follows:
Sectors are grouped together in clusters, or "groups" as the SMSQ/E documentation calls them. A cluster is a grouping of consecutive and contiguous sectors and is the minimum size any file may have. The cluster size is not necessarily the same for all drives, it may vary from drive to drive - but does not vary within one drive. A cluster may be composed of 2,4,8 etc sectors. The cluster size is given in the header of the drive.
Each drive has a header which is 64 bytes long and is located at the very beginning of the drive, i.e. in sector 0. The header contains information about the structure of the disk. The exact content of the header is described below in the data structures. Most of the the words in the header are unsigned values.
The header of the drive is immediately followed by the file allocation table (FAT) or "map" as the SMSQ/E documentation calls it. A physical drive might have several FATs, each FAT corresponding to a partition, but a qxl.win drive does not contain several partitions.
The FAT is composed of unsigned words (2 bytes). There can thus only be 65536 entries in the FAT. Each entry in the FAT corresponds to a cluster and thus to a specific location within the drive. If the cluster size is 4 sectors, then entry 0 in the FAT corresponds to sectors 0,1,2 and 3 of the drive, entry 1 in the FAT corresponds to sectors 4,5,6 and 7 etc... If the cluster size is 2 sectors, then entry 0 in the FAT corresponds to sectors 0 and 1 of the drive, entry 1 in the FAT corresponds to sectors 2 and 3 etc... So the physical location of a cluster in a file is determined by cluster number * cluster size.
Since the size of one entry in the FAT is a word, and there can thus only be a maximum of 65536 entries in the FAT, the size of a drive is this directly proportional to the number of sectors per cluster.
Each FAT entry points to the next cluster FOR THE SAME FILE, or is 0 to mark that this cluster is the of the end of the file. The first entries in the FAT are for the FAT itself. After that, there is the first entry for the root directory of the drive.
Any actual reading/writing from/to the drive is done through THIS object.
Implementation details:
SMSQ/E doesn't open "files". It opens channels to files. this mens that a ('physical') file on the drive may have several channels open to it, provided they are all read only, or one single read/write channel. This object maintains a Hashmap of WinFiles. When a channel is opened an entry for the corresponding file is created. Each file that is opened on a drive is given a file number.
There is a maximum of WinDrive.MAX_FILES_OPEN files that may be open at any one time.
The drive is responsible for opening, closing and deleting files. The files themselves are responsible for the actual I/O INTO THEIR BUFFER. However any actual reading/writing from/to the drive is done through THIS object. Files, dirs, even the FAT, have a clusterchain : just an arraylist with all of the cluster numbers of the file/dir/FAT.
ByteBuffer
holding the entire header + the FAT of the driveEach file has a WinDriver.HEADER_LENGTH bytes long header.
Each (sub)directory contains the entire name of the file (stripped of the device part, though).
Note : As far as SMSQE is concerned, each access to a file on the drive will be atomic - smsqe is suspended until the trzp rturns.
On a QXL.Win drive the fileheaders of files themselves contain rubbish. The fileheader is maintained in the directory and, when SMSQE tries to read the header, this is copied from the directory.
When a file is created, it is allocated one cluster. New clusters are not allocated as the file grows, only when the file is closed/flushed. the drawback of this is that a file may grow enormously without error and, when it is written back, it can't be saved any more.
Modifier and Type | Field and Description |
---|---|
protected int |
clusterSize |
protected MC68000Cpu |
cpu |
protected java.nio.ByteBuffer |
driveFAT |
protected java.lang.String |
driveName |
protected int |
driveNumber |
protected WinDriver |
driver |
protected java.util.ArrayList<java.lang.Integer> |
fatClusterChain |
protected WinFile[] |
fileNumber |
protected java.nio.channels.FileLock |
flock |
protected java.nio.channels.FileChannel |
ioChannel |
static byte[] |
LOWER_CASE
Array for converting QL chars into lower case see : util_cv_locas_asm
|
protected WinDir |
mainDir |
static int |
MAX_FILES_OPEN |
static int |
QWA_CYLD |
static int |
QWA_FCYL |
static int |
QWA_FGRP |
static int |
QWA_FREE |
static int |
QWA_FSCT |
static int |
QWA_GMAP |
static int |
QWA_IDEN
The structure of the drive header.
|
static int |
QWA_INTL |
static int |
QWA_NAME |
static int |
QWA_NGRP |
static int |
QWA_NMAP |
static int |
QWA_PARK |
static int |
QWA_RLEN |
static int |
QWA_ROOT |
static int |
QWA_SCTG |
static int |
QWA_SCTM |
static int |
QWA_SCTT |
static int |
QWA_SPR0 |
static int |
QWA_TRKC |
static int |
QWA_UCHK |
protected java.io.RandomAccessFile |
raFile |
protected boolean |
readOnly |
protected boolean |
specialFileIsOpen |
protected Warnings |
warnings |
Constructor and Description |
---|
WinDrive()
DO NOT USE THIS FORM OF CREATING THE OBJECT.
|
WinDrive(MC68000Cpu cpu,
java.lang.String driveName,
WinDriver driver,
int number,
Warnings warn,
inifile.IniFile inifile)
Creates the object.
|
WinDrive(MC68000Cpu cpu,
Warnings warn)
Create object with a CPU and warnings.
|
Modifier and Type | Method and Description |
---|---|
java.util.ArrayList<java.lang.Integer> |
allocateClusters(int clustersNeeded)
This allocates a new clusterchain with as many clusters as needed.
|
void |
changeParentDir(WinDir oldDir,
int oldEntry,
WinDir newDir,
int newEntry)
Changes the parent dir of a file to the new dir.
|
int |
checkSector(int sector)
Checks that the special file doesn't go beyond the end of the allowed sectors.
|
void |
closeAllFiles()
"Closes" all files by just forgetting about them.
|
boolean |
closeFile(int fileNbr)
Closes a file.
|
static byte[] |
convert2SMSQELowerCase(byte[] in)
This creates a new array of bytes, converting the case of the input array to SMSQE lower case.
|
void |
flush()
Writes the FAT + drive header to the drive.
|
void |
freeClusters(int cluster)
Frees clusters in the FAT, freeing all clusters in a clusterchain.
|
int |
getClusterSize()
Gets the size, in bytes, of one cluster on the drive.
|
java.lang.String |
getDrivename()
Gets the name of the native file containing this drive.
|
int |
getIntFromFAT(int index)
Gets an int from the FAT or header.
|
java.nio.ByteBuffer |
increaseCapacity(java.nio.ByteBuffer buffer,
int bytesToAdd,
java.util.ArrayList<java.lang.Integer> clusterchain)
This "increases" a file's buffer by multiples of the clustersize.
|
boolean |
isReadOnly()
Checks whether the drive is read only.
|
boolean |
openFile(int devDriverLinkageBlock,
int channelDefinitionBlock,
int openType,
int driveNumber,
byte[] filename,
byte[] uncased)
Opens a file.
|
int |
readBytes(int nbrOfBytes,
java.nio.ByteBuffer buffer,
long position)
Reads bytes at a certain position in the drive to a buffer.
|
java.nio.ByteBuffer |
readFile(int fileLength,
int cluster,
java.util.ArrayList<java.lang.Integer> clusterchain)
Creates a ByteBuffer (for a file) and reads the file into it.
|
void |
setCpu(MC68000Cpu cpu)
Sets the cpu for this Object.
|
void |
setRootDirLength(int fsize)
Sets the length of the root directory in the appropriate place in the FAT.
|
void |
specialFileClosed()
Marks special file as closed.
|
void |
trap3OK(int driveNumber,
int trapKey,
int fileNbr)
Handles trap#3 calls.
|
java.util.ArrayList<java.lang.Integer> |
truncateFile(int oldsize,
int newsize,
java.util.ArrayList<java.lang.Integer> currentClusterchain)
If a file is truncated : delete the clusterchain it occupied and make a new one with the lesser size, unless it would still
occupy the same number of clusters (in which case nothing is done).
|
void |
unuse()
Unuses (frees) the locked channel.
|
int |
writeBytes(int nbrOfBytes,
java.nio.ByteBuffer buffer,
long position,
int startInBuffer)
Writes bytes from a certain position in a buffer to a certain position in the drive.
|
void |
writeFile(java.nio.ByteBuffer fileBuffer,
java.util.ArrayList<java.lang.Integer> clusterchain)
This writes an entire file in a byte buffer back to the drive.
|
void |
writePartOfFile(java.nio.ByteBuffer fileBuffer,
java.util.ArrayList<java.lang.Integer> clusterchain,
int start,
int bytesToWrite)
This writes a part of byte buffer back to the drive.
|
public static final int QWA_IDEN
public static final int QWA_NAME
public static final int QWA_SPR0
public static final int QWA_UCHK
public static final int QWA_INTL
public static final int QWA_SCTG
public static final int QWA_SCTT
public static final int QWA_TRKC
public static final int QWA_CYLD
public static final int QWA_NGRP
public static final int QWA_FGRP
public static final int QWA_SCTM
public static final int QWA_NMAP
public static final int QWA_FREE
public static final int QWA_ROOT
public static final int QWA_RLEN
public static final int QWA_FCYL
public static final int QWA_FSCT
public static final int QWA_PARK
public static final int QWA_GMAP
public static final byte[] LOWER_CASE
public static final int MAX_FILES_OPEN
protected MC68000Cpu cpu
protected java.lang.String driveName
protected WinDriver driver
protected int driveNumber
protected Warnings warnings
protected java.io.RandomAccessFile raFile
protected java.nio.channels.FileChannel ioChannel
protected boolean readOnly
protected java.nio.channels.FileLock flock
protected int clusterSize
protected java.util.ArrayList<java.lang.Integer> fatClusterChain
protected java.nio.ByteBuffer driveFAT
protected WinDir mainDir
protected WinFile[] fileNumber
protected boolean specialFileIsOpen
public WinDrive() throws java.lang.UnsupportedOperationException
java.lang.UnsupportedOperationException
public WinDrive(MC68000Cpu cpu, Warnings warn)
cpu
- the cpu to be usedwarn
- the warning object with info about what warnings should be suppressed or not.public WinDrive(MC68000Cpu cpu, java.lang.String driveName, WinDriver driver, int number, Warnings warn, inifile.IniFile inifile) throws java.io.FileNotFoundException, java.io.IOException, java.lang.ArrayIndexOutOfBoundsException, java.net.ProtocolException, DoNothingException, IncorrectFiletypeException, java.lang.UnsupportedOperationException
cpu
- the cpu used.driveName
- the name of the qxl.win file on the native file system.driver
- the driver having created this object.number
- my driveNbr as ASCII!.warn
- object with warning flags.inifile
- the ".ini" file object.java.io.FileNotFoundException
- the qxl.win file isn't foundjava.io.IOException
- any IO exception reading the FAT / main dirjava.lang.ArrayIndexOutOfBoundsException
- a wrong FAT cluster number was givenjava.net.ProtocolException
- if the main dir couldn't be read.DoNothingException
- if this is a drive with a wrong FAT and user doesn't want me to (try to) fix it.IncorrectFiletypeException
- if this is not a valid qlwa file.java.lang.UnsupportedOperationException
- couldn't acquire a file lock.public boolean openFile(int devDriverLinkageBlock, int channelDefinitionBlock, int openType, int driveNumber, byte[] filename, byte[] uncased)
devDriverLinkageBlock
- pointer to the device driver linkage block (a3).channelDefinitionBlock
- pointer to the channel definition block (a0).openType
- which kind of open is requested? (0 - old exclusive, 1 old shared,2 new exclusive,3 new overwrite,4 open dir).driveNumber
- which drive number the file is to be opened on.filename
- the (SMSQE) name of the file to open.uncased
- the lower cased (SMSQE) name of the file to open.DeviceDriver for more information on file open operations.
public void setRootDirLength(int fsize)
fsize
- the length of the root directory, in bytes.public void flush()
public java.nio.ByteBuffer readFile(int fileLength, int cluster, java.util.ArrayList<java.lang.Integer> clusterchain)
fileLength
- the length of the file (should include the length of the file header).cluster
- the first cluster of the file (index into the FAT).clusterchain
- - the empty cluster chain, will be filled in here.null
if problem. Attention : the size of the buffer will most
likely be bigger than the size of the file : the size of the buffer is increased to be a multiple of the clusterSize.
This should correspond to the number of clusters occupied by the file.public void writeFile(java.nio.ByteBuffer fileBuffer, java.util.ArrayList<java.lang.Integer> clusterchain) throws java.io.IOException
fileBuffer
- the ByteBuffer containing the file. The capacity of the buffer may be bigger than the true filesize.clusterchain
- the first cluster of the file.java.io.IOException
- any i/o exception from the java i/o operations.public void writePartOfFile(java.nio.ByteBuffer fileBuffer, java.util.ArrayList<java.lang.Integer> clusterchain, int start, int bytesToWrite) throws java.io.IOException
fileBuffer
- the ByteBuffer containing the file. The capacity of the buffer may be bigger than the true filesize.clusterchain
- the first cluster of the file.start
- where in the buffer to start writing.bytesToWrite
- how many bytes must be written.java.io.IOException
- any i/o exception from the java i/o operations.public java.nio.ByteBuffer increaseCapacity(java.nio.ByteBuffer buffer, int bytesToAdd, java.util.ArrayList<java.lang.Integer> clusterchain)
buffer
- the buffer to increase. The limit and position of the buffer MUST have been put at the correct values before calling this.
(position should be 0, limit set to the fileSize incl the header.bytesToAdd
- the number of bytes to add to the file.clusterchain
- the clusterchain for this file. New clusters will be added at the end.public java.util.ArrayList<java.lang.Integer> truncateFile(int oldsize, int newsize, java.util.ArrayList<java.lang.Integer> currentClusterchain)
oldsize
- old size of the file (=current file size).newsize
- the file size once the file is truncated.currentClusterchain
- the file's cluster chain.public int readBytes(int nbrOfBytes, java.nio.ByteBuffer buffer, long position)
nbrOfBytes
- how many bytes to read.buffer
- where to read the bytes to - this buffer must be at least nbrOfBytes long. The bytes are read to the start of the buffer.position
- where to read from in the drive.public int writeBytes(int nbrOfBytes, java.nio.ByteBuffer buffer, long position, int startInBuffer)
nbrOfBytes
- how many bytes to write.buffer
- where to read the bytes to - this buffer must be at least nbrOfBytes long. The bytes are taken from the start of the bufferposition
- where to write to in the drive.startInBuffer
- where in the buffer to start taking the bytes to wirite from.public java.util.ArrayList<java.lang.Integer> allocateClusters(int clustersNeeded)
clustersNeeded
- the number of clusters neededpublic void freeClusters(int cluster)
cluster
- the first cluster to be freed, all other clusters this cluster refers to will also be freed.public int getIntFromFAT(int index)
index
- where to read in the map.public static final byte[] convert2SMSQELowerCase(byte[] in)
in
- the array with the bytes to convert.public void unuse()
public java.lang.String getDrivename()
public boolean isReadOnly()
public void trap3OK(int driveNumber, int trapKey, int fileNbr)
driveNumber
- number of drive on which to open the filetrapKey
- what kind of trap #3 is it?fileNbr
- the file number given by the ddd when file was opened (A0+0x1e)public void setCpu(MC68000Cpu cpu)
cpu
- the cpu to be set.public boolean closeFile(int fileNbr)
fileNbr
- the number of the file to close.true
if closed ok, else false
.public void specialFileClosed()
public int checkSector(int sector)
sector
- sector to check for EOF.public int getClusterSize()
public void changeParentDir(WinDir oldDir, int oldEntry, WinDir newDir, int newEntry)
oldDir
- the old parent diroldEntry
- where in the old dir the file is : this identifies the file to treatnewDir
- the new parent dirnewEntry
- the new entry in that dirpublic void closeAllFiles()