mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-06 05:28:31 +09:00
clustered test
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -1,61 +1,95 @@
|
|||||||
package net.torvald.tsvm.peripheral
|
package net.torvald.tsvm.peripheral
|
||||||
|
|
||||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.*
|
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.ClusteredFormatDOM
|
||||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.VDUtil.checkReadOnly
|
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.Clustfile
|
||||||
import net.torvald.tsvm.VM
|
import net.torvald.tsvm.VM
|
||||||
import java.io.*
|
import java.io.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by minjaesong on 2022-12-15.
|
* @param driveNum 0 for COM drive number 1, but the file path will still be zero-based
|
||||||
*/
|
*/
|
||||||
class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val theTevdPath: String, val diskUUIDstr: String) : BlockTransferInterface(false, true) {
|
class TevdDiskDrive(private val vm: VM, private val driveNum: Int, theTevdPath: String) : BlockTransferInterface(false, true) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val STATE_CODE_STANDBY = 0
|
||||||
|
const val STATE_CODE_OPERATION_FAILED = 1
|
||||||
|
|
||||||
|
const val STATE_CODE_ILLEGAL_COMMAND = 128
|
||||||
|
const val STATE_CODE_NO_SUCH_FILE_EXISTS = 129
|
||||||
|
const val STATE_CODE_FILE_ALREADY_OPENED = 130
|
||||||
|
const val STATE_CODE_OPERATION_NOT_PERMITTED = 131
|
||||||
|
const val STATE_CODE_READ_ONLY = 132
|
||||||
|
const val STATE_CODE_NOT_A_FILE = 133
|
||||||
|
const val STATE_CODE_NOT_A_DIRECTORY = 134
|
||||||
|
const val STATE_CODE_NO_FILE_OPENED = 135
|
||||||
|
const val STATE_CODE_SYSTEM_IO_ERROR = 192
|
||||||
|
const val STATE_CODE_SYSTEM_SECURITY_ERROR = 193
|
||||||
|
|
||||||
|
|
||||||
private val DBGPRN = true
|
val errorMsgs = Array(256) { "" }
|
||||||
|
|
||||||
val diskID: UUID = UUID.fromString(diskUUIDstr)
|
init {
|
||||||
|
errorMsgs[STATE_CODE_STANDBY] = "READY"
|
||||||
|
errorMsgs[STATE_CODE_OPERATION_FAILED] = "OPERATION FAILED"
|
||||||
|
|
||||||
|
errorMsgs[STATE_CODE_ILLEGAL_COMMAND] = "SYNTAX ERROR"
|
||||||
|
errorMsgs[STATE_CODE_NO_SUCH_FILE_EXISTS] = "NO SUCH FILE EXISTS"
|
||||||
|
errorMsgs[STATE_CODE_FILE_ALREADY_OPENED] = "FILE ALREADY OPENED"
|
||||||
|
errorMsgs[STATE_CODE_SYSTEM_IO_ERROR] = "IO ERROR ON SIMULATED DRIVE"
|
||||||
|
errorMsgs[STATE_CODE_SYSTEM_SECURITY_ERROR] = "SECURITY ERROR ON SIMULATED DRIVE"
|
||||||
|
errorMsgs[STATE_CODE_OPERATION_NOT_PERMITTED] = "OPERATION NOT PERMITTED"
|
||||||
|
errorMsgs[STATE_CODE_NOT_A_FILE] = "NOT A FILE"
|
||||||
|
errorMsgs[STATE_CODE_NOT_A_DIRECTORY] = "NOT A DIRECTORY"
|
||||||
|
errorMsgs[STATE_CODE_NO_FILE_OPENED] = "NO FILE OPENED"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun composePositiveAns(vararg msg: String): ByteArray {
|
||||||
|
val sb = ArrayList<Byte>()
|
||||||
|
sb.addAll(msg[0].toByteArray().toTypedArray())
|
||||||
|
for (k in 1 until msg.size) {
|
||||||
|
sb.add(UNIT_SEP)
|
||||||
|
sb.addAll(msg[k].toByteArray().toTypedArray())
|
||||||
|
}
|
||||||
|
sb.add(END_OF_SEND_BLOCK)
|
||||||
|
return sb.toByteArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val DBGPRN = false
|
||||||
|
|
||||||
private fun printdbg(msg: Any) {
|
private fun printdbg(msg: Any) {
|
||||||
if (DBGPRN) println("[TevDiskDrive] $msg")
|
if (DBGPRN) println("[TevDiskDrive] $msg")
|
||||||
}
|
}
|
||||||
|
|
||||||
private val tevdPath = File(theTevdPath)
|
private val DOM = ClusteredFormatDOM(RandomAccessFile(theTevdPath, "rw"))
|
||||||
private val DOM = PartialDOM(tevdPath, VM.CHARSET)//VDUtil.readDiskArchive(tevdPath, charset = VM.CHARSET)
|
|
||||||
|
|
||||||
private var fileOpen = false
|
private var fileOpen = false
|
||||||
private var fileOpenMode = -1 // 1: 'W", 2: 'A'
|
private var fileOpenMode = -1 // 1: 'W", 2: 'A'
|
||||||
private var file: TevdFileDescriptor = TevdFileDescriptor(DOM, "")
|
private var file = Clustfile(DOM, "")
|
||||||
//private var readModeLength = -1 // always 4096
|
//private var readModeLength = -1 // always 4096
|
||||||
private val writeMode
|
private var writeMode = false
|
||||||
get() = fileOpenMode == 1
|
private var appendMode = false
|
||||||
private val appendMode
|
|
||||||
get() = fileOpenMode == 2
|
|
||||||
private var writeModeLength = -1
|
private var writeModeLength = -1
|
||||||
|
|
||||||
private val messageComposeBuffer = ByteArrayOutputStream(BLOCK_SIZE) // always use this and don't alter blockSendBuffer please
|
private val messageComposeBuffer = ByteArrayOutputStream(BLOCK_SIZE) // always use this and don't alter blockSendBuffer please
|
||||||
private var blockSendBuffer = ByteArray(1)
|
private var blockSendBuffer = ByteArray(1)
|
||||||
private var blockSendCount = 0
|
private var blockSendCount = 0
|
||||||
|
/*set(value) {
|
||||||
|
println("[TevDiskDrive] blockSendCount $field -> $value")
|
||||||
|
val indentation = " ".repeat(this.javaClass.simpleName.length + 4)
|
||||||
|
Thread.currentThread().stackTrace.forEachIndexed { index, it ->
|
||||||
|
if (index == 1)
|
||||||
|
println("[${this.javaClass.simpleName}]> $it")
|
||||||
|
else if (index in 1..8)
|
||||||
|
println("$indentation$it")
|
||||||
|
}
|
||||||
|
field = value
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_STANDBY)
|
statusCode.set(STATE_CODE_STANDBY)
|
||||||
|
|
||||||
if (!tevdPath.exists()) {
|
|
||||||
throw FileNotFoundException("Disk file '${theTevdPath}' not found")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var tevdSyncFilteringCounter = 0
|
|
||||||
fun notifyDiskCommit() {
|
|
||||||
vm.watchdogs["TEVD_COMMIT"]?.addMessage(arrayOf(tevdPath, DOM))
|
|
||||||
|
|
||||||
if (tevdSyncFilteringCounter >= 1) {
|
|
||||||
vm.watchdogs["TEVD_SYNC"]?.addMessage(arrayOf(tevdPath, DOM))
|
|
||||||
tevdSyncFilteringCounter = 0
|
|
||||||
}
|
|
||||||
tevdSyncFilteringCounter += 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -84,6 +118,8 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t
|
|||||||
blockSendBuffer.size % BLOCK_SIZE
|
blockSendBuffer.size % BLOCK_SIZE
|
||||||
else BLOCK_SIZE
|
else BLOCK_SIZE
|
||||||
|
|
||||||
|
// println("blockSendCount = ${blockSendCount}; sendSize = $sendSize; blockSendBuffer.size = ${blockSendBuffer.size}")
|
||||||
|
|
||||||
recipient.writeout(ByteArray(sendSize) {
|
recipient.writeout(ByteArray(sendSize) {
|
||||||
blockSendBuffer[blockSendCount * BLOCK_SIZE + it]
|
blockSendBuffer[blockSendCount * BLOCK_SIZE + it]
|
||||||
})
|
})
|
||||||
@@ -102,93 +138,64 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t
|
|||||||
* Disk drive must create desired side effects in accordance with the input message.
|
* Disk drive must create desired side effects in accordance with the input message.
|
||||||
*/
|
*/
|
||||||
override fun writeoutImpl(inputData: ByteArray) {
|
override fun writeoutImpl(inputData: ByteArray) {
|
||||||
printdbg("inputString=${inputData.trimNull().toString(VM.CHARSET)}")
|
if (writeMode || appendMode) {
|
||||||
|
|
||||||
if ((writeMode || appendMode) && writeModeLength >= 0) {
|
|
||||||
printdbg("writeout with inputdata length of ${inputData.size}")
|
|
||||||
//println("[DiskDrive] writeout with inputdata length of ${inputData.size}")
|
//println("[DiskDrive] writeout with inputdata length of ${inputData.size}")
|
||||||
//println("[DiskDriveMsg] ${inputData.toString(Charsets.UTF_8)}")
|
//println("[DiskDriveMsg] ${inputData.toString(Charsets.UTF_8)}")
|
||||||
|
|
||||||
if (!fileOpen) throw InternalError("File is not open but the drive is in write mode")
|
if (!fileOpen) throw InternalError("File is not open but the drive is in write mode")
|
||||||
|
|
||||||
if (!file.exists()) {
|
|
||||||
printdbg("File '${file.path}' not exists, creating new...")
|
|
||||||
val (result, failReason) = file.createNewFile()
|
|
||||||
if (failReason != null) {
|
|
||||||
throw failReason
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printdbg("Operation successful")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
System.arraycopy(inputData, 0, writeBuffer, writeBufferUsage, minOf(writeModeLength - writeBufferUsage, inputData.size, BLOCK_SIZE))
|
System.arraycopy(inputData, 0, writeBuffer, writeBufferUsage, minOf(writeModeLength - writeBufferUsage, inputData.size, BLOCK_SIZE))
|
||||||
writeBufferUsage += inputData.size
|
writeBufferUsage += inputData.size
|
||||||
|
|
||||||
if (writeBufferUsage >= writeModeLength) {
|
if (writeBufferUsage >= writeModeLength) {
|
||||||
// commit to the disk
|
// commit to the disk
|
||||||
if (appendMode)
|
if (appendMode) {
|
||||||
file.appendBytes(writeBuffer)
|
val filesize = file.length()
|
||||||
|
file.pwrite(writeBuffer, 0, writeBuffer.size, filesize)
|
||||||
|
}
|
||||||
else if (writeMode)
|
else if (writeMode)
|
||||||
file.writeBytes(writeBuffer)
|
file.writeBytes(writeBuffer)
|
||||||
|
|
||||||
fileOpenMode = -1
|
writeMode = false
|
||||||
|
appendMode = false
|
||||||
printdbg("Notifying disk commit (end of write)")
|
|
||||||
notifyDiskCommit()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (fileOpenMode == 17) {
|
else if (fileOpenMode == 17) {
|
||||||
printdbg("File open mode 17")
|
|
||||||
|
|
||||||
if (!fileOpen) throw InternalError("Bootloader file is not open but the drive is in boot write mode")
|
if (!fileOpen) throw InternalError("Bootloader file is not open but the drive is in boot write mode")
|
||||||
|
|
||||||
val inputData = if (inputData.size != BLOCK_SIZE) ByteArray(BLOCK_SIZE) { if (it < inputData.size) inputData[it] else 0 }
|
val inputData = if (inputData.size != BLOCK_SIZE) ByteArray(BLOCK_SIZE) { if (it < inputData.size) inputData[it] else 0 }
|
||||||
else inputData
|
else inputData
|
||||||
|
|
||||||
val creationTime = VDUtil.currentUnixtime
|
file.writeBytes(inputData)
|
||||||
DOM.checkReadOnly()
|
|
||||||
val file = EntryFile(BLOCK_SIZE.toLong())
|
|
||||||
file.getContent().appendBytes(inputData)
|
|
||||||
|
|
||||||
DOM.addNewFile(DiskEntry(1, 1, "TEVDBOOT".toByteArray(VM.CHARSET), creationTime, creationTime, file))
|
|
||||||
|
|
||||||
|
|
||||||
fileOpenMode = -1
|
fileOpenMode = -1
|
||||||
|
|
||||||
printdbg("Notifying disk commit (end of bootloader write)")
|
|
||||||
notifyDiskCommit()
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printdbg("(cmd mode)")
|
|
||||||
|
|
||||||
val inputString = inputData.trimNull().toString(VM.CHARSET)
|
val inputString = inputData.trimNull().toString(VM.CHARSET)
|
||||||
|
|
||||||
|
// println("[TevDiskDrive] $inputString")
|
||||||
|
|
||||||
if (inputString.startsWith("DEVRST\u0017")) {
|
if (inputString.startsWith("DEVRST\u0017")) {
|
||||||
printdbg("Device Reset")
|
printdbg("Device Reset")
|
||||||
//readModeLength = -1
|
//readModeLength = -1
|
||||||
fileOpen = false
|
fileOpen = false
|
||||||
fileOpenMode = -1
|
fileOpenMode = -1
|
||||||
file = TevdFileDescriptor(DOM, "")
|
file = Clustfile(DOM, "")
|
||||||
blockSendCount = 0
|
blockSendCount = 0
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_STANDBY)
|
statusCode.set(STATE_CODE_STANDBY)
|
||||||
|
writeMode = false
|
||||||
writeModeLength = -1
|
writeModeLength = -1
|
||||||
}
|
}
|
||||||
else if (inputString.startsWith("DEVSTU\u0017"))
|
else if (inputString.startsWith("DEVSTU\u0017"))
|
||||||
recipient?.writeout(
|
recipient?.writeout(composePositiveAns("${statusCode.get().toChar()}", errorMsgs[statusCode.get()]))
|
||||||
TestDiskDrive.composePositiveAns(
|
|
||||||
"${statusCode.get().toChar()}",
|
|
||||||
TestDiskDrive.errorMsgs[statusCode.get()]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else if (inputString.startsWith("DEVTYP\u0017"))
|
else if (inputString.startsWith("DEVTYP\u0017"))
|
||||||
recipient?.writeout(TestDiskDrive.composePositiveAns("STOR"))
|
recipient?.writeout(composePositiveAns("STOR"))
|
||||||
else if (inputString.startsWith("DEVNAM\u0017"))
|
else if (inputString.startsWith("DEVNAM\u0017"))
|
||||||
recipient?.writeout(TestDiskDrive.composePositiveAns("Generic Disk Drive"))
|
recipient?.writeout(composePositiveAns("Testtec Virtual Disk Drive"))
|
||||||
else if (inputString.startsWith("OPENR\"") || inputString.startsWith("OPENW\"") || inputString.startsWith("OPENA\"")) {
|
else if (inputString.startsWith("OPENR\"") || inputString.startsWith("OPENW\"") || inputString.startsWith("OPENA\"")) {
|
||||||
if (fileOpen) {
|
if (fileOpen) {
|
||||||
|
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_FILE_ALREADY_OPENED)
|
statusCode.set(STATE_CODE_FILE_ALREADY_OPENED)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,7 +212,7 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t
|
|||||||
}
|
}
|
||||||
// sanity check if path is actually enclosed with double-quote
|
// sanity check if path is actually enclosed with double-quote
|
||||||
if (commaIndex != 6 && inputString[commaIndex - 1] != '"') {
|
if (commaIndex != 6 && inputString[commaIndex - 1] != '"') {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_ILLEGAL_COMMAND)
|
statusCode.set(STATE_CODE_ILLEGAL_COMMAND)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val pathStr = inputString.substring(6, if (commaIndex == 6) inputString.lastIndex else commaIndex - 1)
|
val pathStr = inputString.substring(6, if (commaIndex == 6) inputString.lastIndex else commaIndex - 1)
|
||||||
@@ -215,21 +222,16 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t
|
|||||||
|
|
||||||
// TODO driveNum is for disk drives that may have two or more slots built; for testing purposes we'll ignore it
|
// TODO driveNum is for disk drives that may have two or more slots built; for testing purposes we'll ignore it
|
||||||
|
|
||||||
file = TevdFileDescriptor(DOM, filePath)
|
file = Clustfile(DOM, filePath)
|
||||||
printdbg("file path: ${file.canonicalPath}, drive num: $driveNum")
|
printdbg("file path: ${file.path}, drive num: $driveNum")
|
||||||
|
|
||||||
if (openMode == 'R' && !file.exists()) {
|
if (openMode == 'R' && !file.exists()) {
|
||||||
printdbg("! file not found")
|
printdbg("! file not found")
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_NO_SUCH_FILE_EXISTS)
|
statusCode.set(STATE_CODE_NO_SUCH_FILE_EXISTS)
|
||||||
return
|
|
||||||
}
|
|
||||||
else if (DOM.isReadOnly && (openMode == 'W' || openMode == 'A')) {
|
|
||||||
printdbg("! disk is read-only")
|
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_READ_ONLY)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_STANDBY)
|
statusCode.set(STATE_CODE_STANDBY)
|
||||||
fileOpen = true
|
fileOpen = true
|
||||||
fileOpenMode = when (openMode) {
|
fileOpenMode = when (openMode) {
|
||||||
'W' -> 1
|
'W' -> 1
|
||||||
@@ -240,24 +242,18 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t
|
|||||||
}
|
}
|
||||||
else if (inputString.startsWith("DELETE")) {
|
else if (inputString.startsWith("DELETE")) {
|
||||||
if (!fileOpen) {
|
if (!fileOpen) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_NO_FILE_OPENED)
|
statusCode.set(STATE_CODE_NO_FILE_OPENED)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
val (successful, whyFailed) = file.delete()
|
file.delete()
|
||||||
if (!successful) {
|
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_OPERATION_FAILED)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
printdbg("Notifying disk commit (file deleted)")
|
|
||||||
notifyDiskCommit()
|
|
||||||
}
|
}
|
||||||
catch (e: SecurityException) {
|
catch (e: SecurityException) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_SYSTEM_SECURITY_ERROR)
|
statusCode.set(STATE_CODE_SYSTEM_SECURITY_ERROR)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
catch (e1: IOException) {
|
catch (e1: IOException) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_SYSTEM_IO_ERROR)
|
statusCode.set(STATE_CODE_SYSTEM_IO_ERROR)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,7 +261,7 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t
|
|||||||
// TODO temporary behaviour to ignore any arguments
|
// TODO temporary behaviour to ignore any arguments
|
||||||
resetBuf()
|
resetBuf()
|
||||||
if (!fileOpen) {
|
if (!fileOpen) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_NO_FILE_OPENED)
|
statusCode.set(STATE_CODE_NO_FILE_OPENED)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -276,19 +272,19 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t
|
|||||||
messageComposeBuffer.write(lsfile.name.toByteArray(VM.CHARSET))
|
messageComposeBuffer.write(lsfile.name.toByteArray(VM.CHARSET))
|
||||||
}
|
}
|
||||||
|
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_STANDBY)
|
statusCode.set(STATE_CODE_STANDBY)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_NOT_A_DIRECTORY)
|
statusCode.set(STATE_CODE_NOT_A_DIRECTORY)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e: SecurityException) {
|
catch (e: SecurityException) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_SYSTEM_SECURITY_ERROR)
|
statusCode.set(STATE_CODE_SYSTEM_SECURITY_ERROR)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
catch (e1: IOException) {
|
catch (e1: IOException) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_SYSTEM_IO_ERROR)
|
statusCode.set(STATE_CODE_SYSTEM_IO_ERROR)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -296,28 +292,28 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t
|
|||||||
// TODO temporary behaviour to ignore any arguments
|
// TODO temporary behaviour to ignore any arguments
|
||||||
resetBuf()
|
resetBuf()
|
||||||
if (!fileOpen) {
|
if (!fileOpen) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_NO_FILE_OPENED)
|
statusCode.set(STATE_CODE_NO_FILE_OPENED)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
messageComposeBuffer.write(getSizeStr().toByteArray(VM.CHARSET))
|
messageComposeBuffer.write(getSizeStr().toByteArray(VM.CHARSET))
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_STANDBY)
|
statusCode.set(STATE_CODE_STANDBY)
|
||||||
}
|
}
|
||||||
else if (inputString.startsWith("LIST")) {
|
else if (inputString.startsWith("LIST")) {
|
||||||
// TODO temporary behaviour to ignore any arguments
|
// TODO temporary behaviour to ignore any arguments
|
||||||
resetBuf()
|
resetBuf()
|
||||||
if (!fileOpen) {
|
if (!fileOpen) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_NO_FILE_OPENED)
|
statusCode.set(STATE_CODE_NO_FILE_OPENED)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
messageComposeBuffer.write(getReadableLs().toByteArray(VM.CHARSET))
|
messageComposeBuffer.write(getReadableLs().toByteArray(VM.CHARSET))
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_STANDBY)
|
statusCode.set(STATE_CODE_STANDBY)
|
||||||
}
|
}
|
||||||
else if (inputString.startsWith("CLOSE")) {
|
else if (inputString.startsWith("CLOSE")) {
|
||||||
fileOpen = false
|
fileOpen = false
|
||||||
fileOpenMode = -1
|
fileOpenMode = -1
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_STANDBY)
|
statusCode.set(STATE_CODE_STANDBY)
|
||||||
}
|
}
|
||||||
else if (inputString.startsWith("READ")) {
|
else if (inputString.startsWith("READ")) {
|
||||||
//readModeLength = inputString.substring(4 until inputString.length).toInt()
|
//readModeLength = inputString.substring(4 until inputString.length).toInt()
|
||||||
@@ -326,14 +322,14 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t
|
|||||||
if (file.isFile) {
|
if (file.isFile) {
|
||||||
try {
|
try {
|
||||||
messageComposeBuffer.write(file.readBytes())
|
messageComposeBuffer.write(file.readBytes())
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_STANDBY)
|
statusCode.set(STATE_CODE_STANDBY)
|
||||||
}
|
}
|
||||||
catch (e: IOException) {
|
catch (e: IOException) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_SYSTEM_IO_ERROR)
|
statusCode.set(STATE_CODE_SYSTEM_IO_ERROR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_OPERATION_NOT_PERMITTED)
|
statusCode.set(STATE_CODE_OPERATION_NOT_PERMITTED)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -347,13 +343,7 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t
|
|||||||
|
|
||||||
// TODO driveNum is for disk drives that may have two or more slots built; for testing purposes we'll ignore it
|
// TODO driveNum is for disk drives that may have two or more slots built; for testing purposes we'll ignore it
|
||||||
|
|
||||||
if (DOM.isReadOnly) {
|
statusCode.set(STATE_CODE_STANDBY)
|
||||||
printdbg("! disk is read-only")
|
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_READ_ONLY)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_STANDBY)
|
|
||||||
fileOpen = true
|
fileOpen = true
|
||||||
fileOpenMode = 17
|
fileOpenMode = 17
|
||||||
blockSendCount = 0
|
blockSendCount = 0
|
||||||
@@ -368,163 +358,146 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t
|
|||||||
|
|
||||||
// TODO driveNum is for disk drives that may have two or more slots built; for testing purposes we'll ignore it
|
// TODO driveNum is for disk drives that may have two or more slots built; for testing purposes we'll ignore it
|
||||||
|
|
||||||
val bootFile = DOM.requestFile(1)
|
|
||||||
|
|
||||||
printdbg("bootFile = $bootFile, ID: 1, exists = ${bootFile != null}")
|
|
||||||
|
|
||||||
if (bootFile == null) {
|
|
||||||
printdbg("bootfile not exists!")
|
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_NO_SUCH_FILE_EXISTS)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
val retMsg = (bootFile.contents as EntryFile).getContent().sliceArray(0 until BLOCK_SIZE) //VDUtil.getAsNormalFile(DOM, 1).getContent().sliceArray(0 until BLOCK_SIZE)
|
val retMsg = DOM.readBoot()
|
||||||
|
|
||||||
printdbg("retMsg = ${retMsg.toString(VM.CHARSET)}")
|
|
||||||
|
|
||||||
recipient?.writeout(retMsg)
|
recipient?.writeout(retMsg)
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_STANDBY)
|
statusCode.set(STATE_CODE_STANDBY)
|
||||||
}
|
}
|
||||||
catch (e: IOException) {
|
catch (e: IOException) {
|
||||||
printdbg("exception:")
|
statusCode.set(STATE_CODE_SYSTEM_IO_ERROR)
|
||||||
e.printStackTrace()
|
|
||||||
|
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_SYSTEM_IO_ERROR)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (inputString.startsWith("MKDIR")) {
|
else if (inputString.startsWith("MKDIR")) {
|
||||||
if (!fileOpen) {
|
if (!fileOpen) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_NO_FILE_OPENED)
|
statusCode.set(STATE_CODE_NO_FILE_OPENED)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (fileOpenMode < 1) {
|
if (fileOpenMode < 1) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_OPERATION_NOT_PERMITTED)
|
statusCode.set(STATE_CODE_OPERATION_NOT_PERMITTED)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
val (status, whyFailed) = file.mkdir()
|
val status = file.mkdir()
|
||||||
statusCode.set(if (status) 0 else 1)
|
statusCode.set(if (status) 0 else 1)
|
||||||
if (status) {
|
|
||||||
printdbg("Notifying disk commit (mkdir)")
|
|
||||||
notifyDiskCommit()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (e: SecurityException) {
|
catch (e: SecurityException) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_SYSTEM_SECURITY_ERROR)
|
statusCode.set(STATE_CODE_SYSTEM_SECURITY_ERROR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (inputString.startsWith("MKFILE")) {
|
else if (inputString.startsWith("MKFILE")) {
|
||||||
if (!fileOpen) {
|
if (!fileOpen) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_NO_FILE_OPENED)
|
statusCode.set(STATE_CODE_NO_FILE_OPENED)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (fileOpenMode < 1) {
|
if (fileOpenMode < 1) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_OPERATION_NOT_PERMITTED)
|
statusCode.set(STATE_CODE_OPERATION_NOT_PERMITTED)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
val (f1, whyFailed) = file.createNewFile()
|
val f1 = file.createNewFile()
|
||||||
statusCode.set(if (f1) TestDiskDrive.STATE_CODE_STANDBY else TestDiskDrive.STATE_CODE_OPERATION_FAILED)
|
statusCode.set(if (f1) STATE_CODE_STANDBY else STATE_CODE_OPERATION_FAILED)
|
||||||
if (f1) {
|
|
||||||
printdbg("Notifying disk commit (mkfile)")
|
|
||||||
notifyDiskCommit()
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
catch (e: IOException) {
|
catch (e: IOException) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_SYSTEM_IO_ERROR)
|
statusCode.set(STATE_CODE_SYSTEM_IO_ERROR)
|
||||||
}
|
}
|
||||||
catch (e1: SecurityException) {
|
catch (e1: SecurityException) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_SYSTEM_SECURITY_ERROR)
|
statusCode.set(STATE_CODE_SYSTEM_SECURITY_ERROR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (inputString.startsWith("TOUCH")) {
|
else if (inputString.startsWith("TOUCH")) {
|
||||||
if (!fileOpen) {
|
if (!fileOpen) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_NO_FILE_OPENED)
|
statusCode.set(STATE_CODE_NO_FILE_OPENED)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (fileOpenMode < 1) {
|
if (fileOpenMode < 1) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_OPERATION_NOT_PERMITTED)
|
statusCode.set(STATE_CODE_OPERATION_NOT_PERMITTED)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
val (f1, whyFailed) = file.setLastModified(vm.worldInterface.currentTimeInMills())
|
val f1 = file.setLastModified(vm.worldInterface.currentTimeInMills())
|
||||||
statusCode.set(if (f1) TestDiskDrive.STATE_CODE_STANDBY else TestDiskDrive.STATE_CODE_OPERATION_FAILED)
|
statusCode.set(if (f1) STATE_CODE_STANDBY else STATE_CODE_OPERATION_FAILED)
|
||||||
if (f1) {
|
|
||||||
printdbg("Notifying disk commit (touch)")
|
|
||||||
notifyDiskCommit()
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
catch (e: IOException) {
|
catch (e: IOException) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_SYSTEM_IO_ERROR)
|
statusCode.set(STATE_CODE_SYSTEM_IO_ERROR)
|
||||||
}
|
}
|
||||||
catch (e1: SecurityException) {
|
catch (e1: SecurityException) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_SYSTEM_SECURITY_ERROR)
|
statusCode.set(STATE_CODE_SYSTEM_SECURITY_ERROR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (inputString.startsWith("WRITE")) {
|
else if (inputString.startsWith("WRITE")) {
|
||||||
if (!fileOpen) {
|
if (!fileOpen) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_NO_FILE_OPENED)
|
statusCode.set(STATE_CODE_NO_FILE_OPENED)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (fileOpenMode < 0) {
|
if (fileOpenMode < 0) {
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_OPERATION_NOT_PERMITTED)
|
statusCode.set(STATE_CODE_OPERATION_NOT_PERMITTED)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!file.exists()) {
|
if (fileOpenMode == 1) { writeMode = true; appendMode = false }
|
||||||
val (f1, whyFailed) = file.createNewFile()
|
else if (fileOpenMode == 2) { writeMode = false; appendMode = true }
|
||||||
statusCode.set(if (f1) TestDiskDrive.STATE_CODE_STANDBY else TestDiskDrive.STATE_CODE_OPERATION_FAILED)
|
|
||||||
if (!f1) { return }
|
|
||||||
}
|
|
||||||
// if (fileOpenMode == 1) { writeMode = true; appendMode = false }
|
|
||||||
// else if (fileOpenMode == 2) { writeMode = false; appendMode = true }
|
|
||||||
writeModeLength = inputString.substring(5, inputString.length).toInt()
|
writeModeLength = inputString.substring(5, inputString.length).toInt()
|
||||||
|
|
||||||
printdbg("WRITE issued with len $writeModeLength")
|
|
||||||
|
|
||||||
writeBuffer = ByteArray(writeModeLength)
|
writeBuffer = ByteArray(writeModeLength)
|
||||||
writeBufferUsage = 0
|
writeBufferUsage = 0
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_STANDBY)
|
statusCode.set(STATE_CODE_STANDBY)
|
||||||
}
|
}
|
||||||
else if (inputString.startsWith("USAGE")) {
|
else if (inputString.startsWith("USAGE")) {
|
||||||
recipient?.writeout(TestDiskDrive.composePositiveAns("USED${DOM.usedBytes}/TOTAL${DOM.capacity}"))
|
recipient?.writeout(composePositiveAns("USED123456/TOTAL654321"))
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_STANDBY)
|
statusCode.set(STATE_CODE_STANDBY)
|
||||||
}
|
}
|
||||||
else if (inputString.startsWith("TEVDDISCARDDRIVE\"")) {
|
else
|
||||||
// the actual capacity of the floppy must be determined when the floppy gameitem was created
|
statusCode.set(STATE_CODE_ILLEGAL_COMMAND)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (DOM.isReadOnly) {
|
val diskID: UUID = UUID(0, 0)
|
||||||
printdbg("! disk is read-only")
|
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_READ_ONLY)
|
private fun getReadableLs(): String {
|
||||||
return
|
val sb = StringBuilder()
|
||||||
|
val isRoot = (file.path == "")
|
||||||
|
|
||||||
|
if (file.isFile) sb.append(file.name)
|
||||||
|
else {
|
||||||
|
sb.append("Current directory: ")
|
||||||
|
sb.append(if (isRoot) "(root)" else file.path)
|
||||||
|
sb.append('\n')
|
||||||
|
|
||||||
|
sb.append(".\n")
|
||||||
|
if (isRoot) sb.append("..\n")
|
||||||
|
// actual entries
|
||||||
|
file.listFiles()!!.forEach {
|
||||||
|
var filenameLen = it.name.length
|
||||||
|
|
||||||
|
sb.append(it.name)
|
||||||
|
|
||||||
|
if (it.isDirectory) {
|
||||||
|
sb.append("/")
|
||||||
|
filenameLen += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
var commaIndex = inputString.lastIndex
|
sb.append(" ".repeat(40 - filenameLen))
|
||||||
while (commaIndex > 6) {
|
|
||||||
if (inputString[commaIndex] == ',') break; commaIndex -= 1
|
|
||||||
}
|
|
||||||
// sanity check if path is actually enclosed with double-quote
|
|
||||||
if (commaIndex != 6 && inputString[commaIndex - 1] != '"') {
|
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_ILLEGAL_COMMAND)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val newName = inputString.substring(6, if (commaIndex == 6) inputString.lastIndex else commaIndex - 1)
|
|
||||||
val driveNum =
|
|
||||||
if (commaIndex == 6) null else inputString.substring(commaIndex + 1, inputString.length).toInt()
|
|
||||||
|
|
||||||
// TODO driveNum is for disk drives that may have two or more slots built; for testing purposes we'll ignore it
|
if (it.isFile) {
|
||||||
|
sb.append("${it.length()} B")
|
||||||
|
}
|
||||||
|
|
||||||
TODO()
|
sb.append('\n')
|
||||||
// DOM.entries.clear()
|
|
||||||
// DOM.diskName = newName.toByteArray(VM.CHARSET)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printdbg("Illegal command: ${inputString}")
|
|
||||||
statusCode.set(TestDiskDrive.STATE_CODE_ILLEGAL_COMMAND)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return if (sb.last() == '\n') sb.substring(0, sb.lastIndex) else sb.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSizeStr(): String {
|
||||||
|
val sb = StringBuilder()
|
||||||
|
// val isRoot = (file.absolutePath == rootPath.absolutePath)
|
||||||
|
|
||||||
|
if (file.isFile) sb.append(file.length())
|
||||||
|
else sb.append(file.listFiles()!!.size)
|
||||||
|
|
||||||
|
return sb.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sanitisePath(s: String) = s.replace('\\','/').replace(Regex("""\?<>:\*\|"""),"-")
|
private fun sanitisePath(s: String) = s.replace('\\','/').replace(Regex("""\?<>:\*\|"""),"-")
|
||||||
@@ -557,63 +530,4 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t
|
|||||||
return newPaths.joinToString("/")
|
return newPaths.joinToString("/")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getReadableLs(): String {
|
|
||||||
val sb = StringBuilder()
|
|
||||||
val isRoot = (file.entryID == 0)
|
|
||||||
|
|
||||||
if (file.isFile) sb.append(file.name)
|
|
||||||
else {
|
|
||||||
var filesCount = 0
|
|
||||||
var dirsCount = 0
|
|
||||||
|
|
||||||
sb.append("Current directory: ")
|
|
||||||
sb.append(if (isRoot) "(root)" else file.path)
|
|
||||||
sb.append('\n')
|
|
||||||
|
|
||||||
sb.append(".\n")
|
|
||||||
if (isRoot) sb.append("..\n")
|
|
||||||
// actual entries
|
|
||||||
file.listFiles()!!.forEach {
|
|
||||||
var filenameLen = it.name.length
|
|
||||||
|
|
||||||
sb.append(it.name)
|
|
||||||
|
|
||||||
if (it.isDirectory) {
|
|
||||||
sb.append("/")
|
|
||||||
filenameLen += 1
|
|
||||||
|
|
||||||
dirsCount += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.append(" ".repeat(40 - filenameLen))
|
|
||||||
|
|
||||||
if (it.isFile) {
|
|
||||||
sb.append("${it.length()} B")
|
|
||||||
|
|
||||||
filesCount += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.append('\n')
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.append("\n")
|
|
||||||
sb.append("\n$filesCount Files, $dirsCount, Directories")
|
|
||||||
sb.append("\nDisk used ${DOM.usedBytes} bytes")
|
|
||||||
sb.append("\n${DOM.capacity - DOM.usedBytes} bytes free")
|
|
||||||
if (DOM.isReadOnly)
|
|
||||||
sb.append("\nThe disk is read-only!")
|
|
||||||
}
|
|
||||||
|
|
||||||
return if (sb.last() == '\n') sb.substring(0, sb.lastIndex) else sb.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSizeStr(): String {
|
|
||||||
val sb = StringBuilder()
|
|
||||||
|
|
||||||
if (file.isFile) sb.append(file.length())
|
|
||||||
else sb.append(file.listFiles()!!.size)
|
|
||||||
|
|
||||||
return sb.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -64,12 +64,12 @@ class VMEmuExecutableWrapper(val windowWidth: Int, val windowHeight: Int, var pa
|
|||||||
*/
|
*/
|
||||||
class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX: Int, var panelsY: Int, val diskPathRoot: String) : ApplicationAdapter() {
|
class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX: Int, var panelsY: Int, val diskPathRoot: String) : ApplicationAdapter() {
|
||||||
|
|
||||||
val TEVD_COMMIT = TevdPartialDomCommitWatchdog
|
// val TEVD_COMMIT = TevdPartialDomCommitWatchdog
|
||||||
val TEVD_SYNC = TevdPartialDomCommitWatchdog
|
// val TEVD_SYNC = TevdPartialDomCommitWatchdog
|
||||||
|
|
||||||
val watchdogs = hashMapOf<String, VMWatchdog>(
|
val watchdogs = hashMapOf<String, VMWatchdog>(
|
||||||
"TEVD_COMMIT" to TEVD_COMMIT,
|
// "TEVD_COMMIT" to TEVD_COMMIT,
|
||||||
"TEVD_SYNC" to TEVD_SYNC
|
// "TEVD_SYNC" to TEVD_SYNC
|
||||||
)
|
)
|
||||||
|
|
||||||
data class VMRunnerInfo(val vm: VM, val profileName: String)
|
data class VMRunnerInfo(val vm: VM, val profileName: String)
|
||||||
|
|||||||
Reference in New Issue
Block a user