	page ,132
	title snorest

	if2
	%out Pass 2
	endif

code	segment
	assume	cs:code,ds:code

	org 100h	;COM file

	public snorest
snorest	proc far
	jmp cont

	public splash
splash	db 13,10,"Snorest - Fast restore routine Version 1.1 Serial #00000"
	db 13,10,"Copyright (c) 1985 by Snowcrest Computer Specialties"
	db 13,10,"Provided AS IS. No warranty, express or implied."
	db 13,10,"Snowcrest Computer Specialties, 527 McCloud Ave.,"
	db 13,10,"Mt. Shasta, CA  96067.",13,10,"$"
	public warn
warn	db 13,10,7,"Warning - all files on disk "
warndk	db "A will be destroyed by this program!"
	db 13,10,"To prevent this, press ctrl-break at the next prompt."
	db 13,10,"$"
	public flnam,fln1,fln2,fln3
flnam	db "a:sbackup."
fln1	db "0"
fln2	db "0"
fln3	db "1",0
	public mesgp
mesgp	db "Must specify two drives!$"
	public mesg0
mesg0	db "Must have at least 64k!$"
	public mesg1
mesg1	db "Source and destination drives cannot be the same!$"
	public mesg2
mesg2	db "Problem with source disk!$"
	public mesg3
mesg3	db "Problem with destination disk!$"
	public prepms,prepmn,prepdk
prepms	db 13,10,"Mount diskette number "
prepmn	db "XXX in drive "
prepdk	db "A, press any key:$"
	public wrmsg
wrmsg	db 13,10,7,"Wrong disk. Mount correct disk, press any key:$"
	public source
source	db 0
	public dest
dest	db 0
	public swapo
swapo	db 0
	public handle
handle	dw 0
	public bypsc
bypsc	dw 1024	;bytes per sector
	public scpal
scpal	dw 0	;sectors per allocation unit
	public reserv
reserv	dw 0	;number of reserved sectors
	public nfats
nfats	dw 0	;number of fats
	public ndir
ndir	dw 0	;number of root directory entries
	public totsc
totsc	dw 0	;total number of sectors
	public scpfat
scpfat	dw 0	;number of sectors per fat
	public data
data	dw 0	;first sector of data area
	public nents
nents	dw 0	;number of FAT entries
	public fatpt
fatpt	dw 0	;pointer into FAT
	public fatsid
fatsid	dw 0	;left/right indicator
	public loavl
loavl	dw 0
	public hiavl
hiavl	dw 0
	public swapsw
swapsw	db 0	;non-zero for floppy swapping
	public membf
membf	dw 0	;address of memory buffer start
	public mempt
mempt	dw 0	;address of byte we're using
	public memct
memct	dw 0	;number of bytes in buffer
	public bypal
bypal	dw 0	;bytes per allocation unit
	public rsc
rsc	dw 1	;number of sectors to read
	public sect
sect	dw offset fat	;location of sector buffer
	public quiet
quiet	db 0	;non-zero for quiet mode
	public mtab
mtab	dw nine1-11	;fc - 1 side 9 sector
	dw nine2-11	;fd - 2 side 9 sector
	dw eight1-11	;fe - 1 side 8 sector
	dw eight2-11	;ff - 2 side 8 sector
	public nine1,nine2,eight1,eight2
nine1	dw 512		;bytes/sector
	db 1		;sectors/allocation unit
	dw 1		;reserved sectors
	db 2		;number of FATs
	dw 64		;number of directory sectors
	dw 0168h	;sectors/image
	db 0fch		;media descriptor
	dw 2		;sectors/FAT
nine2	dw 512
	db 2
	dw 1
	db 2
	dw 112
	dw 02d0h
	db 0fdh
	dw 2
eight1	dw 512
	db 1
	dw 1
	db 2
	dw 64
	dw 0140h
	db 0feh
	dw 1
eight2	dw 512
	db 2
	dw 1
	db 2
	dw 112
	dw 0280h
	db 0ffh
	dw 1
	public deflt
deflt	db 0


cont:	mov bx,cs	;set up stack
	cli
	mov ss,bx
	mov sp,offset staknd
	sti
	mov ds,bx

	mov dx,offset splash
	mov ah,9
	int 21h		;write the splash screen

	mov ax,cs
	mov bx,es:[2]	;need 64k
	sub bx,ax
	cmp bx,1000h
	ja pok
	mov dx,offset mesg0	;not enough memory
	jmp error
	public pok
pok:	xor bx,bx
	xor cx,cx
	mov cl,es:0080h[bx]	;check input for /s
	or cx,cx
	jz pdone
	public ploop
ploop:	mov al,es:0081h[bx]	;look for /s
	cmp al,'/'
	jne pnope
	cmp byte ptr es:0082h[bx],'s'
	je pyes
	cmp byte ptr es:0082h[bx],'S'
	je pyes
	cmp byte ptr es:0082h[bx],'q'
	je pyes2
	cmp byte ptr es:0082h[bx],'Q'
	jne pnope
	public pyes2
