home *** CD-ROM | disk | FTP | other *** search
/ hobbes.nmsu.edu / 2008-06-02_hobbes.nmsu.edu.zip / dos / 2gbfix.zip / 2gbfix.asm next >
Assembly Source File  |  1998-11-17  |  9KB  |  315 lines

  1. page 60,132
  2. ;
  3. ; Fix to limit returned disk free space to 2GB in OS/2 DOS sessions
  4. ; (and possibly other multitasking OSes as well)
  5. ; Written 15-17 Nov 1998 by J.M.A. Hall
  6. ;
  7. ; The majority of 16-bit DOS and Windows programs cannot cope with a drive
  8. ; that is larger, or has more free space, than 2GB. This is usually because
  9. ; disk space is calculated in 32-bit signed integer arithmetic, and 2GB is
  10. ; approximately the largest positive value that can be represented.
  11. ; Under true DOS this is not a problem since the largest possible drive size
  12. ; is 2GB (= 65535 32768-byte clusters), but OS/2 DOS sessions emulate larger
  13. ; than 32768 byte clusters, which cause some programs to fail.
  14. ; This TSR implements the same solution that Novell NetWare uses, which is
  15. ; to limit the maximum returned disk space or size to 65535 32K clusters.
  16. ;
  17. ; Modification record:
  18. ; 15-Nov-1998 -    Initial version
  19. ;
  20. progname    equ    '2GBFIX'        ; Reported name of this program
  21. version        equ    '1.0'            ; Current version
  22. ;
  23. ; Some constants
  24. ;
  25. MAXCLUSTERS    equ    65535            ; Max no. of clusters returnable
  26. MAXCLUSTSIZE    equ    32768            ; Max cluster size that should
  27.                         ; be returned (= cluster size
  28.                         ; on 2GB drive)
  29. ;
  30. codeseg        segment 'CODE'
  31.         assume    cs:codeseg, ds:nothing, es:nothing
  32.         org    100h
  33. begin:        jmp    init
  34. ;
  35. ; Data
  36. ;
  37. func        db    ?            ; Function we're processing
  38. old21        label    dword            ; Old INT 21h handler
  39. old21_o        dw    ?
  40. old21_s        dw    ?
  41. ;
  42. ; This is our INT 21 handler - We handle calls with AH=36h
  43. ; also AH=1Bh and AH=1Ch.
  44. ;
  45. idstr        db    progname        ; So we can tell if INT 21 points to us
  46.         even
  47. newint21    proc    far
  48.         cmp    ah,36h            ; Free disk space?
  49.         je    newfunc            ; Jump if yes
  50.         cmp    ah,1Bh            ; Allocation for default drive?
  51.         je    newfunc            ; Jump if yes
  52.         cmp    ah,1Ch            ; Allocation for specific drive?
  53.         je    newfunc            ; Jump if yes
  54. ;
  55. ; At this point we give up and pass the call to the previous INT 21 handler
  56. ;
  57. passon:        jmp    cs:old21
  58. ;
  59. ; New entry point for function 36H, 1Bh and 1Ch
  60. ;
  61. newfunc:
  62.         mov    cs:func,ah        ; Save function we're doing
  63.         pushf                ; Simulate INT
  64.         call    cs:old21        ; Call original DOS function
  65. ;
  66. ; Registers at this point are
  67. ; CX = bytes/sector (normally 512, but this is not assumed)
  68. ; DX = total clusters
  69. ; Func 36h:
  70. ;  AX = sectors/cluster (or 0FFFFh is drive was invalid)
  71. ;  BX = free clusters
  72. ; Func 1Bh,1Ch:
  73. ;  AL = sectors/cluster (or 0FFh if drive was invalid)
  74. ;
  75.         pushf                ; Save return flags
  76.         cmp    cs:func,36h        ; Function 36h?
  77.         je    test36            ; Jump if so
  78.         cbw                ; Sign-extend AL into AH
  79. test36:        cmp    ax,0FFFFh        ; Invalid drive?
  80.         je    done            ; If so just return
  81.         push    si            ; Save work regs
  82.         push    di            ; Ditto
  83.         mov    si,ax            ; Save AX
  84.         mov    di,dx            ; Save DX
  85.         mul    cx            ; DX:AX = cluster size in bytes
  86.         cmp    dx,0            ; > 65535?
  87.         ja    dofix            ; Yes - must fix
  88.         cmp    ax,MAXCLUSTSIZE        ; > MAXCLUSTSIZE?
  89.         ja    dofix            ; Yes - must fix
  90. ;
  91. ; No apparent problem, just restore registers and return
  92. ;
  93. return:        mov    dx,di
  94.         mov    ax,si
  95.         cmp    cs:func,36h        ; Func 36h?
  96.         je    ret36            ; Jump if not
  97.         mov    ah,cs:func        ; Restore AH
  98. ret36:        pop    di
  99.         pop    si
  100. done:        popf                ; Restore flags from DOS call
  101.         ret    2            ; Return to caller dropping flags on stack
  102. ;
  103. ; We need to fix the returned values. We do this by forcing the returned
  104. ; cluster size to 32KB, and scaling up the number of clusters to suit.
  105. ; If this causes the number of clusters to exceed 65535, we simply return
  106. ; 65535 (since this is the maximum that BX or DX can hold).
  107. ; At this point:
  108. ; DX:AX = drive's cluster size in bytes
  109. ; CX = sector size in bytes
  110. ; BX = no. of free clusters (if func = 36h)
  111. ; SI = old AX (i.e. sectors/cluster) (no longer needed)
  112. ; DI = old DX (i.e. total clusters)
  113. ;
  114. dofix:
  115.         mov    si,MAXCLUSTSIZE
  116.         div    si            ; AX = cluster multiplier
  117.         mov    si,ax            ; Save for later
  118. ;
  119. ; Fix total clusters
  120. ;
  121.         mul    di            ; DX:AX = new total clusters
  122.         cmp    dx,0            ; >65535?
  123.         je    nofix1            ; No - leave alone
  124.         mov    ax,MAXCLUSTERS        ; Force to max
  125. nofix1:        mov    di,ax            ; Store back
  126. ;
  127. ; Fix free clusters if func is 36h
  128. ;
  129.         cmp    cs:func,36h        ; Func 36h?
  130.         jne    nfixfree        ; Jump if not
  131.         mov    ax,si            ; Get multiplier back
  132.         mul    bx            ; DX:AX = new free clusters
  133.         cmp    dx,0            ; >65535?
  134.         je    nofix2            ; No - leave alone
  135.         mov    ax,MAXCLUSTERS        ; Force to max
  136. nofix2:        mov    bx,ax            ; Store back
  137. nfixfree:
  138. ;
  139. ; Calculate new sectors/cluster
  140. ;
  141.         mov    ax,MAXCLUSTSIZE
  142.         xor    dx,dx            ; Zero-extend to 32 bits
  143.         div    cx            ; AX = new sectors/cluster
  144.         mov    si,ax            ; So restore works properly!
  145.         jmp    return            ; All sorted!
  146. newint21    endp
  147. ;
  148. ;======== ALL CODE BEYOND THIS POINT IS NOT RETAINED AT EXIT ========
  149. ;
  150. ; Initialisation routine
  151. ;
  152.         assume    ds:codeseg, es:codeseg
  153. init        proc    near
  154.         lea    dx,signonmsg
  155.         mov    ah,9
  156.         int    21h            ; Announce ourself
  157.         mov    si,81h            ; Point to start of command line (in PSP)
  158.         call    getnsp            ; Get 1st non-space char
  159.         cmp    al,0Dh            ; End of line?
  160.         jne    init2            ; No - continue
  161.         jmp    tryins            ; Yes - install
  162. init2:        cmp    al,'/'            ; Option?
  163.         je    init3
  164.         cmp    al,'-'            ; Option
  165.         jne    init4
  166. init3:        jmp    doopt
  167. init4:        dec    si            ; So next call picks up char again.
  168. ;
  169. ; Must be trying to do normal install, check that we are not
  170. ; already installed.
  171. ;
  172. tryins:        mov    ax,3521h        ; Get vector 21h
  173.         int    21h            ; now in ES:BX
  174.         mov    di,bx
  175.         mov    cx,(newint21-idstr)    ; Get length of string
  176.         sub    di,cx            ; Point (hopefully) at start of ID string
  177.         lea    si,idstr
  178.         rep    cmpsb            ; Compare strings
  179.         jne    install            ; OK to install - go do it
  180.         lea    dx,mcxinsmsg        ; Report error
  181.         jmp    errexit
  182. ;
  183. ; OK to install, report the fact
  184. ;
  185. install:    lea    dx,insmsg1
  186.         mov    ah,9
  187.         int    21h
  188. ;;;        lea    dx,insmsg2
  189. ;;;        mov    ah,9
  190. ;;;        int    21h            ; finish off message
  191. ;
  192. ; Patch our INT 21h handler into the system
  193. ;
  194.         mov    ax,3521h        ; Get vector 21h
  195.         int    21h
  196.         mov    old21_o,bx
  197.         mov    old21_s,es
  198.         lea    dx,newint21        ; Address of our handler
  199.                         ; (DS already has correct segment)
  200.         mov    ax,2521h
  201.         int    21h            ; Reset vector
  202. ;
  203. ; Become a TSR (at last!)
  204. ;
  205.         lea    dx,init            ; Get end address
  206.         mov    cl,4
  207.         shr    dx,cl            ; Convert to paragraphs (/ by 16)
  208.         inc    dx            ; Round up to next
  209.         mov    ax,3100h        ; TSR, exit status = 0
  210.         int    21h
  211. ;
  212. ; Process options (chars after a '/' or '-', which must be on the start of the line)
  213. ; At present, the only valid option is 'U', which allows ourself to be unloaded
  214. ; if a later TSR has not grabbed the vector.
  215. ;
  216. doopt:        lodsb                ; get the character after '/' or '-'
  217.         cmp    al,'?'            ; Usage request?
  218.         jne    nousage
  219.         lea    dx,usagemsg
  220.         jmp    errexit
  221. nousage:
  222.         cmp    al,'U'            ; Unload request?
  223.         je    tryunl            ; Jump if so
  224.         cmp    al,'u'            ; Unload request?
  225.         je    tryunl            ; Jump if so
  226.         lea    dx,invoptmsg        ; Report 'invalid option'
  227.         jmp    errexit
  228. ;
  229. ; Try to unload a previous copy of ourself. This can only be done if the
  230. ; INT 21 vector points to it. We test for this by checking for the program name
  231. ; just before the INT 21 handler.
  232. ;
  233. tryunl:        mov    ax,3521h        ; Get vector 21h
  234.         int    21h            ; now in ES:BX
  235.         mov    di,bx
  236.         mov    cx,(newint21-idstr)    ; Get length of string
  237.         sub    di,cx            ; Point (hopefully) at start of ID string
  238.         lea    si,idstr
  239.         rep    cmpsb            ; Compare strings
  240.         je    unload            ; OK to unload - go do it
  241.         lea    dx,nounlmsg        ; Report "can't install"
  242.         jmp    errexit
  243. ;
  244. ; We're OK to unload the old copy of ourself. First, restore the old INT 21 vector
  245. ; (saved in the MXSUB image). At this point, ES=segment of old copy
  246. ;
  247. unload:        push    ds
  248.         lds    dx,es:old21        ; Load old INT 21 vector
  249.         mov    ax,2521h        
  250.         int    21h            ; and put it back in the system
  251.         pop    ds
  252. ;
  253. ; Deallocate the memory block holding the old copy, and the environment block
  254. ; (the segment of which is held in the PSP at offset 2Ch)
  255. ;
  256.         push    es:[2Ch]        ; Save segment of environment
  257.         mov    ah,49h
  258.         int    21h            ; Deallocate resident code
  259.         jc    freerr            ; Jump if failed
  260.         mov    ah,49h            ; AX corrupted by previous call!
  261.         pop    es            ; Get segment of environment
  262.         int    21h            ; and deallocate it
  263.         jnc    okexit
  264. freerr:        lea    dx,nofreemsg
  265.         jmp    errexit
  266. ;
  267. ; Report success message and exit
  268. ;
  269. okexit:        lea    dx,unlmsg
  270.         mov    ah,9
  271.         int    21h
  272.         mov    ax,4c00h        ; Exit with status of 0
  273.         int    21h
  274. ;
  275. ; Report an error and exit: DX points to error message.
  276. ;
  277. errexit:    mov    ah,9
  278.         int    21h            ; Print error message
  279.         mov    ax,4c01h        ; Exit with status of 1
  280.         int    21h            ; ...and terminate
  281. init        endp
  282. ;
  283. ; Subroutine to return the next non-whitespace character from the command line
  284. ;
  285. getnsp        proc    near
  286.         lodsb                ; Get next char
  287.         cmp    al,' '            ; Reject space
  288.         je    getnsp
  289.         cmp    al,9            ; and TAB
  290.         je    getnsp
  291.         ret
  292. getnsp        endp
  293. ;
  294. ; Messages used by init code
  295. ;
  296. signonmsg    db    progname,' v',version,' - a patch to limit returned disk space to 2GB'
  297.         db    13,10
  298.         db    'Written by and copyright (c) J.M.A. Hall November 1998.'
  299.         db    13,10,'$'
  300. usagemsg    db    'Usage: ',progname,' to install'
  301.         db    13,10
  302.         db    '       ',progname,' /U to uninstall',13,10,'$'
  303. mcxinsmsg    db    'ERROR: cannot install - ',progname,' is already installed'
  304.         db    13,10,'$'
  305. insmsg1        db    progname,' successfully installed.'
  306. insmsg2        db    13,10,'$'
  307. invoptmsg    db    'ERROR: invalid option letter (not "U")',13,10,'$'
  308. nounlmsg    db    'ERROR: cannot unload - INT 21h does not point to '
  309.         db    progname,13,10,'$'
  310. nofreemsg    db    'ERROR: cannot free memory belonging to ',progname
  311.         db    13,10,'$'
  312. unlmsg        db    progname,' successfully unloaded.',13,10,'$'
  313. codeseg        ends
  314.         end    begin
  315.