	page ,132
	title snoback

	if2
	%out Pass 2
	endif

code	segment
	assume	cs:code,ds:code

	org 100h	;COM file

	public snoback
snoback	proc far
	jmp cont

	public splash
splash	db 13,10,"Snoback - Fast backup 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 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
prepms	db 13,10,"Mount diskette number "
prepmn	db "XXX in drive "
prepdk	db "A, press any key:$"
	public source
source	db 0
	public swapo
swapo	db 0
	public dest
dest	db 0
	db "sbackup ???",25 dup(0)
	public handle
handle	dw 0
	public bypsc
bypsc	dw 0	;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 mempt
mempt	dw 0
	public memst
memst	dw 0
	public loavl
loavl	dw 0
	public hiavl
hiavl	dw 0
	public swapsw
swapsw	db 0	;non-zero for floppy swapping
	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 id
id	db 0
	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 bads
bads:	mov dx,offset mesg2	;problem with source
	jmp error

	public ok1
ok1:	mov source,al	;save drive numbers
	mov dest,bl
	mov swapo,bl	;save for swapping info

	call open	;open the output file

	mov ah,19h	;get default disk
	int 21h
	mov deflt,al
	mov dl,source
	dec dl
	mov ah,0eh	;select source disk
	int 21h
	push ds
	mov ah,01bh	;get FAT id
	int 21h
	mov al,ds:[bx]
	pop ds
	mov id,al
	mov dl,deflt	;change back
	mov ah,0eh
	int 21h

	mov dx,0	;get boot record for source
	call reads
	jc bads		;bad source disk

	mov ax,11[bx]	;bytes per sector
	or ax,ax	;zero? (diskette)
	jnz fixed

	mov bl,id	;media descriptor byte
	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 memst,ax
	mov mempt,ax

	mov cx,reserv	;write boot sector(s)
	mov dx,0
	public ok1b
ok1b:	call reads
	call mout
	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 mout
	inc dx
	loop ok1c

	mov cx,data	;move rest of special sectors
	sub cx,reserv
	sub cx,scpfat
	public ok1d
ok1d:	call reads
	call mout
	inc dx
	loop ok1d

	mov ax,scpal	;sectors per allocation unit
	mov rsc,ax	;up the number of sectors read at a time
	mov ax,bypal	;also the number of bytes written
	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 mout	;write it (through memory buffer)
	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 empty	;empty the buffer
	call close	;close the output file
	xor al,al
	mov ah,04ch
	int 21h		;return to DOS

snoback	endp

	public reads
reads	proc near
	push ax
	push cx
	push dx
	push si
	push di
	mov al,source	;read a sector from source
	dec al
	mov cx,rsc	;number of sectors to read
	mov bx,sect
	int 25h
	pop di		;pop original flags
	pop di
	pop si
	pop dx
	pop cx
	mov bx,sect
	pop ax
	ret
reads	endp

	public mout
mout	proc near
	push ax
	push bx
	push cx
	push dx
	push si
	push di
	mov di,mempt	;get buffer pointer
	mov ax,bypsc	;number of bytes
	add ax,di	;see if room
	jnc moutok
	mov dx,memst	;start of buffer
	mov mempt,dx
	sub di,dx
	mov cx,di	;number of bytes
	mov di,dx
	call write	;write dx=buffer, cx=# bytes
	public moutok
moutok:	mov si,sect
	cld
	mov cx,bypsc
	rep movsb	;move the bytes in memory
	mov mempt,di	;update pointer
	pop di
	pop si
	pop dx
	pop cx
	pop bx
	pop ax
	ret
mout	endp

	public write
write	proc near
	mov ax,cx
	sub loavl,cx	;see if room on disk
	sbb hiavl,0
	jnc mout4	;yes
	add loavl,cx	;number we can write
	mov cx,loavl
	public mout4
mout4:	push ax
	mov bx,handle	;write the info
	mov ah,40h
	int 21h		;write using DOS
	jc badd
	pop ax
	sub ax,cx	;see if end of disk
	je writok	;no, done
	add dx,cx
	push ax		;save number that are left
	push dx
	push di
	call close	;close the file
	call open	;open a new file
	pop di
	pop dx
	pop cx
	jmp write	;yes, do the rest of the write
	public writok
writok:	ret
write	endp

	public empty
empty	proc near
	mov cx,mempt
	mov dx,memst
	sub cx,dx	;byte count
	je emptrt	;return if nothing in buffer
	call write	;write using DOS (dx=buffer,cx=# bytes)
	public emptrt
emptrt:	ret
empty	endp

	public badd
badd	proc near
	mov dx,offset mesg3
	jmp error
badd	endp

	public open
open	proc near
	mov si,offset fln1	;update diskette number
	mov di,offset prepmn
	mov cx,3
	cld
	rep movsb

	mov al,dest
	add al,"A"-1
	mov prepdk,al		;update disk name

	cmp quiet,0	;is it quiet mode?
	jne open5	;yes

	mov dx,offset prepms
	mov ah,9
	int 21h		;write message

	cmp swapsw,0	;are we swapping?
	je open3	;no
	mov ah,08h	;wait for a character from buffer
	jmp short open4
open3:	mov ax,0c08h	;wait for non-buffer character
open4:	int 21h

open5:	mov dx,offset dest	;fcb to delete files
	mov ah,13h
	int 21h		;delete any backup files already on disk

	mov al,dest	;disk number
	add al,'a'-1	;make into disk letter
	mov flnam,al	;store in name
	mov dx,offset flnam	;create a new file
	xor cx,cx
	mov ah,03ch
	int 21h
	jc badd2
	mov handle,ax

	mov dl,dest	;compute free space
	mov ah,36h
	int 21h
	mul bx		;number of free sectors on drive in ax
	mul cx		;dx, ax = number of free bytes
	mov hiavl,dx
	mov loavl,ax

	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

badd2:	jmp badd

open	endp

	public close
close	proc near
	mov bx,handle	;close the output file
	mov ah,03eh
	int 21h
	jc badd2

	cmp swapsw,0	;see if in swap mode
	je closr	;no
	mov al,swapo
	cmp al,dest	;same?
	jne cdiff
	inc dest	;same, increment the destination
	jmp short closr

cdiff:	mov dest,al	;different, make same

closr:	ret
close	endp

stack	db 64 dup('STACK   ')
staknd	equ this byte


;sector buffer starts at this address plus FAT buffer
;memory buffer starts after sector buffer
	public fat
fat	db 0		;rest of memory for copy of FAT

code	ends
	end snoback
