diff --git a/assets/tvdos/TVDOS.SYS b/assets/tvdos/TVDOS.SYS index d860ce7..8a39bb0 100644 --- a/assets/tvdos/TVDOS.SYS +++ b/assets/tvdos/TVDOS.SYS @@ -63,9 +63,12 @@ filesystem.readAll = function(driveLetter) { let port = filesystem._toPorts(driveLetter); com.sendMessage(port[0], "READ"); let response = com.getStatusCode(port[0]); + if (135 == response) { + throw Error("File not opened"); + } if (response < 0 || response >= 128) { let status = com.getDeviceStatus(port[0]); - throw Error("Reading a file failed with "+status.code+": "+status.message); + throw Error("Reading a file failed with "+response+": "+status.message); } return com.pullMessage(port[0]); }; @@ -79,6 +82,19 @@ filesystem.isDirectory = function(driveLetter) { } return (response === 0); } +filesystem.mkDir = function(driveLetter) { + let port = filesystem._toPorts(driveLetter); + com.sendMessage(port[0], "MKDIR"); + let response = com.getStatusCode(port[0]); + if (135 == response) { + throw Error("File not opened"); + } + if (response < 0 || response >= 128) { + let status = com.getDeviceStatus(port[0]); + throw Error("Creating a directory failed with ("+response+"): "+status.message+"\n"); + } + return (response === 0); // possible status codes: 0 (success), 1 (fail) +} Object.freeze(filesystem); /////////////////////////////////////////////////////////////////////////////// diff --git a/assets/tvdos/bin/command.js b/assets/tvdos/bin/command.js index 4cf4efb..f286cc4 100644 --- a/assets/tvdos/bin/command.js +++ b/assets/tvdos/bin/command.js @@ -123,6 +123,18 @@ shell.parse = function(input) { return tokens; } +function resolvePathInput(input) { + // replace slashes into revslashes + let pathstr = input.replaceAll('/','\\\\'); + let startsWithSlash = input.startsWith('\\'); + + // split them into an array while filtering empty elements except for the root 'head' + let newPwd = (startsWithSlash ? [""] : shell_pwd).concat(pathstr.split("\\").filter(function(it) { return (it.length > 0); })); + // construct new pathstr from pwd arr so it will be sanitised + pathstr = newPwd.join('\\').substring(1); + + return { string: pathstr, pwd: newPwd }; +} shell.coreutils = { /* Args follow this format: * <1st arg> <2nd arg> ... @@ -137,25 +149,28 @@ shell.coreutils = { println(CURRENT_DRIVE+":"+shell_pwd.join("\\")); return } - - // replace slashes into revslashes - let pathstr = args[1].replaceAll('/','\\\\'); - - let startsWithSlash = args[1].startsWith('\\'); - - // split them into an array while filtering empty elements except for the root 'head' - let newPwd = (startsWithSlash ? [""] : shell_pwd).concat(pathstr.split("\\").filter(function(it) { return (it.length > 0); })); - // construct new pathstr from pwd arr so it will be sanitised - pathstr = newPwd.join('\\').substring(1); - - if (DEBUG_PRINT) serial.println("command.js > pathstr = "+pathstr); + let path = resolvePathInput(args[1]) + if (DEBUG_PRINT) serial.println("command.js > cd > pathstr = "+path.string); // check if path is valid - filesystem.open(CURRENT_DRIVE, pathstr, 'R'); + filesystem.open(CURRENT_DRIVE, path.string, 'R'); let dirOpened = filesystem.isDirectory(CURRENT_DRIVE); // open a dir; if path is nonexistent, file won't actually be opened - if (!dirOpened) { printerrln("CHDIR failed for '"+pathstr+"'"); return; } // if file is not opened, FALSE will be returned + if (!dirOpened) { printerrln("CHDIR failed for '"+path.string+"'"); return; } // if file is not opened, FALSE will be returned - shell_pwd = newPwd; + shell_pwd = path.pwd; + }, + mkdir: function(args) { + if (args[1] === undefined) { + printerrln("Syntax error"); + return + } + let path = resolvePathInput(args[1]) + if (DEBUG_PRINT) serial.println("command.js > mkdir > pathstr = "+path.string); + + // check if path is valid + let dirOpened = filesystem.open(CURRENT_DRIVE, path.string, 'W'); + let mkdird = filesystem.mkDir(CURRENT_DRIVE); + if (!mkdird) { printerrln("MKDIR failed for '"+path.string+"'"); return; } }, cls: function(args) { con.clear(); @@ -212,13 +227,14 @@ shell.coreutils = { // check if path is valid let pathOpened = filesystem.open(CURRENT_DRIVE, pathstr, 'R'); - if (!pathOpened) { printerrln("CHDIR failed for '"+pathstr+"'"); return; } + if (!pathOpened) { printerrln("File not found"); return; } let port = filesystem._toPorts(CURRENT_DRIVE)[0] com.sendMessage(port, "LIST"); println(com.pullMessage(port)); } }; +shell.coreutils.chdir = shell.coreutils.cd; Object.freeze(shell.coreutils); shell.execute = function(line) { if (0 == line.size) return; diff --git a/src/net/torvald/tsvm/SerialHelper.kt b/src/net/torvald/tsvm/SerialHelper.kt index d411550..28c39b6 100644 --- a/src/net/torvald/tsvm/SerialHelper.kt +++ b/src/net/torvald/tsvm/SerialHelper.kt @@ -94,7 +94,7 @@ object SerialHelper { while (!checkIfDeviceIsReady(vm, portNo)) { Thread.sleep(SLEEP_TIME) } } - fun getStatusCode(vm: VM, portNo: Int) = vm.getIO().mmio_read(4080L + portNo) + fun getStatusCode(vm: VM, portNo: Int) = vm.getIO().mmio_read(4080L + portNo)!!.toInt().and(255) fun checkIfDeviceIsThere(vm: VM, portNo: Int) = (vm.getIO().mmio_read(4092L + portNo)!! and 1.toByte()) == 1.toByte() diff --git a/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt b/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt index 87229ad..3b477c5 100644 --- a/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt +++ b/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt @@ -11,6 +11,8 @@ class TestDiskDrive(private val driveNum: Int, theRootPath: File? = null) : Bloc 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_FILE_NOT_FOUND = 129 const val STATE_CODE_FILE_ALREADY_OPENED = 130 @@ -27,6 +29,8 @@ class TestDiskDrive(private val driveNum: Int, theRootPath: File? = null) : Bloc init { errorMsgs[STATE_CODE_STANDBY] = "READY" + errorMsgs[STATE_CODE_OPERATION_FAILED] = "OPERATION FAILED" + errorMsgs[STATE_CODE_ILLEGAL_COMMAND] = "SYNTAX ERROR" errorMsgs[STATE_CODE_FILE_NOT_FOUND] = "FILE NOT FOUND" errorMsgs[STATE_CODE_FILE_ALREADY_OPENED] = "FILE ALREADY OPENED" @@ -300,6 +304,23 @@ class TestDiskDrive(private val driveNum: Int, theRootPath: File? = null) : Bloc fis.close() } } + else if (inputString.startsWith("MKDIR")) { + if (!fileOpen) { + statusCode = STATE_CODE_FILE_NOT_FOUND + return + } + if (fileOpenMode < 1) { + statusCode = STATE_CODE_OPERATION_NOT_PERMITTED + return + } + try { + val status = file.mkdir() + statusCode = if (status) 0 else 1 + } + catch (e: SecurityException) { + statusCode = STATE_CODE_SYSTEM_SECURITY_ERROR + } + } else if (inputString.startsWith("WRITE")) { if (!fileOpen) { statusCode = STATE_CODE_FILE_NOT_FOUND