#!/usr/bin/python3 import inspect import unittest import re from datetime import datetime from difflib import unified_diff from os import statvfs, uname, utime, 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, CalledProcessError, run from sys import argv, exit, modules from time import mktime from common_framework import (BaseTestCase, get_test_binaries, 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_lfn_voln_info import lfn_voln_info from func_lfs_disk_info import lfs_disk_info from func_label_create import (label_create, label_create_on_lfns, label_create_noduplicate, label_create_nonrootdir, label_delete_wildcard, label_delete_recreate) from func_lfs_file_info import lfs_file_info from func_lfs_file_seek_tell import lfs_file_seek_tell from func_libi86_testsuite import libi86_create_items from func_memory_dpmi_dpmi10_ldt import memory_dpmi_dpmi10_ldt from func_memory_dpmi_japheth import memory_dpmi_japheth from func_memory_dpmi_leak_check import memory_dpmi_leak_check from func_memory_dpmi_leak_check_dos import memory_dpmi_leak_check_dos from func_memory_ems_borland import memory_ems_borland from func_memory_hma import (memory_hma_freespace, memory_hma_alloc, memory_hma_a20, memory_hma_alloc3, memory_hma_chain) from func_memory_uma import memory_uma_strategy from func_memory_xms import memory_xms from func_mfs_findfile import mfs_findfile from func_mfs_truename import mfs_truename from func_network import network_pktdriver_mtcp from func_pit_mode_2 import pit_mode_2 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): attrs = ['cputest', 'dpmitest', 'hmatest', 'nettest', 'umatest', 'xmstest', 'labeltest'] 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_nasm(ename, r""" bits 16 cpu 386 org 100h section .text push cs pop ds mov ax, %s mov dx, dname int 21h jnc prsucc prfail: mov dx, failmsg jmp @1 prsucc: mov dx, succmsg @1: mov ah, 9 int 21h mov ax, %s cmp ax, 0x7147 je prcwd cmp ax, 0x4700 je prcwd exit: mov ah, 4ch int 21h prcwd: ; get cwd mov dl, 0 mov si, curdir int 21h push ds pop es mov di, si mov cx, 128 mov al, 0 cld repne scasb mov byte [di-1], ')' mov byte [di], '$' mov ah, 9 mov dx, pcurdir int 21h jmp exit section .data dname: db "%s",0 succmsg: db "Directory Operation Success",13,10,'$' failmsg: db "Directory Operation Failed",13,10,'$' pcurdir: db '(' curdir: times 128 db '$' """ % (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_nasm(ename, r""" bits 16 cpu 386 org 100h section .text push cs pop ds ; get cwd mov ax, %s mov dl, 0 mov si, curdir int 21h push ds pop es mov di, si mov cx, 128 mov al, 0 cld repne scasb mov byte [di-1], ')' mov byte [di], '$' mov ah, 9 mov dx, pcurdir int 21h exit: mov ah, 4ch int 21h section .data pcurdir: db '(' curdir: times 128 db '$' """ % 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_nasm(ename, r""" bits 16 cpu 386 org 100h section .text push cs pop ds ; Get current drive and store its letter in fspath mov ax, 1900h int 21h add al, 'A' mov byte [fspath], al ; 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 mov ax, 71a0h mov dx, fspath ; ds:dx mov di, fstype ; es:di mov cx, fstypelen stc int 21h jc chkfail cmp byte [fstype], '$' je prnofstype prsuccess: mov di, fstype mov cx, fstypelen mov al, 0 cld repne scasb mov byte [di-1], ')' mov byte [di], 13 mov byte [di+1], 10 mov byte [di+2], '$' mov dx, success jmp exit prnofstype: mov dx, nofstype jmp exit prnotsupported: mov dx, notsupported jmp exit prcarryset: mov dx, carryset jmp exit chkfail: cmp ax, 7100h jne prcarryset jmp prnotsupported exit: mov ah, 9 int 21h mov ah, 4ch int 21h section .data carryset: db "Carry Set",13,10,'$' notsupported: db "Not Supported(AX=0x7100)",13,10,'$' nofstype: db "Carry Not Set But No Filesystem Type",13,10,'$' success: db "Operation Success(" fstype: times 32 db '$' fstypelen equ $ - fstype successend: times 4 db 0 fspath: db "?:\", 0 """) 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_nasm(ename, r""" bits 16 cpu 386 org 100h section .text push cs pop ds mov ax, 0f00h ; open file mov dx, fcb int 21h cmp al, 0 jne prfailopen mov ax, 1400h ; read from file mov dx, fcb int 21h cmp al, 3 ; partial read jne prfailread jmp prsucc prfailopen: mov dx, failopen jmp @1 prfailread: mov ax, 1000h ; close file mov dx, fcb int 21h mov dx, failread jmp @1 prsucc: mov dx, succstart mov ah, 9 int 21h mov ax, 2f00h ; get DTA address in ES:BX int 21h mov byte [es:bx+%d], '$'; terminate push es pop ds mov dx, bx mov ah, 9 int 21h mov ax, 1000h ; close file mov dx, fcb int 21h push cs pop ds mov dx, succend @1: mov ah, 9 int 21h exit: mov ah, 4ch int 21h section .data fcb: db 0 ; 0 default drive fn1: db "% -8s" ; 8 bytes fe1: db "% -3s" ; 3 bytes wk1: times 24 db 0 succstart: db "Operation Success($" succend: db ')',13,10,'$' failopen: db "Open Operation Failed",13,10,'$' failread: db "Read Operation Failed",13,10,'$' """ % (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_nasm(ename, r""" bits 16 cpu 386 org 100h section .text push cs pop ds mov ax, 1a00h ; set DTA mov dx, altdta int 21h mov ax, 2f00h ; get DTA address in ES:BX int 21h mov ax, cs mov dx, es cmp dx, ax jne prfaildtaset cmp bx, altdta jne prfaildtaset mov ax, 0f00h ; open file mov dx, fcb int 21h cmp al, 0 jne prfailopen mov ax, 1400h ; read from file mov dx, fcb int 21h cmp al, 3 ; partial read jne prfailread jmp prsucc prfaildtaset: mov dx, faildtaset jmp @1 prfailopen: mov dx, failopen jmp @1 prfailread: mov ax, 1000h ; close file mov dx, fcb int 21h mov dx, failread jmp @1 prsucc: mov dx, succstart mov ah, 9 int 21h mov ax, 2f00h ; get DTA address in ES:BX int 21h mov byte [es:bx+%d], '$'; terminate push es pop ds mov dx, bx mov ah, 9 int 21h mov ax, 1000h ; close file mov dx, fcb int 21h push cs pop ds mov dx, succend @1: mov ah, 9 int 21h exit: mov ah, 4ch int 21h section .data fcb: db 0 ; 0 default drive fn1: db "% -8s" ; 8 bytes fe1: db "% -3s" ; 3 bytes wk1: times 24 db 0 succstart: db "Operation Success($" succend: db ')',13,10,'$' faildtaset: db "Set DTA Operation Failed",13,10,'$' failopen: db "Open Operation Failed",13,10,'$' failread: db "Read Operation Failed",13,10,'$' altdta: times 128 db 0 """ % (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_fat_label_create_simple(self): """FAT FCB label create simple""" label_create(self, "FAT", None) test_fat_label_create_simple.labeltest = True def test_fat_label_create_bpb12(self): """FAT FCB label create BPB FAT12""" label_create(self, "FAT", 'bpb12') test_fat_label_create_bpb12.labeltest = True def test_fat_label_create_bpb16(self): """FAT FCB label create BPB FAT16""" label_create(self, "FAT", 'bpb16') test_fat_label_create_bpb16.labeltest = True def test_fat_label_create_bpb32(self): """FAT FCB label create BPB FAT32""" label_create(self, "FAT", 'bpb32') test_fat_label_create_bpb32.labeltest = True def test_fat_label_create_prefile(self): """FAT FCB label create file beforehand""" label_create(self, "FAT", 'prefile') test_fat_label_create_prefile.labeltest = True def test_fat_label_create_predir(self): """FAT FCB label create directory beforehand""" label_create(self, "FAT", 'predir') test_fat_label_create_predir.labeltest = True def test_fat_label_create_postfile(self): """FAT FCB label create file afterwards""" label_create(self, "FAT", 'postfile') test_fat_label_create_postfile.labeltest = True def test_fat_label_create_postdir(self): """FAT FCB label create directory afterwards""" label_create(self, "FAT", 'postdir') test_fat_label_create_postdir.labeltest = True def test_fat_label_create_on_lfns(self): """FAT FCB label create on top of LFNs""" label_create_on_lfns(self) test_fat_label_create_on_lfns.labeltest = True def test_fat_label_create_noduplicate(self): """FAT FCB label create no duplicate""" label_create_noduplicate(self, "FAT") test_fat_label_create_noduplicate.labeltest = True 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_nasm(ename, r""" bits 16 cpu 386 org 100h section .text push cs pop ds mov ax, 1600h ; create file mov dx, fcb int 21h cmp al, 0 jne prfailopen mov si, data ; copy data to DTA mov ax, 2f00h ; get DTA address in ES:BX int 21h mov di, bx mov cx, datalen cld repnz movsb mov ax, 1500h ; write to file mov dx, fcb mov word [flrs], datalen; only the significant part int 21h cmp al , 0 jne prfailwrite mov dx, donewrite jmp @2 prfailwrite: mov dx, failwrite jmp @2 prfailopen: mov dx, failopen jmp @1 @2: mov ax, 1000h ; close file push dx mov dx, fcb int 21h pop dx @1: mov ah, 9 int 21h exit: mov ah, 4ch int 21h section .data data: db "Operation Success(%s)",13,10,'$' datalen equ $ - data - 1 fcb: db 0 ; 0 default drive fn1: db "% -8s" ; 8 bytes fe1: db "% -3s" ; 3 bytes fcbn: dw 0 flrs: dw 0 ffsz: dd 0 fdlw: dw 0 ftlw: dw 0 res8: times 8 db 0 fcbr: db 0 frrn: dd 0 failopen: db "Open Operation Failed",13,10,'$' failwrite: db "Write Operation Failed",13,10,'$' donewrite: db "Write Operation Done",13,10,'$' """ % (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_nasm(ename, r""" bits 16 cpu 386 org 100h section .text push cs pop ds mov ax, 1700h mov dx, fcb int 21h cmp al, 0 je prsucc prfail: mov dx, failmsg jmp @1 prsucc: mov dx, succmsg @1: mov ah, 9 int 21h exit: mov ah, 4ch int 21h section .data fcb: db 0 ; 0 default drive fn1: db "% -8s" ; 8 bytes fe1: db "% -3s" ; 3 bytes wk1: times 5 db 0 fn2: db "% -8s" ; 8 bytes fe2: db "% -3s" ; 3 bytes wk2: times 16 db 0 succmsg: db "Rename Operation Success",13,10,'$' failmsg: db "Rename Operation Failed",13,10,'$' """ % (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(), r"%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_nasm(ename, r""" bits 16 cpu 386 org 100h section .text push cs pop ds mov ax, 1300h mov dx, fcb int 21h cmp al, 0 je prsucc prfail: mov dx, failmsg jmp @1 prsucc: mov dx, succmsg @1: mov ah, 9 int 21h exit: mov ah, 4ch int 21h section .data fcb: db 0 ; 0 default drive fn1: db "% -8s" ; 8 bytes fe1: db "% -3s" ; 3 bytes wk1: times 25 db 0 succmsg: db "Delete Operation Success",13,10,'$' failmsg: db "Delete Operation Failed",13,10,'$' """ % (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(), r"%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(), r"%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_nasm(ename, r""" bits 16 cpu 386 org 100h section .text push cs pop ds ; Get DTA -> ES:BX mov ax, 2f00h int 21h push es push bx pop long [pdta] ; FindFirst findfirst: mov ax, 1100h mov dx, fcb int 21h cmp al, 0 je prsucc prfail: mov dx, failmsg mov ah, 9 int 21h jmp exit prsucc: mov dx, succmsg mov ah, 9 int 21h prfilename: push ds lds si, [pdta] inc si push cs pop es mov di, prires inc di mov cx, 11 cld repne movsb pop ds mov dx, prires mov ah, 9 int 21h ; FindNext findnext: mov ax, 1200h mov dx, fcb int 21h cmp al, 0 je prfilename exit: mov ah, 4ch int 21h section .data fcb: db 0 ; 0 default drive fn1: db "% -8s" ; 8 bytes fe1: db "% -3s" ; 3 bytes wk1: times 25 db 0 pdta: dd 0 prires: db "(" fname: times 8 db 20 fext: times 3 db 20 db ')',13,10,'$' succmsg: db "Find Operation Success",13,10,'$' failmsg: db "Find Operation Failed",13,10,'$' """ % (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_nasm(ename, r""" bits 16 cpu 386 org 100h section .text push cs pop ds mov ax, 3d00h ; open file readonly mov dx, fname int 21h jc prfailopen mov word [fhndl], ax mov ax, 3f00h ; read from file, should be partial (35) mov bx, word [fhndl] mov cx, 64 mov dx, fdata int 21h jc prfailread cmp ax, 35 jne prnumread mov ax, 3f00h ; read from file again to get EOF mov bx, word [fhndl] mov cx, 64 mov dx, fdata int 21h jc prcarryset cmp ax, 0 jne praxnotzero jmp prsucc prfailopen: mov dx, failopen jmp @1 prfailread: mov dx, failread jmp @2 prnumread: mov dx, numread jmp @2 praxnotzero: mov dx, axnotzero jmp @2 prcarryset: mov dx, carryset jmp @2 prsucc: mov byte [fdata + 32], ')' mov byte [fdata + 33], 13 mov byte [fdata + 34], 10 mov byte [fdata + 35], '$' mov dx, success jmp @2 @2: mov ax, 3e00h ; close file mov bx, word [fhndl] int 21h @1: mov ah, 9 ; print string int 21h exit: mov ah, 4ch int 21h section .data fname: db "%s",0 fhndl: dw 0 success: db "Operation Success(" fdata: times 64 db 0 failopen: db "Open Operation Failed",13,10,'$' failread: db "Read Operation Failed",13,10,'$' numread: db "Partial Read Not 35 Chars",13,10,'$' carryset: db "Carry Set at EOF",13,10,'$' axnotzero: db "AX Not Zero at EOF",13,10,'$' """ % "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_nasm(ename, r""" bits 16 cpu 386 org 100h section .text push cs pop ds mov ax, 1a00h ; set DTA mov dx, altdta int 21h mov ax, 2f00h ; get DTA address in ES:BX int 21h mov ax, cs mov dx, es cmp dx, ax jne prfaildtaset cmp bx, altdta jne prfaildtaset mov ax, 3d00h ; open file readonly mov dx, fname int 21h jc prfailopen mov word [fhndl], ax mov ax, 3f00h ; read from file, should be partial (35) mov bx, word [fhndl] mov cx, 64 mov dx, fdata int 21h jc prfailread cmp ax, 35 jne prnumread jmp prsucc prfaildtaset: mov dx, faildtaset jmp @1 prfailopen: mov dx, failopen jmp @1 prfailread: mov dx, failread jmp @2 prnumread: mov dx, numread jmp @2 prsucc: mov byte [fdata + 32], ')' mov byte [fdata + 33], 13 mov byte [fdata + 34], 10 mov byte [fdata + 35], '$' mov dx, success jmp @2 @2: mov ax, 3e00h ; close file mov bx, word [fhndl] int 21h @1: mov ah, 9 ; print string int 21h exit: mov ah, 4ch int 21h section .data fname: db "%s",0 fhndl: dw 0 success: db "Operation Success(" fdata: times 64 db 0 faildtaset: db "Set DTA Operation Failed",13,10,'$' failopen: db "Open Operation Failed",13,10,'$' failread: db "Read Operation Failed",13,10,'$' numread: db "Partial Read Not 35 Chars",13,10,'$' altdta: times 128 db 0 """ % "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_nasm(ename, r""" bits 16 cpu 386 org 100h section .text push cs pop ds push cs pop es mov ax, 5600h mov dx, src mov di, dst int 21h jnc prsucc prfail: mov dx, failmsg jmp @1 prsucc: mov dx, succmsg @1: mov ah, 9 int 21h exit: mov ah, 4ch int 21h section .data src: db "%s",0 ; Full path dst: db "%s",0 ; Full path succmsg: db "Rename Operation Success",13,10,'$' failmsg: db "Rename Operation Failed",13,10,'$' """ % (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(), r"%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_nasm(ename, r""" bits 16 cpu 386 org 100h section .text push cs pop ds mov ax, 4100h mov dx, src int 21h jnc prsucc prfail: mov dx, failmsg jmp @1 prsucc: mov dx, succmsg @1: mov ah, 9 int 21h exit: mov ah, 4ch int 21h section .data src: db "%s",0 ; Full path succmsg: db "Delete Operation Success",13,10,'$' failmsg: db "Delete Operation Failed",13,10,'$' """ % (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(), r"%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_nasm(ename, r""" bits 16 cpu 386 org 100h section .text push cs pop ds ; Get DTA -> ES:BX mov ax, 2f00h int 21h push es push bx pop long [pdta] ; FindFirst findfirst: mov ax, 4e00h mov cx, 0 mov dx, fpatn int 21h jnc prsucc prfail: mov dx, failmsg mov ah, 9 int 21h jmp exit prsucc: mov dx, succmsg mov ah, 9 int 21h prfilename: push ds lds ax, [pdta] add ax, 1eh mov si, ax push cs pop es mov di, prires + 1 mov cx, 13 cld @1: cmp byte [ds:si], 0 je @2 movsb loop @1 @2: mov byte [es:di], ')' mov byte [es:di + 1], 13 mov byte [es:di + 2], 10 mov byte [es:di + 3], '$' pop ds mov dx, prires mov ah, 9 int 21h ; FindNext findnext: mov ax, 4f00h int 21h jnc prfilename exit: mov ah, 4ch int 21h section .data fpatn: db "%s",0 pdta: dd 0 prires: db "(" times 32 db 0 succmsg: db "Findfirst Operation Success",13,10,'$' failmsg: db "Findfirst Operation Failed",13,10,'$' """ % (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_nasm(ename, r""" bits 16 cpu 386 org 100h section .text push cs pop ds mov ax, 4e00h mov cx, %s mov dx, fspec int 21h jnc prsucc cmp ax, 2 je fail02 cmp ax, 3 je fail03 cmp ax, 12h je fail12 jmp genfail fail02: mov dx, filenotfound jmp @1 fail03: mov dx, pathnotfoundmsg jmp @1 fail12: mov dx, nomoremsg jmp @1 genfail: mov dx, genfailmsg jmp @1 prsucc: mov dx, succmsg @1: mov ah, 9 int 21h exit: mov ah, 4ch int 21h section .data fspec: db "%s",0 ; Full path succmsg: db "FindFirst Operation Success",13,10,'$' filenotfound: db "FindFirst Operation Returned FILE_NOT_FOUND(0x02)",13,10,'$' pathnotfoundmsg: db "FindFirst Operation Returned PATH_NOT_FOUND(0x03)",13,10,'$' nomoremsg: db "FindFirst Operation Returned NO_MORE_FILES(0x12)",13,10,'$' genfailmsg: db "FindFirst Operation Returned Unexpected Errorcode",13,10,'$' """ % (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_nasm(ename, r""" bits 16 cpu 386 org 100h section .text push cs pop ds ; Get DTA -> ES:BX mov ax, 2f00h int 21h push es push bx pop long [pdta] ; First FindFirst mov ax, 4e00h mov cx, 0 mov dx, fwild int 21h ; Set alternate DTA mov ax, 1a00h mov dx, altdta int 21h ; Second FindFirst mov ax, 4e00h mov cx, 0 mov dx, fsmpl int 21h ; Set default DTA mov ax, 1a00h lds dx, [pdta] int 21h ; FindNext mov ax, 4f00h int 21h jnc prsucc prfail: mov dx, failmsg mov ah, 9 int 21h jmp exit prsucc: push ds lds ax, [pdta] add ax, 1eh mov si, ax push cs pop es mov di, prires + 1 mov cx, 13 cld @1: cmp byte [ds:si], 0 je @2 movsb loop @1 @2: mov byte [es:di], ')' mov byte [es:di + 1], 13 mov byte [es:di + 2], 10 mov byte [es:di + 3], '$' pop ds mov dx, succmsg mov ah, 9 int 21h exit: mov ah, 4ch int 21h section .data fwild: db "a*.txt",0 fsmpl: db "%s",0 altdta: times 0x80 db 0 pdta: dd 0 succmsg: db "Findnext Operation Success" prires: db "(" times 32 db 0 failmsg: db "Findnext Operation Failed",13,10,'$' """ % 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_nasm(ename, r""" bits 16 cpu 386 org 100h section .text ; designate target segment push cs pop ax add ax, 0200h mov es, ax ; create PSP in memory mov dx, es mov ax, 2600h int 21h ; see if the exit field is set cmp word [es:0000], 20cdh jne extfail ; see if the parent PSP is zero cmp word [es:0016h], 0 je pntzero ; see if the parent PSP points to a PSP push es push word [es:0016h] pop es cmp word [es:0000h], 20cdh pop es jne pntnpsp ; see if the 'INT 21,RETF' is there cmp word [es:0050h], 21cdh jne int21ms cmp byte [es:0052h], 0cbh jne int21ms ; see if the cmdtail is there movzx cx, byte [es:0080h] cmp cx, %d jne cmdlngth inc cx mov si, cmdline mov di, 81h cld repe cmpsb jne cmdtail success: mov dx, successmsg jmp exit extfail: mov dx, extfailmsg jmp exit pntzero: mov dx, pntzeromsg jmp exit pntnpsp: mov dx, pntnpspmsg jmp exit int21ms: mov dx, int21msmsg jmp exit cmdlngth: mov dx, cmdlngthmsg jmp exit cmdtail: mov dx, cmdtailmsg jmp exit exit: mov ah, 9 int 21h mov ah, 4ch int 21h extfailmsg: db "PSP exit field not set to CD20",13,10,'$' pntzeromsg: db "PSP parent is zero",13,10,'$' pntnpspmsg: db "PSP parent doesn't point to a PSP",13,10,'$' int21msmsg: db "PSP is missing INT21, RETF",13,10,'$' cmdlngthmsg: db "PSP has incorrect command length",13,10,'$' cmdtailmsg: db "PSP has incorrect command tail",13,10,'$' successmsg: db "PSP structure okay",13,10,'$' ; 05 20 54 45 53 54 0d cmdline: db " %s",13 """ % (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) test_memory_dpmi_ecm_alloc.dpmitest=True 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) test_memory_dpmi_ecm_mini.dpmitest=True 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) test_memory_dpmi_ecm_modeswitch.dpmitest=True 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) test_memory_dpmi_ecm_psp.dpmitest=True def test_memory_dpmi_japheth(self): """Memory DPMI (Japheth) ''""" memory_dpmi_japheth(self, '') test_memory_dpmi_japheth.dpmitest=True def test_memory_dpmi_japheth_c(self): """Memory DPMI (Japheth) '-c'""" memory_dpmi_japheth(self, '-c') test_memory_dpmi_japheth_c.dpmitest=True def test_memory_dpmi_japheth_d(self): """Memory DPMI (Japheth) '-d'""" memory_dpmi_japheth(self, '-d') test_memory_dpmi_japheth_d.dpmitest=True def test_memory_dpmi_japheth_e(self): """Memory DPMI (Japheth) '-e'""" memory_dpmi_japheth(self, '-e') test_memory_dpmi_japheth_e.dpmitest=True def test_memory_dpmi_japheth_i(self): """Memory DPMI (Japheth) '-i'""" memory_dpmi_japheth(self, '-i') test_memory_dpmi_japheth_i.dpmitest=True def test_memory_dpmi_japheth_m(self): """Memory DPMI (Japheth) '-m'""" memory_dpmi_japheth(self, '-m') test_memory_dpmi_japheth_m.dpmitest=True def test_memory_dpmi_japheth_r(self): """Memory DPMI (Japheth) '-r'""" memory_dpmi_japheth(self, '-r') test_memory_dpmi_japheth_r.dpmitest=True def test_memory_dpmi_japheth_t(self): """Memory DPMI (Japheth) '-t'""" memory_dpmi_japheth(self, '-t') test_memory_dpmi_japheth_t.dpmitest=True def test_memory_dpmi_japheth_z(self): """Memory DPMI (Japheth) '-z'""" memory_dpmi_japheth(self, '-z') test_memory_dpmi_japheth_z.dpmitest=True 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 2048", 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_memory_hma_a20(self): """Memory HMA a20 toggle""" memory_hma_a20(self) test_memory_hma_a20.hmatest = True def test_memory_hma_alloc(self): """Memory HMA allocation""" memory_hma_alloc(self) test_memory_hma_alloc.hmatest = True def test_memory_hma_alloc3(self): """Memory HMA alloc/resize/dealloc""" memory_hma_alloc3(self) test_memory_hma_alloc3.hmatest = True def test_memory_hma_freespace(self): """Memory HMA freespace""" memory_hma_freespace(self) test_memory_hma_freespace.hmatest = True def test_memory_hma_chain(self): """Memory HMA get chain""" memory_hma_chain(self) test_memory_hma_chain.hmatest = True def test_memory_xms(self): """Memory XMS""" memory_xms(self) test_memory_xms.xmstest = True def test_memory_dpmi10_ldt(self): """Memory DPMI-1.0 LDT""" memory_dpmi_dpmi10_ldt(self) test_memory_dpmi10_ldt.dpmitest = True def test_memory_dpmi_leak_check_nofree(self): """Memory DPMI Leak Check No Free""" memory_dpmi_leak_check(self, 'nofree') test_memory_dpmi_leak_check_nofree.dpmitest = True def test_memory_dpmi_leak_check_normal(self): """Memory DPMI Leak Check Normal""" memory_dpmi_leak_check(self, 'normal') test_memory_dpmi_leak_check_normal.dpmitest = True def test_memory_dpmi_leak_check_dos_nofree(self): """Memory DPMI Leak Check DOS No Free""" memory_dpmi_leak_check_dos(self, 'nofree') test_memory_dpmi_leak_check_dos_nofree.dpmitest = True def test_memory_dpmi_leak_check_dos_normal(self): """Memory DPMI Leak Check DOS Normal""" memory_dpmi_leak_check_dos(self, 'normal') test_memory_dpmi_leak_check_dos_normal.dpmitest = True def test_memory_uma_strategy(self): """Memory UMA Strategy""" memory_uma_strategy(self) test_memory_uma_strategy.umatest = True 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') testfil = testdir / "there.txt" testfil.write_text('there') name = self.mkimage_vbr(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") self.assertRegex(results, r"THERE[\t ]+TXT[\t ]+5" r"|" r"\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}\s+5\s+THERE.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_fat16b_img_d_writable(self): """FAT16B image file D writable""" self._test_fat_img_d_writable("16b") def test_fat32_img_d_writable(self): """FAT32 image file D writable""" self._test_fat_img_d_writable("32") 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"), ("DIR", "RealDir2"), ("DIR", "Sub"), ("DIR", "Sub/RealDir"), ("FILE", "Sub/Very Long realName"), ("FILE", "Sub/verylongRealname.txt"), ("FILE", "Sub/RealDir/Very Long realName"), ) tests = ( # Note: CurDrv == D:, CurDir == \Sub # These LFN 7160/0 tests are proven on Win98 and are seen # to have the following rules: # 1/ Any '..' are resolved. # 2/ Any '.\' are stripped. # 3/ If no drive specification, then default drive is prepended. # 4/ If not absolute path, then current directory for drive # is inserted between drive and relative path. # 5/ All path components (except final) are upcased. # 6/ Final path component case is preserved from the request. # 7/ No path component has to exist on the filesystem or # is checked against it and updated for case. ("LFN0", r"aux", r"D:/AUX"), # D:\Sub exists as a directory ("LFN0", r"nonExist", r"D:\\SUB\\nonExist"), ("LFN0", r"\\nonExist", r"D:\\nonExist"), ("LFN0", r"\\Sub\\nonExist", r"D:\\SUB\\nonExist"), ("LFN0", r"c:nonExist", r"C:\\nonExist"), ("LFN0", r"c:\\nonExist", r"C:\\nonExist"), ("LFN0", r"c:\\RootC\\nonExist", r"C:\\ROOTC\\nonExist"), # Both D:\RealDir2 and D:\\Sub\\RealDir exist as directories ("LFN0", r"d:realdir", r"D:\\SUB\\realdir"), ("LFN0", r"d:\\realdir2", r"D:\\realdir2"), ("LFN0", r"d:\\realdir2\\noNexist.TxT", r"D:\\REALDIR2\\noNexist.TxT"), # D:\Sub exists as a directory ("LFN0", r"nonExist\\NewFile.txt", r"D:\\SUB\\NONEXIST\\NewFile.txt"), ("LFN0", r"d:nonExist\\NewFile.txt", r"D:\\SUB\\NONEXIST\\NewFile.txt"), ("LFN0", r"d:\\nonExist\\NewFile.txt", r"D:\\NONEXIST\\NewFile.txt"), ("LFN0", r"..\\Sub\\RealDir\\..\\NewFile.txt", r"D:\\SUB\\NewFile.txt"), # D:\Program Files exists as a directory ("LFN0", r"D:\\progra~1", r"D:\\progra~1"), ("LFN0", r"D:\\PROGRA~1", r"D:\\PROGRA~1"), ("LFN0", r"D:\\program files", r"D:\\program files"), ("LFN0", r"D:\\PROGRAM FILES", r"D:\\PROGRAM FILES"), ("LFN0", r"D:\\Program Files", r"D:\\Program Files"), ("LFN0", r"D:\\Program Files\\NewFile.txt", r"D:\\PROGRAM FILES\\NewFile.txt"), ("LFN0", r"D:\\Program Files\\NewFile.txt", r"D:\\PROGRAM FILES\\NewFile.txt"), ("LFN0", r"D:\\Program Files\\NonExist\\NewFile.txt", r"D:\\PROGRAM FILES\\NONEXIST\\NewFile.txt"), ("LFN1", r"d:very long realname", r"D:\\SUB\\VERYL~CV"), ("LFN1", r"d:\\very long realname", r"ERROR: invalid component"), ("LFN1", r"d:\\Sub\\VERYLONGrEALNAME.TXT", r"D:\\SUB\\VERYL~6S.TXT"), ("LFN1", r"D:\\program files", r"D:\\PROGR~-I"), ("LFN1", r"D:\\PROGRAM FILES", r"D:\\PROGR~-I"), ("LFN1", r"D:\\Program Files", r"D:\\PROGR~-I"), ("LFN2", r"D:\\SUB\\VERYL~CV", r"D:\\Sub\\Very Long realName"), ("LFN2", r"D:\\SUB\\VERYL~6S.TXT", r"D:\\Sub\\verylongRealname.txt"), ("LFN2", r"D:\\progr~-i", r"D:\\Program Files"), ("LFN2", r"D:\\PROGR~-I", r"D:\\Program Files"), ) mfs_truename(self, "UFS", names_to_create, tests) def test_mfs_truename_ufs_sfn(self): """MFS truename UFS SFN""" names_to_create = ( ("DIR", "Sub"), ("DIR", "Sub/testname"), ("FILE", "shrtname.txt"), ) tests = ( # Note: CurDrv == D:, CurDir == \SUB ("SFN", r"aux", r"D:/AUX"), ("SFN", r"fakename", r"D:\\SUB\\FAKENAME"), # Non existent ("SFN", r"\\fakename", r"D:\\FAKENAME"), # Non existent ("SFN", r"\\Sub\\fakename", r"D:\\SUB\\FAKENAME"), # Non existent ("SFN", r"c:fakename", r"C:\\FAKENAME"), # Non existent ("SFN", r"c:\\fakename", r"C:\\FAKENAME"), # Non existent ("SFN", r"c:\\Sub\\fakename", r"C:\\SUB\\FAKENAME"), # Non existent ("SFN", r"testname", r"D:\\SUB\\TESTNAME"), ("SFN", r"\\Sub\\testname", r"D:\\SUB\\TESTNAME"), ("SFN", r"d:testname", r"D:\\SUB\\TESTNAME"), ("SFN", r"d:\\Sub\\testname", r"D:\\SUB\\TESTNAME"), ("SFN", r"shrtname.txt", r"D:\\SUB\\SHRTNAME.TXT"), # Non existent ("SFN", r"\\shrtname.txt", r"D:\\SHRTNAME.TXT"), ("SFN", r"d:shrtname.txt", r"D:\\SUB\\SHRTNAME.TXT"), # Non existent ("SFN", r"d:\\shrtname.txt", r"D:\\SHRTNAME.TXT"), ) mfs_truename(self, "UFS", names_to_create, tests) def test_mfs_truename_vfat_linux_mounted_lfn(self): """MFS truename VFAT Linux mounted LFN""" names_to_create = ( ("DIR", "Program Files"), ("FILE", "lfnInRoot.tXt"), ("FILE", "Sub/verylongfilename.txt"), ("FILE", "Sub/verylongfilename2.txt"), ("FILE", "Sub/space embedded filename.txt"), ("FILE", "Sub/MixedCaseFilename.ext"), ("DIR", "Sub/test/1234567890987654321"), ("DIR", "Sub/abcdefgfedcba/1234567890987654321"), ("FILE", "Sub/1234567890987654321/abcdefgfedcba.txt"), ("FILE", "Sub/1234567890987654321/abcdefclash.txt"), ) tests = ( # Since Truename 0x7160/0 does not interact with the filesystem, # the tests on UFS should give coverage, but just do a few for # belt and braces. ("LFN0", r"D:\\progra~1", r"D:\\progra~1"), ("LFN0", r"D:\\PROGRA~1", r"D:\\PROGRA~1"), ("LFN0", r"D:\\program files", r"D:\\program files"), ("LFN0", r"D:\\PROGRAM FILES", r"D:\\PROGRAM FILES"), ("LFN0", r"D:\\Program Files", r"D:\\Program Files"), ("LFN0", r"D:\\Program Files\\NewFile.txt", r"D:\\PROGRAM FILES\\NewFile.txt"), ("LFN0", r"D:\\Program Files\\NewFile.txt", r"D:\\PROGRAM FILES\\NewFile.txt"), ("LFN0", r"D:\\Program Files\\NonExist\\NewFile.txt", r"D:\\PROGRAM FILES\\NONEXIST\\NewFile.txt"), ("LFN1", r"X:\\lfnNotInRoot.tXt", r"ERROR: invalid component"), # Non existent ("LFN1", r"..\\lfnNotInRoot.tXt", r"ERROR: invalid component"), # Non existent ("LFN1", r"X:\\lfnInRoot.tXt", r"X:\\LFNINR~1.TXT"), ("LFN1", r"..\\lfnInRoot.tXt", r"X:\\LFNINR~1.TXT"), ("LFN1", r"..\\rootc\\..\\lfnInRoot.tXt", r"X:\\LFNINR~1.TXT"), ("LFN1", r"X:\\sub\\verylongfilename.txt", r"X:\\SUB\\VERYLO~1.TXT"), ("LFN1", r"X:\\sub\\verylongfilename2.txt", r"X:\\SUB\\VERYLO~2.TXT"), ("LFN1", r"X:\\sub\\space embedded filename.txt", r"X:\\SUB\\SPACEE~1.TXT"), ("LFN1", r"X:\\sub\\MixedCaseFilename.ext", r"X:\\SUB\\MIXEDC~1.EXT"), ("LFN1", r"X:\\sub\\test\\1234567890987654321", r"X:\\SUB\\TEST\\123456~1"), ("LFN1", r"X:\\sub\\abcdefgfedcba\\1234567890987654321", r"X:\\SUB\\ABCDEF~1\\123456~1"), ("LFN1", r"X:\\sub\\1234567890987654321\\abcdefgfedcba.txt", r"X:\\SUB\\123456~1\\ABCDEF~1.TXT"), ("LFN1", r"X:\\sub\\1234567890987654321\\abcdefclash.txt", r"X:\\SUB\\123456~1\\ABCDEF~2.TXT"), ("LFN1", r"1234567890987654321\\abcdefclash.txt", r"X:\\SUB\\123456~1\\ABCDEF~2.TXT"), ("LFN1", r".\\1234567890987654321\\abcdefclash.txt", r"X:\\SUB\\123456~1\\ABCDEF~2.TXT"), ("LFN1", r"..\\sub\\1234567890987654321\\abcdefclash.txt", r"X:\\SUB\\123456~1\\ABCDEF~2.TXT"), ("LFN1", r"X:\\program files", r"X:\\PROGRA~1"), ("LFN1", r"X:\\PROGRAM FILES", r"X:\\PROGRA~1"), ("LFN1", r"X:\\Program Files", r"X:\\PROGRA~1"), ("LFN2", r"X:\\LFNNOT~1.TXT", r"ERROR: invalid component"), # Non existent ("LFN2", r"X:\\LFNINR~1.TXT", r"X:\\lfnInRoot.tXt"), ("LFN2", r"X:\\sub\\VERYLO~1.TXT", r"X:\\Sub\\verylongfilename.txt"), ("LFN2", r"X:\\sub\\VERYLO~2.TXT", r"X:\\Sub\\verylongfilename2.txt"), ("LFN2", r"X:\\sub\\SPACEE~1.TXT", r"X:\\Sub\\space embedded filename.txt"), ("LFN2", r"X:\\sub\\MIXEDC~1.EXT", r"X:\\Sub\\MixedCaseFilename.ext"), ("LFN2", r"X:\\sub\\TEST\\123456~1", r"X:\\Sub\\test\\1234567890987654321"), ("LFN2", r"X:\\sub\\ABCDEF~1\\123456~1", r"X:\\Sub\\abcdefgfedcba\\1234567890987654321"), ("LFN2", r"X:\\sub\\123456~1\\ABCDEF~1.TXT", r"X:\\Sub\\1234567890987654321\\abcdefgfedcba.txt"), ("LFN2", r"X:\\sub\\123456~1\\ABCDEF~2.TXT", r"X:\\Sub\\1234567890987654321\\abcdefclash.txt"), ("LFN2", r"X:\\progra~1", r"X:\\Program Files"), ("LFN2", r"X:\\PROGRA~1", r"X:\\Program Files"), ("LFN2", r"X:\\PROGRA~1", r"X:\\Program Files"), ) mfs_truename(self, "VFAT", names_to_create, tests) def test_mfs_truename_vfat_linux_mounted_sfn(self): """MFS truename VFAT Linux mounted SFN""" names_to_create = ( ("DIR", "testname"), ("FILE", "Sub/shrtname.txt"), ("FILE", "Sub/verylongfilename.txt"), ("FILE", "Sub/verylongfilename2.txt"), ("FILE", "Sub/space embedded filename.txt"), ("FILE", "Sub/MixedCaseFilename.ext"), ("DIR", "Sub/test/1234567890987654321"), ("DIR", "Sub/abcdefgfedcba/1234567890987654321"), ("FILE", "Sub/654321fedcba/abcdef123456.txt"), ("FILE", "Sub/654321fedcba/abcdefclash.txt"), ) tests = ( # Note: CurDrv == X:, CurDir == \SUB ("SFN", r"X:\\testname", r"X:\\TESTNAME"), ("SFN", r"..\\testname", r"X:\\TESTNAME"), ("SFN", r"testname", r"X:\\SUB\\TESTNAME"), # Non existent ("SFN", r"X:\\sub\\shrtname.txt", r"X:\\SUB\\SHRTNAME.TXT"), ("SFN", r"X:\\sub\\verylo~1.txt", r"X:\\SUB\\VERYLO~1.TXT"), ("SFN", r"X:\\sub\\verylo~2.txt", r"X:\\SUB\\VERYLO~2.TXT"), ("SFN", r"X:\\sub\\spacee~1.txt", r"X:\\SUB\\SPACEE~1.TXT"), ("SFN", r"X:\\sub\\mixedc~1.ext", r"X:\\SUB\\MIXEDC~1.EXT"), ("SFN", r"X:\\sub\\test\\123456~1", r"X:\\SUB\\TEST\\123456~1"), ("SFN", r"X:\\sub\\abcdef~1\\123456~1", r"X:\\SUB\\ABCDEF~1\\123456~1"), ("SFN", r"X:\\sub\\654321~1\\abcdef~1", r"X:\\SUB\\654321~1\\ABCDEF~1"), ("SFN", r"X:\\sub\\654321~1\\abcdef~2", r"X:\\SUB\\654321~1\\ABCDEF~2"), ) mfs_truename(self, "VFAT", names_to_create, tests) 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_mfs(self): """LFN volume info on MFS""" lfn_voln_info(self, "MFS") def test_lfn_volume_info_fat16(self): """LFN volume info on FAT16""" lfn_voln_info(self, "FAT16") def test_lfn_volume_info_fat32(self): """LFN volume info on FAT32""" lfn_voln_info(self, "FAT32") 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 r1 = re.compile(r'total_bytes\((\d+)\)') self.assertRegex(results, r1) t = r1.search(results) dfs_total = int(t.group(1)) r2 = re.compile(r'avail_bytes\((\d+)\)') self.assertRegex(results, r2) a = r2.search(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_lfs_disk_info_fat32(self): """LFS disk info FAT32""" lfs_disk_info(self, "FAT32") def test_lfs_disk_info_mfs(self): """LFS disk info MFS""" lfs_disk_info(self, "MFS") 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_one_process_ds2(self): """MFS DOSv3 share open delete one process DOSv2""" ds3_share_open_access(self, "ONE", "MFS", "DELPTH") def test_fat_ds3_share_open_delete_one_process_ds2(self): """FAT DOSv3 share open delete one process DOSv2""" ds3_share_open_access(self, "ONE", "FAT", "DELPTH") def test_mfs_ds3_share_open_delete_one_process_fcb(self): """MFS DOSv3 share open delete one process FCB""" ds3_share_open_access(self, "ONE", "MFS", "DELFCB") def test_fat_ds3_share_open_delete_one_process_fcb(self): """FAT DOSv3 share open delete one process FCB""" ds3_share_open_access(self, "ONE", "FAT", "DELFCB") def test_mfs_ds3_share_open_rename_one_process_ds2(self): """MFS DOSv3 share open rename one process DOSv2""" ds3_share_open_access(self, "ONE", "MFS", "RENPTH") def test_fat_ds3_share_open_rename_one_process_ds2(self): """FAT DOSv3 share open rename one process DOSv2""" ds3_share_open_access(self, "ONE", "FAT", "RENPTH") def test_mfs_ds3_share_open_rename_one_process_fcb(self): """MFS DOSv3 share open rename one process FCB""" ds3_share_open_access(self, "ONE", "MFS", "RENFCB") def test_fat_ds3_share_open_rename_one_process_fcb(self): """FAT DOSv3 share open rename one process FCB""" ds3_share_open_access(self, "ONE", "FAT", "RENFCB") def test_mfs_ds3_share_open_setfattrs_one_process(self): """MFS DOSv3 share open set file attrs one process DOSv2""" ds3_share_open_access(self, "ONE", "MFS", "SETATT") def test_fat_ds3_share_open_setfattrs_one_process(self): """FAT DOSv3 share open set file attrs one process DOSv2""" ds3_share_open_access(self, "ONE", "FAT", "SETATT") def test_mfs_ds3_share_open_delete_two_process_ds2(self): """MFS DOSv3 share open delete two process DOSv2""" ds3_share_open_access(self, "TWO", "MFS", "DELPTH") def test_fat_ds3_share_open_delete_two_process_ds2(self): """FAT DOSv3 share open delete two process DOSv2""" ds3_share_open_access(self, "TWO", "FAT", "DELPTH") def test_mfs_ds3_share_open_delete_two_process_fcb(self): """MFS DOSv3 share open delete two process FCB""" ds3_share_open_access(self, "TWO", "MFS", "DELFCB") def test_fat_ds3_share_open_delete_two_process_fcb(self): """FAT DOSv3 share open delete two process FCB""" ds3_share_open_access(self, "TWO", "FAT", "DELFCB") def test_mfs_ds3_share_open_rename_two_process_ds2(self): """MFS DOSv3 share open rename two process DOSv2""" ds3_share_open_access(self, "TWO", "MFS", "RENPTH") def test_fat_ds3_share_open_rename_two_process_ds2(self): """FAT DOSv3 share open rename two process DOSv2""" ds3_share_open_access(self, "TWO", "FAT", "RENPTH") def test_mfs_ds3_share_open_rename_two_process_fcb(self): """MFS DOSv3 share open rename two process FCB""" ds3_share_open_access(self, "TWO", "MFS", "RENFCB") def test_fat_ds3_share_open_rename_two_process_fcb(self): """FAT DOSv3 share open rename two process FCB""" ds3_share_open_access(self, "TWO", "FAT", "RENFCB") def test_mfs_ds3_share_open_setfattrs_two_process(self): """MFS DOSv3 share open set file attrs two process DOSv2""" ds3_share_open_access(self, "TWO", "MFS", "SETATT") def test_fat_ds3_share_open_setfattrs_two_process(self): """FAT DOSv3 share open set file attrs two process DOSv2""" ds3_share_open_access(self, "TWO", "FAT", "SETATT") def test_network_pktdriver_mtcp_builtin(self): """Network pktdriver mTCP built-in""" network_pktdriver_mtcp(self, 'builtin') test_network_pktdriver_mtcp_builtin.nettest = True def test_network_pktdriver_mtcp_ne2000(self): """Network pktdriver mTCP NE2000""" network_pktdriver_mtcp(self, 'ne2000') test_network_pktdriver_mtcp_ne2000.nettest = True 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("requires KVM") if cpu_vm == 'vm86' and uname()[4] != 'i686': self.skipTest("native vm86() only on 32bit x86") edir = self.topdir / "test" / "cpu" # Native reference file is now checked in to git and will # only need to be updated if the test source changes reffile = edir / "reffile.log" refoutput = [] with reffile.open("r") as f: refoutput = f.readlines() # DOS test binary is built as part of normal build process copy(edir / "dosbin.exe", self.workdir / "dosbin.exe") dosfile = self.workdir / "dosfile.log" # output from DOS under test self.mkfile("testit.bat", """\ dosbin --common-tests > %s rem end """ % dosfile.name, 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 dosfile.open("r") as f: dosoutput = f.readlines() except FileNotFoundError: pass if not dosoutput: self.fail("DOS output file not found") # Compare DOS output to reference file if dosoutput != refoutput: diff = unified_diff(refoutput, dosoutput, fromfile=str(reffile), tofile=str(dosfile)) self.fail('differences detected\n' + ''.join(list(diff))) def test_cpu_1_vm86native(self): """CPU 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 JIT vm86 + native DPMI""" self._test_cpu("emulated", "native", 0) test_cpu_2_jitnative.cputest = True def test_cpu_jitkvm(self): """CPU JIT vm86 + KVM DPMI""" self._test_cpu("emulated", "kvm", 0) test_cpu_jitkvm.cputest = True def test_cpu_simnative(self): """CPU simulated vm86 + native DPMI""" self._test_cpu("emulated", "native", 1) test_cpu_simnative.cputest = True def test_cpu_simkvm(self): """CPU simulated vm86 + KVM DPMI""" self._test_cpu("emulated", "kvm", 1) test_cpu_simkvm.cputest = True def test_cpu_kvmnative(self): """CPU KVM vm86 + native DPMI""" self._test_cpu("kvm", "native", 0) test_cpu_kvmnative.cputest = True def test_cpu_kvm(self): """CPU KVM vm86 + KVM DPMI""" self._test_cpu("kvm", "kvm", 0) test_cpu_kvm.cputest = True def test_cpu_kvmjit(self): """CPU KVM vm86 + JIT DPMI""" self._test_cpu("kvm", "emulated", 0) test_cpu_kvmjit.cputest = True def test_cpu_kvmsim(self): """CPU KVM vm86 + simulated DPMI""" self._test_cpu("kvm", "emulated", 1) test_cpu_kvmsim.cputest = True def test_cpu_jit(self): """CPU JIT vm86 + JIT DPMI""" self._test_cpu("emulated", "emulated", 0) test_cpu_jit.cputest = True def test_cpu_sim(self): """CPU 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_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' try: run(["git", "clone", "-q", "--depth=1", mosrepo, str(mosroot)], check=True) except CalledProcessError: self.skipTest("repository unavailable") 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 = "" """) self.assertNotIn('Timeout', results) self.assertNotIn('NonZeroReturn', results) 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) def test_passing_environment_variable(self): """Passing Environment Variable to DOS""" tstring1 = "0123456789aBcDeF" self.mkfile("testit.bat", """\ @ECHO on ECHO %TESTVAR1% rem end """, newline="\r\n") args = ["TESTVAR1=" + tstring1, "-q", "-E", "testit.bat"] results = self.runDosemuCmdline(args, config="""\ $_hdimage = "dXXXXs/c:hdtype1 +1" $_floppy_a = "" """) self.assertNotIn('Timeout', results) self.assertNotIn('NonZeroReturn', results) self.assertIn("rem end", results, msg="Test incomplete:\n") self.assertIn(tstring1, results) def test_passing_dos_errorlevel_back(self): """Passing DOS Errorlevel back""" self.mkcom_with_ia16("justerro", r""" int main(int argc, char *argv[]) { return 53; } """) results = self.runDosemuCmdline(["-q", "-E", "justerro.com"], config="""\ $_hdimage = "dXXXXs/c:hdtype1 +1" $_floppy_a = "" """) self.assertNotIn('Timeout', results) self.assertIn('NonZeroReturn:53', results) def test_pit_mode_2(self): """PIT Mode 2""" if environ.get("SKIP_EXPENSIVE"): self.skipTest("expensive test") if environ.get("SKIP_UNCERTAIN"): self.skipTest("uncertain test") pit_mode_2(self) 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 = { r"test_fat_ds3_share_open_setfattrs_(one|two)_process": KNOWNFAIL, r"test_..._ds3_share_open_rename_one_process_fcb": KNOWNFAIL, r"test_..._fcb_rename_simple": KNOWNFAIL, r"test_..._fcb_rename_wild_\d": KNOWNFAIL, "test_mfs_truename_ufs_sfn": KNOWNFAIL, "test_mfs_truename_vfat_linux_mounted_sfn": KNOWNFAIL, "test_fat32_img_d_writable": UNSUPPORTED, "test_lfn_volume_info_fat16": KNOWNFAIL, "test_lfn_volume_info_fat32": UNSUPPORTED, "test_lfn_volume_info_mfs": KNOWNFAIL, "test_lfs_disk_info_fat32": UNSUPPORTED, "test_floppy_vfs": KNOWNFAIL, "test_memory_hma_alloc3": UNSUPPORTED, "test_memory_hma_chain": UNSUPPORTED, "test_pcmos_build": KNOWNFAIL, "test_passing_dos_errorlevel_back": KNOWNFAIL, "test_fat_label_create_bpb12": KNOWNFAIL, "test_fat_label_create_bpb16": KNOWNFAIL, "test_fat_label_create_bpb32": UNSUPPORTED, "test_fat_label_create_on_lfns": UNSUPPORTED, } 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, r"test_fat_ds3_share_open_(delete|rename)_.*": KNOWNFAIL, r"test_mfs_ds3_share_open_rename_(one|two)_process_fcb": KNOWNFAIL, r"test_fat_ds3_share_open_setfattrs_(one|two)_process": KNOWNFAIL, "test_create_new_psp": KNOWNFAIL, "test_command_com_keyword_exist": KNOWNFAIL, "test_memory_emm286_borland": KNOWNFAIL, "test_memory_hma_alloc": KNOWNFAIL, "test_memory_hma_alloc3": UNSUPPORTED, "test_memory_hma_chain": UNSUPPORTED, "test_memory_uma_strategy": KNOWNFAIL, "test_pcmos_build": KNOWNFAIL, r"test_libi86_item_\d+": KNOWNFAIL, "test_passing_dos_errorlevel_back": KNOWNFAIL, "test_fat_label_create_bpb12": KNOWNFAIL, "test_fat_label_create_bpb16": KNOWNFAIL, "test_fat_label_create_bpb32": KNOWNFAIL, "test_fat_label_create_prefile": KNOWNFAIL, "test_fat_label_create_predir": 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 FRDOS130TestCase(OurTestCase, unittest.TestCase): @classmethod def setUpClass(cls): super(FRDOS130TestCase, cls).setUpClass() cls.version = "FreeDOS kernel 2043" cls.prettyname = "FR-DOS-1.30" cls.files = [ ("kernel.sys", "2bdf90c8bc8c0406cfa01349265bf782507af016"), ("command.com", "15abab3d3ee4a50449517131a13b2c5164610582"), ("share.com", "cadc29d49115cb3a250f90921cca345e7c427464"), ] cls.systype = SYSTYPE_FRDOS_NEW cls.autoexec = "fdautoem.bat" cls.confsys = "fdconfig.sys" cls.bootblocks = [ ("boot-306-4-17.blk", "0092a320500d7a8359d40bddc48f592686745aed"), ("boot-615-4-17.blk", "2b757178c7ba97f8a439c83dc627d61c2d6b3cf6"), ("boot-900-15-17.blk", "8cd7adeff4a0265e8a8e20f7942672c677cbc891"), ] cls.images = [ ("boot-floppy.img", "7b68b4dc2de5891bb3700816d8e1a323e8d150bb"), ] cls.actions = { "test_command_com_keyword_exist": KNOWNFAIL, "test_create_new_psp": KNOWNFAIL, "test_fat_ds3_lock_readlckd": KNOWNFAIL, "test_fat_ds3_lock_two_handles": KNOWNFAIL, "test_fat_ds3_lock_writable": KNOWNFAIL, r"test_fat_ds3_share_open_(delete|rename)_.*": KNOWNFAIL, r"test_fat_ds3_share_open_setfattrs_(one|two)_process": KNOWNFAIL, "test_fat_ds3_share_open_twice": KNOWNFAIL, "test_fat_fcb_find_wild_1": KNOWNFAIL, "test_fat_fcb_find_wild_2": KNOWNFAIL, "test_fat_fcb_find_wild_3": 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_fat_label_create_bpb12": KNOWNFAIL, "test_fat_label_create_bpb16": KNOWNFAIL, "test_fat_label_create_bpb32": KNOWNFAIL, "test_fat_label_create_noduplicate": KNOWNFAIL, "test_fat_label_create_predir": KNOWNFAIL, "test_fat_label_create_prefile": KNOWNFAIL, "test_memory_emm286_borland": KNOWNFAIL, "test_memory_hma_alloc": KNOWNFAIL, "test_memory_hma_alloc3": UNSUPPORTED, "test_memory_hma_chain": UNSUPPORTED, "test_memory_uma_strategy": 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_passing_dos_errorlevel_back": 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 FRDOSGITTestCase(OurTestCase, unittest.TestCase): @classmethod def setUpClass(cls): super(FRDOSGITTestCase, cls).setUpClass() cls.version = "DOS version 7.10" cls.prettyname = "FR-DOS-GIT" cls.tarfile = "" cls.systype = SYSTYPE_FRDOS_NEW cls.autoexec = "fdautoem.bat" cls.confsys = "fdconfig.sys" cls.bootblocks = [ ] cls.images = [ ] cls.actions = { "test_fat_ds3_lock_concurrent": KNOWNFAIL, "test_fat_ds3_lock_readlckd": KNOWNFAIL, "test_fat_ds3_lock_two_handles": KNOWNFAIL, "test_fat_ds3_lock_writable": KNOWNFAIL, "test_fat_ds3_share_open_delete_one_process_ds2": KNOWNFAIL, "test_fat_ds3_share_open_delete_one_process_fcb": KNOWNFAIL, "test_fat_ds3_share_open_rename_one_process_ds2": KNOWNFAIL, "test_fat_ds3_share_open_rename_one_process_fcb": KNOWNFAIL, "test_fat_ds3_share_open_setfattrs_one_process": KNOWNFAIL, "test_fat_ds3_share_open_twice": KNOWNFAIL, "test_fat_label_create_bpb12": KNOWNFAIL, "test_fat_label_create_bpb16": KNOWNFAIL, "test_fat_label_create_bpb32": KNOWNFAIL, "test_fat_label_create_noduplicate": KNOWNFAIL, "test_fat_label_create_predir": KNOWNFAIL, "test_fat_label_create_prefile": KNOWNFAIL, "test_memory_emm286_borland": KNOWNFAIL, "test_memory_hma_alloc3": UNSUPPORTED, "test_memory_hma_chain": UNSUPPORTED, "test_memory_uma_strategy": KNOWNFAIL, "test_passing_dos_errorlevel_back": KNOWNFAIL, } cls.setUpClassPost() # Check files under test exist, or skip the whole thing cls.files_to_copy = [ Path(environ.get("FDOS_KERNEL_SYS", "../fdos/kernel.git/bin/kernel.sys")), Path(environ.get("FDOS_COMMAND_COM", "../fdos/freecom.git/command.com")), Path(environ.get("FDOS_SHARE_COM", "../fdos/share.git/src/share.com")), ] for f in cls.files_to_copy: if not f.is_file(): raise unittest.SkipTest("File '%s' not found" % f.name) def setUp(self): super(FRDOSGITTestCase, self).setUp() for f in self.files_to_copy: copy(f, self.workdir) 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.actions = { "test_fat32_img_d_writable": UNSUPPORTED, "test_lfn_volume_info_fat16": KNOWNFAIL, "test_lfn_volume_info_fat32": UNSUPPORTED, "test_lfs_disk_info_fat32": UNSUPPORTED, "test_memory_hma_alloc3": UNSUPPORTED, "test_memory_hma_chain": UNSUPPORTED, "test_passing_dos_errorlevel_back": KNOWNFAIL, "test_fat_label_create_bpb32": UNSUPPORTED, "test_fat_label_create_on_lfns": UNSUPPORTED, } 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 MSDOS700TestCase(OurTestCase, unittest.TestCase): # badged Win95 RTM at winworldpc.com @classmethod def setUpClass(cls): super(MSDOS700TestCase, cls).setUpClass() cls.version = "Windows 95. [Version 4.00.950]" cls.prettyname = "MS-DOS-7.00" cls.files = [ ("io.sys", "22924f93dd0f9ea6a4624ccdd1bbcdf5eb43a308"), ("msdos.sys", "f5d01c68d518f4b8b2482d3815af8bb88003831d"), ("command.com", "67696207c3963a0dc9afab8cf37dbdb966c1f663"), ] cls.systype = SYSTYPE_MSDOS_NEW cls.autoexec = "autoemu.bat" cls.bootblocks = [ ("boot-306-4-17.blk", "8c016e339ca6b8126fd2026ed3a7eeeb6cbb8903"), ("boot-615-4-17.blk", "b6fdddbfb37442a2762d5897de1aa7d7a694286a"), ("boot-900-15-17.blk", "8c1243481112f320f2a5f557f30db11174fe7e3d"), ] cls.images = [ ("boot-floppy.img", ""), ] cls.actions = { "test_fat32_img_d_writable": UNSUPPORTED, "test_fat_label_create_bpb32": UNSUPPORTED, "test_lfn_volume_info_fat16": KNOWNFAIL, "test_lfn_volume_info_fat32": UNSUPPORTED, "test_lfs_disk_info_fat32": UNSUPPORTED, "test_lfs_disk_info_mfs": 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") def setUpDosVersion(self): self.mkfile("version.bat", "ver\r\nrem end\r\n") # Disable the logo here or we get blank screen self.mkfile("msdos.sys", """ [Options] BootGUI=0 Logo=0 """, newline="\r\n") class MSDOS710TestCase(OurTestCase, unittest.TestCase): # badged CDU (Chinese DOS Union) at winworldpc.com @classmethod def setUpClass(cls): super(MSDOS710TestCase, cls).setUpClass() cls.version = "MS-DOS 7.1 [Version 7.10.1999]" cls.prettyname = "MS-DOS-7.10" cls.files = [ ("io.sys", "8c586b1bf38fc2042f2383ca873283a466be2f44"), ("msdos.sys", "cd1e6103ce9cdebbc7a5611df13ff4fbd5e2159c"), ("command.com", "f6547d81e625a784633c059e536e90ee45532202"), ] cls.systype = SYSTYPE_MSDOS_NEW cls.autoexec = "autoemu.bat" cls.bootblocks = [ ("boot-306-4-17.blk", "0f520de6e2a33ef8fd336b2844957689fc1060e9"), ("boot-615-4-17.blk", "5e49a8ee7747191d87a2214cc0281736262687b9"), ("boot-900-15-17.blk", "2c29d06909c7d5ca46a3ca26ddde9287a11ef315"), ] cls.images = [ ("boot-floppy.img", ""), ] cls.actions = { } 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") # Disable the logo here or we get blank screen self.mkfile("msdos.sys", """ [Options] BootGUI=0 Logo=0 """, newline="\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__': # Dynamically create libi86 tests libi86_create_items(OurTestCase) 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"] attrs = sorted(OurTestCase.attrs) 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 | --get-test-binaries | " + "--list-attrs | --list-cases | --list-tests] | " + "[--require-attr=STRING TestCase ...] | " + "[TestCase[.testname] ...]") % argv[0]) exit(0) elif argv[1] == "--get-test-binaries": get_test_binaries() exit(0) elif argv[1] == "--list-attrs": for a in attrs: print(str(a)) 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(r"^--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()