#!/usr/bin/python3 import inspect import unittest import re from datetime import datetime from difflib import unified_diff from os import statvfs, uname, utime, rename, environ, access, R_OK, W_OK from os.path import exists, isdir, join from pathlib import Path from shutil import copy from subprocess import call, check_call, CalledProcessError, DEVNULL, TimeoutExpired from sys import argv, exit, modules from time import mktime from common_framework import (BaseTestCase, main, mkstring, IPROMPT, KNOWNFAIL, UNSUPPORTED) from func_cpu_trap_flag import cpu_trap_flag from func_ds2_file_seek_tell import ds2_file_seek_tell from func_ds2_file_seek_read import ds2_file_seek_read from func_ds2_set_fattrs import ds2_set_fattrs from func_ds3_file_access import ds3_file_access from func_ds3_lock_concurrent import ds3_lock_concurrent from func_ds3_lock_two_handles import ds3_lock_two_handles from func_ds3_lock_readlckd import ds3_lock_readlckd from func_ds3_lock_readonly import ds3_lock_readonly from func_ds3_lock_twice import ds3_lock_twice from func_ds3_lock_writable import ds3_lock_writable from func_ds3_share_open_access import ds3_share_open_access from func_ds3_share_open_twice import ds3_share_open_twice from func_lfs_file_info import lfs_file_info from func_lfs_file_seek_tell import lfs_file_seek_tell from func_memory_ems_borland import memory_ems_borland from func_mfs_findfile import mfs_findfile from func_mfs_truename import mfs_truename SYSTYPE_DRDOS_ENHANCED = "Enhanced DR-DOS" SYSTYPE_DRDOS_ORIGINAL = "Original DR-DOS" SYSTYPE_DRDOS_OLD = "Old DR-DOS" SYSTYPE_PCDOS_NEW = "New PC-DOS" SYSTYPE_PCDOS_OLD = "Old PC-DOS" SYSTYPE_MSDOS_NEW = "New MS-DOS" SYSTYPE_MSDOS_INTERMEDIATE = "Newer MS-DOS" SYSTYPE_MSDOS_OLD = "Old MS-DOS" SYSTYPE_MSDOS_NEC = "NEC MS-DOS" SYSTYPE_FRDOS_OLD = "Old FreeDOS" SYSTYPE_FRDOS_NEW = "FreeDOS" SYSTYPE_FDPP = "FDPP" PRGFIL_SFN = "PROGR~-I" PRGFIL_LFN = "Program Files" class OurTestCase(BaseTestCase): pname = "test_dos" # Tests using assembler def _test_mfs_directory_common(self, nametype, operation): if nametype == "LFN": ename = "mfslfn" testname = "test very long directory" elif nametype == "SFN": ename = "mfssfn" testname = "testdir" else: self.fail("Incorrect argument") testdir = self.mkworkdir('d') cwdnum = "0x0" if operation == "Create": ename += "dc" if nametype == "SFN": intnum = "0x3900" # create else: intnum = "0x7139" elif operation in ["Delete", "DeleteNotEmpty"]: ename += "dd" if nametype == "SFN": intnum = "0x3a00" # delete else: intnum = "0x713a" Path(testdir / testname).mkdir() if operation == "DeleteNotEmpty": self.mkfile("DirNotEm.pty", """hello\r\n""", join(testdir, testname)) elif operation == "Chdir": ename += "dh" if nametype == "SFN": intnum = "0x3b00" # chdir cwdnum = "0x4700" # getcwd else: intnum = "0x713b" cwdnum = "0x7147" Path(testdir / testname).mkdir() else: self.fail("Incorrect argument") self.mkfile("testit.bat", """\ d: c:\\%s rem end """ % ename, newline="\r\n") # compile sources self.mkcom_with_gas(ename, r""" .text .code16 .globl _start16 _start16: push %%cs pop %%ds movw $%s, %%ax movw $dname, %%dx int $0x21 jnc prsucc prfail: movw $failmsg, %%dx jmp 1f prsucc: movw $succmsg, %%dx 1: movb $0x9, %%ah int $0x21 movw $%s, %%ax cmpw $0x7147, %%ax je prcwd cmpw $0x4700, %%ax je prcwd exit: movb $0x4c, %%ah int $0x21 prcwd: # get cwd movb $0, %%dl movw $curdir, %%si int $0x21 push %%ds pop %%es movw %%si, %%di movw $128, %%cx movb $0, %%al cld repne scasb movb $')', -1(%%di) movb $'$', (%%di) movb $0x9, %%ah movw $pcurdir, %%dx int $0x21 jmp exit dname: .asciz "%s" succmsg: .ascii "Directory Operation Success\r\n$" failmsg: .ascii "Directory Operation Failed\r\n$" pcurdir: .byte '(' curdir: .fill 128, 1, '$' """ % (intnum, cwdnum, testname)) results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """) # test to see if the directory intnum made it through to linux if operation == "Create": self.assertIn("Directory Operation Success", results) self.assertTrue(isdir(join(testdir, testname)), "Directory not created") elif operation == "Delete": self.assertIn("Directory Operation Success", results) self.assertFalse(isdir(join(testdir, testname)), "Directory not deleted") elif operation == "DeleteNotEmpty": self.assertIn("Directory Operation Failed", results) self.assertTrue(isdir(join(testdir, testname)), "Directory incorrectly deleted") elif operation == "Chdir": self.assertIn("Directory Operation Success", results) if nametype == "SFN": self.assertIn("(" + testname.upper() + ")", results) else: self.assertIn("(" + testname + ")", results) def test_mfs_sfn_directory_create(self): """MFS SFN directory create""" self._test_mfs_directory_common("SFN", "Create") def test_mfs_sfn_directory_delete(self): """MFS SFN directory delete""" self._test_mfs_directory_common("SFN", "Delete") def test_mfs_sfn_directory_delete_not_empty(self): """MFS SFN directory delete not empty""" self._test_mfs_directory_common("SFN", "DeleteNotEmpty") def test_mfs_sfn_directory_chdir(self): """MFS SFN directory change current""" self._test_mfs_directory_common("SFN", "Chdir") def test_mfs_lfn_directory_create(self): """MFS LFN directory create""" self._test_mfs_directory_common("LFN", "Create") def test_mfs_lfn_directory_delete(self): """MFS LFN directory delete""" self._test_mfs_directory_common("LFN", "Delete") def test_mfs_lfn_directory_delete_not_empty(self): """MFS LFN directory delete not empty""" self._test_mfs_directory_common("LFN", "DeleteNotEmpty") def test_mfs_lfn_directory_chdir(self): """MFS LFN directory change current""" self._test_mfs_directory_common("LFN", "Chdir") def _test_mfs_get_current_directory(self, nametype): if nametype == "LFN": ename = "mfslfngd" testname = PRGFIL_LFN elif nametype == "SFN": ename = "mfssfngd" testname = PRGFIL_SFN else: self.fail("Incorrect argument") testdir = self.mkworkdir('d') if nametype == "SFN": cwdnum = "0x4700" # getcwd else: cwdnum = "0x7147" Path(testdir / PRGFIL_LFN).mkdir() self.mkfile("testit.bat", """\ d: cd %s c:\\%s rem end """ % (PRGFIL_SFN, ename), newline="\r\n") # compile sources self.mkcom_with_gas(ename, r""" .text .code16 .globl _start16 _start16: push %%cs pop %%ds # get cwd movw $%s, %%ax movb $0, %%dl movw $curdir, %%si int $0x21 push %%ds pop %%es movw %%si, %%di movw $128, %%cx movb $0, %%al cld repne scasb movb $')', -1(%%di) movb $'$', (%%di) movb $0x9, %%ah movw $pcurdir, %%dx int $0x21 exit: movb $0x4c, %%ah int $0x21 pcurdir: .byte '(' curdir: .fill 128, 1, '$' """ % cwdnum) results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """) if nametype == "SFN": self.assertIn("(" + testname.upper() + ")", results) else: self.assertIn("(" + testname + ")", results) def test_mfs_sfn_get_current_directory(self): """MFS SFN get current directory""" self._test_mfs_get_current_directory("SFN") def test_mfs_lfn_get_current_directory(self): """MFS LFN get current directory""" self._test_mfs_get_current_directory("LFN") def _test_lfn_support(self, fstype, confsw): ename = "lfnsuppt" testdir = self.mkworkdir('d') if fstype == "MFS": config = """\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """ else: # FAT config = """\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" $_floppy_a = "" """ % self.mkimage("12", cwd=testdir) config += """$_lfn_support = (%s)\n""" % confsw self.mkfile("testit.bat", """\ d: c:\\%s rem end """ % ename, newline="\r\n") # compile sources self.mkcom_with_gas(ename, r""" .text .code16 .globl _start16 _start16: push %cs pop %ds # Get current drive and store its letter in fspath movw $0x1900, %ax int $0x21 addb $'A', %al movb %al, fspath # Get Volume info # Windows95 - LONG FILENAME - GET VOLUME INFORMATION # # Call: # AX = 71A0h # DS:DX -> ASCIZ root name (e.g. "C:\") # ES:DI -> buffer for file system name # CX = size of ES:DI buffer # # Return: # CF clear if successful # AX destroyed (0000h and 0200h seen) # BX = file system flags (see #01783) # CX = maximum length of file name [usually 255] # DX = maximum length of path [usually 260] # ES:DI buffer filled (ASCIZ, e.g. "FAT","NTFS","CDFS") # # CF set on error # AX = error code # 7100h if function not supported movw $0x71a0, %ax movw $fspath, %dx # ds:dx movw $fstype, %di # es:di movw $fstypelen, %cx stc int $0x21 jc chkfail cmpb $'$', fstype je prnofstype prsuccess: movw $fstype, %di movw fstypelen, %cx movb $0, %al cld repne scasb movb $')', -1(%di) movb $'\r', (%di) movb $'\n', 1(%di) movb $'$', 2(%di) movw $success, %dx jmp exit prnofstype: movw $nofstype, %dx jmp exit prnotsupported: movw $notsupported, %dx jmp exit prcarryset: movw $carryset, %dx jmp exit chkfail: cmpw $0x7100, %ax jne prcarryset jmp prnotsupported exit: movb $0x9, %ah int $0x21 movb $0x4c, %ah int $0x21 carryset: .ascii "Carry Set\r\n$" notsupported: .ascii "Not Supported(AX=0x7100)\r\n$" nofstype: .ascii "Carry Not Set But No Filesystem Type\r\n$" success: .ascii "Operation Success(" fstype: .fill 32, 1, '$' fstypelen = (. - fstype) successend: .space 4 fspath: .asciz "?:\\" """) results = self.runDosemu("testit.bat", config=config) if fstype == "MFS": if confsw == "on": self.assertIn("Operation Success(%s)" % fstype, results) else: self.assertIn("Not Supported(AX=0x7100)", results) else: # FAT self.assertIn("Not Supported(AX=0x7100)", results) def test_lfn_mfs_support_on(self): """LFN MFS Support On""" self._test_lfn_support("MFS", "on") def test_lfn_fat_support_on(self): """LFN FAT Support On""" self._test_lfn_support("FAT", "on") def test_lfn_mfs_support_off(self): """LFN MFS Support Off""" self._test_lfn_support("MFS", "off") def test_lfn_fat_support_off(self): """LFN FAT Support Off""" self._test_lfn_support("FAT", "off") def _test_fcb_read(self, fstype): testdir = self.mkworkdir('d') if fstype == "MFS": ename = "mfsfcbrd" fcbreadconfig = """\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """ else: # FAT ename = "fatfcbrd" fcbreadconfig = """\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" $_floppy_a = "" """ % self.mkimage("12", cwd=testdir) testdata = mkstring(32) self.mkfile("testit.bat", """\ d: echo %s > test.fil c:\\%s DIR rem end """ % (testdata, ename), newline="\r\n") # compile sources self.mkcom_with_gas(ename, r""" .text .code16 .globl _start16 _start16: push %%cs pop %%ds movw $0x0f00, %%ax # open file movw $fcb, %%dx int $0x21 cmpb $0, %%al jne prfailopen movw $0x1400, %%ax # read from file movw $fcb, %%dx int $0x21 cmpb $03, %%al # partial read jne prfailread jmp prsucc prfailopen: movw $failopen, %%dx jmp 1f prfailread: movw $0x1000, %%ax # close file movw $fcb, %%dx int $0x21 movw $failread, %%dx jmp 1f prsucc: movw $succstart, %%dx movb $0x9, %%ah int $0x21 movw $0x2f00, %%ax # get DTA address in ES:BX int $0x21 movb $'$', %%es:%d(%%bx) # terminate push %%es pop %%ds movw %%bx, %%dx movb $0x9, %%ah int $0x21 movw $0x1000, %%ax # close file movw $fcb, %%dx int $0x21 push %%cs pop %%ds movw $succend, %%dx 1: movb $0x9, %%ah int $0x21 exit: movb $0x4c, %%ah int $0x21 fcb: .byte 0 # 0 default drive fn1: .ascii "% -8s" # 8 bytes fe1: .ascii "% -3s" # 3 bytes wk1: .space 24 succstart: .ascii "Operation Success($" succend: .ascii ")\r\n$" failopen: .ascii "Open Operation Failed\r\n$" failread: .ascii "Read Operation Failed\r\n$" """ % (len(testdata), "test", "fil")) results = self.runDosemu("testit.bat", config=fcbreadconfig) self.assertNotIn("Operation Failed", results) self.assertIn("Operation Success(%s)" % testdata, results) def test_fat_fcb_read(self): """FAT FCB file read simple""" self._test_fcb_read("FAT") def test_mfs_fcb_read(self): """MFS FCB file read simple""" self._test_fcb_read("MFS") def _test_fcb_read_alt_dta(self, fstype): testdir = self.mkworkdir('d') ename = "fcbradta" if fstype == "MFS": config = """\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """ else: # FAT config = """\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" $_floppy_a = "" """ % self.mkimage("12", cwd=testdir) testdata = mkstring(32) self.mkfile("testit.bat", """\ d: echo %s > test.fil c:\\%s DIR rem end """ % (testdata, ename), newline="\r\n") # compile sources self.mkcom_with_gas(ename, r""" .text .code16 .globl _start16 _start16: push %%cs pop %%ds movw $0x1a00, %%ax # set DTA movw $altdta, %%dx int $0x21 movw $0x2f00, %%ax # get DTA address in ES:BX int $0x21 movw %%cs, %%ax movw %%es, %%dx cmpw %%ax, %%dx jne prfaildtaset cmpw $altdta, %%bx jne prfaildtaset movw $0x0f00, %%ax # open file movw $fcb, %%dx int $0x21 cmpb $0, %%al jne prfailopen movw $0x1400, %%ax # read from file movw $fcb, %%dx int $0x21 cmpb $03, %%al # partial read jne prfailread jmp prsucc prfaildtaset: movw $faildtaset, %%dx jmp 1f prfailopen: movw $failopen, %%dx jmp 1f prfailread: movw $0x1000, %%ax # close file movw $fcb, %%dx int $0x21 movw $failread, %%dx jmp 1f prsucc: movw $succstart, %%dx movb $0x9, %%ah int $0x21 movw $0x2f00, %%ax # get DTA address in ES:BX int $0x21 movb $'$', %%es:%d(%%bx) # terminate push %%es pop %%ds movw %%bx, %%dx movb $0x9, %%ah int $0x21 movw $0x1000, %%ax # close file movw $fcb, %%dx int $0x21 push %%cs pop %%ds movw $succend, %%dx 1: movb $0x9, %%ah int $0x21 exit: movb $0x4c, %%ah int $0x21 fcb: .byte 0 # 0 default drive fn1: .ascii "% -8s" # 8 bytes fe1: .ascii "% -3s" # 3 bytes wk1: .space 24 succstart: .ascii "Operation Success($" succend: .ascii ")\r\n$" faildtaset: .ascii "Set DTA Operation Failed\r\n$" failopen: .ascii "Open Operation Failed\r\n$" failread: .ascii "Read Operation Failed\r\n$" altdta: .space 128 """ % (len(testdata), "test", "fil")) results = self.runDosemu("testit.bat", config=config) self.assertNotIn("Operation Failed", results) self.assertIn("Operation Success(%s)" % testdata, results) def test_fat_fcb_read_alt_dta(self): """FAT FCB file read alternate DTA""" self._test_fcb_read_alt_dta("FAT") def test_mfs_fcb_read_alt_dta(self): """MFS FCB file read alternate DTA""" self._test_fcb_read_alt_dta("MFS") def _test_fcb_write(self, fstype): testdir = self.mkworkdir('d') if fstype == "MFS": ename = "mfsfcbwr" fcbreadconfig = """\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """ else: # FAT ename = "fatfcbwr" fcbreadconfig = """\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" $_floppy_a = "" """ % self.mkimage("12", cwd=testdir) testdata = mkstring(32) self.mkfile("testit.bat", """\ d: c:\\%s DIR type test.fil rem end """ % ename, newline="\r\n") # compile sources self.mkcom_with_gas(ename, r""" .text .code16 .globl _start16 _start16: push %%cs popw %%ds movw $0x1600, %%ax # create file movw $fcb, %%dx int $0x21 cmpb $0, %%al jne prfailopen movw $data, %%si # copy data to DTA movw $0x2f00, %%ax # get DTA address in ES:BX int $0x21 movw %%bx, %%di movw $DATALEN, %%cx cld repnz movsb movw $0x1500, %%ax # write to file movw $fcb, %%dx movw $DATALEN, flrs # only the significant part int $0x21 cmpb $0, %%al jne prfailwrite movw $donewrite, %%dx jmp 2f prfailwrite: movw $failwrite, %%dx jmp 2f prfailopen: movw $failopen, %%dx jmp 1f 2: movw $0x1000, %%ax # close file push %%dx movw $fcb, %%dx int $0x21 popw %%dx 1: movb $0x9, %%ah int $0x21 exit: movb $0x4c, %%ah int $0x21 data: .ascii "Operation Success(%s)\r\n" dend: DATALEN = (dend - data) .ascii "$" # for printing fcb: .byte 0 # 0 default drive fn1: .ascii "% -8s" # 8 bytes fe1: .ascii "% -3s" # 3 bytes fcbn: .word 0 flrs: .word 0 ffsz: .long 0 fdlw: .word 0 ftlw: .word 0 res8: .space 8 fcbr: .byte 0 frrn: .long 0 failopen: .ascii "Open Operation Failed\r\n$" failwrite: .ascii "Write Operation Failed\r\n$" donewrite: .ascii "Write Operation Done\r\n$" """ % (testdata, "test", "fil")) results = self.runDosemu("testit.bat", config=fcbreadconfig) self.assertNotIn("Operation Failed", results) self.assertIn("Operation Success(%s)" % testdata, results) def test_fat_fcb_write(self): """FAT FCB file write simple""" self._test_fcb_write("FAT") def test_mfs_fcb_write(self): """MFS FCB file write simple""" self._test_fcb_write("MFS") def _test_fcb_rename_common(self, fstype, testname): testdir = self.mkworkdir('d') if testname == "simple": ename = "mfsfcbr1" fn1 = "testa" fe1 = "bat" fn2 = "testb" fe2 = "bal" self.mkfile(fn1 + "." + fe1, """hello\r\n""", testdir) elif testname == "source_missing": ename = "mfsfcbr2" fn1 = "testa" fe1 = "bat" fn2 = "testb" fe2 = "bal" elif testname == "target_exists": ename = "mfsfcbr3" fn1 = "testa" fe1 = "bat" fn2 = "testb" fe2 = "bal" self.mkfile(fn1 + "." + fe1, """hello\r\n""", testdir) self.mkfile(fn2 + "." + fe2, """hello\r\n""", testdir) elif testname == "wild_one": ename = "mfsfcbr4" fn1 = "*" fe1 = "in" fn2 = "*" fe2 = "out" for f in ["one.in", "two.in", "three.in", "four.in", "five.in", "none.ctl"]: self.mkfile(f, """hello\r\n""", testdir) elif testname == "wild_two": ename = "mfsfcbr5" fn1 = "a*" fe1 = "*" fn2 = "b*" fe2 = "out" for f in ["aone.in", "atwo.in", "athree.in", "afour.in", "afive.in", "xnone.ctl"]: self.mkfile(f, """hello\r\n""", testdir) elif testname == "wild_three": # To rename "abc001.txt ... abc099.txt" to "abc601.txt....abc699.txt" # REN abc0??.txt ???6*.* ename = "mfsfcbr6" fn1 = "abc0??" fe1 = "*" fn2 = "???6*" fe2 = "*" for f in ["abc001.txt", "abc002.txt", "abc003.txt", "abc004.txt", "abc005.txt", "abc010.txt", "xbc007.txt"]: self.mkfile(f, """hello\r\n""", testdir) elif testname == "wild_four": # To rename abc001.htm to abc001.ht # REN abc*.htm *.?? ename = "mfsfcbr7" fn1 = "abc*" fe1 = "htm" fn2 = "*" fe2 = "??" for f in ["abc001.htm", "abc002.htm", "abc003.htm", "abc004.htm", "abc005.htm", "abc010.htm", "xbc007.htm"]: self.mkfile(f, """hello\r\n""", testdir) self.mkfile("testit.bat", """\ d: c:\\%s DIR rem end """ % ename, newline="\r\n") # compile sources self.mkcom_with_gas(ename, r""" .text .code16 .globl _start16 _start16: push %%cs pop %%ds movw $0x1700, %%ax movw $fcb, %%dx int $0x21 cmpb $0, %%al je prsucc prfail: movw $failmsg, %%dx jmp 1f prsucc: movw $succmsg, %%dx 1: movb $0x9, %%ah int $0x21 exit: movb $0x4c, %%ah int $0x21 fcb: .byte 0 # 0 default drive fn1: .ascii "% -8s" # 8 bytes fe1: .ascii "% -3s" # 3 bytes wk1: .space 5 fn2: .ascii "% -8s" # 8 bytes fe2: .ascii "% -3s" # 3 bytes wk2: .space 16 succmsg: .ascii "Rename Operation Success$" failmsg: .ascii "Rename Operation Failed$" """ % (fn1, fe1, fn2, fe2)) def assertIsPresent(testdir, results, fstype, f, e, msg=None): if fstype == "MFS": self.assertTrue(exists(join(testdir, f + "." + e)), msg) else: self.assertRegex(results.upper(), "%s( +|\.)%s" % (f.upper(), e.upper())) if fstype == "MFS": results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """) else: # FAT name = self.mkimage("12", cwd=testdir) results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" $_floppy_a = "" """ % name) if testname == "simple": self.assertIn("Rename Operation Success", results) assertIsPresent(testdir, results, fstype, fn2, fe2, "File not renamed") elif testname == "source_missing": self.assertIn("Rename Operation Failed", results) elif testname == "target_exists": self.assertIn("Rename Operation Failed", results) elif testname == "wild_one": self.assertIn("Rename Operation Success", results) assertIsPresent(testdir, results, fstype, "one", "out", "File not renamed") assertIsPresent(testdir, results, fstype, "two", "out", "File not renamed") assertIsPresent(testdir, results, fstype, "three", "out", "File not renamed") assertIsPresent(testdir, results, fstype, "four", "out", "File not renamed") assertIsPresent(testdir, results, fstype, "five", "out", "File not renamed") assertIsPresent(testdir, results, fstype, "none", "ctl", "File incorrectly renamed") elif testname == "wild_two": self.assertIn("Rename Operation Success", results) assertIsPresent(testdir, results, fstype, "bone", "out", "File not renamed") assertIsPresent(testdir, results, fstype, "btwo", "out", "File not renamed") assertIsPresent(testdir, results, fstype, "bthree", "out", "File not renamed") assertIsPresent(testdir, results, fstype, "bfour", "out", "File not renamed") assertIsPresent(testdir, results, fstype, "bfive", "out", "File not renamed") assertIsPresent(testdir, results, fstype, "xnone", "ctl", "File incorrectly renamed") elif testname == "wild_three": self.assertIn("Rename Operation Success", results) assertIsPresent(testdir, results, fstype, "abc601", "txt", "File not renamed") assertIsPresent(testdir, results, fstype, "abc602", "txt", "File not renamed") assertIsPresent(testdir, results, fstype, "abc603", "txt", "File not renamed") assertIsPresent(testdir, results, fstype, "abc604", "txt", "File not renamed") assertIsPresent(testdir, results, fstype, "abc605", "txt", "File not renamed") assertIsPresent(testdir, results, fstype, "abc610", "txt", "File not renamed") assertIsPresent(testdir, results, fstype, "xbc007", "txt", "File incorrectly renamed") elif testname == "wild_four": self.assertIn("Rename Operation Success", results) assertIsPresent(testdir, results, fstype, "abc001", "ht", "File not renamed") assertIsPresent(testdir, results, fstype, "abc002", "ht", "File not renamed") assertIsPresent(testdir, results, fstype, "abc003", "ht", "File not renamed") assertIsPresent(testdir, results, fstype, "abc004", "ht", "File not renamed") assertIsPresent(testdir, results, fstype, "abc005", "ht", "File not renamed") assertIsPresent(testdir, results, fstype, "abc010", "ht", "File not renamed") assertIsPresent(testdir, results, fstype, "xbc007", "htm", "File incorrectly renamed") def test_fat_fcb_rename_simple(self): """FAT FCB file rename simple""" self._test_fcb_rename_common("FAT", "simple") def test_mfs_fcb_rename_simple(self): """MFS FCB file rename simple""" self._test_fcb_rename_common("MFS", "simple") def test_fat_fcb_rename_source_missing(self): """FAT FCB file rename source missing""" self._test_fcb_rename_common("FAT", "source_missing") def test_mfs_fcb_rename_source_missing(self): """MFS FCB file rename source missing""" self._test_fcb_rename_common("MFS", "source_missing") def test_fat_fcb_rename_target_exists(self): """FAT FCB file rename target exists""" self._test_fcb_rename_common("FAT", "target_exists") def test_mfs_fcb_rename_target_exists(self): """MFS FCB file rename target exists""" self._test_fcb_rename_common("MFS", "target_exists") def test_fat_fcb_rename_wild_1(self): """FAT FCB file rename wildcard one""" self._test_fcb_rename_common("FAT", "wild_one") def test_mfs_fcb_rename_wild_1(self): """MFS FCB file rename wildcard one""" self._test_fcb_rename_common("MFS", "wild_one") def test_fat_fcb_rename_wild_2(self): """FAT FCB file rename wildcard two""" self._test_fcb_rename_common("FAT", "wild_two") def test_mfs_fcb_rename_wild_2(self): """MFS FCB file rename wildcard two""" self._test_fcb_rename_common("MFS", "wild_two") def test_fat_fcb_rename_wild_3(self): """FAT FCB file rename wildcard three""" self._test_fcb_rename_common("FAT", "wild_three") def test_mfs_fcb_rename_wild_3(self): """MFS FCB file rename wildcard three""" self._test_fcb_rename_common("MFS", "wild_three") def test_fat_fcb_rename_wild_4(self): """FAT FCB file rename wildcard four""" self._test_fcb_rename_common("FAT", "wild_four") def test_mfs_fcb_rename_wild_4(self): """MFS FCB file rename wildcard four""" self._test_fcb_rename_common("MFS", "wild_four") def _test_fcb_delete_common(self, fstype, testname): testdir = self.mkworkdir('d') if testname == "simple": ename = "fcbdel1" fn1 = "testa" fe1 = "bat" self.mkfile(fn1 + "." + fe1, """hello\r\n""", testdir) elif testname == "missing": ename = "fcbdel2" fn1 = "testa" fe1 = "bat" elif testname == "wild_one": ename = "fcbdel3" fn1 = "*" fe1 = "in" for f in ["one.in", "two.in", "three.in", "four.in", "five.in", "none.ctl"]: self.mkfile(f, """hello\r\n""", testdir) elif testname == "wild_two": ename = "fcbdel4" fn1 = "a*" fe1 = "*" for f in ["aone.in", "atwo.in", "athree.in", "afour.in", "afive.in", "xnone.ctl"]: self.mkfile(f, """hello\r\n""", testdir) elif testname == "wild_three": # To delete "abc001.txt ... abc099.txt" ename = "fcbdel5" fn1 = "abc0??" fe1 = "*" for f in ["abc001.txt", "abc002.txt", "abc003.txt", "abc004.txt", "abc005.txt", "abc010.txt", "xbc007.txt"]: self.mkfile(f, """hello\r\n""", testdir) self.mkfile("testit.bat", """\ d: c:\\%s DIR rem end """ % ename, newline="\r\n") # compile sources self.mkcom_with_gas(ename, r""" .text .code16 .globl _start16 _start16: push %%cs pop %%ds movw $0x1300, %%ax movw $fcb, %%dx int $0x21 cmpb $0, %%al je prsucc prfail: movw $failmsg, %%dx jmp 1f prsucc: movw $succmsg, %%dx 1: movb $0x9, %%ah int $0x21 exit: movb $0x4c, %%ah int $0x21 fcb: .byte 0 # 0 default drive fn1: .ascii "% -8s" # 8 bytes fe1: .ascii "% -3s" # 3 bytes wk1: .space 25 succmsg: .ascii "Delete Operation Success$" failmsg: .ascii "Delete Operation Failed$" """ % (fn1, fe1)) def assertIsPresent(testdir, results, fstype, f, e, msg=None): if fstype == "MFS": self.assertTrue(exists(join(testdir, f + "." + e)), msg) else: self.assertRegex(results.upper(), "%s( +|\.)%s" % (f.upper(), e.upper())) def assertIsNotPresent(testdir, results, fstype, f, e, msg=None): if fstype == "MFS": self.assertFalse(exists(join(testdir, f + "." + e)), msg) else: self.assertNotRegex(results.upper(), "%s( +|\.)%s" % (f.upper(), e.upper())) if fstype == "MFS": results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """) else: # FAT name = self.mkimage("12", cwd=testdir) results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" $_floppy_a = "" """ % name) if testname == "simple": self.assertIn("Delete Operation Success", results) assertIsNotPresent(testdir, results, fstype, fn1, fe1, "File not deleted") elif testname == "missing": self.assertIn("Delete Operation Failed", results) elif testname == "wild_one": self.assertIn("Delete Operation Success", results) assertIsNotPresent(testdir, results, fstype, "one", "in", "File not deleted") assertIsNotPresent(testdir, results, fstype, "two", "in", "File not deleted") assertIsNotPresent(testdir, results, fstype, "three", "in", "File not deleted") assertIsNotPresent(testdir, results, fstype, "four", "in", "File not deleted") assertIsNotPresent(testdir, results, fstype, "five", "in", "File not deleted") assertIsPresent(testdir, results, fstype, "none", "ctl", "File incorrectly deleted") elif testname == "wild_two": self.assertIn("Delete Operation Success", results) assertIsNotPresent(testdir, results, fstype, "aone", "in", "File not deleted") assertIsNotPresent(testdir, results, fstype, "atwo", "in", "File not deleted") assertIsNotPresent(testdir, results, fstype, "athree", "in", "File not deleted") assertIsNotPresent(testdir, results, fstype, "afour", "in", "File not deleted") assertIsNotPresent(testdir, results, fstype, "afive", "in", "File not deleted") assertIsPresent(testdir, results, fstype, "xnone", "ctl", "File incorrectly deleted") elif testname == "wild_three": self.assertIn("Delete Operation Success", results) assertIsNotPresent(testdir, results, fstype, "abc001", "txt", "File not deleted") assertIsNotPresent(testdir, results, fstype, "abc002", "txt", "File not deleted") assertIsNotPresent(testdir, results, fstype, "abc003", "txt", "File not deleted") assertIsNotPresent(testdir, results, fstype, "abc004", "txt", "File not deleted") assertIsNotPresent(testdir, results, fstype, "abc005", "txt", "File not deleted") assertIsNotPresent(testdir, results, fstype, "abc010", "txt", "File not deleted") assertIsPresent(testdir, results, fstype, "xbc007", "txt", "File incorrectly deleted") def test_fat_fcb_delete_simple(self): """FAT FCB file delete simple""" self._test_fcb_delete_common("FAT", "simple") def test_mfs_fcb_delete_simple(self): """MFS FCB file delete simple""" self._test_fcb_delete_common("MFS", "simple") def test_fat_fcb_delete_missing(self): """FAT FCB file delete missing""" self._test_fcb_delete_common("FAT", "missing") def test_mfs_fcb_delete_missing(self): """MFS FCB file delete missing""" self._test_fcb_delete_common("MFS", "missing") def test_fat_fcb_delete_wild_1(self): """FAT FCB file delete wildcard one""" self._test_fcb_delete_common("FAT", "wild_one") def test_mfs_fcb_delete_wild_1(self): """MFS FCB file delete wildcard one""" self._test_fcb_delete_common("MFS", "wild_one") def test_fat_fcb_delete_wild_2(self): """FAT FCB file delete wildcard two""" self._test_fcb_delete_common("FAT", "wild_two") def test_mfs_fcb_delete_wild_2(self): """MFS FCB file delete wildcard two""" self._test_fcb_delete_common("MFS", "wild_two") def test_fat_fcb_delete_wild_3(self): """FAT FCB file delete wildcard three""" self._test_fcb_delete_common("FAT", "wild_three") def test_mfs_fcb_delete_wild_3(self): """MFS FCB file delete wildcard three""" self._test_fcb_delete_common("MFS", "wild_three") def _test_fcb_find_common(self, fstype, testname): testdir = self.mkworkdir('d') if testname == "simple": ename = "fcbfind1" fn1 = "testa" fe1 = "bat" self.mkfile(fn1 + "." + fe1, """hello\r\n""", testdir) elif testname == "missing": ename = "fcbfind2" fn1 = "testa" fe1 = "bat" elif testname == "wild_one": ename = "fcbfind3" fn1 = "*" fe1 = "in" for f in ["one.in", "two.in", "three.in", "four.in", "five.in", "none.ctl"]: self.mkfile(f, """hello\r\n""", testdir) elif testname == "wild_two": ename = "fcbfind4" fn1 = "a*" fe1 = "*" for f in ["aone.in", "atwo.in", "athree.in", "afour.in", "afive.in", "xnone.ctl"]: self.mkfile(f, """hello\r\n""", testdir) elif testname == "wild_three": # To find "abc001.txt ... abc099.txt" ename = "fcbfind5" fn1 = "abc0??" fe1 = "*" for f in ["abc001.txt", "abc002.txt", "abc003.txt", "abc004.txt", "abc005.txt", "abc010.txt", "xbc007.txt"]: self.mkfile(f, """hello\r\n""", testdir) self.mkfile("testit.bat", """\ d: c:\\%s DIR rem end """ % ename, newline="\r\n") # compile sources self.mkcom_with_gas(ename, r""" .text .code16 .globl _start16 _start16: push %%cs pop %%ds # Get DTA -> ES:BX movw $0x2f00, %%ax int $0x21 pushw %%es pushw %%bx popl pdta # FindFirst findfirst: movw $0x1100, %%ax movw $fcb, %%dx int $0x21 cmpb $0, %%al je prsucc prfail: movw $failmsg, %%dx movb $0x9, %%ah int $0x21 jmp exit prsucc: movw $succmsg, %%dx movb $0x9, %%ah int $0x21 prfilename: push %%ds lds pdta, %%si inc %%si push %%cs pop %%es movw $prires, %%di inc %%di movw $11, %%cx cld repne movsb pop %%ds movw $prires, %%dx movb $0x9, %%ah int $0x21 # FindNext findnext: movw $0x1200, %%ax movw $fcb, %%dx int $0x21 cmpb $0, %%al je prfilename exit: movb $0x4c, %%ah int $0x21 fcb: .byte 0 # 0 default drive fn1: .ascii "% -8s" # 8 bytes fe1: .ascii "% -3s" # 3 bytes wk1: .space 25 pdta: .long 0 prires: .ascii "(" fname: .space 8, 20 fext: .space 3, 20 .ascii ")\r\n$" succmsg: .ascii "Find Operation Success\r\n$" failmsg: .ascii "Find Operation Failed\r\n$" """ % (fn1, fe1)) if fstype == "MFS": results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """) else: # FAT name = self.mkimage("12", cwd=testdir) results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" $_floppy_a = "" """ % name) if testname == "simple": self.assertIn("Find Operation Success", results) self.assertIn("(TESTA BAT)", results) elif testname == "missing": self.assertIn("Find Operation Failed", results) elif testname == "wild_one": self.assertIn("Find Operation Success", results) self.assertIn("(ONE IN )", results) self.assertIn("(TWO IN )", results) self.assertIn("(THREE IN )", results) self.assertIn("(FOUR IN )", results) self.assertIn("(FIVE IN )", results) self.assertNotIn("(NONE CTL)", results) elif testname == "wild_two": self.assertIn("Find Operation Success", results) self.assertIn("(AONE IN )", results) self.assertIn("(ATWO IN )", results) self.assertIn("(ATHREE IN )", results) self.assertIn("(AFOUR IN )", results) self.assertIn("(AFIVE IN )", results) self.assertNotIn("(XNONE CTL)", results) elif testname == "wild_three": self.assertIn("Find Operation Success", results) self.assertIn("(ABC001 TXT)", results) self.assertIn("(ABC002 TXT)", results) self.assertIn("(ABC003 TXT)", results) self.assertIn("(ABC004 TXT)", results) self.assertIn("(ABC005 TXT)", results) self.assertIn("(ABC010 TXT)", results) self.assertNotIn("(XBC007 TXT)", results) def test_fat_fcb_find_simple(self): """FAT FCB file find simple""" self._test_fcb_find_common("FAT", "simple") def test_mfs_fcb_find_simple(self): """MFS FCB file find simple""" self._test_fcb_find_common("MFS", "simple") def test_fat_fcb_find_missing(self): """FAT FCB file find missing""" self._test_fcb_find_common("FAT", "missing") def test_mfs_fcb_find_missing(self): """MFS FCB file find missing""" self._test_fcb_find_common("MFS", "missing") def test_fat_fcb_find_wild_1(self): """FAT FCB file find wildcard one""" self._test_fcb_find_common("FAT", "wild_one") def test_mfs_fcb_find_wild_1(self): """MFS FCB file find wildcard one""" self._test_fcb_find_common("MFS", "wild_one") def test_fat_fcb_find_wild_2(self): """FAT FCB file find wildcard two""" self._test_fcb_find_common("FAT", "wild_two") def test_mfs_fcb_find_wild_2(self): """MFS FCB file find wildcard two""" self._test_fcb_find_common("MFS", "wild_two") def test_fat_fcb_find_wild_3(self): """FAT FCB file find wildcard three""" self._test_fcb_find_common("FAT", "wild_three") def test_mfs_fcb_find_wild_3(self): """MFS FCB file find wildcard three""" self._test_fcb_find_common("MFS", "wild_three") def _test_ds2_read_eof(self, fstype): testdir = self.mkworkdir('d') ename = "ds2rdeof" if fstype == "MFS": config = """\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """ else: # FAT config = """\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" $_floppy_a = "" """ % self.mkimage("12", cwd=testdir) testdata = mkstring(32) self.mkfile("testit.bat", """\ d: echo %s > test.fil c:\\%s DIR rem end """ % (testdata, ename), newline="\r\n") # compile sources self.mkcom_with_gas(ename, r""" .text .code16 .globl _start16 _start16: push %%cs pop %%ds movw $0x3d00, %%ax # open file readonly movw $fname, %%dx int $0x21 jc prfailopen movw %%ax, fhndl movw $0x3f00, %%ax # read from file, should be partial (35) movw fhndl, %%bx movw $64, %%cx movw $fdata, %%dx int $0x21 jc prfailread cmpw $35, %%ax jne prnumread movw $0x3f00, %%ax # read from file again to get EOF movw fhndl, %%bx movw $64, %%cx movw $fdata, %%dx int $0x21 jc prcarryset cmpw $0, %%ax jne praxnotzero jmp prsucc prfailopen: movw $failopen, %%dx jmp 1f prfailread: movw $failread, %%dx jmp 2f prnumread: movw $numread, %%dx jmp 2f praxnotzero: movw $axnotzero, %%dx jmp 2f prcarryset: movw $carryset, %%dx jmp 2f prsucc: movb $')', (fdata + 32) movb $'\r', (fdata + 33) movb $'\n', (fdata + 34) movb $'$', (fdata + 35) movw $success, %%dx jmp 2f 2: movw $0x3e00, %%ax # close file movw fhndl, %%bx int $0x21 1: movb $0x9, %%ah # print string int $0x21 exit: movb $0x4c, %%ah int $0x21 fname: .asciz "%s" fhndl: .word 0 success: .ascii "Operation Success(" fdata: .space 64 failopen: .ascii "Open Operation Failed\r\n$" failread: .ascii "Read Operation Failed\r\n$" numread: .ascii "Partial Read Not 35 Chars\r\n$" carryset: .ascii "Carry Set at EOF\r\n$" axnotzero: .ascii "AX Not Zero at EOF\r\n$" """ % "test.fil") results = self.runDosemu("testit.bat", config=config) self.assertNotIn("Operation Failed", results) self.assertNotIn("Partial Read Not 35 Chars", results) self.assertNotIn("Carry Set at EOF", results) self.assertNotIn("AX Not Zero at EOF", results) self.assertIn("Operation Success(%s)" % testdata, results) def test_fat_ds2_read_eof(self): """FAT DOSv2 file read EOF""" self._test_ds2_read_eof("FAT") def test_mfs_ds2_read_eof(self): """MFS DOSv2 file read EOF""" self._test_ds2_read_eof("MFS") def _test_ds2_read_alt_dta(self, fstype): testdir = self.mkworkdir('d') ename = "ds2radta" if fstype == "MFS": config = """\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """ else: # FAT config = """\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" $_floppy_a = "" """ % self.mkimage("12", cwd=testdir) testdata = mkstring(32) self.mkfile("testit.bat", """\ d: echo %s > test.fil c:\\%s DIR rem end """ % (testdata, ename), newline="\r\n") # compile sources self.mkcom_with_gas(ename, r""" .text .code16 .globl _start16 _start16: push %%cs pop %%ds movw $0x1a00, %%ax # set DTA movw $altdta, %%dx int $0x21 movw $0x2f00, %%ax # get DTA address in ES:BX int $0x21 movw %%cs, %%ax movw %%es, %%dx cmpw %%ax, %%dx jne prfaildtaset cmpw $altdta, %%bx jne prfaildtaset movw $0x3d00, %%ax # open file readonly movw $fname, %%dx int $0x21 jc prfailopen movw %%ax, fhndl movw $0x3f00, %%ax # read from file, should be partial (35) movw fhndl, %%bx movw $64, %%cx movw $fdata, %%dx int $0x21 jc prfailread cmpw $35, %%ax jne prnumread jmp prsucc prfaildtaset: movw $faildtaset, %%dx jmp 1f prfailopen: movw $failopen, %%dx jmp 1f prfailread: movw $failread, %%dx jmp 2f prnumread: movw $numread, %%dx jmp 2f prsucc: movb $')', (fdata + 32) movb $'\r', (fdata + 33) movb $'\n', (fdata + 34) movb $'$', (fdata + 35) movw $success, %%dx jmp 2f 2: movw $0x3e00, %%ax # close file movw fhndl, %%bx int $0x21 1: movb $0x9, %%ah # print string int $0x21 exit: movb $0x4c, %%ah int $0x21 fname: .asciz "%s" fhndl: .word 0 success: .ascii "Operation Success(" fdata: .space 64 faildtaset: .ascii "Set DTA Operation Failed\r\n$" failopen: .ascii "Open Operation Failed\r\n$" failread: .ascii "Read Operation Failed\r\n$" numread: .ascii "Partial Read Not 35 Chars\r\n$" altdta: .space 128 """ % "test.fil") results = self.runDosemu("testit.bat", config=config) self.assertNotIn("Operation Failed", results) self.assertNotIn("Partial Read Not 35 Chars", results) self.assertIn("Operation Success(%s)" % testdata, results) def test_fat_ds2_read_alt_dta(self): """FAT DOSv2 file read alternate DTA""" self._test_ds2_read_alt_dta("FAT") def test_mfs_ds2_read_alt_dta(self): """MFS DOSv2 file read alternate DTA""" self._test_ds2_read_alt_dta("MFS") def test_fat_ds2_file_seek_set_read(self): """FAT DOSv2 file seek set read""" ds2_file_seek_read(self, "FAT", "SET") def test_mfs_ds2_file_seek_set_read(self): """MFS DOSv2 file seek set read""" ds2_file_seek_read(self, "MFS", "SET") def test_fat_ds2_file_seek_cur_read(self): """FAT DOSv2 file seek current read""" ds2_file_seek_read(self, "FAT", "CUR") def test_mfs_ds2_file_seek_cur_read(self): """MFS DOSv2 file seek current read""" ds2_file_seek_read(self, "MFS", "CUR") def test_fat_ds2_file_seek_end_read(self): """FAT DOSv2 file seek end read""" ds2_file_seek_read(self, "FAT", "END") def test_mfs_ds2_file_seek_end_read(self): """MFS DOSv2 file seek end read""" ds2_file_seek_read(self, "MFS", "END") def test_fat_ds2_file_seek_tell_end_back(self): """FAT DOSv2 file seek tell end back""" ds2_file_seek_tell(self, "FAT", "ENDBCKSML") def test_mfs_ds2_file_seek_tell_end_back(self): """MFS DOSv2 file seek tell end back""" ds2_file_seek_tell(self, "MFS", "ENDBCKSML") def test_fat_ds2_file_seek_tell_end_back_large(self): """FAT DOSv2 file seek tell end back large""" ds2_file_seek_tell(self, "FAT", "ENDBCKLRG") def test_mfs_ds2_file_seek_tell_end_back_large(self): """MFS DOSv2 file seek tell end back large""" ds2_file_seek_tell(self, "MFS", "ENDBCKLRG") def test_fat_ds2_file_seek_tell_end_forward(self): """FAT DOSv2 file seek tell end forward""" ds2_file_seek_tell(self, "FAT", "ENDFWDSML") def test_mfs_ds2_file_seek_tell_end_forward(self): """MFS DOSv2 file seek tell end forward""" ds2_file_seek_tell(self, "MFS", "ENDFWDSML") def test_fat_ds2_file_seek_tell_end_forward_large(self): """FAT DOSv2 file seek tell end forward large""" ds2_file_seek_tell(self, "FAT", "ENDFWDLRG") def test_mfs_ds2_file_seek_tell_end_forward_large(self): """MFS DOSv2 file seek tell end forward large""" ds2_file_seek_tell(self, "MFS", "ENDFWDLRG") def _test_ds2_rename_common(self, fstype, testname): testdir = self.mkworkdir('d') extrad = "" if testname == "file": ename = "mfsds2r1" fn1 = "testa" fe1 = "bat" fn2 = "testb" fe2 = "bal" self.mkfile(fn1 + "." + fe1, """hello\r\n""", testdir) elif testname == "file_src_missing": ename = "mfsds2r2" fn1 = "testa" fe1 = "bat" fn2 = "testb" fe2 = "bal" elif testname == "file_tgt_exists": ename = "mfsds2r3" fn1 = "testa" fe1 = "bat" fn2 = "testb" fe2 = "bal" self.mkfile(fn1 + "." + fe1, """hello\r\n""", testdir) self.mkfile(fn2 + "." + fe2, """hello\r\n""", testdir) elif testname == "dir": ename = "mfsds2r4" fn1 = "testa" fe1 = "" fn2 = "testb" fe2 = "" extrad = "mkdir %s\n" % fn1 elif testname == "dir_src_missing": ename = "mfsds2r5" fn1 = "testa" fe1 = "" fn2 = "testb" fe2 = "" elif testname == "dir_tgt_exists": ename = "mfsds2r6" fn1 = "testa" fe1 = "" fn2 = "testb" fe2 = "" extrad = "mkdir %s\nmkdir %s\n" % (fn1, fn2) self.mkfile("testit.bat", """\ d: %s c:\\%s DIR rem end """ % (extrad, ename), newline="\r\n") # compile sources self.mkcom_with_gas(ename, r""" .text .code16 .globl _start16 _start16: push %%cs pop %%ds push %%cs pop %%es movw $0x5600, %%ax movw $src, %%dx movw $dst, %%di int $0x21 jnc prsucc prfail: movw $failmsg, %%dx jmp 1f prsucc: movw $succmsg, %%dx 1: movb $0x9, %%ah int $0x21 exit: movb $0x4c, %%ah int $0x21 src: .asciz "%s" # Full path dst: .asciz "%s" # Full path succmsg: .ascii "Rename Operation Success$" failmsg: .ascii "Rename Operation Failed$" """ % (fn1 + "." + fe1, fn2 + "." + fe2)) def assertIsPresent(testdir, results, fstype, f, e, msg=None): if fstype == "MFS": self.assertTrue(exists(join(testdir, f + "." + e)), msg) else: self.assertRegex(results.upper(), "%s( +|\.)%s" % (f.upper(), e.upper()), msg) def assertIsPresentDir(testdir, results, fstype, f, msg=None): if fstype == "MFS": self.assertTrue(exists(join(testdir, f)), msg) else: # 2019-06-27 11:29 DOSEMU # DOSEMU 06-27-19 5:33p # TESTB 8-17-20 2:03p self.assertRegex(results.upper(), r"\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}\s\s+%s" r"|" r"%s\s+\s+\d{1,2}-\d{1,2}-\d{2}\s+\d+:\d+[AaPp]" % (f.upper(), f.upper()), msg) if fstype == "MFS": results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """) else: # FAT name = self.mkimage("12", cwd=testdir) results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" $_floppy_a = "" """ % name) if testname == "file": self.assertIn("Rename Operation Success", results) assertIsPresent(testdir, results, fstype, fn2, fe2, "File not renamed") elif testname == "file_src_missing": self.assertIn("Rename Operation Failed", results) elif testname == "file_tgt_exists": self.assertIn("Rename Operation Failed", results) elif testname == "dir": self.assertIn("Rename Operation Success", results) assertIsPresentDir(testdir, results, fstype, fn2, "Directory not renamed") elif testname == "dir_src_missing": self.assertIn("Rename Operation Failed", results) elif testname == "dir_tgt_exists": self.assertIn("Rename Operation Failed", results) def test_fat_ds2_rename_file(self): """FAT DOSv2 rename file""" self._test_ds2_rename_common("FAT", "file") def test_mfs_ds2_rename_file(self): """MFS DOSv2 rename file""" self._test_ds2_rename_common("MFS", "file") def test_fat_ds2_rename_file_src_missing(self): """FAT DOSv2 rename file src missing""" self._test_ds2_rename_common("FAT", "file_src_missing") def test_mfs_ds2_rename_file_src_missing(self): """MFS DOSv2 rename file src missing""" self._test_ds2_rename_common("MFS", "file_src_missing") def test_fat_ds2_rename_file_tgt_exists(self): """FAT DOSv2 rename file tgt exists""" self._test_ds2_rename_common("FAT", "file_tgt_exists") def test_mfs_ds2_rename_file_tgt_exists(self): """MFS DOSv2 rename file tgt exists""" self._test_ds2_rename_common("MFS", "file_tgt_exists") def test_fat_ds2_rename_dir(self): """FAT DOSv2 rename dir""" self._test_ds2_rename_common("FAT", "dir") def test_mfs_ds2_rename_dir(self): """MFS DOSv2 rename dir""" self._test_ds2_rename_common("MFS", "dir") def test_fat_ds2_rename_dir_src_missing(self): """FAT DOSv2 rename dir src missing""" self._test_ds2_rename_common("FAT", "dir_src_missing") def test_mfs_ds2_rename_dir_src_missing(self): """MFS DOSv2 rename dir src missing""" self._test_ds2_rename_common("MFS", "dir_src_missing") def test_fat_ds2_rename_dir_tgt_exists(self): """FAT DOSv2 rename dir tgt exists""" self._test_ds2_rename_common("FAT", "dir_tgt_exists") def test_mfs_ds2_rename_dir_tgt_exists(self): """MFS DOSv2 rename dir tgt exists""" self._test_ds2_rename_common("MFS", "dir_tgt_exists") def _test_ds2_delete_common(self, fstype, testname): testdir = self.mkworkdir('d') if testname == "file": ename = "mfsds2d1" fn1 = "testa" fe1 = "bat" self.mkfile(fn1 + "." + fe1, """hello\r\n""", dname=testdir) elif testname == "file_missing": ename = "mfsds2d2" fn1 = "testa" fe1 = "bat" self.mkfile("testit.bat", """\ d: c:\\%s DIR rem end """ % ename, newline="\r\n") # compile sources self.mkcom_with_gas(ename, r""" .text .code16 .globl _start16 _start16: push %%cs pop %%ds movw $0x4100, %%ax movw $src, %%dx int $0x21 jnc prsucc prfail: movw $failmsg, %%dx jmp 1f prsucc: movw $succmsg, %%dx 1: movb $0x9, %%ah int $0x21 exit: movb $0x4c, %%ah int $0x21 src: .asciz "%s" # Full path succmsg: .ascii "Delete Operation Success$" failmsg: .ascii "Delete Operation Failed$" """ % (fn1 + "." + fe1)) def assertIsNotPresent(testdir, results, fstype, f, e, msg=None): if fstype == "MFS": self.assertFalse(exists(join(testdir, f + "." + e)), msg) else: self.assertNotRegex(results.upper(), "%s( +|\.)%s" % (f.upper(), e.upper())) if fstype == "MFS": results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """) else: # FAT name = self.mkimage("12", cwd=testdir) results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" $_floppy_a = "" """ % name) if testname == "file": self.assertIn("Delete Operation Success", results) assertIsNotPresent(testdir, results, fstype, fn1, fe1, "File not deleted") elif testname == "file_missing": self.assertIn("Delete Operation Failed", results) def test_fat_ds2_delete_file(self): """FAT DOSv2 delete file""" self._test_ds2_delete_common("FAT", "file") def test_mfs_ds2_delete_file(self): """MFS DOSv2 delete file""" self._test_ds2_delete_common("MFS", "file") def test_fat_ds2_delete_file_missing(self): """FAT DOSv2 delete file missing""" self._test_ds2_delete_common("FAT", "file_missing") def test_mfs_ds2_delete_file_missing(self): """MFS DOSv2 delete file missing""" self._test_ds2_delete_common("MFS", "file_missing") def _test_ds2_find_common(self, fstype, testname): testdir = self.mkworkdir('d') if testname == "simple": ename = "ds2find1" fn1 = "testa" fe1 = "bat" self.mkfile(fn1 + "." + fe1, """hello\r\n""", testdir) elif testname == "missing": ename = "ds2find2" fn1 = "testa" fe1 = "bat" elif testname == "wild_one": ename = "ds2find3" fn1 = "*" fe1 = "in" for f in ["one.in", "two.in", "three.in", "four.in", "five.in", "none.ctl"]: self.mkfile(f, """hello\r\n""", testdir) elif testname == "wild_two": ename = "ds2find4" fn1 = "a*" fe1 = "*" for f in ["aone.in", "atwo.in", "athree.in", "afour.in", "afive.in", "xnone.ctl"]: self.mkfile(f, """hello\r\n""", testdir) elif testname == "wild_three": # To find "abc001.txt ... abc099.txt" ename = "ds2find5" fn1 = "abc0??" fe1 = "*" for f in ["abc001.txt", "abc002.txt", "abc003.txt", "abc004.txt", "abc005.txt", "abc010.txt", "xbc007.txt"]: self.mkfile(f, """hello\r\n""", testdir) self.mkfile("testit.bat", """\ d: c:\\%s DIR rem end """ % ename, newline="\r\n") # compile sources self.mkcom_with_gas(ename, r""" .text .code16 .globl _start16 _start16: push %%cs pop %%ds # Get DTA -> ES:BX movw $0x2f00, %%ax int $0x21 pushw %%es pushw %%bx popl pdta # FindFirst findfirst: movw $0x4e00, %%ax movw $0, %%cx movw $fpatn, %%dx int $0x21 jnc prsucc prfail: movw $failmsg, %%dx movb $0x9, %%ah int $0x21 jmp exit prsucc: movw $succmsg, %%dx movb $0x9, %%ah int $0x21 prfilename: push %%ds lds pdta, %%ax addw $0x1e, %%ax movw %%ax, %%si push %%cs pop %%es movw $(prires + 1), %%di movw $13, %%cx cld 1: cmpb $0, %%ds:(%%si) je 2f movsb loop 1b 2: movb $')', %%es:(%%di) inc %%di movb $'\r', %%es:(%%di) inc %%di movb $'\n', %%es:(%%di) inc %%di movb $'$', %%es:(%%di) inc %%di pop %%ds movw $prires, %%dx movb $0x9, %%ah int $0x21 # FindNext findnext: movw $0x4f00, %%ax int $0x21 jnc prfilename exit: movb $0x4c, %%ah int $0x21 fpatn: .asciz "%s" pdta: .long 0 prires: .ascii "(" .space 32 succmsg: .ascii "Findfirst Operation Success\r\n$" failmsg: .ascii "Findfirst Operation Failed\r\n$" """ % (fn1 + "." + fe1)) if fstype == "MFS": results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """) else: # FAT name = self.mkimage("12", cwd=testdir) results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" $_floppy_a = "" """ % name) if testname == "simple": self.assertIn("Findfirst Operation Success", results) self.assertIn("(TESTA.BAT)", results) elif testname == "missing": self.assertIn("Findfirst Operation Failed", results) elif testname == "wild_one": self.assertIn("Findfirst Operation Success", results) self.assertIn("(ONE.IN)", results) self.assertIn("(TWO.IN)", results) self.assertIn("(THREE.IN)", results) self.assertIn("(FOUR.IN)", results) self.assertIn("(FIVE.IN)", results) self.assertNotIn("(NONE.CTL)", results) elif testname == "wild_two": self.assertIn("Findfirst Operation Success", results) self.assertIn("(AONE.IN)", results) self.assertIn("(ATWO.IN)", results) self.assertIn("(ATHREE.IN)", results) self.assertIn("(AFOUR.IN)", results) self.assertIn("(AFIVE.IN)", results) self.assertNotIn("(XNONE.CTL)", results) elif testname == "wild_three": self.assertIn("Findfirst Operation Success", results) self.assertIn("(ABC001.TXT)", results) self.assertIn("(ABC002.TXT)", results) self.assertIn("(ABC003.TXT)", results) self.assertIn("(ABC004.TXT)", results) self.assertIn("(ABC005.TXT)", results) self.assertIn("(ABC010.TXT)", results) self.assertNotIn("(XBC007.TXT)", results) def test_fat_ds2_find_simple(self): """FAT DOSv2 file find simple""" self._test_ds2_find_common("FAT", "simple") def test_mfs_ds2_find_simple(self): """MFS DOSv2 file find simple""" self._test_ds2_find_common("MFS", "simple") def test_fat_ds2_find_missing(self): """FAT DOSv2 file find missing""" self._test_ds2_find_common("FAT", "missing") def test_mfs_ds2_find_missing(self): """MFS DOSv2 file find missing""" self._test_ds2_find_common("MFS", "missing") def test_fat_ds2_find_wild_1(self): """FAT DOSv2 file find wildcard one""" self._test_ds2_find_common("FAT", "wild_one") def test_mfs_ds2_find_wild_1(self): """MFS DOSv2 file find wildcard one""" self._test_ds2_find_common("MFS", "wild_one") def test_fat_ds2_find_wild_2(self): """FAT DOSv2 file find wildcard two""" self._test_ds2_find_common("FAT", "wild_two") def test_mfs_ds2_find_wild_2(self): """MFS DOSv2 file find wildcard two""" self._test_ds2_find_common("MFS", "wild_two") def test_fat_ds2_find_wild_3(self): """FAT DOSv2 file find wildcard three""" self._test_ds2_find_common("FAT", "wild_three") def test_mfs_ds2_find_wild_3(self): """MFS DOSv2 file find wildcard three""" self._test_ds2_find_common("MFS", "wild_three") def _test_ds2_find_first(self, fstype, testname): testdir = self.mkworkdir('d') ename = "ds2fndfi" ATTR = "$0x00" if testname == "file_exists": FSPEC = r"\\fileexst.ext" elif testname == "file_exists_as_dir": FSPEC = r"\\fileexst.ext\\somefile.ext" elif testname == "file_not_found": FSPEC = r"\\Notfname.ext" elif testname == "no_more_files": FSPEC = r"\\????????.??x" elif testname == "path_not_found_wc": FSPEC = r"\\NotDir\\????????.???" elif testname == "path_not_found_pl": FSPEC = r"\\NotDir\\plainfil.txt" elif testname == "path_exists_empty": FSPEC = r"\\DirExist" elif testname == "path_exists_not_empty": FSPEC = r"\\DirExis2" elif testname == "path_exists_file_not_dir": FSPEC = r"\\DirExis2\\fileexst.ext" ATTR = "$0x10" elif testname == "dir_exists_pl": FSPEC = r"\\DirExis2" ATTR = "$0x10" elif testname == "dir_exists_wc": FSPEC = r"\\Di?Exis?" ATTR = "$0x10" elif testname == "dir_not_exists_pl": FSPEC = r"\\dirNOTex" ATTR = "$0x10" elif testname == "dir_not_exists_wc": FSPEC = r"\\dirNOTex\\wi??card.???" ATTR = "$0x10" elif testname == "dir_not_exists_fn": FSPEC = r"\\dirNOTex\\somefile.ext" ATTR = "$0x10" self.mkfile("testit.bat", """\ d: echo hello > fileexst.ext mkdir DirExist mkdir DirExis2 echo hello > DirExis2\\fileexst.ext c:\\%s DIR rem end """ % ename, newline="\r\n") # compile sources self.mkcom_with_gas(ename, r""" .text .code16 .globl _start16 _start16: push %%cs pop %%ds movw $0x4e00, %%ax movw %s, %%cx movw $fspec, %%dx int $0x21 jnc prsucc cmpw $0x02, %%ax je fail02 cmpw $0x03, %%ax je fail03 cmpw $0x12, %%ax je fail12 jmp genfail fail02: movw $filenotfound, %%dx jmp 1f fail03: movw $pathnotfoundmsg, %%dx jmp 1f fail12: movw $nomoremsg, %%dx jmp 1f genfail: movw $genfailmsg, %%dx jmp 1f prsucc: movw $succmsg, %%dx 1: movb $0x9, %%ah int $0x21 exit: movb $0x4c, %%ah int $0x21 fspec: .asciz "%s" # Full path succmsg: .ascii "FindFirst Operation Success\r\n$" filenotfound: .ascii "FindFirst Operation Returned FILE_NOT_FOUND(0x02)\r\n$" pathnotfoundmsg: .ascii "FindFirst Operation Returned PATH_NOT_FOUND(0x03)\r\n$" nomoremsg: .ascii "FindFirst Operation Returned NO_MORE_FILES(0x12)\r\n$" genfailmsg: .ascii "FindFirst Operation Returned Unexpected Errorcode\r\n$" """ % (ATTR, FSPEC)) if fstype == "MFS": results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """) else: # FAT name = self.mkimage("12", cwd=testdir) results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" $_floppy_a = "" """ % name) if testname == "file_exists": self.assertIn("Operation Success", results) elif testname == "file_exists_as_dir": self.assertIn("Operation Returned PATH_NOT_FOUND(0x03)", results) elif testname == "file_not_found": # Confirmed as not FILE_NOT_FOUND self.assertIn("Operation Returned NO_MORE_FILES(0x12)", results) elif testname == "no_more_files": self.assertIn("Operation Returned NO_MORE_FILES(0x12)", results) elif testname == "path_not_found_wc": self.assertIn("Operation Returned PATH_NOT_FOUND(0x03)", results) elif testname == "path_not_found_pl": self.assertIn("Operation Returned PATH_NOT_FOUND(0x03)", results) elif testname == "path_exists_empty": self.assertIn("Operation Returned NO_MORE_FILES(0x12)", results) elif testname == "path_exists_not_empty": self.assertIn("Operation Returned NO_MORE_FILES(0x12)", results) elif testname == "path_exists_file_not_dir": self.assertIn("Operation Success", results) elif testname == "dir_exists_pl": self.assertIn("Operation Success", results) elif testname == "dir_exists_wc": self.assertIn("Operation Success", results) elif testname == "dir_not_exists_pl": self.assertIn("Operation Returned NO_MORE_FILES(0x12)", results) elif testname == "dir_not_exists_wc": self.assertIn("Operation Returned PATH_NOT_FOUND(0x03)", results) elif testname == "dir_not_exists_fn": self.assertIn("Operation Returned PATH_NOT_FOUND(0x03)", results) def test_fat_ds2_findfirst_file_exists(self): """FAT DOSv2 findfirst file exists""" self._test_ds2_find_first("FAT", "file_exists") def test_mfs_ds2_findfirst_file_exists(self): """MFS DOSv2 findfirst file exists""" self._test_ds2_find_first("MFS", "file_exists") def test_fat_ds2_findfirst_file_exists_as_dir(self): """FAT DOSv2 findfirst file exists as dir""" self._test_ds2_find_first("FAT", "file_exists_as_dir") def test_mfs_ds2_findfirst_file_exists_as_dir(self): """MFS DOSv2 findfirst file exists as dir""" self._test_ds2_find_first("MFS", "file_exists_as_dir") def test_fat_ds2_findfirst_file_not_found(self): """FAT DOSv2 findfirst file not found""" self._test_ds2_find_first("FAT", "file_not_found") def test_mfs_ds2_findfirst_file_not_found(self): """MFS DOSv2 findfirst file not found""" self._test_ds2_find_first("MFS", "file_not_found") def test_fat_ds2_findfirst_no_more_files(self): """FAT DOSv2 findfirst no more files""" self._test_ds2_find_first("FAT", "no_more_files") def test_mfs_ds2_findfirst_no_more_files(self): """MFS DOSv2 findfirst no more files""" self._test_ds2_find_first("MFS", "no_more_files") def test_fat_ds2_findfirst_path_not_found_wc(self): """FAT DOSv2 findfirst path not found wildcard""" self._test_ds2_find_first("FAT", "path_not_found_wc") def test_mfs_ds2_findfirst_path_not_found_wc(self): """MFS DOSv2 findfirst path not found wildcard""" self._test_ds2_find_first("MFS", "path_not_found_wc") def test_fat_ds2_findfirst_path_not_found_pl(self): """FAT DOSv2 findfirst path not found plain""" self._test_ds2_find_first("FAT", "path_not_found_pl") def test_mfs_ds2_findfirst_path_not_found_pl(self): """MFS DOSv2 findfirst path not found plain""" self._test_ds2_find_first("MFS", "path_not_found_pl") def test_fat_ds2_findfirst_path_exists_empty(self): """FAT DOSv2 findfirst path exists empty""" self._test_ds2_find_first("FAT", "path_exists_empty") def test_mfs_ds2_findfirst_path_exists_empty(self): """MFS DOSv2 findfirst path exists empty""" self._test_ds2_find_first("MFS", "path_exists_empty") def test_fat_ds2_findfirst_path_exists_file_not_dir(self): """FAT DOSv2 findfirst path exists file not dir""" self._test_ds2_find_first("FAT", "path_exists_file_not_dir") def test_mfs_ds2_findfirst_path_exists_file_not_dir(self): """MFS DOSv2 findfirst path exists file not dir""" self._test_ds2_find_first("MFS", "path_exists_file_not_dir") def test_fat_ds2_findfirst_path_exists_not_empty(self): """FAT DOSv2 findfirst path exists not empty""" self._test_ds2_find_first("FAT", "path_exists_not_empty") def test_mfs_ds2_findfirst_path_exists_not_empty(self): """MFS DOSv2 findfirst path exists not empty""" self._test_ds2_find_first("MFS", "path_exists_not_empty") def test_fat_ds2_findfirst_dir_exists_pl(self): """FAT DOSv2 findfirst dir exists plain""" self._test_ds2_find_first("FAT", "dir_exists_pl") def test_mfs_ds2_findfirst_dir_exists_pl(self): """MFS DOSv2 findfirst dir exists plain""" self._test_ds2_find_first("MFS", "dir_exists_pl") def test_fat_ds2_findfirst_dir_exists_wc(self): """FAT DOSv2 findfirst dir exists wildcard""" self._test_ds2_find_first("FAT", "dir_exists_wc") def test_mfs_ds2_findfirst_dir_exists_wc(self): """MFS DOSv2 findfirst dir exists wildcard""" self._test_ds2_find_first("MFS", "dir_exists_wc") def test_fat_ds2_findfirst_dir_not_exists_pl(self): """FAT DOSv2 findfirst dir not exists plain""" self._test_ds2_find_first("FAT", "dir_not_exists_pl") def test_mfs_ds2_findfirst_dir_not_exists_pl(self): """MFS DOSv2 findfirst dir not exists plain""" self._test_ds2_find_first("MFS", "dir_not_exists_pl") def test_fat_ds2_findfirst_dir_not_exists_wc(self): """FAT DOSv2 findfirst dir not exists wildcard""" self._test_ds2_find_first("FAT", "dir_not_exists_wc") def test_mfs_ds2_findfirst_dir_not_exists_wc(self): """MFS DOSv2 findfirst dir not exists wildcard""" self._test_ds2_find_first("MFS", "dir_not_exists_wc") def test_fat_ds2_findfirst_dir_not_exists_fn(self): """FAT DOSv2 findfirst dir not exists filename""" self._test_ds2_find_first("FAT", "dir_not_exists_fn") def test_mfs_ds2_findfirst_dir_not_exists_fn(self): """MFS DOSv2 findfirst dir not exists filename""" self._test_ds2_find_first("MFS", "dir_not_exists_fn") def _test_ds2_find_mixed_wild_plain(self, fstype): testdir = self.mkworkdir('d') ename = "ds2findm" fsmpl = "xbc007.txt" for f in ["abc001.txt", "abc002.txt", "abc003.txt", "abc004.txt", "abc005.txt", "abc010.txt", "xbc007.txt"]: self.mkfile(f, """hello\r\n""", testdir) self.mkfile("testit.bat", """\ d: c:\\%s DIR rem end """ % ename, newline="\r\n") # compile sources self.mkcom_with_gas(ename, r""" .text .code16 .globl _start16 _start16: push %%cs pop %%ds # Get DTA -> ES:BX movw $0x2f00, %%ax int $0x21 pushw %%es pushw %%bx popl pdta # First FindFirst movw $0x4e00, %%ax movw $0, %%cx movw $fwild, %%dx int $0x21 # Set alternate DTA movw $0x1a00, %%ax movw $altdta, %%dx int $0x21 # Second FindFirst movw $0x4e00, %%ax movw $0, %%cx movw $fsmpl, %%dx int $0x21 # Set default DTA movw $0x1a00, %%ax lds pdta, %%dx int $0x21 # FindNext movw $0x4f00, %%ax int $0x21 jnc prsucc prfail: movw $failmsg, %%dx movb $0x9, %%ah int $0x21 jmp exit prsucc: push %%ds lds pdta, %%ax addw $0x1e, %%ax movw %%ax, %%si push %%cs pop %%es movw $(prires + 1), %%di movw $13, %%cx cld 1: cmpb $0, %%ds:(%%si) je 2f movsb loop 1b 2: movb $')', %%es:(%%di) inc %%di movb $'\r', %%es:(%%di) inc %%di movb $'\n', %%es:(%%di) inc %%di movb $'$', %%es:(%%di) inc %%di pop %%ds movw $succmsg, %%dx movb $0x9, %%ah int $0x21 exit: movb $0x4c, %%ah int $0x21 fwild: .asciz "a*.txt" fsmpl: .asciz "%s" altdta: .space 0x80 pdta: .long 0 succmsg: .ascii "Findnext Operation Success" prires: .ascii "(" .space 32 failmsg: .ascii "Findnext Operation Failed\r\n$" """ % fsmpl) if fstype == "MFS": config="""\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """ else: # FAT name = self.mkimage("12", cwd=testdir) config="""\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" $_floppy_a = "" """ % name results = self.runDosemu("testit.bat", config=config) self.assertNotIn("Findnext Operation Failed", results) self.assertRegex(results, r"Findnext Operation Success\(ABC...\.TXT\)") def test_fat_ds2_find_mixed_wild_plain(self): """FAT DOSv2 findnext intermixed wild plain""" self._test_ds2_find_mixed_wild_plain("FAT") def test_mfs_ds2_find_mixed_wild_plain(self): """MFS DOSv2 findnext intermixed wild plain""" self._test_ds2_find_mixed_wild_plain("MFS") def test_create_new_psp(self): """Create New PSP""" ename = "getnwpsp" cmdline = "COMMAND TAIL TEST" self.mkfile("testit.bat", """\ c:\\%s %s rem end """ % (ename, cmdline), newline="\r\n") # compile sources self.mkcom_with_gas(ename, r""" .text .code16 .globl _start16 _start16: # designate target segment push %%cs pop %%ax addw $0x0200, %%ax movw %%ax, %%es # create PSP in memory movw %%es, %%dx movw $0x2600, %%ax int $0x21 # see if the exit field is set cmpw $0x20cd, %%es:(0x0000) jne extfail # see if the parent PSP is zero cmpw $0x0000, %%es:(0x0016) je pntzero # see if the parent PSP points to a PSP push %%es pushw %%es:(0x0016) pop %%es cmpw $0x20cd, %%es:(0x0000) pop %%es jne pntnpsp # see if the 'INT 21,RETF' is there cmpw $0x21cd, %%es:(0x0050) jne int21ms cmpb $0xcb, %%es:(0x0052) jne int21ms # see if the cmdtail is there movzx %%es:(0x0080), %%cx cmpw $%d, %%cx jne cmdlngth inc %%cx mov $cmdline, %%si mov $0x0081, %%di cld repe cmpsb jne cmdtail success: movw $successmsg, %%dx jmp exit extfail: movw $extfailmsg, %%dx jmp exit pntzero: movw $pntzeromsg, %%dx jmp exit pntnpsp: movw $pntnpspmsg, %%dx jmp exit int21ms: movw $int21msmsg, %%dx jmp exit cmdlngth: movw $cmdlngthmsg, %%dx jmp exit cmdtail: movw $cmdtailmsg, %%dx jmp exit exit: movb $0x9, %%ah int $0x21 movb $0x4c, %%ah int $0x21 extfailmsg: .ascii "PSP exit field not set to CD20\r\n$" pntzeromsg: .ascii "PSP parent is zero\r\n$" pntnpspmsg: .ascii "PSP parent doesn't point to a PSP\r\n$" int21msmsg: .ascii "PSP is missing INT21, RETF\r\n$" cmdlngthmsg: .ascii "PSP has incorrect command length\r\n$" cmdtailmsg: .ascii "PSP has incorrect command tail\r\n$" successmsg: .ascii "PSP structure okay\r\n$" # 05 20 54 45 53 54 0d cmdline: .ascii " %s\r" """ % (1 + len(cmdline), cmdline)) results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 +1" $_floppy_a = "" """) self.assertIn("PSP structure okay", results) # Tests using neither compiler nor assembler def test_systype(self): """SysType""" self.runDosemu("version.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 +1" $_debug = "-D+d" """) # read the logfile systypeline = "Not found in logfile" with open(self.logfiles['log'][0], "r") as f: for line in f: if "system type is" in line: systypeline = line break self.assertIn(self.systype, systypeline) def test_command_com_keyword_exist(self): """Command.com keyword exist""" self.mkfile("testit.bat", r""" rem X: is a non-existent drive if not exist X:\ANYTHING.EXE echo 00_True if not exist X:\NUL echo 01_True if not exist X:\FAKEDIR\NUL echo 02_True rem D: is a FAT(local) drive D: cd \ mkdir ISDIR echo hello > ISDIR\EXIST.TRU if exist D:\NUL echo 03_True if not exist D:\EXIST.NOT echo 04_True if not exist D:\NODIR\NUL echo 05_True if not exist D:\NODIR\ANYTHING.EXE echo 06_True if exist D:\ISDIR\EXIST.TRU echo 07_True if not exist D:\ISDIR\EXIST.NOT echo 08_True rem C: is an MFS(network redirected) drive C: cd \ mkdir ISDIR echo hello > ISDIR\EXIST.TRU if exist C:\NUL echo 09_True if not exist C:\EXIST.NOT echo 10_True if not exist C:\NODIR\NUL echo 11_True if not exist C:\NODIR\ANYTHING.EXE echo 12_True if exist C:\ISDIR\EXIST.TRU echo 13_True if not exist C:\ISDIR\EXIST.NOT echo 14_True rem end """, newline="\r\n") testdir = self.mkworkdir('d') name = self.mkimage("12", cwd=testdir) results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" """ % name) for i in range(15): with self.subTest("Subtest %02d" % i): self.assertRegex(results, r"(?m)^%02d_True.*" % i) def _test_memory_dpmi_ecm(self, name): ename = "%s.com" % name edir = self.topdir / "test" / "ecm" / "dpmitest" call(["make", "--quiet", "-C", str(edir), ename]) copy(edir / ename, self.workdir) self.mkfile("testit.bat", """\ c:\\%s rem end """ % name, newline="\r\n") return self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 +1" $_floppy_a = "" """) def test_memory_dpmi_ecm_alloc(self): """Memory DPMI (ECM) alloc""" results = self._test_memory_dpmi_ecm("dpmialoc") # About to Execute : dpmialoc.com # Protected mode breakpoint at 0221h. # 32-bit code segment breakpoint at 0233h. # Return from child process at 0403h. # Welcome in 32-bit protected mode. # DPMI allocation at 02121000h. # DPMI allocation entrypoint at 00EFh:00000000h. # Real mode procedure called at 00EFh:00000044h. # DPMI allocation exit at 00EFh:0000006Ch. # Hello from DPMI memory section! # Calling real mode procedure which called callback successful. # Child process terminated okay, back in real mode. self.assertRegex(results, r"Protected mode breakpoint at") self.assertRegex(results, r"32-bit code segment breakpoint at") self.assertRegex(results, r"Return from child process at") self.assertRegex(results, r"Welcome in 32-bit protected mode") self.assertRegex(results, r"Hello from DPMI memory section!") self.assertRegex(results, r"Calling real mode procedure which called callback successful") self.assertRegex(results, r"Child process terminated okay, back in real mode") self.assertNotIn("fail", results) def test_memory_dpmi_ecm_mini(self): """Memory DPMI (ECM) mini""" results = self._test_memory_dpmi_ecm("dpmimini") # About to Execute : dpmimini.com # Protected mode breakpoint at 015Ah. # 32-bit code segment breakpoint at 016Ch. # # Welcome in 32-bit protected mode. self.assertRegex(results, r"Protected mode breakpoint at") self.assertRegex(results, r"32-bit code segment breakpoint at") self.assertRegex(results, r"Welcome in 32-bit protected mode") self.assertNotIn("fail", results) def test_memory_dpmi_ecm_modeswitch(self): """Memory DPMI (ECM) Mode Switch""" results = self._test_memory_dpmi_ecm("dpmims") # About to Execute : dpmims.com # Protected mode breakpoint at 015Eh. # # Welcome in protected mode. # Mode-switched to real mode. # In protected mode again. self.assertRegex(results, r"Protected mode breakpoint at") self.assertRegex(results, r"Welcome in protected mode") self.assertRegex(results, r"Mode-switched to real mode") self.assertRegex(results, r"In protected mode again") self.assertNotIn("fail", results) def test_memory_dpmi_ecm_psp(self): """Memory DPMI (ECM) psp""" results = self._test_memory_dpmi_ecm("dpmipsp") # About to Execute : dpmipsp.com # Protected mode breakpoint at 0221h. # 32-bit code segment breakpoint at 0233h. # Real mode procedure called at 0275h. # Return from child process at 02FCh. # # Welcome in 32-bit protected mode. # Calling real mode procedure which called callback successful. # Child process terminated okay, back in real mode. self.assertRegex(results, r"Protected mode breakpoint at") self.assertRegex(results, r"32-bit code segment breakpoint at") self.assertRegex(results, r"Real mode procedure called at") self.assertRegex(results, r"Return from child process at") self.assertRegex(results, r"Welcome in 32-bit protected mode") self.assertRegex(results, r"Calling real mode procedure which called callback successful") self.assertRegex(results, r"Child process terminated okay, back in real mode") self.assertNotIn("fail", results) def _test_memory_dpmi_japheth(self, switch): self.unTarOrSkip("VARIOUS.tar", [ ("dpmihxrt218.exe", "65fda018f4422c39dbf36860aac2c537cfee466b"), ]) rename(self.workdir / "dpmihxrt218.exe", self.workdir / "dpmi.exe") self.mkfile("testit.bat", """\ c:\\dpmi %s rem end """ % switch, newline="\r\n") return self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 +1" $_floppy_a = "" """, timeout=60) def test_memory_dpmi_japheth(self): """Memory DPMI (Japheth) ''""" results = self._test_memory_dpmi_japheth("") #Cpu is in V86-mode #Int 15h, ax=e801h, extended memory: 8256 kB #int 15h, ax=e820h, available memory at 000100000, size 8256 kB #XMS v3.0 host found, largest free block: 8192 kB #No VCPI host found #DPMI v0.90 host found, cpu: 05, support of 32-bit clients: 1 #entry initial switch to protected-mode: F000:F500 #size task-specific memory: 230 paragraphs #now in protected mode, client CS/SS/DS/FS/GS: A7/AF/AF/0/0 #Eflags=206, ES (=PSP): B7 (environment: BF, parent PSP segm: 431) #GDTR: 17.A308100 IDTR: 7FF.A308200 LDTR: 0 TR: 0 #DPMI version flags: 5 #master/slave PICs base: 08/70 #state save protected-mode: 97:1, real-mode: F000:F514 #size state save buffer: 52 bytes #raw jump to real-mode: 97:0, protected-mode: F000:F513 #largest free/lockable memory block (kB): 131004/131004 #free unlocked (=virtual) memory (kB): 131004 #total/free address space (kB): 32768/32768 #total/free physical memory (kB): 131072/131004 #Coprocessor status: 4D #vendor: DOSEMU Version 2.0, version: 0.90 #capabilities: 78 #vendor 'MS-DOS' API entry: 97:130 #'MS-DOS' API, ax=100h (get LDT selector): E7 self.assertRegex(results, r"DPMI v0.90 host found, cpu: \d+, support of 32-bit clients: 1") self.assertRegex(results, r"DPMI version flags: 5") self.assertRegex(results, r"vendor: DOSEMU Version 2.0, version: 0.90") self.assertRegex(results, r"capabilities: 78") def test_memory_dpmi_japheth_c(self): """Memory DPMI (Japheth) '-c'""" results = self._test_memory_dpmi_japheth("-c") self.assertRegex(results, r"time.*CLI/STI: \d+ ms") self.assertRegex(results, r"time.*interrupts via DPMI: \d+ ms") def test_memory_dpmi_japheth_i(self): """Memory DPMI (Japheth) '-i'""" results = self._test_memory_dpmi_japheth("-i") self.assertRegex(results, r"time.*IN 21: \d+ ms") def test_memory_dpmi_japheth_m(self): """Memory DPMI (Japheth) '-m'""" results = self._test_memory_dpmi_japheth("-m") t = re.search(r"alloc largest mem block \(size=(\d+) kB\) returned handle [0-9a-fA-F]+, base \d+", results) self.assertIsNotNone(t, "Unable to parse memory block size") size = int(t.group(1)) self.assertGreater(size, 128000, results) def test_memory_dpmi_japheth_r(self): """Memory DPMI (Japheth) '-r'""" results = self._test_memory_dpmi_japheth("-r") self.assertRegex(results, r"time.*INT 69h: \d+ ms") self.assertRegex(results, r"time.*INT 31h, AX=0300h \(Sim INT 69h\): \d+ ms") self.assertRegex(results, r"time.*real-mode callback: \d+ ms") self.assertRegex(results, r"time.*raw mode switches PM->RM->PM: \d+ ms") def test_memory_dpmi_japheth_t(self): """Memory DPMI (Japheth) '-t'""" results = self._test_memory_dpmi_japheth("-t") #C:\>c:\dpmi -t #allocated rm callback FF10:214, rmcs=AF:20E4 #calling rm proc [53A:8B6], rm cx=1 # inside rm proc, ss:sp=7A8:1FC, cx=1 # calling rm callback FF10:214 # inside rm callback, ss:esp=9F:EFF4, ds:esi=F7:1FC # es:edi=AF:20E4, rm ss:sp=7A8:1FC, rm cx=1 # calling rm proc [53A:8B6] # inside rm proc, ss:sp=7A8:1F8, cx=2 # calling rm callback FF10:214 # inside rm callback, ss:esp=9F:EFE0, ds:esi=F7:1F8 # es:edi=AF:20E4, rm ss:sp=7A8:1F8, rm cx=2 # exiting # back in rm proc, ss:sp=7A8:1F8; exiting # back in rm callback, rm ss:sp=7A8:1FC, rm cx=2; exiting # back in rm proc, ss:sp=7A8:1FC; exiting #back in protected-mode, rm ss:sp=7A8:200, rm cx=2 self.assertRegex(results, re.compile(r"^allocated rm callback", re.MULTILINE)) self.assertRegex(results, re.compile(r"^ inside rm proc", re.MULTILINE)) self.assertRegex(results, re.compile(r"^ inside rm callback", re.MULTILINE)) self.assertRegex(results, re.compile(r"^ inside rm proc", re.MULTILINE)) self.assertRegex(results, re.compile(r"^ inside rm callback", re.MULTILINE)) self.assertRegex(results, re.compile(r"^ back in rm proc", re.MULTILINE)) self.assertRegex(results, re.compile(r"^ back in rm callback", re.MULTILINE)) self.assertRegex(results, re.compile(r"^ back in rm proc", re.MULTILINE)) self.assertRegex(results, re.compile(r"^back in protected-mode", re.MULTILINE)) def test_memory_emm286_borland(self): """Memory EMM286 (Borland)""" self.unTarOrSkip("TEST_EMM286.tar", [ ("tasm32.exe", "61c2ddb2c193f49dd29c083579ec7f47566278a7"), ("emm286.exe", "d8388a574f024d500515e4f0575958cf52939f26"), ("32rtm.exe", "720c8bdcb0b3b2634e95c89c56c0cc1573272cd9"), ]) # Modify the config.sys contents = (self.workdir / self.confsys).read_text() contents = re.sub(r"device=(c:\\)?dosemu\\umb.sys", r"device=\1dosemu\\umb.sys /full", contents) contents = re.sub(r"devicehigh=(c:\\)?dosemu\\ems.sys", r"devicehigh=c:\\emm286.exe 4096", contents) self.mkfile(self.confsys, contents, newline="\r\n") self.mkfile("testit.bat", """\ c:\\tasm32 /h rem end """, newline="\r\n") results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 +1" $_floppy_a = "" """) # Look for last line of output to indicate successful load/run # /zi,/zd,/zn Debug info: zi=full, zd=line numbers only, zn=none self.assertRegex(results, r"/zi.*Debug info: zi=full") def test_memory_ems_borland(self): """Memory EMS (Borland)""" memory_ems_borland(self) def test_floppy_img(self): """Floppy image file""" # Note: image must have # dosemu directory # autoexec.bat # version.bat self.unTarImageOrSkip("boot-floppy.img") results = self.runDosemu("version.bat", config="""\ $_hdimage = "" $_floppy_a = "boot-floppy.img" $_bootdrive = "a" """) self.assertIn(self.version, results) def test_floppy_vfs(self): """Floppy vfs directory""" self.mkfile(self.confsys, """\ DOS=UMB,HIGH lastdrive=Z files=40 stacks=0,0 buffers=10 device=a:\\dosemu\\emufs.sys device=a:\\dosemu\\umb.sys devicehigh=a:\\dosemu\\ems.sys devicehigh=a:\\dosemu\\cdrom.sys install=a:\\dosemu\\emufs.com shell=command.com /e:1024 /k %s """ % self.autoexec, newline="\r\n") self.mkfile(self.autoexec, """\ prompt $P$G path a:\\bin;a:\\gnu;a:\\dosemu system -s DOSEMU_VERSION @echo %s """ % IPROMPT, newline="\r\n") results = self.runDosemu("version.bat", config="""\ $_hdimage = "" $_floppy_a = "dXXXXs/c:fiveinch_360" $_bootdrive = "a" """) self.assertIn(self.version, results) def test_three_drives_vfs(self): """Three vfs directories configured""" # C exists as part of standard test self.mkworkdir('d') self.mkworkdir('e') results = self.runDosemu("version.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 dXXXXs/e:hdtype1 +1" $_floppy_a = "" """) self.assertIn(self.version, results) # Just to check we booted def _test_fat_img_d_writable(self, fat): self.mkfile("testit.bat", """\ D: mkdir test echo hello > hello.txt DIR rem end """, newline="\r\n") testdir = self.mkworkdir('d') name = self.mkimage(fat, cwd=testdir) results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" """ % name) # Std DOS format # TEST # HELLO TXT 8 # # ComCom32 format # 2019-06-28 22:29 TEST # 2019-06-28 22:29 8 HELLO.TXT self.assertRegex(results, r"TEST[\t ]+" r"|" r"\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}\s\s+TEST") self.assertRegex(results, r"HELLO[\t ]+TXT[\t ]+8" r"|" r"\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}\s+8\s+HELLO.TXT") def test_fat12_img_d_writable(self): """FAT12 image file D writable""" self._test_fat_img_d_writable("12") def test_fat16_img_d_writable(self): """FAT16 image file D writable""" self._test_fat_img_d_writable("16") def test_mfs_lredir_auto_hdc(self): """MFS lredir auto C drive redirection""" self.mkfile("testit.bat", "lredir\r\nrem end\r\n") results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 +1" """) # C:\>lredir # Current Drive Redirections: # C: = LINUX\FS\dosemu2.git\test-imagedir\dXXXXs\c\ attrib = READ/WRITE self.assertRegex(results, r"C: = /.*") def test_mfs_lredir_command(self): """MFS lredir command redirection""" self.mkfile("testit.bat", """\ lredir X: /tmp lredir rem end """, newline="\r\n") results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 +1" $_floppy_a = "" $_lredir_paths = "/tmp" """) # A:\>lredir # Current Drive Redirections: # C: = LINUX\FS\dosemu2.git\test-imagedir\dXXXXs\c\ attrib = READ/WRITE # X: = LINUX\FS\tmp\ attrib = READ/WRITE self.assertRegex(results, r"X: = /tmp") def test_mfs_lredir_command_no_perm(self): """MFS lredir command redirection permission fail""" self.mkfile("testit.bat", """\ lredir X: /tmp lredir rem end """, newline="\r\n") results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 +1" $_floppy_a = "" """) # A:\>lredir # Current Drive Redirections: # C: = LINUX\FS\dosemu2.git\test-imagedir\dXXXXs\c\ attrib = READ/WRITE # X: = LINUX\FS\tmp\ attrib = READ/WRITE self.assertRegex(results, r"Error 5 \(access denied\) while redirecting drive X:") # Tests using the DJGPP DOS compiler def test_mfs_findfile_ufs_lfn(self): """MFS findfile UFS LFN""" tests = ( # Type, Create, Find ("DIR", "Program Files", "Program Files"), ("FILE", "verylongfilename.txt", "verylongfilename.txt"), ("FILE", "verylongfilename2.txt", "verylongfilename2.txt"), ("FILE", "space embedded filename.txt", "space embedded filename.txt"), ("FILE", "MixedCaseFilename.ext", "MixedCaseFilename.ext"), ) mfs_findfile(self, "UFS", "LFN", tests) def test_mfs_findfile_ufs_sfn(self): """MFS findfile UFS SFN""" tests = ( # Type, Create, Find ("DIR", "Program Files", "PROGR~-I"), ("FILE", "verylongfilename.txt", "VERYL~3G.TXT"), ("FILE", "verylongfilename2.txt", "VERYL~2N.TXT"), ("FILE", "space embedded filename.txt", "SPACE~L#.TXT"), ("FILE", "MixedCaseFilename.ext", "MIXED~G4.EXT"), ) mfs_findfile(self, "UFS", "SFN", tests) def test_mfs_findfile_vfat_linux_mounted_lfn(self): """MFS findfile VFAT Linux mounted LFN""" tests = ( # Type, Create, Find ("DIR", "Program Files", "Program Files"), ("FILE", "verylongfilename.txt", "verylongfilename.txt"), ("FILE", "verylongfilename2.txt", "verylongfilename2.txt"), ("FILE", "space embedded filename.txt", "space embedded filename.txt"), ("FILE", "MixedCaseFilename.ext", "MixedCaseFilename.ext"), ) mfs_findfile(self, "VFAT", "LFN", tests) def test_mfs_findfile_vfat_linux_mounted_sfn(self): """MFS findfile VFAT Linux mounted SFN""" tests = ( # Type, Create, Find ("DIR", "Program Files", "PROGRA~1"), ("FILE", "verylongfilename.txt", "VERYLO~1.TXT"), ("FILE", "verylongfilename2.txt", "VERYLO~2.TXT"), ("FILE", "space embedded filename.txt", "SPACEE~1.TXT"), ("FILE", "MixedCaseFilename.ext", "MIXEDC~1.EXT"), ) mfs_findfile(self, "VFAT", "SFN", tests) def test_mfs_truename_ufs_lfn(self): """MFS truename UFS LFN""" names_to_create = ( ("DIR", "Program Files"), ("FILE", "very long testname"), ("FILE", "verylongtestname.txt"), ) tests = ( # NOTE: not sure that the output should be UPCASED. ("LFN0", "very long testname", "C:\\VERY LONG TESTNAME"), ("LFN0", "d:\\verylongtestname.txt", "D:\\VERYLONGTESTNAME.TXT"), ("LFN0", "d:\\very long testname", "D:\\VERY LONG TESTNAME"), ("LFN0", "aux", "C:/AUX"), ("LFN0", "d:very long testname", "D:\\VERY LONG TESTNAME"), # FAIL ("LFN0", "d:\\fakedir\\very long testname", None), ("LFN0", "D:\\PROGR~-I", "D:\\PROGR~-I"), ("LFN1", "D:\\Program Files", "D:\\PROGR~-I"), ("LFN2", "D:\\PROGR~-I", "D:\\Program Files"), ) for t in tests: with self.subTest(t=t): mfs_truename(self, "UFS", names_to_create, *t) def test_mfs_truename_ufs_sfn(self): """MFS truename UFS SFN""" names_to_create = ( ("DIR", "testname"), ("FILE", "shrtname.txt"), ) tests = ( ("SFN", "testname", "C:\\TESTNAME"), ("SFN", "d:\\shrtname.txt", "D:\\SHRTNAME.TXT"), ("SFN", "d:\\testname", "D:\\TESTNAME"), ("SFN", "aux", "C:/AUX"), ("SFN", "d:testname", "D:\\TESTNAME"), # FAIL ("SFN", "d:\\fakedir\\testname", None), ) for t in tests: with self.subTest(t=t): mfs_truename(self, "UFS", names_to_create, *t) def test_mfs_truename_vfat_linux_mounted_lfn(self): """MFS truename VFAT Linux mounted LFN""" names_to_create = ( ("DIR", "Program Files"), ("FILE", "verylongfilename.txt"), ("FILE", "verylongfilename2.txt"), ("FILE", "space embedded filename.txt"), ("FILE", "MixedCaseFilename.ext"), ) tests = ( ("LFN1", "X:\\verylongfilename.txt", "X:\\VERYLO~1.TXT"), ("LFN1", "X:\\verylongfilename2.txt", "X:\\VERYLO~2.TXT"), ("LFN1", "X:\\space embedded filename.txt", "X:\\SPACEE~1.TXT"), ("LFN1", "X:\\MixedCaseFilename.ext", "X:\\MIXEDC~1.EXT"), ("LFN2", "X:\\VERYLO~1.TXT", "X:\\verylongfilename.txt"), ("LFN2", "X:\\VERYLO~2.TXT", "X:\\verylongfilename2.txt"), ("LFN2", "X:\\SPACEE~1.TXT", "X:\\space embedded filename.txt"), ("LFN2", "X:\\MIXEDC~1.EXT", "X:\\MixedCaseFilename.ext"), ("LFN0", "X:\\progra~1", "X:\\PROGRA~1"), ("LFN1", "X:\\Program Files", "X:\\PROGRA~1"), ("LFN2", "X:\\PROGRA~1", "X:\\Program Files"), ) for t in tests: with self.subTest(t=t): mfs_truename(self, "VFAT", names_to_create, *t) def test_mfs_truename_vfat_linux_mounted_sfn(self): """MFS truename VFAT Linux mounted SFN""" names_to_create = ( ("DIR", "testname"), ("FILE", "shrtname.txt"), ("FILE", "verylongfilename.txt"), ("FILE", "verylongfilename2.txt"), ("FILE", "space embedded filename.txt"), ("FILE", "MixedCaseFilename.ext"), ) tests = ( ("SFN", "X:\\testname", "X:\\TESTNAME"), ("SFN", "d:\\shrtname.txt", "D:\\SHRTNAME.TXT"), ("SFN", "X:\\verylo~1.txt", "X:\\VERYLO~1.TXT"), ("SFN", "X:\\verylo~2.txt", "X:\\VERYLO~2.TXT"), ("SFN", "X:\\spacee~1.txt", "X:\\SPACEE~1.TXT"), ("SFN", "X:\\mixedc~1.ext", "X:\\MIXEDC~1.EXT"), ) for t in tests: with self.subTest(t=t): mfs_truename(self, "VFAT", names_to_create, *t) def _test_mfs_file_read(self, nametype): if nametype == "LFN": testname = "verylongname.txt" disablelfn = "" elif nametype == "SFN": testname = "shrtname.txt" disablelfn = "set LFN=n" else: self.fail("Incorrect argument") testdata = mkstring(128) testdir = self.mkworkdir('d') self.mkfile("testit.bat", """\ %s d: c:\\mfsread %s %s rem end """ % (disablelfn, testname, testdata), newline="\r\n") self.mkfile(testname, testdata, dname=testdir) # compile sources self.mkexe_with_djgpp("mfsread", r""" #include #include #include #include #include int main(int argc, char *argv[]) { char b[512]; int f, size; if (argc < 1) { printf("missing filename argument\n"); return 3; } f = open(argv[1], O_RDONLY | O_TEXT); if (f < 0) { printf("open failed\n"); return 2; } size = read(f, b, sizeof(b)); if (size < 0) { printf("read failed\n"); return 1; } write(1, b, size); close(f); return 0; } """) results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """) self.assertIn(testdata, results) def test_mfs_lfn_file_read(self): """MFS LFN file read""" self._test_mfs_file_read("LFN") def test_mfs_sfn_file_read(self): """MFS SFN file read""" self._test_mfs_file_read("SFN") def _test_mfs_file_write(self, nametype, operation): if nametype == "LFN": ename = "mfslfn" testname = "verylongname.txt" disablelfn = "" elif nametype == "SFN": ename = "mfssfn" testname = "shrtname.txt" disablelfn = "set LFN=n" else: self.fail("Incorrect argument") if operation == "create": ename += "wc" testprfx = "" openflags = "O_WRONLY | O_CREAT | O_TEXT" mode = ", 0222" elif operation == "createreadonly": ename += "wk" testprfx = "" openflags = "O_WRONLY | O_CREAT | O_TEXT" mode = ", 0444" elif operation == "truncate": ename += "wt" testprfx = "dummy data" openflags = "O_WRONLY | O_CREAT | O_TRUNC | O_TEXT" mode = ", 0222" elif operation == "append": ename += "wa" testprfx = "Original Data" openflags = "O_RDWR | O_APPEND | O_TEXT" mode = "" else: self.fail("Incorrect argument") testdata = mkstring(64) # need to be fairly short to pass as arg testdir = self.mkworkdir('d') self.mkfile("testit.bat", """\ %s d: c:\\%s %s %s rem end """ % (disablelfn, ename, testname, testdata), newline="\r\n") if operation != "create" and operation != "createreadonly": self.mkfile(testname, testprfx, dname=testdir) # compile sources self.mkexe_with_djgpp(ename, r""" #include #include #include #include #include #include int main(int argc, char *argv[]) { int f, size; if (argc < 2) { printf("missing filename argument\n"); return 4; } if (argc < 3) { printf("missing data argument\n"); return 3; } f = open(argv[1], %s %s); if (f < 0) { printf("open failed\n"); return 2; } size = write(f, argv[2], strlen(argv[2])); if (size < strlen(argv[2])) { printf("write failed\n"); return 1; } close(f); return 0; } """ % (openflags, mode)) results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """) self.assertNotIn("open failed", results) try: with open(join(testdir, testname), "r") as f: filedata = f.read() if operation == "truncate": self.assertNotIn(testprfx, filedata) elif operation == "append": self.assertIn(testprfx + testdata, filedata) self.assertIn(testdata, filedata) except IOError: self.fail("File not created/opened") def test_mfs_lfn_file_create(self): """MFS LFN file create""" self._test_mfs_file_write("LFN", "create") def test_mfs_sfn_file_create(self): """MFS SFN file create""" self._test_mfs_file_write("SFN", "create") def test_mfs_lfn_file_create_readonly(self): """MFS LFN file create readonly""" self._test_mfs_file_write("LFN", "createreadonly") def test_mfs_sfn_file_create_readonly(self): """MFS SFN file create readonly""" self._test_mfs_file_write("SFN", "createreadonly") def test_mfs_lfn_file_truncate(self): """MFS LFN file truncate""" self._test_mfs_file_write("LFN", "truncate") def test_mfs_sfn_file_truncate(self): """MFS SFN file truncate""" self._test_mfs_file_write("SFN", "truncate") def test_mfs_lfn_file_append(self): """MFS LFN file append""" self._test_mfs_file_write("LFN", "append") def test_mfs_sfn_file_append(self): """MFS SFN file append""" self._test_mfs_file_write("SFN", "append") def _test_lfn_volume_info(self, fstype): if not fstype in ["MFS", "FAT"]: self.fail("Incorrect argument") self.mkfile("testit.bat", """\ c:\\lfnvinfo D:\\ rem end """, newline="\r\n") testdir = self.mkworkdir('d') self.mkfile("foo.dat", "some content", dname=testdir) name = self.mkimage("16", cwd=testdir) # compile sources self.mkexe_with_djgpp("lfnvinfo", r""" #include #include #include #include #include #include int main(int argc, char *argv[]) { int max_file_len, max_path_len; char fsystype[32]; unsigned rval; if (argc < 1) { printf("missing volume argument e.g. 'C:\\'\n"); return 1; } rval = _get_volume_info(argv[1], &max_file_len, &max_path_len, fsystype); if (rval == 0 && errno) { printf("ERRNO(%d)\r\n", errno); return 2; } if (rval == _FILESYS_UNKNOWN) { printf("FILESYS_UNKNOWN(%d)\r\n", errno); return 3; } printf("FSTYPE(%s), FILELEN(%d), PATHLEN(%d), BITS(0x%04x)\r\n", fsystype, max_file_len, max_path_len, rval); return 0; } """) if fstype == "MFS": hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1" elif fstype == "FAT": hdimage = "dXXXXs/c:hdtype1 %s" % name results = self.runDosemu("testit.bat", config="""\ $_hdimage = "%s +1" $_floppy_a = "" """ % hdimage) if fstype == "MFS": self.assertIn("FSTYPE(MFS)", results) elif fstype == "FAT": self.assertIn("ERRNO(27)", results) def test_lfn_volume_info_mfs(self): """LFN volume info on MFS""" self._test_lfn_volume_info("MFS") def test_lfn_volume_info_fat_img(self): """LFN volume info on FAT(img)""" self._test_lfn_volume_info("FAT") def test_fat32_disk_info(self): """FAT32 disk info""" path = "C:\\" self.mkfile("testit.bat", """\ c:\\fat32dif %s rem end """ % path, newline="\r\n") # compile sources self.mkexe_with_djgpp("fat32dif", r"""\ #include #include #include struct dinfo { uint16_t size; uint16_t version; // (0000h) uint32_t spc; uint32_t bps; uint32_t avail_clusters; uint32_t total_clusters; uint32_t avail_sectors; uint32_t total_sectors; uint32_t avail_units; uint32_t total_units; char reserved[8]; }; #define MAXPATH 128 int main(int argc, char *argv[]) { struct dinfo df; uint8_t carry; uint16_t ax; int len; if (argc < 2) { printf("path argument missing e.g. 'C:\\'\n"); return 3; } len = strlen(argv[1]) + 1; if (len > MAXPATH) { printf("path argument too long\n"); return 2; } /* AX = 7303h DS:DX -> ASCIZ string for drive ("C:\" or "\\SERVER\Share") ES:DI -> buffer for extended free space structure (see #01789) CX = length of buffer for extended free space Return: CF clear if successful ES:DI buffer filled CF set on error AX = error code */ asm volatile("stc\n" "int $0x21\n" "setc %0\n" : "=r"(carry), "=a"(ax) : "a"(0x7303), "d"(argv[1]), "D"(&df), "c"(sizeof(df)) : "cc", "memory"); if (carry) { printf("Call failed (CARRY), AX = 0x%04x\n", ax); return 1; } /* See if we have valid data */ if (df.size > sizeof(df)) { printf("Call failed (Struct invalid), size = 0x%04x, version 0x%04x\n", df.size, df.version); return 1; } printf("size 0x%04x\n", df.size); printf("version 0x%04x\n", df.version); printf("spc 0x%08lx\n", df.spc); printf("bps 0x%08lx\n", df.bps); printf("avail_clusters 0x%08lx\n", df.avail_clusters); printf("total_clusters 0x%08lx\n", df.total_clusters); printf("avail_sectors 0x%08lx\n", df.avail_sectors); printf("total_sectors 0x%08lx\n", df.total_sectors); printf("avail_units 0x%08lx\n", df.avail_units); printf("total_units 0x%08lx\n", df.total_units); printf("avail_bytes(%llu)\n", (unsigned long long)df.spc * (unsigned long long)df.bps * (unsigned long long)df.avail_clusters); printf("total_bytes(%llu)\n", (unsigned long long)df.spc * (unsigned long long)df.bps * (unsigned long long)df.total_clusters); return 0; } """) results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 +1" $_floppy_a = "" """) self.assertNotIn("Call failed", results) fsinfo = statvfs(self.workdir) lfs_total = fsinfo.f_blocks * fsinfo.f_bsize lfs_avail = fsinfo.f_bavail * fsinfo.f_bsize t = re.search(r'total_bytes\((\d+)\)', results) self.assertIsNotNone(t, "Unable to parse 'total_bytes'") dfs_total = int(t.group(1)) a = re.search(r'avail_bytes\((\d+)\)', results) self.assertIsNotNone(a, "Unable to parse 'avail_bytes'") dfs_avail = int(a.group(1)) # see if we are within 5% of the values obtained from Linux msg = "total dos %d, linux %d" % (dfs_total, lfs_total) self.assertLessEqual(dfs_total, lfs_total * 1.05, msg) self.assertGreaterEqual(dfs_total, lfs_total * 0.95, msg) msg = "avail dos %d, linux %d" % (dfs_avail, lfs_avail) self.assertLessEqual(dfs_avail, lfs_avail * 1.05, msg) self.assertGreaterEqual(dfs_avail, lfs_avail * 0.95, msg) def test_int21_disk_info(self): """INT21 disk info""" path = "C:\\" self.mkfile("testit.bat", """\ c:\\int21dif %s rem end """ % path, newline="\r\n") # compile sources self.mkexe_with_djgpp("int21dif", r"""\ #include #include #include struct dinfo { uint16_t spc; uint16_t avail_clusters; uint16_t bps; uint16_t total_clusters; }; #define MAXPATH 128 int main(int argc, char *argv[]) { struct dinfo df; uint8_t carry; uint16_t ax, bx, cx, dx; int len; if (argc < 2) { printf("path argument missing e.g. 'C:\\'\n"); return 3; } len = strlen(argv[1]) + 1; if (len > MAXPATH) { printf("path argument too long\n"); return 2; } if (argv[1][0] && argv[1][1] == ':') { if (argv[1][0] == 'a' || argv[1][0] == 'A') dx = 1; else if (argv[1][0] == 'b' || argv[1][0] == 'B') dx = 2; else if (argv[1][0] == 'c' || argv[1][0] == 'C') dx = 3; else if (argv[1][0] == 'd' || argv[1][0] == 'D') dx = 4; else { printf("Drive out of range\n"); return 2; } } else { printf("Drive used is default\n"); dx = 0; // default drive } /* AH = 36h DL = drive number (00h = default, 01h = A:, etc) Return: AX = FFFFh if invalid drive else AX = sectors per cluster BX = number of free clusters CX = bytes per sector DX = total clusters on drive */ asm volatile("stc\n" "int $0x21\n" : "=a"(ax), "=b"(bx), "=c"(cx), "=d"(dx) : "a"(0x3600), "d"(dx) : "cc", "memory"); if (ax == 0xffff) { printf("Call failed, AX = 0x%04x\n", ax); return 1; } printf("spc 0x%04x\n", ax); printf("avail_clusters 0x%04x\n", bx); printf("bps 0x%04x\n", cx); printf("total_clusters 0x%04x\n", dx); printf("avail_bytes(%llu)\n", (unsigned long long)ax * (unsigned long long)cx * (unsigned long long)bx); printf("total_bytes(%llu)\n", (unsigned long long)ax * (unsigned long long)cx * (unsigned long long)dx); return 0; } """) results = self.runDosemu("testit.bat", config="""\ $_hdimage = "dXXXXs/c:hdtype1 +1" $_floppy_a = "" """) self.assertNotIn("Call failed", results) fsinfo = statvfs(self.workdir) lfs_total = fsinfo.f_blocks * fsinfo.f_bsize lfs_avail = fsinfo.f_bavail * fsinfo.f_bsize t = re.search(r'total_bytes\((\d+)\)', results) dfs_total = int(t.group(1)) a = re.search(r'avail_bytes\((\d+)\)', results) dfs_avail = int(a.group(1)) # see if we are within 5% of the values obtained from Linux if lfs_total > 2147450880: lfs_total = 2147450880 if lfs_avail > 2147450880: lfs_avail = 2147450880 msg = "total dos %d, linux %d" % (dfs_total, lfs_total) self.assertLessEqual(dfs_total, lfs_total * 1.05, msg) self.assertGreaterEqual(dfs_total, lfs_total * 0.95, msg) msg = "avail dos %d, linux %d" % (dfs_avail, lfs_avail) self.assertLessEqual(dfs_avail, lfs_avail * 1.05, msg) self.assertGreaterEqual(dfs_avail, lfs_avail * 0.95, msg) def test_mfs_lfs_file_info_1MiB(self): """MFS LFS file info (1 MiB)""" lfs_file_info(self, "MFS", "1MiB") def test_mfs_lfs_file_info_6GiB(self): """MFS LFS file info (6 GiB)""" lfs_file_info(self, "MFS", "6GiB") def test_mfs_lfs_file_seek_tell_set(self): """MFS LFS file seek tell set""" lfs_file_seek_tell(self, "MFS", "SET") def test_mfs_lfs_file_seek_tell_cur(self): """MFS LFS file seek tell current""" lfs_file_seek_tell(self, "MFS", "CUR") def test_mfs_lfs_file_seek_tell_end(self): """MFS LFS file seek tell end""" lfs_file_seek_tell(self, "MFS", "END") def _test_ds2_get_ftime(self, fstype, tstype): testdir = self.mkworkdir('d') self.mkfile("testit.bat", """\ d: c:\\getftime %s rem end """ % tstype, newline="\r\n") # compile sources self.mkexe_with_djgpp("getftime", r""" #include #include #include #include #include int gettest(const char *fname) { int handle; int ret; unsigned int date, time; unsigned int year, month, day, hour, minute, second; ret = _dos_open(fname, O_RDONLY, &handle); if (ret != 0) { printf("FAIL: File '%s' not opened\n", fname); return -1; } _dos_getftime(handle, &date, &time); _dos_close(handle); year = ((date >> 9) & 0x7f) + 1980; month = (date >> 5) & 0x0f; day = (date & 0x1f); hour = (time >> 11) & 0x1f; minute = (time >> 5) & 0x3f; second = (time & 0x1f) * 2; // 2018-08-13 10:10:51 printf("%s: %04u-%02u-%02u %02u:%02u:%02u\n", fname, year, month, day, hour, minute, second); return 0; } int main(int argc, char *argv[]) { unsigned int val; int ret; char fname[13]; if (argc < 2) { printf("FAIL: missing argument\n"); return -2; } if (strcmp(argv[1], "DATE") == 0) { // Year for (val = 1980; val <= 2099; val++) { sprintf(fname, "%08u.YR", val); if (gettest(fname) < 0) return -1; } // Month for (val = 1; val <= 12; val++) { sprintf(fname, "%08u.MN", val); if (gettest(fname) < 0) return -1; } // Day for (val = 1; val <= 31; val++) { sprintf(fname, "%08u.DY", val); if (gettest(fname) < 0) return -1; } } else if (strcmp(argv[1], "TIME") == 0) { // Hour for (val = 0; val <= 23; val++) { sprintf(fname, "%08u.HR", val); if (gettest(fname) < 0) return -1; } // Minute for (val = 0; val <= 59; val++) { sprintf(fname, "%08u.MI", val); if (gettest(fname) < 0) return -1; } // Seconds for (val = 0; val <= 59; val += 2) { sprintf(fname, "%08u.SC", val); if (gettest(fname) < 0) return -1; } } else { printf("FAIL: argument not DATE or TIME\n"); return -2; } return 0; } """) def settime(fn, Y, M, D, h, m, s): date = datetime(year=Y, month=M, day=D, hour=h, minute=m, second=s) modTime = mktime(date.timetuple()) utime(join(testdir, fname), (modTime, modTime)) YEARS = range(1980, 2099 + 1) if tstype == "DATE" else [] for i in YEARS: fname = "%08d.YR" % i self.mkfile(fname, "some content", dname=testdir) settime(fname, i, 1, 1, 0, 0, 0) MONTHS = range(1, 12 + 1) if tstype == "DATE" else [] for i in MONTHS: fname = "%08d.MN" % i self.mkfile(fname, "some content", dname=testdir) settime(fname, 1980, i, 1, 0, 0, 0) DAYS = range(1, 31 + 1) if tstype == "DATE" else [] for i in DAYS: fname = "%08d.DY" % i self.mkfile(fname, "some content", dname=testdir) settime(fname, 1980, 1, i, 0, 0, 0) HOURS = range(0, 23 + 1) if tstype == "TIME" else [] for i in HOURS: fname = "%08d.HR" % i self.mkfile(fname, "some content", dname=testdir) settime(fname, 1980, 1, 1, i, 0, 0) MINUTES = range(0, 59 + 1) if tstype == "TIME" else [] for i in MINUTES: fname = "%08d.MI" % i self.mkfile(fname, "some content", dname=testdir) settime(fname, 1980, 1, 1, 0, i, 0) SECONDS = range(0, 59 + 1, 2) if tstype == "TIME" else [] for i in SECONDS: fname = "%08d.SC" % i self.mkfile(fname, "some content", dname=testdir) settime(fname, 1980, 1, 1, 0, 0, i) if fstype == "MFS": config="""\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """ else: # FAT name = self.mkimage("12", cwd=testdir) config="""\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" $_floppy_a = "" """ % name results = self.runDosemu("testit.bat", config=config) for i in YEARS: self.assertIn("%08d.YR: %04d-01-01 00:00:00" % (i, i), results) for i in MONTHS: self.assertIn("%08d.MN: 1980-%02d-01 00:00:00" % (i, i), results) for i in DAYS: self.assertIn("%08d.DY: 1980-01-%02d 00:00:00" % (i, i), results) for i in HOURS: self.assertIn("%08d.HR: 1980-01-01 %02d:00:00" % (i, i), results) for i in MINUTES: self.assertIn("%08d.MI: 1980-01-01 00:%02d:00" % (i, i), results) for i in SECONDS: self.assertIn("%08d.SC: 1980-01-01 00:00:%02d" % (i, i), results) self.assertNotIn("FAIL:", results) def test_mfs_ds2_get_ftime(self): """MFS DOSv2 get file time""" self._test_ds2_get_ftime("MFS", "DATE") self._test_ds2_get_ftime("MFS", "TIME") def test_fat_ds2_get_ftime(self): """FAT DOSv2 get file time""" # Note: we need to split this test as FAT cannot have enough files # in the root directory, and mkimage can't store them in a # subdirectory. self._test_ds2_get_ftime("FAT", "DATE") self._test_ds2_get_ftime("FAT", "TIME") def _test_ds2_set_ftime(self, fstype): testdir = self.mkworkdir('d') self.mkfile("testit.bat", """\ d: c:\\setftime rem end """, newline="\r\n") # compile sources self.mkexe_with_djgpp("setftime", r""" /* Most of this was copied from DJGPP docs at http://www.delorie.com/djgpp/doc/libc/libc_181.html */ #include #include #include #include #define FNAME "FOO.DAT" int settest(unsigned int year, unsigned int month, unsigned int day, unsigned int hour, unsigned int minute, unsigned int second) { int handle; struct find_t f; int ret; unsigned int date, time; unsigned int _year, _month, _day, _hour, _minute, _second; _dos_creat(FNAME, _A_NORMAL, &handle); date = ((year - 1980) << 9) | (month << 5) | day; time = (hour << 11) | (minute << 5) | (second / 2); _dos_setftime(handle, date, time); _dos_close(handle); ret = _dos_findfirst(FNAME, _A_NORMAL, &f); if (ret != 0) { printf("FAIL: File '%s' not found\n", FNAME); return -1; } _year = ((f.wr_date >> 9) & 0x7f) + 1980; _month = (f.wr_date >> 5) & 0x0f; _day = (f.wr_date & 0x1f); _hour = (f.wr_time >> 11) & 0x1f; _minute = (f.wr_time >> 5) & 0x3f; _second = (f.wr_time & 0x1f) * 2; second &= ~1; // DOS has 2 second resolution so round down the target if ((year != _year) || (month != _month) || (day != _day) || (hour != _hour) || (minute != _minute) || (second != _second)) { printf("FAIL: mismatch year(%u -> %u), month(%u -> %u), day(%u -> %u)\n", year, _year, month, _month, day, _day); printf(" hour(%u -> %u), minute(%u -> %u), second(%u -> %u)\n", hour, _hour, minute, _minute, second, _second); return -2; } return 0; } int main(void) { unsigned int val; int ret; // Year for (val = 1980; val <= 2099; val++) { if (settest(val, 1, 1, 0, 0, 0) < 0) return -1; } printf("OKAY: years matched\n"); // Month for (val = 1; val <= 12; val++) { if (settest(1980, val, 1, 0, 0, 0) < 0) return -1; } printf("OKAY: months matched\n"); // Day for (val = 1; val <= 31; val++) { if (settest(1980, 1, val, 0, 0, 0) < 0) return -1; } printf("OKAY: days matched\n"); // Hour for (val = 0; val <= 23; val++) { if (settest(1980, 1, 1, val, 0, 0) < 0) return -1; } printf("OKAY: hours matched\n"); // Minute for (val = 0; val <= 59; val++) { if (settest(1980, 1, 1, 0, val, 0) < 0) return -1; } printf("OKAY: minutes matched\n"); // Seconds for (val = 0; val <= 59; val++) { if (settest(1980, 1, 1, 0, 0, val) < 0) return -1; } printf("OKAY: seconds matched\n"); printf("PASS: Set values are retrieved and matched\n"); return 0; } """) if fstype == "MFS": config="""\ $_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1" $_floppy_a = "" """ else: # FAT name = self.mkimage("12", cwd=testdir) config="""\ $_hdimage = "dXXXXs/c:hdtype1 %s +1" $_floppy_a = "" """ % name results = self.runDosemu("testit.bat", config=config) self.assertNotIn("FAIL:", results) def test_mfs_ds2_set_ftime(self): """MFS DOSv2 set file time""" self._test_ds2_set_ftime("MFS") def test_fat_ds2_set_ftime(self): """FAT DOSv2 set file time""" self._test_ds2_set_ftime("FAT") def test_mfs_ds2_set_fattrs(self): """MFS DOSv2 set file attrs""" tests = ('RDONLY', 'HIDDEN', 'SYSTEM') for t in tests: with self.subTest(t=t): ds2_set_fattrs(self, "MFS", t) def test_fat_ds2_set_fattrs(self): """FAT DOSv2 set file attrs""" tests = ('RDONLY', 'HIDDEN', 'SYSTEM') for t in tests: with self.subTest(t=t): ds2_set_fattrs(self, "FAT", t) def test_fat_ds3_file_access_read(self): """FAT DOSv3 file access read""" ds3_file_access(self, "FAT", "READ") def test_mfs_ds3_file_access_read(self): """MFS DOSv3 file access read""" ds3_file_access(self, "MFS", "READ") def test_fat_ds3_file_access_write(self): """FAT DOSv3 file access write""" ds3_file_access(self, "FAT", "WRITE") def test_mfs_ds3_file_access_write(self): """MFS DOSv3 file access write""" ds3_file_access(self, "MFS", "WRITE") def test_fat_ds3_file_access_read_device_readonly(self): """FAT DOSv3 file access read device readonly""" ds3_file_access(self, "FATRO", "READ") def test_mfs_ds3_file_access_read_device_readonly(self): """MFS DOSv3 file access read device readonly""" ds3_file_access(self, "MFSRO", "READ") def test_fat_ds3_file_access_write_device_readonly(self): """FAT DOSv3 file access write device readonly""" ds3_file_access(self, "FATRO", "WRITE") def test_mfs_ds3_file_access_write_device_readonly(self): """MFS DOSv3 file access write device readonly""" ds3_file_access(self, "MFSRO", "WRITE") def test_mfs_ds3_lock_readonly(self): """MFS DOSv3 lock file readonly""" ds3_lock_readonly(self, "MFS") def test_fat_ds3_lock_readonly(self): """FAT DOSv3 lock file readonly""" ds3_lock_readonly(self, "FAT") def test_mfs_ds3_lock_readlckd(self): """MFS DOSv3 lock file read locked""" ds3_lock_readlckd(self, "MFS") def test_fat_ds3_lock_readlckd(self): """FAT DOSv3 lock file read locked""" ds3_lock_readlckd(self, "FAT") def test_mfs_ds3_lock_concurrent(self): """MFS DOSv3 lock file lock concurrent limit""" ds3_lock_concurrent(self, "MFS") def test_fat_ds3_lock_concurrent(self): """FAT DOSv3 lock file lock concurrent limit""" ds3_lock_concurrent(self, "FAT") def test_mfs_ds3_lock_two_handles(self): """MFS DOSv3 lock file lock with two handles""" ds3_lock_two_handles(self, "MFS") def test_fat_ds3_lock_two_handles(self): """FAT DOSv3 lock file lock with two handles""" ds3_lock_two_handles(self, "FAT") def test_mfs_ds3_lock_twice(self): """MFS DOSv3 lock file twice""" ds3_lock_twice(self, "MFS") def test_fat_ds3_lock_twice(self): """FAT DOSv3 lock file twice""" ds3_lock_twice(self, "FAT") def test_mfs_ds3_lock_writable(self): """MFS DOSv3 lock file writable""" ds3_lock_writable(self, "MFS") def test_fat_ds3_lock_writable(self): """FAT DOSv3 lock file writable""" ds3_lock_writable(self, "FAT") def test_mfs_ds3_share_open_twice(self): """MFS DOSv3 share open twice""" ds3_share_open_twice(self, "MFS") def test_fat_ds3_share_open_twice(self): """FAT DOSv3 share open twice""" ds3_share_open_twice(self, "FAT") def test_mfs_ds3_share_open_delete_ds2(self): """MFS DOSv3 share open delete DOSv2""" ds3_share_open_access(self, "MFS", "DELPTH") def test_fat_ds3_share_open_delete_ds2(self): """FAT DOSv3 share open delete DOSv2""" ds3_share_open_access(self, "FAT", "DELPTH") def test_mfs_ds3_share_open_delete_fcb(self): """MFS DOSv3 share open delete FCB""" ds3_share_open_access(self, "MFS", "DELFCB") def test_fat_ds3_share_open_delete_fcb(self): """FAT DOSv3 share open delete FCB""" ds3_share_open_access(self, "FAT", "DELFCB") def test_mfs_ds3_share_open_rename_ds2(self): """MFS DOSv3 share open rename DOSv2""" ds3_share_open_access(self, "MFS", "RENPTH") def test_fat_ds3_share_open_rename_ds2(self): """FAT DOSv3 share open rename DOSv2""" ds3_share_open_access(self, "FAT", "RENPTH") def test_mfs_ds3_share_open_rename_fcb(self): """MFS DOSv3 share open rename FCB""" ds3_share_open_access(self, "MFS", "RENFCB") def test_fat_ds3_share_open_rename_fcb(self): """FAT DOSv3 share open rename FCB""" ds3_share_open_access(self, "FAT", "RENFCB") def test_mfs_ds3_share_open_setfattrs(self): """MFS DOSv3 share open set file attrs DOSv2""" ds3_share_open_access(self, "MFS", "SETATT") def test_fat_ds3_share_open_setfattrs(self): """FAT DOSv3 share open set file attrs DOSv2""" ds3_share_open_access(self, "FAT", "SETATT") def _test_cpu(self, cpu_vm, cpu_vm_dpmi, cpu_emu): if ('kvm' in cpu_vm or 'kvm' in cpu_vm_dpmi) and not access("/dev/kvm", W_OK|R_OK): self.skipTest("No KVM available") if cpu_vm == 'vm86' and uname()[4] == 'x86_64': self.skipTest("x86_64 doesn't support native vm86()") edir = self.topdir / "test" / "cpu" try: check_call(['make', '-C', str(edir), 'all'], stdout=DEVNULL, stderr=DEVNULL) except CalledProcessError as e: self.skipTest("Unable to build test binaries '%s'" % e) copy(edir / "dosbin.exe", self.workdir / "dosbin.exe") reffile = "reffile.log" dosfile = "dosfile.log" # reference file try: with open(self.topdir / reffile, "w") as f: check_call([str(edir / 'native32'), '--common-tests'], stdout=f, stderr=DEVNULL) except CalledProcessError as e: self.skipTest("Host reference file error '%s'" % e) refoutput = [] try: with open(self.topdir / reffile, "r") as f: refoutput = f.readlines() except FileNotFoundError as e: self.fail("Could not open reference file error '%s'" % e) # output from dos under test self.mkfile("testit.bat", """\ dosbin --common-tests > %s rem end """ % dosfile, newline="\r\n") self.runDosemu("testit.bat", timeout=20, config="""\ $_hdimage = "dXXXXs/c:hdtype1 +1" $_floppy_a = "" $_cpu_vm = "%s" $_cpu_vm_dpmi = "%s" $_cpuemu = (%i) $_ignore_djgpp_null_derefs = (off) """%(cpu_vm, cpu_vm_dpmi, cpu_emu)) dosoutput = [] try: with open(self.workdir / dosfile, "r") as f: dosoutput = f.readlines() except FileNotFoundError: self.fail("DOS output file not found") # Compare DOS output to reference file if dosoutput != refoutput: diff = unified_diff(refoutput, dosoutput, fromfile=reffile, tofile=dosfile) self.fail('differences detected\n' + ''.join(list(diff))) def test_cpu_1_vm86native(self): """CPU test: native vm86 + native DPMI (i386 only)""" self._test_cpu("vm86", "native", 0) test_cpu_1_vm86native.cputest = True def test_cpu_2_jitnative(self): """CPU test: JIT vm86 + native DPMI""" self._test_cpu("emulated", "native", 0) test_cpu_2_jitnative.cputest = True def test_cpu_jitkvm(self): """CPU test: JIT vm86 + KVM DPMI""" self._test_cpu("emulated", "kvm", 0) test_cpu_jitkvm.cputest = True def test_cpu_simnative(self): """CPU test: simulated vm86 + native DPMI""" self._test_cpu("emulated", "native", 1) test_cpu_simnative.cputest = True def test_cpu_simkvm(self): """CPU test: simulated vm86 + KVM DPMI""" self._test_cpu("emulated", "kvm", 1) test_cpu_simkvm.cputest = True def test_cpu_kvmnative(self): """CPU test: KVM vm86 + native DPMI""" self._test_cpu("kvm", "native", 0) test_cpu_kvmnative.cputest = True def test_cpu_kvm(self): """CPU test: KVM vm86 + KVM DPMI""" self._test_cpu("kvm", "kvm", 0) test_cpu_kvm.cputest = True def test_cpu_kvmjit(self): """CPU test: KVM vm86 + JIT DPMI""" self._test_cpu("kvm", "emulated", 0) test_cpu_kvmjit.cputest = True def test_cpu_kvmsim(self): """CPU test: KVM vm86 + simulated DPMI""" self._test_cpu("kvm", "emulated", 1) test_cpu_kvmsim.cputest = True def test_cpu_jit(self): """CPU test: JIT vm86 + JIT DPMI""" self._test_cpu("emulated", "emulated", 0) test_cpu_jit.cputest = True def test_cpu_sim(self): """CPU test: simulated vm86 + simulated DPMI""" self._test_cpu("emulated", "emulated", 1) test_cpu_sim.cputest = True def test_cpu_trap_flag_emulated(self): """CPU Trap Flag emulated""" cpu_trap_flag(self, 'emulated') test_cpu_trap_flag_emulated.cputest = True def test_cpu_trap_flag_kvm(self): """CPU Trap Flag KVM""" cpu_trap_flag(self, 'kvm') test_cpu_trap_flag_kvm.cputest = True def test_libi86_build(self): """libi86 build and test script""" if environ.get("SKIP_EXPENSIVE"): self.skipTest("expensive test") i86repo = 'https://github.com/tkchia/libi86.git' i86root = self.imagedir / 'i86root.git' args = ["git", "clone", "-q"] args += ["--single-branch", "--branch=20220105"] args += [i86repo, str(i86root)] call(args, stdout=DEVNULL, stderr=DEVNULL) self.mkfile("dosemu.conf", """\ $_hdimage = "dXXXXs/c:hdtype1 +1" $_floppy_a = "" """, dname=self.imagedir, mode="a") dose = self.topdir / "bin" / "dosemu" opts = '-f {0}/dosemu.conf -n --Fimagedir {0}'.format(self.imagedir) build = i86root / "build-xxxx" build.mkdir() if environ.get("CC"): del environ["CC"] # logfiles # - dosemu log not applicable as libi86 test suite invokes dosemu multiple times # - libi86 test suite has its own log file called 'testsuite.log' # which contains configure, build, and test. We will present it as # our usual output log # - expect log is not present as it's run non-interactively self.logfiles['log'][1] = "testsuite.log" del self.logfiles['xpt'] check_call(['../configure', '--host=ia16-elf', '--disable-elks-libc'], cwd=build, env=environ, stdout=DEVNULL, stderr=DEVNULL) check_call(['make'], cwd=build, env=environ, stdout=DEVNULL, stderr=DEVNULL) try: environ["TESTSUITEFLAGS"] = "--x-test-underlying --x-with-dosemu=%s --x-with-dosemu-options=\"%s\"" % (dose, opts) starttime = datetime.utcnow() check_call(['make', 'check'], cwd=build, env=environ, timeout=900, stdout=DEVNULL, stderr=DEVNULL) self.duration = datetime.utcnow() - starttime except CalledProcessError: copy(build / "tests" / "testsuite.log", self.logfiles['log'][0]) raise self.failureException("Test error") from None except TimeoutExpired: copy(build / "tests" / "testsuite.log", self.logfiles['log'][0]) raise self.failureException("Test timeout") from None def test_pcmos_build(self): """PC-MOS build script""" if environ.get("SKIP_EXPENSIVE"): self.skipTest("expensive test") mosrepo = 'https://github.com/roelandjansen/pcmos386v501.git' mosroot = self.imagedir / 'pcmos.git' call(["git", "clone", "-q", "--depth=1", mosrepo, str(mosroot)]) outfiles = [mosroot / 'SOURCES/src/latest' / x for x in [ '$286n.sys', '$386.sys', '$all.sys', '$arnet.sys', '$charge.sys', '$ems.sys', '$gizmo.sys', '$kbbe.sys', '$kbcf.sys', '$kbdk.sys', '$kbfr.sys', '$kbgr.sys', '$kbit.sys', '$kbla.sys', '$kbnl.sys', '$kbno.sys', '$kbpo.sys', '$kbsf.sys', '$kbsg.sys', '$kbsp.sys', '$kbsv.sys', '$kbuk.sys', 'minbrdpc.sys', 'mosdd7f.sys', '$$mos.sys', '$mouse.sys', '$netbios.sys', '$pipe.sys', '$ramdisk.sys', '$serial.sys', '$$shell.sys']] for outfile in outfiles: outfile.unlink(missing_ok=True) # Run the equivalent of the MOSROOT/build.sh script from MOSROOT # Note: # We have to avoid runDosemu() as this test is non-interactive args = ["-K", r".:SOURCES\src", "-E", "MAKEMOS.BAT", r"path=%D\bin;%O"] results = self.runDosemuCmdline(args, cwd=str(mosroot), timeout=300, config="""\ $_hdimage = "dXXXXs/c:hdtype1 +1" $_floppy_a = "" """) if results == 'Timeout': raise self.failureException("Timeout:\n") missing = [str(x.relative_to(mosroot)) for x in outfiles if not x.exists()] if len(missing): msg = "Output file(s) missing %s\n" % str(missing) raise self.failureException(msg) class DRDOS701TestCase(OurTestCase, unittest.TestCase): # OpenDOS 7.01 @classmethod def setUpClass(cls): super(DRDOS701TestCase, cls).setUpClass() cls.version = "Caldera OpenDOS 7.01" cls.prettyname = "DR-DOS-7.01" cls.files = [ ("ibmbio.com", "61211eb63329a67fdd9d336271f06e1bfdab2b6f"), ("ibmdos.com", "52e71c8e9d74100f138071acaecdef4a79b67d3c"), ("command.com", "4bc38f973b622509aedad8c6af0eca59a2d90fca"), ("share.exe", "10f2c0e2cabe98617faa017806c80476b3b6c1e1"), ] cls.systype = SYSTYPE_DRDOS_ORIGINAL cls.autoexec = "dautoemu.bat" cls.confsys = "dconfig.sys" cls.bootblocks = [ ("boot-306-4-17.blk", "1151ab9a3429163ac3ddf55b88d81359cb6975e5"), ("boot-615-4-17.blk", "a18ee96e63e384b766bafc4ff936e4087c31bf59"), ("boot-900-15-17.blk", "2ea4ea747f6e62a8ea46f14f6c9af1ad6fd0126b"), ] cls.images = [ ("boot-floppy.img", "d38fb2dba30185ce510cf3366bd71a1cbc2635da"), ] cls.actions = { "test_fat_ds3_share_open_setfattrs": KNOWNFAIL, "test_fat_fcb_rename_simple": KNOWNFAIL, "test_fat_fcb_rename_wild_1": KNOWNFAIL, "test_fat_fcb_rename_wild_2": KNOWNFAIL, "test_fat_fcb_rename_wild_3": KNOWNFAIL, "test_fat_fcb_rename_wild_4": KNOWNFAIL, "test_mfs_fcb_rename_simple": KNOWNFAIL, "test_mfs_fcb_rename_wild_1": KNOWNFAIL, "test_mfs_fcb_rename_wild_2": KNOWNFAIL, "test_mfs_fcb_rename_wild_3": KNOWNFAIL, "test_mfs_fcb_rename_wild_4": KNOWNFAIL, "test_mfs_truename_ufs_sfn": KNOWNFAIL, "test_mfs_truename_vfat_linux_mounted_sfn": KNOWNFAIL, "test_floppy_vfs": KNOWNFAIL, "test_pcmos_build": KNOWNFAIL, } cls.setUpClassPost() def setUpDosAutoexec(self): # Use the (almost) standard shipped config contents = (self.topdir / "src" / "bindist" / self.autoexec).read_text() contents = re.sub(r"[Dd]:\\", r"c:\\", contents) self.mkfile(self.autoexec, contents, newline="\r\n") def setUpDosConfig(self): # Link back to std dosemu commands and scripts p = self.workdir / "dosemu" p.symlink_to(self.topdir / "commands" / "dosemu") # Use the (almost) standard shipped config contents = (self.topdir / "src" / "bindist" / self.confsys).read_text() contents = re.sub(r"[Dd]:\\", r"c:\\", contents) contents = re.sub(r"rem SWITCHES=/F", r"SWITCHES=/F", contents) self.mkfile(self.confsys, contents, newline="\r\n") def setUpDosVersion(self): self.mkfile("version.bat", "ver\r\nrem end\r\n") class FRDOS120TestCase(OurTestCase, unittest.TestCase): @classmethod def setUpClass(cls): super(FRDOS120TestCase, cls).setUpClass() cls.version = "FreeDOS kernel 2042" cls.prettyname = "FR-DOS-1.20" cls.files = [ ("kernel.sys", "0709f4e7146a8ad9b8acb33fe3fed0f6da9cc6e0"), ("command.com", "0733db7babadd73a1b98e8983c83b96eacef4e68"), ("share.com", "cadc29d49115cb3a250f90921cca345e7c427464"), ] cls.systype = SYSTYPE_FRDOS_NEW cls.autoexec = "fdautoem.bat" cls.confsys = "fdconfig.sys" cls.bootblocks = [ ("boot-302-4-17.blk", "8b5cfda502e59b067d1e34e993486440cad1d4f7"), ("boot-603-4-17.blk", "5c89a0c9c20ba9d581d8bf6969fda88df8ab2d45"), ("boot-900-15-17.blk", "523f699a79edde098fceee398b15711fac56a807"), ] cls.images = [ ("boot-floppy.img", "c3faba3620c578b6e42a6ef26554cfc9d2ee3258"), ] cls.actions = { "test_fat_fcb_rename_target_exists": KNOWNFAIL, "test_fat_fcb_rename_source_missing": KNOWNFAIL, "test_fat_fcb_rename_wild_1": KNOWNFAIL, "test_fat_fcb_rename_wild_2": KNOWNFAIL, "test_fat_fcb_rename_wild_3": KNOWNFAIL, "test_mfs_fcb_rename_target_exists": KNOWNFAIL, "test_mfs_fcb_rename_source_missing": KNOWNFAIL, "test_mfs_fcb_rename_wild_1": KNOWNFAIL, "test_mfs_fcb_rename_wild_2": KNOWNFAIL, "test_mfs_fcb_rename_wild_3": KNOWNFAIL, "test_mfs_fcb_rename_wild_4": KNOWNFAIL, "test_fat_fcb_find_wild_1": KNOWNFAIL, "test_fat_fcb_find_wild_2": KNOWNFAIL, "test_fat_fcb_find_wild_3": KNOWNFAIL, "test_mfs_fcb_find_wild_1": KNOWNFAIL, "test_mfs_fcb_find_wild_2": KNOWNFAIL, "test_mfs_fcb_find_wild_3": KNOWNFAIL, "test_mfs_lfs_file_info_1MiB": KNOWNFAIL, "test_mfs_lfs_file_info_6GiB": KNOWNFAIL, "test_mfs_lfs_file_seek_tell_set": KNOWNFAIL, "test_mfs_lfs_file_seek_tell_cur": KNOWNFAIL, "test_mfs_lfs_file_seek_tell_end": KNOWNFAIL, "test_mfs_lredir_command": KNOWNFAIL, "test_mfs_lredir_command_no_perm": KNOWNFAIL, "test_fat_ds3_lock_writable": KNOWNFAIL, "test_fat_ds3_lock_readlckd": KNOWNFAIL, "test_fat_ds3_lock_two_handles": KNOWNFAIL, "test_mfs_truename_vfat_linux_mounted_lfn": KNOWNFAIL, "test_mfs_truename_vfat_linux_mounted_sfn": KNOWNFAIL, "test_mfs_findfile_vfat_linux_mounted_lfn": KNOWNFAIL, "test_mfs_findfile_vfat_linux_mounted_sfn": KNOWNFAIL, "test_fat_ds3_share_open_twice": KNOWNFAIL, "test_fat_ds3_share_open_delete_ds2": KNOWNFAIL, "test_fat_ds3_share_open_delete_fcb": KNOWNFAIL, "test_fat_ds3_share_open_rename_ds2": KNOWNFAIL, "test_fat_ds3_share_open_rename_fcb": KNOWNFAIL, "test_mfs_ds3_share_open_rename_fcb": KNOWNFAIL, "test_fat_ds3_share_open_setfattrs": KNOWNFAIL, "test_create_new_psp": KNOWNFAIL, "test_command_com_keyword_exist": KNOWNFAIL, "test_memory_emm286_borland": KNOWNFAIL, "test_pcmos_build": KNOWNFAIL, "test_libi86_build": KNOWNFAIL, } cls.setUpClassPost() def setUpDosAutoexec(self): # Use the (almost) standard shipped config contents = (self.topdir / "src" / "bindist" / self.autoexec).read_text() contents = re.sub(r"[Dd]:\\", r"c:\\", contents) self.mkfile(self.autoexec, contents, newline="\r\n") def setUpDosConfig(self): # Link back to std dosemu commands and scripts p = self.workdir / "dosemu" p.symlink_to(self.topdir / "commands" / "dosemu") # Use the (almost) standard shipped config contents = (self.topdir / "src" / "bindist" / "c" / self.confsys).read_text() contents = re.sub(r"[Dd]:\\", r"c:\\", contents) contents = re.sub(r"rem SWITCHES=/F", r"SWITCHES=/F", contents) self.mkfile(self.confsys, contents, newline="\r\n") class MSDOS622TestCase(OurTestCase, unittest.TestCase): @classmethod def setUpClass(cls): super(MSDOS622TestCase, cls).setUpClass() cls.version = "MS-DOS Version 6.22" cls.prettyname = "MS-DOS-6.22" cls.files = [ ("io.sys", "d697961ca6edaf9a1aafe8b7eb949597506f7f95"), ("msdos.sys", "d6a5f54006e69c4407e56677cd77b82395acb60a"), ("command.com", "c2179d2abfa241edd388ab875cfabbac89fec44d"), ("share.exe", "9e7385cfa91a012638520e89b9884e4ce616d131"), ("dos/himem.sys", "fb41fbc1c4bdd8652d445055508bc8265bc64aea"), ] cls.systype = SYSTYPE_MSDOS_INTERMEDIATE cls.autoexec = "autoemu.bat" cls.bootblocks = [ ("boot-306-4-17.blk", "d40c24ef5f5f9fd6ef28c29240786c70477a0b06"), ("boot-615-4-17.blk", "7fc96777727072471dbaab6f817c8d13262260d2"), ("boot-900-15-17.blk", "2a0ca1b87b82013fd417542a5ac28e965fb13e7a"), ] cls.images = [ ("boot-floppy.img", "14b8310910bf19d6e375298f3b06da7ffdec9932"), ] cls.setUpClassPost() def setUpDosAutoexec(self): # Use the (almost) standard shipped config contents = (self.topdir / "src" / "bindist" / self.autoexec).read_text() contents = re.sub(r"[Dd]:\\", r"c:\\", contents) self.mkfile(self.autoexec, contents, newline="\r\n") def setUpDosConfig(self): # Link back to std dosemu commands and scripts p = self.workdir / "dosemu" p.symlink_to(self.topdir / "commands" / "dosemu") # Use the (almost) standard shipped config contents = (self.topdir / "src" / "bindist" / "c" / self.confsys).read_text() contents = re.sub(r"[Dd]:\\", r"c:\\", contents) contents = re.sub(r"rem SWITCHES=/F", r"SWITCHES=/F", contents) self.mkfile(self.confsys, contents, newline="\r\n") def setUpDosVersion(self): self.mkfile("version.bat", "ver\r\nrem end\r\n") class PPDOSGITTestCase(OurTestCase, unittest.TestCase): @classmethod def setUpClass(cls): super(PPDOSGITTestCase, cls).setUpClass() cls.version = "FDPP kernel" cls.prettyname = "PP-DOS-GIT" cls.actions = { "test_floppy_img": UNSUPPORTED, "test_floppy_vfs": UNSUPPORTED, } # Use the default files that FDPP installed cls.tarfile = "" cls.systype = SYSTYPE_FDPP cls.autoexec = "fdppauto.bat" cls.confsys = "fdppconf.sys" cls.setUpClassPost() if __name__ == '__main__': tests = [t[0] for t in inspect.getmembers(OurTestCase, predicate=inspect.isfunction) if t[0].startswith("test")] xtests = [t[0] for t in inspect.getmembers(OurTestCase, predicate=inspect.isfunction) if t[0].startswith("xtest")] cases = [c[0] for c in inspect.getmembers(modules[__name__], predicate=inspect.isclass) if issubclass(c[1], OurTestCase) and c[0] != "OurTestCase"] def explode(n, attr=None): if n in tests: return [c + "." + n for c in cases] if n in xtests: return [c + "." + n for c in cases] if n in cases: if attr: return [n + "." + t[0] for t in inspect.getmembers(OurTestCase, predicate=inspect.isfunction) if hasattr(t[1], attr)] else: return [n,] p = n.split('.') if p and p[0] in cases and (p[1] in tests or p[1] in xtests): return [n,] return [] if len(argv) > 1: if argv[1] == "--help": print("Usage: %s [--help | --list-cases | --list-tests] | [--require-attr=STRING TestCase ...] | [TestCase[.testname] ...]" % argv[0]) exit(0) elif argv[1] == "--list-cases": for m in cases: print(str(m)) exit(0) elif argv[1] == "--list-tests": for m in tests: print(str(m)) exit(0) else: x = re.match("^--require-attr=(\S+).*$", argv[1]) if x: attr = x.groups()[0] del argv[1] else: attr = None a = [] for b in [explode(x, attr=attr) for x in argv[1:]]: a.extend(b) if not len(a): print("No tests found, was your testcase or testname incorrect? See --help") exit(1) argv = [argv[0],] + a main(argv) main()