├── src ├── WDEVDD.DEF ├── INCLUDE │ ├── WINUSER.INC │ ├── VDDSVC.INC │ └── WINBASE.INC ├── oemchars.inc ├── debug.inc ├── timer.inc ├── wdent.inc ├── setargv.inc ├── exfat.inc ├── srcnotes.txt ├── undelete.inc ├── sprintf.inc ├── initpm.inc ├── wdepm.inc ├── getstrng.inc ├── SETM432.ASM ├── SETM43.ASM ├── fatfs.inc ├── WDEVDD.ASM └── unformat.inc ├── compress ├── Make.bat ├── Readme.txt ├── setargv.inc ├── printf.inc └── compress.asm ├── wdevdd.txt ├── Makefile ├── readme.txt ├── license.txt └── changes.txt /src/WDEVDD.DEF: -------------------------------------------------------------------------------- 1 | 2 | LIBRARY WDEVDD 3 | EXPORTS 4 | Init 5 | Dispatch 6 | -------------------------------------------------------------------------------- /src/INCLUDE/WINUSER.INC: -------------------------------------------------------------------------------- 1 | 2 | 3 | ifdef __JWASM__ 4 | option dllimport: 5 | endif 6 | 7 | wsprintfA proto C :ptr byte, :ptr byte, :vararg 8 | 9 | ifdef __JWASM__ 10 | option dllimport:none 11 | endif 12 | 13 | -------------------------------------------------------------------------------- /compress/Make.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem use jwasm -coff & jwlink 3 | jwasm -nologo -coff -D?PUREFLAT -Fl compress.asm 4 | jwlink format win pe hx f compress.obj op m,q,stub=loadpe.bin,stack=0x4000,heap=0x1000 5 | rem 6 | rem use jwasm -pe; needs jwasm v2.19+ 7 | rem jwasm -nologo -pe -DFMTPE -D?STUB=\hx\bin\loadpe.bin -D?PUREFLAT -Fl compress.asm 8 | rem patchpe -s:0x2000 -x compress.exe 9 | -------------------------------------------------------------------------------- /wdevdd.txt: -------------------------------------------------------------------------------- 1 | 2 | About WDEVDD 3 | 4 | WDEVDD is a "Virtual DOS Driver" (VDD) for Windows XP/Vista NTVDM. 5 | It allows WDE low-level access to block devices when running in Windows. 6 | This feature requires the user to have administrator rights. 7 | 8 | Installation 9 | 10 | WDEVDD.DLL must be copied to a directory included in the PATH 11 | environment variable. AFAIK, for Vista, it has to be copied to the 12 | Windows system directory. 13 | 14 | License 15 | 16 | WDEVDD is Copyright Japheth. Source is released under the GNU GPL2 17 | license. 18 | 19 | -------------------------------------------------------------------------------- /compress/Readme.txt: -------------------------------------------------------------------------------- 1 | 2 | About 3 | 4 | Compress is a small tool intended to be used together with WDe. It 5 | "compresses" a directory stored in a file by removing all "deleted" 6 | entries ( first byte == E5h ). Such an operation may be useful 7 | specifically for the root directory of a FAT32 disk that has been 8 | "flooded" with (temporary) files. 9 | 10 | 11 | Usage 12 | 13 | - save directory to compress in WDe as file/fat chain. 14 | - use compress to compress the directory. 15 | - restore directory in WDe as file/fat chain. 16 | 17 | 18 | Restrictions 19 | 20 | To be able to "compress" directories of "any" size, compress has been 21 | written as 32-bit application and hence needs a DPMI host to run. 22 | Actually, size of the buffer to read the directory into is 256 kB - 23 | that should cover most cases. If it does not, constant BUFFSIZE has to 24 | be adjusted and the program must be recreated using Make.bat. 25 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | # this makefile creates 3 | # - wde.com : the standard WDe 4 | # - setm43.exe : helper tool to set a 43x100 text resolution with 14x8 font. 5 | # - setm432.exe : a variant of setm43.exe, if setm43 shows garbage. 6 | # - wdevdd.dll : helper tool to allow direct disk access in WinXP/Vista 7 | # - wdex.com : WDe running as DPMI app 8 | 9 | odir=build 10 | idir=src 11 | 12 | incfiles=$(idir)\undelete.inc $(idir)\unformat.inc $(idir)\fatfs.inc $(idir)\getstrng.inc 13 | 14 | all: $(odir) $(odir)\wde.com $(odir)\setm43.exe $(odir)\setm432.exe $(odir)\wdevdd.dll $(odir)\wdex.com 15 | 16 | $(odir): 17 | @mkdir $(odir) 18 | 19 | $(odir)\wde.com: $(idir)\wde.asm $(incfiles) 20 | @jwasm -mz -nologo -Sg -Fl=$(odir)\wde.lst -Fo=$(odir)\WDE.COM $(idir)\wde.asm 21 | 22 | $(odir)\setm43.exe: $(idir)\setm43.asm 23 | @jwasm -mz -nologo -Sg -Fl=$(odir)\setm43.lst -Fo=$(odir)\SETM43.EXE $(idir)\setm43.asm 24 | 25 | $(odir)\setm432.exe: $(idir)\setm432.asm 26 | @jwasm -mz -nologo -Sg -Fl=$(odir)\setm432.lst -Fo=$(odir)\SETM432.EXE $(idir)\setm432.asm 27 | 28 | $(odir)\wdevdd.dll: $(idir)\wdevdd.asm 29 | @jwasm -pe -nologo -zze -I $(idir)\INCLUDE -Fl=$(odir)\wdevdd.lst -Fo $(odir)\wdevdd.dll $(idir)\wdevdd.asm 30 | 31 | $(odir)\wdex.com: $(idir)\wde.asm $(incfiles) $(idir)\wdepm.inc $(idir)\initpm.inc 32 | @jwasm -mz -nologo -Sg -D?PM=1 -Fl=$(odir)\wdex.lst -Fo=$(odir)\WDEX.COM $(idir)\wde.asm 33 | 34 | -------------------------------------------------------------------------------- /src/oemchars.inc: -------------------------------------------------------------------------------- 1 | 2 | ;--- to translate LFN chars 0080-00FF to ANSI (CP 1252?); 3 | ;--- currently just German umlauts. 4 | 5 | oemchars label byte 6 | ;------- 0---1---2---3---4---5---6---7---8---9---A---B---C---D---E---F 7 | db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;80-8f 8 | db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;90-9f 9 | db 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0 ;a0-af 10 | db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;b0-bf 11 | db 0, 0, 0, 0,142, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;c0-cf 12 | db 0, 0, 0, 0, 0, 0,153, 0, 0, 0, 0, 0,154, 0, 0,225 ;d0-df 13 | db 0, 0, 0, 0,132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;e0-ef 14 | db 0, 0, 0, 0, 0, 0,148, 0, 0, 0, 0, 0,129, 0, 0, 0 ;f0-ff 15 | 16 | ;--- valid OEM chars in SFNs. 17 | ;--- this table is used by WDe when it tries to detect a "directory" sector, 18 | ;--- and,if ok, will activate the "directory view". 19 | ;--- currently contains German upper case umlauts (8E/99/9A) and "sz" (E1) only. 20 | ;--- actually, many chars > 128 are accepted as valid SFN chars. 21 | 22 | oembittab label word 23 | ;---------0---0---0---0 24 | ;---------C---8---4---0 25 | dw 0100000000000000b ;8X 26 | dw 0000011000000000b ;9X 27 | dw 0000000000000000b ;AX 28 | dw 0000000000000000b ;BX 29 | dw 0000000000000000b ;CX 30 | dw 0000000000000000b ;DX 31 | dw 0000000000000010b ;EX 32 | dw 0000000000000000b ;FX 33 | -------------------------------------------------------------------------------- /src/debug.inc: -------------------------------------------------------------------------------- 1 | 2 | ;--- definitions for debug version 3 | 4 | ;--- get (start) time in ms 5 | 6 | @getstarttime macro 7 | if ?DEBUG 8 | pushad 9 | call gettimer 10 | mov starttime, eax 11 | popad 12 | endif 13 | endm 14 | 15 | ;--- print measured time in menu row 16 | 17 | @dprinttime macro formstr 18 | if ?DEBUG 19 | pushf 20 | pushad 21 | call gettimer 22 | sub eax, starttime 23 | sub sp, 80 24 | mov dx, sp 25 | invoke sprintf, dx, CStr(formstr), eax 26 | call printerror 27 | add sp, 80 28 | popad 29 | popf 30 | endif 31 | endm 32 | 33 | if ?DEBUG 34 | 35 | _BSS segment 36 | dbgbuff db 80 dup (?) 37 | _BSS ends 38 | 39 | _dbgout proc 40 | push dx 41 | push ax 42 | mov dx, offset dbgbuff 43 | if ?VDD 44 | cmp [hVdd],-1 45 | jz @F 46 | push 41h 47 | mov ax, [hVdd] 48 | Dispatch 49 | jmp done ; note that the VDD has restored AX already 50 | @@: 51 | endif 52 | mov ah,9 53 | int 21h 54 | pop ax 55 | done: 56 | pop dx 57 | ret 58 | _dbgout endp 59 | 60 | endif 61 | 62 | ;--- print a line on stdout/debug terminal if ?DEBUG=1 63 | 64 | @dprintfln macro formstr, args:vararg 65 | if ?DEBUG 66 | pushf 67 | ifb 68 | invoke sprintf, offset dbgbuff, CStr(formstr,13,10,'$') 69 | else 70 | invoke sprintf, offset dbgbuff, CStr(formstr,13,10,'$'), args 71 | endif 72 | call _dbgout 73 | popf 74 | endif 75 | endm 76 | 77 | @dprintduration macro prefix 78 | if ?DEBUG 79 | pushf 80 | push eax 81 | call gettimer 82 | sub eax, starttime 83 | invoke sprintf, offset dbgbuff, CStr( prefix, ": %u ms",13,10,'$'), eax 84 | pop eax 85 | call _dbgout 86 | popf 87 | endif 88 | endm 89 | 90 | -------------------------------------------------------------------------------- /src/timer.inc: -------------------------------------------------------------------------------- 1 | 2 | ;--- GetTimerValue: return timer value in edx:ax 3 | 4 | GetTimerValue proc uses ds 5 | 6 | mov ds, [_0000H] 7 | tryagain: 8 | mov edx,ds:[46ch] 9 | mov al,0C2h ;read timer 0 status + value low/high 10 | out 43h, al 11 | xchg edx, edx 12 | in al,40h 13 | mov cl,al ;CL = status 14 | xchg edx, edx 15 | in al,40h 16 | mov ah, al ;AH = value low 17 | xchg edx, edx 18 | in al,40h ;AL = value high 19 | 20 | test cl,40h ;was latch valid? 21 | jnz tryagain 22 | cmp edx,ds:[46ch] ;did an interrupt occur in the meantime? 23 | jnz tryagain ;then do it again! 24 | 25 | xchg al,ah 26 | ;--- usually (counter mode 3) the timer is set to count down *twice*! 27 | ;--- however, sometimes counter mode 2 is set! 28 | mov ch,cl 29 | and ch,0110B ;bit 1+2 relevant 30 | cmp ch,0110B ;counter mode 3? 31 | jnz @F 32 | ;--- in mode 3, PIN status of OUT0 will become bit 15 33 | shr ax,1 34 | and cl,80h 35 | or ah, cl 36 | @@: 37 | ;--- now the counter is in AX (counts from FFFF to 0000) 38 | neg ax 39 | ;--- now the count is from 0 to FFFF 40 | ret 41 | GetTimerValue endp 42 | 43 | ;--- gettimer: get timer value in ms in eax 44 | 45 | gettimer proc 46 | 47 | call GetTimerValue 48 | 49 | ;--- the timer ticks are in EDX:AX, timer counts down 50 | ;--- a 16bit value with 1,193,180 Hz -> 1193180/65536 = 18.20648 Hz 51 | ;--- which are 54.83 ms 52 | ;--- to convert in ms: 53 | ;--- 1. subticks in ms: AX / 1193 54 | ;--- 2. ticks in ms: EDX * 55 55 | ;--- 3. total 1+2 56 | 57 | push edx 58 | movzx eax,ax ;step 1 59 | cdq 60 | mov ecx, 1193 61 | div ecx 62 | mov ecx, eax 63 | pop eax ;step 2 64 | mov edx, 55 65 | mul edx 66 | add eax, ecx ;step 3 67 | ret 68 | 69 | gettimer endp 70 | 71 | -------------------------------------------------------------------------------- /src/INCLUDE/VDDSVC.INC: -------------------------------------------------------------------------------- 1 | 2 | VDM_V86 equ 0 3 | VDM_PM equ 1 4 | 5 | @Vdd macro name_, parms 6 | if parms eq 0 7 | name_ proto 8 | elseif parms eq 4 9 | name_ proto :dword 10 | elseif parms eq 8 11 | name_ proto :dword, :dword 12 | elseif parms eq 12 13 | name_ proto :dword, :dword, :dword 14 | endif 15 | endm 16 | 17 | ifdef __JWASM__ 18 | option dllimport: 19 | endif 20 | 21 | @Vdd VdmMapFlat ,12 22 | @Vdd getEAX, 0 23 | @Vdd getAX, 0 24 | @Vdd getAL, 0 25 | @Vdd getAH , 0 26 | @Vdd getEBX , 0 27 | @Vdd getBX , 0 28 | @Vdd getBL , 0 29 | @Vdd getBH , 0 30 | @Vdd getECX , 0 31 | @Vdd getCX , 0 32 | @Vdd getCL , 0 33 | @Vdd getCH , 0 34 | @Vdd getEDX , 0 35 | @Vdd getDX , 0 36 | @Vdd getDL , 0 37 | @Vdd getDH , 0 38 | @Vdd getESP , 0 39 | @Vdd getSP , 0 40 | @Vdd getEBP , 0 41 | @Vdd getBP , 0 42 | @Vdd getESI , 0 43 | @Vdd getSI , 0 44 | @Vdd getEDI , 0 45 | @Vdd getDI , 0 46 | @Vdd getEIP , 0 47 | @Vdd getIP , 0 48 | @Vdd getCS , 0 49 | @Vdd getSS , 0 50 | @Vdd getDS , 0 51 | @Vdd getES , 0 52 | @Vdd getFS , 0 53 | @Vdd getGS , 0 54 | @Vdd getCF , 0 55 | @Vdd getPF , 0 56 | @Vdd getAF , 0 57 | @Vdd getZF , 0 58 | @Vdd getSF , 0 59 | @Vdd getIF , 0 60 | @Vdd getDF , 0 61 | @Vdd getOF , 0 62 | @Vdd getMSW , 0 63 | @Vdd setEAX, 4 64 | @Vdd setAX, 4 65 | @Vdd setAH, 4 66 | @Vdd setAL, 4 67 | @Vdd setEBX, 4 68 | @Vdd setBX, 4 69 | @Vdd setBH, 4 70 | @Vdd setBL, 4 71 | @Vdd setECX, 4 72 | @Vdd setCX, 4 73 | @Vdd setCH, 4 74 | @Vdd setCL, 4 75 | @Vdd setEDX, 4 76 | @Vdd setDX, 4 77 | @Vdd setDH, 4 78 | @Vdd setDL, 4 79 | @Vdd setESP, 4 80 | @Vdd setSP, 4 81 | @Vdd setEBP, 4 82 | @Vdd setBP, 4 83 | @Vdd setESI, 4 84 | @Vdd setSI, 4 85 | @Vdd setEDI, 4 86 | @Vdd setDI, 4 87 | @Vdd setEIP, 4 88 | @Vdd setIP, 4 89 | @Vdd setCS, 4 90 | @Vdd setSS, 4 91 | @Vdd setDS, 4 92 | @Vdd setES, 4 93 | @Vdd setFS, 4 94 | @Vdd setGS, 4 95 | @Vdd setCF, 4 96 | @Vdd setPF, 4 97 | @Vdd setAF, 4 98 | @Vdd setZF, 4 99 | @Vdd setSF, 4 100 | @Vdd setIF, 4 101 | @Vdd setDF, 4 102 | @Vdd setOF, 4 103 | @Vdd setMSW, 4 104 | 105 | ifdef __JWASM__ 106 | option dllimport:none 107 | endif 108 | -------------------------------------------------------------------------------- /src/wdent.inc: -------------------------------------------------------------------------------- 1 | 2 | ;--- include to make WDE compatible with Windows NT/XP 3 | ;--- copyright japheth 2010 4 | ;--- Released under GNU GPL 2 license. 5 | 6 | RegisterModule macro 7 | db 0C4h, 0C4h, 58h, 0 8 | endm 9 | UnRegisterModule macro 10 | db 0C4h, 0C4h, 58h, 1 11 | endm 12 | Dispatch macro 13 | db 0C4h, 0C4h, 58h, 2 14 | endm 15 | 16 | @int13 equ 17 | @int21 equ 18 | @int25 equ 19 | @int26 equ 20 | @int2F equ 21 | 22 | .data 23 | 24 | hVdd dw -1 25 | 26 | .code 27 | 28 | int13: 29 | int 13h 30 | ret 31 | mov ax, [hVdd] 32 | Dispatch 33 | ret 34 | int21: 35 | int 21h 36 | ret 37 | mov ax, [hVdd] 38 | Dispatch 39 | ret 40 | int25: 41 | int 25h 42 | pop dx 43 | ret 44 | mov ax, [hVdd] 45 | Dispatch 46 | ret 47 | int26: 48 | int 26h 49 | pop dx 50 | ret 51 | mov ax, [hVdd] 52 | Dispatch 53 | ret 54 | int2F: 55 | int 2fh 56 | ret 57 | mov ax, [hVdd] 58 | Dispatch 59 | ret 60 | 61 | ;--- this routine must run before (optionally) switching to protected-mode 62 | 63 | initvdd proc 64 | mov ax, 3306h 65 | int 21h 66 | cmp bx, 3205h 67 | jnz @F 68 | mov si, CStr("wdevdd.dll") 69 | mov bx, CStr("Dispatch") ; DS:BX->"Dispatch" 70 | mov di, CStr("Init") ; ES:DI->"Init" 71 | push ds 72 | pop es 73 | RegisterModule 74 | jc @F 75 | cmp ax, -1 76 | jz @F 77 | push ds 78 | mov [hVdd], ax 79 | push cs 80 | pop ds 81 | assume ds:_TEXT 82 | mov ax, 6A50h ; push AX, push XX 83 | mov cx, 9013h ; push XX, nop 84 | mov word ptr [int13+0], ax 85 | mov byte ptr [int13+2], cl 86 | mov cl, 21h 87 | mov word ptr [int21+0], ax 88 | mov byte ptr [int21+2], cl 89 | mov cl, 25h 90 | mov word ptr [int25+0], ax 91 | mov word ptr [int25+2], cx 92 | mov cl, 26h 93 | mov word ptr [int26+0], ax 94 | mov word ptr [int26+2], cx 95 | mov cl, 2Fh 96 | mov word ptr [int2F+0], ax 97 | mov byte ptr [int2F+2], cl 98 | pop ds 99 | assume ds:DGROUP 100 | @@: 101 | ret 102 | initvdd endp 103 | 104 | exitvdd proc 105 | mov ax, -1 106 | xchg ax, [hVdd] 107 | cmp ax, -1 108 | jz @F 109 | UnRegisterModule 110 | @@: 111 | ret 112 | exitvdd endp 113 | 114 | -------------------------------------------------------------------------------- /src/setargv.inc: -------------------------------------------------------------------------------- 1 | 2 | ;--- read the commandline at PSP:81h 3 | ;--- and create an argc/argv structure on the stack. 4 | ;--- in: ES=PSP, DS=DGROUP, SS=DGROUP 5 | ;--- out: _argc (=[bp-2]) 6 | ;--- _argv (=[bp-4]) 7 | ;--- all std registers modified (including SP) 8 | 9 | ?DUMMYFN equ 1 10 | ?QUOTES equ 1 11 | 12 | _setargv proc 13 | 14 | mov bp, sp 15 | sub sp, 256 ; just make enough room for argc/argv 16 | 17 | xor di, di ; init argc 18 | xor dx, dx ; init size of mem block 19 | mov si, 81H 20 | push es 21 | pop ds 22 | ; assume ds:nothing ; no need for assumes, since no global vars are accessed 23 | jmp scanarg 24 | 25 | ;--- DI = argc 26 | ;--- DX = block size (not including null terminators) 27 | nextarg: 28 | push bx ; save argument size 29 | scanarg: 30 | @@: 31 | lodsb 32 | cmp al, ' ' 33 | je @B 34 | cmp al, 9 35 | je @B 36 | cmp al, 13 37 | jz doneargs ; exit if eol 38 | inc di ; another argument 39 | xor bx, bx ; init argument size 40 | if ?QUOTES 41 | cmp al, '"' 42 | jz handle_quote 43 | endif 44 | dec si ; back up to reload character 45 | push si ; save argument ofs 46 | @@: 47 | lodsb 48 | cmp al, ' ' ; end argument? 49 | je nextarg 50 | cmp al, 9 51 | je nextarg ; white space terminates argument 52 | cmp al, 13 53 | jz doneargs2 ; exit if eol 54 | inc bx 55 | inc dx 56 | jmp @B 57 | if ?QUOTES 58 | handle_quote: 59 | push si 60 | @@: 61 | lodsb 62 | cmp al, 13 63 | jz quoteerr 64 | cmp al, '"' 65 | jz @F 66 | inc dx 67 | inc bx 68 | jmp @B 69 | quoteerr: 70 | dec si ; "unread" the CR 71 | @@: 72 | jmp nextarg 73 | endif 74 | doneargs2: 75 | push bx ; last argument's size 76 | doneargs: 77 | 78 | ;--- address & size of arguments are pushed 79 | 80 | mov cx, di 81 | add dx, di ; DX=size arguments + terminator bytes 82 | inc di ; add one for NULL pointer 83 | if ?DUMMYFN 84 | inc di ; add one for filename 85 | endif 86 | shl di, 1 ; each ofs needs 2 bytes 87 | add dx, di ; DX=size args + size argv 88 | and dx, -2 ; ensure stack remains word aligned 89 | mov ax, [bp] 90 | sub bp, dx ; alloc the really needed space for argc/argv 91 | mov [bp-6], ax ; store return address 92 | 93 | _argc equ 94 | _argv equ 95 | 96 | mov [_argv], bp 97 | mov [_argc], cx 98 | 99 | add di, bp ; di -> behind vector table (strings) 100 | xor ax, ax 101 | lea bx, [di-2] 102 | mov ss:[bx], ax ; terminating 0000 _argv[x] 103 | sub bx, 2 104 | jcxz noargs 105 | push ss 106 | pop es 107 | 108 | ;--- copy the arguments from PSP onto the stack 109 | 110 | mov dx, cx 111 | @@: 112 | pop cx ; size 113 | pop si ; address 114 | mov ss:[bx], di ; store _argv[x] 115 | sub bx, 2 116 | rep movsb 117 | stosb ; AL still 0 118 | dec dx 119 | jnz @B 120 | 121 | noargs: 122 | push ss 123 | pop ds 124 | ; assume ds:DGROUP 125 | if ?DUMMYFN 126 | mov [bx], ax ; store 0 as dummy filename 127 | inc word ptr [_argc] 128 | endif 129 | lea sp, [bp-6] 130 | ret 131 | _setargv endp 132 | 133 | -------------------------------------------------------------------------------- /compress/setargv.inc: -------------------------------------------------------------------------------- 1 | 2 | ;--- read the commandline at PSP:81h 3 | ;--- and create an argc/argv structure on the stack. 4 | ;--- in: ES=FLAT, DS=FLAT, SS=FLAT 5 | ;--- out: _argc (=[ebp-4]) 6 | ;--- _argv (=[ebp-8]) 7 | ;--- all std registers modified (including ESP) 8 | 9 | ?DUMMYFN equ 1 10 | ?QUOTES equ 1 11 | 12 | _setargv proc 13 | 14 | ifndef ?PUREFLAT ; don't change seg regs ( LOADPE used ) 15 | mov ah, 51h 16 | int 21h 17 | mov es, ebx 18 | endif 19 | 20 | mov ebp, esp 21 | sub esp, 256 ; just make enough room for argc/argv 22 | 23 | xor edi, edi ; init argc 24 | xor edx, edx ; init size of mem block 25 | ifdef ?PUREFLAT 26 | lea esi, [ebx+81h] 27 | else 28 | mov esi, 81H 29 | push es 30 | pop ds 31 | endif 32 | jmp scanarg 33 | 34 | ;--- EDI = argc 35 | ;--- EDX = block size (not including null terminators) 36 | nextarg: 37 | push Ebx ; save argument size 38 | scanarg: 39 | @@: 40 | lodsb 41 | cmp al, ' ' 42 | je @B 43 | cmp al, 9 44 | je @B 45 | cmp al, 13 46 | jz doneargs ; exit if eol 47 | inc edi ; another argument 48 | xor ebx, ebx ; init argument size 49 | if ?QUOTES 50 | cmp al, '"' 51 | jz handle_quote 52 | endif 53 | dec esi ; back up to reload character 54 | push esi ; save argument ofs 55 | @@: 56 | lodsb 57 | cmp al, ' ' ; end argument? 58 | je nextarg 59 | cmp al, 9 60 | je nextarg ; white space terminates argument 61 | cmp al, 13 62 | jz doneargs2 ; exit if eol 63 | inc ebx 64 | inc edx 65 | jmp @B 66 | if ?QUOTES 67 | handle_quote: 68 | push esi 69 | @@: 70 | lodsb 71 | cmp al, 13 72 | jz quoteerr 73 | cmp al, '"' 74 | jz @F 75 | inc edx 76 | inc ebx 77 | jmp @B 78 | quoteerr: 79 | dec esi ; "unread" the CR 80 | @@: 81 | jmp nextarg 82 | endif 83 | doneargs2: 84 | push ebx ; last argument's size 85 | doneargs: 86 | 87 | ;--- address & size of arguments are pushed 88 | 89 | mov ecx, edi 90 | add edx, edi ; EDX=size arguments + terminator bytes 91 | inc edi ; add one for NULL pointer 92 | if ?DUMMYFN 93 | inc edi ; add one for filename 94 | endif 95 | shl edi, 2 ; each ofs needs 4 bytes 96 | add edx, edi ; EDX=size args + size argv 97 | add edx, 3 98 | and edx, -4 ; ensure stack remains dword aligned 99 | mov eax, [ebp] 100 | sub ebp, edx ; alloc the really needed space for argc/argv 101 | mov [ebp-12], eax ; store return address 102 | 103 | _argc equ 104 | _argv equ 105 | 106 | mov [_argv], ebp 107 | mov [_argc], ecx 108 | 109 | add edi, ebp ; edi -> behind vector table (strings) 110 | xor eax, eax 111 | lea ebx, [edi-4] 112 | ifdef ?PUREFLAT 113 | mov [ebx], eax ; terminating 0000 _argv[x] 114 | else 115 | mov ss:[ebx], eax ; terminating 0000 _argv[x] 116 | endif 117 | sub ebx, 4 118 | jecxz noargs 119 | ifndef ?PUREFLAT 120 | push ss 121 | pop es 122 | endif 123 | 124 | ;--- copy the arguments from PSP onto the stack 125 | 126 | mov edx, ecx 127 | @@: 128 | pop ecx ; size 129 | pop esi ; address 130 | ifdef ?PUREFLAT 131 | mov [ebx], edi ; store _argv[x] 132 | else 133 | mov ss:[ebx], edi ; store _argv[x] 134 | endif 135 | sub ebx, 4 136 | rep movsb 137 | stosb ; AL still 0 138 | dec edx 139 | jnz @B 140 | 141 | noargs: 142 | ifndef ?PUREFLAT 143 | push ss 144 | pop ds 145 | push ss 146 | pop es 147 | endif 148 | if ?DUMMYFN 149 | mov [ebx], eax ; store 0 as dummy filename 150 | inc dword ptr [_argc] 151 | endif 152 | lea esp, [ebp-12] 153 | ret 154 | _setargv endp 155 | 156 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | 2 | 1. About 3 | 4 | WDe is designed to be a modular disk editor capable of allowing users 5 | to manipulate data stored in various ways on different kinds of storage 6 | mediums. 7 | 8 | WDe is currently capable of editing logical, physical and CD-Rom drives 9 | on MS-DOS V4.0+ or compatible. It understands all FAT file systems, 10 | including exFAT. It should be able to edit drives up to 2 TB in size, 11 | and is aware of both MBR and GPT partitioning schemes. Image files may 12 | be "mounted" by WDe as either logical or physical drives. 13 | 14 | Please be aware that a disk editor, if used inappropriately, might easily 15 | cause severe data losses. WDe is no exception in this regard, on the 16 | contrary, it generally assumes that the user knows exactly what he/she 17 | is doing and will begin any job that is is told to do instantly, without 18 | confirmation. So if you're not accustomed to WDe's user interface yet, 19 | don't experiment with storage devices that hold important data - unless 20 | you love to live dangerously! 21 | 22 | 23 | 2. User Interface 24 | 25 | WDe has a text mode interface. It needs at least 43 rows and 80 columns. 26 | If the current text mode has less than 43 rows, WDE will switch to the 27 | standard text mode, but loads the 8x8 font instead of the usual 8x16 one 28 | and restricts the scan lines to 350, thus achieving the needed 43 rows. 29 | In other words, WDe needs at least an EGA video card to work. 30 | 31 | There are 2 small tools, SETM43/SETM432, supplied. These may allow WDE 32 | to use a better looking font (8x14) with still 43 lines, but there is no 33 | guarantee that any of those tools runs with your graphics card - they use 34 | a heavily modified VESA mode 0x102, something that may work or not. 35 | 36 | 37 | 3. Environment 38 | 39 | WDe is supposed to run in DOS. There's a support dll supplied (WDEVDD.DLL), 40 | that may allow to run WDe in Windows XP or Vista as administrator, but this 41 | is unsupported and won't work with newer versions of Windows. Also note that 42 | WDe needs at least a 80386 cpu to run. 43 | 44 | 45 | 4. Creating the Binaries 46 | 47 | In case one wants to create the binaries from the source: 48 | 49 | WDe and the optional tools ( SETM43 and WDEVDD.DLL ) are written in 50 | Masm-style assembly language. They are supposed to be created by JWasm; 51 | Masm may also be used, but this additionally requires an OMF linker for 52 | WDe ( and SETM43 ) and a COFF linker for WDEVDD.DLL. Both a simple batch 53 | file ( build.bat ) and a Makefile are supplied that will do the job. 54 | The source can be found at https://github.com/Baron-von-Riedesel/WDe. 55 | 56 | The build tools will also create wdex.com, a version of WDe that runs 57 | in protected-mode as DPMI client. There is currently no real benefit 58 | using this binary. However, since protected-mode offers access to huge 59 | amounts of memory, it may allow to implement things that the real-mode 60 | WDe can't efficiently accomplish, for example, read in the whole FAT 61 | ( or directory structure ) of a drive and thus speed up certain functions 62 | considerably. 63 | 64 | There's buildd.bat supplied to create debug versions of WDe/WDeX. Those 65 | versions will write debug information to either the screen ( or a file, 66 | if stdout is redirected ) or - if running in a NTVDM and WDeVDD.dll is 67 | loaded - to the Windows debug terminal. 68 | 69 | 70 | 5. License 71 | 72 | WDe Copyright(C)2005 Ben Cadieux (ben.cadieux@gmail.com) and 2022 japheth. 73 | 74 | This program is free software; you can redistribute it and/or modify it 75 | under the terms of the GNU General Public License (Version 2) as published 76 | by the Free Software Foundation. 77 | 78 | This program is distributed in the hope that it will be useful, but 79 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 80 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 81 | for more details. 82 | 83 | You should have received a copy of the GNU General Public License 84 | along with this program; if not, write to the Free Software 85 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 86 | 87 | -------------------------------------------------------------------------------- /compress/printf.inc: -------------------------------------------------------------------------------- 1 | 2 | ;--- simple printf implementation for DOS 32-bit 3 | ;--- supports: 4 | ;--- %x : dword 5 | ;--- %lx : qword 6 | ;--- %u : dword 7 | ;--- %lu : qword 8 | ;--- %d : sdword 9 | ;--- %ld : sqword 10 | ;--- %s : near32 string out 11 | ;--- %c : character 12 | 13 | .386 14 | 15 | ;--- i64toa(long long n, char * s, int base); 16 | ;--- convert 64-bit long long to string 17 | 18 | i64toa PROC stdcall uses esi edi number:qword, outb:ptr, base:dword 19 | 20 | mov ch,0 21 | mov edi, base 22 | mov eax, dword ptr number+0 23 | mov esi, dword ptr number+4 24 | cmp edi,-10 25 | jne @F 26 | neg edi 27 | and esi,esi 28 | jns @F 29 | neg esi 30 | neg eax 31 | sbb esi,0 32 | mov ch,'-' 33 | @@: 34 | mov ebx,outb 35 | add ebx,22 36 | mov byte ptr [ebx],0 37 | @@nextdigit: 38 | dec ebx 39 | xor edx,edx 40 | xchg eax,esi 41 | div edi 42 | xchg eax,esi 43 | div edi 44 | add dl,'0' 45 | cmp dl,'9' 46 | jbe @F 47 | add dl,7+20h 48 | @@: 49 | mov [ebx],dl 50 | mov edx, eax 51 | or edx, esi 52 | jne @@nextdigit 53 | cmp ch,0 54 | je @F 55 | dec ebx 56 | mov [ebx],ch 57 | @@: 58 | mov eax,ebx 59 | ret 60 | 61 | i64toa ENDP 62 | 63 | printf PROC c uses ebx esi edi fmt:ptr sbyte, args:VARARG 64 | 65 | local flag:byte 66 | local longarg:byte 67 | local size_:dword 68 | local fillchr:dword 69 | local szTmp[24]:byte 70 | 71 | lea edi,args 72 | @@L335: 73 | mov esi,fmt 74 | nextchar: 75 | lodsb 76 | or al,al 77 | je done 78 | cmp al,'%' 79 | je formatitem 80 | push eax 81 | call handle_char 82 | jmp nextchar 83 | done: 84 | xor eax,eax 85 | ret 86 | 87 | formatitem: 88 | push offset @@L335 89 | xor edx,edx 90 | mov [longarg],dl 91 | mov bl,1 92 | mov cl,' ' 93 | cmp BYTE PTR [esi],'-' 94 | jne @F 95 | dec bl 96 | inc esi 97 | @@: 98 | mov [flag],bl 99 | cmp BYTE PTR [esi],'0' 100 | jne @F 101 | mov cl,'0' 102 | inc esi 103 | @@: 104 | mov [fillchr],ecx 105 | mov ebx,edx 106 | 107 | .while ( byte ptr [esi] >= '0' && byte ptr [esi] <= '9' ) 108 | lodsb 109 | sub al,'0' 110 | movzx eax,al 111 | imul ecx,ebx,10 ;ecx = ebx * 10 112 | add eax,ecx 113 | mov ebx,eax 114 | .endw 115 | 116 | mov [size_],ebx 117 | cmp BYTE PTR [esi],'l' 118 | jne @F 119 | mov [longarg],1 120 | inc esi 121 | @@: 122 | lodsb 123 | mov [fmt],esi 124 | cmp al,'x' 125 | je handle_x 126 | cmp al,'X' 127 | je handle_x 128 | cmp al,'d' 129 | je handle_d 130 | cmp al,'u' 131 | je handle_u 132 | cmp al,'s' 133 | je handle_s 134 | cmp al,'c' 135 | je handle_c 136 | and al,al 137 | jnz @F 138 | pop eax 139 | jmp done 140 | handle_c: 141 | mov eax,[edi] 142 | add edi, 4 143 | @@: 144 | push eax 145 | call handle_char 146 | retn 147 | 148 | handle_s: 149 | mov esi,[edi] 150 | add edi,4 151 | jmp print_string 152 | handle_d: 153 | handle_i: 154 | mov ebx,-10 155 | jmp @F 156 | handle_u: 157 | mov ebx, 10 158 | jmp @F 159 | handle_x: 160 | mov ebx, 16 161 | @@: 162 | xor edx,edx 163 | mov eax,[edi] 164 | add edi,4 165 | cmp longarg,1 166 | jnz @F 167 | mov edx,[edi] 168 | add edi,4 169 | jmp printnum 170 | @@: 171 | and ebx,ebx 172 | jns @F 173 | cdq 174 | @@: 175 | printnum: 176 | lea esi, szTmp 177 | invoke i64toa, edx::eax, esi, ebx 178 | mov esi, eax 179 | 180 | print_string: ;print string ESI, size EAX 181 | mov eax, esi 182 | .while byte ptr [esi] 183 | inc esi 184 | .endw 185 | sub esi, eax 186 | xchg eax, esi 187 | mov ebx,size_ 188 | sub ebx,eax 189 | .if flag == 1 190 | .while sdword ptr ebx > 0 191 | push [fillchr] 192 | call handle_char ;print leading filler chars 193 | dec ebx 194 | .endw 195 | .endif 196 | 197 | .while byte ptr [esi] 198 | lodsb 199 | push eax 200 | call handle_char ;print char of string 201 | .endw 202 | 203 | .while sdword ptr ebx > 0 204 | push [fillchr] 205 | call handle_char ;print trailing spaces 206 | dec ebx 207 | .endw 208 | retn 209 | 210 | handle_char: 211 | pop ecx 212 | pop edx 213 | cmp dl,10 214 | jnz @F 215 | mov dl,13 216 | mov ah,2 217 | int 21h 218 | mov dl,10 219 | @@: 220 | mov ah,2 221 | int 21h 222 | jmp ecx 223 | align 4 224 | 225 | printf ENDP 226 | 227 | 228 | -------------------------------------------------------------------------------- /src/exfat.inc: -------------------------------------------------------------------------------- 1 | 2 | ;--- exFAT data structures as documented by MS 3 | 4 | EXFAT struct 5 | db 64 dup (?) 6 | dqHidden dq ? ; +64 sector offset to start of partition 7 | dqSize dq ? ; +72 size of volume in sectors 8 | dwFatOfs dd ? ; +80 offset in sectors to start of first FAT 9 | dwFatSiz dd ? ; +84 size of a FAT in sectors 10 | dwClHpOfs dd ? ; +88 offset in sectors to start of clusters 11 | dwClCnt dd ? ; +92 no of clusters in cluster "heap" 12 | dwRootCl dd ? ; +96 starting cluster of root dir 13 | dwVolId dd ? ; volume serial no 14 | wFSRev dw ? 15 | wVolFlgs dw ? 16 | bBpSShift db ? ; bytes per sector shift 17 | bSpCShift db ? ; sectors per cluster shift 18 | bNumFats db ? ; number of FATs 19 | bDrive db ? ; drive no (80h=phys disk 0) 20 | EXFAT ends 21 | 22 | EFET_EOD equ 0 ; end of directory 23 | 24 | ;--- entry type bits 25 | ;--- 0-4: type code 26 | ;--- 5: importance, 0=critical, 1=benign 27 | ;--- 6: category, 0=primary, 1=secondary 28 | ;--- 7: InUse, 0=entry is free, 1=in use 29 | 30 | ;--- critical primary: 31 | ;--- typecode 1: allocation bitmap: 81h 32 | ;--- typecode 2: upcase table 82h 33 | ;--- typecode 3: volume label 83h 34 | ;--- typecode 5: file 85h 35 | 36 | EXFPTC_GUID equ 0 ; no cluster/size fields, no secondary 37 | EXFPTC_ALLOCBM equ 1 38 | EXFPTC_UPCASET equ 2 39 | EXFPTC_VOLLABEL equ 3 ; no cluster/size fields, just count and 11 wide characters 40 | EXFPTC_FILE equ 5 41 | 42 | ;--- primary flags 43 | ;--- bit 0: 0=cluster and size are undefined, 1=are defined 44 | ;--- bit 1: 0=has FAT chain, 1=no FAT chain, is contiguous series of cluster 45 | ;--- bit 2-15: custom defined 46 | 47 | EXFPF_CLSDEFINED equ 1 48 | EXFPF_NOCHAIN equ 2 49 | 50 | ;--- generic primary directory entry 51 | 52 | EXFDIRP struct 53 | etype db ? ; entry type 54 | seccnt db ? ; secondary count - no of secondary entries that follow 55 | chksum dw ? ; 56 | ;primflgs dw ? ; see above ( primary flags ) - this field is NOT very generic 57 | dw ? 58 | db 14 dup (?) ; custom defined 59 | dwFirstCl dd ? ; first cluster 60 | dqSize dq ? ; data length 61 | EXFDIRP ends 62 | 63 | ;--- primary file directory entry 64 | 65 | EXFDIRPF struct 66 | etype db ? ;+0 67 | seccnt db ? ;+1 secondary count 68 | chksum dw ? ;+2 69 | attributes dw ? 70 | dw ? 71 | dwCreated dd ? ;+8 72 | dwModified dd ? ;+12 last modified 73 | dwAccessed dd ? ;+16 last accessed 74 | bCreInc db ? ;+20 create 10ms inc 75 | bModInc db ? ;+21 last modifed 10ms inc 76 | bCreUtcOfs db ? ;+22 create utc offset 77 | bModUtcOfs db ? ;+23 last modifed utc offset 78 | bAccUtcOfs db ? ;+24 last accessed utc offset 79 | db 7 dup (?) 80 | EXFDIRPF ends 81 | 82 | ;--- attributes: 83 | ;--- bit 0-5: readonly, hidden, system, reserved, directory, archive 84 | ;--- bit 6-15: reserved 85 | 86 | ;--- generic secondary entry 87 | 88 | ;--- secondary flags 89 | ;--- bit 0: 1=cluster & size defined 90 | ;--- bit 1: 1=no fat chain 91 | ;--- bit 2-15: custom defined 92 | 93 | EXFDIRS struct 94 | etype db ? ; entry type 95 | secflgs db ? 96 | db 18 dup (?) ; custom defined 97 | dwFirstCl dd ? ; first cluster 98 | dqSize dq ? ; data length 99 | EXFDIRS ends 100 | 101 | ;--- secondary typecodes for files 102 | EXFSTCF_STREAM equ 0 or 0C0h 103 | EXFSTCF_NAME equ 1 or 0C0h 104 | 105 | ;--- stream extension, critical secondary entry in a file directory entry set, 106 | ;--- must immediately follow the primary entry, just 1 in a set. 107 | ;--- typecode is 0. 108 | 109 | EXFDIRSS struct 110 | etype db ? 111 | secflgs db ? 112 | db ? 113 | namelength db ? 114 | namehash dw ? 115 | dw ? 116 | dqValiddatalength dq ? 117 | dd ? 118 | dwFirstCl dd ? 119 | dqSize dq ? 120 | EXFDIRSS ends 121 | 122 | ;--- critical secondary file name direntry 123 | ;--- typecode is 1. 124 | 125 | EXFDIRSN struct 126 | etype db ? 127 | secflgs db ? 128 | name_ dw 15 dup (?) 129 | EXFDIRSN ends 130 | -------------------------------------------------------------------------------- /src/srcnotes.txt: -------------------------------------------------------------------------------- 1 | 2 | ; You might notice "\Fix/" in a few spots; this refers to my having 3 | ; hard-coded 512 bytes for sector sizes, not necessarily a bug. Often 4 | ; I just need to go over the code and make sure it doesn't need to be fixed. 5 | ; 6 | ; for lfn/undelete: 7 | ; if (spot < 33), then a calculation needs to be done to check 8 | ; if it's the first sector of the current cluster or start of the root. 9 | ; for fat32, ((currentsector - datastart % spc) = 0) should be true if 10 | ; at cluster start. checksum needs to be calculated as well. 11 | ; 12 | ; for CD-rom drives/bootsector: 13 | ; offset: 14 | ; 15 | ; 50 (4): total sectors on drive 16 | ; 80 (2): bytes per sector 17 | ; 8C (4): type L path table location 18 | ; 94 (4): type M path table location 19 | ; 9C (-): directory record for root (below) 20 | ; 21 | ; Directory records: 22 | ; 0 (1): length of record 23 | ; 1 (1): extended attribute record length 24 | ; 2 (8): logical block number to entry's data 25 | ; 10 (8): length of file in bytes 26 | ; 18 (7?): recording date/time 27 | ; 25 (1): attributes hidden/directory (______DH) 28 | ; 32 (1): length of file identifier 29 | ; 33+ : file identifier 30 | ; padding field byte at the end if file identifier length = even 31 | ; another byte after this? 32 | ; 33 | ; for NTFS partitions/bootsector: 34 | ; offset: 35 | ; 36 | ; 0B (2): bytes per sector 37 | ; 0D (1): sectors per cluster 38 | ; 0E (1): reserved sectors 39 | ; 10 (5): 0 40 | ; 15 (1): media descriptor (F8h) 41 | ; 16 (2): 0 42 | ; 1C (4): LBA partition start 43 | ; 18 (2): sectors per track 44 | ; 1A (2): # of heads 45 | ; 20 (4): 0 46 | ; 28 (8): total number of sectors 47 | ; 24 (1): drive # (80h) 48 | ; 30 (8): logical cluster for file $MFT 49 | ; 38 (8): logical cluster for file $MFTmirr 50 | ; 40 (4): bytes per file record segment 2^(-1*this value, signed) 51 | ; 44 (4): clusters per index block (ie directories) 52 | ; 50 (4): checksum? 53 | ; 54 | ; MFT: first 16 entries are inaccessible to OS, known as metafiles 55 | ; each entry is ~1k - the first one is the MFT itself. others: 56 | ; 57 | ; calculation in bootsector for bytes per file record is to negate the 58 | ; value (two's complement), then shift the value 1 stored in eax left by 59 | ; that value. eax = 10000000000 = 1024 - why is this needlessly complex? 60 | ; 61 | ; 62 | ; $logfile: list of steps used for file recovery 63 | ; $volume: volume info 64 | ; $attrdef: table of attribute names, numbers & descriptions 65 | ; $: root folder 66 | ; $bitmap: cluster bitmap? 67 | ; $boot: bpb copy? 68 | ; $badclus: bad cluster table 69 | ; $secure: security descriptors for all files 70 | ; $upcase: converts lowercase chars to matching unicode chars 71 | ; $quota: info like quotas, reparse point data, object identifiers? 72 | ; 73 | ; backup bootsector is in the middle of the drive 74 | ; 75 | ; possible future functions: 76 | ; - validcluster: clear/set carry flag depending on whether or not a 77 | ; cluster stored in eax is within the boundaries of the 78 | ; logical partition 79 | ; - validsector: same as above but for sectors 80 | ; 81 | ; Notes for int 24h: 82 | ; 83 | ; AH = device error bits 84 | ; 0: error type 85 | ; 0: read 86 | ; 1: write 87 | ; 88 | ; 1-2: location of error 89 | ; 00: ms-dos area 90 | ; 01: fat table 91 | ; 10: root 92 | ; 11: file area 93 | ; 94 | ; 7: error type 95 | ; 0: char device error 96 | ; 1: block type error 97 | ; 98 | ; 99 | ; if block type error, low byte of DI contains error code: 100 | ; 101 | ; 00: write protection violation 102 | ; 01: unknown drive 103 | ; 02: drive not ready 104 | ; 03: invalid command 105 | ; 04: crc data error 106 | ; 05: length of request struct incorrect 107 | ; 06: seek error 108 | ; 07: unknown media (not formatted) 109 | ; 08: sector not found 110 | ; 0A: write error 111 | ; 0B: read error 112 | ; 0C: general failure 113 | ; 0E: lock violation 114 | ; 0F: disk changed at inappropriate time 115 | ; 10: uncertain media? 116 | ; 11: sharing buffer overflow? 117 | ; 14: insufficient disk space 118 | ; 119 | 120 | ; 121 | ; Notes about diskaccess_internal: 122 | ; Old versions of MS-DOS that do not support FAT32 do not set carry 123 | ; flag when returning from int 21h/ax=7305h to indicate that the function 124 | ; is not supported. 125 | ; 126 | ; New versions of MS-DOS do not return ax=0207h when attempting a read 127 | ; with int 25h on a FAT32 partition as reported by Ralf Browns interrupt 128 | ; list, however, they do set the carry flag. 129 | ; 130 | ; This function can't simply be removed from WDe quite yet, as many 131 | ; assumptions are made about various buffers being filled. 132 | ; 133 | -------------------------------------------------------------------------------- /src/undelete.inc: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------- 2 | ; 3 | ; WDe Copyright(C)2005 Ben Cadieux 4 | ; 5 | ;------------------------------------------------------- 6 | 7 | ;--- entered with spot on a (deleted) directory entry; 8 | ;--- will never get called if file system is exFAT. 9 | ;--- problems: 10 | ;--- 1. only fat1 is updated 11 | ;--- 2. free entries in the FAT are modified, unfree entries 12 | ;--- are skipped. This strategy is not convincing. 13 | ;--- fixed in v0.50: if "used" entries are detected, the 14 | ;--- options are to cancel undelete or truncate the file. 15 | ;--- 3. [fixed in v0.50] if the free clusters in the FAT aren't 16 | ;--- sufficient, the changes aren't undone, leaving 17 | ;--- the FAT in bad shape. 18 | 19 | undelete proc 20 | mov [fromfat], FF_FAT1 21 | call spot2bufofs ; bx = spot + bufofs 22 | and bl, 11100000b ; bx = start directory entry 23 | add bx, offset sectbuffer 24 | mov eax, [bx].SFNENTRY.dwSize 25 | mov [dwFilesize], eax 26 | mov ax, [bx].SFNENTRY.wClHigh ; get start cluster (high 16-bits) 27 | shl eax, 16 28 | mov ax, [bx].SFNENTRY.wClLow ; get start cluster (low 16-bits) 29 | ;--- bounds check 30 | cmp eax, 2 31 | jb invclust ; not a valid cluster if it's below 2 32 | mov [dwCluster], eax 33 | call getfatentry ; what's stored at the start entry? 34 | jc invclust 35 | test eax, eax ; must be 0, else "file too corrupt" 36 | jz undel1good 37 | 38 | ;--- error "File too corrupt" may also occur if one has manually edited the first byte 39 | ;--- of a directory entry to 0E5h. 40 | 41 | mov dx, CStr('File Too Corrupt') 42 | call printerror 43 | ret 44 | invclust: 45 | mov dx, offset invalstartclust ; "invalid start cluster" 46 | call printerror 47 | ret 48 | 49 | undel1good: 50 | mov dx, CStr('New First Character: ') 51 | call printbottom 52 | getkeyagain16: 53 | call cursorgetkey 54 | cmp al, ESCAPE_KEY 55 | je done 56 | call validfileinputchar 57 | jc getkeyagain16 58 | cmp al, 'a' 59 | jb unok1 60 | cmp al, 'z' 61 | ja unok1 62 | sub al, 32 63 | unok1: 64 | ; call spot2bufofs ; should be preserved from above 65 | ; and bl, 11100000b 66 | ; add bx, offset sectbuffer 67 | push ax 68 | ; mov byte ptr [bx], al 69 | 70 | mov dx, CStr('UnDeleting...') 71 | call printbottom 72 | 73 | mov al, 0 74 | call UndeleteCore 75 | pop ax 76 | jc undelete_err1 77 | 78 | mov [bx].SFNENTRY.name_, al 79 | mov eax, [dwFilesize] ; file may have been truncated 80 | mov [bx].SFNENTRY.dwSize, eax 81 | 82 | call writecursect ; rewrite directory sector 83 | 84 | mov dx, CStr('Finished UnDeleting File') 85 | call printerror 86 | done: 87 | ret 88 | undelete_err1: 89 | mov dx, CStr('Undelete aborted') 90 | call printerror 91 | ret 92 | undelete endp 93 | 94 | ;-------------------------------------------------------- 95 | ;--- in: [dwFilesize] - size of file to undelete) 96 | ;--- [dwCluster] - cluster to work from 97 | ;--- 98 | ;--- since v0.50, the FAT scan is done twice: 99 | ;--- First is without updates to the FAT, so if an 100 | ;--- error occurs, nothing is corrupted. 101 | 102 | ;--- UndeleteCore is also called by unformat!!! 103 | ;--- al=0 : called by undelete 104 | ;--- al=1 : called by unformat 105 | 106 | UndeleteCore proc 107 | pushad 108 | mov bp, sp 109 | mov cl, 2 110 | nexttry: 111 | mov edi, [dwFilesize] 112 | mov esi, [dwCluster] 113 | undelLoop: 114 | mov eax, [dwBpC] ; bytes per cluster 115 | mov ebx, esi 116 | cmp edi, eax ; less than bytes per cluster left? 117 | jbe writeeof ; yes, write end of file in 118 | sub edi, eax ; no, subtract bpc 119 | getnextentry: 120 | inc ebx 121 | mov eax, ebx 122 | call getfatentry 123 | jc undelCoreError2 124 | 125 | test eax, eax ; is the entry free? 126 | ; jnz getnextentry ; if no, just get the next????? 127 | jnz undelCoreError 128 | 129 | mov eax, ebx 130 | xchg ebx, esi 131 | cmp cl, 2 132 | jz undelLoop 133 | call putfatentry 134 | jmp undelLoop 135 | writeeof: 136 | dec cl 137 | jnz nexttry 138 | mov eax, 0FFFFFFFh 139 | call putfatentry 140 | exit: 141 | popad 142 | ret 143 | undelCoreError2: 144 | jmp exit 145 | undelCoreError: 146 | 147 | cmp byte ptr [bp+28], 1 ; called by unformat? 148 | jz getnextentry ; then do the old thing: just continue scan 149 | 150 | mov dx, offset sprintfbuffer 151 | mov edx, [dwFilesize] 152 | sub edx, edi 153 | invoke sprintf, dx, CStr("No more free space at offset %lX; T(runcate) or C(ancel)?"), edx 154 | call printbottom 155 | keyloop: 156 | call getkey 157 | or al,20h 158 | cmp al, 't' 159 | jz trunc 160 | cmp al, 'c' 161 | jnz keyloop 162 | stc 163 | jmp exit 164 | trunc: 165 | mov [dwFilesize], edx 166 | jmp writeeof 167 | 168 | UndeleteCore endp 169 | 170 | ;------------------------------------------------------- 171 | -------------------------------------------------------------------------------- /src/sprintf.inc: -------------------------------------------------------------------------------- 1 | 2 | ;--- simple sprintf() implementation 3 | 4 | if ?SN64 or ?GPT 5 | ?SUPPLL equ 1 ; 1=support 64-bit numbers in sprintf 6 | else 7 | ?SUPPLL equ 0 8 | endif 9 | 10 | ?SPRBUFSIZE = 12 11 | 12 | if 1 ; used by exFAT file size rendering 13 | 14 | ?SPRBUFSIZE = 24 15 | 16 | ;--- i64toa(long long n, char * s, int base); 17 | ;--- convert 64-bit long long to string 18 | 19 | i64toa PROC stdcall uses esi edi number:qword, outb:ptr, base:word 20 | 21 | mov ch, 0 22 | movsx edi, base 23 | mov eax, dword ptr number+0 24 | mov esi, dword ptr number+4 25 | cmp edi, -10 26 | jne @F 27 | neg edi 28 | and esi, esi 29 | jns @F 30 | neg esi 31 | neg eax 32 | sbb esi, 0 33 | mov ch, '-' 34 | @@: 35 | mov bx, outb 36 | add bx, 22 37 | mov byte ptr [bx], 0 38 | @@nextdigit: 39 | dec bx 40 | xor edx, edx 41 | xchg eax, esi 42 | div edi 43 | xchg eax, esi 44 | div edi 45 | add dl, '0' 46 | cmp dl, '9' 47 | jbe @F 48 | add dl, 7+20h 49 | @@: 50 | mov [bx], dl 51 | mov edx, eax 52 | or edx, esi 53 | jne @@nextdigit 54 | cmp ch, 0 55 | je @F 56 | dec bx 57 | mov [bx], ch 58 | @@: 59 | mov ax, bx 60 | ret 61 | 62 | i64toa ENDP 63 | 64 | endif 65 | 66 | ;--- ltob(long n, char * s, int base); 67 | ;--- convert long to string 68 | 69 | ltob PROC stdcall uses bx di number:dword, outb:ptr, base:word 70 | 71 | mov ch, 0 72 | movzx edi, base 73 | mov eax, number 74 | cmp di, -10 75 | jne @F 76 | mov di, 10 77 | and eax,eax 78 | jns @F 79 | neg eax 80 | mov ch, '-' 81 | @@: 82 | mov bx, outb 83 | add bx, 10 84 | mov BYTE PTR [bx], 0 85 | dec bx 86 | @@nextdigit: 87 | xor edx, edx 88 | div edi 89 | add dl, '0' 90 | cmp dl, '9' 91 | jbe @F 92 | add dl, 7+20h 93 | @@: 94 | mov [bx], dl 95 | dec bx 96 | and eax, eax 97 | jne @@nextdigit 98 | cmp ch, 0 99 | je @F 100 | mov [bx], ch 101 | dec bx 102 | @@: 103 | inc bx 104 | mov ax, bx 105 | ret 106 | 107 | ltob ENDP 108 | 109 | ;--- ds=ss=dgroup 110 | 111 | sprintf PROC c buffer:ptr byte, fmt:ptr byte, args:VARARG 112 | 113 | local size_:word 114 | local flag:byte 115 | local longarg:byte 116 | local fill:byte 117 | local szTmp[?SPRBUFSIZE]:byte 118 | 119 | pushad 120 | push ds 121 | pop es 122 | lea bx, [fmt+2] 123 | mov di, buffer 124 | reloadfmt: 125 | mov si, [fmt] 126 | nextchar: 127 | lodsb 128 | cmp al, '%' 129 | je formatitem 130 | done: 131 | stosb 132 | or al, al 133 | jne nextchar 134 | popad 135 | ret 136 | 137 | formatitem: 138 | push reloadfmt 139 | mov al, 1 140 | mov cl, ' ' 141 | cmp BYTE PTR [si], '-' 142 | jne @F 143 | mov al, 0 144 | inc si 145 | @@: 146 | mov [flag], al 147 | cmp BYTE PTR [si], '0' 148 | jne @F 149 | mov cl,'0' 150 | inc si 151 | @@: 152 | mov [fill], cl 153 | xor dx, dx 154 | jmp chkdigit 155 | nextdigit: 156 | sub al, '0' 157 | cbw 158 | imul dx, dx, 10 ; dx = dx * 10 159 | add dx, ax 160 | chkdigit: 161 | lodsb 162 | cmp al, '0' 163 | jb @F 164 | cmp al, '9' 165 | jbe nextdigit 166 | @@: 167 | mov [size_], dx 168 | 169 | cmp al, 'l' 170 | sete [longarg] 171 | if ?SUPPLL 172 | jne nol 173 | lodsb 174 | cmp al, 'l' 175 | jne nol 176 | inc [longarg] 177 | inc si 178 | nol: 179 | dec si 180 | else 181 | je @F 182 | dec si 183 | @@: 184 | endif 185 | lodsb 186 | mov [fmt], si 187 | cmp al, 'x' 188 | je handle_x 189 | cmp al, 'X' 190 | je handle_x 191 | cmp al, 'c' 192 | je handle_c 193 | cmp al, 'd' 194 | je handle_d 195 | cmp al, 'i' 196 | je handle_i 197 | cmp al, 's' 198 | je handle_s 199 | cmp al, 'u' 200 | je handle_u 201 | cmp al, 0 202 | jnz storeal 203 | pop cx 204 | jmp done 205 | handle_c: 206 | mov ax, [bx] 207 | add bx, 2 208 | storeal: 209 | stosb 210 | retn 211 | 212 | handle_x: 213 | mov cx, 16 214 | jmp @@lprt262 215 | handle_d: 216 | handle_i: 217 | mov cx, -10 218 | jmp @@lprt262 219 | handle_u: 220 | mov cx, 10 221 | @@lprt262: 222 | mov eax, [bx] 223 | add bx, 4 224 | if ?SUPPLL 225 | dec [longarg] 226 | js is16 227 | jz @F 228 | mov edx, [bx] 229 | add bx, 4 230 | lea si, [szTmp] 231 | invoke i64toa, edx::eax, si, cx 232 | jmp outnum 233 | is16: 234 | else 235 | cmp [longarg], 1 236 | je @F 237 | endif 238 | sub bx, 2 239 | movzx eax, ax 240 | and cx, cx ;signed or unsigned? 241 | jge @F 242 | movsx eax, ax 243 | @@: 244 | lea dx, [szTmp] 245 | invoke ltob, eax, dx, cx 246 | outnum: 247 | mov si, ax 248 | call output_string 249 | retn 250 | 251 | handle_s: 252 | mov si, [bx] 253 | add bx, 2 254 | 255 | output_string: ;display string at si 256 | mov dx, si 257 | mov cx, size_ 258 | @@: 259 | lodsb 260 | cmp al, 0 261 | jnz @B 262 | dec si 263 | sub si, dx 264 | mov al, [fill] 265 | xchg dx, si ;restore si, dx=size of string 266 | sub cx, dx 267 | jnc @F 268 | xor cx, cx 269 | @@: 270 | cmp [flag], 1 271 | jnz @F 272 | rep stosb 273 | @@: 274 | push cx 275 | mov cx, dx 276 | rep movsb 277 | pop cx 278 | rep stosb 279 | retn 280 | 281 | sprintf ENDP 282 | 283 | -------------------------------------------------------------------------------- /src/initpm.inc: -------------------------------------------------------------------------------- 1 | 2 | ;*** startup code to run a small model program as DPMI client 3 | ;*** will try to load HDPMI if no DPMI host is active 4 | 5 | ?LIMITCS equ 1 ; 1=limit CS to real code size 6 | ifndef ?32BIT 7 | ?32BIT equ 1 ; 1=run as 32-bit client 8 | endif 9 | 10 | EXECRM struct 11 | environ dw ? 12 | cmdline dd ? 13 | fcb1 dd ? 14 | fcb2 dd ? 15 | res1 dd ? 16 | res2 dd ? 17 | EXECRM ends 18 | 19 | .const 20 | 21 | szPath db 'PATH=' 22 | 23 | if ?32BIT 24 | szHDPMI db 'HDPMI32.EXE',00 25 | else 26 | szHDPMI db 'HDPMI16.EXE',00 27 | endif 28 | LHDPMI equ $ - szHDPMI 29 | 30 | errNoHost db "no DPMI host found",13,10,'$' 31 | errInit db "DPMI initialization failed",13,10,'$' 32 | 33 | .code 34 | 35 | ;--- DPMI initialization 36 | 37 | initpm proc 38 | 39 | mov ax, 1687h ; DPMI host installed? 40 | int 2fh 41 | and ax, ax 42 | jz @F 43 | call loadserver 44 | mov ax, 1687h ; try again 45 | int 2fh 46 | and ax, ax 47 | jnz nodpmi ; still no host, exit 48 | @@: 49 | push es 50 | push di 51 | and si, si 52 | jz @F 53 | ; alloc memory for dpmi host 54 | mov ah, 48h 55 | mov bx, si 56 | int 21h 57 | jc memerr 58 | mov es, ax 59 | @@: 60 | if ?LIMITCS 61 | mov dx, ds 62 | inc dx ; one paragraph more since start of DGROUP may be within code 63 | mov cx, cs 64 | sub dx, cx 65 | shl dx, 4 66 | dec dx 67 | endif 68 | mov bp, sp 69 | if ?32BIT 70 | mov ax, 1 ; run as 32-bit client 71 | else 72 | xor ax, ax ; run as 16-bit client 73 | endif 74 | call dword ptr [bp] 75 | jc initerr 76 | if ?LIMITCS 77 | mov bx, cs 78 | xor cx, cx 79 | mov ax, 8 80 | int 31h 81 | endif 82 | add sp, 4 83 | ret 84 | 85 | nodpmi: 86 | mov dx, offset errNoHost 87 | jmp errexit 88 | memerr: 89 | initerr: 90 | mov dx, offset errInit 91 | errexit: 92 | mov ah, 9 93 | int 21h 94 | mov ax, 4CFFh 95 | int 21h 96 | initpm endp 97 | 98 | ;*** search and load hdpmixx.exe 99 | 100 | loadserver proc 101 | 102 | local psp:word 103 | local env:word 104 | local cmdline:word 105 | local parmblock:EXECRM 106 | local pgmname[80]:byte 107 | 108 | mov ah, 51h 109 | int 21h 110 | mov psp, bx 111 | mov es, bx 112 | mov ax, es:[002Ch] 113 | mov env, ax 114 | 115 | call searchpath ; search PATH= variable -> SI, SI=0000 if error 116 | call searchpgm ; search HDPMIxx 117 | jb error ; error "not found" 118 | 119 | mov AX, env 120 | mov parmblock.environ, ax 121 | mov cmdline, 0D00h 122 | lea bx, cmdline 123 | mov word ptr parmblock.cmdline+0, bx 124 | mov word ptr parmblock.cmdline+2, ss 125 | mov AX, psp 126 | mov word ptr parmblock.fcb1+0, 5Ch 127 | mov word ptr parmblock.fcb1+2, ax 128 | mov word ptr parmblock.fcb1+0, 6Ch 129 | mov word ptr parmblock.fcb2+2, ax 130 | 131 | push ss 132 | pop es 133 | lea dx, pgmname 134 | lea bx, parmblock 135 | mov ax, 4B00h ; execute dpmi host executable 136 | int 21h 137 | error: 138 | ret 139 | 140 | ;*** search HDPMIxx in current directory and directories of PATH 141 | ;*** Input: SI=address of PATH Variable or NULL (no PATH defined) 142 | ;*** : DI=name of executable (=hdpmixx.exe) 143 | 144 | searchpgm: 145 | push si 146 | mov si, di 147 | lea di, pgmname 148 | push ds 149 | pop es 150 | mov dx, di 151 | push ds 152 | mov ds, env 153 | nxtc: 154 | lodsb 155 | stosb 156 | cmp al, '\' 157 | jnz @F 158 | mov dx, di 159 | @@: 160 | cmp al, 0 161 | jnz nxtc 162 | pop ds 163 | mov di, dx 164 | pop si 165 | mov bl, 0 166 | nexttry: ; <---- 167 | push si 168 | mov si, offset szHDPMI 169 | mov cx, LHDPMI 170 | rep movsb 171 | 172 | lea dx, pgmname 173 | mov ax, 3d00h 174 | int 21h 175 | pop si 176 | jnb hostfound ; found! 177 | and bl, bl 178 | jnz @F 179 | mov bl, 1 180 | lea di, pgmname ; get current directory 181 | jmp nexttry 182 | @@: 183 | and si, si 184 | jz nohost ; PATH isnt defined, so were done 185 | mov di, dx 186 | push ds 187 | mov ds, env 188 | @@: 189 | lodsb 190 | stosb 191 | cmp al, ';' 192 | jz @f 193 | cmp al, 00 194 | jnz @b 195 | xor si, si 196 | @@: 197 | pop ds 198 | dec di 199 | cmp byte ptr es:[di-01], '\' 200 | jz nexttry 201 | mov byte ptr es:[di], '\' 202 | inc di 203 | jmp nexttry 204 | 205 | hostfound: 206 | mov bx, ax 207 | mov ah, 3eh ; close file 208 | int 21h 209 | clc 210 | retn 211 | nohost: 212 | stc 213 | retn 214 | 215 | ;*** search PATH in environment 216 | ;*** Out: SI-> behind "PATH=" or 0000 217 | ;*** DI-> path of executable in environment 218 | 219 | searchpath: 220 | sub di, di 221 | xor dx, dx 222 | mov es, env 223 | nextvar: 224 | mov SI, offset szPath ; "PATH=" 225 | mov cx, 0005 226 | repz cmpsb 227 | jnz @f 228 | mov dx, di 229 | @@: 230 | mov al, 00 231 | or cx, -1 232 | repnz scasb 233 | cmp al, es:[di] 234 | jnz nextvar 235 | add di, 3 ; so DI points to path of executable now 236 | mov si, dx 237 | retn 238 | 239 | loadserver endp 240 | 241 | -------------------------------------------------------------------------------- /compress/compress.asm: -------------------------------------------------------------------------------- 1 | 2 | ;--- compress - a little "bonus" tool for WDe. 3 | ;--- it "compresses" a directory stored in a file by 4 | ;--- removing all "deleted" entries ( first byte == E5h ). 5 | ;--- Public Domain. 6 | 7 | .386 8 | .model flat, c 9 | option casemap:none 10 | 11 | BUFFSIZE equ 256 ;buffer size in kB 12 | 13 | lf equ 10 14 | 15 | CStr macro text:vararg 16 | local sym 17 | .const 18 | sym db text,0 19 | .code 20 | exitm 21 | endm 22 | 23 | ifdef FMTPE 24 | option dotname 25 | .hdr$1 segment use16 26 | % incbin 27 | .hdr$1 ends 28 | .drectve segment info 29 | db "-fixed:no" 30 | .drectve ends 31 | endif 32 | 33 | .data? 34 | 35 | buffer db BUFFSIZE * 1024 dup (?) 36 | 37 | .code 38 | 39 | include printf.inc 40 | 41 | ;--- remove all entries containing E5 at pos 0 42 | ;--- dwItem: # of directory entries 43 | 44 | compress proc uses esi edi pBuffer:ptr, dwItems:dword 45 | 46 | local dwEOD:dword ; "end of directory" ( first dir entry starting with a 00 ) found? 47 | local dwInAcc:dword 48 | 49 | cld 50 | mov dwEOD, -1 51 | mov dwInAcc, 0 52 | mov esi, pBuffer 53 | mov edi, pBuffer 54 | mov ecx, dwItems 55 | xor edx, edx 56 | nextentry: 57 | mov al, [esi] 58 | cmp al, 0E5h 59 | jz skipentry 60 | cmp al, 00 61 | jnz realentry 62 | cmp dwEOD, -1 63 | jnz @F 64 | mov eax, esi ; remember the first 00 entry 65 | sub eax, pBuffer 66 | mov dwEOD, eax 67 | jmp @F 68 | realentry: 69 | cmp dwEOD, -1 70 | jz @F 71 | inc dwInAcc ; count real entries behind first 00 entry 72 | @@: 73 | push ecx 74 | mov ecx, 32/4 75 | rep movsd 76 | pop ecx 77 | loop nextentry 78 | cmp dwInAcc, 0 ; inaccessible entries in file? 79 | jz done ; jump if no 80 | pushad 81 | invoke printf, CStr("%u inaccessible entries found after 00 entry at pos 0x%X)",lf), dwInAcc, dwEOD 82 | popad 83 | jmp done 84 | skipentry: 85 | inc edx 86 | add esi, 32 87 | loop nextentry 88 | done: 89 | and edx, edx 90 | jz @F 91 | mov ecx, edx 92 | shl ecx, 5 93 | xor eax, eax 94 | rep stosd 95 | @@: 96 | ret 97 | compress endp 98 | 99 | ;--- open file 100 | ;--- first try LFN function, then SFN 101 | 102 | openfile proc uses esi edi pszName:ptr 103 | mov esi, pszName 104 | mov cx, 0 ; normal file 105 | mov di, 0 106 | mov dl, 1h ; fail if file not exists 107 | mov dh, 0 108 | mov bx, 2 ; read+write 109 | mov ax, 716Ch ; open file 110 | int 21h 111 | jnc @F 112 | cmp ax, 7100h 113 | stc 114 | jnz @F 115 | mov ax, 6C00h ; try SFN variant 116 | int 21h 117 | @@: 118 | ret 119 | openfile endp 120 | 121 | ;--- set abs/rel file position 122 | 123 | setfilepos proc hFile:dword, dwPos:dword, bType:byte 124 | mov ebx, hFile 125 | mov dx, word ptr dwPos+0 126 | mov cx, word ptr dwPos+2 127 | mov al, bType 128 | mov ah, 42h 129 | int 21h 130 | ret 131 | setfilepos endp 132 | 133 | getfilesize proc hFile:dword 134 | invoke setfilepos, hFile, 0, 2 ; set file pos to EOF 135 | jc @F 136 | push dx ; returns abs position (=size) in DX:AX 137 | push ax 138 | invoke setfilepos, hFile, 0, 0 139 | pop eax 140 | @@: 141 | ret 142 | getfilesize endp 143 | 144 | readfile proc hFile:dword, pBuffer:ptr, dwSize:dword 145 | mov ebx, hFile 146 | mov edx, pBuffer 147 | mov ecx, dwSize 148 | mov ah, 3Fh 149 | int 21h 150 | ret 151 | readfile endp 152 | 153 | writefile proc hFile:dword, pBuffer:ptr, dwSize:dword 154 | mov ebx, hFile 155 | mov edx, pBuffer 156 | mov ecx, dwSize 157 | mov ah, 40h 158 | int 21h 159 | ret 160 | writefile endp 161 | 162 | main proc c argc:dword, argv:ptr ptr 163 | 164 | local hFile:dword 165 | local dwSize:dword 166 | 167 | mov hFile, -1 168 | 169 | mov eax,argc 170 | cmp eax, 2 171 | jb error ; no argument given 172 | mov ebx,argv 173 | @@: 174 | mov esi,[ebx+4] 175 | 176 | invoke openfile, esi 177 | jc openerr 178 | mov hFile, eax 179 | 180 | invoke getfilesize, eax 181 | jc seekerr 182 | mov dwSize, eax 183 | test al, 11111b ; size must be a multiple of 32 184 | jnz invalidfile 185 | cmp eax, sizeof buffer 186 | ja buffertoosmall 187 | 188 | invoke readfile, hFile, offset buffer, dwSize 189 | jc readerr 190 | mov eax, dwSize 191 | shr eax, 5 ; divide by 32 192 | invoke compress, offset buffer, eax 193 | jc exiterr 194 | 195 | invoke setfilepos, hFile, 0, 0 196 | invoke writefile, hFile, offset buffer, dwSize 197 | jc writeerr 198 | invoke printf, CStr("done",lf) 199 | mov al,0 200 | jmp exit 201 | 202 | openerr: 203 | invoke printf, CStr("file '%s' open error [%X]",lf), esi, eax 204 | jmp exiterr 205 | buffertoosmall: 206 | test ax, 3FFh 207 | setnz cl 208 | shr eax, 10 209 | movzx ecx, cl 210 | add eax, ecx 211 | invoke printf, CStr(<"file size (%u kB) exceeds buffer size (%u kB)",lf>), eax, BUFFSIZE 212 | jmp exiterr 213 | invalidfile: 214 | invoke printf, CStr(<"file size not a multiple of 32 (size of a directory entry)",lf>) 215 | jmp exiterr 216 | seekerr: 217 | invoke printf, CStr(<"seek error [%X]",lf>), eax 218 | jmp exiterr 219 | readerr: 220 | invoke printf, CStr(<"read error [%X]",lf>), eax 221 | jmp exiterr 222 | writeerr: 223 | invoke printf, CStr(<"write error [%X]",lf>), eax 224 | jmp exiterr 225 | error: 226 | invoke printf, CStr(<"compress - removes 'deleted' entries of a FAT directory stored in a file.",lf>) 227 | invoke printf, CStr(<"usage: compress filename",lf>) 228 | exiterr: 229 | mov al,1 230 | exit: 231 | call closefiles 232 | ret 233 | 234 | closefiles: 235 | mov ebx,hFile 236 | .if (ebx != -1) 237 | push eax 238 | mov ah,3Eh 239 | int 21h 240 | pop eax 241 | .endif 242 | retn 243 | 244 | main endp 245 | 246 | include setargv.inc 247 | 248 | _start: 249 | call _setargv 250 | invoke main, [_argc], [_argv] 251 | mov ah,4ch 252 | int 21h 253 | 254 | END _start 255 | -------------------------------------------------------------------------------- /src/wdepm.inc: -------------------------------------------------------------------------------- 1 | 2 | ;*** WDe specific protected-mode initialization. 3 | ;--- it's mostly to translate int 13h and int 2fh. 4 | ;--- also, for NTVDM, the LFN functions must be translated. 5 | ;--- translation itself is simple, since WDe runs in 6 | ;--- conventional memory, no copy operations are needed. 7 | 8 | ?TR217302 equ 1 ; 1=translate int 21h, ax=7302h ( for NTVDM only ) 9 | 10 | RMCS struct ; dpmi real-mode call struct 11 | rDI dw ?,? 12 | rSI dw ?,? 13 | rBP dw ?,? 14 | rRes dw ?,? 15 | rBX dw ?,? 16 | rDX dw ?,? 17 | rCX dw ?,? 18 | rAX dw ?,? 19 | rFlags dw ? 20 | rES dw ? 21 | rDS dw ? 22 | rFS dw ? 23 | rGS dw ? 24 | rCSIP dd ? 25 | rSSSP dd ? 26 | RMCS ends 27 | 28 | if ?32BIT 29 | 30 | .486 ; make jwasm/masm avoid to generate LEAVE in procs with locals 31 | 32 | IRETS struct ; IRETD struct on stack in INT 33 | wIP dd ? 34 | wCS dd ? 35 | wFlags dd ? 36 | IRETS ends 37 | 38 | @fp equ 39 | @iret equ 40 | 41 | @movr macro dst, src 42 | mov e&dst, e&src 43 | endm 44 | @storevec macro addr 45 | mov dword ptr addr[0], edx 46 | mov word ptr addr[4], cx 47 | endm 48 | @loadvec macro addr 49 | mov edx, dword ptr addr[0] 50 | mov cx, word ptr addr[4] 51 | endm 52 | @movofs macro dst, src 53 | mov e&dst, src 54 | endm 55 | 56 | else 57 | 58 | IRETS struct ; IRETW struct on stack in INT 59 | wIP dw ? 60 | wCS dw ? 61 | wFlags dw ? 62 | IRETS ends 63 | 64 | @fp equ
65 | @iret equ 66 | 67 | @movr macro dst, src 68 | mov dst, src 69 | endm 70 | @storevec macro addr 71 | mov word ptr addr[0], dx 72 | mov word ptr addr[2], cx 73 | endm 74 | @loadvec macro addr 75 | mov dx, word ptr addr[0] 76 | mov cx, word ptr addr[2] 77 | endm 78 | @movofs macro dst, src 79 | mov dst, src 80 | endm 81 | 82 | endif 83 | 84 | 85 | .data 86 | 87 | oldint13 @fp 0 88 | oldint2f @fp 0 89 | oldint21 @fp 0 90 | 91 | .code 92 | 93 | ;--- int 13h interception. 94 | ;--- There's usually no translation for extended int 13h in DPMI hosts. 95 | ;--- ah=42h/43h have a far16 buffer address in their "request package" 96 | ;--- that must be converted. Since WDE runs in small memory model, 97 | ;--- there's only one data segment: DGROUP. 98 | 99 | myint13 proc 100 | cmp ah, 42h 101 | jz is42 102 | cmp ah, 43h 103 | jz is43 104 | cmp ah, 48h 105 | jz is48 106 | jmp [oldint13] 107 | is42: 108 | is43: 109 | mov [si].DAP.wBufferSeg, DGROUP ; set segment of transfer buffer 110 | is48: 111 | pushd 0 112 | sub sp, sizeof RMCS-(32+4+2) 113 | pushf 114 | pushad 115 | @movr di, sp 116 | push ss 117 | pop es 118 | mov [di].RMCS.rDS, DGROUP ; request ptr is in DS:SI 119 | push ax 120 | mov bx, 0013h 121 | xor cx, cx 122 | mov ax, 0300h 123 | int 31h 124 | pop ax 125 | cmp ah, 48h 126 | jz @F 127 | mov [si].DAP.wBufferSeg, ds ; restore transfer buffer (for 42/43) 128 | @@: 129 | mov al, byte ptr [di].RMCS.rFlags 130 | mov byte ptr [di+sizeof RMCS].IRETS.wFlags, al 131 | popad 132 | add sp, sizeof RMCS-32 133 | @iret 134 | myint13 endp 135 | 136 | ;--- int 21h interception 137 | 138 | myint21 proc 139 | cmp ax, 7305h 140 | jz is7305 141 | if ?LFN 142 | cmp ah, 71h 143 | jz is71 144 | endif 145 | if ?TR217302 146 | cmp ax, 7302h 147 | jz is7302 148 | endif 149 | if ?32BIT 150 | cmp ah, 4Ch 151 | jnz is71 152 | endif 153 | jmp [oldint21] 154 | is7305: 155 | mov [bx].DISKIO.buffseg, DGROUP ; set segment of buffer 156 | is71: 157 | is7302: 158 | pushd 0 159 | sub sp, sizeof RMCS - (32+4+2) 160 | pushf 161 | pushad 162 | @movr di, sp 163 | push ss 164 | pop es 165 | mov [di].RMCS.rES, DGROUP 166 | mov [di].RMCS.rDS, DGROUP 167 | mov bx, 0021h 168 | xor cx, cx 169 | push ax 170 | mov ax, 0300h 171 | int 31h 172 | mov al, byte ptr [di].RMCS.rFlags 173 | mov byte ptr [di+sizeof RMCS].IRETS.wFlags, al 174 | pop ax 175 | cmp ax, 7305h 176 | popad 177 | jnz @F 178 | mov [bx].DISKIO.buffseg, ds 179 | @@: 180 | add sp, sizeof RMCS-32 181 | @iret 182 | myint21 endp 183 | 184 | ;--- translate int 2Fh, ax=1510h (CD-ROM access) 185 | ;--- here also the segment part of the transfer buffer is to be set. 186 | 187 | myint2f proc 188 | cmp ax, 1510h 189 | jz is1510 190 | jmp [oldint2f] 191 | is1510: 192 | mov [bx].CDREQ.bufseg, DGROUP ; set transfer buffer segment part 193 | pushd 0 194 | sub sp, sizeof RMCS-(32+4+2) 195 | pushf 196 | pushad 197 | @movr di, sp 198 | push ss 199 | pop es 200 | mov [di].RMCS.rES, DGROUP 201 | mov bx, 002Fh 202 | xor cx, cx 203 | mov ax, 0300h 204 | int 31h 205 | mov al, byte ptr [di].RMCS.rFlags 206 | mov byte ptr [di+sizeof RMCS].IRETS.wFlags, al 207 | popad 208 | add sp, sizeof RMCS-32 209 | mov [bx].CDREQ.bufseg, ds ; restore selector of transfer buffer 210 | @iret 211 | myint2f endp 212 | 213 | ;--- alloc descriptors for _0000H and vidseg 214 | 215 | getdescriptors proc 216 | 217 | mov cx, 2 ; alloc 2 descriptors 218 | xor ax, ax 219 | int 31h 220 | jc done 221 | mov _0000H, ax 222 | mov bx, ax ; set bases ( 00000000h, 000Bx000h ) 223 | xor dx, dx 224 | xor cx, cx 225 | mov ax, 7 226 | int 31h 227 | mov dx, 7fffh ; set limits to 07FFFh 228 | xor cx, cx 229 | mov ax, 8 230 | int 31h 231 | add bx, 8 232 | mov word ptr [vidaddr+2], bx ; base will be set later 233 | mov ax, 8 234 | int 31h 235 | done: 236 | ret 237 | getdescriptors endp 238 | 239 | ;--- WDe protected-mode init 240 | ;--- in: DS=SS=DGROUP, ES=PSP, CS=_TEXT 241 | 242 | initwdepm proc 243 | mov [_psp], es ; update PSP to a selector 244 | call getdescriptors ; get descriptors for _0000H & vidseg 245 | jc error 246 | if ?VDD 247 | cmp [hVdd], -1 ; wdevdd.dll can handle protected-mode 248 | jnz skip132f 249 | endif 250 | mov bl, 13h ; intercept int 13h 251 | mov ax, 204h 252 | int 31h 253 | @storevec [oldint13] 254 | mov cx, cs 255 | @movofs dx, myint13 256 | mov al, 5 257 | int 31h 258 | 259 | mov bl, 2Fh ; intercept int 2Fh 260 | mov al, 4 261 | int 31h 262 | @storevec [oldint2f] 263 | mov cx, cs 264 | @movofs dx, myint2f 265 | mov al, 5 266 | int 31h 267 | skip132f: 268 | mov bl, 21h ; intercept int 21h 269 | mov ax, 204h 270 | int 31h 271 | @storevec [oldint21] 272 | mov cx, cs 273 | @movofs dx, myint21 274 | mov al, 5 275 | int 31h 276 | done: 277 | ret 278 | error: 279 | mov ax,4cffh 280 | int 21h 281 | initwdepm endp 282 | 283 | exitwdepm proc 284 | mov bl, 13h 285 | @loadvec [oldint13] 286 | mov ax, 205h 287 | int 31h 288 | mov bl, 21h 289 | @loadvec [oldint21] 290 | int 31h 291 | mov bl, 2Fh 292 | @loadvec [oldint2f] 293 | int 31h 294 | ret 295 | exitwdepm endp 296 | 297 | -------------------------------------------------------------------------------- /src/getstrng.inc: -------------------------------------------------------------------------------- 1 | 2 | ;--- reads in a string from keyboard 3 | 4 | GS_ESCAPE equ 1 5 | GS_EXIT equ 2 6 | 7 | CSRPOS struct 8 | col db ? 9 | row db ? 10 | CSRPOS ends 11 | 12 | VPAGE equ <[vidpg]> 13 | 14 | .code 15 | 16 | getkbdstatus proc 17 | push ds 18 | push _0000H 19 | pop ds 20 | mov ah, ds:[417h] 21 | pop ds 22 | ret 23 | getkbdstatus endp 24 | 25 | ;--- pBuffer: buffer for string to store 26 | ;--- wSizeBuf: size of buffer 27 | ;--- wCursor: cursor offset on entry; -1 = no positioning 28 | ;--- wChars: max chars to display 29 | ;--- out: ax = chars in buffer 30 | ;--- dx = current cursor offset 31 | 32 | getstring proc stdcall uses bx si di pBuffer:ptr, wSizeBuf:word, wCursor:word, wChars:word, tabproc:ptr 33 | 34 | local flags:word ; bool: escape (terminate without update) 35 | local strsta:word ; string start offset 36 | local lastkey:word 37 | local csrsta:CSRPOS ; start cursor position 38 | 39 | mov cx, wSizeBuf 40 | sub sp, cx 41 | mov di, sp ; copy string to edit in temp buffer 42 | mov strsta, di 43 | mov si, pBuffer 44 | push ds 45 | pop es 46 | @@: 47 | lodsb 48 | stosb 49 | and al, al 50 | loopnz @B 51 | 52 | xor cx, cx 53 | mov flags, cx 54 | mov di, sp 55 | mov si, di 56 | 57 | mov cx, wSizeBuf 58 | mov ax, wCursor 59 | add di, ax ; DI=current pointer 60 | sub cx, ax ; CX=wSizeBuf - cursor 61 | jbe strex ; C if cursor beyond string len 62 | 63 | mov dx, [scrn_xy] 64 | cmp ax, wChars ; cursor beyond display window? 65 | jb @F 66 | sub ax, wChars 67 | add si, ax 68 | mov ax, wChars 69 | dec al ; leave room for 1 char 70 | @@: 71 | sub dl, al 72 | mov [csrsta], dx ; start screen pos for str_out 73 | 74 | wingx: ; <---- get next key 75 | 76 | ;--- check if di - si is < wChars 77 | ;--- if no, adjust si : 78 | 79 | mov dx, wChars 80 | mov ax, di ; current offset -> ax 81 | sub ax, si 82 | jnc @F 83 | mov si, di 84 | xor ax, ax 85 | @@: 86 | cmp ax, dx 87 | jb @F 88 | mov si, di 89 | sub si, dx 90 | inc si 91 | @@: 92 | push [csrsta] 93 | pop [scrn_xy] 94 | call str_out ; display string 95 | 96 | mov ax, di 97 | sub ax, si 98 | mov dx, [csrsta] 99 | add dl, al 100 | mov [scrn_xy], dx 101 | call cursorgetkey 102 | 103 | mov dx, ax 104 | mov lastkey, ax 105 | mov ah,byte ptr lastkey+1 ; scancode is in bits 8-15 106 | call chkctl 107 | xor ax, ax ; exit "no chars entered" 108 | test byte ptr flags, GS_ESCAPE ; escape pressed? 109 | jnz str_1 110 | test byte ptr flags, GS_EXIT 111 | jz wingx ; get next key 112 | push ds 113 | pop es 114 | mov si, strsta 115 | mov di, pBuffer 116 | @@: 117 | lodsb 118 | stosb 119 | and al,al 120 | jnz @B 121 | mov ax, di 122 | dec ax 123 | sub ax, pBuffer 124 | str_1: 125 | add sp, wSizeBuf 126 | strex: 127 | mov dx, wSizeBuf 128 | sub dx, cx 129 | ret 130 | 131 | chkctl: 132 | and al, al ; ctrl key? 133 | jz chkctl2 134 | cmp al, 0E0h 135 | jz chkctl2 136 | cmp al, 8 ; BS? 137 | jnz @F 138 | call bsv 139 | retn 140 | smexit: 141 | or byte ptr flags, GS_EXIT 142 | retn 143 | @@: 144 | cmp al, 09 ; TAB? 145 | jz handle_tab 146 | cmp al, 13 147 | jz smexit 148 | cmp al, 10 149 | jz smexit 150 | cmp al, 1bh ; ESC? 151 | jnz @F 152 | or byte ptr flags, GS_ESCAPE 153 | retn 154 | @@: 155 | cmp al,20h ; exit on all ctrl codes? 156 | jb _ret ; smexit ; no! 157 | 158 | call getkbdstatus 159 | test ah, 80h 160 | jz @F 161 | call insert 162 | and al, al 163 | jnz chkm3 164 | retn 165 | @@: 166 | mov ah, [di] 167 | mov [di], al 168 | and ah, ah ; was cursor at eol? 169 | jnz @F 170 | cmp cx, 2 171 | jb @F 172 | mov byte ptr [di+1], 0 ; mark new eol 173 | @@: 174 | chkm3: 175 | inc di ; "cursor" right 176 | dec cx 177 | cmp cx, 1 ; end reached? 178 | ja @F 179 | call ringbell 180 | dec di 181 | inc cx 182 | @@: 183 | retn 184 | 185 | handle_tab: 186 | ;--- tabproc is called with ax=strsta, di=curpos, cx=remaining 187 | mov ax, strsta 188 | call tabproc 189 | jc smexit 190 | and ax, ax 191 | jnz _ret 192 | push [csrsta] 193 | pop [scrn_xy] 194 | if 1 195 | mov cl, MAXCOL 196 | sub cl, [scrn_xy.col] 197 | mov al, SPACE 198 | call fillchar 199 | endif 200 | mov di, strsta ; set cursor to pos 0 201 | mov cx, wSizeBuf 202 | mov si, di 203 | retn 204 | 205 | chkctl2: ; ctrl key entered ( ascii 00 or 0E0 ) 206 | mov bx, offset ctlkeytab 207 | mov dl, lctlkeytab 208 | @@: 209 | cmp ah, cs:[bx] 210 | jz ctlfound 211 | inc bx 212 | dec dl 213 | jnz @B 214 | retn 215 | ctlfound: 216 | sub bx, offset ctlkeytab 217 | shl bx, 1 218 | jmp word ptr cs:[bx+ctlkeyjmptab] 219 | 220 | ctlkeytab label byte 221 | db CSRLEFT_KEY 222 | db HOME_KEY 223 | db END_KEY 224 | db CSRRIGHT_KEY 225 | db DEL_KEY 226 | lctlkeytab equ $ - ctlkeytab 227 | 228 | align 2 229 | 230 | ctlkeyjmptab label word 231 | dw offset cursleft 232 | dw offset curshome 233 | dw offset cursend 234 | dw offset cursright 235 | dw offset delkey 236 | 237 | ;*** subroutines (ctrl keys) 238 | 239 | curshome: 240 | call cursleft 241 | jnz curshome 242 | _ret: 243 | retn 244 | cursend: 245 | call cursright 246 | jnc cursend 247 | retn 248 | 249 | ;--- parms: cx=remainder length 250 | ;--- si -> string 251 | 252 | str_out: 253 | pusha 254 | mov cx, wChars 255 | @@: 256 | lodsb 257 | and al, al 258 | jz @F 259 | mov dl, al 260 | call printchar 261 | loop @B 262 | @@: 263 | mov dl, ' ' 264 | call printchar 265 | popa 266 | retn 267 | 268 | cursleft: 269 | cmp cx, wSizeBuf 270 | jz _ret 271 | inc cx 272 | dec di 273 | retn 274 | 275 | cursright: 276 | cmp cx, 2 277 | jna @F 278 | cmp byte ptr [di], 00 279 | jz @F 280 | dec cx 281 | inc di 282 | retn 283 | @@: 284 | stc 285 | retn 286 | 287 | delkey: 288 | cmp byte ptr [di], 00 289 | jz _ret 290 | inc di 291 | jmp bsv3 292 | 293 | bsv: ; handle backspace 294 | cmp cx, wSizeBuf 295 | jz _ret ; cursor at start? 296 | inc cx 297 | mov ax, di 298 | dec ax 299 | bsv3: 300 | push si 301 | mov si, di 302 | dec di 303 | push di 304 | push ds 305 | pop es 306 | @@: 307 | lodsb 308 | stosb 309 | and al, al 310 | jnz @B 311 | pop di 312 | pop si 313 | retn 314 | 315 | insert: ; insert mode 316 | push ax 317 | push di 318 | mov dx, cx 319 | push ds 320 | pop es 321 | 322 | mov cx,-1 323 | xor al,al 324 | repnz scasb 325 | neg cx 326 | dec cx 327 | mov ax, dx 328 | sub ax, wSizeBuf 329 | neg ax 330 | add ax, cx 331 | cmp ax, wSizeBuf 332 | jnb ins1 333 | 334 | push si 335 | mov si, di 336 | dec si 337 | std 338 | rep movsb ; make room 339 | cld 340 | mov cx, dx 341 | pop si 342 | 343 | pop di 344 | pop ax 345 | mov [di],al 346 | mov al,-1 347 | retn 348 | ins1: ; error insert 349 | mov cx, dx ; restore CX 350 | push cx 351 | call ringbell 352 | pop cx 353 | pop di 354 | pop ax 355 | xor al,al 356 | retn 357 | 358 | ringbell: 359 | mov ax, 0e07h 360 | int 10 361 | retn 362 | 363 | getstring endp 364 | 365 | -------------------------------------------------------------------------------- /src/SETM432.ASM: -------------------------------------------------------------------------------- 1 | 2 | ;--- this tool sets 100x43 lines text mode 3 | ;--- how is this done? 4 | ;--- 1. set vesa gfx mode 0x102 (800x600x4) 5 | ;--- 2. change some CRT registers (max scan line, cursor start/end, mode control) 6 | ;--- 3. change some sequencer registers (set odd/even mode) 7 | ;--- 4. change some graphics controller registers (set odd/even mode, text mode, ...) 8 | ;--- 5. change some attribute controller registers 9 | ;--- 6. load VGA ROM font 14x8 into plane 2 10 | 11 | ;--- possible problems: 12 | ;--- VESA mode 0x102 not supported 13 | ;--- mouse driver doesn't expect a non-80 columns resolution 14 | ;--- when running in a DOS Box, windows might not be able to save/restore video settings 15 | 16 | .286 17 | .model small,stdcall 18 | 19 | ROWS equ 43 ;600/14 ( actually, 43*14 is 430+172=602 ) 20 | ?DRIVER equ 1 ;insert code to generate a DOS driver + .EXE 21 | 22 | .stack 200h 23 | .code 24 | 25 | ASSUME DS: _TEXT 26 | 27 | if ?DRIVER 28 | 29 | IODAT struct ;structure for dos device drivers 30 | cmdlen db ? 31 | unit db ? 32 | cmd db ? 33 | status dw ? 34 | db 8 dup (?) 35 | media db ? 36 | trans dd ? 37 | count dw ? 38 | start dw ? 39 | drive db ? 40 | IODAT ends 41 | 42 | dw 0ffffh 43 | dw 0ffffh 44 | dw 8000h ;attribute 45 | dw offset devstrat ;device strategy 46 | dw offset devint ;device interrupt 47 | db 'SETM37$1' ;device name 8 chars (use carefully) 48 | 49 | saveptr dd 1 dup(?) 50 | 51 | devstrat proc far 52 | mov cs:word ptr[saveptr],bx 53 | mov cs:word ptr[saveptr+2],es 54 | ret 55 | devstrat endp 56 | 57 | devint proc far 58 | pusha 59 | push ds 60 | push es 61 | lds bx,cs:[saveptr] 62 | mov [bx.IODAT.status],8103h 63 | cmp [bx.IODAT.cmd],00 64 | jnz devi1 65 | mov [bx.IODAT.status],0100h 66 | mov word ptr [bx+0eh],0000 67 | mov word ptr [bx+10h],cs 68 | xor dx,dx 69 | call main 70 | devi1: 71 | pop ds 72 | pop es 73 | popa 74 | ret 75 | devint endp 76 | 77 | endif 78 | 79 | ;--- clear write protection for CRT register 0-7 80 | 81 | disablewp proc 82 | mov al,11h ;vertikal retrace end register bit 7 reset 83 | out dx,al 84 | inc dx 85 | in al,dx 86 | and al,7fh 87 | out dx,al 88 | dec dx 89 | ret 90 | disablewp endp 91 | 92 | ;--- restore write protection for CRT register 0-7 93 | 94 | enablewp proc 95 | mov al,11h 96 | out dx,al 97 | inc dx 98 | in al,dx 99 | or al,80h 100 | out dx,al 101 | dec dx 102 | ret 103 | enablewp endp 104 | 105 | ;--- get input status register 1 106 | 107 | getinpst1 proc 108 | mov dx,3cch 109 | in al,dx 110 | mov dx,3dah 111 | test al,1 112 | jnz @F 113 | mov dx,3bah 114 | @@: 115 | ret 116 | getinpst1 endp 117 | 118 | ;--- clear text screen 119 | 120 | clearscreen proc uses ds 121 | push 40h 122 | pop ds 123 | mov dx,0b800h 124 | mov ax,ds:[63h] 125 | cmp ax,3d4h 126 | jz @F 127 | mov dh,0b0h 128 | @@: 129 | mov es,dx 130 | mov di,ds:[4eh] 131 | mov cx,ds:[4ch] 132 | shr cx,1 133 | mov ax,0720h 134 | rep stosw 135 | mov bh,ds:[62h] 136 | mov ah,02 137 | mov dx,0000 138 | int 10h 139 | ret 140 | clearscreen endp 141 | 142 | ;--- set a plane to read/write 143 | 144 | setplane0: 145 | mov ah,0 146 | jmp setplane 147 | setplane1: 148 | mov ah,1 149 | jmp setplane 150 | setplane2: 151 | mov ah,2 152 | setplane:: 153 | mov cl,ah 154 | mov dx,3ceh 155 | mov al,4 ;"read map select" 156 | out dx,ax 157 | mov dx,3c4h 158 | mov ah,1 159 | shl ah,cl 160 | mov al,2 ;"map mask" register:select map to write to 161 | out dx,ax 162 | ret 163 | 164 | ;--- setevenmode: changes dx, ax 165 | ;--- sets register: 3CE: 1, 5, 6, 8 166 | ;--- sets register: 3C4: 4 167 | 168 | setevenmode proc 169 | mov dx,3ceh 170 | mov ax,1 ;"enable set/reset" register 171 | out dx,ax 172 | 173 | mov al,5 ;"graphics mode" register 174 | out dx,al 175 | inc dx 176 | in al,dx 177 | and al,084h ;reset "odd/even mode", set "read mode 0" 178 | out dx,al ;set "write mode" 0 179 | 180 | mov dx,3ceh 181 | mov al,6 ;"miscellaneous" register 182 | out dx,al 183 | inc dx 184 | in al,dx 185 | and al,0F0h ;reset "odd/even" 186 | or al,1+4+8 ;set addr=B800h,32K, graphics mode 187 | out dx,al 188 | 189 | mov dx,3ceh 190 | mov al,8 ;"bit mask" register: all bits to change 191 | mov ah,0FFh 192 | out dx,ax 193 | 194 | mov dl,0c4h 195 | mov al,4 196 | out dx,al 197 | inc dx 198 | in al,dx 199 | and al,not 8 ;reset "chain 4" 200 | or al,4+2 ;set odd/even=4, set extended memory=2 201 | out dx,al 202 | ret 203 | setevenmode endp 204 | 205 | ;--- table of values to save/restore 206 | 207 | savetab label word 208 | dw 3CEh 209 | db 4,5,6,8,-1 210 | dw 3C4h 211 | db 2,4,-1 212 | dw -1 213 | 214 | ;--- save regs of graphics controller + sequencer 215 | 216 | saveregs proc 217 | push ss 218 | pop es 219 | mov si,offset savetab 220 | devdone: 221 | lodsw 222 | cmp ax,-1 223 | jz done 224 | mov dx,ax 225 | nextindex: 226 | lodsb 227 | cmp al,-1 228 | jz devdone 229 | out dx,al 230 | inc dx 231 | in al,dx 232 | stosb 233 | dec dx 234 | jmp nextindex 235 | done: 236 | ret 237 | saveregs endp 238 | 239 | ;--- restore regs of graphics controller + sequencer 240 | 241 | restregs proc 242 | 243 | mov bx,si 244 | mov si,offset savetab 245 | devdone: 246 | lodsw 247 | cmp ax,-1 248 | jz done 249 | mov dx,ax 250 | nextindex: 251 | lodsb 252 | cmp al,-1 253 | jz devdone 254 | mov ah,ss:[bx] 255 | inc bx 256 | out dx,ax 257 | jmp nextindex 258 | done: 259 | ret 260 | restregs endp 261 | 262 | ;--- load a 14 pixel font (256 * 32 == 8 kB) 263 | 264 | LoadFontInPlane2 proc stdcall uses si di dwFnt:dword 265 | 266 | local savebuff[12]:byte 267 | 268 | cld 269 | lea di,savebuff 270 | call saveregs 271 | 272 | call setevenmode 273 | 274 | call setplane2 275 | mov ax,0B800h 276 | mov es,ax 277 | mov di,0000h ;use charset 0 278 | mov dl,00h 279 | mov dh,14 ;char size 280 | push ds 281 | lds si,[dwFnt] 282 | mov ch,0 283 | nextchar: 284 | mov cl,dh 285 | lea bx, [di+20h] 286 | rep movsb 287 | mov di, bx 288 | inc dl 289 | jnz nextchar 290 | pop ds 291 | lea si,savebuff 292 | call restregs 293 | ret 294 | LoadFontInPlane2 endp 295 | 296 | main proc c 297 | 298 | local bFlags:word 299 | local dwFnt14:dword 300 | 301 | mov bFlags,dx 302 | push cs 303 | pop ds 304 | assume ds:_TEXT 305 | 306 | push bp 307 | mov ax,1130h ;get ROM VGA font (14 pixel) 308 | mov bh,2 309 | int 10h 310 | mov dx,bp 311 | pop bp 312 | mov word ptr [dwFnt14+0],dx 313 | mov word ptr [dwFnt14+2],es 314 | 315 | ;--- set vesa gfx mode 102h (800x600x4) 316 | 317 | mov ax,4F02h 318 | mov bx,102h 319 | int 10h 320 | cmp ax,004Fh 321 | jz @F 322 | 323 | mov ax,4F02h 324 | mov bx,6Ah ; or try the old "supervga" mode 325 | int 10h 326 | cmp ax,004Fh 327 | jnz notsupported 328 | @@: 329 | 330 | ;--- set BIOS variables to match the new resolution 331 | 332 | push 0 333 | pop es 334 | mov byte ptr es:[449h],3 ;video mode 335 | mov word ptr es:[44Eh],0 ;page start 336 | mov word ptr es:[460h],0C0Dh ;cursor form 337 | and byte ptr es:[465h],0fdh ;reset bit 1 ("graphics" mode) 338 | or byte ptr es:[465h],1 ;set bit 0 ("text" mode) 339 | mov byte ptr es:[484h],ROWS-1 ;max line# 340 | mov byte ptr es:[485h],14 ;scan lines 341 | mov al,es:[044Ah] ;columns 342 | mov cl,ROWS*2 343 | mul cl 344 | mov word ptr es:[44ch],ax ;page size (ROWS * CULUMNS * size WORD) 345 | 346 | ;--- reprogram CRT controller 347 | 348 | cli 349 | mov dx,es:[463h] ;get crt address 350 | call disablewp 351 | 352 | test bFlags,2 353 | jz @F 354 | mov ax,4F01h ; set display end to 79 355 | out dx,ax 356 | @@: 357 | mov al,9 358 | out dx,al 359 | inc dx 360 | in al,dx 361 | and al,0E0h ;clear bits 0-4 362 | or al,0Dh ;set max scan line to 14-1 363 | out dx,al 364 | dec dx 365 | 366 | mov ax,0C0Ah ;set cursor start/end 367 | out dx,ax 368 | mov ax,0D0Bh 369 | out dx,ax 370 | 371 | mov ax,5C10h ;vertical retrace end at line 602 372 | out dx,ax 373 | mov ax,5912h ;vertical display end at line 601 374 | out dx,ax 375 | mov ax,5915h ;vertical blank start end at line 601 376 | out dx,ax 377 | 378 | mov al,17h ;mode control register 379 | out dx,al 380 | inc dx 381 | in al,dx 382 | and al,not 40h ;set byte mode 383 | out dx,al 384 | dec dx 385 | 386 | call enablewp 387 | 388 | ;--- write sequencer 389 | 390 | ;--- make planes 2+3 write protected 391 | mov dx,3c4h 392 | mov al,2 393 | mov ah,3 394 | out dx,ax 395 | 396 | ;--- set odd/even mode, reset chain 4, more than 64 kB 397 | mov dx,3c4h 398 | mov al,4 399 | mov ah,2 400 | out dx,ax 401 | 402 | ;--- write graphics controller 403 | 404 | mov dx,3ceh 405 | mov ax,1005h ;set write mode 0, read mode 0, odd/even addressing 406 | out dx,ax 407 | 408 | mov dx,3ceh 409 | mov al,6 410 | out dx,al 411 | inc dx 412 | in al,dx 413 | and al,0F0h 414 | or al,0Eh ;set B800h as base, set text mode, set odd/even 415 | out dx,al 416 | 417 | ;--- write attribute controller 418 | 419 | call getinpst1 420 | in al,dx ;reset attribute controller 421 | mov dx,3c0h 422 | 423 | mov al,10h ;select mode register 424 | out dx,al 425 | mov al,0 ;set text mode [bit 0=0] 426 | out dx,al 427 | 428 | mov al,20h ;turn screen on again 429 | out dx,al 430 | 431 | push word ptr [dwFnt14+2] 432 | push word ptr [dwFnt14+0] 433 | call LoadFontinPlane2 434 | 435 | sti 436 | 437 | .if (bFlags & 1) 438 | call clearscreen 439 | .else 440 | push 40h 441 | pop ds 442 | mov cx,ds:[4Ch] 443 | mov si,ds:[4Eh] 444 | mov ax,0B800h 445 | cmp byte ptr ds:[63h],0D4h 446 | jz @F 447 | mov ax,0B000h 448 | @@: 449 | shr cx,1 450 | mov ds,ax 451 | nextchar: 452 | lodsw 453 | cmp ah,0 454 | jnz @F 455 | mov ax,0720h 456 | mov [si-2],ax 457 | @@: 458 | loop nextchar 459 | .endif 460 | notsupported: 461 | mov al,00 462 | ret 463 | main endp 464 | 465 | 466 | start: 467 | ;--- get cmdline parameter 468 | 469 | mov bx,80h 470 | mov cl,es:[bx] 471 | inc bx 472 | xor ax,ax 473 | xor dx,dx 474 | .while (cl) 475 | mov ah,al 476 | mov al,es:[bx] 477 | or al,20h 478 | .if ((ah == '/') || (ah == '-')) 479 | .if (al == 'c') 480 | or dl,1 481 | .elseif (al == '8') 482 | or dl,2 483 | .elseif (al == '?') 484 | push cs 485 | pop ds 486 | mov dx,offset help 487 | mov ah,9 488 | int 21h 489 | jmp exit 490 | .endif 491 | .endif 492 | inc bx 493 | dec cl 494 | .endw 495 | call main 496 | exit: 497 | mov ah,4ch 498 | int 21h 499 | 500 | help db "usage: SETM43 [option]",13,10 501 | db "option: -c clear screen",13,10 502 | db " -8 set display end to 80 chars",13,10,'$' 503 | db " -? this text",13,10,'$' 504 | 505 | END start 506 | -------------------------------------------------------------------------------- /src/SETM43.ASM: -------------------------------------------------------------------------------- 1 | 2 | ;--- this tool sets 100x43 lines text mode 3 | ;--- how is this done? 4 | ;--- 1. set vesa gfx mode 0x102 (800x600x4) 5 | ;--- 2. change some CRT registers (max scan line, cursor start/end, mode control) 6 | ;--- 3. change some sequencer registers (set odd/even mode) 7 | ;--- 4. change some graphics controller registers (set odd/even mode, text mode, ...) 8 | ;--- 5. change some attribute controller registers 9 | ;--- 6. load VGA ROM font 14x8 into plane 2 10 | 11 | ;--- possible problems: 12 | ;--- VESA mode 0x102 not supported 13 | ;--- mouse driver doesn't expect a non-80 columns resolution 14 | ;--- when running in a DOS Box, windows might not be able to save/restore video settings 15 | 16 | ;--- to create the binary, run: jwasm -mz setm43.asm 17 | 18 | .286 19 | .model small,stdcall 20 | 21 | ROWS equ 43 ; 600/14 ( actually, 43*14 is 602 ) 22 | ?DRIVER equ 1 ; insert code to generate a DOS driver + .EXE 23 | ?DIRECTCRT equ 1 ; 0=use BIOS to enable/disable write access to CRT 24 | 25 | .stack 200h 26 | .code 27 | 28 | ASSUME DS: _TEXT 29 | 30 | if ?DRIVER 31 | 32 | IODAT struct ;structure for dos device drivers 33 | cmdlen db ? 34 | unit db ? 35 | cmd db ? 36 | status dw ? 37 | db 8 dup (?) 38 | media db ? 39 | trans dd ? 40 | count dw ? 41 | start dw ? 42 | drive db ? 43 | IODAT ends 44 | 45 | dw 0ffffh 46 | dw 0ffffh 47 | dw 8000h ;attribute 48 | dw offset devstrat ;device strategy 49 | dw offset devint ;device interrupt 50 | db 'SETM37$1' ;device name 8 chars (use carefully) 51 | 52 | saveptr dd 1 dup(?) 53 | 54 | devstrat proc far 55 | mov cs:word ptr[saveptr],bx 56 | mov cs:word ptr[saveptr+2],es 57 | ret 58 | devstrat endp 59 | 60 | devint proc far 61 | pusha 62 | push ds 63 | push es 64 | lds bx,cs:[saveptr] 65 | mov [bx.IODAT.status],8103h 66 | cmp [bx.IODAT.cmd],00 67 | jnz devi1 68 | mov [bx.IODAT.status],0100h 69 | mov word ptr [bx+0eh],0000 70 | mov word ptr [bx+10h],cs 71 | xor dx,dx 72 | call main 73 | devi1: 74 | pop ds 75 | pop es 76 | popa 77 | ret 78 | devint endp 79 | 80 | endif 81 | 82 | ;--- clear write protection for CRT register 0-7 83 | 84 | disablewp proc 85 | if ?DIRECTCRT 86 | mov al,11h ;vertikal retrace end register bit 7 reset 87 | out dx,al 88 | inc dx 89 | in al,dx 90 | and al,7fh 91 | out dx,al 92 | dec dx 93 | else 94 | mov ax,1201h 95 | mov bl,32h 96 | int 10h 97 | endif 98 | ret 99 | disablewp endp 100 | 101 | ;--- restore write protection for CRT register 0-7 102 | 103 | enablewp proc 104 | if ?DIRECTCRT 105 | mov al,11h 106 | out dx,al 107 | inc dx 108 | in al,dx 109 | or al,80h 110 | out dx,al 111 | dec dx 112 | else 113 | mov ax,1200h 114 | mov bl,32h 115 | int 10h 116 | endif 117 | ret 118 | enablewp endp 119 | 120 | ;--- get input status register 1 121 | 122 | getinpst1 proc 123 | mov dx,3cch 124 | in al,dx 125 | mov dx,3dah 126 | test al,1 127 | jnz @F 128 | mov dx,3bah 129 | @@: 130 | ret 131 | getinpst1 endp 132 | 133 | ;--- clear text screen 134 | 135 | clearscreen proc uses ds 136 | push 40h 137 | pop ds 138 | mov dx,0b800h 139 | mov ax,ds:[63h] 140 | cmp ax,3d4h 141 | jz @F 142 | mov dh,0b0h 143 | @@: 144 | mov es,dx 145 | mov di,ds:[4eh] 146 | mov cx,ds:[4ch] 147 | shr cx,1 148 | mov ax,0720h 149 | rep stosw 150 | mov bh,ds:[62h] 151 | mov ah,02 152 | mov dx,0000 153 | int 10h 154 | ret 155 | clearscreen endp 156 | 157 | ;--- set a plane to read/write 158 | 159 | setplane0: 160 | mov ah,0 161 | jmp setplane 162 | setplane1: 163 | mov ah,1 164 | jmp setplane 165 | setplane2: 166 | mov ah,2 167 | setplane:: 168 | mov cl,ah 169 | mov dx,3ceh 170 | mov al,4 ;"read map select" 171 | out dx,ax 172 | mov dx,3c4h 173 | mov ah,1 174 | shl ah,cl 175 | mov al,2 ;"map mask" register:select map to write to 176 | out dx,ax 177 | ret 178 | 179 | ;--- setevenmode: changes dx, ax 180 | ;--- sets register: 3CE: 1, 5, 6, 8 181 | ;--- sets register: 3C4: 4 182 | 183 | setevenmode proc 184 | mov dx,3ceh 185 | mov ax,1 ;"enable set/reset" register 186 | out dx,ax 187 | 188 | mov al,5 ;"graphics mode" register 189 | out dx,al 190 | inc dx 191 | in al,dx 192 | and al,084h ;reset "odd/even mode", set "read mode 0" 193 | out dx,al ;set "write mode" 0 194 | 195 | mov dx,3ceh 196 | mov al,6 ;"miscellaneous" register 197 | out dx,al 198 | inc dx 199 | in al,dx 200 | and al,0F0h ;reset "odd/even" 201 | or al,1+4+8 ;set addr=B800h,32K, graphics mode 202 | out dx,al 203 | 204 | mov dx,3ceh 205 | mov al,8 ;"bit mask" register: all bits to change 206 | mov ah,0FFh 207 | out dx,ax 208 | 209 | mov dl,0c4h 210 | mov al,4 211 | out dx,al 212 | inc dx 213 | in al,dx 214 | and al,not 8 ;reset "chain 4" 215 | or al,4+2 ;set odd/even=4, set extended memory=2 216 | out dx,al 217 | ret 218 | setevenmode endp 219 | 220 | ;--- table of values to save/restore 221 | 222 | savetab label word 223 | dw 3CEh 224 | db 4,5,6,8,-1 225 | dw 3C4h 226 | db 2,4,-1 227 | dw -1 228 | 229 | ;--- save regs of graphics controller + sequencer 230 | 231 | saveregs proc 232 | push ss 233 | pop es 234 | mov si,offset savetab 235 | devdone: 236 | lodsw 237 | cmp ax,-1 238 | jz done 239 | mov dx,ax 240 | nextindex: 241 | lodsb 242 | cmp al,-1 243 | jz devdone 244 | out dx,al 245 | inc dx 246 | in al,dx 247 | stosb 248 | dec dx 249 | jmp nextindex 250 | done: 251 | ret 252 | saveregs endp 253 | 254 | ;--- restore regs of graphics controller + sequencer 255 | 256 | restregs proc 257 | 258 | mov bx,si 259 | mov si,offset savetab 260 | devdone: 261 | lodsw 262 | cmp ax,-1 263 | jz done 264 | mov dx,ax 265 | nextindex: 266 | lodsb 267 | cmp al,-1 268 | jz devdone 269 | mov ah,ss:[bx] 270 | inc bx 271 | out dx,ax 272 | jmp nextindex 273 | done: 274 | ret 275 | restregs endp 276 | 277 | ;--- load a 14 pixel font (256 * 32 == 8 kB) 278 | 279 | LoadFontInPlane2 proc stdcall uses si di dwFnt:dword 280 | 281 | local savebuff[12]:byte 282 | 283 | cld 284 | lea di,savebuff 285 | call saveregs 286 | 287 | call setevenmode 288 | 289 | call setplane2 290 | mov ax,0B800h 291 | mov es,ax 292 | mov di,0000h ;use charset 0 293 | mov dl,00h 294 | mov dh,14 ;char size 295 | push ds 296 | lds si,[dwFnt] 297 | mov ch,0 298 | nextchar: 299 | inc si 300 | mov cl,dh 301 | lea bx, [di+20h] 302 | rep movsb 303 | inc si 304 | mov di, bx 305 | inc dl 306 | jnz nextchar 307 | pop ds 308 | lea si,savebuff 309 | call restregs 310 | ret 311 | LoadFontInPlane2 endp 312 | 313 | main proc c 314 | 315 | local bFlags:word 316 | local dwFnt14:dword 317 | 318 | mov bFlags,dx 319 | push cs 320 | pop ds 321 | assume ds:_TEXT 322 | 323 | push bp 324 | mov ax,1130h ;get ROM VGA font (14 pixel) 325 | mov bh,2 326 | int 10h 327 | mov dx,bp 328 | pop bp 329 | mov word ptr [dwFnt14+0],dx 330 | mov word ptr [dwFnt14+2],es 331 | 332 | ;--- set vesa gfx mode 102h (800x600x4) 333 | 334 | mov ax,4F02h 335 | mov bx,102h 336 | int 10h 337 | cmp ax,004Fh 338 | jz @F 339 | 340 | mov ax,4F02h 341 | mov bx,6Ah 342 | int 10h 343 | cmp ax,004Fh 344 | jnz notsupported 345 | @@: 346 | 347 | ;--- set BIOS variables to match the new resolution 348 | 349 | push 0 350 | pop es 351 | mov byte ptr es:[449h],3 ;video mode 352 | mov word ptr es:[44Eh],0 ;page start 353 | mov word ptr es:[460h],0C0Dh ;cursor form 354 | and byte ptr es:[465h],0fdh ;reset bit 1 ("graphics" mode) 355 | or byte ptr es:[465h],1 ;set bit 0 ("text" mode) 356 | mov byte ptr es:[484h],ROWS-1 ;max line# 357 | mov byte ptr es:[485h],14 ;scan lines 358 | mov al,es:[044Ah] ;columns 359 | mov cl,ROWS*2 360 | mul cl 361 | mov word ptr es:[44ch],ax ;page size (ROWS * CULUMNS * size WORD) 362 | 363 | ;--- reprogram CRT controller 364 | 365 | cli 366 | mov dx,es:[463h] ;get crt address 367 | call disablewp 368 | 369 | test bFlags, 2 370 | jz @F 371 | mov ax,4F01h ;set display end to 79 372 | out dx,ax 373 | @@: 374 | mov al,9 375 | out dx,al 376 | inc dx 377 | in al,dx 378 | and al,0E0h ;clear bits 0-4 379 | or al,0Dh ;set max scan line to 13 380 | out dx,al 381 | dec dx 382 | 383 | mov ax,0C0Ah ;set cursor start/end 384 | out dx,ax 385 | mov ax,0D0Bh 386 | out dx,ax 387 | if 1 388 | mov ax,5B10h ;vertical retrace start at line 603 389 | out dx,ax 390 | mov ax,5912h ;vertical display end at line 601 391 | out dx,ax 392 | mov ax,5915h ;vertical blank start at line 601 393 | out dx,ax 394 | endif 395 | mov al,17h ;mode control register 396 | out dx,al 397 | inc dx 398 | in al,dx 399 | and al,not 40h ;set byte mode 400 | out dx,al 401 | dec dx 402 | 403 | call enablewp 404 | 405 | ;--- write sequencer 406 | 407 | ;--- make planes 2+3 write protected 408 | mov dx,3c4h 409 | mov al,2 410 | mov ah,3 411 | out dx,ax 412 | 413 | ;--- set odd/even mode, reset chain 4, more than 64 kB 414 | mov dx,3c4h 415 | mov al,4 416 | mov ah,2 417 | out dx,ax 418 | 419 | ;--- write graphics controller 420 | 421 | mov dx,3ceh 422 | mov ax,1005h ;set write mode 0, read mode 0, odd/even addressing 423 | out dx,ax 424 | 425 | mov dx,3ceh 426 | mov al,6 427 | out dx,al 428 | inc dx 429 | in al,dx 430 | and al,0F0h 431 | or al,0Eh ;set B800h as base, set text mode, set odd/even 432 | out dx,al 433 | 434 | ;--- write attribute controller 435 | 436 | call getinpst1 437 | in al,dx ;reset attribute controller 438 | mov dx,3c0h 439 | 440 | mov al,10h ;select mode register 441 | out dx,al 442 | mov al,0 ;set text mode [bit 0=0] 443 | out dx,al 444 | 445 | mov al,20h ;turn screen on again 446 | out dx,al 447 | 448 | push word ptr [dwFnt14+2] 449 | push word ptr [dwFnt14+0] 450 | call LoadFontinPlane2 451 | 452 | sti 453 | 454 | .if (bFlags & 1) 455 | call clearscreen 456 | .else 457 | push 40h 458 | pop ds 459 | mov cx,ds:[4Ch] 460 | mov si,ds:[4Eh] 461 | mov ax,0B800h 462 | cmp byte ptr ds:[63h],0D4h 463 | jz @F 464 | mov ax,0B000h 465 | @@: 466 | shr cx,1 467 | mov ds,ax 468 | nextchar: 469 | lodsw 470 | cmp ah,0 471 | jnz @F 472 | mov ax,0720h 473 | mov [si-2],ax 474 | @@: 475 | loop nextchar 476 | .endif 477 | notsupported: 478 | mov al,00 479 | ret 480 | main endp 481 | 482 | 483 | start: 484 | ;--- get cmdline parameter 485 | 486 | mov bx,80h 487 | mov cl,es:[bx] 488 | inc bx 489 | xor ax,ax 490 | xor dx,dx 491 | .while (cl) 492 | mov ah,al 493 | mov al,es:[bx] 494 | or al,20h 495 | .if ((ah == '/') || (ah == '-')) 496 | .if (al == 'c') 497 | or dl,1 498 | .elseif (al == '8') 499 | or dl,2 500 | .elseif (al == '?') 501 | push cs 502 | pop ds 503 | mov dx,offset help 504 | mov ah,9 505 | int 21h 506 | jmp exit 507 | .endif 508 | .endif 509 | inc bx 510 | dec cl 511 | .endw 512 | call main 513 | exit: 514 | mov ah,4ch 515 | int 21h 516 | 517 | help db "usage: SETM43 [option]",13,10 518 | db "option: -c clear screen",13,10 519 | db " -8 set display end to 80 chars",13,10,'$' 520 | db " -? this text",13,10,'$' 521 | 522 | END start 523 | -------------------------------------------------------------------------------- /src/fatfs.inc: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------- 2 | ; 3 | ; WDe Copyright(C)2005 Ben Cadieux 4 | ; 5 | ;------------------------------------------------------- 6 | ; 7 | ; cluster2sector converts a cluster number to its matching sector number. 8 | ; 9 | ; IN: eax: cluster number 10 | ; OUT: eax: sector number 11 | ; edx is corrupted 12 | ; 13 | ; if the cluster number given multiplies out to a value larger than 14 | ; can be stored in 32-bits, or the value ends up less than 2, then 15 | ; -1 is returned instead. 16 | ; 17 | ;------------------------------------------------------- 18 | cluster2sector proc 19 | push ebx 20 | sub eax, 2 21 | jc errem2 22 | 23 | movzx ebx, [wSpC] 24 | mul ebx 25 | jc errem2 26 | 27 | add eax, [dwDataStart] 28 | jc errem2 29 | 30 | test [bFilesys], FS_FAT32 31 | je skipfat32adjust 32 | cmp [dwRootCluster], 2 33 | ja skipfat32adjust 34 | sub eax, ebx 35 | jnc skipfat32adjust 36 | errem2: 37 | mov eax, -1 ; invalid cluster number was sent 38 | skipfat32adjust: 39 | pop ebx 40 | ret 41 | cluster2sector endp 42 | ;------------------------------------------------------- 43 | ; 44 | ; sector2cluster converts a sector number to its matching cluster number. 45 | ; 46 | ; IN: eax sector number 47 | ; OUT: 48 | ; NC: eax corresponding cluster number 49 | ; ecx corrupted 50 | ; C: error 51 | ; 52 | ;------------------------------------------------------- 53 | sector2cluster proc 54 | movzx ecx, [bFats] 55 | ; jcxz skipfats ; useful if ever FATS=0 56 | @@: 57 | sub eax, [dwSpF] 58 | jc done 59 | loop @B 60 | skipfats: 61 | 62 | test [bFilesys], FS_FAT32 63 | jnz @F 64 | mov cx, [wRootsectors] 65 | sub eax, ecx 66 | jc done 67 | @@: 68 | 69 | sub eax, [dwReserved] 70 | jc done 71 | 72 | mov cl, [bSpCshift] 73 | shr eax, cl ; divide by sectors per cluster 74 | 75 | add eax, 2 ; clusters start at 2 76 | done: 77 | ret 78 | sector2cluster endp 79 | ;------------------------------------------------------- 80 | ; 81 | ; getfatentry returns the entry in the fat table for a particular cluster# 82 | ; called: 83 | ; 1. when "recursing" ( ctrl-left ) within a FAT ( then may be called quite often). 84 | ; 2. if ctrl-right has been pressed in data region 85 | ; 3. within savechain 86 | ; 4. within restorechain 87 | ; 5. by undelete and unformat 88 | ; 89 | ; IN: eax entry# to get 90 | ; OUT: eax data stored in the fat 91 | ; C if entry# in eax is invalid 92 | ;------------------------------------------------------- 93 | getfatentry proc 94 | push ebx 95 | push si 96 | 97 | ; and eax, 0FFFFFFFh ; ignore highest nibble 98 | mov ebx, eax 99 | call locatefatentry ; will set BX=offset in sector 100 | jc abort 101 | mov si, [pFatCache] 102 | cmp [bFilesys], FS_FAT12 103 | jne fat1632 104 | 105 | push [dwFatSector] 106 | call fat12pad 107 | 108 | test al, 00000001b 109 | jnz @F 110 | mov ax, word ptr [si+bx] 111 | and ah, 0Fh 112 | jmp f12gfs 113 | @@: 114 | mov ax, word ptr [si+bx] 115 | shr ax, 4 116 | f12gfs: 117 | cmp ax, 0FF7h ; if the fat entry is an end of chain 118 | jb f16gfd ; or bad cluster entry, then pad 119 | jmp filltopbits ; it so for any FAT type it's set 120 | ; to 0FFFFFFxh 121 | fat1632: 122 | mov eax, dword ptr [si+bx] 123 | test [bFilesys], FS_FAT32 ; FAT32 or exFAT? 124 | jnz f32gfd 125 | f16gfd: 126 | movzx eax, ax ; clear top word for fat12/fat16 127 | cmp ax, 0FFF7h 128 | cmc ; should be NC when jumping! 129 | jnc done 130 | 131 | filltopbits: ; for ease/compatibility, all fat 132 | or eax, 0FFFF000h ; oddities (full/bad cluster) are 133 | f32gfd: ; set as FFFFFFxh 134 | and eax, 0FFFFFFFh 135 | done: 136 | abort: 137 | pop si 138 | pop ebx 139 | ret 140 | getfatentry endp 141 | ;------------------------------------------------------- 142 | ; 143 | ; putfatentry writes the entry in the fat table for a particular cluster # 144 | ; called by undelete and unformat. 145 | ; 146 | ; IN: ebx entry# that is to be modified 147 | ; eax data to store at that entry 148 | ; 149 | ;------------------------------------------------------- 150 | putfatentry proc 151 | ; @dprintfln "putfatentry: entry=%lX, data=%lX", ebx, eax 152 | push edx 153 | push si 154 | mov edx, ebx 155 | ; and eax, 0FFFFFFFh 156 | call locatefatentry ; will copy FAT sector into FAT cache buffer 157 | jc abortpfe 158 | mov si, [pFatCache] 159 | cmp [bFilesys], FS_FAT12 160 | jne dof132 161 | 162 | push [dwFatSector] 163 | call fat12pad 164 | 165 | test dl, 00000001b 166 | jnz pmethod2 167 | pmethod1: 168 | and ah, 0Fh 169 | and byte ptr [si+bx+1], 0F0h ; replacing bottom 12 bits 170 | or ah, byte ptr [si+bx+1] ; so preserve old top nibble 171 | jmp isfat1x 172 | pmethod2: 173 | shl ax, 4 ; replacing the top 12 bits 174 | and byte ptr [si+bx], 0Fh 175 | or al, [si+bx] ; so preserve old low nibble 176 | jmp isfat1x 177 | 178 | ;--- FAT16/FAT32 179 | 180 | dof132: 181 | test [bFilesys], FS_FAT32 182 | je isfat1x 183 | ;fat32pfe: 184 | and dword ptr [si+bx], 0F0000000h ; preserve highest nibble in fat32 185 | or dword ptr [si+bx], eax ; as it is not part of the entry 186 | isfat1x: 187 | mov [si+bx], ax 188 | 189 | push [ioreq.pBuffer] 190 | push [pFatCache] 191 | pop [ioreq.pBuffer] 192 | nextsector: 193 | push [dwFatSector] 194 | pop [ioreq.sectno] 195 | ; @dprintfln "putfatentry: writing FAT, sector=%lu", [ioreq.sectno] 196 | call diskaccess_write 197 | 198 | cmp bx, 511 ; FAT12? 199 | jne abortpfe2 200 | 201 | inc [dwFatSector] 202 | push [dwFatSector] 203 | pop [ioreq.sectno] 204 | mov [ioreq.bRW], RW_READ 205 | call diskaccess 206 | 207 | inc bx 208 | mov al, [si+bx] 209 | mov [si], al 210 | jmp nextsector 211 | 212 | abortpfe2: 213 | pop [ioreq.pBuffer] 214 | clc 215 | abortpfe: 216 | pop si 217 | pop edx 218 | ret 219 | 220 | putfatentry endp 221 | 222 | ;----------------------------------------------------------------- 223 | ; 224 | ; locatefatentry finds the offset within the fat for a given cluster 225 | ; called by getfatentry and putfatentry. 226 | ; 227 | ; IN: ebx cluster number to locate 228 | ; OUT: [dwFatSector] sector # the entry is in 229 | ; bx byte offset to it inside the sector 230 | ; C if error 231 | ; the sector is read into pFatCache 232 | ; 233 | ;----------------------------------------------------------------- 234 | locatefatentry proc 235 | push eax 236 | push ecx 237 | 238 | if 0 ; changed in v0.50 239 | cmp ebx, [dwLastCluster] ; past the last cluster on the drive? 240 | stc ; ERROR!!! 241 | ja done ; so abort with an error 242 | else 243 | cmp [dwLastCluster], ebx ; past the last cluster on the drive? 244 | jb done ; C set if ebx > dwLastCluster 245 | endif 246 | 247 | mov cl, [bFilesys] ; convert cluster number to FAT offset 248 | and cl, FS_FAT12 or FS_FAT16 or FS_FAT32 249 | shr cl, 1 ; FAT32: 4->2, FAT16: 2->1, FAT12: 1->0 250 | jnz @F 251 | mov eax, ebx ; adjustment for fat12 - 252 | shr eax, 1 ; we must multiply with 1.5 253 | add ebx, eax 254 | @@: 255 | shl ebx, cl ; ebx = FAT offset 256 | ; divides ebx by bps in order to find 257 | movzx ecx, [wBps] ; sector# of the entry 258 | push cx 259 | shr cx, 9 ; 0x200 / 0x200 + 8 = 9; 0x400 / 0x200 + 8 = 10 260 | add cl, 8 261 | mov eax, ebx 262 | shr eax, cl 263 | pop cx 264 | 265 | ; shr ch, 1 ; ??? 266 | ; or cx, 1ffh ; ??? 267 | dec cx 268 | 269 | and ebx, ecx 270 | 271 | add eax, [dwReserved] 272 | 273 | ; cmp [bFats], 2 274 | ; jb @F 275 | cmp [fromfat], FF_FAT1 276 | je @F 277 | add eax, [dwSpF] 278 | @@: 279 | cmp [dwFatSector], eax ; read that FAT sector if necessary 280 | je done 281 | call readfatcache 282 | jc done 283 | mov [dwFatSector], eax 284 | done: 285 | pop ecx 286 | pop eax 287 | ret 288 | locatefatentry endp 289 | 290 | ;--- ensure the fat cache sector will be reread 291 | 292 | resetfatcache proc 293 | mov [dwFatSector], 0 294 | or [dwFat12fixsec], -1 ; ensure dwFat12fixsec is != dwFatSector 295 | ret 296 | resetfatcache endp 297 | 298 | ;----------------------------------------------------------------- 299 | ; 300 | ; fat12pad adds extra fat data around the sector pointed to by SI in case 301 | ; the fat entry being read/written crosses a sector boundary 302 | ; 303 | ; IN: sector number as stack param! 304 | ; si: pointer to sector content; it's pointing 305 | ; to the fat cache if called by get/putfatentry. 306 | ; OUT: bytes written around si ([si-1] & [si+wBps]) 307 | ; 308 | ;----------------------------------------------------------------- 309 | fat12pad proc 310 | pusha 311 | mov bp, sp 312 | push eax 313 | mov eax, [bp+16+2] ; assumes 16-bit! 314 | 315 | cmp [dwFat12fixsec], eax ; the same sector? then 316 | je done ; we already have the correct data 317 | mov [dwFat12fixsec], eax ; ...this would be a tiny bug if 318 | ; we switch drives on sector 0 319 | 320 | push [dwFatSector] ; save current fatcache sector 321 | mov [handling], IGNORE_ERRORS ; inside fat12pad 322 | mov bx, [wBps] 323 | test eax, eax ; if the current sector is 0 324 | jz nopred ; then we can't read the previous 325 | 326 | dec eax 327 | call readfatcache ; read previous sector into fatcache 328 | jc @F 329 | mov di, [pFatCache] ; load DI AFTER readfatcache! 330 | mov cl, [di+bx-1] ; copy last byte of previous sector 331 | mov [si-1], cl 332 | @@: 333 | inc eax 334 | nopred: ; we don't want to read the next 335 | cmp eax, [lastSector] ; sector if it's past the drive end 336 | jae @F 337 | inc eax 338 | call readfatcache ; read next sector into fatcache 339 | jc @F 340 | mov di, [pFatCache] ; load DI AFTER readfatcache! 341 | mov cl, [di+0] ; and copy first byte of next sector 342 | mov byte ptr [si+bx], cl ; behind the current sector 343 | @@: 344 | done2: 345 | pop eax 346 | call readfatcache ; restore content of fatcache 347 | mov [handling], ABORT_OPERATION ; inside fat12pad 348 | done: 349 | pop eax 350 | popa 351 | ret 4 352 | 353 | readfatcache:: 354 | cmp [pFatCache],0 355 | jnz @F 356 | push ax 357 | mov ax,[wBps] 358 | add ax, 2*4 ; add a 4 byte reserve at start/end for fat12fix 359 | call allocmem 360 | add ax, 4 ; the fat12 fix must be BEFORE sector start 361 | mov [pFatCache], ax 362 | @dprintfln "readfatcache: pFatCache allocated: %X", ax 363 | pop ax 364 | @@: 365 | mov [ioreq.sectno], eax 366 | push [ioreq.pBuffer] 367 | push [pFatCache] 368 | pop [ioreq.pBuffer] 369 | mov [ioreq.bRW], RW_READ 370 | call diskaccess 371 | pop [ioreq.pBuffer] 372 | ret 373 | 374 | fat12pad endp 375 | ;----------------------------------------------------------------- 376 | ; 377 | ; getentrynumber gets the fat entry number the cursor is on 378 | ; called 1. in FAT, when ENTER has been pressed 379 | ; 2. in FAT, when Ctrl+Left (recurse) has been pressed 380 | ; 3. in FAT, to display entry# in top line 381 | ; 4. in FAT, from getcurrententry 382 | ; 383 | ; IN: [currSector] current sector within a fat 384 | ; [spot] byte offset inside current sector 385 | ; OUT: eax entry number. That is actually 386 | ; the cluster. 387 | ;----------------------------------------------------------------- 388 | getentrynumber proc 389 | movzx ebx, [spot] 390 | getentrynumberX:: ; <--- if just the entry# of the sector start interests 391 | mov eax, [currSector] 392 | sub eax, [dwReserved] 393 | 394 | mov [fromfat], FF_FAT1 395 | cmp eax, [dwSpF] 396 | jb @F 397 | sub eax, [dwSpF] ; in 2. FAT 398 | inc [fromfat] 399 | @@: 400 | 401 | ;--- here eax contains relative sector# within FAT 402 | 403 | mov cl, byte ptr [wBps+1] ; if sector size = 512, it's 2 404 | shr cl, 1 ; 2 -> 1 405 | add cl, 8 ; = 9 406 | 407 | shl eax, cl ; * 512 408 | 409 | ;--- here eax contains relative offset of current sector within FAT 410 | 411 | add eax, ebx 412 | 413 | ;--- here eax contains relative offset of current spot within FAT 414 | ;--- it's now to be divided thru 1.5 (FAT12), 2 (FAT16) or 4 (FAT32/exFAT) 415 | 416 | mov cl, [bFilesys] ; 12=exFAT,4=FAT32,2=FAT16,1=FAT12 417 | and cl, FS_FAT12 or FS_FAT16 or FS_FAT32 ; mask out the exFAT bit 418 | shr cl, 1 ; 4->2, 2->1, 1->0 419 | jz isfat12 420 | shr eax, cl ; eax = entry # 421 | ret 422 | isfat12: 423 | ;--- a FAT12-FAT can't have a size > 65536 (max should be 4096*12/8=6144), 424 | ;--- so a 16-bit muldiv should be ok as well. 425 | xor edx, edx 426 | shl eax, 1 ; eax = muldiv( eax, 2, 3 ) 427 | mov bx, 3 428 | div ebx 429 | ret 430 | getentrynumber endp 431 | ;----------------------------------------------------------------- 432 | ; 433 | ; go2entry jumps to an entry in the fat 434 | ; 435 | ; IN: eax cluster number 436 | ; OUT: [ioreq.sectno] corresponding sector within a fat 437 | ; [spot] byte offset within the sector 438 | ; 439 | ;----------------------------------------------------------------- 440 | go2entry proc 441 | cmp [bFilesys], FS_FAT12 442 | jne nosmd 443 | mov ecx, 3 444 | mul ecx 445 | 446 | shr eax, 1 447 | jnc noinc12 448 | inc eax 449 | noinc12: 450 | jmp sub512 451 | nosmd: 452 | 453 | mov cl, [bFilesys] 454 | and cl, FS_FAT12 or FS_FAT16 or FS_FAT32 455 | shr cl, 1 456 | shl eax, cl 457 | 458 | sub512: 459 | 460 | movzx edx, [wBps] ; \Fixed?/ 461 | xor ecx, ecx 462 | loopfindsect: 463 | cmp eax, edx 464 | jb donesub 465 | sub eax, edx 466 | inc ecx 467 | jmp loopfindsect 468 | donesub: 469 | 470 | add ecx, [dwReserved] 471 | mov [ioreq.sectno], ecx 472 | 473 | xor dl, dl 474 | jmp movecursor 475 | 476 | go2entry endp 477 | ;------------------------------------------------------- 478 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /src/INCLUDE/WINBASE.INC: -------------------------------------------------------------------------------- 1 | 2 | DLL_PROCESS_ATTACH equ 1 3 | DLL_THREAD_ATTACH equ 2 4 | DLL_THREAD_DETACH equ 3 5 | DLL_PROCESS_DETACH equ 0 6 | 7 | PAGE_NOACCESS equ 1h 8 | PAGE_READONLY equ 2h 9 | PAGE_READWRITE equ 4h 10 | PAGE_WRITECOPY equ 8h 11 | PAGE_EXECUTE equ 10h 12 | PAGE_EXECUTE_READ equ 20h 13 | PAGE_EXECUTE_READWRITE equ 40h 14 | PAGE_EXECUTE_WRITECOPY equ 80h 15 | PAGE_GUARD equ 100h 16 | PAGE_NOCACHE equ 200h 17 | MEM_COMMIT equ 1000h 18 | MEM_RESERVE equ 2000h 19 | MEM_DECOMMIT equ 4000h 20 | MEM_RELEASE equ 8000h 21 | MEM_FREE equ 10000h 22 | MEM_PRIVATE equ 20000h 23 | MEM_MAPPED equ 40000h 24 | MEM_RESET equ 80000h 25 | 26 | MEMORY_BASIC_INFORMATION STRUCT 27 | BaseAddress DWORD ? 28 | AllocationBase DWORD ? 29 | AllocationProtect DWORD ? 30 | RegionSize DWORD ? 31 | State DWORD ? 32 | Protect DWORD ? 33 | Type_ DWORD ? 34 | MEMORY_BASIC_INFORMATION ENDS 35 | 36 | FILE_ATTRIBUTE_READONLY EQU 00000001h 37 | FILE_ATTRIBUTE_HIDDEN EQU 00000002h 38 | FILE_ATTRIBUTE_SYSTEM EQU 00000004h 39 | FILE_ATTRIBUTE_DIRECTORY EQU 00000010h 40 | FILE_ATTRIBUTE_ARCHIVE EQU 00000020h 41 | FILE_ATTRIBUTE_ENCRYPTED EQU 00000040h 42 | FILE_ATTRIBUTE_NORMAL EQU 00000080h 43 | FILE_ATTRIBUTE_TEMPORARY EQU 00000100h 44 | 45 | GENERIC_READ equ 80000000h 46 | GENERIC_WRITE equ 40000000h 47 | 48 | CREATE_NEW equ 1 ; fails if file already exists 49 | CREATE_ALWAYS equ 2 ; if file exists, it will be overwritten 50 | OPEN_EXISTING equ 3 ; fails if file doesn't exist 51 | OPEN_ALWAYS equ 4 ; creates file if it doesn't exist 52 | TRUNCATE_EXISTING equ 5 ; fails if file doesn't exist. will be truncated 53 | 54 | FILE_SHARE_READ EQU 00000001h 55 | FILE_SHARE_WRITE EQU 00000002h 56 | FILE_SHARE_DELETE EQU 00000004h 57 | 58 | IMAGE_FILE_RELOCS_STRIPPED EQU 0001h 59 | IMAGE_FILE_DLL EQU 2000h 60 | 61 | INVALID_SET_FILE_POINTER equ -1 62 | 63 | DRIVE_CDROM equ 5 64 | 65 | NO_ERROR equ 0 66 | 67 | CTL_CODE macro DeviceType,Function,Method,Access 68 | exitm <( DeviceType shl 16 ) or ( Access shl 14 ) or ( Function shl 2 ) or Method> 69 | endm 70 | 71 | FILE_DEVICE_CD_ROM EQU 00000002h 72 | FILE_DEVICE_DISK EQU 00000007h 73 | 74 | METHOD_BUFFERED EQU 0 75 | METHOD_OUT_DIRECT EQU 2 76 | 77 | FILE_ANY_ACCESS EQU 0 78 | FILE_READ_ACCESS EQU 1 79 | 80 | ;--- CD Track Mode 81 | YELLOWMODE2 EQU 0 82 | XAFORM2 EQU 1 83 | CDDA EQU 2 84 | 85 | IOCTL_DISK_BASE EQU FILE_DEVICE_DISK 86 | IOCTL_CDROM_BASE EQU FILE_DEVICE_CD_ROM 87 | 88 | IOCTL_DISK_GET_DRIVE_GEOMETRY EQU 89 | IOCTL_DISK_GET_DRIVE_GEOMETRY_EX EQU 90 | IOCTL_CDROM_RAW_READ EQU 91 | 92 | DISK_GEOMETRY struct 93 | Cylinders dq ? 94 | MediaType dd ? 95 | TracksPerCylinder DWORD ? 96 | SectorsPerTrack DWORD ? 97 | BytesPerSector DWORD ? 98 | DISK_GEOMETRY ends 99 | 100 | DISK_PARTITION_INFO struct 101 | SizeOfPartitionInfo DWORD ? 102 | PartitionStyle DWORD ? 103 | union 104 | struct Mbr 105 | Signature DWORD ? 106 | CheckSum DWORD ? 107 | ends 108 | struct Gpt 109 | DiskId db 16 dup (?) 110 | ends 111 | ends 112 | DISK_PARTITION_INFO ends 113 | 114 | DISK_INT13_INFO struct 4 115 | DriveSelect WORD ? 116 | MaxCylinders DWORD ? 117 | SectorsPerTrack WORD ? 118 | MaxHeads WORD ? 119 | NumberDrives WORD ? 120 | DISK_INT13_INFO ends 121 | 122 | DISK_EX_INT13_INFO struct 8 123 | ExBufferSize WORD ? ;+0 124 | ExFlags WORD ? ;+2 125 | ExCylinders DWORD ? ;+4 126 | ExHeads DWORD ? 127 | ExSectorsPerTrack DWORD ? ;+12 128 | ExSectorsPerDrive QWORD ? ;+16 129 | ExSectorSize WORD ? ;+24 130 | ExReserved WORD ? 131 | DISK_EX_INT13_INFO ends 132 | 133 | DISK_DETECTION_INFO struct 134 | SizeOfDetectInfo DWORD ? ;+0 135 | DetectionType DWORD ? ;+4 136 | union 137 | struct 138 | Int13 DISK_INT13_INFO <> ;+8, size 16 139 | ExInt13 DISK_EX_INT13_INFO <> ;+24, size 32 140 | ends 141 | ends 142 | DISK_DETECTION_INFO ends 143 | 144 | DISK_GEOMETRY_EX struct 8 145 | Geometry DISK_GEOMETRY <> 146 | DiskSize dq ? 147 | DISK_PARTITION_INFO <> 148 | DISK_DETECTION_INFO <> 149 | DISK_GEOMETRY_EX ends 150 | 151 | 152 | ifdef __JWASM__ 153 | option dllimport: 154 | endif 155 | 156 | AddAtomA proto stdcall :ptr byte 157 | Beep proto stdcall :dword, :dword 158 | CancelWaitableTimer proto stdcall :dword 159 | CloseHandle proto stdcall :dword 160 | CompareStringA proto stdcall :DWORD, :DWORD, :ptr BYTE, :DWORD, :ptr BYTE, :DWORD 161 | CompareStringW proto stdcall :DWORD, :DWORD, :ptr WORD, :DWORD, :ptr WORD, :DWORD 162 | CopyFileA proto stdcall :ptr BYTE, :ptr BYTE, :DWORD 163 | CreateDirectoryA proto stdcall :ptr BYTE, :dword 164 | CreateDirectoryExA proto stdcall :ptr BYTE, :ptr BYTE, :ptr 165 | CreateDirectoryW proto stdcall :ptr WORD, :dword 166 | CreateEventA proto stdcall :dword, :dword, :dword, :ptr BYTE 167 | CreateFileA proto stdcall :dword, :dword, :dword, :dword, :dword, :dword, :dword 168 | CreateFileMappingA proto stdcall :dword, :dword, :dword, :dword, :dword, :ptr BYTE 169 | CreateMutexA proto stdcall :dword, :dword, :ptr BYTE 170 | CreateMutexW proto stdcall :dword, :dword, :ptr WORD 171 | CreateProcessA proto stdcall :ptr BYTE, :ptr BYTE, :dword, :dword, :dword, :dword, :ptr , :ptr BYTE, :ptr STARTUPINFOA, :ptr PROCESS_INFORMATION 172 | CreateSemaphoreA proto stdcall :dword, :dword, :dword, :dword 173 | CreateThread proto stdcall :dword, :dword, :dword, :dword, :dword, :dword 174 | CreateWaitableTimerA proto stdcall :dword, :dword, :ptr BYTE 175 | DebugBreak proto stdcall 176 | DeleteAtom proto stdcall :dword 177 | DeleteCriticalSection proto stdcall :ptr CRITICAL_SECTION 178 | DeleteFileA proto stdcall :dword 179 | DeviceIoControl proto stdcall :dword, :dword, :ptr, :dword, :ptr, :dword, :ptr dword, :dword 180 | DisableThreadLibraryCalls proto stdcall :dword 181 | DosDateTimeToFileTime proto stdcall :DWORD, :DWORD, :ptr FILETIME 182 | DuplicateHandle proto stdcall :dword, :dword, :dword, :dword, :dword, :dword, :dword 183 | EnterCriticalSection proto stdcall :ptr CRITICAL_SECTION 184 | EnumResourceLanguagesA proto stdcall :dword, :ptr BYTE, :ptr BYTE, :dword, :dword 185 | EnumResourceNamesA proto stdcall :dword, :ptr BYTE, :dword, :dword 186 | EnumResourceTypesA proto stdcall :dword, :dword, :dword 187 | ExitProcess proto stdcall :dword 188 | ExitThread proto stdcall :dword 189 | ExpandEnvironmentStringsA proto stdcall :ptr BYTE, :ptr BYTE, :dword 190 | FatalAppExitA proto stdcall :dword, :ptr BYTE 191 | FileTimeToDosDateTime proto stdcall :ptr FILETIME, :ptr WORD, :ptr WORD 192 | FileTimeToSystemTime proto stdcall :ptr FILETIME, :ptr SYSTEMTIME 193 | FindAtomA proto stdcall :ptr byte 194 | FindClose proto stdcall :dword 195 | FindFirstFileA proto stdcall :ptr BYTE, :ptr WIN32_FIND_DATAA 196 | FindFirstFileW proto stdcall :ptr WORD, :ptr WIN32_FIND_DATAW 197 | FindNextFileA proto stdcall :dword, :ptr WIN32_FIND_DATAA 198 | FindNextFileW proto stdcall :dword, :ptr WIN32_FIND_DATAW 199 | FindResourceA proto stdcall :dword, :dword, :dword 200 | FindResourceExA proto stdcall :dword, :dword, :dword, :dword 201 | FindResourceW proto stdcall :dword, :ptr WORD, :ptr word 202 | FlushFileBuffers proto stdcall :dword 203 | FlushViewOfFile proto stdcall :ptr, :dword 204 | FormatMessageA proto stdcall :dword, :ptr, :DWORD, :DWORD, :ptr BYTE, :DWORD, :ptr 205 | FreeEnvironmentStringsA proto stdcall :dword 206 | FreeEnvironmentStringsW proto stdcall :dword 207 | FreeLibrary proto stdcall :dword 208 | GetACP proto stdcall 209 | GetAtomNameA proto stdcall :dword, :ptr byte, :dword 210 | GetCommandLineA proto stdcall 211 | GetComputerNameA proto stdcall :ptr BYTE, :ptr DWORD 212 | GetCurrentDirectoryA proto stdcall :dword, :ptr byte 213 | GetCurrentProcess proto stdcall 214 | GetCurrentProcessId proto stdcall 215 | GetCurrentThread proto stdcall 216 | GetCurrentThreadId proto stdcall 217 | GetDateFormatA proto stdcall lcid:DWORD, dwFlags:DWORD, pDate:ptr SYSTEMTIME,lpFormat:ptr BYTE, lpDateStr:ptr BYTE, cchDate:DWORD 218 | GetDiskFreeSpaceA proto stdcall :ptr BYTE, :ptr dword, :ptr dword, :ptr dword, :ptr dword 219 | GetDiskFreeSpaceW proto stdcall :ptr WORD, :ptr dword, :ptr dword, :ptr dword, :ptr dword 220 | GetDriveTypeA proto stdcall :ptr BYTE 221 | GetDriveTypeW proto stdcall :ptr WORD 222 | GetEnvironmentStrings proto stdcall 223 | GetEnvironmentStringsA proto stdcall 224 | GetEnvironmentStringsW proto stdcall 225 | GetEnvironmentVariableA proto stdcall :ptr BYTE, :ptr BYTE, :dword 226 | GetExitCodeThread proto stdcall :dword, :ptr dword 227 | GetFileAttributesA proto stdcall :ptr byte 228 | GetFileAttributesExA proto stdcall :ptr BYTE, :DWORD, :ptr WIN32_FILE_ATTRIBUTE_DATA 229 | GetFileSize proto stdcall :dword, :ptr dword 230 | GetFileTime proto stdcall :dword, :ptr FILETIME, :ptr FILETIME, :ptr FILETIME 231 | GetFileType proto stdcall :dword 232 | GetFullPathNameA proto stdcall :ptr BYTE, :DWORD, :ptr BYTE, :ptr ptr BYTE 233 | GetFullPathNameW proto stdcall :ptr WORD, :DWORD, :ptr WORD, :ptr ptr WORD 234 | GetLastError proto stdcall 235 | GetLocaleInfoA proto stdcall :dword, :dword, :ptr BYTE, :dword 236 | GetLocalTime proto stdcall :ptr SYSTEMTIME 237 | GetLongPathNameA proto stdcall :ptr byte, :ptr byte, :DWORD 238 | GetModuleFileNameA proto stdcall :dword, :ptr byte, :dword 239 | GetModuleHandleA proto stdcall :ptr BYTE 240 | GetOEMCP proto stdcall 241 | GetPrivateProfileStringA proto stdcall :ptr BYTE, :ptr BYTE, :ptr BYTE, :ptr BYTE, :DWORD, :ptr BYTE 242 | GetProcAddress proto stdcall :DWORD, :DWORD 243 | GetProcessHeap proto stdcall 244 | GetShortPathNameA proto stdcall :ptr byte, :ptr byte, :DWORD 245 | GetStartupInfoA proto stdcall :ptr STARTUPINFOA 246 | GetStdHandle proto stdcall :dword 247 | GetSystemDirectoryA proto stdcall :ptr byte, :DWORD 248 | GetSystemTime proto stdcall :ptr SYSTEMTIME 249 | GetSystemTimeAsFileTime proto stdcall :ptr FILETIME 250 | GetTempFileNameA proto stdcall :ptr BYTE, :ptr BYTE, :DWORD, :ptr BYTE 251 | GetTempPathA proto stdcall :DWORD, :ptr BYTE 252 | GetTickCount proto stdcall 253 | GetUserDefaultLCID proto stdcall 254 | GetVersion proto stdcall 255 | GetVersionExA proto stdcall :ptr OSVERSIONINFO 256 | GlobalAddAtomA proto stdcall :ptr BYTE 257 | GlobalAlloc proto stdcall :dword, :dword 258 | GlobalFree proto stdcall :dword 259 | GlobalGetAtomNameA proto stdcall :dword, :ptr BYTE, :dword 260 | GlobalMemoryStatus proto stdcall :ptr MEMORYSTATUS 261 | GlobalSize proto stdcall :dword 262 | HeapAlloc proto stdcall :dword, :dword, :dword 263 | HeapCreate proto stdcall :dword, :dword, :dword 264 | HeapDestroy proto stdcall :dword 265 | HeapFree proto stdcall :dword, :dword, :dword 266 | HeapReAlloc proto stdcall :dword, :dword, :dword, :dword 267 | HeapSize proto stdcall :dword, :dword, :dword 268 | HeapValidate proto stdcall :dword, :dword, :dword 269 | HeapWalk proto stdcall :dword, :ptr PROCESS_HEAP_ENTRY 270 | InitializeCriticalSection proto stdcall :ptr CRITICAL_SECTION 271 | InterlockedDecrement proto stdcall :dword 272 | InterlockedExchange proto stdcall :ptr DWORD, :DWORD 273 | InterlockedIncrement proto stdcall :dword 274 | IsBadCodePtr proto stdcall :DWORD 275 | IsBadReadPtr proto stdcall :DWORD, :DWORD 276 | IsBadWritePtr proto stdcall :DWORD, :DWORD 277 | IsDebuggerPresent proto stdcall 278 | IsProcessorFeaturePresent proto stdcall :dword 279 | LeaveCriticalSection proto stdcall :ptr CRITICAL_SECTION 280 | LoadLibraryA proto stdcall :ptr BYTE 281 | LoadLibraryExA proto stdcall :ptr BYTE, :DWORD, :DWORD 282 | LoadResource proto stdcall :dword, :dword 283 | LocalAlloc proto stdcall :dword, :dword 284 | LocalFileTimeToFileTime proto stdcall :ptr FILETIME, :ptr FILETIME 285 | LocalFree proto stdcall :dword 286 | MapViewOfFile proto stdcall :dword, :dword, :dword, :dword, :dword 287 | MapViewOfFileEx proto stdcall :dword, :dword, :dword, :dword, :dword, :ptr 288 | MoveFileA proto stdcall :ptr BYTE, :ptr BYTE 289 | MoveFileExA proto stdcall :ptr BYTE, :ptr BYTE, :dword 290 | MultiByteToWideChar proto stdcall :DWORD, :DWORD, :ptr BYTE, :DWORD, :ptr WORD, :DWORD 291 | OpenEventA proto stdcall :dword, :dword, :ptr BYTE 292 | OpenFile proto stdcall :ptr byte, :ptr OFSTRUCT, :dword 293 | OpenFileMappingA proto stdcall :dword, :dword, :ptr BYTE 294 | OpenMutexA proto stdcall :dword, :dword, :dword 295 | OpenProcess proto stdcall :dword, :dword, :dword 296 | OpenSemaphoreA proto stdcall :dword, :dword, :dword 297 | OutputDebugStringA proto stdcall :ptr BYTE 298 | PulseEvent proto stdcall :dword 299 | QueueUserAPC proto stdcall :dword, :dword, :dword 300 | RaiseException proto stdcall :DWORD, :DWORD, :DWORD, :ptr 301 | ReadFile proto stdcall :dword, :dword, :dword, :ptr dword, :ptr OVERLAPPED 302 | ReleaseMutex proto stdcall :dword 303 | ReleaseSemaphore proto stdcall :dword, :dword, :dword 304 | RemoveDirectoryA proto stdcall :ptr BYTE 305 | RemoveDirectoryW proto stdcall :ptr WORD 306 | ResetEvent proto stdcall :dword 307 | ResumeThread proto stdcall :dword 308 | RtlFillMemory proto stdcall :ptr BYTE, :DWORD, :dword 309 | RtlMoveMemory proto stdcall :ptr BYTE, :ptr BYTE, :dword 310 | RtlUnwind proto stdcall :ptr EXCEPTION_REGISTRATION, :dword, :ptr EXCEPTION_RECORD, :dword 311 | RtlZeroMemory proto stdcall :ptr BYTE, :dword 312 | SearchPathA proto stdcall :ptr BYTE, :ptr BYTE, :ptr BYTE, :DWORD, :ptr BYTE, :ptr ptr BYTE 313 | SetCurrentDirectoryA proto stdcall :ptr BYTE 314 | SetCurrentDirectoryW proto stdcall :ptr WORD 315 | SetEndOfFile proto stdcall :dword 316 | SetEnvironmentVariableA proto stdcall :ptr BYTE, :ptr BYTE 317 | SetErrorMode proto stdcall :dword 318 | SetEvent proto stdcall :dword 319 | SetFileAttributesA proto stdcall :ptr byte, :dword 320 | SetFilePointer proto stdcall :dword, :dword, :dword, :dword 321 | SetFilePointerEx proto stdcall :dword, :qword, :ptr QWORD, :dword 322 | SetFileTime proto stdcall :dword, :ptr FILETIME, :ptr FILETIME, :ptr FILETIME 323 | SetHandleCount proto stdcall :dword 324 | SetLastError proto stdcall :dword 325 | SetPriorityClass proto stdcall :dword, :dword 326 | SetStdHandle proto stdcall :dword, :dword 327 | SetThreadPriority proto stdcall :dword, :dword 328 | SetUnhandledExceptionFilter proto stdcall :ptr 329 | SetWaitableTimer proto stdcall :dword, :ptr QWORD, :dword, :dword, :dword, :dword 330 | SizeofResource proto stdcall :dword, :dword 331 | Sleep proto stdcall :dword 332 | SuspendThread proto stdcall :dword 333 | SwitchToThread proto stdcall 334 | SystemTimeToFileTime proto stdcall :ptr SYSTEMTIME, :ptr FILETIME 335 | TerminateProcess proto stdcall :dword, :dword 336 | TerminateThread proto stdcall :dword, :dword 337 | TlsAlloc proto stdcall 338 | TlsFree proto stdcall :dword 339 | TlsGetValue proto stdcall :dword 340 | TlsSetValue proto stdcall :dword, :dword 341 | UnmapViewOfFile proto stdcall :ptr 342 | VirtualAlloc proto stdcall :dword, :dword, :dword, :dword 343 | VirtualFree proto stdcall :dword, :dword, :dword 344 | VirtualLock proto stdcall :dword, :dword 345 | VirtualProtect proto stdcall :dword, :dword, :dword, :dword 346 | VirtualQuery proto stdcall :dword, :ptr MEMORY_BASIC_INFORMATION, :dword 347 | WaitForMultipleObjects proto stdcall :dword, :ptr dword, :dword, :dword 348 | WaitForSingleObject proto stdcall :dword, :dword 349 | WideCharToMultiByte proto stdcall :DWORD, :DWORD, :ptr WORD, :DWORD, :ptr BYTE, :DWORD, :DWORD, :DWORD 350 | WinExec proto stdcall :ptr BYTE, :DWORD 351 | WriteFile proto stdcall :dword, :dword, :dword, :ptr dword, :ptr OVERLAPPED 352 | WritePrivateProfileStringA proto stdcall lpAppName:ptr BYTE, lpKeyName:ptr BYTE, lpString:ptr BYTE, lpFileName:ptr BYTE 353 | _lclose proto stdcall :dword 354 | _lcreat proto stdcall :dword, :dword 355 | _llseek proto stdcall :dword, :dword, :dword 356 | _lopen proto stdcall :dword, :dword 357 | _lread proto stdcall :dword, :dword, :dword 358 | _lwrite proto stdcall :dword, :dword, :dword 359 | lstrcat proto stdcall :ptr BYTE, :ptr BYTE 360 | lstrcatA proto stdcall :ptr BYTE, :ptr BYTE 361 | lstrcatW proto stdcall :ptr WORD, :ptr WORD 362 | lstrcmp proto stdcall :ptr BYTE, :ptr BYTE 363 | lstrcmpA proto stdcall :ptr BYTE, :ptr BYTE 364 | lstrcmpi proto stdcall :ptr BYTE, :ptr BYTE 365 | lstrcmpiA proto stdcall :ptr BYTE, :ptr BYTE 366 | lstrcpy proto stdcall :ptr BYTE, :ptr BYTE 367 | lstrcpyA proto stdcall :ptr BYTE, :ptr BYTE 368 | lstrcpyn proto stdcall :ptr BYTE, :ptr BYTE, :DWORD 369 | lstrcpynA proto stdcall :ptr BYTE, :ptr BYTE, :DWORD 370 | lstrcpynW proto stdcall :ptr WORD, :ptr WORD, :DWORD 371 | lstrlen proto stdcall :ptr BYTE 372 | lstrlenA proto stdcall :ptr BYTE 373 | lstrlenW proto stdcall :ptr WORD 374 | 375 | GetNumberOfConsoleMouseButtons proto stdcall :ptr DWORD 376 | 377 | ifdef __JWASM__ 378 | option dllimport:none 379 | endif 380 | 381 | ZeroMemory textequ 382 | FillMemory textequ 383 | CopyMemory textequ 384 | 385 | -------------------------------------------------------------------------------- /src/WDEVDD.ASM: -------------------------------------------------------------------------------- 1 | 2 | ;--- WDEVDD is a NTVDM VDD which 3 | ;--- supplies low-level access to block devices for WDE. 4 | ;--- Copyright japheth 2010-2022. 5 | ;--- Released under GNU GPL 2 license. 6 | 7 | ;--- emulated are: 8 | ;--- int 13h, ah=02h/03h/08h/41h/42h/43h/48h 9 | ;--- int 21h, ax=7305h ( add 7302h? ) 10 | ;--- int 25h 11 | ;--- int 26h 12 | ;--- int 2fh, ax=1510h 13 | 14 | .386 15 | .MODEL FLAT, stdcall 16 | option casemap:none 17 | 18 | include winbase.inc 19 | ifdef _DEBUG 20 | include winuser.inc 21 | endif 22 | include vddsvc.inc 23 | 24 | ifdef __JWASM__ 25 | @pe_file_flags = @pe_file_flags and not IMAGE_FILE_RELOCS_STRIPPED 26 | @pe_file_flags = @pe_file_flags or IMAGE_FILE_DLL 27 | endif 28 | 29 | ?RAWMODE equ 1 ; 1=support CDROM raw read mode 30 | ?CDSECADJUST equ 1 ; 1=adjust sector number for CD access 31 | 32 | ;--- CStr() define a string in .CONST 33 | 34 | CStr macro string:req 35 | local sym 36 | .const 37 | sym db string,0 38 | .code 39 | exitm 40 | endm 41 | 42 | @DbgOutC macro xx 43 | ifdef _DEBUG 44 | pushad 45 | invoke OutputDebugStringA, CStr() 46 | popad 47 | endif 48 | endm 49 | 50 | @DbgOut macro xx:REQ, parms:VARARG 51 | ifdef _DEBUG 52 | pushad 53 | invoke wsprintfA, addr szText, CStr(), parms 54 | invoke OutputDebugStringA, addr szText 55 | popad 56 | endif 57 | endm 58 | 59 | .data 60 | 61 | queried dd 0 62 | cddrvs dd 0 63 | hDisk dd -1 64 | bOldDisk dd -1 65 | bOldAccess db -1 66 | bOldMode db -1 67 | 68 | .data? 69 | 70 | ifdef _DEBUG 71 | szText db 128 dup (?) 72 | endif 73 | 74 | .code 75 | 76 | ;--- Init 77 | 78 | Init proc stdcall export 79 | 80 | @DbgOutC <"WDEVDD.Init enter",13,10> 81 | @DbgOutC <"WDEVDD.Init exit",13,10> 82 | ret 83 | align 4 84 | 85 | Init endp 86 | 87 | ;--- helper: 64bit multiplication 88 | 89 | _mul64 proc public uses esi parm1:qword, parm2:dword 90 | 91 | mov esi,parm2 92 | xor esi,dword ptr parm1+4 93 | test dword ptr parm1+4,80000000h 94 | jz @F 95 | neg dword ptr parm1+4 96 | neg dword ptr parm1+0 97 | sbb dword ptr parm1+4,+0 98 | @@: 99 | test parm2,80000000h 100 | jz @F 101 | neg parm2 102 | @@: 103 | mov eax,parm2 104 | mul dword ptr parm1+0 105 | push edx 106 | mov ecx,eax 107 | mov eax,parm2 108 | mul dword ptr parm1+4 109 | add eax,[esp] 110 | test esi,80000000h 111 | jz @F 112 | neg eax 113 | neg ecx 114 | sbb eax,+0 115 | @@: 116 | add esp,+4 117 | mov edx,eax 118 | mov eax,ecx 119 | ret 120 | align 4 121 | 122 | _mul64 endp 123 | 124 | ;--- for INT 13, AH=48 125 | 126 | I13DPARAM struct ;version 1 127 | wSize dw ? 128 | wFlags dw ? ; 129 | dwCyls dd ? ;num cylinders 130 | dwHeads dd ? ;tracks per cylinder 131 | dwSecs dd ? ;sectors per track 132 | qwNumSecs dq ? 133 | wBytSec dw ? ;bytes per sector 134 | I13DPARAM ends 135 | 136 | GetDiskParameters proc public uses ebx pszDisk:ptr BYTE, pBuffer:ptr I13DPARAM, bUseEx:byte 137 | 138 | local handle:dword 139 | local cb:dword 140 | local dg:DISK_GEOMETRY 141 | local dgX:DISK_GEOMETRY_EX 142 | 143 | invoke CreateFileA, pszDisk,\ 144 | GENERIC_READ,\ 145 | FILE_SHARE_READ or FILE_SHARE_WRITE,\ 146 | 0, OPEN_EXISTING,\ 147 | FILE_ATTRIBUTE_NORMAL, 0 148 | cmp eax,-1 149 | jz openerror 150 | mov handle, eax 151 | 152 | .if ( bUseEx ) 153 | invoke DeviceIoControl, handle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,\ 154 | 0,0, addr dgX, sizeof DISK_GEOMETRY_EX, addr cb, 0 155 | and eax, eax 156 | jz ioerror 157 | mov ebx, pBuffer 158 | mov eax,dword ptr dgX.Geometry.Cylinders 159 | mov ecx,dgX.Geometry.TracksPerCylinder 160 | mov edx,dgX.Geometry.SectorsPerTrack 161 | mov [ebx].I13DPARAM.wSize, sizeof I13DPARAM 162 | mov [ebx].I13DPARAM.dwCyls, eax 163 | mov [ebx].I13DPARAM.dwHeads, ecx 164 | mov [ebx].I13DPARAM.dwSecs, edx 165 | mov eax,dword ptr dgX.DiskSize+0 166 | mov edx,dword ptr dgX.DiskSize+4 167 | mov dword ptr [ebx].I13DPARAM.qwNumSecs+0, eax 168 | mov dword ptr [ebx].I13DPARAM.qwNumSecs+4, edx 169 | mov eax,dgX.Geometry.BytesPerSector 170 | mov [ebx].I13DPARAM.wBytSec, ax 171 | .else 172 | invoke DeviceIoControl, handle, IOCTL_DISK_GET_DRIVE_GEOMETRY,\ 173 | 0,0, addr dg, sizeof DISK_GEOMETRY, addr cb, 0 174 | and eax, eax 175 | jz ioerror 176 | mov ebx, pBuffer 177 | mov eax,dword ptr dg.Cylinders 178 | mov ecx,dg.TracksPerCylinder 179 | mov edx,dg.SectorsPerTrack 180 | mov [ebx].I13DPARAM.dwCyls, eax 181 | mov [ebx].I13DPARAM.dwHeads, ecx 182 | mov [ebx].I13DPARAM.dwSecs, edx 183 | mov eax,dg.BytesPerSector 184 | mov [ebx].I13DPARAM.wBytSec, ax 185 | .endif 186 | invoke CloseHandle, handle 187 | mov eax,1 188 | ret 189 | openerror: 190 | ifdef _DEBUG 191 | invoke GetLastError 192 | @DbgOut <"WDEVDD.GetDiskParameters open error [%X]",13,10>, eax 193 | endif 194 | xor eax,eax 195 | ret 196 | ioerror: 197 | ifdef _DEBUG 198 | invoke GetLastError 199 | @DbgOut <"WDEVDD.GetDiskParameters io error [%X]",13,10>, eax 200 | endif 201 | invoke CloseHandle, handle 202 | xor eax,eax 203 | ret 204 | 205 | align 4 206 | 207 | GetDiskParameters endp 208 | 209 | ;--- test if drive is CDROM 210 | 211 | IsCDROM proc drive:dword 212 | 213 | local szDrv[8]:byte 214 | 215 | mov eax, drive 216 | cmp eax,32 217 | jae no 218 | bts [queried], eax 219 | jc @F 220 | add al,'A' 221 | mov ah,':' 222 | mov dword ptr szDrv,eax 223 | mov szDrv+2,'\' 224 | invoke GetDriveTypeA, addr szDrv 225 | cmp eax, DRIVE_CDROM 226 | jnz @F 227 | mov eax,[drive] 228 | bts [cddrvs],eax 229 | @@: 230 | mov eax,[drive] 231 | bt [cddrvs], eax 232 | jc yes 233 | no: 234 | xor eax, eax 235 | ret 236 | yes: 237 | mov eax,1 238 | ret 239 | align 4 240 | 241 | IsCDROM endp 242 | 243 | ;--- int 21h, ax=7305: 244 | ;--- DL=drive (01=A:, ...) 245 | ;--- SI=read/write mode flags (0=read,1=write) 246 | ;--- DS:BX=disk packet 247 | 248 | ;--- int 25h/26h 249 | ;--- AL=drive (00=A:, ...) 250 | ;--- CX=sector numbers or FFFFh 251 | ;--- if CX != FFFF 252 | ;--- DX=start sector number 253 | ;--- DS:BX=read/write buffer 254 | ;--- if CX == FFFF 255 | ;--- DX=start sector number 256 | ;--- DS:BX=disk packet 257 | 258 | ;--- int 2Fh, ax=1510: (read/write long) 259 | ;--- CX=drive letter (0=A,...) 260 | ;--- ES:BX=device driver request 261 | 262 | DPACKET struct 263 | secsta dd ? 264 | seccnt dw ? 265 | bufofs dw ? 266 | bufseg dw ? 267 | DPACKET ends 268 | 269 | if ?RAWMODE 270 | RAW_READ_INFO struct 271 | DiskOffset dq ? 272 | SectorCount dd ? 273 | TrackMode dd ? 274 | RAW_READ_INFO ends 275 | endif 276 | 277 | ;--- drive access emulation 278 | ;--- bType: 279 | ;--- 0=Int 21h, ax=7305h 280 | ;--- 1=Int 25h/26h 281 | ;--- 2=Int 2Fh, ax=1510h 282 | ;--- bWrite: 0=read, 1=write (for bType=1 only) 283 | ;--- wAX: value of register AX in VDM 284 | ;--- this proc modifies EBX and EDI 285 | 286 | drive_access proc bType:byte, bWrite:byte, wAX:word 287 | 288 | local drive:dword 289 | ;local hDisk:dword 290 | local dwRead:dword 291 | local dwBuffer:dword 292 | local secsize:dword 293 | local cdmode:byte 294 | local szDrv[8]:byte 295 | local tmppkt:DPACKET 296 | local bMode:dword 297 | if ?RAWMODE 298 | local rri:RAW_READ_INFO 299 | endif 300 | 301 | invoke getMSW 302 | and eax, 1 303 | mov bMode, eax 304 | invoke getEBX 305 | movzx edi, ax ; 16bit offset! 306 | invoke getDS 307 | invoke VdmMapFlat, eax, edi, bMode 308 | mov ebx, eax 309 | .if ( bType == 1 ) 310 | movzx eax, byte ptr wAX 311 | mov drive, eax 312 | invoke getECX 313 | .if ( ax != 0FFFFh ) 314 | lea ebx, tmppkt 315 | mov [ebx].DPACKET.seccnt, ax 316 | invoke getEDX 317 | movzx eax,ax 318 | mov [ebx].DPACKET.secsta, eax 319 | invoke getEBX 320 | mov [ebx].DPACKET.bufofs, ax 321 | invoke getDS 322 | mov [ebx].DPACKET.bufseg, ax 323 | .endif 324 | .elseif ( bType == 2 ) 325 | invoke getCX 326 | mov drive, eax 327 | invoke getEBX 328 | movzx edi,ax 329 | invoke getES 330 | invoke VdmMapFlat, eax, edi, bMode 331 | mov edi, eax 332 | cmp byte ptr [edi+2],134 ;134=write long 333 | jnz @F 334 | mov bWrite,1 335 | @@: 336 | lea ebx, tmppkt 337 | mov ax, [edi+18] 338 | mov [ebx].DPACKET.seccnt, ax 339 | mov eax, [edi+20] 340 | mov [ebx].DPACKET.secsta, eax 341 | mov ax, [edi+14] 342 | mov [ebx].DPACKET.bufofs, ax 343 | mov ax, [edi+16] 344 | mov [ebx].DPACKET.bufseg, ax 345 | mov al, [edi+24] 346 | mov cdmode,al ; 0=cooked, 1=raw 347 | .else 348 | invoke getEDX 349 | movzx eax, al 350 | dec al 351 | mov drive, eax 352 | invoke getESI 353 | and al,1 354 | mov bWrite, al ; 0=read, 1=write 355 | .endif 356 | 357 | movzx ecx,[ebx].DPACKET.bufofs 358 | movzx eax,[ebx].DPACKET.bufseg 359 | invoke VdmMapFlat, eax, ecx, bMode 360 | mov dwBuffer, eax 361 | 362 | cmp bType, 2 363 | jz @F 364 | invoke IsCDROM, drive 365 | and eax, eax 366 | jnz typeerror 367 | @@: 368 | @DbgOut <"WDEVDD.drive_access, drv=%s, packet=%X [cnt=%u, start=%X, buf=%X:%X], buffer=%X",13,10>,\ 369 | addr szDrv, ebx, [ebx].DPACKET.seccnt, [ebx].DPACKET.secsta, [ebx].DPACKET.bufseg, [ebx].DPACKET.bufofs 370 | 371 | mov eax,[drive] 372 | add al,'A' 373 | mov ah,':' 374 | movzx eax,ax 375 | mov cl, bWrite 376 | .if eax != [bOldDisk] || cl != [bOldAccess] || bOldMode != 0 377 | mov [bOldDisk], eax 378 | mov [bOldAccess], cl 379 | mov bOldMode, 0 380 | mov dword ptr szDrv+0,"\.\\" 381 | mov dword ptr szDrv+4,eax 382 | .if hDisk != -1 383 | invoke CloseHandle, hDisk 384 | mov hDisk, -1 385 | .endif 386 | 387 | mov ecx, GENERIC_READ 388 | .if (bWrite) 389 | or ecx, GENERIC_WRITE 390 | .endif 391 | invoke CreateFileA, addr szDrv, ecx, FILE_SHARE_READ or FILE_SHARE_WRITE,\ 392 | 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 393 | cmp eax,-1 394 | jz openerror 395 | mov hDisk, eax 396 | .endif 397 | mov eax, [ebx].DPACKET.secsta 398 | mov edx,512 399 | cmp bType, 2 400 | jnz @F 401 | mov edx,2048 ;or 2352 402 | cmp cdmode,1 403 | jnz @F 404 | mov edx,2352 405 | if ?RAWMODE 406 | call rawreadcd 407 | jmp io_done 408 | endif 409 | @@: 410 | mov secsize, edx 411 | mul edx 412 | push edx 413 | mov edx, esp 414 | invoke SetFilePointer, hDisk, eax, edx, 0 415 | pop edx 416 | cmp eax, INVALID_SET_FILE_POINTER 417 | jnz @F 418 | invoke GetLastError 419 | cmp eax, NO_ERROR 420 | jnz poserror 421 | @@: 422 | movzx ecx,[ebx].DPACKET.seccnt 423 | imul ecx, secsize 424 | .if (bWrite) 425 | invoke WriteFile, hDisk, dwBuffer, ecx, addr dwRead, 0 426 | .else 427 | invoke ReadFile, hDisk, dwBuffer, ecx, addr dwRead, 0 428 | .endif 429 | io_done: 430 | if 0 431 | push eax 432 | invoke CloseHandle, hDisk 433 | pop eax 434 | endif 435 | and eax, eax 436 | jz accerror 437 | invoke setCF, 0 438 | ret 439 | accerror: 440 | ifdef _DEBUG 441 | invoke GetLastError 442 | @DbgOut <"WDEVDD.drive_access access error [%X]",13,10>, eax 443 | jmp generror 444 | endif 445 | poserror: 446 | ifdef _DEBUG 447 | @DbgOut <"WDEVDD.drive_access pos error [%X]",13,10>, eax 448 | jmp generror 449 | endif 450 | openerror: 451 | ifdef _DEBUG 452 | invoke GetLastError 453 | @DbgOut <"WDEVDD.drive_access open error [%X]",13,10>, eax 454 | jmp generror 455 | endif 456 | typeerror: 457 | ifdef _DEBUG 458 | @DbgOutC <"WDEVDD.drive_access type error",13,10> 459 | jmp generror 460 | endif 461 | generror: 462 | invoke setAX, 0Ch ;general failure 463 | invoke setCF, 1 464 | ret 465 | if ?RAWMODE 466 | rawreadcd: 467 | mov secsize, edx 468 | movzx ecx, [ebx].DPACKET.seccnt 469 | mov eax, [ebx].DPACKET.secsta 470 | mov rri.SectorCount, ecx 471 | if ?CDSECADJUST 472 | add eax, 32 ;to match what WDE returns without WDEVDD 473 | endif 474 | @DbgOut <"WDEVDD.drive_access CD-ROM raw read, true start sector=%u, cnt=%u",13,10>, eax, ecx 475 | mov edx, 2048 ;!? 476 | mul edx 477 | mov dword ptr rri.DiskOffset+0, eax 478 | mov dword ptr rri.DiskOffset+4, edx 479 | mov rri.TrackMode, CDDA 480 | movzx ecx,[ebx].DPACKET.seccnt 481 | imul ecx, secsize 482 | invoke DeviceIoControl, hDisk, IOCTL_CDROM_RAW_READ, addr rri, 483 | sizeof RAW_READ_INFO, dwBuffer, ecx, addr dwRead, 0 484 | retn 485 | endif 486 | 487 | align 4 488 | drive_access endp 489 | 490 | ;--- CH=low bits cylinder number 491 | ;--- CL=sector + high bits cylinder number 492 | 493 | I13DPARAM struct ;version 1 494 | wSize dw ? 495 | wFlags dw ? 496 | dwCyls dd ? ;num cylinders 497 | dwHeads dd ? ;tracks per cylinder 498 | dwSecs dd ? ;sectors per track 499 | qwNumSecs dq ? 500 | wBytSec dw ? ;bytes per sector 501 | I13DPARAM ends 502 | 503 | set1308 proc params:ptr I13DPARAM 504 | mov edx, params 505 | mov al,byte ptr [edx].I13DPARAM.dwSecs 506 | .if ( [edx].I13DPARAM.dwCyls > 1024 ) 507 | mov ah,0FFh 508 | or al,11000000b 509 | .else 510 | mov ecx,[edx].I13DPARAM.dwCyls 511 | dec ecx 512 | mov ah,cl 513 | shl ch,6 514 | or al,ch 515 | .endif 516 | invoke setCX, eax 517 | mov ah,byte ptr [edx].I13DPARAM.dwHeads 518 | dec ah 519 | mov al,1 520 | invoke setDX, eax 521 | ret 522 | align 4 523 | set1308 endp 524 | 525 | ;--- disk access emulation ( int 13h ) 526 | ;--- wAX: value of register AX in VDM 527 | ;--- this proc modifies EDI. 528 | ;--- supported is AH=02/03/08/42h/43h/48h 529 | 530 | I13PACKET struct 531 | wSize dw ? 532 | wBlocks dw ? 533 | dwBuffer dd ? 534 | qwStart dq ? ;start block 535 | I13PACKET ends 536 | 537 | disk_access proc wAX:word 538 | 539 | local bIsFD:byte 540 | local bWrite:byte 541 | local drive:dword 542 | ;local hDisk:dword 543 | local dwRead:dword 544 | local dwBuffer:dword 545 | local bMode:dword 546 | local szDrv[24]:byte 547 | local tmppkt:I13PACKET 548 | local drvparam:I13DPARAM 549 | 550 | invoke getMSW 551 | and eax,1 552 | mov bMode, eax 553 | mov bWrite, 0 554 | invoke getEDX 555 | movzx eax, al 556 | .if ( al & 80h ) 557 | mov bIsFD, 0 558 | .else 559 | mov bIsFD, 1 560 | .endif 561 | and eax, 7Fh 562 | mov drive, eax 563 | invoke lstrcpyA, addr szDrv, CStr("\\.\PhysicalDrive") 564 | mov eax, drive 565 | add al,'0' 566 | mov word ptr szDrv+17,ax 567 | 568 | movzx eax, wAX 569 | .if ( ah == 2 || ah == 3 ) 570 | .if ( ah == 3 ) 571 | mov bWrite, 1 572 | .endif 573 | lea edi, tmppkt 574 | movzx ax, al 575 | mov [edi].I13PACKET.wBlocks, ax 576 | 577 | invoke GetDiskParameters, addr szDrv, addr drvparam, 0 578 | and eax, eax 579 | jz diskerror 580 | 581 | invoke getEBX 582 | movzx ecx,ax ;16bit offset! 583 | push ecx 584 | invoke getES 585 | pop ecx 586 | invoke VdmMapFlat, eax, ecx, bMode 587 | mov dwBuffer, eax 588 | .elseif ( ah == 8 ) 589 | invoke GetDiskParameters, addr szDrv, addr drvparam, 0 590 | and eax, eax 591 | jz diskerror 592 | invoke set1308, addr drvparam 593 | jmp exit 594 | .elseif ( ah == 41h ) 595 | invoke getEBX 596 | .if ax == 55AAh 597 | xchg ah, al 598 | invoke setEBX, eax 599 | .endif 600 | invoke getECX 601 | or al, 101b ; set bits 0 (ah=42h/43h supported) and 2 (?) 602 | invoke setECX, eax 603 | jmp exit 604 | .elseif ( ah == 42h || ah == 43h ) 605 | .if ( ah == 43h ) 606 | mov bWrite, 1 607 | .endif 608 | invoke getESI 609 | movzx edi,ax ;16bit offset! 610 | invoke getDS 611 | invoke VdmMapFlat, eax, edi, bMode 612 | mov edi, eax ;EDI -> I13PACKET 613 | movzx eax, word ptr [edi].I13PACKET.dwBuffer+0 614 | movzx edx, word ptr [edi].I13PACKET.dwBuffer+2 615 | invoke VdmMapFlat, edx, eax, bMode 616 | mov dwBuffer, eax 617 | .elseif ( ah == 48h ) 618 | invoke getESI 619 | movzx eax,ax ;16bit offset! 620 | push eax 621 | invoke getDS 622 | pop ecx 623 | invoke VdmMapFlat, eax, ecx, bMode 624 | invoke GetDiskParameters, addr szDrv, eax, 1 625 | and eax, eax 626 | jz diskerror 627 | jmp exit 628 | .else 629 | @DbgOut <"WDEVDD.disk_access, ax=%X not supported",13,10>, eax 630 | jmp generror ;unsupported 631 | .endif 632 | 633 | @DbgOut <"WDEVDD.disk_access, drv=%u, packet=%X [secs=%u, buf=%X, start=%X], buffer=%X",13,10>,\ 634 | drive, edi, [edi].I13PACKET.wBlocks, [edi].I13PACKET.dwBuffer, dword ptr [edi].I13PACKET.qwStart, dwBuffer 635 | 636 | .if (bIsFD ) 637 | jmp accerror ;FD access not supported, use disk access 638 | .endif 639 | 640 | mov eax, drive 641 | mov cl, bWrite 642 | .if eax != [bOldDisk] || [bOldAccess] != cl || bOldMode != 1 643 | mov [bOldDisk], eax 644 | mov cl, bWrite 645 | mov [bOldAccess], cl 646 | mov bOldMode, 1 647 | .if hDisk != -1 648 | invoke CloseHandle, hDisk 649 | mov hDisk, -1 650 | .endif 651 | mov ecx, GENERIC_READ 652 | .if (bWrite) 653 | or ecx, GENERIC_WRITE 654 | .endif 655 | invoke CreateFileA, addr szDrv, ecx, FILE_SHARE_READ or FILE_SHARE_WRITE,\ 656 | 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 657 | cmp eax,-1 658 | jz openerror 659 | mov hDisk, eax 660 | .endif 661 | 662 | invoke _mul64, [edi].I13PACKET.qwStart, 512 663 | push edx 664 | mov edx, esp 665 | invoke SetFilePointer, hDisk, eax, edx, 0 666 | pop edx 667 | cmp eax, INVALID_SET_FILE_POINTER 668 | jnz @F 669 | invoke GetLastError 670 | cmp eax, NO_ERROR 671 | jnz poserror 672 | @@: 673 | movzx ecx,[edi].I13PACKET.wBlocks 674 | shl ecx,9 675 | .if (bWrite) 676 | invoke WriteFile, hDisk, dwBuffer, ecx, addr dwRead, 0 677 | .else 678 | invoke ReadFile, hDisk, dwBuffer, ecx, addr dwRead, 0 679 | .endif 680 | if 0 681 | push eax 682 | invoke CloseHandle, hDisk 683 | pop eax 684 | endif 685 | and eax, eax 686 | jz accerror 687 | exit: 688 | invoke setCF, 0 689 | ret 690 | diskerror: 691 | ifdef _DEBUG 692 | invoke GetLastError 693 | @DbgOut <"WDEVDD.disk_access disk error",13,10>, eax 694 | jmp generror 695 | endif 696 | accerror: 697 | ifdef _DEBUG 698 | invoke GetLastError 699 | @DbgOut <"WDEVDD.disk_access access error [%X]",13,10>, eax 700 | jmp generror 701 | endif 702 | poserror: 703 | ifdef _DEBUG 704 | @DbgOut <"WDEVDD.disk_access pos error [%X]",13,10>, eax 705 | jmp generror 706 | endif 707 | openerror: 708 | ifdef _DEBUG 709 | invoke GetLastError 710 | @DbgOut <"WDEVDD.disk_access open error, file=%s [%X]",13,10>, addr szDrv, eax 711 | jmp generror 712 | endif 713 | generror: 714 | invoke setAX, 0Ch ;general failure 715 | invoke setCF, 1 716 | ret 717 | 718 | ;--- translate CHS to LBA 719 | ;--- cl=maxcyl[8-9]+sectors/track in lowest 6 bits 720 | ;--- ch=maxcyl[0-7] 721 | ;--- dh=maxhead 722 | 723 | Chs2Lba: 724 | mov ah,cl 725 | shr ah,6 726 | mov al,ch 727 | movzx eax,ax 728 | inc eax ;cylinder in eax 729 | mov dl,dh 730 | movzx edx,dl 731 | inc edx ;heads in edx 732 | and cl,3Fh 733 | movzx ecx,cl 734 | retn 735 | 736 | align 4 737 | 738 | disk_access endp 739 | 740 | ;--- Dispatch 741 | ;--- int number is found in real-mode SS:[SP+0] 742 | ;--- value of register AX is found in real-mode SS:[SP+2] 743 | 744 | Dispatch proc stdcall export uses ebx esi edi 745 | 746 | local bMode:dword 747 | 748 | @DbgOutC <"WDEVDD.Dispatch enter",13,10> 749 | invoke getMSW 750 | and eax,1 751 | mov bMode, eax 752 | invoke getESP 753 | movzx ebx, ax 754 | invoke getSS 755 | movzx eax, ax 756 | invoke VdmMapFlat, eax, ebx, bMode 757 | movzx edi,word ptr [eax+0] ;int number 758 | movzx esi,word ptr [eax+2] ;VDM value of AX 759 | @DbgOut <"WDEVDD.Dispatch: emulate INT %02Xh, ax=%04X, sp=%04X",13,10>, edi, esi, ebx 760 | add bx, 4 761 | invoke setESP, ebx 762 | invoke setAX, si ;restore AX value 763 | 764 | ;--- ebx contains flat address of ss:sp 765 | 766 | .if di == 13h 767 | invoke disk_access, si 768 | .elseif di == 21h 769 | .if si == 7305h 770 | invoke drive_access, 0, 0, si 771 | .else 772 | @DbgOutC <"WDEVDD.Dispatch: can't handle this call",13,10> 773 | jmp error 774 | .endif 775 | .elseif di == 25h 776 | invoke drive_access, 1, 0, si 777 | .elseif di == 26h 778 | invoke drive_access, 1, 1, si 779 | .elseif di == 2Fh 780 | .if si == 1510h 781 | invoke drive_access, 2, 0, si 782 | .else 783 | @DbgOutC <"WDEVDD.Dispatch: can't handle this call",13,10> 784 | jmp error 785 | .endif 786 | .elseif di == 41h ; string to display in DS:DX 787 | invoke getDX 788 | movzx ebx, ax 789 | invoke getDS 790 | invoke VdmMapFlat, eax, ebx, bMode 791 | mov esi, eax 792 | .while byte ptr [esi] ; go to end of string 793 | inc esi 794 | .endw 795 | mov byte ptr [esi-1], 0 ; remove the '$' 796 | invoke OutputDebugStringA, eax 797 | .else 798 | @DbgOutC <"WDEVDD.Dispatch: can't handle this call",13,10> 799 | jmp error 800 | .endif 801 | exit: 802 | @DbgOutC <"WDEVDD.Dispatch exit",13,10> 803 | ret 804 | error: 805 | invoke setCF,1 806 | jmp exit 807 | align 4 808 | Dispatch endp 809 | 810 | ;*** main proc *** 811 | 812 | DllMain proc stdcall hInstance:dword, reason:dword, lpReserved:dword 813 | 814 | mov eax, reason 815 | .if (eax == DLL_PROCESS_ATTACH) 816 | @DbgOutC <"wdevdd process attach",13,10> 817 | mov eax,1 818 | .elseif (eax == DLL_PROCESS_DETACH) 819 | .if hDisk != -1 820 | invoke CloseHandle, hDisk 821 | .endif 822 | @DbgOutC <"wdevdd process detach",13,10> 823 | .elseif (eax == DLL_THREAD_ATTACH) 824 | @DbgOutC <"wdevdd thread attach",13,10> 825 | .elseif (eax == DLL_THREAD_DETACH) 826 | @DbgOutC <"wdevdd thread detach",13,10> 827 | .endif 828 | ret 829 | DllMain endp 830 | 831 | END DllMain 832 | 833 | -------------------------------------------------------------------------------- /changes.txt: -------------------------------------------------------------------------------- 1 | WDe Copyright(C)2005 Ben Cadieux (ben.cadieux@gmail.com), Japheth. 2 | 3 | WDe V1.1 [20.10.2024] 4 | - fixed: mounting logical drives from image files didn't adjust the 5 | "last sector", thus cluster numbers beyond logical disk size weren't 6 | rejected. 7 | - fixed: if current device was an image file, hitting Ctrl-Enter while 8 | in sector 0 of a logical drive did switch to a real physical disk. 9 | - save file chain: last update date & time now copied. 10 | - cmdline option -n added. 11 | - Goto menu: exchanged "Goto Boot Sector" and "Goto Cluster". 12 | - FAT directory sectors: LFNs in ASCII region displayed light green. 13 | - file AND directory names are accepted. 14 | 15 | WDe V1.00 [08.11.2022] 16 | - rearranged startup code so there's no writing to the screen before 17 | main() has been reached; makes debuggers happy. 18 | - added timer.inc ( used by debug version ) 19 | - wdex.com: restore pm interrupt vectors. 20 | - quick exit if no EGA/VGA detected. 21 | - wrong checksum of LFN entries detected. 22 | - accept (some) OEM chars in SFNs (oemchar.inc, oembittab) 23 | - fixed: sometimes, "chain" menu item was shown, but key F7 didn't 24 | start the op. 25 | - if a directory is to be saved as a file chain, don't ask if file 26 | is to be truncated ( since file size is always 0 then ). 27 | - added support for GPT-partitioned disks. 28 | - MBR view changed to a more readable table format. 29 | - in MBR, pressing Enter while cursor is positioned within a partition 30 | entry jumps to that partition. 31 | - fixed: changing drive or using "restrict" must invalidate items on 32 | sector stack. 33 | - fixed: save/restore root directory for FAT32 did save/restore just 34 | the first cluster ( was a "known bug" ). 35 | - fixed: internal var "sectors/cluster" was 8 bits only, too small for exFAT. 36 | - fixed: distinction FAT16/FAT32 wasn't foolproof. 37 | - fixed: restoring a sector range from file did ignore trailing bytes 38 | behind the last full sector. Also, if file size was < sector size, the 39 | restore was rejected ( error "File too small" ). 40 | 41 | WDe V0.99 [20.06.2022] 42 | - fixed: menu line restore after i/o error didn't work in v0.50. 43 | - fixed: to enter a cluster# in "goto cluster" did jump to a wrong 44 | cluster if cluster number contained a '9'. 45 | - fixed: Alt-Left at cluster 2 caused an error with a strange cluster#. 46 | - fixed: unformat FAT12/FAT16 didn't work in v0.50 47 | - fixed: unformat works for FAT32. 48 | - fixed: unformat may have stopped prematurely, leaving the disk in 49 | a corrupted state. 50 | - fixed: in v0.50, WDe had problems to handle image files correctly. 51 | - fixed: when restoring a file chain and the source file was a bit smaller 52 | than what's stored in the directory entry, WDe did show that last 53 | sector after the copy process. 54 | - fixed: function "find MBR" wasn't correct - did check 3 entries only, 55 | and assumed word at offset 1FCh to be 0000. 56 | - fixed: find MBR/BS/FAT/Dir displayed a wrong sector if the item was 57 | "found" in the current sector. 58 | - in directory view, files and directory names are displayed in different 59 | colors, the rest is darkened a bit ( light grey ). 60 | - filenames now accepted as cmdline parameters. 61 | - -m cmdline option may now be entered without number. 62 | - added option -8 to setm43.exe and setm432.exe. 63 | - debug version writes to debug terminal when running in a NTVDM. 64 | 65 | 66 | WDe V0.50 [12.05.2022] 67 | - fixed: restore chain didn't work in v0.50pre1. 68 | - restore exFAT file chains implemented. 69 | - fixed: restore partition didn't restore last sector. 70 | - fixed: menuitem "unformat" removed for exFAT. 71 | - fixed: for "undelete", before the FAT is modified, it's first checked 72 | if there're enough free contiguous clusters at the required location; 73 | if no, the file is optionally truncated or the operation canceled. 74 | Hence error "File chain exceeds FAT" obsolete and removed. 75 | - fixed: in v0.50pre, the last cluster of exFAT was not accessible. 76 | - in FAT view, entries beyond last cluster# are displayed with "-". 77 | - with image files, bytes/sector are no longer fixed to 512. 78 | - exFAT primary file entries: created & modified timestamps displayed in view. 79 | - exFAT file stream entries: 64-bit file size fully displayed in view. 80 | - significant speed-up for "save to file" function. 81 | - in "save to file", file "chain", pressing TAB presets filename to enter 82 | with the filename from the directory entries. 83 | - up to 255 chars may be entered as long filenames in bottom line. 84 | - main menu: F1 display help now, "Save" moved to F7. 85 | - huge speed-up for "find" and "fill" (string & hex). 86 | - another variant of tool setm43, setm432, added. 87 | - check for invalid LFNs added in dirview. 88 | - screen color softened if no user input possible in main area. 89 | - in data region of FAT file systems, if the current cluster# is 90 | associated with a file ( that is, not a free cluster# ), it is shown 91 | in light green. 92 | - fixed: find MBR didn't work. 93 | - speed-up for "recurse" ( searching "linking" entry ) scan in FAT. 94 | - added navigation Ctrl-Enter in FAT: search directory entry with matching 95 | start cluster. 96 | - added navigation Ctrl-Right in data area: search previous cluster in 97 | chain. 98 | 99 | WDe V0.50pre1 [24.04.2022] 100 | - the non-menu keys ( cursor movement, sector editing, ... ) 101 | will work in all menus, not just in the main menu. 102 | - directory view changed, displays 1 item only, detects and shows 103 | LFN entries. 104 | - option -s ( safe mode ) added. 105 | - optionally build wdex.com, a WDe running as DPMI client. 106 | - fixed: recursing a chain searched "below" the current cluster only; 107 | this didn't guarantee that the linking cluster ( the predecessor ) 108 | was found. OTOH, this fix has the effect that the recurse scan will 109 | take quite a bit longer if the current cluster is the start of a 110 | chain. 111 | - wdevdd.dll: adjusted to also work with protected-mode apps ( wdex.com ). 112 | - regression in v0.40: ctrl-left inside FAT didn't work if the entry 113 | was located in a different sector. 114 | - menu item "disk" moved to "file" submenu, new menu item "help" added 115 | to main menu. 116 | - wdevdd.dll got a significant speed-up, making lengthy operations 117 | under WinXP/Vista ( "find", "fill", "recurse", ... ) usable. 118 | - fixed: logical disks with format NTFS are no longer handled like FAT disks. 119 | - support for exFAT file system implemented - it's experimental so far. 120 | Under DOS, to investigate exFAT partitions, one will heve to use the 121 | "restrict" option, since DOS itself doesn't know how to mount such 122 | partitions. 123 | - option -m ( mount partition as logical drive ) added. 124 | - string enter function has improved edit capabilities. 125 | - if available, WDe now uses LFN functions for file open/create. 126 | - Alt+Right/Left navigation ( forward/back 1 cluster ) added. 127 | 128 | WDe V0.40 [13.04.2022] 129 | - decimal numbers now displayed without leading zeros. 130 | - input of numeric data is now checked only after the return key has 131 | been pressed. 132 | - fixed: find directory in v0.33 didn't update the screen until ESC 133 | has been pressed. 134 | - fixed: if the string to be found began at offset 0 of next sector, 135 | the cursor wasn't positioned correctly. 136 | - prompts for entering sectors/cluster show hints about valid range. 137 | - fixed: menu item "file ops" may have displayed a wrong submenu in 138 | v0.33 if current sector was in data region. 139 | - lengthy operations will display progress in bottom line. 140 | - memory model changed to small to increase data segment to 64 kB 141 | and allow to implement dynamically allocated buffers. 142 | - fixed: restoring file/fat chain gave wrong or misleading feedback. 143 | - string search fastened (but still room for improvements). 144 | - enclose current entry in directory view with '>' and '<'. 145 | - implemented a small (8 items) "sector stack" to be used by Ctrl-Up. 146 | Supposed to revert Enter, Ctrl-Enter or Ctrl-Left keys. 147 | 148 | WDe V0.33 [01.04.2022] 149 | - set video attributes only in the 80x43 area in case current video mode 150 | has more rows/cols. 151 | - ensure that displays are done in current video page. 152 | - fixed: switching between hex and binary mode didn't clear the first data 153 | line. 154 | - fixed: if HD access had to use int 13h, ah=3 ("old" write function), 155 | a wrong address (read buffer instead of write buffer) was used. 156 | - added SETM43 tool. If it works with the graphics card, WDE's look 157 | might improve since a 8x14 font (instead of 8x8) is used then. 158 | - accept 'x:' or 'xH'/'xF' on the command line when WDe is started. 159 | - source changed to true tiny model (reduces binary size). 160 | - lot of "spaghetti" code cleaned. 161 | - find function will move cursor to the start of the found string. 162 | - Home/End key in main menu move cursor to start/end of current sector. 163 | - "find next" function added. Also, find will now start from cursor 164 | position in current sector, not from the current sector's start. 165 | 166 | WDe V0.32 [17.03.2022] 167 | - don't change video mode if current mode has at least 43 lines. 168 | 169 | WDe V0.31 [21.02.2010] 170 | - added WDEVDD to allow WDE running in Windows XP. 171 | 172 | WDe V0.30b [??/??/??] 173 | - fixed a small bug in the hex printing code 174 | - separated int 13h buffers for getting drive info and reading/writing, 175 | - reversed display of attribute bits in directory view to match binary 176 | - fixed root cluster number display bug 177 | - enhanced finding MBR; less chance of a false positive 178 | - sector saving/restoring can no longer read/write outside drive parameters 179 | - fixed bug in fat functions allowing them to read/write past fat tables 180 | - added workaround to Win9x bug for theoretical writes to CD-Roms 181 | - fixed bootsector display bug that occurred under certain conditions 182 | - read functions fixed and reversed back to oldest to newest 183 | - fixed bug switching to drives that were unable to be edited 184 | - optimized code that converts values to hex strings 185 | - modified menu system to be more versatile 186 | - fixed bug getting fat entry data for last few allowable clusters 187 | on maximally sized Fat12 and Fat16 partitions 188 | - enhanced/corrected directory detection; less false negatives/positives 189 | - updated file/path character checking; this further improves directory 190 | finding and accepts more characters as valid input when undeleting 191 | - unformat function has been re-designed, re-written and implemented 192 | - bytes per sector returned by int 13h/48h now used for hard disks 193 | - hitting enter in the fat area now works regardless of the view set 194 | - fixed bug causing restore chain to default to second fat in directories 195 | - fixed rare bug causing Fat16 partitions to be shown as Fat32 196 | - file sharing violation crashes under windows fixed by having int 24h 197 | return "fail" instruction to the calling code 198 | - running out of disk space while writing a file now aborts with an error 199 | - last sector bound now kept for non-physical drives restricted as physical 200 | - restricting above as physical now always correctly sets last sector 201 | - defaults to Fat1 if saving/restoring Fat2 when none exists 202 | - fixed major partition saving bug (saving was starting at MBR) 203 | - fixed partition saving/restoring bug causing it to miss last sector 204 | - fixed CHS display code for high sector numbers 205 | - CHS no longer displayed when switching from physical to non-physical 206 | - workarounds added for CHS reading with poorly written BIOSes 207 | - searching for String/Hex on CDs no longer randomly stops 208 | - excessive amounts of code clean-up & optimization for speed and size 209 | - much better system implemented to generate random values 210 | - fixed some fat type detection problems 211 | - MBR view now shows Linux, FreeBSD and NTFS as partition types 212 | 213 | WDe V0.21b [04/17/04] 214 | - read functions now attempted from newest to oldest (DrDOS fat32 fix) 215 | - fat type detection always relies on number of clusters now 216 | - re-wrote logical to physical jumping; works for fat1x now 217 | - fixed calculation bug for root if it isn't early on the drive 218 | - binary editing is now supported (SHIFT+TAB) 219 | - added Raw/Cooked CD reading option (for use with all functions now) 220 | - current sector numbers now showed for all save/restore sector functions 221 | - can no longer jump beyond the end of the drive with goto functions 222 | - added some proper support for non-standard sized sectors 223 | - old int 13h functions for backwards compatibility were reliant on new 224 | int 13h functions to get last sector number; fixed this 225 | - recurse and chain saving functions now work with the second fat (slower?) 226 | - added some unreadable sector compensation (fill with null) 227 | - for searches, unreadable sector skipping added 228 | - optimized CHS printing code for physical reads 229 | - cleaned writefile function; fixed two chain saving bugs 230 | - removed forgotten debug code for switching to CDs (displayed '06') 231 | - optimized and centralized a lot of screen and cursor code 232 | - re-implemented CD reading code; fixed some bugs (including dump as ISO) 233 | - cleaned/optimized various parts of the code; added some debug options 234 | - centralized sector saving code 235 | - re-wrote some fat12 support functions 236 | - re-wrote and centralized current fat entry calculations 237 | - jumping to linked clusters in the data area now aborts if fat entry is 0 238 | - fixed tiny fat12 finding bug that produced more false positives 239 | - CD fat12 view function problems fixed 240 | - bug using fat12 view on the last sector of the drive fixed 241 | - fixed annoying "file size too big" bug saving sectors to files 242 | - moved some code to where it belongs so the view area no longer gets 243 | wiped when it's not supposed to while performing certain functions 244 | - fixed screen-destroying bug saving sectors from physical drives 245 | - fixed bug not allowing aborting from sector saving 246 | - fixed bug getting dword values for 32-bit fill functions 247 | - aborting with escape key now possible with fill functions 248 | - fixed small logic flaw checking if a file to be written is too large 249 | - fixed small bug with fat16 fat cluster jumping & chain saving 250 | - fixed serious off-by-1 error with fat saving/restoring for the second fat 251 | - fixed tiny fat16 cluster jumping bugs with chain ending entries 252 | - centralized some filling function code 253 | - fixed bug losing high word with 32-bit fill functions 254 | - fixed logic error with decrement rollover for 12-bit fill function 255 | - fixed bug writing across sector limits with putfatentry for fat12 256 | - fixed bootsector view for fat1x showing hard drive number 257 | - MBR finding code much better; now finds MBRs created by more OSes 258 | - updated directory finding function to be slightly more strict 259 | - fixed year digit highlighting for directory view 260 | - cluster number now shows in fat32 root regions 261 | - fixed logic flaw in string/hex searches 262 | - set cursor position now uses bios; speed no longer needed 263 | - files can now be read as drives (TAB instead of choosing a drive) 264 | - limiting a sector range as a drive is now possible 265 | - fixed some bugs with saving/restoring partitions 266 | 267 | WDe V0.20 [03/06/04] 268 | - jumping support for CDs cut down to sectors 269 | - support for direct reading of floppies (using 13h) added 270 | - undelete function can no longer accidentally write past fat1 271 | - directory detection now works with fat drives touched by Windows NT 272 | - int 24h is now hooked to handle errors that once crashed WDe 273 | - fixed small directory highlighting bug with modified time 274 | - 'CHS:' displayed when using extended int 13h functions 275 | - ISOs will automatically be dumped in RAW mode if possible 276 | - fat chain and file saving/restoring added 277 | - ctrl+left now recurses in the fat/data 278 | - now "Searching..." is always displayed while doing searches 279 | - full 4-digit dates now displayed in directory view 280 | - save/restore sectors now show the sector number being worked with 281 | 282 | WDe V0.19 [08/24/02] 283 | - optimizations 284 | - added fill functions 285 | - added 'unknown' to fsinfo view 286 | - only the 'delete' key now writes nulls when ascii editing 287 | - fixed bug saving fat 288 | - fixed nasty bug saving sectors 289 | - fixed small bug entering "jump to cluster" values 290 | - fixed small bug when switching from fat32 to fat1x 291 | - fixed remainder of ctrl+right fat12 bug 292 | - jumping to fat2 now jumps to fat1 when there is no fat2 293 | - append option added for file writing 294 | - file undelete function added 295 | 296 | WDe V0.18 [07/29/02] 297 | - fixed possible file handle bug 298 | - added "tab" to switch between ascii/hex editing 299 | - partition starts no longer show boot sector view by default 300 | - MBR view shows "Unused" when partition type is 00h 301 | - ctrl+enter in sector 0 of a logical drive now jumps to the 302 | physical drive that partition is on 303 | - logical to physical drive switching no longer shows cluster number 304 | - hitting enter in physical drives no longer jumps 305 | - physical drives show proper area along the top when views are set 306 | - added highest nibble ignoring for fat32 entries 307 | - fixed small multiplication bug when using over 8 sectors per cluster 308 | - directory view now has Created/Accessed/Modified fields 309 | - added FSinfo sector view (default only) 310 | 311 | WDe V0.17 [06/22/02] 312 | - some optimizations 313 | - added a fat search function 314 | - added a quit prompt 315 | - corrected small mbr view bug again (permanent fix this time) 316 | - default view for CDs now clears the view 317 | - added 'Hid Fat' (hidden fat) partitions for MBR view 318 | - removed Ctrl+Right & Ctrl+Enter in root for fat1x 319 | - added directory auto-detect for physical drives 320 | - added '[MBR]' and '[Boot/Reserved]' for physical drives 321 | - "Save to Disk" now gives status messages 322 | - some fat12 view support for CDs 323 | - escape quits from file saving/restoring operations 324 | - ctrl+right now supports the second fat 325 | - fixed accidental re-reading of fat sectors on one ctrl+right 326 | - fixed accidental re-reading of fat sectors on multiple ctrl+rights 327 | - fixed fat12 ctrl+right for last two bytes of fat sector 1,4,7,10 etc. 328 | - added query to overwrite files 329 | - ctrl+right now always jumps to the low nibble in the fat 330 | - fixed file re-creation bug when saving sector mbr/bootsect 331 | - added proper theoretical "save to disk" for CDs 332 | - fixed low nibble hex backspace bug 333 | - fixed inconsistent locking issue 334 | - fixed drive re-locking bug (system would reset) 335 | - fixed small stack issues when aborting searches 336 | 337 | WDe V0.16 [05/20/02] 338 | - some optimizations 339 | - mbr, bootsector, and directory search functions now support cd-rom 340 | - added proper CD extension detection 341 | - added fat12 view, [ctrl+]enter, ctrl+right & entry number display 342 | - fixed a stack bug when a string is not found 343 | - added more hard disk numbers allowed in boot sector view (up to 9) 344 | 345 | WDe V0.15 [05/12/02] 346 | - lots of optimizations 347 | - implemented ctrl+right to jump to the next entry when in the fat 348 | and jumping directly to the next cluster when in the data area 349 | - ctrl+enter now jumps to the fat entry corresponding to the 350 | current cluster when in the data area 351 | - updated the boot sector display, and added 'media descriptor' to it 352 | - added 'Ext Fat' (extended fat) partitions for MBR view 353 | - boot sector view for backup boot sector added 354 | - boot sector view for partitions when using physical view 355 | - automatic directory detection added 356 | 357 | WDe V0.14 [05/08/02] 358 | - some optimizations 359 | - fixed nasty key getting bug (created in V0.13b) 360 | - restore sectors can no longer go over the partition limit 361 | 362 | WDe V0.13b [05/07/02] 363 | - some optimizations 364 | - fixed locking bug causing writes under windows to fail 365 | - save/restore root now supports fat12/fat16 366 | - fixed size checking when using restore drive/etc 367 | - now checks to see if sectors being saved exceeds 2gb 368 | - fixed view problem when saving sectors from cd from a subsector 369 | - added jumping from fat entries and directory entries 370 | to appropriate clusters by pressing 'enter' 371 | - fixed a small directory view bug (high cluster highlighting) 372 | - shows partition type in MBR-view (if fat12/fat16/fat32) 373 | - re-wrote functions handling hex editing movement 374 | 375 | WDe V0.12b [04/25/02] 376 | - many optimizations 377 | - fixed a bug switching from a "subsector" on a CD drive to a logical 378 | or physical drive 379 | - fixed a cd-rom reading bug 380 | - fixed an MBR view bug (highlighting sectors) 381 | - fixed an insignificant potential fat type detection bug 382 | - added CHS sector reading (int13h/ah=02) and writing for compatibility 383 | with older systems that do not support extended int13h functions 384 | - added "entry: [hex entry number]" along the top when in the fat 385 | - dumping as ISO added for CDs 386 | - added save options to save/restore the mbr, bootsector, fat 1/2, 387 | root, entire drives and partitions to/from files 388 | - fixed a bug when unable to write to drive (defaulted to CD-rom r/w) 389 | - added 'active' for the active partition byte in mbr view 390 | - fixed bootsector view issues with non-fat32 drives 391 | - all view functions now work for CD subsectors 392 | - fixed bug entering cluster when using jump to cluster 393 | - fixed jumping bugs to input sector/cluster and last sector 394 | 395 | WDe V0.11b 396 | - ctrl+pgup/pgdn now jumps 100 sectors at a time instead of 1000 397 | - won't crash when sectors per cluster is 0 398 | - will abort when unable to write sectors from file 399 | - will abort when unable to read sectors when searching 400 | - view functions added for fat16, fat32 and directories 401 | - directory search functions added 402 | - cd-rom support was [somewhat] added 403 | - fixed mbr/bs/dir search (ended one sector before the drive ended) 404 | 405 | WDe V0.10b [04/01/02] 406 | - int13h sector writes were fixed, since the previous versions 407 | re-wrote the same data that was read from the drive 408 | - display is now properly set to 80x25 text mode on quit 409 | - some optimizations 410 | - fixed a small cluster miscalculation when the root is immediately 411 | after the fat on fat32 partitions 412 | - fixed a problem when changing to non-existant physical drives 413 | from logical drives 414 | - fixed a bug causing wde to quit when hitting escape when changing 415 | from a physical drive 416 | - view functions added (default/mbr/bootsector) 417 | - drive locking was added 418 | - proper fat type detection was added (for use with view functions) 419 | - bug fixed when saving sectors near the end of the drive 420 | - bug fixed when writing to disk after saving sectors 421 | - some search functions were added (string/hex/mbr/bs) 422 | - added jump functions for int13h disk reading (partition 1/2/3/4) 423 | - fixed a bug where two keys must be pressed after trying to read an 424 | invalid drive when WDe first starts 425 | - ctrl+pgup/pgdn now jumps 1000 sectors at a time 426 | 427 | WDe V0.09b [03/18/02] 428 | - initial public release 429 | -------------------------------------------------------------------------------- /src/unformat.inc: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------- 2 | ; 3 | ; WDe Copyright(C)2005 Ben Cadieux, 2022 japheth 4 | ; 5 | ;------------------------------------------------------- 6 | 7 | ;--- unformat didn't work for FAT32 until v0.99, 8 | ;--- because subdirectories of root have an ".." entry with 9 | ;--- cluster# 0000000, but root has a cluster# != 0. 10 | 11 | ;--- the disk is scanned for directories. Each directory is 12 | ;--- stored on the heap in a UFDIR structure. 13 | 14 | UFDIR struct 15 | bFlags db ? 16 | dwCluster dd ? 17 | UFDIR ends 18 | 19 | ;--- values for bFlags field in UFDIR 20 | 21 | ROOTLINKED_DIRECTORY EQU 00000001b ; cluster# of ".." matches that of root 22 | REGULAR_DIRECTORY EQU 00000010b ; cluster# of ".." isn't that of root 23 | UNLINKED_DIRECTORY EQU 00000100b ; directory without "." and ".." entry 24 | UNTERMINATED_DIRECTORY EQU 00001000b 25 | PROCESSABLE_DIRECTORY EQU 00010000b 26 | PROCESSED_DIRECTORY EQU 00100000b 27 | SUB_DIRECTORY EQU 01000000b 28 | VALID_DIRECTORY EQU 10000000b 29 | 30 | ; commandflag for checkDirValidity function 31 | 32 | VALIDATE EQU 0 33 | PROCESS EQU 1 34 | FILE_RECOVERY EQU 2 35 | 36 | ; writerootentry function 37 | 38 | ROOT_DIRECTORY EQU 1 39 | LOST_DIRECTORY EQU 2 40 | 41 | ;--- 1.: scan FAT entries, must all be zero or 0ffffff7h 42 | ;--- 2.: scan root directory, must be zero (just first entry is checked) 43 | ;--- 3.: scan clusters for directories 44 | ;--- 4.: process all found directories in foundProcessed() 45 | ;--- 5.: file recovery - files larger than 1 cluster 46 | ; 47 | ; known bugs: 48 | ; - there can be a blank sector in the middle of a directory cluster 49 | ; with the remaining sectors filled. 50 | ; - error handling missing for "out of root entries" problems 51 | ; also: too many directories may cause an "out of memory" error. The heap 52 | ; is located in DGROUP, free space about 50 kB, that's room for 10000 dirs. 53 | 54 | unformat proc 55 | 56 | push bp 57 | mov bp, sp 58 | sub sp, 3*4+3*2 59 | 60 | maxsize equ ; maximum filesize to recover 61 | minsize equ ; minimum filesize to recover 62 | nextsize equ ; next smallest filesize to recover 63 | lostdirs equ < word ptr [bp-14]> ; total lost directories found 64 | rootdirs equ < word ptr [bp-16]> ; total root directories found 65 | wDirs equ < word ptr [bp-18]> ; total dirs found 66 | 67 | mov [fromfat], FF_FAT1 ; always use fat 1 68 | mov dx, CStr('Scanning Fat...') 69 | call printbottom 70 | 71 | ;--- scan the whole FAT, beginning with entry 2, for values != 0 or ffffff7. 72 | ;--- For FAT32, start at 3 ( assuming root dir is at 2, size 1 cluster ) 73 | 74 | mov eax, 2 ; start at cluster 2 75 | test [bFilesys], FS_FAT32 76 | jz @F 77 | inc eax ; for FAT32, start at cluster 3 78 | @@: 79 | continuefatscan: 80 | call checkabort 81 | je abortUnformat 82 | push eax 83 | call getfatentry ; get fat data for this cluster 84 | mov edx, eax 85 | pop eax 86 | jc abortUnformat 87 | test edx, edx ; blank fat entry? 88 | jz entryisok ; yes, acceptable. 89 | cmp edx, 0FFFFFF7h ; bad cluster? 90 | mov dx, CStr('Fat Table Not Blank') 91 | jne unformatError1 ; no, not acceptable 92 | entryisok: 93 | inc eax ; cluster++ 94 | cmp eax, [dwLastCluster] 95 | jbe continuefatscan 96 | 97 | unffatok: 98 | mov eax, [dwRootSect] ; jump to the root directory 99 | mov [ioreq.sectno], eax 100 | call diskaccess_read 101 | jc abortUnformat 102 | mov dx, CStr('Root Not Blank') 103 | cmp byte ptr [sectbuffer], 0 ; check if first root entry is blank 104 | jne unformatError2 105 | 106 | @dprintfln "unformat: fat & root scan ok" 107 | 108 | ;--- 109 | ;--- scan for directories 110 | ;--- 111 | 112 | call scandirectories 113 | jc unformatError4 114 | @dprintfln "unformat: directory searching done" 115 | 116 | ;--- 117 | ;--- processing of directories 118 | ;--- 119 | 120 | xor ax, ax 121 | mov [lostdirs], ax ; zero lost directory count 122 | mov [rootdirs], ax ; zero root directory count 123 | cmp [wDirs], ax 124 | mov dx, CStr('No Directories Found') 125 | je unformatError3 126 | 127 | mov dx, offset sprintfbuffer 128 | invoke sprintf, dx, CStr('Directories found: %u - recovering...'), [wDirs] 129 | call printbottom 130 | 131 | dirsFound: 132 | 133 | mov ah, PROCESSABLE_DIRECTORY ; the default is to search for 134 | ; processable directories 135 | dirsFound2: 136 | mov al, 0 137 | mov cx, [wDirs] 138 | mov bx, [_mem] 139 | @dprintfln "unformat: start dirscan, ax=%X, wDirs=%u, bx=%X", ax, cx, bx 140 | 141 | ;--- the following loop sets all 'ah' directories to "processed" 142 | 143 | processedLoop: 144 | call checkabort 145 | je abortUnformat 146 | test [bx].UFDIR.bFlags, PROCESSED_DIRECTORY 147 | jnz @F 148 | test [bx].UFDIR.bFlags, ah 149 | jz @F 150 | call foundProcessed 151 | mov al, 1 ; at least one processable directory found 152 | @@: 153 | add bx, sizeof UFDIR 154 | dec cx 155 | jnz processedLoop 156 | 157 | test al, al 158 | jnz dirsFound 159 | cmp ah, UNLINKED_DIRECTORY ; did we already search for unlinked dirs? 160 | mov ah, UNLINKED_DIRECTORY 161 | jnz dirsFound2 ; if no, do now, else done. 162 | 163 | ;--- 164 | ;--- file recovery. recover all files that are larger than 1 cluster 165 | ;--- 166 | 167 | @dprintfln "unformat: recoverFiles" 168 | 169 | mov dx, CStr('Recovering Files...') 170 | call printbottom 171 | 172 | ;--- the strategy is to recover files from small sizes to larger sizes. 173 | ;--- for that 3 variables - minsize, maxsize, newsize - are maintained. 174 | 175 | mov eax, [dwBpC] ; all single cluster files were recovered, 176 | mov [minsize], eax ; so set the min. recovery size to [dwBpC] 177 | shl eax, 1 178 | mov [maxsize], eax ; and the max to twice [dwBpC]. 179 | 180 | restartRecoveryLoop: 181 | mov bx, [_mem] 182 | mov cx, [wDirs] 183 | recovernextdir: 184 | call checkabort 185 | je abortUnformat 186 | test [bx].UFDIR.bFlags, VALID_DIRECTORY 187 | jz @F 188 | @dprintfln "unformat: calling checkDirValidity(3), cluster=%lX", [bx].UFDIR.dwCluster 189 | mov eax, [bx].UFDIR.dwCluster 190 | mov [dwCluster], eax 191 | mov [commandflag], FILE_RECOVERY 192 | call checkDirValidity 193 | @@: 194 | add bx, sizeof UFDIR 195 | dec cx 196 | jnz recovernextdir 197 | mov eax, [nextsize] 198 | cmp [maxsize], eax ; nextsize is smaller or equal to maxsize, 199 | jae finishedUnformat ; so no bigger files were found. 200 | mov edx, [dwBpC] 201 | @@: 202 | add [minsize], edx 203 | add [maxsize], edx 204 | cmp [maxsize], eax 205 | jb @B 206 | jmp restartRecoveryLoop 207 | 208 | ;--- finished unformat 209 | 210 | finishedUnformat: 211 | cmp [bFats], 2 212 | jb noCopyF1toF2 213 | mov dx, CStr("Copying Fat-1 to Fat-2...") 214 | call printbottom 215 | mov eax, [dwReserved] 216 | mov ecx, [dwSpF] 217 | mov edx, [dwFat1end] 218 | 219 | f1tof2loop: 220 | mov [ioreq.sectno], eax 221 | call diskaccess_read 222 | mov [ioreq.sectno], edx 223 | call diskaccess_write 224 | inc eax 225 | inc edx 226 | dec ecx 227 | jnz f1tof2loop 228 | 229 | noCopyF1toF2: 230 | mov dx, CStr('Finished UnFormatting') 231 | unformatError1: 232 | unformatError2: 233 | unformatError3: 234 | unformatError4: 235 | and dx, dx 236 | jz @F 237 | call printerror 238 | @@: 239 | abortUnformat: 240 | call readcursect 241 | 242 | mov sp, bp 243 | pop bp 244 | ret 245 | 246 | unformat endp 247 | 248 | ;--- process a directory 249 | 250 | foundProcessed proc 251 | 252 | or [bx].UFDIR.bFlags, PROCESSED_DIRECTORY 253 | 254 | @dprintfln "foundProcessed: processing dir (cx=%u, bx=%X), check for subdirectories", cx, bx 255 | 256 | ; check the directory for subdirectories. 257 | ; any subdirectories will have the 'SUB_DIRECTORY' bit set. 258 | ; any files/subdirectories will not have their first cluster used. 259 | push ax 260 | mov eax, dword ptr [bx].UFDIR.dwCluster 261 | mov [dwCluster], eax 262 | mov [commandflag], VALIDATE 263 | call checkDirValidity 264 | 265 | ; if the directory is deemed invalid, then AL=1, 266 | ; so any subdirectories are invalid and cannot be set to 'processed' 267 | push cx 268 | push bx 269 | mov cx, [wDirs] 270 | mov bx, [_mem] 271 | 272 | checkForSubdirs: 273 | test [bx].UFDIR.bFlags, SUB_DIRECTORY 274 | jz @F 275 | and [bx].UFDIR.bFlags, NOT SUB_DIRECTORY 276 | cmp al, 1 277 | je @F 278 | or [bx].UFDIR.bFlags, PROCESSABLE_DIRECTORY 279 | @@: 280 | add bx, sizeof UFDIR 281 | dec cx 282 | jnz checkForSubdirs 283 | pop bx 284 | pop cx 285 | cmp al, 1 286 | pop ax 287 | je done_foundProcessed 288 | push ax 289 | 290 | or [bx].UFDIR.bFlags, VALID_DIRECTORY ; recover files from this directory 291 | ; in the next stage, since it's valid 292 | test [bx].UFDIR.bFlags, ROOTLINKED_DIRECTORY 293 | jz @F 294 | mov al, ROOT_DIRECTORY 295 | call writeRootEntry 296 | @@: 297 | 298 | @dprintfln "foundProcessed: terminate directory, cluster %lX", [dwCluster] 299 | push bx ; terminate the current directory 300 | mov ebx, [dwCluster] ; in the fat 301 | mov eax, 0FFFFFFFh 302 | call putfatentry 303 | pop bx 304 | mov [commandflag], PROCESS 305 | call checkDirValidity 306 | 307 | test [bx].UFDIR.bFlags, UNLINKED_DIRECTORY 308 | pop ax 309 | jz done_foundProcessed 310 | 311 | ; Next we deal with pieces of directories that have so many files 312 | ; that some of the directory data is placed further on the drive. 313 | ; This is done by recursing the array searching for a directory 314 | ; that is an UNTERMINATED_DIRECTORY, then connecting it to the next 315 | ; unlinked directory in the fat. 316 | 317 | ; unlinked directory will now be processed, so remove the 318 | ; unlinked bit and set it as a regular directory 319 | 320 | and [bx].UFDIR.bFlags, NOT UNLINKED_DIRECTORY 321 | or [bx].UFDIR.bFlags, REGULAR_DIRECTORY 322 | 323 | push ax 324 | push cx 325 | push bx 326 | @@: 327 | cmp cx, [wDirs] ; couldn't find an unterminated dir? 328 | je writeLDEntry ; write "LOST0001" in the root 329 | inc cx 330 | sub bx, sizeof UFDIR ; check previous item in the array 331 | test [bx].UFDIR.bFlags, UNTERMINATED_DIRECTORY 332 | jz @B 333 | 334 | ;--- found an unterminated directory, so remove unterminated bit 335 | and [bx].UFDIR.bFlags, NOT UNTERMINATED_DIRECTORY 336 | 337 | mov eax, [dwCluster] ; link the unlinked directory 338 | mov ebx, [bx].UFDIR.dwCluster ; with the unterminated directory 339 | call putfatentry 340 | jmp foundUnterminated 341 | 342 | writeLDEntry: 343 | mov al, LOST_DIRECTORY 344 | call writeRootEntry 345 | foundUnterminated: 346 | pop bx 347 | pop cx 348 | pop ax 349 | done_foundProcessed: 350 | ret 351 | 352 | foundProcessed endp 353 | 354 | ;--------------------------------------------------------- 355 | ;--- root directory entry re-writing 356 | ;--- IN: AL = ROOT_DIRECTORY (1), LOST_DIRECTORY (2) 357 | 358 | writeRootEntry proc 359 | 360 | @dprintfln "writeRootEntry enter, ax=%X", ax 361 | 362 | push bx 363 | push cx 364 | 365 | ;--- scan root directory for an empty entry 366 | 367 | mov ebx, [dwRootSect] 368 | mov ch, byte ptr [wSpC] ; start at the first root sector ( hibyte(wSpC) is 0 if not exfat ) 369 | xor dx, dx ; zero the checked root entry count 370 | 371 | checkNextRootSect: 372 | mov [ioreq.sectno], ebx ; error checking needed 373 | call diskaccess_read 374 | @dprintfln "unformat: writeRootEntry, root sector %lu read", ebx 375 | mov cl, 512 / DIRENTSIZE ; 16 entries per sector 376 | mov si, offset sectbuffer ; start with entry at offset 0 377 | 378 | checkNextEntry: 379 | cmp byte ptr [si], 0 ; first byte of the entry is 0? 380 | je writeEntry 381 | add si, DIRENTSIZE ; next entry 382 | dec cl 383 | jnz checkNextEntry 384 | 385 | add dx, 512 / DIRENTSIZE ; add to total number of processed 386 | ; directory entries (dx) 387 | inc ebx ; increase sector # 388 | 389 | test [bFilesys], FS_FAT32 ; FAT12/FAT16? 390 | je maxEntryCheck 391 | dec ch ; spc processed < spc? 392 | jnz checkNextRootSect 393 | ; 394 | ; todo: needs to find an empty cluster 395 | ; 396 | @dprintfln "unformat: writeRootEntry FAT32 out of root entries" 397 | jmp wre_exit 398 | maxEntryCheck: 399 | cmp dx, [wRootentries] ; reached maximum # of root entries? 400 | jb checkNextRootSect 401 | ; 402 | ; todo: out of entries error handling 403 | ; 404 | @dprintfln "unformat: writeRootEntry FAT1X out of root entries" 405 | jmp wre_exit 406 | writeEntry: 407 | cmp al, LOST_DIRECTORY 408 | je writeLostDir 409 | mov dword ptr [si].SFNENTRY.name_[0], 'RIDW'; "WDIR" 410 | inc [rootdirs] 411 | mov ax, [rootdirs] 412 | jmp writtenDirType 413 | writeLostDir: 414 | mov dword ptr [si].SFNENTRY.name_[0], 'TSOL'; "LOST" 415 | inc [lostdirs] 416 | mov ax, [lostdirs] 417 | writtenDirType: 418 | movzx eax, ax 419 | add ax, 10000 ; ensure there are "leading zeros" generated 420 | 421 | call rendernumdec ; decimal representation 422 | mov eax, dword ptr [valuebuffer+6] ; of the lost/root dir count 423 | mov dword ptr [si].SFNENTRY.name_[4], eax ; ("WDIR0001" etc) 424 | 425 | mov eax, [dwCluster] 426 | mov [si].SFNENTRY.wClLow, ax 427 | shr eax, 16 428 | mov [si].SFNENTRY.wClHigh, ax 429 | mov dword ptr [si+08h], 10202020h ; extension+attribs 430 | 431 | call diskaccess_write ; write [ioreq.sectno] 432 | 433 | @dprintfln "writeRootEntry: exit, root dir (sec %lu) entry written: >%s<", [ioreq.sectno], si 434 | wre_exit: 435 | pop cx 436 | pop bx 437 | ret 438 | 439 | writeRootEntry endp 440 | 441 | ;--- scan the whole partition for directories 442 | 443 | scandirectories proc 444 | 445 | mov [dwCluster], 1 ; start at cluster 1 (actually will be 2) 446 | mov [wDirs], 0 ; init directory count 447 | 448 | nextCluster: 449 | inc [dwCluster] 450 | 451 | mov eax, [dwCluster] 452 | cmp eax, [dwRootCluster] ; matches root cluster? 453 | je nextCluster ; next cluster. 454 | 455 | call checktime 456 | jc @F 457 | 458 | call checkabort 459 | je abort 460 | 461 | mov dx, offset sprintfbuffer 462 | invoke sprintf, dx, CStr('Searching Directories... (cluster %lX, directories %u)'), [dwCluster], [wDirs] 463 | call printbottom 464 | call darkclr3 465 | @@: 466 | 467 | call cluster2sector ; read first sector in cluster 468 | 469 | mov cl, byte ptr [wSpC] 470 | 471 | nextSectorOfCluster: 472 | 473 | cmp eax, [lastSector] 474 | ja doneFindDirs 475 | 476 | mov [ioreq.sectno], eax 477 | call diskaccess_read ; need error checking b4 & after 478 | 479 | mov si, offset sectbuffer 480 | call IsDirectory 481 | jnc directory_found 482 | cmp cl, byte ptr [wSpC] ; if the first sector in a cluster 483 | je nextCluster ; is not a directory...scan next 484 | ; cluster 485 | mov bx, [wBps] 486 | verifySectorNull: ; if the first sector of the cluster 487 | lodsb ; was a directory then check the 488 | test al, al ; remaining sectors if they're null 489 | jnz nextCluster ; (unused directory entries) 490 | dec bx 491 | jnz verifySectorNull 492 | 493 | directory_found: 494 | 495 | mov eax, [ioreq.sectno] 496 | inc eax ; increase sector # in cluster 497 | dec cl ; if there are sectors left, loop 498 | jnz nextSectorOfCluster 499 | 500 | mov bx, [wDirs] ; dirs*5 to find array position 501 | lea ebx,[ebx*4+ebx] ; sizeof UFDIR is 5 502 | add bx, [_mem] 503 | jc outofmemory ; 64 kB limit of DGROUP exceeded? 504 | cmp bx, - sizeof UFDIR 505 | jnc outofmemory 506 | 507 | @dprintfln "unformat: directory found at cluster %lX, cnt=%u, mem=%X", [dwCluster], [wDirs], bx 508 | 509 | inc [wDirs] 510 | 511 | mov [bx].UFDIR.bFlags, 0 ; zero this clusters attributes 512 | 513 | cmp cl, 0 ; last sector in cluster? 514 | jne notLastSect 515 | mov si, [wBps] 516 | cmp byte ptr [sectbuffer-DIRENTSIZE+si], 0; if the first byte of the 517 | je notLastSect ; last entry is not null, then 518 | or [bx].UFDIR.bFlags, UNTERMINATED_DIRECTORY ; directory is unterminated 519 | notLastSect: 520 | 521 | mov eax, [dwCluster] ; set the cluster 522 | mov [bx].UFDIR.dwCluster, eax 523 | 524 | call cluster2sector 525 | 526 | cmp [ioreq.sectno], eax ; if it's already the current sector 527 | je dontReRead ; don't re-read it. 528 | 529 | mov [ioreq.sectno], eax ; read first sector of cluster 530 | call diskaccess_read 531 | 532 | dontReRead: 533 | ;--- starting with "." and ".." dir entries? 534 | cmp word ptr [sectbuffer].SFNENTRY.name_, " ." 535 | jne unlinkeddirectory 536 | cmp dword ptr [sectbuffer+sizeof SFNENTRY].SFNENTRY.name_, " .." 537 | jne unlinkeddirectory 538 | 539 | mov ax, [sectbuffer+sizeof SFNENTRY].SFNENTRY.wClHigh 540 | shl eax, 16 541 | mov ax, [sectbuffer+sizeof SFNENTRY].SFNENTRY.wClLow 542 | 543 | ;--- v0.99: the clusternumber of the ".." is 0000000 for subdirs of root in FAT32! 544 | ;--- in that case only "regular" may be found - and nothing is recovered! 545 | 546 | cmp [bFilesys], FS_FAT32 547 | jnz @F 548 | cmp eax, 0 549 | jz rootlinked 550 | @@: 551 | cmp eax, [dwRootCluster] ; check if directory was in the root 552 | jne regulardirectory 553 | rootlinked: 554 | @dprintfln "unformat: directory marked ROOTLINKED or PROCESSABLE (cluster# of '..' is %lX)", eax 555 | or [bx].UFDIR.bFlags, ROOTLINKED_DIRECTORY OR PROCESSABLE_DIRECTORY 556 | jmp nextCluster 557 | 558 | regulardirectory: 559 | @dprintfln "unformat: directory marked REGULAR, (cluster# of '..' is %lX)", eax 560 | or [bx].UFDIR.bFlags, REGULAR_DIRECTORY 561 | jmp nextCluster 562 | 563 | unlinkeddirectory: 564 | @dprintfln "unformat: directory marked UNLINKED" 565 | or [bx].UFDIR.bFlags, UNLINKED_DIRECTORY 566 | jmp nextCluster 567 | 568 | doneFindDirs: 569 | ret 570 | outofmemory: 571 | mov dx, CStr('Out of memory') 572 | stc 573 | ret 574 | abort: 575 | xor dx, dx 576 | stc 577 | ret 578 | scandirectories endp 579 | 580 | ;--- 581 | ;--- checkDirValidity 582 | ;--- in: [dwCluster] : start of directory 583 | ;--- [commandflag] : what to do exactly 584 | ;--- 585 | ;--- all files/subdirs of the directory must be in free space 586 | ;--- 587 | 588 | checkDirValidity proc 589 | push bx 590 | push cx 591 | 592 | .const 593 | cmdvecs label word 594 | dw validatecmd 595 | dw processcmd 596 | dw recoverfilescmd 597 | .code 598 | 599 | @dprintfln "checkDirValidity enter, commandflag[lobyte]=%X", word ptr [commandflag] 600 | mov eax, [dwCluster] ; cluster number for this directory 601 | call cluster2sector ; get matching sector number 602 | mov edi, eax 603 | mov dh, byte ptr [wSpC] ; number of sectors per cluster 604 | 605 | checkNextSector: 606 | 607 | mov [ioreq.sectno], edi 608 | call diskaccess_read ; read the data into sectbuffer 609 | ; 610 | ; jc doneValidation 611 | ; 612 | mov dl, 512 / DIRENTSIZE 613 | mov si, offset sectbuffer ; pointer to the entry being worked with 614 | 615 | processNextEntry: 616 | cmp [si].SFNENTRY.name_, 00 ; no entries left? 617 | je validDir 618 | cmp word ptr [si], " ." ; skip "." & ".." entries 619 | je entrydone 620 | cmp dword ptr [si], " .." 621 | je entrydone 622 | cmp [si].SFNENTRY.name_, 0E5h 623 | je entrydone ; skip deleted entries 624 | cmp [si].SFNENTRY.bAttr, 0Fh 625 | je entrydone ; skip LFNs 626 | 627 | ;--- get the cluster number of the entry 628 | 629 | mov ax, [si].SFNENTRY.wClHigh 630 | shl eax, 16 631 | mov ax, [si].SFNENTRY.wClLow 632 | ; 633 | ; error checking for cluster # missing here 634 | ; 635 | movzx bx,[commandflag] 636 | shl bx, 1 637 | call [bx+cmdvecs] 638 | jc doneValidation 639 | entrydone: 640 | add si, DIRENTSIZE ; check next entry 641 | dec dl 642 | jnz processNextEntry 643 | inc edi 644 | dec dh ; check next sector 645 | jnz checkNextSector 646 | validDir: 647 | mov al, 0 648 | doneValidation: 649 | @dprintfln "checkDirValidity exit, ax=%X", ax 650 | pop cx 651 | pop bx 652 | ret 653 | 654 | ;----------------------------- 655 | 656 | validatecmd: 657 | @dprintfln "checkDirValidity: VALIDATE [name=%s, cluster=%lX]", si, eax 658 | 659 | cmp eax, [dwCluster] ; cluster # of any entries within the 660 | je invalidDir ; directory cannot match parent # 661 | push eax 662 | call getfatentry ; get the matching fat entry 663 | test eax, eax ; test to see if it's 0 664 | pop eax 665 | jnz invalidDir ; if not, skip. 666 | 667 | test [si].SFNENTRY.bAttr, DA_DIRECTORY 668 | jz validate_done ; jump if not a directory 669 | 670 | mov cx, [wDirs] 671 | mov bx, [_mem] 672 | @@: 673 | cmp [bx].UFDIR.dwCluster, eax ; compare the starting cluster number of 674 | je foundClusterMatch ; the subdirectory with the list of detected 675 | add bx, sizeof UFDIR ; directories. 676 | loop @B 677 | 678 | ; If the subdirectories in the directory being checked for validity 679 | ; were not found scanning the entire hard drive, then the directory 680 | ; must be invalid --- it could be a false positive or directory information 681 | ; stored on a disk image saved on this drive (or something similar). 682 | 683 | invalidDir: 684 | mov al, 1 ; invalid directory 685 | stc 686 | ret 687 | foundClusterMatch: 688 | or [bx].UFDIR.bFlags, SUB_DIRECTORY ; specify it's a located subdirectory 689 | validate_done: 690 | clc 691 | ret 692 | 693 | ;----------------------------- 694 | 695 | recoverfilescmd: 696 | 697 | mov [dwCluster], eax ; file start cluster# 698 | mov ebx, [si].SFNENTRY.dwSize 699 | mov [dwFilesize], ebx 700 | 701 | mov eax, [maxsize] 702 | cmp ebx, eax ; filesize <= maxsize? 703 | jbe skipSetNextSize ; ignore for setting nextsize 704 | 705 | ;--- v0.99: a small bug, resulting in premature end of file recovery: 706 | ;--- if nextsize == maxsize, the larger filesize is ignored 707 | cmp [nextsize], eax ; nextsize <= maxsize? 708 | ; jb setNextSize 709 | jbe setNextSize ; set filesize as nextsize. 710 | 711 | cmp ebx, [nextsize] ; filesize >= nextsize? 712 | jae skipSetNextSize ; ignore for setting nextsize 713 | setNextSize: 714 | mov [nextsize], ebx 715 | skipSetNextSize: 716 | 717 | @dprintfln "checkDirValidity: FILE_RECOVERY [name=%s, cluster=%lX, size=%lu] min/max/next=%lu/%lu/%lu", si, [dwCluster], ebx, [minsize], [maxsize], [nextsize] 718 | 719 | cmp ebx, [minsize] ; filesize must be > minsize 720 | jbe done_recoverfiles 721 | cmp ebx, [maxsize] ; filesize must be <= maxsize 722 | ja done_recoverfiles 723 | 724 | @dprintfln "checkDirValidity: FILE_RECOVERY, calling UndeleteCore" 725 | mov al, 1 726 | call UndeleteCore 727 | done_recoverfiles: 728 | clc 729 | ret 730 | 731 | ;----------------------------- 732 | 733 | processcmd: 734 | @dprintfln "checkDirValidity: PROCESS [name=%s, cluster=%lX]", si, eax 735 | mov ebx, eax 736 | mov eax, 0FFFFFFFh 737 | call putfatentry 738 | clc 739 | ret 740 | 741 | checkDirValidity endp 742 | 743 | maxsize equ <> 744 | minsize equ <> 745 | nextsize equ <> 746 | lostdirs equ <> 747 | rootdirs equ <> 748 | wDirs equ <> 749 | 750 | ;--------------------------------------------------------- 751 | --------------------------------------------------------------------------------