ÖÛÖÛÖÛÖÛÖÛÖÛÖÛÖÛSCAV1XX ASM;SCAV2XX ASM<?ÿÛÖÛÖÛÖÛÖÛÖÛÖÛÖÛÖÛÖÛÖÛÖÛÖÛÖÛÖÛÖÛtitle scavenge -- MSDOS bad block mapper ; ;**************************************** ;* * ;* SCAVENGE * ;* * ;* Mark bad blocks on MSDOS * ;* as allocated in the FAT. * ;* * ;* T. Jennings 29 Sept. 82 * ;* created 15 Sept. 82 * ;* * ;**************************************** ; ;Reads all sectors in logical MSDOS blocks ;and marks the file allocation tables such ;that the blocks are permanently allocated ;where CHKDSK will not deallocate them. ; ;This version works on any pre-2.00 MSDOS or ;PCDOS, on any media type, fixed or removable. ;One (major) limitation: it will not map out ;blocks that are already allocated to a file; ;it will say "block used", but won't tell you ;which file it is in. ; ;If SCAVENGE finds any bad blocks, it will ask ;you whether or not you want the disk updated. ;You can safely run it just to see if the disk ;is OK. ; cr equ 0dh lf equ 0ah page cgroup group code code segment byte public 'code' assume cs:cgroup,ds:cgroup,ss:cgroup ; ;MSDOS page 0 stuff. ; org 5ch tfcb label byte org 80h tbuff label byte org 100h main: jmp start ; ;Disk parameters: ; blkcnt dw (?) ;blocks this disk blksize dw (?) ;sectors per block secsize dw (?) ;phys. sector size badcnt dw (?) ;# bad blocks found newbad dw (?) ;new bad ones block dw (?) ;current block sector dw (?) ;sector to read disk db (?) ;selected disk curdsk db (?) ;current disk. dw 128 dup (?) stack dw (?) ;what else page ; ;Say who we are, describe the disk we are ;about to fix, ask to continue or abort. ; start: mov ax,cs mov ds,ax mov ss,ax mov sp,offset stack mov dx,offset signon call pstr call setup ;get disk stuff jnc st1 mov dx,offset strstr call pstr int 32 ;error. st1: call liststat ;describe dsk mov dx,offset contstr call pstr ;type any key.. call ina ; ;Find all the bad blocks, if any, display them, ;ask if we should update the FAT. If so, mark ;it dirty so MSDOS will update it. ; mov dx,offset crlf call pstr call findbad ;map bad, call listbad ;list them, cmp newbad,0 ;if new bad je st2 ;blocks... mov dx,offset updstr ;ask if we call pstr ;should update call ina and al,5fh cmp al,'Y' jne st2 mov byte ptr es:[di-1],1 ;FAT changed. st2: mov al,curdsk ;reselect the call seldsk ;original disk int 32 signon db cr,lf,'MSDOS 1.25 Bad Sector Mapper' db cr,lf,' T. Jennings 29 Sept. 82' db '$' strstr db cr,lf,'Must specify a disk drive.$' contstr db cr,lf,'Type ^C to abort, any ' db 'other key to continue: $' updstr db cr,lf,lf,' Want the disk updated? [y,n] :$' crlf db cr,lf,'$' page ; ;Get the data on the specified disk. Return ;carry if no drive specified. Returns ES:DI ;pointing to the FAT for the selected drive. ; setup: call initdsk ;reset dsk sys, call getdsk ;get current, mov curdsk,al ;save it, mov al,tfcb ;make sure a cmp al,0 ;new one spec'd stc ;quit if none, jz gd1 dec al ;make 0-N, mov disk,al call seldsk ;select, push ds ;save local DS, mov ah,1bh int 33 push ds pop es ;point ES:DI to mov di,bx ;FAT, pop ds mov blkcnt,dx ;save # blocks, mov secsize,cx ;sector size, mov ah,0 mov blksize,ax ;secs/block. clc ;no error, gd1: ret page ; ;Read the entire disk looking for bad blocks. ;When one is found, go mark it as an allocated ;bad block. ; findbad: mov block,0 ;1st block, mov badcnt,0 ;none yet, fb1: mov dx,offset blkstr ;type 'block ' call pstr mov bx,block ;block number, call outdec call readblk ;read a block, jnc fb3 ;if bad, inc badcnt ;count it, mov dx,offset badstr call pstr ;type 'bad' call mapout ;mark bad, mov dx,offset cntstr ;error if cant jc fb2 add newbad,cx ;count it, mov dx,offset alrstr jcxz fb2 ;already markd mov dx,offset mrkstr fb2: call pstr fb3: inc block ;next block, dec blkcnt ;another... jnz fb1 ;keep looking. ret blkstr db cr,'Block $' badstr db ' bad,$' alrstr db ' already marked.',cr,lf,'$' mrkstr db ' mapped out.',lf,'$' cntstr db ' already used! I dont know' db ' which file.',lf,'$' page ; ;Mark the current block as bad in the FAT. ;Multiply the block number by 1.5 to find the ;block number, (actually *3, /2) and if not ;used, mark it bad. If used, report which file ;it's in. If it's already mapped as bad, ;return CX =0, else return CX=1. ; mapout: mov bx,block ;block, shl bx,1 ;times 2, add bx,block ;times 3, shr bx,1 ;divide by 2, mov ax,es:[di+bx] ;get word, ; ;If carry is set, we want the high 12 bits in ;the word in AX, else the low 12 bits. Set CH ;as the shift count, DX as the mask. ; mov ch,0 ;assume low, mov dx,0fffh jnc mo1 mov ch,4 ;else high 12, mov dx,0fff0h mo1: and ax,dx ;mask it, mov cl,ch shr ax,cl ;shift it, ; ;AX is the block number; if it's anything ;but 000 or ff7, return with carry set, ;indicating that its already used. ; cmp ax,0ff7h ;if ff7, je mo2 ;already marked cmp ax,0 ;if allocated, je mo3 stc ;error! mo2: mov cx,0 ;none mapped, ret ; ;Bad unused block. Mark as bad in the FAT. ; mo3: mov ax,0ff7h ;marker, mov cl,ch shl ax,cl ;shift it, or es:[di+bx],ax ;mark it. mov cx,1 ;1 mapped, ret page ; ;Read one block, return carry set if read ;error. Leave the useless data in the buffer ;following the end of this program. ; readblk: mov ax,block ;find start mov cx,blksize ;sector, mul cx ;CX= count, mov dx,ax ;DX= sector, mov al,disk mov bx,offset blkbuf ;our buffer, int 25h ;read sectors, pop dx ;pop flags, ret page ; ;List the general info on the disk, like ;sector sizes, etc. ; liststat: mov dx,offset st1str call pstr mov al,disk add al,'A' call outa mov dx,offset st2str call pstr mov bx,blkcnt call outdec mov dx,offset st3str call pstr ret ;Disk A:, total of 12345 data blocks. st1str db cr,lf,'Disk $' st2str db ':, total of $' st3str db ' data blocks.$' ; ;List out the bad things about this disk. ; listbad: mov dx,offset bd1str call pstr mov bx,badcnt call outdec mov dx,offset bd2str call pstr mov bx,newbad call outdec mov dx,offset bd3str call pstr ret ;Total of 12345 bad blocks, found 12234 more this pass. bd1str db cr,'Total of $' ;note no linefeed. bd2str db ' bad blocks, found $' bd3str db ' more this pass.$' page ; ;Generally useful system calls. ; pstr: mov ah,9 int 33 ret ; ;Type BX in decimal, suppressing leading ;zeros. ; outdec: mov cl,0 ;0 suppress flag, mov dx,10000 call rsdiv mov dx,1000 call rsdiv mov dx,100 call rsdiv mov dx,10 call rsdiv mov ch,bl jmp odf rsdiv: mov ch,-1 ;iteration -1, rs1: inc ch ;count, sub bx,dx ;subtract, jnc rs1 ;til underflow, add bx,dx ;adjust back, cmp ch,0 ;if non-zero, jne odf ;type it, test cl,1 ;dont type 0's jnz odf ;if leading, ret odf: push dx mov dl,ch add dl,'0' ;ASCII, mov ah,2 int 33 pop dx mov cl,1 ;no suppress, ret page ; ;More system calls. ; seldsk: mov dl,al ;select disk, mov ah,0eh int 33 ret getdsk: mov ah,19h int 33 ret initdsk:mov ah,0dh int 33 ret ina: mov ah,0ch ;char in with mov al,1 ;flush. int 33 ret outa: mov dl,al mov ah,2 int 33 ret blkbuf equ $ ;block buffer. code ends end title scavenge -- MSDOS bad block mapper ; ;**************************************** ;* * ;* SCAVENGE * ;* * ;* Mark bad blocks on MSDOS * ;* as allocated in the FAT. * ;* * ;* T. Jennings 5 June 82 * ;* created 15 Sept. 82 * ;* * ;**************************************** ; ;Reads all sectors in logical MSDOS blocks ;and marks the file allocation tables such ;that the blocks are permanently allocated ;where CHKDSK will not deallocate them. ; ; ;This version works on any 2.xx MSDOS or ;PCDOS, on any media type, fixed or removable. ;One (major) limitation: it will not map out ;blocks that are already allocated to a file; ;it will say "block used", but won't tell you ;which file it is in. ; ;If SCAVENGE finds any bad blocks, it will ask ;you whether or not you want the disk updated. ;You can safely run it just to see if the disk ;is OK. ; cr equ 0dh lf equ 0ah page cgroup group code code segment byte public 'code' assume cs:cgroup,ds:cgroup,ss:cgroup ; ;MSDOS page 0 stuff. ; org 5ch tfcb label byte org 80h tbuff label byte org 100h scavenge: jmp start ; ;Disk parameters: ; blkcnt dw (?) ;blocks this disk blksize dw (?) ;sectors per block secsize dw (?) ;phys. sector size badcnt dw (?) ;# bad blocks found newbad dw (?) ;new bad ones block dw (?) ;current block sector dw (?) ;sector to read disk db (?) ;selected disk curdsk db (?) ;current disk. fatsec dw (?) ;1st FAT sector, fatcnt dw (?) ;FAT sec count. dw 128 dup (?) stack dw (?) ;what else page ; ;Say who we are, describe the disk we are ;about to fix, ask to continue or abort. ; start: mov ax,cs mov ds,ax mov ss,ax mov sp,offset stack mov dx,offset signon call pstr call setup ;get disk stuff jnc st1 call pstr int 32 ;error. st1: call liststat ;describe dsk mov dx,offset contstr call pstr ;type any key.. call ina ; ;Find all the bad blocks, if any, display them, ;ask if we should update the FAT. If so, write ;it out. ; mov dx,offset crlf call pstr call findbad ;map bad, call listbad ;list them, cmp newbad,0 ;if new bad je st2 ;blocks... mov dx,offset updstr ;ask if we call pstr ;should update call ina and al,5fh cmp al,'Y' jne st2 mov al,disk ;write out the mov dx,fatsec ;FAT, mov cx,fatcnt mov bx,offset fatbuf int 26h pop ax ;pop flags st2: mov al,curdsk ;reselect the call seldsk ;original disk int 32 signon db cr,lf,'MSDOS 2.00 Bad Sector Mapper' db cr,lf,' T. Jennings 5 June 83' db '$' contstr db cr,lf,'Type ^C to abort, any ' db 'other key to continue: $' updstr db cr,lf,lf,' Want the disk updated? [y,n] :$' crlf db cr,lf,'$' page ; ;Get the data on the specified disk. Return ;carry if no drive specified. Returns ES:DI ;pointing to the FAT for the selected drive. ; setup: call initdsk ;reset dsk sys, call getdsk ;get current, mov curdsk,al ;save it, mov al,tfcb ;make sure a cmp al,0 ;new one spec'd stc ;quit if none, mov dx,offset strstr jz gd1 dec al ;make 0-N, mov disk,al call seldsk ;select, push ds ;save local DS, mov ah,1bh int 33 pop ds mov blkcnt,dx ;save # blocks, mov secsize,cx ;sector size, mov ah,0 mov blksize,ax ;secs/block. push ds ;now get the mov dl,disk inc dl ;drive 1=A, b=2 mov ah,50 ;FAT, int 33 ;get the DPB, mov cx,[bx+15] ;CX= sec count, mov ch,0 mov dx,[bx+6] ;DX= 1st sec, pop ds mov fatcnt,cx ;save both, mov fatsec,dx mov al,disk ;AL= drive #, mov bx,offset fatbuf ;DS:BX= buffer int 25h ;read the FAT, pop ax ;pop flags mov dx,offset bscstr gd1: ret strstr db cr,lf,'Must specify a disk drive.$' bscstr db cr,lf,'Bad FAT sector: disk not useable.$' page ; ;Read the entire disk looking for bad blocks. ;When one is found, go mark it as an allocated ;bad block. ; findbad: mov block,0 ;1st block, mov badcnt,0 ;none yet, fb1: mov dx,offset blkstr ;type 'block ' call pstr mov bx,block ;block number, call outdec call readblk ;read a block, jnc fb3 ;if bad, inc badcnt ;count it, mov dx,offset badstr call pstr ;type 'bad' call mapout ;mark bad, mov dx,offset cntstr ;error if cant jc fb2 add newbad,cx ;count it, mov dx,offset alrstr jcxz fb2 ;already markd mov dx,offset mrkstr fb2: call pstr fb3: inc block ;next block, dec blkcnt ;another... jnz fb1 ;keep looking. ret blkstr db cr,'Block $' badstr db ' bad,$' alrstr db ' already marked.',cr,lf,'$' mrkstr db ' mapped out.',lf,'$' cntstr db ' already used! I dont know' db ' which file.',lf,'$' page ; ;Mark the current block as bad in the FAT. ;Multiply the block number by 1.5 to find the ;block number, (actually *3, /2) and if not ;used, mark it bad. If used, report which file ;it's in. If it's already mapped as bad, ;return CX =0, else return CX=1. ; mapout: mov bx,block ;block, shl bx,1 ;times 2, add bx,block ;times 3, shr bx,1 ;divide by 2, mov ax,fatbuf[bx] ;get word, ; ;If carry is set, we want the high 12 bits in ;the word in AX, else the low 12 bits. Set CH ;as the shift count, DX as the mask. ; mov ch,0 ;assume low, mov dx,0fffh jnc mo1 mov ch,4 ;else high 12, mov dx,0fff0h mo1: and ax,dx ;mask it, mov cl,ch shr ax,cl ;shift it, ; ;AX is the block number; if it's anything ;but 000 or ff7, return with carry set, ;indicating that its already used. ; cmp ax,0ff7h ;if ff7, je mo2 ;already marked cmp ax,0 ;if allocated, je mo3 stc ;error! mo2: mov cx,0 ;none mapped, ret ; ;Bad unused block. Mark as bad in the FAT. ; mo3: mov ax,0ff7h ;marker, mov cl,ch shl ax,cl ;shift it, or fatbuf[bx],ax ;mark it. mov cx,1 ;1 mapped, ret page ; ;Read one block, return carry set if read ;error. Leave the useless data in the buffer ;following the end of this program. ; readblk: mov ax,block ;find start mov cx,blksize ;sector, mul cx ;CX= count, mov dx,ax ;DX= sector, mov al,disk mov bx,offset blkbuf ;our buffer, int 25h ;read sectors, pop dx ;pop flags, ret page ; ;List the general info on the disk, like ;sector sizes, etc. ; liststat: mov dx,offset st1str call pstr mov al,disk add al,'A' call outa mov dx,offset st2str call pstr mov bx,blkcnt call outdec mov dx,offset st3str call pstr ret ;Disk A:, total of 12345 data blocks. st1str db cr,lf,'Disk $' st2str db ':, total of $' st3str db ' data blocks.$' ; ;List out the bad things about this disk. ; listbad: mov dx,offset bd1str call pstr mov bx,badcnt call outdec mov dx,offset bd2str call pstr mov bx,newbad call outdec mov dx,offset bd3str call pstr ret ;Total of 12345 bad blocks, found 12234 more this pass. bd1str db cr,'Total of $' ;note no linefeed. bd2str db ' bad blocks, found $' bd3str db ' more this pass.$' page ; ;Generally useful system calls. ; pstr: mov ah,9 int 33 ret ; ;Type BX in decimal, suppressing leading ;zeros. ; outdec: mov cl,0 ;0 suppress flag, mov dx,10000 call rsdiv mov dx,1000 call rsdiv mov dx,100 call rsdiv mov dx,10 call rsdiv mov ch,bl jmp odf rsdiv: mov ch,-1 ;iteration -1, rs1: inc ch ;count, sub bx,dx ;subtract, jnc rs1 ;til underflow, add bx,dx ;adjust back, cmp ch,0 ;if non-zero, jne odf ;type it, test cl,1 ;dont type 0's jnz odf ;if leading, ret odf: push dx mov dl,ch add dl,'0' ;ASCII, mov ah,2 int 33 pop dx mov cl,1 ;no suppress, ret page ; ;More system calls. ; seldsk: mov dl,al ;select disk, mov ah,0eh int 33 ret getdsk: mov ah,19h int 33 ret initdsk:mov ah,0dh int 33 ret ina: mov ah,0ch ;char in with mov al,1 ;flush. int 33 ret outa: mov dl,al mov ah,2 int 33 ret blkbuf db 16384 dup (?) ;cluster buffer fatbuf label word ;FAT buffer. code ends end scavenge