;********* S E N D D I S K . A S M ******************************************* ; A disk duplication utility to allow all sectors (including boot) ; of a floppy disk to be transmitted via a temporary file over a ; modem and replaced on another floppy disk. With this utility, ; you should be able to distribute the IBM PC-DOS 4.0 fix disks ; with the SBBS system. The temporary file is 368,640 bytes long ; for a 360k diskette and twice that for a 720k diskette. This is long, ; but length should compress nicely using pkarc or equivalent. ; The .exe version of this file needs to be included in the .ARC ; file distributed to enable recreation of the disk. ; ; This program will allow a BOOTABLE disk to be transmitted via a ; modem and recreated at another location. ; ; created 2 November 1988 ; Jim Offenbecher, Software Librarian, Huntsville PC Users Group ; 13920 Creely Drive SW ; Huntsville, AL 35803 ; Tel: [H] (205) 882-3205 ; [W] (205) 881-5741 ; ; modified to: 1. Allow 720k disk usage with message showing type. ; 2. Check file length prior to disk write. ; 3. Comment the source code. ; 4 November 1988 - jko (per conversation with IBM SBBS) ; ; This program including source code is hereby placed in the ; Public Domain for all to use. This program including source ; code may be freely distributed provided that no fee is charged ; for it or it's distribution. Feel free to modify it providing ; original credits are retained - it is quick and dirty to allow ; early distribution of the DOS 4.0 fixes... ; yes I know the error exits don't reset the stack on exit... ; assemble with MASM 5.0 or above - no macros or libraries needed. .model small .data cr equ 0dh lf equ 0ah secsiz equ 512 sectrk equ 9 ;track count for 3.5" 720k disks trks7 equ 80 ;track count for 5.25" 360k disks trks equ 40 sides equ 2 trklen equ secsiz * sectrk ; number of clusters to check for when IDing the floppy ; if it's more than this, and the FAT ID is 0F9h, then it's a ; 5.25" 1.2 Meg and not a 720k 3.5" diskette... clustchk equ 750 signon db ' SENDDISK.EXE',cr,lf db cr,lf db 'A Utility program to allow the IBM SBBS to',cr,lf db 'distribute the patches for IBM Dos 4.0 via',cr,lf db 'file mode. This Program captures the entire',cr,lf db 'disk into a single file and/or recreates the',cr,lf db 'disk from the file. It requires a disk which',cr,lf db 'has been formatted to 360k (9 secs per track)',cr,lf db 'or to 720k (80 tracks-9 secs per track- 3.5")',cr,lf db 'in the A: or B: drive. It is quick and dirty,',cr,lf db 'written in assembly, and is hereby placed in',cr,lf db 'the public domain for all to use.',cr,lf db cr,lf db ' by Jim Offenbecher',cr,lf db ' SSS Computer Center Inc.',cr,lf db ' Huntsville, Alabama',cr,lf db 'Software Librarian- Huntsville PC Users Group (P1239 AL)',cr,lf db cr,lf dirask db cr,lf,'Do you want to:',cr,lf db ' 1. Read a floppy disk into a file on hard disk',cr,lf db ' 2. Write a hard disk file onto a floppy disk',cr,lf db ' Enter your choice (1-2)->','$' askerr db cr,lf,'Must be a 1 or 2 only',cr,lf,'$' as2err db cr,lf,'Must be an A or B only',cr,lf,'$' askdsk db cr,lf,'Enter Floppy Disk Drive Designation (A-B)->','$' typ360 db cr,lf,'Diskette is 360k 5.25 inch',cr,lf,'$' typ720 db cr,lf,'Diskette is 720k 3.5 inch',cr,lf,'$' askfil db cr,lf,'Enter Hard Disk File Name ->','$' rerr001 db cr,lf,'Error Reading Floppy Disk',cr,lf,'$' werr001 db cr,lf,'Error Writing Floppy Disk',cr,lf,'$' serr001 db cr,lf,'File Size does NOT match disk type',cr,lf,'$' newlin db cr,lf,'$' nofile db cr,lf,'File Not Found',cr,lf,'$' badpath db cr,lf,'Invalid Path',cr,lf,'$' nohand db cr,lf,'No Handle Available',cr,lf,'$' accden db cr,lf,'Access to File Denied',cr,lf,'$' gopnerr db cr,lf,'Error Opening File',cr,lf,'$' gmaker db cr,lf,'Error Creating File',cr,lf,'$' rfiler db cr,lf,'Error Reading File',cr,lf,'$' wfiler db cr,lf,'Error Writing File',cr,lf,'$' closerr db cr,lf,'Error Closing File',cr,lf,'$' fwtok db cr,lf,'Disk Capture Successful',cr,lf,'$' dwtok db cr,lf,'Disk Re-Creation Successful',cr,lf,'$' dotmsg db '.$' ; storage for temporary variables ;file name input buffer bufinp db 40 ;max length of buffer chrcnt db 0 ; 1234567890123456789012345678901234567890 filsto db ' ' ; ascii storage for the floppy drive involved drivasc db 'A' ; binary storage for the floppy drive involved dskbin db 1 ; disk type (number of tracks) dsktyp dw 80 ;current sector storage for reading and writing floppy disk cursec dw 0 ; storage for the file handle assigned to the temp file handle dw 0 ; buffer for a single track of data... bugbuff db sectrk+1 dup (secsiz dup (?)) ; executable code begins here... .code mov ax,@data ;MASM 5.0+ find data segment mov ds,ax ;set up data segment mov es,ax ;set up extended segment too restart: mov dx,offset signon mov ah,9 int 21h ;sign on the system mov ah,1 int 21h ;get a single character cmp al,'1' ;check for make file condition jz makfil ;go make a file if so cmp al,'2' ;check for make disk condition jz makdsk ;go make a disk if a 2 mov dx,offset askerr mov ah,9 ;print error if not 1 or 2 int 21h jmp restart ;and ask again ;this module creates a file on the hard disk from all sectors on the ;specified floppy drive. Drive type is checked to determine correct ;number of sectors to read. makfil: call getdisk ;find out which floppy to use call getfile ;and the file name to use too call makefile ; make the file jc exit ;exit if error mov cx,0 ;start at sector zero mov cursec,cx mov cx,dsktyp ;get # tracks this type ; copy a single track from the floppy to a file, looping till all tracks done fillop: push cx ;save track counter mov dx,offset dotmsg;tell user another track mov ah,9 int 21h call readdisk ;go read track into buffer call writfile ;write buffer out to file mov cx,cursec ;get starting sector read last time add cx,9 mov cursec,cx ;bump the starting sector for next loop pop cx ;get track counter back dec cx ;one less track to do jnz fillop ;loop till all tracks done... ; all done writing the file, so bye-bye call closfile ;close the new file mov dx,offset fwtok jmp errexit ;tell user OK, and leave the program ; this module writes all sectors on a floppy disk from data in a ; file on the hard disk. The floppy must be formatted, and the file ; length must match the format of the floppy disk. makdsk: call getdisk ;find out which floppy to use call getfile ;and which file to write to it call openfile ;open the file using handles jc exit ;abort if can't open call lenchk ;check length and abort if wrong mov cx,0 ;initialize the sector to write to mov cursec,cx mov cx,dsktyp ;and get the track count from storage ; this module reads one track's worth of data from the file and ; writes it out to the floppy, looping until 'dsktyp' tracks are written fil2lop: push cx ;save the track counter on stack mov dx,offset dotmsg ;tell him we're working mov ah,9 int 21h call readfile ;get one tracks data from file call writdisk ;put it on the floppy mov cx,cursec ;get the old starting sector written add cx,9 ;bump it one track's worth mov cursec,cx ;and save it for next loop pop cx ;get track counter back dec cx ;one less track to do jnz fil2lop ;loop till all tracks done... ;all done writing the floppy drive now... call closfile ;close the file mov dx,offset dwtok jmp errexit ;tell user OK, and exit the program ;common exit point for errors... prints string at DS:DX and then exits... errexit: mov ah,9 int 21h exit: mov ah,4ch int 21h ; this module prompts the operator for the floppy drive to use, only A and ; B are acceptable answers. It then checks the type of media involved using ; the FAT Descriptor for 360k drives, and a combination of the FAT Descriptor ; and the cluster count for 720k drives. The correct number of 9 sectored ; tracks is stored for later loop usage. getdisk: mov dx,offset askdsk mov ah,9 int 21h ;ask the question mov ah,1 int 21h ;get the answer and al,05fh ;make lower case cmp al,3 jz exit ;exit on control-c cmp al,27 jz exit ;or on escape char cmp al,'A' ;was it an 'A'??? jnz gd002 ;process drive A request mov drivasc,al ;save for later use sub al,41h ;convert to binary mov dskbin,al ;save it too jmp gdret ;jump around the B check and error for ;common return ;it wasn't an A so check for a B gd002: cmp al,'B' jnz gd003 ;not B either - then must be wrong mov drivasc,al ;save the B for later use sub al,41h ;convert to binary mov dskbin,al ;save it too jmp gdret ;here if not A or B - must be error... gd003: ;here if in error mov dx,offset as2err mov ah,9 int 21h ;tell him A or B only jmp getdisk ;ask again... ;here with al containing binary drive value...0=A, 1=B gdret: inc al ;convert to base 1 for absolute call mov dl,al ;put in DL for absolute call mov ah,1ch ;put the GET FAT function in AH push ds ;save from int 21 function int 21h jnc gdret1 ;got a good fat description jmp readerr ;couldn't get a good FAT description ;here if got good fat function call - note: DS has changed..... gdret1: mov al,Byte Ptr[bx] ;get the Media Descriptor Byte... pop ds ;restore Data Segment to ours... cmp al,0fdh ;check for 9 sector 5.25 inch disk jnz chk720 ;no, check for the 720k... mov ax,80 ;360k disk has 40 trks, 2 sides, for tot of 80 mov dsktyp,ax ;save in storage for later loop mov dx,offset typ360 mov ah,9 int 21h ;tell user it's a 360 jmp dskgood ;go to common exit point... ;here if wasn't a 360k drive in the selected drive... chk720: cmp al,0f9h ;check for 3.5 inch disk...(maybe 1.2 Meg)?? jnz readerr ;if not 0fdh or 0f9h then must be wrong type ; both the 3.5" 720k and the 1.2m 5.25 have an f9 Fat descriptor - ; use the tot clusters to insure it's a 720k... cmp dx,clustchk ;check for 720k jnc readerr ;error if it's too many mov ax,160 ;track count on 3.5 inch disk mov dsktyp,ax ;save the total tracks for later looping use ; now have good drive type entered, and know correct number of tracks to use dskgood: mov dx,offset newlin mov ah,9 int 21h ;just start a new line for clarity... ret ; this module prompts for and inputs a file name to use via the buffered ; input routine. It also terminates the input with a zero byte for the ; file handle routines to come later... getfile: mov dx,offset askfil mov ah,9 int 21h ;show user what we want... mov ah,0ah ;buffered input for file name... mov dx,offset bufinp int 21h ;get an input from him.. mov al,chrcnt ;get character count he entered cmp al,0 ;nothing means exit... jnz gfl01 ;he did something... jmp exit ;operator entered a response other than enter key... gfl01: mov ah,0 ;clear hi byte of AX mov di,offset filsto;set offset to 1st character entered add di,ax ;add the number of chars entered mov byte ptr[di],0 ;put a zero terminator there mov dx,offset newlin;clear the line for clarity... mov ah,9 int 21h ret ; this module opens the file using the handle function... openfile: mov ah,3dh ;function to open file handle mov al,0 ;read only mode - careful... mov dx,offset filsto;point to ASCIIZ name... int 21h ;go try to open... jnc openok ;if carry not set, then ok... ;here if error opening file... check sequentially for errors... mov dx,offset nofile cmp al,2 ;error 2 is no file found jz openerr mov dx,offset badpath cmp al,3 ;error 3 is can't find path jz openerr mov dx,offset nohand cmp al,4 ;error 4 is no handle available jz openerr mov dx,offset accden cmp al,5 ;error 5 is Access Denied jz openerr mov dx,offset gopnerr ;use general error if not above... openerr: jmp errexit ;go print the error and quit... ;here if file opened ok... openok: mov handle,ax ;save handle for later use. ret ;tell operator we had an error reading file and then exit.. readerr: mov dx,offset rerr001 jmp errexit ; this module creates a new file when reading in a floppy disk makefile: mov ah,3ch ;function in AH mov cx,0 ;attributes set to none mov dx,offset filsto;point to ASCIIZ string inputted int 21h ;go try to make it jnc makeok ;carry not set - then OK - it's made mov dx,offset badpath cmp al,3 ;error 3 is can't find path jz makerr mov dx,offset nohand cmp al,4 ;error 4 is no handle available jz makerr mov dx,offset accden cmp al,5 ;error 5 is access denied jz makerr mov dx,offset gmaker ;use general error if not above... makerr: jmp errexit ;print the error for user and exit ;here if file was created OK makeok: mov handle,ax ;save handle for later writes... ret ;this module closes the file and updates the directory closfile: mov ah,3eh ;function to close in AH mov bx,handle ;get the saved handle int 21h ;go close it jnc closok ;branch if no error ocurred ;here if error closing file mov dx,offset closerr jmp errexit ;print the error and exit ;here if closed OK closok: ret ; this module reads one tracks worth of data (9 sectors) into the buffer. ; the file pointer is left for DOS to handle, we only do a sequential read. readfile: mov ah,3fh ;function in AH mov bx,handle ;handle in BX mov dx,offset bugbuff;point to the buffer to use mov cx,trklen ;number of bytes to read in CX int 21h ;go read the file jnc readok ;skip error if none ocurred rfiler2: mov dx,offset rfiler jmp errexit ;tell him an error and exit ;here if no error ocurred, however, make sure we didn't run out of bytes... readok: cmp ax,cx ;see if we read all we wanted... jnz rfiler2 ;error if short read... ret ; this routine writes one track's worth of data from the buffer to the file ; the file pointer is left for DOS to handle, we only do a sequential write. writfile: mov ah,40h ;function in AH mov bx,handle ;handle in BX mov dx,offset bugbuff;point to the buffer to use mov cx,trklen ;number of bytes to write in CX int 21h ;go write it jnc writok ;skip error if none ocurred ;here if DOS reported an error wfiler2: call closfile ;don't leave lost clusters mov dx,offset wfiler jmp errexit ;tell user we can't write and exit ;here if no error ocurred, however, make sure we wrote the whole buffer... writok: cmp ax,cx ;check to see complete write jnz wfiler2 ;error if not ret ;else all is ok ; this module reads one track's worth of data from the floppy disk readdisk: mov al,dskbin ;get the disk to use mov cx,9 ;nine sectors per track mov dx,cursec ;where to start mov bx,offset bugbuff;where to put data int 25h ;go do it pop cx ;clean up stack from int 25h (the flags) jnc dredok ;skip the error if ok jmp readerr ;else tell user and exit ;here if read the track ok dredok: ret ; this module writes one track's worth of data to the floppy disk writdisk: mov al,dskbin ;get the disk to use mov cx,9 ;write the whole nine sectors mov dx,cursec ;where to start mov bx,offset bugbuff;where to get data from int 26h ;go do it pop cx ;clean up stack from int 25h (the flags) jnc dwitok ;skip the error if ok jmp writerr ;else tell user and exit ;here if wrote the whole track dwitok: ret ;here if an error writing a track to floppy disk writerr: mov dx,offset werr001 jmp errexit ; check the length of the file to see if it came from the same type ; disk drive - 360k disks return DX=0005 and AX=A000 while ; 720k drives return DX=000B and AX=4000... error exit if no match.. lenchk: mov ax,4202h ;LSEEK ref EOF mov bx,handle ;file handle to use mov cx,0 ;cx and dx set the offset mov dx,cx ;offset 0 from end int 21h ;go move the DOS pointer push dx ;save the pointer (DX:AX) on stack for rewind push ax mov ax,4200h ;LSEEK ref beginning mov bx,handle ;same file mov cx,0 ;same offset mov dx,cx ;offset 0 from beginning int 21h ;reset pointer to beginning pop ax ;get the length back from the stack pop dx ; now have file length in DX:AX and pointer back at beginning of file... mov cx,dsktyp ;get # tracks in CX mov si,5 ;set to 360k first mov di,0a000h cmp cx,80 ;check for 360k track count jz chkit ;ok, then skip the set to 720k value mov si,0bh ;set comparators to 720k standard mov di,04000h chkit: ; now compare DX with SI and AX with DI - if they dont both match, file ; is the wrong size... cmp dx,si ;check hi words first jnz sizerr ;error if not equal cmp ax,di ;check lo words too jnz sizerr ;error if not equal ret ;ok, file is right length ; here if wrong size file - tell user and abort program. sizerr: mov dx,offset serr001 jmp errexit ;thats all folks...... end