pyes2:	mov quiet,1	;set quiet switch
	jmp short pnope
	public pyes,pnope
pyes:	mov swapsw,1	;set swap switch
pnope:	inc bx
	loop ploop	;keep going till done

pdone:	mov al,es:[005ch]	;drive number of first parameter
	mov bl,es:[006ch]	;drive number of second parameter
	push cs
	pop es

	or al,al	;must be two drives given
	jz badpr
	or bl,bl
	jz badpr

	cmp al,bl
	jne ok1
	mov dx,offset mesg1	;cannot be the same drive

	public error
error:	mov ah,9
	int 21h
	mov al,1	;error return code
	mov ah,04ch
	int 21h

	public badpr
badpr:	mov dx,offset mesgp
	jmp error

	public ok1
ok1:	mov source,al	;save drive numbers
	mov swapo,al
	mov dest,bl

	cmp quiet,0	;quiet mode?
	jne pyes3	;yes
	mov al,dest
	add al,'A'-1
	mov warndk,al
	mov dx,offset warn	;send warning
	mov ah,9
	int 21h

pyes3:	call open	;open the input file

	mov ah,19h	;get default disk
	int 21h
	mov deflt,al
	mov dl,dest
	dec dl
	mov ah,0eh	;select dest disk
	int 21h
	push ds
	mov ah,01bh	;get FAT id (to log in for DOS)
	int 21h
	pop ds
	mov dl,deflt	;change back
	mov ah,0eh
	int 21h

	mov ah,03fh
	mov bx,handle
	mov dx,sect
	mov cx,bypsc
	int 21h		;read boot record and first FAT from source
	xor cx,cx	;seek to beginning of file
	xor dx,dx
	mov bx,handle
	mov al,0
	mov ah,42h
	int 21h

	mov bx,sect
	mov ax,11[bx]	;bytes per sector
	or ax,ax	;zero? (diskette)
	jnz fixed

	mov bl,512[bx]	;media descriptor byte from FAT table
	sub bl,0fch
	xor bh,bh
	shl bx,1
	mov ax,offset mtab
	add bx,ax
	mov bx,[bx]	;address of media table
	mov ax,11[bx]	;bytes per sector

fixed:	mov bypsc,ax
	mov al,13[bx]	;sectors per allocation unit
	xor ah,ah
	mov scpal,ax
	mul bypsc	;compute bytes per allocation unit
	mov bypal,ax
	mov ax,14[bx]	;number of reserved sectors
	mov reserv,ax
	mov ax,16[bx]	;number of fats
	xor ah,ah
	mov nfats,ax
	mov ax,17[bx]	;number of root directory entries
	mov ndir,ax
	mov ax,19[bx]	;total number of sectors
	mov totsc,ax
	mov ax,22[bx]	;number of sectors per fat
	mov scpfat,ax

	mov cx,reserv	;compute first data sector
	mov ax,scpfat
	mul nfats
	add cx,ax
	mov ax,ndir
	mov bx,32
	mul bx		;number of bytes for directory
	mov bx,bypsc
	div bx		;number of sectors for directory
	or dx,dx	;remainder?
	jz ok1a
	inc ax		;yes, increment
	public ok1a
ok1a:	add cx,ax
	mov data,cx	;first data sector

	mov ax,totsc	;compute number of fat entries
	sub ax,cx
	xor dx,dx
	div scpal
	mov nents,ax

	mov ax,scpfat	;compute sector buffer address
	mul bypsc
	add ax,offset fat
	mov sect,ax

	add ax,bypal	;compute data memory buffer address
	mov membf,ax
	mov mempt,ax
	mov memct,0

	mov cx,reserv	;write boot sector(s)
	mov dx,0
	public ok1b
ok1b:	call reads
	call out
	inc dx
	loop ok1b

	mov cx,scpfat	;move first fat to disk and memory
	mov di,offset fat
	cld
	public ok1c
ok1c:	call reads
	mov si,bx
	push cx
	mov cx,bypsc	;move info to memory
	rep movsb
	pop cx
	call out
	inc dx
	loop ok1c

	mov cx,data	;move rest of special sectors
	sub cx,reserv
	sub cx,scpfat
	public ok1d
ok1d:	call reads
	call out
	inc dx
	loop ok1d

	mov ax,scpal	;sectors per allocation unit
	mov rsc,ax	;up the number of sectors written at a time
	mov ax,bypal	;also the number of bytes read
	mov bypsc,ax

	mov bx,offset fat+3	;first actual FAT entry
	mov fatpt,bx	;initialize pointer
	mov fatsid,0	;initialize left/right indicator

	public biglp
biglp:	mov si,fatpt
	mov ax,[si]	;get a FAT pointer
	inc fatpt
	mov di,fatsid
	inc fatsid
	and di,1	;left or right?
	jz right
	inc fatpt
	shr ax,1	;left, shift it
	shr ax,1
	shr ax,1
	shr ax,1
	public right
