home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS - Coast to Coast
/
simteldosarchivecoasttocoast.iso
/
pcmag
/
vol5n21.zip
/
DISKPREP.ASM
next >
Wrap
Assembly Source File
|
1987-12-13
|
32KB
|
558 lines
code segment para public 'code'
assume cs:code,ds:code,es:code
org 100h
begin: jmp prep ;skip data area
;
copy_right db 13,10,'Copyright 1986 Ziff-Davis Publishing Co.',13,10,'$'
errmsg1 db 13,10,'Invalid Drive Specifier',13,10,'$'
errmsg2 db 13,10,'Illegal Disk Format',13,10,'$'
errmsg3 db 13,10,'Disk Read Error',13,10,'$'
errmsg4 db 13,10,'Disk Write Error',13,10,'$'
errmsg5 db 13,10,'Insufficient Space in Disk Directory',13,10,'$'
errmsg6 db 13,10,'Insufficient Disk Space',13,10,'$'
errmsg7 db 13,10,'Allocation Chain Error',13,10,'$'
errmsg8 db 13,10,'Cannot Delete System Files',13,10,'$'
errmsg9 db 13,10,'Bad Sector in System Area',13,10,'$'
msg1 db 13,10,'System Prep Completed',13,10,'$'
msg2 db 13,10,'System Already Installed - Delete Old System (Y/N)?',13,10,'$'
msg3 db 13,10,'Execution Aborted',13,10,'$'
;
last_cluster dw 41 ;last available cluster found
sec_per_cluster dw ? ;number of sectors per cluster
clusters dw ? ;total number of data clusters on disk
DIR_entries dw ? ;maximum number of directory entries
DIR_sectors dw ? ;number of sectors used for directory
FAT_sectors dw ? ;number of sectors used for one copy of the FAT
FAT_entry dw ? ;temporary storage for any FAT entry
drive db ? ;current disk drive
format_table dw 64,4,2 ;S-9 disk format parameters
dw 112,7,2 ;D-9 " " "
dw 64,4,1 ;S-8 " " "
dw 112,7,1 ;D-8 " " "
system_id db 'IBMBIO',32,32,'COM' ;text of system file IBMBIO.COM
ibmbio db 'B:IBMBIO.COM',0 ;ASCIIZ string for DOS file functions
ibmdos db 'B:IBMDOS.COM',0 ; " " " " " "
cbuffer dw offset endprog ;pointer to buffer area for cluster transfers
FAT_data dw offset endprog + 1024 ;pointer to area where FAT image is stored
DIR_data dw offset endprog + 2048 ;pointer to area where DIR image is stored
;
prep proc near ;start of main program
;
;Parse the command line for a drive specifier. If none, use default drive.
;
cld ;clear DF for string operations
mov si,80h ;point si to start of command line
lodsb ;get number of characters entered
cmp al,1 ;one or less characters specified?
jbe prep1 ;yes, then use default drive
inc si ;skip first delimiter
lodsb ;get first character (drive specifier)
and al,0DFh ;capitalize it
sub al,'A' ;convert ASCII to drive number
cmp al,1 ;is drive specified either A: or B:?
jbe prep2 ;yes, then parsing is finished
lea dx,errmsg1 ;no, then specifier is illegal
jmp error_exit ;load error message address and abort
prep1: mov ah,19h ;DOS function 19h - get current drive
int 21h ;get default drive number
cmp al,1 ;is it drive A: or B:?
jbe prep2 ;yes, then skip error routine
lea dx,errmsg1 ;no, then get message address and abort
;
;Program execution is routed here when a critical error condition is detected.
;
error_exit: mov ah,9 ;DOS function number - print string
int 21h ;print error message
mov ah,14 ;ROM BIOS teletype routine function number
mov al,7 ;ASCII code for beep
int 10h ;'print' the beep
error1: mov ah,4Ch ;DOS function number - exit
mov al,1 ;set ERRORLEVEL return code to 1
int 21h ;terminate program on error
;
; Check the format of the disk to verify that it's a 40-track diskette
; (8 or 9 sectors per track, one or two sides).
; Store information pertaining to the disk format.
;
prep2: mov drive,al ;save current drive ID
mov dl,al ;get drive identifier in DL
inc dl ;adjust drive ID for DOS function call
push ds ;save segment register
mov ah,1Ch ;DOS function number-get FAT information
int 21h ;get pointer to FAT ID byte
mov cl,[bx] ;store ID byte in CL
pop ds ;restore DS
cmp cl,0FCh ;ID byte greater than or equal to FCh?
jae prep2a ;yes, then format is OK
lea dx,errmsg2 ;no, then format is invalid
jmp error_exit ;abort on error
prep2a: cbw ;convert byte in AL to word in AX
mov sec_per_cluster,ax ;store number of sectors per cluster
mov clusters,dx ;store total number of data clusters
sub cl,0FCh ;normalize ID byte by subtracting FCh
mov al,cl
mov dl,6
mul dl ;multiply result by 6
mov bl,al ;transfer table index in AL to BL
xor bh,bh ;convert byte to word
add bx,offset format_table ;form address of disk format
;parameter line
mov ax,[bx] ;read number of dir entries from table
mov DIR_entries,ax ;save number of entries
mov ax,[bx+2] ;read directory length from table
mov DIR_sectors,ax ;save directory length
mov ax,[bx+4] ;read FAT length from table
mov FAT_sectors,ax ;save FAT length
;
;Read root directory and one copy of FAT into memory from the selected drive.
;
prep3: call read_FAT ;read in one copy of the File Allocation Table
jnc prep3a ;continue if no error on read
lea dx,errmsg3 ;exit if error occurred during read
jmp error_exit
prep3a: call read_DIR ;read in the disk directory
jnc prep4 ;continue if no error
lea dx,errmsg3 ;otherwise abort
jmp error_exit
;
;Determine if the disk is already system formatted by seeing if the first
;file in the directory is IBMBIO.COM.
;
prep4: lea si,system_id ;point SI to 'IBMBIO.COM' text
mov di,DIR_data ;point DI to first filename
mov cx,11 ;11 bytes to check
repe cmpsb ;compare the two strings
jne prep6 ;skip delete routine if no system
;
;Disk already system formatted--see if user wants to delete the system files.
;
lea dx,msg2 ;get query message address
mov ah,9 ;DOS function number - print string
int 21h ;print 'Delete System?' message
prep5: mov ah,0 ;ROM BIOS function number - get keypress
int 16h ;get user response from keyboard
and al,0DFh ;capitalize entry
cmp al,'Y' ;was 'Y' pressed?
je prep5a ;yes - delete system files
cmp al,'N' ;was 'N' pressed?
jne prep5 ;no, then get another keypress
lea dx,msg3 ;get abort message address
mov ah,9 ;print 'Execution Aborted' message
int 21h
jmp error1 ;exit with ERRORLEVEL set to 1
;
;Delete system files - change file attributes to 0 (eliminating read-only bit)
;before using DOS delete function.
;
prep5a: cmp drive,1 ;is B: the current drive?
je prep5b ;yes, then continue
dec ibmbio ;no, set ASCIIZ drive designators to A:
dec ibmdos
prep5b: lea dx,ibmbio ;change IBMBIO.COM file attribute for deletion
mov ah,43h ;DOS function number - change attribute
mov cx,0 ;new file attribute
mov al,1 ;specify that attribute is to be changed
int 21h ;zero IBMBIO.COM file attribute
jc prep5c ;exit on error if unsuccessful
lea dx,ibmdos ;do the same for IBMDOS.COM
mov ah,43h
mov cx,0
mov al,1
int 21h
jc prep5c
lea dx,ibmbio ;now delete IBMBIO.COM
mov ah,41h ;DOS function number - delete file
int 21h ;delete the file
jc prep5c ;exit on error if unsuccessful
lea dx,ibmdos ;do the same for IBMDOS.COM
mov ah,41h
int 21h
jc prep5c
jmp prep3 ;reread FAT and directory
prep5c: lea dx,errmsg8 ;files cannot be deleted - abort
jmp error_exit
;
;Check that the disk has adequate free space before continuing.
;
prep6: mov dl,drive ;get drive in DL
inc dl ;adjust drive ID for DOS function call
mov ah,36h ;DOS function number - get free space
int 21h ;get number of clusters that are free
mov ax,sec_per_cluster ;get sectors per cluster
mul bx ;multiply to get free sectors
cmp ax,100 ;at least 100 sectors (50K) free?
jae prep7 ;yes, then continue
lea dx,errmsg6 ;no, then load error message address
jmp error_exit ;exit
;
;Check first two directory entries to see whether each is used or available.
;For each one not available, transfer it to the first available space.
;
prep7: mov si,DIR_data ;point SI to directory image
cmp byte ptr [si],0 ;is the first entry available?
je prep9 ;yes, then goto next entry
cmp byte ptr [si],0E5h ;erased file?
jne prep7a ;no, then move it
mov byte ptr [si],0 ;mark entry as 'Never Used'
jmp prep9 ;jump to next entry
prep7a: mov dx,2 ;entry is occupied
call find_entry ;find first available directory entry
jnc prep8 ;entry found - continue
lea dx,errmsg5 ;no space in dir - load error message address
jmp error_exit ;abort
prep8: mov ax,0
call move_entry ;copy entry 0 into first available slot
prep9: mov si,DIR_data ;check second entry for availability
add si,32 ;point SI to second entry
cmp byte ptr [si],0 ;first byte zero?
je prep13 ;yes, then it's available
cmp byte ptr [si],0E5h ;erased file?
jne prep9a ;no, then move it
mov byte ptr [si],0 ;mark entry as 'Never Used'
jmp prep13 ;continue
prep9a: mov dx,2 ;not available
call find_entry ;find first available entry
jnc prep10 ;continue if empty slot found
lea dx,errmsg5 ;abort if not
jmp error_exit
prep10: mov ax,1
call move_entry ;copy entry and mark old one available
;
;Copy each of the first forty clusters currently in use to clusters beyond the
;first forty and adjust the corresponding FAT entries accordingly.
;
prep13: mov cx,40 ;check 40 clusters
mov dx,2 ;start checking at cluster 2
prep14: push cx ;save loop counter
call get_FAT_entry ;get FAT entry for current cluster
cmp ax,0 ;is it available?
je prep17 ;yes, then proceed to next cluster
cmp ax,0FF0h ;is FAT entry less than FF0h?
jb prep14a ;yes, then move cluster
cmp ax,0FF7h ;is it greater than FF7h?
ja prep14a ;yes, then move cluster
pop cx ;bad cluster - clean up stack
lea dx,errmsg9 ;load error message address
jmp error_exit ;abort
prep14a: mov FAT_entry,ax ;save FAT entry for later
mov ax,last_cluster ;get number of last available cluster
inc ax ;increment to the next one to begin search
mov bx,0
call find_cluster ;find first cluster with FAT entry of zero
mov last_cluster,ax ;store cluster number just found
call move_cluster ;copy the old cluster into the new
jnc prep15 ;continue if no error in disk I/O
pop cx ;on error, clean up stack and exit
jmp error_exit
prep15: mov ax,FAT_entry ;retrieve the FAT entry for the old cluster
push dx ;save the old cluster number
mov dx,last_cluster ;target the new cluster
call put_FAT_entry ;put the old FAT entry into the new one
pop dx ;restore old cluster number
mov ax,0 ;mark the old cluster available...
call put_FAT_entry ;...by setting its FAT entry to zero
mov bx,dx ;get old cluster number in BX for search
mov ax,2 ;start search at cluster 2
call find_cluster ;find FAT entry that referenced old cluster
jnc prep16 ;if found, then continue
call search_DIR ;if not, then look in the directory
jnc prep15a ;if found, then continue
pop cx ;clean up stack
lea dx,errmsg7 ;error - lost cluster or subdir encountered
jmp error_exit ;abort on error
prep15a: mov ax,last_cluster ;get new cluster number
mov [bx],ax ;replace the starting cluster directory entry
jmp prep17 ;skip forward
prep16: push dx ;save current cluster number
mov dx,ax ;change FAT entry that formerly referenced
mov ax,last_cluster ;the old cluster to reference new one
call put_FAT_entry
pop dx ;restore current cluster number
prep17: pop cx ;restore count of clusters checked
inc dx ;index to next sequential cluster
loop prep14 ;loop until the first 40 are clear
;
;Write two copies of the File Allocation Table and one copy of the disk
;directory back to disk, then exit.
;
prep17a: call write_FAT ;write two copies of the FAT
jnc prep18 ;continue if no error on write
lea dx,errmsg4 ;abort on error
jmp error_exit
prep18: call write_DIR ;write the directory to disk
jnc prep19 ;check error status
lea dx,errmsg4 ;abort on write error
jmp error_exit
prep19: lea dx,msg1 ;message address for successful completion
mov ah,9 ;DOS display string function
int 21h ;print message
mov ah,4Ch ;DOS function number - exit
mov al,0 ;set ERRORLEVEL return code to 0
int 21h ;exit program
prep endp
;
;-----------------------------------------------------------------------------
;GET_FAT_ENTRY routine returns the FAT entry for the indicated cluster.
;Entry: DX - cluster number (2-XXX) | Exit: AX - FAT entry
;-----------------------------------------------------------------------------
get_FAT_entry proc near
mov ax,3 ;multiply cluster number by 3
push dx ;save cluster number
mul dx ;multiply
pop dx ;restore cluster number
shr ax,1 ;divide by 2 to obtain offset into FAT
mov bx,ax ;transfer result to bx
add bx,FAT_data ;make address relative to code segment
mov ax,[bx] ;get word at calculated address
test dx,1 ;is cluster number odd or even?
je getf1 ;even, then jump
mov cl,4 ;number is odd, so keep upper 12 bits of word
shr ax,cl ;by shifting right 4 bits
ret ;done - entry in AX
getf1: and ax,0FFFh ;even number, then mask off upper 4 bits
ret ;done - entry in AX
get_FAT_entry endp
;
;------------------------------------------------------------------------------
;PUT_FAT_ENTRY places the designated number into the FAT entry for the named
;cluster. Entry: DX - cluster number (2-XXX)
; AX - entry
;------------------------------------------------------------------------------
put_FAT_entry proc near
push ax ;save new FAT entry
push dx ;save cluster number
mov ax,3 ;multiply cluster by 3
mul dx
pop dx ;restore cluster number
shr ax,1 ;divide by 2
mov bx,ax ;transfer to BX
add bx,FAT_data ;complete offset address of FAT entry
pop ax ;restore FAT entry
test dx,1 ;is the cluster odd or even?
je putf1 ;even, then jump forward
mov cl,4 ;odd - shift entry 4 bits left
shl ax,cl
and word ptr [bx],0Fh ;zero upper 12 bits of word
or [bx],ax ;install new FAT entry
ret ;done - exit
putf1: and [bx],0F000h ;even - zero lower 12 bits
or [bx],ax ;place entry in lower 12 bits
ret ;done - exit
put_FAT_entry endp
;
;------------------------------------------------------------------------------
;The following four routines write and read complete copies of the FAT and the
;disk directory to and from the selected drive.
;------------------------------------------------------------------------------
read_FAT proc near ;read one copy of the FAT into memory
mov al,drive ;define drive
mov dx,1 ;start at sector 1
mov cx,FAT_sectors ;set number of sectors
mov bx,FAT_data ;define buffer address
int 25h ;DOS absolute sector read
pop dx ;clean flags off stack
ret
read_FAT endp
;
read_DIR proc near ;read one copy of directory into memory
mov al,drive ;define drive
mov dx,FAT_sectors ;get number of sectors per FAT
shl dx,1 ;double it for two copies of the FAT
inc dx ;directory starts in next sector
mov cx,DIR_sectors ;number of sectors to read
mov bx,DIR_data ;address of storage buffer
int 25h ;read sectors
pop dx ;clean up the stack before exit
ret
read_DIR endp
;
write_FAT proc near ;write two copies of the FAT to disk
mov al,drive ;define drive
mov dx,1 ;begin at sector 1
mov cx,FAT_sectors ;get number of sectors per FAT
mov bx,FAT_data ;define buffer address
int 26h ;DOS absolute sector write
pop dx ;clean up stack
jc wfat1 ;exit on write error
mov al,drive ;repeat process for second copy of FAT
mov dx,1
mov cx,FAT_sectors
add dx,cx ;start second FAT after first one on disk
mov bx,FAT_data
int 26h
pop dx
wfat1: ret
write_FAT endp
;
write_DIR proc near ;write disk directory image in memory to disk
mov al,drive ;define drive
mov dx,FAT_sectors ;get number of sectors per FAT
shl dx,1 ;double it for two copies
inc dx ;directory starts in next sector
mov cx,DIR_sectors ;number of sectors to read
mov bx,DIR_data ;address of data to be written
int 26h ;write sectors
pop dx ;clean up stack
ret
write_DIR endp
;
;------------------------------------------------------------------------------
;FIND_ENTRY searches thru the image of the disk directory stored in memory and
;finds the first available directory entry.
;Entry: DX - starting entry (0-XXX) | Exit: DX - first available entry
; | CF - clear: avail. entry found
; | set: not found
;------------------------------------------------------------------------------
find_entry proc near
mov cx,DIR_entries ;set maximum number of tries in CX
sub cx,dx
push cx ;save count value
mov bx,dx ;get starting entry number in BX
mov cl,5 ;multiply BX by 32
shl bx,cl
add bx,DIR_data ;complete offset address
pop cx ;restore loop counter
findent1: cmp byte ptr [bx],0 ;is the first byte zero?
je findent2 ;yes, then it's available
cmp byte ptr [bx],0E5h ;is it an erased file?
je findent2 ;yes, then it's available
inc dx ;not available - check next entry
add bx,32 ;address of next entry
loop findent1 ;loop back if some remain
stc ;none available - set CF
ret
findent2: clc ;clear CF to indicate entry found
ret
find_entry endp
;
;------------------------------------------------------------------------------
;MOVE_ENTRY routine transfers a directory entry from one space to another and
;sets the old entry to indicate that it's available.
;Entry: AX - source entry (0-XXX)
; DX - target entry (0-XXX)
;------------------------------------------------------------------------------
move_entry proc near
mov si,ax ;convert entry number to offset address in SI
mov cl,5
shl si,cl
add si,DIR_data
mov di,dx ;do the same for DI
mov cl,5
shl di,cl
add di,DIR_data
push si ;save address of old entry for later
mov cx,32 ;32 bytes per entry
rep movsb ;move all 32 bytes
pop si ;get address of old entry
mov byte ptr [si],0 ;mark entry as 'Never Used'
ret
move_entry endp
;
;------------------------------------------------------------------------------
;FIND_CLUSTER routine finds the first cluster whose FAT entry matches the number
;specified in BX.
;Entry: AX - starting cluster (2-XXX) | Exit: AX - first cluster found
; BX - FAT entry | CF - clear: cluster found
; | set: not found
;------------------------------------------------------------------------------
find_cluster proc near
mov cx,clusters ;get number of clusters
add cx,2 ;calculate max number of search loops
sub cx,ax
push dx ;save DX
mov dx,ax ;starting cluster in DX
findcls1: push cx ;save count of clusters checked
push bx ;save FAT entry value
call get_FAT_entry ;get FAT entry for designated cluster
pop bx ;restore FAT entry to BX
pop cx ;restore count
cmp ax,bx ;is it what we're searching for?
je findcls2 ;yes, then terminate search
inc dx ;no, then try next cluster
loop findcls1
pop dx ;restore DX
stc ;set CF to indicate cluster not found
ret ;exit
findcls2: mov ax,dx ;put cluster number in AX
pop dx ;restore DX
clc ;clear CF to indicate success
ret ;exit
find_cluster endp
;
;------------------------------------------------------------------------------
;CLS2SEC routine returns the sector number that corresponds to the cluster
;number input. Entry: DX - cluster number (2-XXX) | Exit: DX - sector number
;------------------------------------------------------------------------------
cls2sec proc near
sub dx,2 ;subtract two from the cluster number
mov ax,sec_per_cluster ;get number of sectors in each cluster
mul dx ;multiply DX by sectors per cluster
mov dx,ax ;get result in DX
mov ax,FAT_sectors ;get number of sectors in FAT
shl ax,1 ;double it for two copies of the FAT
add dx,ax ;add FAT sectors
add dx,DIR_sectors ;add directory sectors
inc dx ;data starts in next sector
ret
cls2sec endp
;
;------------------------------------------------------------------------------
;MOVE_CLUSTER routine copies the contents of the source cluster into the
;target cluster.
;Entry: DX - source cluster (2-XXX) | Exit: CF - clear: no error in disk I/O
; AX - target cluster (2-XXX) | set: I/O error
;------------------------------------------------------------------------------
move_cluster proc near
push dx ;save source cluster number
push ax ;save target cluster number
call cls2sec ;get sector number of source cluster
mov cx,sec_per_cluster ;number of sectors to read
mov al,drive ;specify drive
mov bx,cbuffer ;set data transfer area
int 25h ;DOS sector read
pop ax ;clean up stack
pop dx ;target cluster in DX
jc movec1 ;exit on error
call cls2sec ;get sector number of target cluster
mov cx,sec_per_cluster ;number of sectors to read
mov al,drive ;specify drive
mov bx,cbuffer ;data transfer area
int 26h ;DOS sector write
pop ax ;clean up stack
pop dx ;restore source cluster
jc movec2 ;abort on error
ret ;exit after successful transfer
movec1: pop dx ;clean up stack before exit
lea dx,errmsg3 ;exit with pointer to 'Read Error' message
ret
movec2: lea dx,errmsg4 ;exit with 'Write Error' message address
ret
move_cluster endp
;
;------------------------------------------------------------------------------
;SEARCH_DIR routine searches each entry in the disk directory image for a
;starting;cluster entry that matches the one input in DX.
;Entry: DX - cluster number (2-XXX) | Exit: BX - addr of starting cluster word
; | CF - clear: match found
; | set: not found
;------------------------------------------------------------------------------
search_DIR proc near
mov bx,DIR_data ;get starting address of directory image
add bx,90 ;starting cluster offset - 3rd directory entry
mov cx,DIR_entries ;get maximum number of search loops
sub cx,2 ;skip first two entries
sdir1: cmp [bx],dx ;do the words match for this entry?
je sdir2 ;yes, then clear CF and exit
add bx,32 ;no, then adjust BX for next entry
loop sdir1 ;try next entry
stc ;no match found - set CF and exit
ret
sdir2: clc ;match found - clear CF
ret
search_DIR endp
;
endprog label byte ;end of program - start of buffer area
;
code ends
end begin