home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
hobbes.nmsu.edu
/
2008-06-02_hobbes.nmsu.edu.zip
/
dos
/
2gbfix.zip
/
2gbfix.asm
next >
Wrap
Assembly Source File
|
1998-11-17
|
9KB
|
315 lines
page 60,132
;
; Fix to limit returned disk free space to 2GB in OS/2 DOS sessions
; (and possibly other multitasking OSes as well)
; Written 15-17 Nov 1998 by J.M.A. Hall
;
; The majority of 16-bit DOS and Windows programs cannot cope with a drive
; that is larger, or has more free space, than 2GB. This is usually because
; disk space is calculated in 32-bit signed integer arithmetic, and 2GB is
; approximately the largest positive value that can be represented.
; Under true DOS this is not a problem since the largest possible drive size
; is 2GB (= 65535 32768-byte clusters), but OS/2 DOS sessions emulate larger
; than 32768 byte clusters, which cause some programs to fail.
; This TSR implements the same solution that Novell NetWare uses, which is
; to limit the maximum returned disk space or size to 65535 32K clusters.
;
; Modification record:
; 15-Nov-1998 - Initial version
;
progname equ '2GBFIX' ; Reported name of this program
version equ '1.0' ; Current version
;
; Some constants
;
MAXCLUSTERS equ 65535 ; Max no. of clusters returnable
MAXCLUSTSIZE equ 32768 ; Max cluster size that should
; be returned (= cluster size
; on 2GB drive)
;
codeseg segment 'CODE'
assume cs:codeseg, ds:nothing, es:nothing
org 100h
begin: jmp init
;
; Data
;
func db ? ; Function we're processing
old21 label dword ; Old INT 21h handler
old21_o dw ?
old21_s dw ?
;
; This is our INT 21 handler - We handle calls with AH=36h
; also AH=1Bh and AH=1Ch.
;
idstr db progname ; So we can tell if INT 21 points to us
even
newint21 proc far
cmp ah,36h ; Free disk space?
je newfunc ; Jump if yes
cmp ah,1Bh ; Allocation for default drive?
je newfunc ; Jump if yes
cmp ah,1Ch ; Allocation for specific drive?
je newfunc ; Jump if yes
;
; At this point we give up and pass the call to the previous INT 21 handler
;
passon: jmp cs:old21
;
; New entry point for function 36H, 1Bh and 1Ch
;
newfunc:
mov cs:func,ah ; Save function we're doing
pushf ; Simulate INT
call cs:old21 ; Call original DOS function
;
; Registers at this point are
; CX = bytes/sector (normally 512, but this is not assumed)
; DX = total clusters
; Func 36h:
; AX = sectors/cluster (or 0FFFFh is drive was invalid)
; BX = free clusters
; Func 1Bh,1Ch:
; AL = sectors/cluster (or 0FFh if drive was invalid)
;
pushf ; Save return flags
cmp cs:func,36h ; Function 36h?
je test36 ; Jump if so
cbw ; Sign-extend AL into AH
test36: cmp ax,0FFFFh ; Invalid drive?
je done ; If so just return
push si ; Save work regs
push di ; Ditto
mov si,ax ; Save AX
mov di,dx ; Save DX
mul cx ; DX:AX = cluster size in bytes
cmp dx,0 ; > 65535?
ja dofix ; Yes - must fix
cmp ax,MAXCLUSTSIZE ; > MAXCLUSTSIZE?
ja dofix ; Yes - must fix
;
; No apparent problem, just restore registers and return
;
return: mov dx,di
mov ax,si
cmp cs:func,36h ; Func 36h?
je ret36 ; Jump if not
mov ah,cs:func ; Restore AH
ret36: pop di
pop si
done: popf ; Restore flags from DOS call
ret 2 ; Return to caller dropping flags on stack
;
; We need to fix the returned values. We do this by forcing the returned
; cluster size to 32KB, and scaling up the number of clusters to suit.
; If this causes the number of clusters to exceed 65535, we simply return
; 65535 (since this is the maximum that BX or DX can hold).
; At this point:
; DX:AX = drive's cluster size in bytes
; CX = sector size in bytes
; BX = no. of free clusters (if func = 36h)
; SI = old AX (i.e. sectors/cluster) (no longer needed)
; DI = old DX (i.e. total clusters)
;
dofix:
mov si,MAXCLUSTSIZE
div si ; AX = cluster multiplier
mov si,ax ; Save for later
;
; Fix total clusters
;
mul di ; DX:AX = new total clusters
cmp dx,0 ; >65535?
je nofix1 ; No - leave alone
mov ax,MAXCLUSTERS ; Force to max
nofix1: mov di,ax ; Store back
;
; Fix free clusters if func is 36h
;
cmp cs:func,36h ; Func 36h?
jne nfixfree ; Jump if not
mov ax,si ; Get multiplier back
mul bx ; DX:AX = new free clusters
cmp dx,0 ; >65535?
je nofix2 ; No - leave alone
mov ax,MAXCLUSTERS ; Force to max
nofix2: mov bx,ax ; Store back
nfixfree:
;
; Calculate new sectors/cluster
;
mov ax,MAXCLUSTSIZE
xor dx,dx ; Zero-extend to 32 bits
div cx ; AX = new sectors/cluster
mov si,ax ; So restore works properly!
jmp return ; All sorted!
newint21 endp
;
;======== ALL CODE BEYOND THIS POINT IS NOT RETAINED AT EXIT ========
;
; Initialisation routine
;
assume ds:codeseg, es:codeseg
init proc near
lea dx,signonmsg
mov ah,9
int 21h ; Announce ourself
mov si,81h ; Point to start of command line (in PSP)
call getnsp ; Get 1st non-space char
cmp al,0Dh ; End of line?
jne init2 ; No - continue
jmp tryins ; Yes - install
init2: cmp al,'/' ; Option?
je init3
cmp al,'-' ; Option
jne init4
init3: jmp doopt
init4: dec si ; So next call picks up char again.
;
; Must be trying to do normal install, check that we are not
; already installed.
;
tryins: mov ax,3521h ; Get vector 21h
int 21h ; now in ES:BX
mov di,bx
mov cx,(newint21-idstr) ; Get length of string
sub di,cx ; Point (hopefully) at start of ID string
lea si,idstr
rep cmpsb ; Compare strings
jne install ; OK to install - go do it
lea dx,mcxinsmsg ; Report error
jmp errexit
;
; OK to install, report the fact
;
install: lea dx,insmsg1
mov ah,9
int 21h
;;; lea dx,insmsg2
;;; mov ah,9
;;; int 21h ; finish off message
;
; Patch our INT 21h handler into the system
;
mov ax,3521h ; Get vector 21h
int 21h
mov old21_o,bx
mov old21_s,es
lea dx,newint21 ; Address of our handler
; (DS already has correct segment)
mov ax,2521h
int 21h ; Reset vector
;
; Become a TSR (at last!)
;
lea dx,init ; Get end address
mov cl,4
shr dx,cl ; Convert to paragraphs (/ by 16)
inc dx ; Round up to next
mov ax,3100h ; TSR, exit status = 0
int 21h
;
; Process options (chars after a '/' or '-', which must be on the start of the line)
; At present, the only valid option is 'U', which allows ourself to be unloaded
; if a later TSR has not grabbed the vector.
;
doopt: lodsb ; get the character after '/' or '-'
cmp al,'?' ; Usage request?
jne nousage
lea dx,usagemsg
jmp errexit
nousage:
cmp al,'U' ; Unload request?
je tryunl ; Jump if so
cmp al,'u' ; Unload request?
je tryunl ; Jump if so
lea dx,invoptmsg ; Report 'invalid option'
jmp errexit
;
; Try to unload a previous copy of ourself. This can only be done if the
; INT 21 vector points to it. We test for this by checking for the program name
; just before the INT 21 handler.
;
tryunl: mov ax,3521h ; Get vector 21h
int 21h ; now in ES:BX
mov di,bx
mov cx,(newint21-idstr) ; Get length of string
sub di,cx ; Point (hopefully) at start of ID string
lea si,idstr
rep cmpsb ; Compare strings
je unload ; OK to unload - go do it
lea dx,nounlmsg ; Report "can't install"
jmp errexit
;
; We're OK to unload the old copy of ourself. First, restore the old INT 21 vector
; (saved in the MXSUB image). At this point, ES=segment of old copy
;
unload: push ds
lds dx,es:old21 ; Load old INT 21 vector
mov ax,2521h
int 21h ; and put it back in the system
pop ds
;
; Deallocate the memory block holding the old copy, and the environment block
; (the segment of which is held in the PSP at offset 2Ch)
;
push es:[2Ch] ; Save segment of environment
mov ah,49h
int 21h ; Deallocate resident code
jc freerr ; Jump if failed
mov ah,49h ; AX corrupted by previous call!
pop es ; Get segment of environment
int 21h ; and deallocate it
jnc okexit
freerr: lea dx,nofreemsg
jmp errexit
;
; Report success message and exit
;
okexit: lea dx,unlmsg
mov ah,9
int 21h
mov ax,4c00h ; Exit with status of 0
int 21h
;
; Report an error and exit: DX points to error message.
;
errexit: mov ah,9
int 21h ; Print error message
mov ax,4c01h ; Exit with status of 1
int 21h ; ...and terminate
init endp
;
; Subroutine to return the next non-whitespace character from the command line
;
getnsp proc near
lodsb ; Get next char
cmp al,' ' ; Reject space
je getnsp
cmp al,9 ; and TAB
je getnsp
ret
getnsp endp
;
; Messages used by init code
;
signonmsg db progname,' v',version,' - a patch to limit returned disk space to 2GB'
db 13,10
db 'Written by and copyright (c) J.M.A. Hall November 1998.'
db 13,10,'$'
usagemsg db 'Usage: ',progname,' to install'
db 13,10
db ' ',progname,' /U to uninstall',13,10,'$'
mcxinsmsg db 'ERROR: cannot install - ',progname,' is already installed'
db 13,10,'$'
insmsg1 db progname,' successfully installed.'
insmsg2 db 13,10,'$'
invoptmsg db 'ERROR: invalid option letter (not "U")',13,10,'$'
nounlmsg db 'ERROR: cannot unload - INT 21h does not point to '
db progname,13,10,'$'
nofreemsg db 'ERROR: cannot free memory belonging to ',progname
db 13,10,'$'
unlmsg db progname,' successfully unloaded.',13,10,'$'
codeseg ends
end begin