right:	and ax,0fffh	;mask it
	or ax,ax	;is it zero?
	jz ignor	;yes, ignore the cluster
	cmp ax,0ff0h	;is it reserved?
	jl fatok	;no
	cmp ax,0ff8h
	jl ignor	;yes, ignore the cluster
	public fatok
fatok:	call reads	;read a sector (number in dx)
	call out	;write it
	public ignor,endlp
ignor:	add dx,scpal	;adjust sector pointer
endlp:	dec nents	;decrement number of FAT entries
	jz done		;quit if done
	jmp biglp

	public done
done:	call close	;close the input file
	xor al,al
	mov ah,04ch
	int 21h		;return to DOS

snorest	endp

	public out
out	proc near
	push ax
	push bx
	push cx
	push dx
	push si
	push di
	mov al,dest	;write a sector to dest
	dec al
	mov cx,rsc
	mov bx,sect
	int 26h
	pop di		;pop original flags
	pop di
	pop si
	pop dx
	pop cx
	pop bx
	pop ax
	ret
out	endp

	public reads
reads	proc near
	push ax
	push cx
	push dx
	push si
	push di
	mov cx,bypsc	;number of bytes
	mov dx,sect	;place to put them
	public read7
read7:	mov ax,memct	;see if enough in buffer
	or ax,ax	;anything there?
	jne read8	;yes
	push cx
	push dx
	public read9
read9:	mov ax,membf
	neg ax		;number of bytes available in mem buffer
	mov cx,ax	;number of bytes to read
	cmp hiavl,0
	jne read3	;jump if that number in file
	cmp cx,loavl
	jb read3
	mov cx,loavl	;just read the number left
	or cx,cx	;any left in file?
	jnz read3
	call close	;open new file
	call open
	jmp read9
	public read3
read3:	mov dx,membf
	mov mempt,dx	;fix pointer
	mov bx,handle	;read the info
	mov ah,3fh
	int 21h		;read using DOS
	jc bads
	mov memct,cx	;store number of bytes in buffer
	sub loavl,cx	;adjust number of bytes left in file
	sbb hiavl,0
	pop dx
	pop cx
	jmp read7	;go read now
	public read8
read8:	mov si,mempt	;from here
	mov di,dx	;to here
	push cx
	cmp cx,ax
	jbe read6
	mov cx,ax	;this number of bytes
	public read6
read6:	mov ax,cx
	cld
	rep movsb	;move them
	mov mempt,si
	mov dx,di
	sub memct,ax
	pop cx		;number requested
	sub cx,ax	;number remaining
	jnz read7	;do remaining if necessary

	pop di
	pop si
	pop dx
	pop cx
	mov bx,sect
	pop ax
	ret
reads	endp

	public wrong
wrong:	mov dx,offset wrmsg	;tell user the wrong disk
	mov ah,9
	int 21h
	mov ax,0c08h		;wait for new disk
	int 21h
	jmp short open8		;ok, try again

	public bads
bads:	mov dx,offset mesg2	;problem with source
	jmp error

	public open
open	proc near
	mov si,offset fln1	;update diskette number
	mov di,offset prepmn
	mov cx,3
	cld
	rep movsb

	mov al,source
	add al,'A'-1
	mov prepdk,al		;update disk name

	cmp quiet,0	;quiet mode?
	jne open8	;yes

	mov dx,offset prepms
	mov ah,9
	int 21h		;write message

	cmp swapsw,0	;are we swapping?
	je open3	;no
	mov ah,08h	;yes, wait for a character from buffer
	jmp short open4
open3:	mov ax,0c08h	;wait for non-buffer character
open4:	int 21h

open8:	mov al,source	;make disk letter
	add al,'a'-1
	mov flnam,al
	mov dx,offset flnam	;open a file
	xor al,al
	mov ah,03dh
	int 21h
	jc wrong
	mov handle,ax

	mov bx,ax
	mov ah,42h	;do a seek to find size of file
	xor cx,cx
	xor dx,dx
	mov al,2	;end of file
	int 21h
	jc bads
	mov loavl,ax
	mov hiavl,dx
	xor dx,dx
	mov ah,42h
	mov al,0	;beginning of file
	int 21h
	jc bads

	mov al,fln3	;update file number
	add al,1
	aaa
	mov fln3,al
	mov al,fln2
	adc al,0
	aaa
	mov fln2,al
	mov al,fln1
	adc al,0
	aaa
	or al,30h
	mov fln1,al
	or fln2,30h
	or fln3,30h

	ret		;done
open	endp

	public close
close	proc near
	mov bx,handle	;close the input file
	mov ah,03eh
	int 21h
	jnc okcls
	jmp bads

okcls:	cmp swapsw,0	;see if in swap mode
	je closr	;no
	mov al,swapo
	cmp al,source	;same?
	jne cdiff
	inc source	;same, increment the source
	jmp short closr

cdiff:	mov source,al	;different, make same

closr:	ret
close	endp

stack	db 64 dup('STACK   ')
staknd	equ this byte

	public fat
fat	db 0		;rest of memory for copy of FAT

code	ends
	end snorest
