home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / library / sampler0 / diskscan.asm < prev    next >
Assembly Source File  |  1986-01-31  |  10KB  |  304 lines

  1. ;    DISKSCAN.ASM -- Checks out disk by reading sectors
  2. ;    --------------------------------------------------
  3.  
  4. CSEG        Segment
  5.         Assume    CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
  6.         Org    100h
  7. Entry:        Jmp    Begin
  8.  
  9. ;    All Data
  10. ;    --------
  11.                 db    ' Copyright 1986 Ziff-Davis Publishing Co.'
  12.         db    ' Programmed by Charles Petzold '
  13. DriveError    db    'Invalid Drive$'
  14. DosVersErr    db    'Needs DOS 2.0+$'
  15. MemoryError    db    'Needs 64K$'
  16. ReadSegment    dw    ?
  17. DriveNum    db    ?
  18. DiskBlock    db    18 dup (?)
  19. TotalSectors    dw    ?
  20. SectorsIn64K    dw    ?
  21. StartSector    dw    0
  22. SectorLabel2    db    9,'Sector $' 
  23. SectorLabel    db    13,'Sectors $'
  24. DashLabel    db    ' - $'
  25. ErrorLabel    db    ': Error!'
  26. CRLF        db    13,10,'$'
  27. ErrorAddr    dw    Err0,Err1,Err2,Err3,Err4,Err5,Err6,Err7
  28.         dw    Err8,Err9,ErrA,ErrB,ErrC,ErrD,ErrD,ErrD  
  29. Err0        db    'Write Protect$'
  30. Err1        db    'Unknown Unit$'
  31. Err2        db    'Drive Not Ready$'
  32. Err3        db    'Unknown Command$'
  33. Err4        db    'CRC Error$'
  34. Err5        db    'Request Length$'
  35. Err6        db    'Seek Error$'
  36. Err7        db    'Unknown Media$'
  37. Err8        db    'Sector Not Found$'
  38. Err9        db    'No Paper$'
  39. ErrA        db    'Write Fault$'
  40. ErrB        db    'Read Fault$'
  41. ErrC        db    'General Failure$'
  42. ErrD        db    'Undocumented Error$'
  43. BootSectMsg    db    'Boot Sector$'
  44. RootDirMsg    db    'Root Directory$'
  45. BadFatMsg    db    'File Alloc. Table$'
  46. InUseMsg    db    'Used by file$'
  47. NotInUseMsg    db    'Unallocated$'
  48. BadFlagMsg    db    'Flagged as bad$'    
  49. FatReadMsg    db    "Can't Read FAT$"
  50. Divisors    dw    10000, 1000, 100, 10, 1    ; For decimal conversion
  51.  
  52. ;    Check Drive Parameter, DOS Version, and Enough Memory
  53. ;    -----------------------------------------------------
  54.  
  55. ErrorExit:    Mov    AH,9        ; Write error message
  56.         Int    21h        ;      through DOS
  57.         Int    20h        ; And terminate
  58.  
  59. Begin:        Mov    DX, Offset DriveError    ; Possible message
  60.         Or    AL, AL        ; Check Drive Validity Byte
  61.         Jnz    ErrorExit    ; If not zero, invalid drive
  62.         Mov    DX, Offset DosVersErr    ; Possible message
  63.         Mov    AH, 30h
  64.         Int    21h        ; Get DOS Version Number
  65.         Cmp    AL, 2        ; Check for 2.0 or later
  66.         Jb    ErrorExit    ; If not, terminate with message 
  67.         Mov    DX, Offset MemoryError    ; Possible error message
  68.         Mov    BX, 256+Offset EndProg    ; Set beyond program 
  69.         Mov    SP, BX        ; Move stack closer to code
  70.         Add    BX, 15        ; Add 15 to round up
  71.         Mov    CL, 4        ; Divide BX by 16
  72.         Shr    BX, CL
  73.         Mov    AH, 4Ah        ; Free allocated memory
  74.         Int    21h        ;   by calling DOS Set Block
  75.         Jc    ErrorExit    ; Terminate on error
  76.         Mov    BX, 1000h    ; Ask for 64K bytes
  77.         Mov    AH, 48h        ;   by using DOS
  78.         Int    21h        ;   Allocate Memory call
  79.         Jc    ErrorExit    ; Terminate on error
  80.         Mov    [ReadSegment], AX    ; Save segment of memory block
  81.  
  82. ;    Get Disk Information From DOS
  83. ;    -----------------------------
  84.  
  85.         Mov    DL, DS:[005Ch]    ; Get Drive Parameter
  86.         Push    DS        ; Save DS
  87.         Mov    AH, 32h        ; Call DOS to
  88.         Int    21h        ;   get DOS Disk Block (DS:BX)
  89.         Mov    SI, BX        ; Now DS:SI points to Disk Block
  90.         Mov    DI, Offset DiskBlock    ; DI points to destination
  91.         Mov    CX, 18        ; 18 bytes to copy'
  92.         Cld            ; Forward direction
  93.         Rep    Movsb        ; Move 'em in
  94.         Pop    DS        ; Get back DS
  95.         Mov    BX, Offset DiskBlock    ; BX to address Disk Block 
  96.         Mov    DX, 1        ; Set DX:AX to 65,536
  97.         Sub    AX, AX
  98.         Div    Word Ptr [BX + 2]    ; Divide by Bytes Per Sector
  99.         Mov    [SectorsIn64K], AX    ; Save that values
  100.         Mov    AX, [BX + 13]        ; Last Cluster Number
  101.         Dec    AX            ; AX = Number of Clusters
  102.         Mov    CL, [BX + 5]        ; Cluster to Sector Shift
  103.         Shl    AX, CL            ; AX = Number Data Sectors
  104.         Add    AX, [BX + 11]        ; Add First Data Sector
  105.         Mov    [TotalSectors], AX    ; AX = Number Total Sectors
  106.         Mov    AL, DS:[005Ch]    ; Drive Number (0=def, 1=A)
  107.         Dec    AL        ; Make it 0=A, 1=B
  108.         Jns    GotDriveNumber    ; If no sign, not default drive
  109.         Mov    AH, 19h        ; Get current disk 
  110.         Int    21h        ;   by calling DOS
  111.  
  112. GotDriveNumber:    Mov    [DriveNum], AL    ; Save Drive Number (0=A, 1=B)
  113.  
  114. ;    Start Reading
  115. ;    -------------    
  116.  
  117. MainLoop:    Mov    DX, Offset SectorLabel    ; String to display on screen
  118.         Call    StringWrite        ; Display it
  119.         Mov    AX, [StartSector]    ; Starting sector number
  120.         Call    WordWrite        ; Display number on screen
  121.         Mov    DX, Offset DashLabel    ; String containing a dash
  122.         Call    StringWrite        ; Display it on the screen
  123.         Mov    CX, [SectorsIn64K]    ; Number of sectors to read
  124.         Add    AX, CX            ; Add it to starting sector
  125.         Jc    NumRecalc
  126.         Cmp    AX, [TotalSectors]    ; See if bigger than total
  127.         Jbe    NumSectorsOK        ; If so, proceed
  128.  
  129. NumRecalc:    Mov    AX, [TotalSectors]    ; Otherwise get total sectors
  130.         Mov    CX, AX            ; Move it to CX also
  131.         Sub    CX, [StartSector]    ; Now CX = sectors to read
  132.  
  133. NumSectorsOK:    Dec    AX            ; AX = last sector to read
  134.         Call    WordWrite        ; Display it on screen
  135.         Call    ReadSectors        ; Read the sectors
  136.         Jnc    NextSectors        ; If no error, skip detail
  137.         Call    ReadSectors        ; Repeat read
  138.         Jnc    NextSectors        ; If still no error, skip
  139.  
  140. DiskError:    Mov    DX, Offset ErrorLabel    ; String saying "Error!"
  141.         Call    StringWrite        ; Display it on screen
  142.  
  143. ErrorLoop:    Push    CX            ; Now save previous number
  144.         Mov    CX, 1            ; So we can read one at a time
  145.         Call    ReadSectors        ; Read one sector
  146.         Jnc    NoError            ; If no error, proceed
  147.         Mov    BL, AL            ; Save error code
  148.         Mov    DX, Offset SectorLabel2    ; String with "Sector "
  149.         Call    StringWrite        ; Display it on screen
  150.         Mov    AX, [StartSector]    ; The sector we just read
  151.         Call    WordWrite        ; Display it on screen
  152.         Mov    DX, Offset DashLabel    ; String with a dash
  153.         Call    StringWrite        ; Display it on screen
  154.         And    BL, 0Fh            ; Blank out error top bits
  155.         Sub    BH, BH            ; Now BX is error code
  156.         Add    BX, BX            ; Double it for word access
  157.         Mov    DX, [ErrorAddr + BX]    ; Get address of message
  158.         Call    StringWrite        ; Display message on screen
  159.         Call    FindSector        ; See where sector is 
  160.         Mov    DX, Offset CRLF        ; String for new line 
  161.         Call    StringWrite        ; Do carriage ret & line feed 
  162.  
  163. NoError:    Inc    [StartSector]        ; Kick up the start sector
  164.         Pop    CX            ; Get back counter
  165.         Loop    ErrorLoop        ; And read next sector
  166.         Mov    AX, [StartSector]    ; Sector of next group
  167.         Jmp    Short CheckFinish    ; Check if at end yet
  168.  
  169. NextSectors:    Mov    AX, [StartSector]    ; For no error, increment 
  170.         Add    AX, [SectorsIn64K]    ;   StartSector for next group
  171.         Jc    Terminate        ; (If overflow, terminate)
  172.         Mov    [StartSector], AX    ; And save it
  173.  
  174. CheckFinish:    Cmp    AX, [TotalSectors]    ; See if at then end
  175.         Jae    Terminate        ; If so, just terminate
  176.         Jmp    MainLoop        ; If not, do it again
  177.  
  178. Terminate:    Int    20h            ; Terminate
  179.  
  180. ;    Find Sector in FAT to see if used by file, etc.
  181. ;    -----------------------------------------------
  182.  
  183. FindSector:    Mov    DX, Offset DashLabel        ; Print dash
  184.         Call    StringWrite
  185.         Mov    AX, [StartSector]        ; Sector with error
  186.         Mov    DX, Offset BootSectMsg        ; Set up message
  187.         Cmp    AX, Word Ptr [DiskBlock + 6]    ; See if sector boot
  188.         Jb    PrintMsg            ; If so, print as such
  189.         Mov    DX, Offset BadFatMsg        ; Set up message
  190.         Cmp    AX, Word Ptr [DiskBlock + 16]    ; See if sector in FAT
  191.          Jb    PrintMsg            ; If so, print as such
  192.         Mov    DX, Offset RootDirMsg        ; Set up message
  193.         Cmp    AX, Word Ptr [DiskBlock + 11]    ; See if sector in dir
  194.         Jb    PrintMsg            ; If so, print as such
  195.         Push    [StartSector]            ; Save the sector
  196.         Mov    AX, Word Ptr [DiskBlock + 6]    ; Reserved sectors
  197.         Mov    [StartSector], AX        ; Start of first FAT
  198.         Mov    CL, [DiskBlock + 15]        ; Sectors for FAT
  199.         Sub    CH, CH                ; Zero out top byte        
  200.         Call    ReadSectors            ; Read in FAT
  201.         Pop    [StartSector]            ; Get back bad sector
  202.         Mov    DX, Offset FatReadMsg        ; Set up possible msg
  203.         Jc    PrintMsg            ; If read error, print
  204.         Mov    AX, [StartSector]        ; Get bad sector
  205.         Sub    AX, Word Ptr [DiskBlock + 11]    ; Subtract data start
  206.         Mov    CL, [DiskBlock + 5]        ; Sector Shift
  207.         Shr    AX, CL                ; Shift the sector
  208.         Add    AX, 2                ; AX is now cluster
  209.         Push    ES            ; Save ES for awhile                
  210.         Mov    ES, [ReadSegment]    ; ES segment of FAT
  211.         Cmp    Word Ptr [DiskBlock + 13], 0FF0h; 12 or 16-bit FAT?
  212.         Jge    Fat16Bit        ; And jump accordingly
  213.         Mov    BX, AX            ; This is cluster number
  214.         Mov    SI, AX            ; So is this
  215.         Shr    BX, 1            ; This is one-half cluster
  216.         Mov    AX, ES:[BX + SI]    ; BX + SI = 1.5 CX
  217.         Jnc    NoShift            ; If no CY from shift, got it
  218.         Mov    CL, 4            ; If CY from shift must
  219.         Shr    AX, CL            ;   shift word 4 bits right
  220.  
  221. NoShift:    Or    AX, 0F000h        ; Now put 1's in top bits
  222.         Cmp    AX, 0F000h        ; See if zero otherwise
  223.         Jmp    Short CheckWord        ; And continue checking
  224.  
  225. Fat16Bit:    Mov    BX, AX            ; This is cluster number
  226.         Shl    BX, 1            ; Double it
  227.         Mov    AX, ES:[BX]        ; Pull out word from sector
  228.         Or    AX, AX            ; See if zero (unallocated)
  229.  
  230. CheckWord:    Pop    ES            ; Get back ES
  231.         Mov    DX, Offset NotInUseMsg    ; Set up possible message
  232.         Jz    PrintMsg        ; If so, print message
  233.         Mov    DX, Offset BadFlagMsg    ; Set up possible message
  234.         Cmp    AX, 0FFF7h        ; See if cluster flagged bad
  235.         Jz    PrintMsg        ; If so, print message
  236.         Mov    DX, Offset InUseMsg    ; If not, cluster is in use
  237.  
  238. PrintMsg:    Call    StringWrite        ; Print cluster disposition
  239.         Ret                ; And return
  240.  
  241. ;    Read Sectors (CX = Number of Sectors, Return CY and AL for error)
  242. ;    -----------------------------------------------------------------
  243.  
  244. ReadSectors:    Push    BX            ; Push all needed registers
  245.         Push    CX
  246.         Push    DX
  247.         Push    DS
  248.         Mov    AL, [DriveNum]        ; Get the drive number code
  249.         Sub    BX, BX            ; Buffer address offset
  250.         Mov    DX, [StartSector]    ; Starting Sector
  251.         Mov    DS, [ReadSegment]    ; Buffer address segment
  252.         Int    25h            ; Absolute Disk Read
  253.         Pop    BX            ; Fix up stack
  254.         Pop    DS            ; Get back registers
  255.         Pop    DX
  256.         Pop    CX
  257.         Pop    BX
  258.         Ret                ; Return to program 
  259.  
  260. ;    Screen Display Routines
  261. ;    -----------------------
  262.  
  263. WordWrite:    Push    AX            ; Push some registers
  264.         Push    BX            ; AX contains word to display
  265.         Push    CX
  266.         Push    DX
  267.         Push    SI
  268.         Mov    SI, Offset Divisors    ; SI points to divisors
  269.         Mov    CX, 4            ; CL counter; CH zero blanker 
  270.  
  271. WordWriteLoop:    Mov    BX, [SI]        ; Get divisor 
  272.         Add    SI, 2            ; Increment SI for next one
  273.         Sub    DX, DX            ; Prepare for division
  274.         Div    BX            ; Divide DX:AX by BX
  275.         Push    DX            ; Save remainder
  276.         Or    CH, AL            ; See if zero
  277.         Jz    LeadZero        ; If so, do not display it
  278.         Add    AL, '0'            ; Convert number to ASCII
  279.         Mov    DL, AL            ; Print out character
  280.         Mov    AH, 2            ;   by calling DOS
  281.         Int    21h
  282.  
  283. LeadZero:    Pop    AX            ; Get back remainder
  284.         Dec    CL            ; Decrement counter
  285.         Jg    WordWriteLoop        ; If CL still > 0, do it again
  286.         Mov    CH, 1            ; No more zero blanking
  287.         Jz    WordWriteLoop        ; Convert last digit to ASCII
  288.         Pop    SI            ; Get back pushed registers
  289.         Pop    DX
  290.         Pop    CX
  291.         Pop    BX
  292.         Pop    AX
  293.         Ret
  294.  
  295. StringWrite:    Push    AX            ; Displays string from DX
  296.         Mov    AH, 9            ;   to screen by calling DOS
  297.         Int    21h
  298.         Pop    AX
  299.         Ret
  300.  
  301. EndProg        Label    Byte            ; End of program
  302. CSEG        EndS
  303.         End    Entry
  304.