PAGE 90,132 ;A2 TITLE COPYINIT -- DISKCOPY INITIALIZATION PROGRAM ;****************** START OF SPECIFICATIONS ***************************** ; MODULE NAME: COPYINIT ; DESCRIPTIVE NAME: Initialization for Diskette to diskette copy Utility ;FUNCTION: DISKCOPY is to copy the contents of the diskette in the ; specified source drive to the diskette in the target ; drive. If necessary, the target diskette is also ; formatted. ; Multiple copies may be performed with one load of DISKCOPY. ; A prompt, "Copy another (Y/N)?" permits additional ; executions, all with the same drive specifications. ; ENTRY POINT: "DISKCOPY" at ORG 100h, jumps to "BEGIN". ; INPUT: (DOS command line parameters) ; [d:][path]DISKCOPY [d: [D:]][/1] ; Where ; [d:][path] before DISKCOPY to specify the drive and path that ; contains the DISKCOPY command file. ; [d:] to specify the source drive id ; [D:] to specify the destination drive id ; [/1] to request single sided operations only ; EXIT-NORMAL: Errorlevel = 0 ; Function completed successfully. ; EXIT-ERROR: Errorlevel = 1 ; Abnormal termination due to error, wrong DOS, ; invalid parameters, unrecoverable I/O errors on ; the diskette. ; EFFECTS: The entire source diskette is copied, including the unused ; sectors. There is no awareness of the separate files ; involved. A unique volume serial number is generated ; for the target diskette. ; INCLUDED FILES: ; INCLUDE DCPYMACR.INC ; INCLUDE DISKCOPY.EQU ; INCLUDE PATHMAC.INC ;PATHGEN MACRO ; INTERNAL REFERENCES: ; ROUTINES: ; INIT - INITIALIZATION ROUTINE, MAIN PROGRAM ; SOURCE_TARGET_DRV - CONVERT SOURCE/TARGET DRIVE TO BIOS VALUES ; TEST_DRIVE_VALIDITY - ARE SOURCE/TARGET DRIVES VALID? ; DOS_DRIVE_VALIDITY - CHECK DOS DRIVE VALIDITY BYTE ; TEST_REMOVABLE - IS SPECIFIED DRIVE REMOVABLE? ; CHK_SINGLE_DRIV_OP - IS TARGET DRIVE SAME AS SOURCE? ; GET_LOGICAL_DRIVE - GET LOG. DRIV NO. WHO OWNS PHYSICAL DRIVE ; DISKETTE_DRV_TYPE - CHECK COMPATABILITY SOURCE/TARGET DRIVES ; CHECK_REDIRECTION - IS DEVICE REDIRECTED? ; BUFFER_SIZE - FINDS START AND END OF BUFFER ; SETUP_CTRL_BREAK - SETUP THE CTRL-BREAK VECTOR ; CHECK_SERVER - IS SERVER OR REDIRECTOR LOADED? ; DATA AREAS: ; PSP - Contains the DOS command line parameters. ; WORKAREA - Temporary storage ; EXTERNAL REFERENCES: ; ROUTINES: ; SYSDISPMSG - Uses the MSG parm lists to construct the messages ; on STDOUT. ; SYSLOADMSG - Loads messages, makes them accessable. ; PARSER - Processes the DOS Command line, finds parms. ; DATA AREAS: ; DCOPYSM.SAL - Defines the control blocks that describe the messages ; DCOPYPAR.SAL - Defines the control blocks that describe the ; DOS Command line parameters. ; NOTES: ; This module should be processed with the SALUT preprocessor ; with the re-alignment not requested, as: ; SALUT COPYINIT,NUL ; To assemble these modules, the alphabetical or sequential ; ordering of segments may be used. ; For instructions as to how to LINK, see prolog for DISKCOPY. ;PROGRAM AUTHOR: Original written by: JK ; 4.00 modifications by: EMK ;****************** END OF SPECIFICATIONS ***************************** IF1 %OUT COMPONENT=DISKCOPY, MODULE=COPYINIT.SAL ENDIF ;DATE: 9-22-83 ;TIME: 8:00 PM ;DATE: 10-30-84 - chk_para routine added. many parts are modified to ; permit DISKCOPY /1, DISKCOPY D: /1 cases. Restore diskbase ; before return to DOS when invalid DOS version occurs. ;DATE: 3-27-85 MAIN PARTS OF DISKCOPY PROGRAM HAS BEEN REWRITTEN ; TO USE NEW IOCTL FUNCTION CALLS - READ, WRITE AND FORMAT. INCLUDE DCPYMACR.INC INCLUDE PATHMAC.INC ;AN015;PATHGEN MACRO CSEG SEGMENT PARA PUBLIC 'CODE' ;AN000; ASSUME CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG INCLUDE DISKCOPY.EQU ;$salut (4,2,9,41) ;**************************************************************************** ; * ; EXTERNAL VARIABLES * ; * ;**************************************************************************** EXTRN PARSER:NEAR ;DCOPYPAR.SAL - DRIVES SYS PARSER ;AN000; EXTRN RECOMMENDED_BYTES_SECTOR:WORD ;SOURCE DRIVE DEFAULT BYTES/SECTOR EXTRN S_OWNER_SAVED:BYTE EXTRN T_OWNER_SAVED:BYTE EXTRN ASCII_DRV1_ID:BYTE ;40H SOURCE DRIVE ID IN ASCII EXTRN ASCII_DRV2_ID:BYTE ;40H TARGET DRIVE ID IN ASCII EXTRN MSGNUM_INVALID_DRV:BYTE ;"INVALID DRIVE SPECIFICATION" ;AC000; EXTRN MSGNUM_NOT_COMPATIBLE :BYTE ;"DEVICE TYPE OF DISKETTE TYPES NOT COMPATIBLE";AC000; EXTRN MSGNUM_DRV_REDIRECTED:BYTE ;"INVALID, DRIVE REDIRECTED" ;AC000; EXTRN SUBLIST_8 :WORD ; ;AN000; EXTRN SUBLIST_9 :WORD ; ;AN000; EXTRN SUBLIST_13 :WORD ; ;AN000; EXTRN SUBLIST_17A :WORD ; ;AN000; EXTRN SUBLIST_17B :WORD ; ;AN000; EXTRN SUBLIST_17C :WORD ; ;AN000; EXTRN SUBLIST_19C :WORD ; ;AN000; EXTRN SUBLIST_19D :WORD ; ;AN000; EXTRN SUBLIST_19E :WORD ; ;AN000; EXTRN SUBLIST_26A :WORD ; ;AN001; EXTRN SUBLIST_26B :WORD ; ;AN001; EXTRN SUBLIST_PARSE:WORD ;PARSE ERROR XX - %0 ;AN003; .XLIST ;EXTRN MSG_INVALID_PARM_PTR:BYTE ;"INVALID PARAMETER" ;EXTRN MSG_INVALID_DOS :BYTE ;"INVALID DOS" .LIST EXTRN S_DRV_SECT_TRACK :BYTE ;SECT/TRACK EXTRN S_DRV_HEADS :BYTE ;# OF HEADS EXTRN S_DRV_TRACKS :BYTE ;# OF TRACKS EXTRN T_DRV_SECT_TRACK :BYTE EXTRN T_DRV_HEADS :BYTE EXTRN T_DRV_TRACKS :BYTE EXTRN SOURCE_DRIVE :BYTE ;SRC DRV LOGICAL NUMBER EXTRN TARGET_DRIVE :BYTE ;TARGET DRV LOGICAL NUMBER EXTRN COPY_TYPE :BYTE ;1 = 1-DRIVE COPY 2 = 2-DRIVE COPY EXTRN USER_OPTION :BYTE ;NO OPTION (-1) /1 (1), INVALID (9) EXTRN BUFFER_BEGIN :WORD ;STARTING BUFFER @ FOR LOADING EXTRN BUFFER_END :WORD ;ENDING BUFFER @ FOR LOADING EXTRN MAIN_EXIT :WORD ;EXIT ADDRESS FOR CONTROL-BREAK EXTRN IO_ERROR :BYTE EXTRN DS_IOCTL_DRV_PARM :BYTE ;PLACE HOLDER FOR DEFAULT SOURCE DRV PARM EXTRN DT_IOCTL_DRV_PARM :BYTE ;PLACE HOLDER FOR DEFAULT TARGET DRV PARM EXTRN DS_specialFunctions :BYTE ;AND THEIR CONTENTS EXTRN DT_specialFunctions :BYTE EXTRN DS_deviceType:BYTE EXTRN DT_deviceType:BYTE EXTRN DS_deviceAttributes :WORD EXTRN DT_deviceAttributes :WORD EXTRN DS_numberOfCylinders :WORD EXTRN DT_numberOfCylinders :WORD EXTRN DS_mediaType :BYTE EXTRN DT_mediaType :BYTE EXTRN DS_BPB_PTR :BYTE EXTRN DT_BPB_PTR :BYTE EXTRN MS_IOCTL_DRV_PARM :BYTE ;DRIVE PARM FROM SOURCE MEDIUM EXTRN MT_IOCTL_DRV_PARM :BYTE EXTRN GENERIC_IOCTL :NEAR EXTRN SET_LOGICAL_DRIVE :NEAR ; $salut (4,20,24,41) ; ;AN000; MY_BPB STRUC CBYTE_SECT DW 0 ; 200H BYTES / SECTOR CSECT_CLUSTER DB 0 ; 2h SECTORS / CLUSTER CRESEV_SECT DW 0 ; 1h RESERVED SECTORS CFAT DB 0 ; 2h # OF FATS CROOTENTRY DW 0 ; 70h # OF ROOT ENTRIES CTOTSECT DW 0 ; 02D0h TOTAL # OF SECTORS ; INC. BOOT SECT, DIRECTORIES MEDIA_DESCRIP DB 0 ;0FDh MEDIA DISCRIPTOR CSECT_FAT DW 0 ; 2h SECTORS / FAT CSECT_TRACK DW 0 ; CHEAD DW 0 ; CHIDDEN_SECT DD 0 ; BIG_TOT_SECT DD 0 ; DB 6 DUP (0) ; MY_BPB ENDS ;**************************************************************************** ; * ; VARIABLE DECLARATIONS * ; * ;**************************************************************************** DRIVE_VALID DW ? ;DRIVE VALIDITY INDICATOR DEFAULT_DRV DB ? ;DEFAULT DRIVE ID (0=A,1=B,ETC) NUMBER_OF_DRV DB ? ;TOTAL # OF DISKT DRIVES ON THE SYS ;(NUMBER_OF_DRV = 0 ---> 1 DRIVE) ASCII_DRIVE_LETTER DB " :",0 PATHLABL COPYINIT ;AN015; HEADER ; ;AN000; ; $salut (4,9,15,41) ; ;AN000; ;############################################################################# ; INITIALIZATION ROUTINE - MAIN PROGRAM INIT PROC NEAR PUBLIC INIT ;MAKE ENTRY IN LINK MAP ;AN000; ;OUTPUT: DX = EXIT CODE, "FINE" ;############################################################################# MOV DRIVE_VALID,AX ;SAVE DRIVE VALIDITY BYTE ; REPLACE THE "FILL_SEG" IN THE SUBLIST MESSAGE CONTROL BLOCKS. ; BECAUSE THIS IS A .COM STYLE FILE, THESE SEGID VALUES CANNOT ; BE PROVIDED BY THE DOS SYSTEM LOADER, BUT MUST BE DYNAMICALLY ; PERFORMED AT EXECUTION TIME AS PART OF A .COM FILE'S OBLIGATION ; TO BE "SELF-RELOCATING". MOV AX,CS ;GET SEGID OF COMMON SEGMENT ;AN000; MOV SUBLIST_8.SUB_VALUE_SEG,AX ; ;AN000; MOV SUBLIST_9.SUB_VALUE_SEG,AX ; ;AN000; MOV SUBLIST_13.SUB_VALUE_SEG,AX ; ;AN000; MOV SUBLIST_17A.SUB_VALUE_SEG,AX ; ;AN000; MOV SUBLIST_17B.SUB_VALUE_SEG,AX ; ;AN000; MOV SUBLIST_17C.SUB_VALUE_SEG,AX ; ;AN000; MOV SUBLIST_19C.SUB_VALUE_SEG,AX ; ;AN000; MOV SUBLIST_19D.SUB_VALUE_SEG,AX ; ;AN000; MOV SUBLIST_19E.SUB_VALUE_SEG,AX ; ;AN000; MOV SUBLIST_26A.SUB_VALUE_SEG,AX ; ;AN001; MOV SUBLIST_26B.SUB_VALUE_SEG,AX ; ;AN001; MOV SUBLIST_PARSE.SUB_VALUE_SEG,AX ; ;AN003; CALL SETUP_CTRL_BREAK ;STEALS CTRL_BREAK CLD ;CLEAR DIRECTION FLAG MOV DX,FINE ;ASSUME EVERYTHING IS FINE .XLIST ; CALL SCREENING ;CHECK DOS VERSION AND INPUT PARMS ; CALL CHK_PARA ; GENERAL SYNTAX CHECK .LIST CALL PARSER ;LOOK AT DOS COMMAND LINE ;AN000; CMP DX,FINE ;IF ALL OK ;AN000; ; $IF E ; ;AN000; JNE $$IF1 CALL SOURCE_TARGET_DRV ;SET UP TO USE THE DRIVE LETTERS ;AN000; CALL TEST_DRIVE_VALIDITY CMP DX,FINE ; $IF E ; ;AN000; JNE $$IF2 CALL DISKETTE_DRV_TYPE ;SOURCE & TARGET DRIVE TYPES CMP DX,FINE ;IF FINE & DANDY ; $IF E ; ;AN000; JNE $$IF3 CALL BUFFER_SIZE ;GET BUFFER SIZE FOR COPYING ; $ENDIF ; ;AN000; $$IF3: ; $ENDIF ; ;AN000; $$IF2: ; $ENDIF ; ;AN000; $$IF1: EXIT_INIT: ;DX <-- 1 IF INIT OK RET ;DX <-- ERROR OFFSET IF NOT OK ;RETURN TO CALLER INIT ENDP ;END INITIALLIZATION PROGRAM .XLIST ; HEADER ;****************************************************************************** ; SUBROUTINE NAME : SCREENING - CHECKS THE FOLLOWING: * ; - DOS VERSION * ; - GENERAL SYNTAX CHECKING FOR PARAMETERS * ; INPUT : NONE * ; OUTPUT : DX : FINE - NO ERROR * ; (OTHERS)- ERROR MSG OFFSET * ;****************************************************************************** ;SCREENING PROC NEAR ;CHECK DOS VERSION: ; MOV AH,DOSVER_FUNC ;SEE IF CORRECT DOS VERSION ; INT 21H ;FUNCTION CALL (AL <- DOS VERSION) ;NOTE: BX IS DESTROYED ; XCHG AH,AL ;AH=MAJOR VER, AL=MINOR VER ; CMP AX,expected_version ;IF DOS MAJOR VERSION LESS THAN 3.00 ; $IF NE ;THEN ISSUE ERROR MSG ; MOV DX,OFFSET MSG_INVALID_DOS ; MOV AH,PRINT_FUNC ;USE PRINT FUNCTION TO TELL USER ; INT 21H ;THAT HE IS USING THE OLD VERSION ; INT 20H ;EXIT TO DOS ; $ELSE ;VERSION OK ; CALL CHK_PARA ;GENERAL SYNTAX CHECK ; $ENDIF ;END VERSION TEST ; RET ;SCREENING ENDP ; HEADER ;************************************************************************** ;kiser: this proc is to be deleted ;CHK_PARA PROC NEAR ; CHECK SYNTAX OF THE ENTERED PARAMETERS * ; ALSO, DETERMINE THE USER OPTION "/1" IS ENTERED OR NOT. * ; INPUT: DX = FINE * ; IF /1 HAS BEEN ENTERED, THE VARIABLE USER_OPTION = OPTION_1 * ; ELSE USER_OPTION = NO_OPTION. * ; OUTPUT: DX = FINE - NO ERROR * ; OTHERWISE DX POINTS TO ERROR MSG * ;************************************************************************** ; PUSH CX ; MOV USER_OPTION, NO_OPTION ;ASSUME NO /1 IS ENTERED. ; XOR CX, CX ; MOV CL, BYTE PTR DS:BEGIN_UNFORM_AREA ;GET # OF CHR ; CMP CL, 0 ; $IF NZ ; CLD ;CLEAR DIRECTION ; MOV DI, BEGIN_UNFORM_AREA+2 ;STARTING POINT OF PARA ; DEC CL ;TO IGNORE LAST CHR (0DH) ; CALL SKIP_BLANKS ;SKIP BLANKS, IF ANY. THE POINTER ; ; WILL POINT TO THE NEXT NON_BLANK CHR ; ; $IF NZ ;SOMETHING OTHER THAN BLANKS ; ; ARE ENTERED ; CALL CHK_SLASH_ONE ;IS NEXT WORD /1 ? ; ; JNC SLASH_ONE ;YES ; CALL CHK_DRV_SPEC ;IS IT A DRIVE SPECIFICATION LIKE d: ? ; ; JC INVALID_PARA ;IF NOT, THEN ERROR ; JZ CHK_PARA_EXIT ;NO MORE CHR? THEN, OK. (EX. DISKCOPY D:) ; CALL CHK_SLASH_ONE ;IS NEXT WORD /1 ? ; ; JNC SLASH_ONE ;YES.(EX. DISKCOPY D:/1) ; CALL CHK_BLANK ;IF NOT, NEXT CHR SHOULD BE A BLANK. ; ; JC INVALID_PARA ;OTHERWISE, ERROR. ; CALL SKIP_BLANKS ;SKIP BLANKS, IF ANY. ; ; JZ CHK_PARA_EXIT ;(EX. DISKCOPY D: ) ; CALL CHK_SLASH_ONE ;IS IT A /1 ? ; ; JNC SLASH_ONE ;YES. (EX. DISKCOPY D: /1) ; CALL CHK_DRV_SPEC ;IF NOT /1, THEN IS IT A DRV SPEC? ; ; JC INVALID_PARA ;OTHERWISE, ERROR. ; CALL SKIP_BLANKS ;SKIP BLANKS, IF ANY. ; ; JZ CHK_PARA_EXIT ;NO MORE CHR. (EX. DISKCOPY D: D:) ; CALL CHK_SLASH_ONE ;OTHERWISE, IT SHOULD BE /1. ; ; JNC SLASH_ONE ;YES, /1. JMP TO SLASH_ONE ; JMP INVALID_PARA ;PARAMETER ERROR. ;SLASH_ONE: ; MOV USER_OPTION, OPTION_1 ;YES, /1 HAS BEEN ENTERED. ; CALL SKIP_BLANKS ;/1 SHOULD BE END OF PARAMETERS, OR ONLY BLANKS CAN FOLLOW. ; ; $IF NZ ;INVALID_PARA: ; MOV DX,OFFSET MSG_INVALID_PARM_PTR ;WRONG PARM ENTERED MSG ; $ENDIF ; $ENDIF ; $ENDIF ;CHK_PARA_EXIT: ; POP CX ; ; RET ;CHK_PARA ENDP ; HEADER ;*************************************************************************** ;SKIP_BLANKS PROC NEAR ; ** SKIP BLANKS, OR TABS IF ANY, IN THE PARAMETER STRING. * ; INPUT: ES:DI POINTS TO THE CURRENT CHR. * ; CX - # OF REMAINING CHR IN THE STRING. * ; OUTPUT: ES:DI POINT TO THE NEXT NON_BLANK CHR. * ; CX IS ADJUSTED ACCORINGLY. * ; IF THE CURRENT CHR IS NOT A BLANK, THEN DI, CX VALUE NOT CHANGED.* ; IF CX = 0, THEN ZERO FLAG WILL BE SET AND EXIT THIS PROC. * ;*************************************************************************** ; $DO ; MOV AL, 20H ;20H=BLANK ; CLD ;CLEAR DIRECTION ; REPE SCASB ; $LEAVE Z ;IF NOT FOUND A NON_BLANK CHR YET, AND CX=0, EXIT THIS ROUTINE. ; DEC DI ;OTHERWISE, RESTORE DI TO THE NON_BLANK POSITION. ; INC CX ; AND RESTORE CX TO WHERE IT WAS AT NON_BLANK CHR ; ;(IF FOUND A NON_BLANK CHR, ZERO FLAG WOULD NOT BE SET) ; MOV AL, ES:BYTE PTR [DI] ; CMP AL, 09H ;09H=TAB ; $LEAVE NZ ;IF THE NON_BLANK CHR IS NOT A TAB THEN EXIT ; INC DI ;ELSE TRY SKIP AGAIN ; DEC CX ; $ENDDO ; RET ;SKIP_BLANKS ENDP ; HEADER ;*************************************************************************** ;kiser: this proc is to be deleted ;CHK_SLASH_ONE PROC NEAR ; ** CHECK CURRENT CHR IS / FOLLOWED BY 1. * ; INPUT: ES:DI POINTS TO THE CURRENT CHR TO BE CHECKED. * ; CX REPRESENTS THE # OF CHR'S IN THE STRING. * ; OUTPUT: FOUND - DI POINTS TO THE NEXT CHR. CX CHANGED ACCORDINGLY. * ; IF THIS HAD BEEN A LAST WORD, ZERO FLAG WILL BE SET. * ; NOT FOUND - CARRY IS SET. DI, CX UNCHANGED. * ;*************************************************************************** ; ; CLC ;CLEAR CARRY FLAG ; CMP CX, 2 ;# OF CHR IN THE STRING. ; $IF NL,AND ;IF LESS THAN 2, THEN SET CARRY AND EXIT. ; ; MOV AX, ES:WORD PTR [DI] ;GET CURRENT WORD IN AX ; CMP AX, '1/' ;IS IT /1 ? ; $IF Z ;IF NOT, THEN SET CARRY AND EXIT ; INC DI ;ADJUST CX, DI TO THE NEXT CHR ; INC DI ; DEC CX ; DEC CX ; CMP CX, 0 ;IF NO MORE CHR, THEN SET ZERO FLAG. ; $ELSE ; STC ;NOT FOUND, SET CARRY FLAG. ; $ENDIF ; RET ;CHK_SLASH_ONE ENDP ; HEADER ;*************************************************************************** ;kiser: this proc is to be deleted ;CHK_DRV_SPEC PROC NEAR ; ** CHECK CURRENT CHR IS ALPHA CHR FOLLOWED BY COLON. * ; INPUT: ES:DI POINTS TO THE CURRENT CHR TO BE CHECKED. * ; CX -- # OF CHR IN THE STRING. * ; OUTPUT: FOUND - DI POINTS TO THE NEXT CHR. CX ADJUSTED ACCORDINGLY. * ; IF THIS HAD BEEN A LAST WORD, ZERO FLAG WILL BE SET. * ; NOT FOUND - CARRY IS SET. DI, CX UNCHANGED. * ;*************************************************************************** ; CLC ;CLEAR CARRY ; CMP CX, 2 ;# OF CHR REMAINING IN THE STRING. ; $IF NL,AND ;IF NOT LESS THAN 2, THEN FOUND ; ;IF LESS THAN 2, THEN NOT FOUND - SET CARRY AND EXIT. ; MOV AL, ES:BYTE PTR [DI] ;GET CURRENT CHR ; AND AL, 11011111B ;CHANGE IT TO UPPER_CASE CHR. ; CMP AL, 'A' ; $IF NB,AND ;NOT BELOW 'A', THEN MAYBE FOUND OK ; ; CMP AL, 'Z' ; $IF NA,AND ;NOT ABOVE 'Z', THEN FOUND ; ; MOV AL, ES:BYTE PTR [DI+1] ;LOOK AHEAD THE FOLLOWING CHR. ; CMP AL, ':' ;SHOULD BE A COLON. ; $IF Z ;IF FOUND. ; INC DI ;FOUND. ADJUST CX, DI TO THE NEXT CHR. ; INC DI ; DEC CX ; DEC CX ; CMP CX, 0 ;IF NO MORE CHR, THAN SET THE ZERO FLAG. ; $ELSE ; STC ;SET CARRY ; $ENDIF ; RET ;CHK_DRV_SPEC ENDP ; HEADER ;*************************************************************************** ;kiser: this proc is to be deleted ;CHK_BLANK PROC NEAR ;; ** CHECK THE CURRENT CHR IS A BLANK OR TAB * ;; INPUT: ES:DI POINTS TO THE CURRENT CHR. * ; CX - # OF CHR IN THE STRING. * ; OUTPUT: FOUND - DI MOVES TO THE NEXT CHR. CX DECREASES BY 1. * ; NOT FOUND - CARRY IS SET. DI, CX UNCHANGED. * ;*************************************************************************** ; CLC ;CLEAR CARRY ; CMP CX, 1 ;IF LESS THAN 1, NOT FOUND. ; $IF L,OR ;GO SET CARRY AND EXIT ; ; MOV AL, ES:BYTE PTR [DI] ;GET CURRENT CHR ; CMP AL, 020H ;020H=BLANK CHR ; $IF NZ,AND ;NOT FOUND ; CMP AL, 09H ;09H=TAB CHR ; $IF NZ ;NOT FOUND EITHER ; ; ;THEN NOT FOUND ; STC ;SET CARRY ; $ELSE ;CHAR MUST BE EITHER TAB OR BLANK ; INC DI ;FOUND. ADJUST DI, CX ; DEC CX ; $ENDIF ; RET ;CHK_BLANK ENDP .LIST HEADER ; ;AN000; ;****************************************************************************** ; SUBROUTINE NAME : SOURCE_TARGET_DRV DETERMINES SOURCE & TARGET DRIVES & * ; CONVERT THEM FROM DOS TO BIOS VALUE * ; INPUT : SOURCE_DRIVE & TARGET_DRIVE HAVE DOS DRIVE ID'S: * ; 0 = DEFAULT 1 = DRV A * ; 2 = DRV B 3 = DRV C ETC * ; * ; * ; OUTPUT : DEFAULT_DRV: CURRENT DEFAULT DRIVE * ; 0 - DRIVE A 1 - DRIVE B * ; 2 - DRIVE C 3 - DRIVE D * ; * ; : SOURCE_DRIVE 1 = DRIVE A 2 = DRIVE B ETC. * ; : TARGET_DRIVE 1 = DRIVE A 2 = DRIVE B ETC. * ; (UNCHANGED) * ;****************************************************************************** SOURCE_TARGET_DRV PROC NEAR PUBLIC SOURCE_TARGET_DRV ;MAKE ENTRY IN LINK MAP ;AN000; ;GET CURRENT DEFAULT DRIVE MOV AH,CURRENTDRV_FUNC ;FUNCTION CALL (19H) ;(AL <- CURRENT DEFAULT DRV INT 21H ;0 = A, 1 = B, ETC) MOV DEFAULT_DRV,AL ;SAVE IT INC AL ;NOW A=1, B=2, ETC ;AN000; CMP SOURCE_DRIVE,ZERO ;FIRST DRV ENTERED? ;AC000; ; $IF E ;NO DRIVE LETTER ENTERED JNE $$IF7 MOV SOURCE_DRIVE,AL ;USE DEFAULT DRIVE AS SOURCE ;AC000; MOV TARGET_DRIVE,AL ; AND AS TARGET ;AC000; ; $ELSE JMP SHORT $$EN7 $$IF7: CMP TARGET_DRIVE,ZERO ;WAS THE SECOND DRIVE ID SPECIFIED? ;AC000; ; $IF E ;NO, SO TARGET DRV IS DEFAULT ;AC000; JNE $$IF9 MOV TARGET_DRIVE,AL ;USE DEFAULT DRIVE AS TARGET ;AC000; ; $ENDIF $$IF9: ; $ENDIF $$EN7: MOV AX,WORD PTR SOURCE_DRIVE ;SOURCE TO AL, TARGET TO AH ;AC000; ADD ASCII_DRV1_ID,AL ;MAKE THE DRIVE ALPHABET READABLE ADD ASCII_DRV2_ID,AH ;IN THE MESSAGE RET SOURCE_TARGET_DRV ENDP HEADER ; ;AN000; ;****************************************************************************** ; SUBROUTINE NAME : TEST_DRIVE_VALIDITY--MAKE SURE SOURCE AND TARGET DRIVES * ; SPECIFIED BY USER ARE VALID FOR DISKCOPY * ; * ; INPUT : SOURCE_DRIVE:BYTE, TARGET_DRIVE:BYTE * ; * ; OUTPUT : DX='FINE' IF DRIVES ARE VALID, ELSE DX CONTAINS MSG PTR * ;****************************************************************************** TEST_DRIVE_VALIDITY PROC NEAR PUBLIC TEST_DRIVE_VALIDITY ;MAKE ENTRY IN LINK MAP ;AN000; CALL DOS_DRIVE_VALIDITY CMP DX,FINE ; $IF E,AND ; ;AC000; JNE $$IF12 MOV BL,SOURCE_DRIVE CALL CHECK_REDIRECTION CMP DX,FINE ; $IF E,AND ; ;AC000; JNE $$IF12 MOV BL,TARGET_DRIVE CALL CHECK_REDIRECTION CMP DX,FINE ; $IF E,AND ; ;AC000; JNE $$IF12 MOV BL,SOURCE_DRIVE CALL CHECK_SERVER CMP DX,FINE ; $IF E,AND ; ;AC000; JNE $$IF12 MOV BL,TARGET_DRIVE CALL CHECK_SERVER CMP DX,FINE ; $IF E,AND ; ;AC000; JNE $$IF12 CALL TEST_REMOVABLE CMP DX,FINE ; $IF E ; ;AC000; JNE $$IF12 CALL CHK_SINGLE_DRV_OP ;CHECK IF IT IS ; ONE PHYSICAL DRIVE OPERATION ; $ENDIF ; ;AC000; $$IF12: RET TEST_DRIVE_VALIDITY ENDP HEADER ; ;AN000; ;****************************************************************************** ; SUBROUTINE NAME : DOS_DRIVE_VALIDITY -- CHECK DOS DRIVE VALIDITY BYTE * ; * ; INPUT : DRIVE_VALID:BYTE * ; * ; OUTPUT : DX="FINE" IF DRIVES ARE VALID ELSE DX CONTAINS MESSAGE PTR * ;****************************************************************************** DOS_DRIVE_VALIDITY PROC NEAR CMP DRIVE_VALID,0 ;SEE IF DRIVES ARE VALID DOS DEVICE ; $IF NE JE $$IF14 MOV DX,OFFSET MSGNUM_INVALID_DRV ; ;AC000; ; $ENDIF $$IF14: RET DOS_DRIVE_VALIDITY ENDP HEADER ; ;AN000; ;****************************************************************************** ; SUBROUTINE NAME : TEST_REMOVABLE -- CHECK IF DRIVES SPECIFED ARE REMOVABLE * ; * ; INPUT : SOURCE_DRIVE:BYTE, TARGET_DRIVE:BYTE * ; * ; OUTPUT : DX=FILE IF DRIVES ARE VALID ELSE DX CONTAINS MESSAGE PTR * ;****************************************************************************** TEST_REMOVABLE PROC NEAR MOV BL,SOURCE_DRIVE ;GET PARM 1 DRIVE ID MOV AX,DRIVE_CHECK ;CHECK FOR REMOVABLE DRIVE = 4408h INT 21H ;IOCTL CALL ; $IF NC ;IF DRIVE ID IS WITHIN RANGE JC $$IF16 CMP AX,REMOVABLE ;THEN IF SOURCE DRIVE IS FIXED ; $IF NE ; THEN JE $$IF17 MOV DX,OFFSET MSGNUM_INVALID_DRV ;GENERATE HARD ;AC000; ; DRIVE ERROR MESSAGE ; $ELSE ;ELSE, SRC IS REMOVABLE; JMP SHORT $$EN17 $$IF17: MOV BL,TARGET_DRIVE ;NOW GO CHECK TARGET MOV AX,DRIVE_CHECK ;CHECK FOR REMOVABLE DRIVE INT 21H ;IOCTL CALL ; $IF NC ;IF DRV WITHIN RANGE JC $$IF19 CMP AX,REMOVABLE ;THEN TGT DRV IS FIXED ; $IF NE ; THEN JE $$IF20 MOV DX,OFFSET MSGNUM_INVALID_DRV ;GENERATE HARD ;AC000; ; DRV ERROR MSG ; $ENDIF ;END TEST IF TGT DRV IS FIXED $$IF20: ; $ELSE ;TGT DRV OUT OF RANGE. EX. DRIVE X: JMP SHORT $$EN19 $$IF19: MOV DX,OFFSET MSGNUM_INVALID_DRV ; ;AC000; ; $ENDIF ;END TEST IF TGT WITHIN RANGE $$EN19: ; $ENDIF ;END IF SRC IS REMOVABLE $$EN17: ; $ELSE ;ELSE, SRC DRV OUT OF RANGE JMP SHORT $$EN16 $$IF16: MOV DX,OFFSET MSGNUM_INVALID_DRV ;PRINT ERROR MSG ;AC000; ; $ENDIF ;END TEST IF SRC DRV WITHIN RANGE $$EN16: RET TEST_REMOVABLE ENDP HEADER ; ;AN000; ;****************************************************************************** ; SUBROUTINE NAME : CHK_SINGLE_DRV_OP * ; * ; INPUT : SOURCE_DRIVE - LOGICAL DRIVE NUMBER * ; TARGET_DRIVE * ; * ; OUTPUT : COPY_TYPE WILL BE SET TO ONE OR TWO DEPENDING ON THE * ; TEST RESULT. IF IT IS A SINGLE DRIVE COPY, THEN * ; TARGET DRIVE LETTER WILL BE CHANGED TO THAT OF SOURCE. * ; THE OWNERSHIP OF THE SOURCE AND TARGET DRIVE LETTER * ; MIGHT HAVE BEEN CHANGED. * ; SO, BEFORE EXIT TO DOS, THEY SHOULD BE RESET TO THE SAVED* ; ONE USING S_OWNER_SAVED AND T_OWNER_SAVED UNLESS THEY * ; ARE EQUAL TO 0. (0 MEANS ONLY ONE DRIVE LETTER ASSIGNED.)* ; ASCII_DRV1_ID, ASCII_DRV2_ID MAY BE CHANGED ACCORDINGLY. * ;****************************************************************************** CHK_SINGLE_DRV_OP PROC NEAR PUSH AX MOV BL,SOURCE_DRIVE CALL GET_LOGICAL_DRIVE MOV S_OWNER_SAVED, AL ;SAVE CURRENT OWNER DRIVE LETTER. MOV BL, TARGET_DRIVE CALL GET_LOGICAL_DRIVE MOV T_OWNER_SAVED, AL ;SAVE CURRENT OWNER MOV BL, SOURCE_DRIVE CALL SET_LOGICAL_DRIVE MOV BL, TARGET_DRIVE CALL SET_LOGICAL_DRIVE MOV BL, SOURCE_DRIVE CALL GET_LOGICAL_DRIVE ;CHECK SOURCE DRV LETTER ; STILL HAS A OWNERSHIP. CMP AL, SOURCE_DRIVE ; ; $IF NE ;IF IT DOES NOT, THEN A JE $$IF27 ; SINGLE DRIVE COPY. MOV COPY_TYPE, ONE MOV BL, SOURCE_DRIVE MOV TARGET_DRIVE, BL ;SET TARGET DRV LETTER ; TO THAT OF SOURCE MOV BL, ASCII_DRV1_ID MOV ASCII_DRV2_ID, BL MOV BL, SOURCE_DRIVE CALL SET_LOGICAL_DRIVE ;SET THE OWNER BACK TO ; SOURCE DRV LETTER ; $ELSE JMP SHORT $$EN27 $$IF27: CMP AL, TARGET_DRIVE ;SOURCE DRV LETTER = TARGET DRV ; LETTER CASE, FOR EX. DISKCOPY A: A: ; $IF E JNE $$IF29 MOV COPY_TYPE, ONE ; $ELSE JMP SHORT $$EN29 $$IF29: MOV COPY_TYPE, TWO ; $ENDIF $$EN29: ; $ENDIF $$EN27: POP AX RET CHK_SINGLE_DRV_OP ENDP HEADER ;AN000; ;****************************************************************************** GET_LOGICAL_DRIVE PROC NEAR ; *** GET THE LOGICAL DRIVE NUMBER WHO HAS THE OWNERSHIP OF THE PHYSICAL ; DRIVE. ; INPUT: BL = DRIVE NUMBER (0=DEFAULT, 1=A, 2=B...) ; OUTPUT: AL = DRIVE NUMBER (0= ONLY ONE DRIVE LETTER ASSIGNED TO THE ; BLOCK DEVICE. OTHERWISE, 1=A, 2=B...) ; ;****************************************************************************** MOV AH, 44H MOV AL, 0EH ; GET THE OWNER OF LOGICAL DRIVE NUMBER INT 21H CMP AL, 0 ;ONLY ONE DRIVE LETTER ASSIGNED? ; $IF E JNE $$IF33 MOV AL, BL ;THEN SET THE INPUT DRIVE NUMBER TO AL. ; $ENDIF $$IF33: RET GET_LOGICAL_DRIVE ENDP HEADER ; ;AN000; ;****************************************************************************** ; SUBROUTINE NAME : DISKETTE_DRV_TYPE DOES THE FOLLOWING: * ; - GETS SOURCE, TARGET DRIVE INFORMATION * ; - CHECK REMOVABLE DRIVE * ; *** REMARK: WILL NOT ALLOW DISKCOPY BETWEEN 5.25" AND 3.5" DRIVES. * ; *** ALSO, IN THE MAIN PROGRAM, SOURCE MEDIA BPB INFORMATIONS (# OF SEC/TRK, * ; *** # OF TRACKS) SHOULD BE CHECKED AGAINST TARGET DEVICE INFORMATIONS. * ; *** IF # OF SECT/TRACK, # OF TRACKS OF TARGET DEVICE ARE EQUAL TO, OR * ; *** GREATER THAN THOSE OF THE SOURCE MEDIA BPB, THEN IT IS OK. OTHERWISE * ; *** DEVICE NOT COMPATIBLE. * ; *** IF THIS DOES NOT GAURANTEES COMPATIBILITY BETWEEN SOURCE AND TARGET * ; *** DEVICE OR MEDIA, EVENTUALLY, FAILURE TO FORMAT THE TARGET WILL * ; *** TELL THAT SOURCE, TARGET DEVICE OR MEDIA ARE NOT COMPATIBLE. * ; * ;****************************************************************************** DISKETTE_DRV_TYPE PROC NEAR PUSH AX xor bx, bx MOV BL, SOURCE_DRIVE MOV CL, GETDEVPARM ;=60h MOV DX, OFFSET DS_IOCTL_DRV_PARM ;POINTER TO THE CONTROL STRING CALL GENERIC_IOCTL ;GET DEFAULT DEVICE PARM. TEST DS_deviceAttributes, 0001h ;CHECK REMOVABLE. 0001 = NOT REMOVABLE ; $IF E,AND ;NO, CONTINUE ;AC000; JNE $$IF35 MOV AX, DS_numberOfCylinders ;CURRENTLY IGNORE AH. ASSUME LESS ; THAN TWO BYTES MOV S_DRV_TRACKS, AL MOV BX, OFFSET DS_BPB_PTR MOV AX, [BX].CHead MOV S_DRV_HEADS, AL MOV AX, [BX].CSECT_TRACK MOV S_DRV_SECT_TRACK, AL MOV AX, [BX].CBYTE_SECT ;RECOMMENDED BYTES/SECTOR MOV RECOMMENDED_BYTES_SECTOR, AX XOR BX,BX MOV BL, TARGET_DRIVE MOV CL, GETDEVPARM MOV DX, OFFSET DT_IOCTL_DRV_PARM CALL GENERIC_IOCTL ;GET DEFAULT DEVICE PARM. TEST DT_deviceAttributes, 0001h ;FIXED DISK? ; $IF Z ;TARGET IS NOT FIXED DISK, OK ;AC000; JNZ $$IF35 MOV AX, DT_numberOfCylinders MOV T_DRV_TRACKS, AL MOV BX, OFFSET DT_BPB_PTR MOV AX, [BX].CHead MOV T_DRV_HEADS, AL MOV AX, [BX].CSECT_TRACK MOV T_DRV_SECT_TRACK, AL ;**NOW, CHECK SOURCE, TARGET DEVICE COMPATIBILITY MOV DX, FINE ;GUESS, ALL WILL BE OK ; DX MAY BE CHANGED TO REFLECT ERROR CMP DS_deviceType, DRV_720 ;0 - 48 TPI, 5.25", 96 TPI, ; 5.25", 2 - 720kb, 3.5" ; $IF E ;WILL ONLY ALLOW DISKCOPY BETWEEN ;AC000; JNE $$IF36 ; 720KB, 3.5 SOURCE, TARGET CMP DT_deviceType, DRV_720 ;target = 720KB also? ; $IF NE ; ;AC000; JE $$IF37 MOV DX, OFFSET MSGNUM_NOT_COMPATIBLE ;AC000; ; $ENDIF ; ;AC000; $$IF37: ; $ELSE ;SINCE SOURCE NOT 720 ;AC000; JMP SHORT $$EN36 $$IF36: CMP DT_deviceType, DRV_720 ;SOURCE IS NOT 720kb, ; IS TARGET 720? ; $IF E ;IF SO, THEN ;AC000; JNE $$IF40 ;DDT IS NOT COMPATIBLE MOV DX, OFFSET MSGNUM_NOT_COMPATIBLE ; ;AC000; ; $ENDIF ; ;AC000; $$IF40: ; $ENDIF ; ;AC000; $$EN36: ; $ELSE ;SINCE SOURCE IS FIXED DISK, ERROR ;AC000; JMP SHORT $$EN35 $$IF35: MOV DX, OFFSET MSGNUM_INVALID_DRV ;ISSUE BAD DRV MSG ;AC000; ; $ENDIF ; ;AC000; $$EN35: POP AX RET DISKETTE_DRV_TYPE ENDP HEADER ; ;AN000; ;****************************************************************************** ; SUBROUTINE NAME : CHECK_REDIRECTION FIND OUT IF DEVICE IS REDIRECTED * ; IF IT IS, GENERATE ERROR MSG & EXIT * ; INPUT : BL - DRIVE TO BE TESTED * ; : AL : CURRENT DEFAULT DRIV * ; * ; OUTPUT : DX = LOCAL_DRV (-1) * ; = DIRECTED ( ERROR MSG OFFSET) * ; = INVALID_DRIVE (ERROR MSG OFFSET) * ;****************************************************************************** CHECK_REDIRECTION PROC NEAR PUSH AX ;SAVE REGISTERS PUSH BX PUSH CX MOV CX,DX ;SAVE RET TEMPORARILY MOV AH,IOCTL_FUNC ;GET IOCTL FUNTION & MOV AL,REDIRECTED_FUNC ;IOCTL SUB-FUNCTION ******CHECK*** INT 21H ;AND GO FIND OUT IF IT'S LOCAL ; $IF C JNC $$IF45 MOV CX,OFFSET MSGNUM_INVALID_DRV ;REDIR INVALID ;AC000; ; $ELSE JMP SHORT $$EN45 $$IF45: TEST DX,REMOTE_DRV ;IF DRIVE IS REDIRECTED ; $IF NZ JZ $$IF47 MOV CX,OFFSET MSGNUM_DRV_REDIRECTED ; ;AC000; ; $ENDIF $$IF47: ; $ENDIF $$EN45: MOV DX,CX ;GET ERROR MSG @ POP CX ;RESTORE REGISTERS POP BX POP AX RET ;RETURN TO CALLER CHECK_REDIRECTION ENDP HEADER ; ;AN000; ;****************************************************************************** ; SUBROUTINE NAME : BUFFER_SIZE DETERMINES WHERE BUFFER STARTS & ENDS * ; INPUT : NONE * ; * ; OUTPUT : BUFFER_BEGIN ADDRESS * ; : BUFFER_END ADDRESS * ;****************************************************************************** BUFFER_SIZE PROC NEAR PUSH AX ;SAVE REGISTERS PUSH BX PUSH CX MOV BX, offset init ;GET ADDR OF INIT + 1024 AS ; A START OF BUFFER add bx, 1024 ;(OFFSET FROM CS, IN BYTES) MOV CL,4 ;CONVERT OFFSET INTO SEGMT BY DIVIDING SHR BX,CL ;IT BY 16 MOV AX,CS ;CS + OFFSET => INIT+1024@ IN SEGMENT ADD BX,AX ;WHERE BUFFER CAN START ;NEED TO START AT A NEW SECTOR ==> AND BL,CLEAR_SEGMENT ;TRUNCATE TO PREVIOUS 512 BYTE BOUNDRY ;(GET PREVIOUS SECTOR NUMBER) ADD BX,20H ;THEN, ADVANCE TO THE BEGINNING OF ;NEXT SECTOR (SINCE PART OF PREVIOUS ;SECTOR WAS USED) MOV BUFFER_BEGIN,BX ;SAVE OUR BUFFER START SEGMENT ADDR ;(AT THE BEGINNING OF A SECTOR WITH ;SEGMENT BITS CLEARED) MOV BX,DS:TWO ;GET ADDR WHERE BUFFER ENDS MOV BUFFER_END,BX ;(TOP OF MEMORY, OFFSET 2 IN PSP) POP CX ;RESTORE REGISTERS POP BX POP AX RET ;RETURN TO CALLER BUFFER_SIZE ENDP HEADER ; ;AN000; ;****************************************************************************** SETUP_CTRL_BREAK PROC NEAR ;SETUP CTRL-BREAK VECTOR ;****************************************************************************** PUSH AX PUSH BX PUSH DX PUSH ES MOV AX,SET_CTL_BREAK_VECT ;SET THE CTRL-BREAK VECTOR MOV DX,OFFSET MAIN_EXIT INT 21H POP ES POP DX POP BX POP AX RET SETUP_CTRL_BREAK ENDP HEADER ; ;AN000; ;****************************************************************************** CHECK_SERVER PROC NEAR ;SEE IF SERVER OR REDIRECTOR IS IN++ ; ; INPUT: BL = DRIVE NUMBER (1=A,2=B ETC....) ;****************************************************************************** MOV AH,0 ;SEE IF SERVER LOADED INT SERVER CMP AH,0 ; $IF E JNE $$IF50 MOV DX,FINE ; $ELSE JMP SHORT $$EN50 $$IF50: DEC BL ADD BL,"A" ;CONVERT TO ASCII DRIVE LETTER MOV ASCII_DRIVE_LETTER,BL ;PUT IN ASCIIZ STRING MOV SI,OFFSET ASCII_DRIVE_LETTER MOV AH,SHARED CLC INT SERVER ; $IF C JNC $$IF52 MOV DX,OFFSET MSGNUM_DRV_REDIRECTED ; ;AC000; ; $ELSE JMP SHORT $$EN52 $$IF52: MOV DX,FINE ; $ENDIF $$EN52: ; $ENDIF $$EN50: RET CHECK_SERVER ENDP COPYINIT_END LABEL NEAR PUBLIC COPYINIT_END PATHLABL COPYINIT ;AN015; CSEG ENDS END