PAGE, 132 ;AN000; TITLE XCOPY WITH FULL MEMORY USE ;AN000; ; ##### R E A D M E ##### ; ; This file contains a copy of the XCOPY code. The code has been ; Revised (additions and many parts commented out) to conform to the ; needs of SELECT. ; ; ######################### ;****************** START OF SPECIFICATIONS ***************************** ; MODULE NAME: XCOPY ; ; DESCRIPTIVE NAME: selectively copy groups of files, which can include ; lower level subdirectories. ; ; FUNCTION: The modules of XCOPY will be placed in the following order - ; SSEG, DSEG(MAIN DATA, MAIN MSG), CSEG (MAIN + INIT), ; DSEG_INIT(INIT DATA, INIT MSG) ; ; HEADER - informations needed about the file, subdirectory ... ; Continue_Info -> 0 - a whole single file in this header ; segment, or dir. ; 1 - Continuation of a small file. ; 2 - Continuation of a Big file ; 3 - Eof of continuation ; Next_Ptr -> points to the next header segment ; Before_Ptr -> points to the old header segment ; ; By optionally using the Archive bit in the directory of each ; file, XCOPY can be used as an alternative method of creating ; backup files which can be accessed directly by DOS and its ; applications without the need to "restore" the backup files. ; ; XCOPY is especially useful when several files are being copied ; and there is a generous amount of RAM available, because XCOPY ; will fill the memory with all the source files it can read in ; before starting to create output files. If the memory is not ; enough to hold all the source, this cycle will be repeated until ; the process is completed. For single drive systems, this maximum ; usage of the memory greatly reduces the amount of diskette ; swapping that would be required by the usual COPY command. ; ; ENTRY POINT: MAIN ; ; INPUT: (DOS COMMAND LINE PARAMETERS) ; ; SOURCE OPERAND: TARGET OPERAND: ; ; [d:] [path] filename[.ext] [d:] [path] [filename[.ext]] ; or ; [d:] path [filename[.ext]] ; or ; d: [path] [filename[.ext]] ; ; ; SWITCHES: ; ; /A /D /E /M /P /S /V /W ; ;The /A switch will copy only those files whose archive bit of the attribute is ;set to one. The attribute of the source file is not changed. This option is ;useful when making multiple backups when doing the non-final backup. ;The archive bit is one when a file has be created or Revised since the last ;time the bit was turned off. XCOPY /M or BACKUP /M will turn this bit off. ;The ATTRIB command can also be used to change the setting of the archive bit. ; ;The /D switch will copy only those files whose date is the same or later than ;the date specified. Depending on the country code you selected using the ;COUNTRY command, the date is specified in the format corresponding to the ;indicated country. ; ;The /E switch will create subdirectories on the target even if they end up ;being empty after all copying is over. If /E is not specified, empty ;subdirectories are not created. ; ;The /M switch will copy only those files whose archive bit is set in its ;attribute. Unlike the /A switch, /M will cause the archive bit in the source ;file to be turned off. This allows XCOPY to be used in making a final backup. ;The archive bit is one when a file has be created or Revised since the last ;time the bit was turned off. XCOPY /M or BACKUP /M will turn this bit off. ;The ATTRIB command can also be used to change the setting of the archive bit. ; ;The /P switch will prompt the operator before copying each file. In this ;situation, each file is copied onto the target before reading in the next ;file. The multi-file copy into a large memory buffer is not done. The prompt ;displays the complete filespec it proposes to copy and asks for (Y/N) ;response, which is then read in from the standard input device. ; ;The /S switch will not only copy the files in the current source directory but ;also those in all the subdirectories below the current one, with XCOPY ;following the Tree of the subdirectories to access these files. /S does not ;create an empty subdirectory on the target (unless /E is also specified). ;If the /S switch is not specified, XCOPY works only within the specified (or ;current) subdirectory of the source. ; ;The /V switch will cause DOS to verify that the sectors written on the target ;are recorded properly. This option has been provided so you can verify that ;critical data has been correctly recorded. This option will cause XCOPY to ;run more slowly, due to the additional overhead of verification. ; ;The /W switch will instruct XCOPY to pause before actually starting the ;movement of data, thus permit the copying of diskettes that do not actually ;have XCOPY available on them. The diskette containing XCOPY can be mounted ;first, the XCOPY command given with the /W option, then when the prompt ;requesting permission to continue is given, that diskette can then be removed ;and the source diskette mounted in its place, then the operator can press any ;key to continue after the pause. This feature is especially useful in a ;non-hardfile system. ; ; EXIT-NORMAL: ERRORLEVEL_0 - This is the normal completion code. ; ERRORLEVEL_2 - This is due to termination via Control-Break. ; ERRORLEVEL_4 - This is used to indicate an error condition. ; ; There are many types of problems that are detected and result in this ; return code, such as: ; ; write failure due to hard disk error ; disk full ; conflict between name of new subdirectory and existing filename ; access denied ; too many open files ; sharing violation ; lock violation ; general failure ; file not found ; path not found ; directory full ; invalid parms ; reserved file name as source ; insufficient memory ; incorrect DOS version ; ; ; INTERNAL REFERENCES: ; ; ROUTINES: ; ; ; DATA AREAS: ; ; ; EXTERNAL REFERENCES: ; ; ROUTINES: ; ; ; DATA AREAS: ; ; ; NOTES: This module should be processed with the SALUT pre-processor ; with the re-alignment not requested, as: ; ; SALUT XCOPY,NUL,; ; ; To assemble these modules, the sequential ; ordering of segments may be used. ; ; For LINK instructions: ; link profile ..\lib ; ; REVISION HISTORY: A000 Version 4.00: add PARSER, System Message Handler, ; Remove the BELL char.,turn off APPEND during TREE ; search,Extended Attribute processing, Uppercasing ; and "Out Of Space" during write to standard out. ; A001 PTM0011 XCOPY not handling path >63 characters. ; CHK_MAX_LENGTH proc(XCPYINIT) is Revised to err if ; >63 chrs. ; A002 PTM0012 XCOPY unnecessarily accessing current drive. ; ORG_S_T_DEF is Revised to ignore CHDIR if drive ; is not TARGET or SOURCE. ; A003 PTM0088 XCOPY (\) missing in 'FILE SHARING ERROR'. ; This problem is fixed with incorporation of the ; new message services. ; A005 DCR0201 10/9/87 Incorperate new format for EXTENDED ; ATTRIBUTES. ; ; ; Label: "DOS XCOPY Utility" ; "Version 4.00 (C) Copyright 1988 Microsoft" ; "Licensed Material - Program Property of Microsoft" ; ;****************** END OF SPECIFICATIONS ***************************** CLEAR_SCREEN2 MACRO;AN000; MOV CX,0 ;;AN000; MOV DX,184Fh ;;AN000; scroll screen from (0,0) tO (24,79) MOV AX,0600h ;;AN000; AH = 6, Scroll Function ;; AL = 0, Clear scroll area MOV BH,7 ;;AN000; video I/O interrupt INT 10H ;;AN000; MOV DX,0 ;;AN000; RKJ-set cursor posn to top right hand corner MOV BH,0 ;;AN000; RKJ MOV AH,2 ;;AN000; RKJ INT 10H ;;AN000; RKJ ENDM ;;AN000; ;-------------------------------- ; Include Files ;-------------------------------- INCLUDE STRUC.INC ;AN000; SAR INCLUDE XMAINMSG.EQU ;AN000;message file INCLUDE DOS.EQU ;AN000; INCLUDE XCOPY.EQU ;AN000; INCLUDE PAN-LIST.INC ;AN111;JW INCLUDE PANEL.MAC ;AN111;JW INCLUDE CASEXTRN.INC ;AN111;JW EXTRN FK_ENT:BYTE ;AN111;JW EXTRN FK_ENT_LEN:ABS ;AN111;JW EXTRN E_RETURN:ABS ;AN111;JW EXTRN S_DOS_SHEL_DISK:WORD ;AN111;JW EXTRN S_DOS_SEL_360:WORD ;AN111;JW EXTRN E_FILE_ATTR:ABS ;AN111;JW EXTRN FIND_FILE_ROUTINE:FAR ;AN111;JW EXTRN EXIT_SELECT:near ;AN111;JW ;------------------------------- ; Structures ;------------------------------- ;HEADER - informations needed about the file, subdirectory ... ;Continue_Info -> 0 - a whole single file in this header segment, or dir. ; 1 - Continuation of a small file. ; 2 - Continuation of a Big file ; 3 - EOF of continuation ;Next_Ptr -> points to the next header segment ;Before_Ptr -> points to the old header segment HEADER STRUC ;AN000; CONTINUE_INFO DB 0 ;AN000;set for filesize bigger then 0FFD0h NEXT_PTR DW ? ;AN000;next buffer ptr in para BEFORE_PTR DW ? ;AN000;before ptr in para DIR_DEPTH DB ? ;AN000;same as S_DEPTH CX_BYTES DW 0 ;AN000;actual # of bytes in this buffer seg. ATTR_FOUND DB ? ;AN000;attribute found FILE_TIME_FOUND DW ?;AN000; FILE_DATE_FOUND DW ?;AN000; LOW_SIZE_FOUND DW ?;AN000; HIGH_SIZE_FOUND DW ?;AN000; TARGET_DRV_LET DB " :" ;AN000;used for writing FILENAME_FOUND DB 13 DUP (0) ;AN000; FILENAME ATTRIB_LIST DB ? ;AC005;EXTENDED ATTRIBUTE BUFFER ;------------------------------------------------------------------- ; extended attribute list used by extended open & get extended ;------------------------------------------------------------------- ; ATTRIB_LIST LABEL BYTE extended attribute buffer ; ;EA STRUC ; EXTENDED ATTRIBUTE ;EA_TYPE DB ? ; TYPE ;EAISUNDEF EQU 0 ; UNDEFINED TYPE (ATTRIB SKIPS) ; ; (OR TYPE NOT APPLICABLE) ; ; LENGTH: 0 TO 64K-1 BYTES ;EAISLOGICAL EQU 1 ; LOGICAL (0 OR 1) (ATTRIB DISPLAYS) ; LENGTH: 1 BYTE ;EAISBINARY EQU 2 ; BINARY INTEGER (ATTRIB DISPLAYS) ; ; LENGTH: 1, 2, 4 BYTES ;EAISASCII EQU 3 ; ASCII TYPE (ATTRIB DISPLAYS) ; ; LENGTH: 0 TO 128 BYTES ;EAISDATE EQU 4 ; DOS FILE DATE FORMAT (ATTRIB DISPLAYS) ; ; LENGTH: 2 BYTES ;EAISTIME EQU 5 ; DOS FILE TIME FORMAT (ATTRIB DISPLAYS) ; ; LENGTH: 2 BYTES ; ; OTHER VALUES RESERVED ;EA_FLAGS DW ? ; FLAGS ;EASYSTEM EQU 8000H ; EA IS SYSTEM DEFINED ; ; (BUILTIN, NOT APPLICATION DEFINED) ;EAREADONLY EQU 4000H ; EA IS READ ONLY (CANT BE CHANGED) ;EAHIDDEN EQU 2000H ; EA IS HIDDEN FROM ATTRIB ;EACREATEONLY EQU 1000H ; EA IS SETABLE ONLY AT CREATE TIME ; ; OTHER BITS RESERVED ;EA_RC DB ? ; FAILURE REASON CODE (SET BY DOS) ;EARCNOTFOUND EQU 1 ; NAME NOT FOUND ;EARCNOSPACE EQU 2 ; NO SPACE TO HOLD NAME OR VALUE ;EARCNOTNOW EQU 3 ; NAME CAN'T BE SET ON THIS FUNCTION ;EARCNOTEVER EQU 4 ; NAME CAN'T BE SET ;EARCUNDEF EQU 5 ; NAME KNOWN TO THIS FS BUT NOT SUPPORTED ;EARCDEFBAD EQU 6 ; EA DEFINTION BAD (TYPE, LENGTH, ETC) ;EARCACCESS EQU 7 ; EA ACCESS DENIED ;EARCUNKNOWN EQU -1 ; UNDETERMINED CAUSE ;EA_NAMELEN DB ? ; LENGTH OF NAME ;EA_VALLEN DW ? ; LENGTH OF VALUE ;EA_NAME DB ? ; FIRST BYTE OF NAME ; ;EA_VALUE DB ? ; FIRST BYTE OF VALUE ; HEADER ENDS ;AN000; ;;;;SUB_LIST STRUC ; SAR ;;;; DB 11 ; SAR ;AN000; ;;;; DB 0 ; SAR ;AN000; ;;;;DATA_OFF DW 0 ; SAR ;AN000; offset of data to be inserted ;;;;DATA_SEG DW 0 ; SAR ;AN000; offset of data to be inserted ;;;;MSG_ID DB 0 ; SAR ;AN000; n of %n ;;;;FLAGS DB 0 ; SAR ;AN000; Flags ;;;;MAX_WIDTH DB 0 ; SAR ;AN000; Maximum field width ;;;;MIN_WIDTH DB 0 ; SAR ;AN000; Minimum field width ;;;;PAD_CHAR DB 0 ; SAR ;AN000; character for pad field ;;;; ; SAR ;;;;SUB_LIST ENDS ; SAR ;****************************************************************************** DATA SEGMENT BYTE PUBLIC 'DATA' ;AN000; DATA Segment INCLUDE DOSFILES.INC ;AN000; SAR ;; ERRORLEVEL DB 0 ; SAR ;errorlevel ;; INPUT_DATE DW 0 ; SAR ;; INPUT_TIME DW 0 ; SAR PSP_SEG DW ? ;AN000; SAV_DEFAULT_DRV DB ? ;AN000;1 = A, 2 = B etc. saved default SAV_DEF_DIR_ROOT DB '\';AN000; SAV_DEFAULT_DIR DB 64 DUP (0);AN000; SAV_S_DRV DB 'A:\' ;AN000; SAV_S_CURDIR DB 64 DUP (0);AN000; SAV_T_DRV DB 'B:\' ;AN000; SAV_T_CURDIR DB 64 DUP (0);AN000; PUBLIC SOURCE_PANEL, DEST_PANEL, CHECK_FILE ;AN111;JW SOURCE_PANEL DW ? ;AN111;JW DEST_PANEL DW ? ;AN111;JW CHECK_FILE DW ? ;AN111;JW SOURCE_IN DB ? ;AN111;JW YES EQU 0 ;AN111;JW NO EQU 1 ;AN111;JW OLD_DTA_SEG DW ? ;AN111;JW OLD_DTA_OFF DW ? ;AN111;JW ; ;; DISP_S_PATH DB 67 DUP (0) ; SAR ;mirror image of source path. used for display message when copying ;; DISP_S_FILE DB 13 DUP (0) ; SAR ;; DISP_T_PATH DB 67 DUP (0) ; SAR ;mirror image of target path ;; DISP_T_FILE DB 13 DUP (0) ; SAR ; ;;B_SLASH DB '\',0 ; SAR FILE_COUNT LABEL WORD ;AN000; FILE_CNT_LOW DW 0 ;AN000;copied file count FILE_CNT_HIGH DW 0 ;AN000; ; ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;; APPENDFLAG DW 0 ; SAR ;append /X status save area FOUND_FILE_FLAG DB 0 ;AN000;used for showing the message "File not found" ; S_DRV_NUMBER DB 0 ;AN000;source, target drv # T_DRV_NUMBER DB 0 ;AN000; ; S_DRV_PATH LABEL BYTE ;AN000;source drv, path used for single_drv_copy S_DRV DB 'A:\' ;AN000; S_PATH DB 80 DUP (0) ;AN000;Initialized by calling GET CUR DIR S_DEPTH DB 0 ;AN000; S_DRV_1 DB 'A:' ;AN000; S_FILE DB '????????.???',0 ;AN000;default filename to find file ;; S_DIR DB '????????.???',0 ; SAR ;to find any subdirectory name ;; S_PARENT DB '..',0 ; SAR ;source parent used for non single_drv_copy S_HANDLE DW 0 ;AN000;file handle opened ;; S_ARC_DRV_PATH LABEL BYTE ; SAR ;informations used to change source file's ;; S_ARC_DRV DB 'A:\' ; SAR ;archieve bits. ;; S_ARC_PATH DB 64 DUP (0) ; SAR ;; S_ARC_DEPTH DB 0 ; SAR T_DRV_PATH LABEL BYTE ;AN000;target drv, path used all the time T_DRV DB 'B:\' ;AN000; T_PATH DB 64 DUP (0) ;AN000;initialized by calling GET CUR DIR in INIT T_DEPTH DB 0 ;AN000; ;; T_FILE LABEL BYTE ; SAR ;target filename for file creation ;; T_DRV_1 DB 'B:' ; SAR ;target drv letter ;; T_FILENAME DB 13 DUP (0) ; SAR ;target filename ;; T_TEMPLATE DB 11 DUP (0) ; SAR ;if global chr entered, this will be used instead of filename. ;; T_PARENT LABEL BYTE ; SAR ;; T_DRV_2 DB 'B:' ; SAR ;; T_PARENT_1 DB '..',0 ; SAR T_HANDLE DW 0 ;AN000;target handle created ;; T_MKDIR_LVL DB 0 ; SAR ;# of target starting directories created. ; ;------------------------------------------ ; PRINT_STDOUT input parameter save area ;------------------------------------------ ;; SUBST_COUNT DW 0 ; SAR ;AN000; message substitution count ;; MSG_CLASS DB 0 ; SAR ;AN000; message class ;; INPUT_FLAG DB 0 ; SAR ;AN000; Type of INT 21 used for KBD input ;; MSG_NUM DW 0 ; SAR ;AN000; message number ;---------------------------------------------- ; Parameter list used by extended open DOS call ;---------------------------------------------- PARAM_LIST LABEL WORD;AN000; E_A_LST DD 0 ;AN005; E A LIST POINTER DW 1 ;AN005; number of additional parameters DB 6 ;AN005; ID for IO mode = WORD VALUE DW 1 ;AN005; IO mode = PURE SEQUENTIAL ;; INPUT_BUFF db 20 dup(0) ; SAR ;AN000; keyboard input buffer used ;for user response (Y/N) ;-------------------------------------------------------------- ; Following three sublists are used by the Message Retriever ;-------------------------------------------------------------- ;;SUBLIST1 LABEL DWORD ; SAR ;AN000;SUBSTITUTE LIST 1 ;; DB 11 ; SAR ;AN000;sublist size ;; DB 0 ; SAR ;AN000;reserved ;; DD 0 ; SAR ;AN000;substition data Offset ;; DB 1 ; SAR ;AN000;n of %n ;; DB 0 ; SAR ;AN000;data type ;; DB 0 ; SAR ;AN000;maximum field width ;; DB 0 ; SAR ;AN000;minimum field width ;; DB 0 ; SAR ;AN000;characters for Pad field ;; ; SAR ;; ; SAR ;;SUBLIST2 LABEL DWORD ; SAR ;AN000;SUBSTITUTE LIST 2 ;; DB 11 ; SAR ;AN000;sublist size ;; DB 0 ; SAR ;AN000;reserved ;; DD 0 ; SAR ;AN000;substition data Offset ;; DB 2 ; SAR ;AN000;n of %n ;; DB 0 ; SAR ;AN000;data type ;; DB 0 ; SAR ;AN000;maximum field width ;; DB 0 ; SAR ;AN000;minimum field width ;; DB 0 ; SAR ;AN000;characters for Pad field ;; ; SAR ;; ; SAR ;;SUBLIST3 LABEL DWORD ; SAR ;AN000;SUBSTITUTE LIST 3 ;; DB 11 ; SAR ;AN000;sublist size ;; DB 0 ; SAR ;AN000;reserved ;; DD 0 ; SAR ;AN000;substition data Offset ;; DB 3 ; SAR ;AN000;n of %n ;; DB 0 ; SAR ;AN000;data type ;; DB 0 ; SAR ;AN000;maximum field width ;; DB 0 ; SAR ;AN000;minimum field width ;; DB 0 ; SAR ;AN000;characters for Pad field ;; FILE_SEARCH_ATTR DW NORM_ATTR;AN000; ;; DIR_SEARCH_ATTR DW INCL_H_S_DIR_ATTR ; SAR ; OPEN_MODE DB Read_Only_Deny_Write ;AN000;READ_ONLY_DENY_WRITE ;access, sharing mode ; ;Equates are defined in XCOPY.EQU MY_FLAG DB 0 ;AN000;informations for a tree walk ; find_first_flag equ 01h ;set MY_FLAG by "OR" ; findfile_flag equ 02h ; no_more_file equ 04h ; single_copy_flag equ 08h ;single copy instead of multi copy ; visit_parent_flag equ 10h ;visit parent node ; found_flag equ 20h ;found flag - for find subdir ; missing_link_flag equ 40h ;insuffiecient info. for not creating empty dir ; is_source_flag equ 80h ;if set, dealing with source ; reset_find_first equ 0FEh ;reset by AND ; reset_findfile equ 0FDh ; reset_no_more equ 0FBh ; reset_visit_parent equ 0EFh ; reset_found equ 0DFh ; reset_missing_link equ 0BFh ; reset_is_source equ 07Fh FILE_FLAG DB 0 ;AN000; ; cont_flag equ 01h ; eof_flag equ 02h ; big_file_flag equ 04h ; file_bigger_flag equ 08h ; created_flag equ 10h ; reset_cont equ 0FEh ; reset_eof equ 0FDh ; reset_big_file equ 0FBh ; reset_file_bigger equ 0F7h ; reset_created equ 0EFh ; reset_readfile equ 0F0h ;reset FILE_FLAG for read a file ; COPY_STATUS DB 0;AN000; ; open_error_flag equ 01h ; read_error_flag equ 02h ; create_error_flag equ 04h ; write_error_flag equ 08h ; mkdir_error_flag equ 10h ; chdir_error_flag equ 20h ; maybe_itself_flag equ 40h ; disk_full_flag equ 80h ; reset_open_error equ 0FEh ; reset_read_error equ 0FDh ; reset_create_error equ 0FBh ; reset_write_error equ 0F7h ; reset_close_error equ 0EFh ; reset_chdir_error equ 0DFh ; ACTION_FLAG DB 0;AN000; ; reading_flag equ 01h ;display "Reading source files..." ; reset_reading equ 0FEh ;do not display. ; SYS_FLAG DB 0 ;AN000;system information ; one_disk_copy_flag equ 01h ;xcopy with only one logical drive. ; default_drv_set_flag equ 02h ;default drive has been changed by this program ; default_s_dir_flag equ 04h ;source current directory saved. ; default_t_dir_flag equ 08h ;target current directory saved. ; removalble_drv_flag equ 10h ; sharing_source_flag equ 20h ;source shared ; sharing_target_flag equ 40h ; turn_verify_off_flag equ 80h ;turn the verify off when exit to dos ; reset_default_s_dir equ 0FBh ;reset default_s_dir_flag ; OPTION_FLAG DB 0;AN000; ; slash_a equ 01h ;soft archieve ? ; slash_d equ 02h ;date? ; slash_e equ 04h ;create empty dir? ; slash_m equ 08h ;hard archieve ? (turn off source archieve bit) ; slash_p equ 10h ;prompt? ; slash_s equ 20h ;walk the tree? ; slash_v equ 40h ;verify on? ; slash_w equ 80h ;show "Press any key to begin copying" msg) ; reset_slash_a equ 0FEh ;turn off soft archieve ; reset_slash_m equ 0F7h ;turn off hard archieve MAX_CX DW 0 ;AN000;less than 0FFD0h ACT_BYTES DW 0 ;AN000;actual bytes read. HIGH_FILE_SIZE DW 0;AN000; LOW_FILE_SIZE DW 0;AN000; ; TOP_OF_MEMORY DW 0 ;AN000;para BUFFER_BASE DW 0 ;AN000;para MAX_BUFFER_SIZE DW 0 ;AN000;para. BUFFER_LEFT at INIT time. BUFFER_LEFT DW 0 ;AN000;para BUFFER_PTR DW 0 ;AN000;para. If buffer_left=0 then invalid value DATA_PTR DW 0 ;AN000;buffer_ptr + 2 (32 bytes) OLD_BUFFER_PTR DW 0 ;AN000;last buffer_ptr SIZ_OF_BUFF DW ? ;AN005;para. EXTENDED ATTRIB BUFF SIZE BYTS_OF_HDR DW ? ;AN005;bytes TOTAL HEADER SIZE PARA_OF_HDR DW ? ;AN005;para. TOTAL HEADER SIZE OPEN_FILE_COUNT DW ? ;AN005;TRACKING OF OPEN FLS FOR BUFFER ; ;SIZE CALCULATION. ; ;structured data storage allocation FILE_DTA Find_DTA <> ;AN000;DTA for find file DTAS Find_DTA 32 dup (<>) ;AN000;DTA STACK for find dir ;** Througout the program BP will be used for referencing fieldsname in DTAS. ;For example, DS:[BP].dta_filename. DATA ENDS ;AN000; ;****************************************************************************** SELECT SEGMENT PARA PUBLIC 'SELECT';AN000; ASSUME CS:SELECT, DS:DATA ;AN000; ;--- START OF A PROGRAM --- PUBLIC MOD_XCOPY ;AN000; MOD_XCOPY PROC NEAR ;AN000; SAR PUSH ES ;AN000; SAR PUSH BP ;AN000; SAR ; SAR PUSH DS ;AN000; SAR POP ES ;AN000; SAR MOV SP_SAVE, SP ;AN000; SAR ; SAR MOV SOURCE_IN,YES ;AN111;JW .IF < AL eq 1 > ;AN000; MOV AL,2 ;AN000; .ELSEIF < AL eq 2 > ;AN000; MOV AL,1 ;AN000; .ENDIF ;AN000; MOV DEST,AL ;AN000; SAR MOV TABLE_OFFSET, BX ;AN000; SAR MOV NUMBER_OF_FILES, CX ;AN000; SAR MOV PATH_OFFSET, SI ;AN000; SAR CALL SAVE_DTA ;AN000; MOV AH, 62H ;AN000; SAR INT 21H ;AN000; SAR MOV PSP_SEG, BX ;AN000; SAR CALL ALLOCATE ;AN000; SAR .IF < C > ;AN000; SAR JMP JUST_EXIT ;AN000; SAR .ENDIF ;AN000; SAR XCOPY_INIT: ;AN000; CALL INIT ;AN000;initialization JC MAIN_EXIT ;AN000;error. (Already message has been displayed) MOV BP, OFFSET DTAS ;AN000;initialize BP OR ACTION_FLAG, READING_FLAG ;AN000;set reading flag for copy message CALL TREE_COPY ;AN000; CALL ORG_S_DEF ;AN000;restore the original source default dir CALL WRITE_FROM_BUFFER ;AN000;write from buffer if we missed it. CALL SWITCH_DTAS ;AN111;JW CLC ;AN000; SAR JMP RESTORE_DIRS ;AN000; SAR MAIN_EXIT: ;AN000; ;;;;; MOV BX, DATA ; SAR ;;;;; MOV DS, BX ; SAR re initialize ds, es ;;;;; MOV ES, BX ; SAR exit here if the status of source, target or default drv has been changed. ;;;;; CALL CHK_FILE_NOT_FOUND ; SAR if no files has been found, show the message. MAIN_EXIT_A: ;AN000; STC ;AN000; SAR RESTORE_DIRS:;AN000; MOV BX, DATA ;AN000; SAR MOV DS, BX ;AN000;re initialize ds, es MOV ES, BX ;AN000;exit here if the status of source, target or default drv has been changed. ;;;;; CALL CHK_MKDIR_LVL ; SAR starting target directory has been created? PUSHF ;AN000; SAR CALL ORG_S_T_DEF ;AN000;restore original target, source, default drv, and verify status POPF ;AN000; SAR JMP DO_DEALLOCATE ;AN000; SAR JUST_EXIT: ;AN000;unconditional immediate exit MOV AX, DATA ;AN000; SAR MOV DS, AX ;AN000; SAR STC ;AN000; SAR DO_DEALLOCATE: ;AN000; SAR ; Restore the original status of APPEND if active. CALL DEALLOCATE ;AN000; SAR .IF < NC > ;AN000; SAR .IF < NOT_FOUND_FLAG EQ 1 > ;AN000; SAR STC ;AN000; SAR .ELSE ;AN000; SAR CLC ;AN000; SAR .ENDIF ;AN000; SAR .ENDIF ;AN000; SAR MOV SP, SP_SAVE ;AN000; SAR POP BP ;AN000; SAR POP ES ;AN000; SAR RET ;AN000; SAR ; MOV AH, 4Ch ;return to dos ; MOV AL, ERRORLEVEL ;set return code whatever ; INT 21H MOD_XCOPY ENDP;AN000; ; ;----------------- SUBROUTINES --------------------------------------------- ALLOCATE PROC NEAR ;AN000; SAR ; SAR MOV BX, 0FFFFH ;AN000; SAR Attempt to allocate as much as possible MOV AH, 48H ;AN000; SAR INT 21H ;AN000; SAR MOV AH, 48H ;AN000; SAR BX contains the amount of memory available INT 21H ;AN000; SAR MOV ALLOCATE_START, AX ;AN000; SAR ; SAR RET ;AN000; SAR ; SAR ALLOCATE ENDP ;AN000; SAR ; SAR DEALLOCATE PROC NEAR ;AN000; SAR ; SAR PUSHF ;AN000; SAR PUSH ES ;AN000; SAR MOV AX, ALLOCATE_START ;AN000; SAR MOV ES, AX ;AN000; SAR MOV AH, 49H ;AN000; SAR INT 21H ;AN000; SAR POP ES ;AN000; SAR POPF ;AN000; SAR ; SAR RET ;AN000; SAR ; SAR DEALLOCATE ENDP ;AN000; SAR TREE_COPY PROC NEAR ;AN000; ;Walk the source tree to read files and subdirectories .IF < DEST EQ 1 > ;AN000; SAR Copying to drive b? MOV SI, OFFSET B_TARGET ;AN000; SAR Yes! Copy the drive information MOV CX, LENGTH_B_TARGET ;AN000; SAR .ELSEIF < DEST EQ 3 > ;AN111;JW ; SAR Copying to drive A? MOV SI, OFFSET A_TARGET ;AN111;JW ; SAR Yes! Copy the drive information MOV CX, LENGTH_A_TARGET ;AN111;JW ; SAR .ELSE ;AN000; SAR MOV SI, PATH_OFFSET ;AN000; SAR No! Copy to this directory. MOV CX, WORD PTR [SI] ;AN000; SAR ADD SI, 2 ;AN000; SAR Adjust for the length word .ENDIF ;AN000; SAR MOV DI,OFFSET T_DRV_PATH ;AN000; SAR CLD ;AN000; SAR REP MOVSB ;AN000; SAR OR MY_FLAG, FINDFILE_FLAG ;AN000;deals with files OR MY_FLAG, FIND_FIRST_FLAG ;AN000;find first MOV NOT_FOUND_FLAG, 0 ;AN000; SAR ; SAR NEXT_PASS: ;AN000; SAR ; SAR MOV SI, TABLE_OFFSET ;AN000; SAR MOV DOS_FILE_PTR,SI ;AN000; SAR MOV FILE_NUM,1 ;AN000; SAR CALL SET_MY_DTA ;AN000;set DTA to FILE_DTA ; $DO $$DO1: ;AN000; AND MY_FLAG, RESET_NO_MORE ;AN000; SAR CALL LOAD_DOS_FILENAME ;AN000; SAR TEST MY_FLAG, NO_MORE_FILE ;AN000; SAR ; $LEAVE NZ ; SAR JNZ $$EN1 ;AN000; .IF < SOURCE_IN EQ NO > AND ;AN000; .IF < DEST EQ 3 > ;AN000; CALL GET_SOURCE ;AN000; .ENDIF ;AN000; CALL FIND_FILE ;AN000;find first (next) ; SAR .IF < BIT MY_FLAG NAND NO_MORE_FILE > ;AN000; SAR CALL READ_INTO_BUFFER ;AN000; SAR .ELSE ;AN000; SAR MOV NOT_FOUND_FLAG, 1 ;AN000; SAR .ENDIF ;AN000; SAR ; $ENDDO ; SAR JMP SHORT $$DO1 ;AN000; $$EN1: ;AN000; CLC ;AN000; SAR ;  SAR  ;;;;;; TEST OPTION_FLAG, SLASH_S ;walk the tree? ; $IF NZ,LONG ; ; AND MY_FLAG, RESET_FINDFILE ;now, deals with directory ; OR MY_FLAG, FIND_FIRST_FLAG ;find first ; $DO ; CALL SET_MY_DTA ;set DTA to DTAS according to BP ; CALL FIND_DIR ;find first (next) ; TEST MY_FLAG, NO_MORE_FILE ;no more subdirectory? ; $LEAVE NZ ;then leave this loop to return to caller ; LEA DI, S_DRV_PATH ; LEA SI, [BP].DTA_FILENAME ; CMP S_PATH, 0 ;root directory? ; $IF E ; MOV AL, 0FFh ;then '\' is already provided. Just concat. ; $ELSE ; MOV AL, PATH_DELIM ;put delimiter ; $ENDIF ; CALL CONCAT_ASCIIZ ;make new path ; test option_flag, slash_p ;prompt mode? ; $IF NZ ; call p_concat_display_path ; $ENDIF ; INC S_DEPTH ;increase depth ; CALL MAKE_HEADER ;make header in the buffer ; OR MY_FLAG, IS_SOURCE_FLAG ;dealing with source ; AND MY_FLAG, RESET_VISIT_PARENT ;going to visit child node ; CALL CHANGE_S_DIR ;change source dir ; ADD BP, type FIND_DTA ;increase DTAS stack pointer ; CALL TREE_COPY ;tree copy the sub directory ; $ENDDO ; ; CMP S_DEPTH, 0 ;starting directory? then exit ; $IF NE ;else ; DEC S_DEPTH ;dec depth ; TEST OPTION_FLAG, SLASH_E ;copy subdirectories even if empty? ; $IF Z ; CALL DEL_EMPTY ;then check the old_buffer_ptr and ; ;if it is a directory, then restore ; ;buffer_ptr to old. ; $ENDIF ; LEA DI, S_DRV_PATH ; CALL LAST_DIR_OUT ;change environments ; test option_flag, slash_p ;prompt mode? ; $IF NZ ; call p_cut_display_path ; $ENDIF ; LEA DX, S_DRV_PATH ;before returning to the caller ; OR MY_FLAG, IS_SOURCE_FLAG ; OR MY_FLAG, VISIT_PARENT_FLAG ; CALL CHANGE_S_DIR ; SUB BP, type FIND_DTA ; $ENDIF ;;;;;;; $ENDIF ;walk the tree RET ;AN000; TREE_COPY ENDP;AN000; GET_SOURCE PROC NEAR;AN000; CALL SWITCH_DTAS;AN000; .REPEAT ;AN000; INIT_PQUEUE PAN_INST_PROMPT ;AN000; initialize queue PREPARE_PANEL SOURCE_PANEL ;AN000; remove select from A: & insert DOS PREPARE_PANEL PAN_HBAR ;AN000; PREPARE_CHILDREN ;AN000; prepare child panels DISPLAY_PANEL ;AN000; ; GET_FUNCTION FK_ENT ;AN000; .IF < SOURCE_PANEL eq SUB_REM_DOS_A > ;AN000; LEA DI, S_DOS_SEL_360 ;AN000; .ELSE ;AN000; LEA DI, S_DOS_SHEL_DISK ;AN000; .ENDIF ;AN000; MOV CX, E_FILE_ATTR ;AN000; CALL FIND_FILE_ROUTINE ;AN000; .LEAVE < nc > ;AN000; ; HANDLE_ERROR ERR_DOS_DISK, E_RETURN ;AN000; ; .UNTIL ;AN000; ;;;copying files from diskette 1 screen ; INIT_PQUEUE PAN_INSTALL_DOS ;AN000; initialize queue PREPARE_PANEL SUB_COPYING ;AN000; prepare copying from diskette 1 message DISPLAY_PANEL ;AN000; MOV SOURCE_IN,YES ;AN000; CALL SWITCH_DTAS ;AN000; RET ;AN000; GET_SOURCE ENDP ;AN000; GET_DEST PROC NEAR ;AN000; INIT_PQUEUE PAN_INST_PROMPT ;AN000; initialize queue PREPARE_PANEL DEST_PANEL ;AN000; remove select from A: & insert DOS PREPARE_PANEL PAN_HBAR ;AN000; PREPARE_CHILDREN ;AN000; prepare child panels DISPLAY_PANEL ;AN000; ; GET_FUNCTION FK_ENT ;AN000; ; ;;;copying files from diskette 1 screen ; INIT_PQUEUE PAN_INSTALL_DOS ;AN000; initialize queue PREPARE_PANEL SUB_COPYING ;AN000; prepare copying from diskette 1 message DISPLAY_PANEL ;AN000; MOV SOURCE_IN,NO ;AN000; ; SUB DOS_FILE_PTR,12 ; DEC FILE_NUM RET ;AN000; GET_DEST ENDP ;AN000; ; ;****************************************************************************** ; Subroutine: LOAD_DOS_FILENAME - Load the next filename into S_FILE. ; INPUT: ; SI - Points to the start of the filename ; ; OUTPUT: ; The S_FILE field in the data segment is updated. ;Registers Affected: ; SI - At the end, SI points to the end of the filename. It therefore ; also points to the beginning of the next filename. ; ;****************************************************************************** LOAD_DOS_FILENAME PROC NEAR;AN000; PUSH DI ;AN000; PUSH ES ;AN000; OR MY_FLAG, FIND_FIRST_FLAG ;AN000; Find first in the directory MOV SI,DOS_FILE_PTR ;AN000; LDF_SEE_IF_DONE: ;AN000; ; ; See if we are finished this pass of the files ; OR MY_FLAG, NO_MORE_FILE ;AN000; For now, assume there are not files found MOV DX, NUMBER_OF_FILES ;AN000; Get the number of files in the table .IF < FILE_NUM BE DX > ;AN000; Search while there are still more files AND MY_FLAG, RESET_NO_MORE ;AN000; Indicate that there are more files LEA DI,S_FILE ;AN000; Where to put the name MOV CX,12 ;AN000; Number of bytes CLD ;AN000; REP MOVSB ;AN000; INC FILE_NUM ;AN000; .ENDIF ;AN000; MOV DOS_FILE_PTR,SI ;AN000; Save the pointer to the files POP ES ;AN000; POP DI ;AN000; RET ;AN000; LOAD_DOS_FILENAME ENDP ;AN000; ; READ_INTO_BUFFER PROC NEAR ;AN000; ;Read *** a *** file into buffer ;  SAR  ; TEST MY_FLAG, SINGLE_COPY_FLAG ;single copy? ; $IF Z,AND ;no, multi copy ; TEST ACTION_FLAG, READING_FLAG ;show message? ; $IF NZ ;yes. ; MOV AX,MSG_READING_SOURCE ;AN000; message number ; MOV MSG_NUM,AX ;AN000; set message number ; MOV SUBST_COUNT,0 ;AN000; no message substitution ; MOV MSG_CLASS,-1 ;AN000; message class ; MOV INPUT_FLAG,0 ;AN000; no input ; MOV AX,MSG_READING_SOURCE ; CALL PRINT_STDOUT ;show message "Reading source files" ; ; AND ACTION_FLAG, RESET_READING ;reset it ;;;;;;; $ENDIF AND FILE_FLAG, RESET_READFILE ;AN000;reset file_flag to read a file MOV AX,FILE_DTA.DTA_FILE_SIZE_HIGH;AN000; MOV HIGH_FILE_SIZE, AX ;AN000; MOV AX,FILE_DTA.DTA_FILE_SIZE_LOW;AN000; MOV LOW_FILE_SIZE, AX ;AN000; MOV AX, PARA_OF_HDR ;AN005;GET THE HEADER SIZE (para.) CMP MAX_BUFFER_SIZE,AX ;AN005;IS EA BUFFER TOO LARGE? JB RIB_ERROR ;AN005;CLOSE THE FILE AND GET THE NEXT CALL CMP_FILESIZE_TO_BUFFER_LEFT ;AN000;compare sizes TEST FILE_FLAG, FILE_BIGGER_FLAG ;AN000;filesize > buffer_left - header? JZ RIB_SMALL ;AN000;if not, then small file MOV BX, S_HANDLE ;AN005; CALL CLOSE_A_FILE ;AN005;ONLY OPENED TO GET BUFFER SIZE CALL WRITE_FROM_BUFFER;AN000; .IF < SOURCE_IN EQ NO > AND ;AN111;JW .IF < DEST EQ 3 > ;AN111;JW CALL GET_SOURCE ;AN111;JW put source diskette in A: .ENDIF ;AN111;JW ; JC RIB_ERROR ;any problem with writing? CALL CMP_FILESIZE_TO_BUFFER_LEFT ;AN000;compare again TEST FILE_FLAG, FILE_BIGGER_FLAG ;AN000;still bigger? JNZ RIB_BIG ;AN000;yes. Big file RIB_SMALL: ;AN000; CALL SMALL_FILE;AN000; JC RIB_ERROR ;AN000; JMP RIB_EXIT ;AN000; RIB_BIG: ;AN000; MOV BX, S_HANDLE ;AN005; CALL CLOSE_A_FILE ;AN005;ONLY OPENED TO GET BUFFER SIZE CALL BIG_FILE ;AN000; JNC RIB_EXIT ;AN000; RIB_ERROR: ;AN000; TEST COPY_STATUS, OPEN_ERROR_FLAG ;AN000;open error? JNZ RIB_EXIT ;AN000;just exit. find next file MOV BX, S_HANDLE ;AN000;else write error CALL CLOSE_A_FILE ;AN000;close the troubled file ;and find next file RIB_EXIT: ;AN000; TEST MY_FLAG, SINGLE_COPY_FLAG ;AN000;single copy? ; $IF NZ JZ $$IF4 ;AN000; CALL WRITE_FROM_BUFFER ;AN000;then write a file ; $ENDIF $$IF4: ;AN000; RET ;AN000; READ_INTO_BUFFER ENDP ;AN000; ; SMALL_FILE PROC NEAR ;AN000; ;handles a file smaller than max_buffer_size or buffer_left, i.e. fit in memory. ;This routine will call MAKE_HEADER, SET_BUFFER_PTR< READ_A_FILE, OPEN_A_FIEL ;CALC_FILE_SIZE, CMP_FILE_FFD0h, CLOSE_A_FILE. TEST FILE_FLAG, BIG_FILE_FLAG ;AN000;called from BIG_FILE? JNZ SMF_CONT ;AN000;then need not open a file again CALL OPEN_A_FILE ;AN000;open a file using FILE_DTA JC SMF_ERROR ;AN000;open error? SMF_CONT: ;AN000; CALL CMP_FILE_FFD0h ;AN000;filesize > 0FFD0h ? TEST FILE_FLAG, FILE_BIGGER_FLAG;AN000; JZ SMF_EOF ;AN000;filesize <= 0FFD0h OR FILE_FLAG, CONT_FLAG ;AN000;filesize > 0FFD0h. set cont_flag MOV CX, 0FFD0h ;AN000;# of bytes to read CALL READ_A_FILE;AN000; JC SMF_ERROR ;AN000;unsuccessful read? CALL MAKE_HEADER ;AN000;else make header and ready for next CALL CALC_FILE_SIZE ;AN000;filesize = filesize - bytes read JMP SMF_CONT ;AN000;loop. compare again with the rest SMF_EOF: ;AN000; MOV CX, LOW_FILE_SIZE ;AN000;rest of the bytes to read OR FILE_FLAG, EOF_FLAG ;AN000;set EOF CALL READ_A_FILE ;AN000; JC SMF_ERROR ;AN000; CALL MAKE_HEADER ;AN000; MOV BX, S_HANDLE ;AN000; CALL CLOSE_A_FILE ;AN000; JMP SMF_EXIT ;AN000; SMF_ERROR: ;AN000; ; SMF_EXIT: ;AN000; RET ;AN000; SMALL_FILE ENDP ;AN000; ; BIG_FILE PROC NEAR ;AN000; ;handles a file which is bigger than max_buffer_size ;Needs 2 file handles open concurrently for read and write OR FILE_FLAG, BIG_FILE_FLAG;AN000; OR FILE_FLAG, CONT_FLAG;AN000; CALL OPEN_A_FILE ;AN000; JC BIF_ERROR ;AN000;error in open? CMP MAX_BUFFER_SIZE, 0FFFh ;AN000;max buffer size > 0FFFh in para ? JA BIF_BIG ;AN000;yes. large buffer system ;else small buffer MOV CX, MAX_CX ;AN000;CX = max_buffer_size * 16 - 32 BIF_SM: ;AN000; CALL READ_A_FILE;AN000; JC BIF_ERROR ;AN000;read error? CALL MAKE_HEADER;AN000; CALL WRITE_FROM_BUFFER;AN000; JC BIF_ERROR ;AN000;write error? TEST FILE_FLAG, EOF_FLAG ;AN000;end of file set by READ_A_FILE? JZ BIF_SM ;AN000;if not, read again MOV BX, S_HANDLE;AN000; CALL CLOSE_A_FILE;AN000; JMP BIF_EXIT ;AN000;finished. BIF_BIG: ;AN000; MOV CX, 0FFD0h ;AN000;max # of data bytes this program supports BIF_BIG1: ;AN000; CALL READ_A_FILE;AN000; JC BIF_ERROR ;AN000; CALL MAKE_HEADER;AN000; CALL CALC_FILE_SIZE ;AN000;modify file size BIF_BIG2: ;AN000; CALL CMP_FILESIZE_TO_BUFFER_LEFT ;AN000;filesize > buffer_left? TEST FILE_FLAG, FILE_BIGGER_FLAG ;AN000;yes. JZ BIF_END ;AN000;if it is not, call small_file CMP BUFFER_LEFT, 0FFFh ;AN000;BUFFER_LEFT >= 0FFF0h in bytes? JAE BIF_BIG ;AN000;then loop again. CMP BUFFER_LEFT, 140H ;AN000;else BUFFER_LEFT >= 5 K in bytes? ;minimum buffer size this program supports. JL BIF_BIG3 ;AN000;then flush buffer and try again. **IF system buffer left < 5 K then infinit loop can happen. MOV AX,BUFFER_LEFT;AN000; SUB AX,PARA_OF_HDR ;AC005;FOR HEADER SIZE para. MOV CX,BYTS_OF_HDR ;AN005;FOR HEADER SIZE bytes. JMP BIF_BIG1 ;AN000;read again BIF_BIG3: ;AN000; CALL WRITE_FROM_BUFFER;AN000; JC BIF_ERROR ;AN000; JMP BIF_BIG2 ;AN000;flush buffer and compare again. BIF_END: ;AN000; CALL SMALL_FILE ;AN000;when filesize <= buffer_left then SMALL_FILE will finish it. JC BIF_ERROR ;AN000;something wrong? CALL WRITE_FROM_BUFFER ;AN000;else finish copying this file JNC BIF_EXIT ;AN000; BIF_ERROR: ;AN000; ;what happened? BIF_EXIT: ;AN000; RET ;AN000; BIG_FILE ENDP ;AN000; ; MAKE_HEADER PROC NEAR ;AN000; ;When called by READ_A_FILE after the data had been read into the buffer, this ;routine will put the header which is just below the data area where the ;current BUFFER_PTR points. The header is 32 (2 para) byte long. And this ;routine will also call SET_BUFFER_PTR to set the BUFFER_PTR, BUFFER_LEFT ;for the next process. ;If called by TREE_COPY for a SUBDIRECTORY handle, this routine should ;check the BUFFER_LEFT (when called by READ_A_FILE, the caller is assumed ;to check the size of buffer_left before calling.) In this case, this ;routine will set the next BUFFER_PTR, BUFFER_LEFT, OLD_BUFFER_PTR ;instead of SET_BUFFER_PTR routine. ;Informations are obtained from the DTA area (for file - FILE_DTA.xxx ;dir - DS:[BP].xxx ) and stored into the header by referencing ES:field;s name. ;DS - Program Data area ;ES - will be used for a header segment in the buffer. ; PUSH ES ;AN000;save ES PUSH AX ;AN000; MH_AGAIN: ;AN000; MOV AX,BUFFER_PTR ;AN000;buffer_ptr is a segment MOV ES, AX ;AN000;now, ES is a header seg. ; MOV AX, PARA_OF_HDR ;AN005;GET THE HEADER SIZE (para.) CMP BUFFER_LEFT,AX ;AC005;buffer_left=less than NEEDED? JAE MH_START ;AN000; CALL WRITE_FROM_BUFFER ;AN000;if so, flush buffer JC MH_ERROR_BRIDGE ;AN000;write error? JMP SHORT MH_AGAIN ;AN000;reinitialize ES to new buffer ptr MH_START: ;AN000; TEST MY_FLAG, FINDFILE_FLAG ;AN000;identify caller. JNZ MH_FILE ;AN000;if a file, jmp to MH_FILE ;else deals with directory. MOV ES:CONTINUE_INFO, 0 ;AN000;not a continuation. MOV AX,OLD_BUFFER_PTR ;AN000; MOV ES:BEFORE_PTR, AX ;AN000;set before_ptr in header MOV AX,BUFFER_PTR ;AN000; MOV OLD_BUFFER_PTR, AX ;AN000;set variable OLD_BUFFER_PTR ADD AX,PARA_OF_HDR ;AC005;AX = BUFFER_PTR+HEADER(para) MOV BUFFER_PTR, AX ;AN000;set new BUFFER_PTR MOV ES:NEXT_PTR, AX ;AN000;set NEXT_PTR in the header MOV AX, PARA_OF_HDR ;AN005;GET THE HEADER SIZE (para.) SUB BUFFER_LEFT,AX ;AC005;adjust BUFFER_LEFT CMP BUFFER_LEFT,AX ;AC005;less than HEADER SIZE (para) ? ; $IF B JNB $$IF6 ;AN000; MOV BUFFER_LEFT, 0 ;AN000;indicate buffer_full ; $ENDIF $$IF6: ;AN000; MOV AL, S_DEPTH ;AN000; MOV ES:DIR_DEPTH, AL ;AN000;now save other info's MOV AL, DS:[BP].DTA_ATTRIBUTE;AN000; MOV ES:ATTR_FOUND, AL ;AN000;in this case, DIR MOV AL, BYTE PTR T_DRV;AN000; MOV ES:TARGET_DRV_LET, AL ;AN000;mov target drive letter MOV ES:TARGET_DRV_LET+1, DRV_delim ;AN000; ':' MOV CX, 13 ;AN000; LEA SI, [BP].DTA_FILENAME ;AN000;DS:SI MOV DI, OFFSET ES:FILENAME_FOUND ;AN000;ES:DI REP MOVSB ;AN000;mov sting until cx = 0 JMP MH_EXIT ;AN000; MH_ERROR_BRIDGE: JMP MH_ERROR;AN000; MH_FILE: ;AN000;handles a file header hereafter. TEST FILE_FLAG, CONT_FLAG ;AN000;continuation? JZ MH_WHOLE_FILE ;AN000;no, just a whole file TEST FILE_FLAG, EOF_FLAG ;AN000;Eof flag set? JNZ MH_CONT_END ;AN000;yes, must be end of continuation TEST FILE_FLAG, BIG_FILE_FLAG ;AN000;Is this a big file? JNZ MH_BIG ;AN000;yes MOV ES:CONTINUE_INFO, 1 ;AN000;else small file continuation. JMP MH_A_FILE ;AN000; MH_WHOLE_FILE: ;AN000; MOV ES:CONTINUE_INFO, 0 ;AN000; JMP MH_A_FILE ;AN000; MH_CONT_END: ;AN000; MOV ES:CONTINUE_INFO, 3 ;AN000; JMP MH_A_FILE ;AN000; MH_BIG: ;AN000; MOV ES:CONTINUE_INFO, 2 ;AN000; MH_A_FILE: ;AN000; MOV AX,FILE_DTA.DTA_FILE_TIME;AN000; MOV ES:FILE_TIME_FOUND, AX;AN000; MOV AX, FILE_DTA.DTA_FILE_DATE;AN000; MOV ES:FILE_DATE_FOUND, AX;AN000; MOV AX, FILE_DTA.DTA_FILE_SIZE_LOW;AN000; MOV ES:LOW_SIZE_FOUND, AX;AN000; MOV AX, FILE_DTA.DTA_FILE_SIZE_HIGH;AN000; MOV ES:HIGH_SIZE_FOUND, AX;AN000; MOV AL, BYTE PTR T_DRV ;AN000; MOV ES:TARGET_DRV_LET, AL;AN000; MOV ES:TARGET_DRV_LET+1, DRV_DELIM;AN000; MOV CX, 13 ;AN000; MOV SI, OFFSET FILE_DTA.DTA_FILENAME;AN000; MOV DI, OFFSET ES:FILENAME_FOUND;AN000; REP MOVSB ;AN000; ; Get Extended Attribute list of the opened file and save in attribute buff. ; old method ; MOV AX,INT_ORDINAL ;AN000; SET THE ORDINAL TO 0 ; MOV ES:QUERY_LIST,AX ;AN000; PUT IT IN THE BUFFER ; MOV AX,SIZ_OF_BUFF ;AN000; SET THE SIZE TO 510 BYTES ; MOV ES:BUFR_SIZ,AX ;AN000; PUT IT IN THE BUFFER ; ; MOV BX,S_HANDLE ;AN000; BX = handle ; MOV AX, QUY_ATTRIB ;AN000; extended attribute code 5703H ; MOV DI, OFFSET QUERY_LIST ;AN000; ES:DI-->QUERY list ; INT 21H ;AN000; get extended attribute list ; MOV BX,S_HANDLE ;AN005; BX = handle MOV SI,ALL_ATTR ;AN005; SELECT ALL ATTRIBUTES SIZE MOV CL, PARAGRAPH ;AN005; PARAGRAPH = 4 FOR DIV BY 16 MOV AX,SIZ_OF_BUFF ;AN005; GET THE SIZE EXPRESSED IN para. SHL AX, CL ;AN005; GET # OF BYTES FROM para. MOV CX, AX ;AN005; NEEDS TO BE IN CX MOV DI, OFFSET ES:ATTRIB_LIST ;AN005; ES:DI = E A LIST IN BUFFER MOV AX, GET_ATTRIB ;AN005; extended attribute code 5702H INT 21H ;AN005; get extended attribute list ; JC MH_ERROR ;AN000; jump if error MOV AX, OLD_BUFFER_PTR;AN000; MOV ES:BEFORE_PTR, AX;AN000; MOV AX, ACT_BYTES;AN000; MOV ES:CX_BYTES, AX;AN000; CALL SET_BUFFER_PTR ;AN000;set buffer_ptr for next. AX is already set. MOV AX, BUFFER_PTR ;AN000; MOV ES:NEXT_PTR, AX ;AN000;next buffer_ptr is next_ptr MOV AL, S_DEPTH ;AN000; MOV ES:DIR_DEPTH, AL ;AN000;same as source depth MOV AL, FILE_DTA.DTA_ATTRIBUTE;AN000; MOV ES:ATTR_FOUND, AL ;AN000;attribute found JMP MH_EXIT ;AN000; MH_ERROR: ;AN000; OR COPY_STATUS, OPEN_ERROR_FLAG ;AN000; CALL EXTENDED_ERROR_HANDLER ;AN000; MH_EXIT: ;AN000; POP AX ;AN000; POP ES ;AN000; RET ;AN000; MAKE_HEADER ENDP ;AN000; ; OPEN_A_FILE PROC NEAR ;AN000; ;------------------------------------------------------------------------- ; Use extended open DOS call to open source file, ; if successfully open, then save filehand to S_HANDLE. ;------------------------------------------------------------------------- ; Set drive letter and file name pointer in parameter list LEA SI,FILE_DTA.DTA_FILENAME ;AN005; DS:SI-->NAME TO OPEN MOV DX,OPN_FLAG ;AN000; flag = 0101H MOV CX,OPN_ATTR ;AN000; attribute = 0 MOV BX,OPN_MODE ;AN000; open mode = 0002H MOV DI, NUL_LIST ;AN005; ES:DI = -1 MOV AX, Ext_Open ;AN000; = 6Ch INT 21H ;AN000; OPEN SOURCE FILE JC OF_ERROR;AN000; MOV S_HANDLE, AX ;AN000;save filehandle INC OPEN_FILE_COUNT ;AN005;UPDATE THE OPEN FILE COUNTER JMP OF_EXIT ;AN000; exit OF_ERROR: ;AN000; OR COPY_STATUS, OPEN_ERROR_FLAG;AN000; CALL EXTENDED_ERROR_HANDLER;AN000; OF_EXIT: ;AN000; RET ;AN000; OPEN_A_FILE ENDP;AN000; ; CMP_FILE_FFD0h PROC NEAR;AN000; ;check whether the filesize in HIGH_FILE_SIZE, LOW_FILE_SIZE is bigger than ;0FFD0h. If it is, then set FILE_BIGGER_FLAG, else reset it. CMP HIGH_FILE_SIZE, 0;AN000; ; $IF E,AND JNE $$IF8 ;AN000; CMP LOW_FILE_SIZE, 0FFD0h;AN000; ; $IF BE JNBE $$IF8 ;AN000; AND FILE_FLAG, RESET_FILE_BIGGER ;AN000;filesize <= 0FFD0h ; $ELSE JMP SHORT $$EN8 ;AN000; $$IF8: ;AN000; OR FILE_FLAG, FILE_BIGGER_FLAG ;AN000; ; $ENDIF $$EN8: ;AN000; RET ;AN000; CMP_FILE_FFD0h ENDP ;AN000; ; CALC_FILE_SIZE PROC NEAR ;AN000; ;subtract the bytes read (ACT_BYTES) from the filesize in HIGH_FILE_SIZE, ;LOW_FILE_SIZE. MOV AX, ACT_BYTES ;AN000; SUB LOW_FILE_SIZE, AX ;AN000; SBB HIGH_FILE_SIZE, 0 ;AN000; RET ;AN000; CALC_FILE_SIZE ENDP ;AN000; ; READ_A_FILE PROC NEAR ;AN000; ;read a file. ;if after reading, AX < CX or AX = 0 the set EOF_FLAG. ;INPUT:CX - # of bytes to read ; BUFFER_PTR ; S_HANDLE ;OUTPUT: ACT_BYTES ; .IF < SOURCE_IN EQ NO > AND ; .IF < DEST EQ 3 > ; CALL GET_SOURCE ; .ENDIF PUSH DS ;AN000;save program data seg MOV AH, Read;AN000; MOV BX, S_HANDLE;AN000; MOV DX, BUFFER_PTR ;AN000;current buffer header seg ADD DX, PARA_OF_HDR ;AC005;skip the header part MOV DS, DX ;AN000;now DS = buffer_ptr + 2, data area XOR DX, DX ;AN000;offset DX = 0 INT 21H ;AN000; POP DS ;AN000;restore program data area JC RF_ERROR ;AN000;read error? CMP AX, CX ;AN000; JE RF_OK ;AN000; OR FILE_FLAG, EOF_FLAG ;AN000;EOF reached. AX = 0 or AX < CX RF_OK: ;AN000; CLC ;AN000;clear carry caused from CMP MOV ACT_BYTES, AX ;AN000;save actual bytes read JMP RF_EXIT ;AN000; RF_ERROR: ;AN000; OR COPY_STATUS, READ_ERROR_FLAG;AN000; CALL EXTENDED_ERROR_HANDLER;AN000; RF_EXIT: ;AN000; RET ;AN000; READ_A_FILE ENDP ;AN000; ; FIND_IT PROC NEAR ;AN000; ;set first or next depending on FIND_FIRST_FLAG. ;once called, reset FIND_FIRST_FLAG. TEST MY_FLAG, FIND_FIRST_FLAG;AN000; ; $IF NZ ;yes JZ $$IF11 ;AN000; MOV AH, Find_First;AN000; ; $ELSE JMP SHORT $$EN11 ;AN000; $$IF11: ;AN000; MOV AH, Find_Next;AN000; ; $ENDIF $$EN11: ;AN000; AND MY_FLAG, RESET_FIND_FIRST ;AN000;reset FIND_FIRST_FLAG INT 21H ;AN000; RET ;AN000; FIND_IT ENDP ;AN000; ; FIND_FILE PROC NEAR ;AN000; ;find a file ;set NO_MORE_FILE if carry. ; $SEARCH ; PUSH DS ; MOV DX,DATA ; MOV DS,DX ; .IF < SOURCE_IN EQ NO > AND ; .IF < DEST EQ 3 > ; CALL GET_SOURCE ; .ENDIF ; POP DS $$DO14: ;AN000; TEST MY_FLAG, FIND_FIRST_FLAG ;AN000;find first ? ; $IF NZ JZ $$IF15 ;AN000; MOV DX, OFFSET S_FILE ;AN000; MOV CX, File_Search_Attr ;AN000;normal = 0 ; $ELSE JMP SHORT $$EN15 ;AN000; $$IF15: ;AN000; MOV DX, OFFSET FILE_DTA ;AN000; ; $ENDIF $$EN15: ;AN000; CALL FIND_IT ;AN000; ; $EXITIF C JNC $$IF14 ;AN000; OR MY_FLAG, NO_MORE_FILE ;AN000;no more file in this directory ; $ORELSE JMP SHORT $$SR14 ;AN000; $$IF14: ;AN000; MOV FOUND_FILE_FLAG, 1 ;AN000;set the flag for "File not found" msg. OR MY_FLAG, FOUND_FLAG ;AN000; SAR ;;;;;;; CALL FILTER_FILES ;found. filter it with options TEST MY_FLAG, FOUND_FLAG ;AN000; ; $ENDLOOP NZ ;if found, leave this loop else start again JZ $$DO14 ;AN000; AND MY_FLAG, RESET_NO_MORE;AN000; ; $ENDSRCH $$SR14: ;AN000; RET ;AN000; FIND_FILE ENDP ;AN000; ; SET_MY_DTA PROC NEAR ;AN000; ;set DS:DX for find_first(next). If MY_FLAG is set to FINDFILE_FLAG then ;set it to the offset FILE_DTA, otherwise to BP. ;DS should be set to the area whre FILE_DTA, DTAS are. PUSH DX ;AN000;save current DX TEST MY_FLAG, FINDFILE_FLAG ;AN000;handling file? ; $IF NZ JZ $$IF22 ;AN000; MOV DX, OFFSET FILE_DTA;AN000; ; $ELSE JMP SHORT $$EN22 ;AN000; $$IF22: ;AN000; MOV DX, BP ;AN000; ; $ENDIF $$EN22: ;AN000; MOV AH, Set_DTA ;AN000; INT 21H ;AN000; POP DX ;AN000; RET ;AN000; SET_MY_DTA ENDP ;AN000; ; ; SAVE_DTA PROC NEAR ;AN000; ; Save old DTA address PUSH ES ;AN000; PUSH BX ;AN000; MOV AH, Get_DTA ;AN000; INT 21H ;AN000; MOV OLD_DTA_SEG,ES ;AN000; MOV OLD_DTA_OFF,BX ;AN000; POP BX ;AN000; POP ES ;AN000; RET ;AN000; SAVE_DTA ENDP ;AN000; ; ; SWITCH_DTAS PROC NEAR ;AN000; ; SWITCH DTA ADDRESSES PUSH DS ;AN000; PUSH DX ;AN000; PUSH OLD_DTA_SEG ;AN000; PUSH OLD_DTA_OFF ;AN000; CALL SAVE_DTA ;AN000; POP DX ;AN000; POP DS ;AN000; MOV AH, Set_DTA ;AN000; INT 21H ;AN000; POP DX ;AN000; POP DS ;AN000; SWITCH_DTAS ENDP ;AN000; ; ; CHANGE_T_DIR PROC NEAR ;AN000; ;change target dir according to t_drv_path. ;Since this routine is called by WRITE_FROM_BUFFER and DS now points ;to buffer area while ES points to the program data area, we set DS ;to data seg again here for the function call Chdir. PUSH DS ;AN000;save current buffer seg PUSH ES ;AN000;currentpy es is a data seg POP DS ;AN000;restore DS value as program data seg CMP T_DRV[2], 0 ;AN000;LAST_DIR_OUT took '\' out? ; $IF E JNE $$IF25 ;AN000; MOV T_DRV[2], '\' ;AN000;then put it back for root dir MOV T_DRV[3], 0 ;AN000; ; $ENDIF $$IF25: ;AN000; MOV DX, OFFSET T_DRV_PATH ;AN000; MOV AH, CHDIR ;AN000; INT 21H ;AN000; POP DS ;AN000;restore caller's DS value RET ;AN000; CHANGE_T_DIR ENDP;AN000; ; CMP_FILESIZE_TO_BUFFER_LEFT PROC NEAR;AN000; ;Compare buffer_left (paragraph) with filesize (high_file_size, low_file_size.) ;if filesize is bigger than buffer_left, then set FILE_BIGGER_FLAG ;indicating filesize > buffer_left. PUSH DX ;AN000; PUSH AX ;AN000; CMP OPEN_FILE_COUNT,NUL ;AN005;ARE THERE ANY OPEN FILES ; $IF Z ;AN005;NO, THEN GO AHEAD AND OPEN JNZ $$IF28A ;AN000; CALL OPEN_A_FILE ;AN005;OPEN A FILE USING FILE_DTA ; Get extended Attribute list size. MOV BX,S_HANDLE ;AN005; BX = handle MOV AX, GET_ATTRIB ;AN005; extended attribute code 5702H MOV SI,ALL_ATTR ;AN005; SELECT ALL ATTRIBUTES SIZE XOR CX,CX ;AN005; JUST QUERY SIZE NEEDED MOV DI, OFFSET NUL_LIST ;AN005; DI = LIST FOR NO DATA RETURNED INT 21H ;AN005; get extended attribute SIZE ADD CX,PARA_BOUND ;AN005; TO FIGURE THE NEXT PARAGRAPH MOV AX,CX ;AN005; MOV CL,PARAGRAPH ;AN005; GET PARAGRAPHS (DIV BY 16) SHR AX,CL ;AN005; MOV SIZ_OF_BUFF,AX ;AN005;SAVE BUFF SIZE FOR THE HEADER ADD AX,FIXD_HD_SIZ ;AN005;GET THE TOTAL HEADER SIZE MOV PARA_OF_HDR,AX ;AN005;SAVE FOR LATER SHL AX, CL ;AN005;CONVERT BACK TO TOTAL BYTES MOV BYTS_OF_HDR,AX ;AN005;SAVE FOR LATER MOV BX,S_HANDLE ;AN005; CALL CLOSE_A_FILE ;AN005;CLOSE THE FILE OPENED ; $ENDIF $$IF28A: ;AN000; AND FILE_FLAG, RESET_FILE_BIGGER;AN000; MOV AX,PARA_OF_HDR ;AN005;GET THE HEADER SIZE (para.) CMP BUFFER_LEFT,AX ;AC005;buffer_left >= HEADER SIZE ; $IF AE JNAE $$IF27 ;AN000; MOV AX, BUFFER_LEFT ;AN000;buffer_left in para SUB AX,PARA_OF_HDR ;AC005;consider header size in advance MOV CX, 16 ;AN000; MUL CX ;AN000;* 16. result in DX;AX CMP HIGH_FILE_SIZE, DX;AN000; ; $IF A ;if high_filesize > dx JNA $$IF28 ;AN000; OR FILE_FLAG, FILE_BIGGER_FLAG;AN000; ; $ELSE JMP SHORT $$EN28;AN000; $$IF28: ;AN000; ; $IF E JNE $$IF30 ;AN000; CMP LOW_FILE_SIZE, AX;AN000; ; $IF A JNA $$IF31 ;AN000; OR FILE_FLAG, FILE_BIGGER_FLAG;AN000; ; $ENDIF $$IF31: ;AN000; ; $ENDIF $$IF30: ;AN000; ; $ENDIF $$EN28: ;AN000; ; $ELSE JMP SHORT $$EN27 ;AN000; $$IF27: ;AN000; OR FILE_FLAG, FILE_BIGGER_FLAG ;AN000;buffer_left < 2 ; $ENDIF $$EN27: ;AN000; POP AX ;AN000; POP DX ;AN000; RET ;AN000; CMP_FILESIZE_TO_BUFFER_LEFT ENDP ;AN000; ; SET_BUFFER_PTR PROC NEAR ;AN000; ;set BUFFER_PTR, BUFFER_LEFT, OLD_BUFFER_PTR in paragraph boundary ;to be used when reading a file into buffer. ;this routine uses current BUFFER_PTR to figure out the next BUFFER_PTR. ;So, at initialization time set BUFFER_PTR to CS, and set AX to the offset ;of INIT, then thr resultant BUFFER_PTR indicates the BUFFER_BASE and ;OLD_BUFFER_PTR indicates CS.(This means if old_buffer_ptr = cs, then ;it is the start of buffer) ;To get the next BUFFER_PTR during multi-copy, just set the AX to the ;number of bytes read. This routine will add 32 bytes for header size and ;will set the next BUFFER_PTR. ;input: AX - offset of buffer ; Top_of_memory in segment ; current BUFFER_PTR ; current OLD_BUFFER_PTR ; current BUFFER_LEFT ;output: BUFFER_PTR for next reading ; OLD_BUFFER_PTR ; BUFFER_LEFT (Top_of_memory - Buffer_Ptr. If it is 0, then indicates ; the BUFFER is FULL. In this case, the BUFFER_PTR is ; invalid, but OLD_BUFFER_PTR keep the former buffer_ptr ; value which says that it is the last header in the buffer) ;** Currently this program support maxium top of memory in seg 0FFFF - resident ; area. This routine will check the overflow case to gaurd the next buffer_ptr ; not to exceed FFFF. PUSH CX ;AN000; MOV CX, BUFFER_PTR ;AN000; MOV OLD_BUFFER_PTR, CX ;AN000;set old_buffer_ptr MOV CL, 4 ;AN000; SHR AX, CL ;AN000;get paragraphs INC AX ;AN000;get next paragraph ADD AX,PARA_OF_HDR ;AC005;consider header size ADD BUFFER_PTR, AX ;AN000;add this to the current buffer_ptr ; $IF NC,AND ;not exceed 16 bit. JC $$IF37 ;AN000; MOV AX, Top_of_memory;AN000; SUB AX, BUFFER_PTR ;AN000;AX = Top_of_memory - Buffer_ptr ; $IF A ;if buffer_left > 0 JNA $$IF37 ;AN000; MOV BUFFER_LEFT, AX;AN000; ; $ELSE JMP SHORT $$EN37 ;AN000; $$IF37: ;AN000; MOV BUFFER_LEFT, 0 ;AN000;indication of buffer full ; $ENDIF $$EN37: ;AN000; POP CX ;AN000; RET ;AN000; SET_BUFFER_PTR ENDP ;AN000; ; WRITE_FROM_BUFFER PROC NEAR ;AN000; ;Write from the first header starting at buffer_base until finishes ;the last header which, actually, happens to be the old_buffer_ptr ;at the time of the call. After the writing, reset the buffer_ptr ;to buffer_base again for the next read_into_buffer. ;If continue_info is 1 or 2 (Continue of small, bigfile) then after ;the creation of a target file, it will set the CREATED_FLAG. ;This flag will be reset when it found the continue_info to be 3 ;(End of contine). ;For convenience of use of function call, ES will be used for ;the program data seg while DS will be used for the BUFFER seg. ; PUSH DS ;AN000; PUSH ES ;AN000;save ds, es PUSH DS ;AN000; POP ES ;AN000;set ES to program data seg OR ACTION_FLAG, READING_FLAG ;AN000;show reading message next time ; AND ES:MY_FLAG, RESET_IS_SOURCE ;now, deals with target ;set this for change_dir MOV AX, ES:BUFFER_BASE ;AN000; MOV DS, AX ;AN000; PUSH CS ;AN000; POP AX ;AN000; CMP ES:OLD_BUFFER_PTR, AX ;AN000;if old_buffer_ptr = CS then ;buffer is empty. Just exit JE WFB_EXIT_BRIDGE ;AN000; PUSH DS ;AN000; MOV DX,DATA ;AN000; MOV DS,DX ;AN000; .IF < DEST eq 3 > ;AN000; CALL GET_DEST ;AN000; .ENDIF ;AN000; POP DS ;AN000; WFB_CD: ;AN000; CALL CHANGE_T_DIR ;AN000; JC WFB_ERROR_BRIDGE ;AN000;error? WFB_CHATT: ;AN000; CMP DS:ATTR_FOUND, Is_subdirectory ;AN000;a subdirectory? = 10H JNE WFB_FILE ;AN000;no. a file WFB_CMP_DEPTH: ;AN000; ;  SAR  ;;;;;;; ; MOV AH, ES:T_DEPTH ;yes. a subdir. ; CMP DS:DIR_DEPTH, AH ;DIR_DEPTH > T_DEPTH ? ; JBE WFB_DEC_DEPTH ;if not, go to parent node ; LEA DI, ES:T_DRV_PATH ;else goto child node ; LEA SI, DS:FILENAME_FOUND ; CMP ES:T_PATH, 0 ;root directory? ; $IF E ; MOV AL, 0FFh ;then don't need to put delim since it is already there ; $ELSE ; MOV AL, Path_delim ;path_delim '\' ; $ENDIF ; CALL CONCAT_ASCIIZ ; call concat_display_path ;modify the path for display ; INC ES:T_DEPTH ; CALL MAKE_DIR ;try to make a new sub directory ; JC WFB_EXIT_A_BRIDGE ;there exists a file with same name. ; MOV AX, DS ;current buffer seg = old_buffer_ptr? ; CMP ES:OLD_BUFFER_PTR, AX ; JNE WFB_NEXT ;not finished yet. jmp to next ; OR ES:MY_FLAG, MISSING_LINK_FLAG ;Finished. Missing link condition occurred regarding empty sub dir ; JMP WFB_EXIT_A ;check archieve options. WFB_NEXT: ;AN000; ; MOV DS, DS:NEXT_PTR ;let's handles next header. ; JMP WFB_CD ;change directory first. WFB_EXIT_BRIDGE: JMP WFB_EXIT;AN000; WFB_ERROR_BRIDGE: JMP WFB_ERROR;AN000; WFB_EXIT_A_BRIDGE: JMP WFB_EXIT_A;AN000; WFB_DEC_DEPTH: ;AN000; ; LEA DI, ES:T_DRV_PATH ; CALL RM_EMPTY_DIR ;check flags and remove empty dir ; CALL LAST_DIR_OUT ;take off the last dir from path ; call cut_display_path ;modify path for display purpose ;;;;;; DEC ES:T_DEPTH ;and decrease depth JMP WFB_CD ;AN000;CHANGE DIR AND compare the depth again. WFB_FILE: ;AN000;Handling a file AND ES:MY_FLAG, RESET_MISSING_LINK ;AN000;if found a file, then current dir is not empty. TEST ES:FILE_FLAG, CREATED_FLAG ;AN000; A file handle is created ? JNZ WFB_WRITE ;AN000;yes, skip create again. CALL CREATE_A_FILE ;AN000;create a file in the cur dir JC WFB_ERROR ;AN000;file creation error? WFB_WRITE: ;AN000; CALL WRITE_A_FILE;AN000; JC WFB_EXIT_A ;AN000;target file has been already deleted. CMP DS:CONTINUE_INFO, 0;AN000; ; $IF E,OR ;if continue_info = 0 or 3 JE $$LL40 ;AN000; CMP DS:CONTINUE_INFO, 3;AN000; ; $IF E JNE $$IF40 ;AN000; $$LL40: ;AN000; MOV BX, ES:T_HANDLE;AN000; CALL SET_FILE_DATE_TIME ;AN000;then set file's date, time PUSH DS ;AN005;SAVE THE BUFFER PTR PUSH ES ;AN005;WE NEED THE DATA PTR POP DS ;AN005;DS = THE DATA PTR CALL CLOSE_A_FILE ;AN000;and close the handle POP DS ;AN005;DS = THE BUFFER PTR AGAIN ;;;;;;; CALL RESTORE_FILENAME_FOUND ; SAR if filename_found has been changed, restore it for reset_s_archieve. AND ES:FILE_FLAG, RESET_CREATED ;AN000;and reset created_flag CALL INC_FILE_COUNT ;AN000;increase file count ; $ENDIF $$IF40: ;AN000; MOV AX, DS ;AN000; CMP ES:OLD_BUFFER_PTR, AX ;AN000;current header is the last one? JE WFB_EXIT_A ;AN000;then exit MOV DS, DS:NEXT_PTR ;AN000;else set ds to the next ptr JMP WFB_CHATT ;AN000;handle the next header WFB_ERROR: ;AN000; jmp main_exit ;AN000;meaningful when MKDIR failed because ;of there already exist same named file, ;or disk_full case. WFB_EXIT_A: ;AN000; test ES:option_flag, slash_m ;AN000;hard archieve ? - turn off source archieve bit. jz wfb_exit_B ;AN000;no, chk error flag and exit ;;;; call reset_s_archieve ; SAR reset source file(s) archieve bit using header info(s). WFB_EXIT_B: ;AN000; test ES:copy_status, mkdir_error_flag ;AN000;mkdir error happened? JNZ WFB_ERROR ;AN000;yes, exit test ES:copy_status, disk_full_flag ;AN000;disk full happened? JNZ WFB_ERROR ;AN000;yes, exit WFB_EXIT: ;AN000; MOV ES:OLD_BUFFER_PTR, CS ;AN000;set old_buffer_ptr to CS MOV AX, ES:BUFFER_BASE ;AN000; MOV ES:BUFFER_PTR, AX ;AN000;set buffer_ptr to base MOV AX, ES:MAX_BUFFER_SIZE;AN000; MOV ES:BUFFER_LEFT, AX ;AN000;set buffer_left POP ES ;AN000; POP DS ;AN000; ;;;; TEST SYS_FLAG, ONE_DISK_COPY_FLAG ; SAR one drive letter copy? ; ; $IF NZ ; SAR yes ; ; CALL CHANGE_S_DIR ; SAR then change current dir to s dir ;;;; $ENDIF RET ;AN000; WRITE_FROM_BUFFER ENDP ;AN000; ; INC_FILE_COUNT PROC NEAR;AN000; ;increase the file count by one. ;increase file_cnt_low, file_cnt_high. ;input: DS - buffer ; ES - data seg INC ES:FILE_CNT_LOW ;AN000; JNZ IFC_EXIT ;AN000; INC ES:FILE_CNT_HIGH ;AN000;if carry over, then inc file_cnt_high IFC_EXIT: ;AN000; RET ;AN000; INC_FILE_COUNT ENDP ;AN000; ; CREATE_A_FILE PROC NEAR;AN000; ;create a file in the header and return the file handle in T_HANDLE. ;Set CREATED_FLAG. This will be reset by WRITE_FROM_BUFFER when it ;close the handle. ;this routine will check the T_FILENAME and T_TEMPLATE if any target ;filename has been entered. If T_FILENAME is there, then DX will ;points to this (This is the case when the user has specified non_global ;chr filename and any source filename be changed to this name.) ;If T_TEMPLATE is present, then modify the filename found in the ;header part. ;Also, this routine show copy messages just before a file creation using ;FILENAME_FOUND. ;ES - data seg ;DS - buffer seg PUSH DS ;AN000; PUSH ES ;AN000; ;  SAR  ;save the original filename from the header ;;;;; MOV CX, 13 ;max 13 chr ; LEA SI, DS:FILENAME_FOUND ;original source file name ; LEA DI, ES:DISP_S_FILE ;filename to be displayed ; REP MOVSB ;filename_found => disp_s_file ;;;;; test es:option_flag, slash_p ; SAR ;;;;; $IF Z ; SAR ;;;;; CALL SHOW_COPY_MESSAGE ; SAR he source path, file ;;;;; $ENDIF ; SAR ; ; CMP ES:T_FILENAME, 0 ; $IF NE ;non_global target filename entered. ; TEST ES:COPY_STATUS, MAYBE_ITSELF_FLAG ; $IF NZ ; LEA SI, DS:FILENAME_FOUND ; LEA DI, ES:T_FILENAME ; CALL COMP_FILENAME ;compare it. if same then show ; ;file cannot be copied onto itself and ; ;abort ; $ENDIF ; ; CALL SWITCH_DS_ES ;now ds - data, es - buffer ; MOV CX, 13 ; LEA SI, DS:T_FILENAME ; LEA DI, ES:FILENAME_FOUND ; REP MOVSB ; t_filename => filename_found ; CALL SWITCH_DS_ES ;now ds - buffer, es - data seg ; ; $ELSE ; CMP ES:T_TEMPLATE, 0 ;global chr target filename entered? ; $IF NE ;yes, entered. modify the filename found ;;;;; CALL MODIFY_FILENAME ; SAR ; TEST ES:COPY_STATUS, MAYBE_ITSELF_FLAG ; $IF NZ ; LEA SI, DS:FILENAME_FOUND ;compare the Revised filename ; LEA DI, ES:DISP_S_FILE ;with original name ; CALL COMP_FILENAME ;if same, then issue error message and exit ; $ENDIF ; $ELSE ; TEST ES:COPY_STATUS, MAYBE_ITSELF_FLAG ;*.* CASE ; $IF NZ ; PUSH ES ; POP DS ;ds - data seg ; ; ; Set message parameters ;;;;; MOV AX,MSG_COPY_ITSELF ; SAR ; MOV MSG_NUM,AX ; SAR ;AN000; set message number ; MOV SUBST_COUNT,0 ; SAR AN000; no message subst. ; MOV MSG_CLASS,-1 ; SAR AN000; message class ; MOV INPUT_FLAG,0 ; SAR AN000; no user input ; CALL PRINT_STDERR ; SAR AN000; display error ; JMP MAIN_EXIT ; $ENDIF ; $ENDIF ;;;;;; $ENDIF ;------------------------------------------------------------------------- ; Use extended open DOS call to create the target file, use attribute list ; obtained from the previous Get Extended attribute DOS call ;------------------------------------------------------------------------- ; SET ATTRIBUTE LIST POINTER IN PARAMETER LIST MOV DX, OFFSET DS:ATTRIB_LIST ;AN005;E A BUFFER IN HEADER MOV WORD PTR ES:E_A_LST,DX ;AN005; set offset MOV WORD PTR ES:E_A_LST+WORD,DS ;AN005; set segment MOV AX, Ext_Open ;AN000; = 6Ch MOV DX,CREATE_FLAG ;AN000; flag = 0111H MOV BX,CREATE_MODE ;AN000;CREATE MODE = 0011H MOV CX,CREATE_ATTR ;AN000; attribute = 0 MOV SI,OFFSET TARGET_DRV_LET ;AN005; DS:SI-->NAME TO CREATE LEA DI,ES:PARAM_LIST ;AN005;PARAMETER LIST (ES:DI) INT 21H ;AN000; create file JC CAF_ERROR ;AN000; MOV ES:T_HANDLE, AX ;AN000;save handle ;;;;; CALL CHK_T_RES_DEVICE ; SAR check target handle is a reserved dev OR ES:FILE_FLAG, CREATED_FLAG ;AN000;set created_flag JMP CAF_EXIT ;AN000; CAF_ERROR: ;AN000; PUSH DS ;AN000; PUSH ES ;AN000; POP DS ;AN000; OR COPY_STATUS, CREATE_ERROR_FLAG;AN000; CALL EXTENDED_ERROR_HANDLER ;AN000; POP DS ;AN000; CAF_EXIT: ;AN000; POP ES ;AN000; POP DS ;AN000; RET ;AN000; CREATE_A_FILE ENDP ;AN000; ; ;COMP_FILENAME PROC NEAR ;;this routine is called when MAYBE_COPY_ITSELF flag in on. ;;SI, DI asciiz string will be compared and if they are identical ;;the show "Cannot copy onto itself" msg and jmp to main_exit. ;;INPUT: DS - buffer ;; ES - data seg ; ; CLD ; MOV AL, 0 ; PUSH DI ;save DI ; CALL STRING_LENGTH ;CX get the length of string ; MOV BX, CX ;now, BX got the length of the target filename entered. ; PUSH BX ;save BX ; PUSH ES ;save ES ; ; PUSH DS ; POP ES ;now ES set to DS ; PUSH SI ; POP DI ;now DI points to the source filename found. ; ; MOV AL, 0 ; CALL STRING_LENGTH ;CX got the length of the string ; ; POP ES ;restore ES ; POP BX ;restore BX ; POP DI ;restore DI ; ;; ; CMP BX, CX ;COMPARE LENGTH ; JNE CF_EXIT ;IF THEY ARE DIFFERENT, EXIT ; ; REPE CMPSB ;compare SI, DI until not equal, ; CMP CX, 0 ;finish at cx = 0? ; JE CF_SAME ; JMP SHORT CF_EXIT ;CF_SAME: ; PUSH ES ; POP DS ;ds = data seg ; ;; Set message parameters ;;;;;; MOV AX,MSG_COPY_ITSELF ; SAR ;AN000; message number ;; MOV MSG_NUM,AX ; SAR AN000; set message number ;; MOV SUBST_COUNT,0 ; SAR AN000; no message substitution ;; MOV MSG_CLASS,-1 ; SAR AN000; message class ;;; MOV INPUT_FLAG,0 ; SAR AN000; no input ;; CALL PRINT_STDERR ; SAR AN000; display error message ; JMP MAIN_EXIT ;CF_EXIT: ; RET ;COMP_FILENAME ENDP ;; WRITE_A_FILE PROC NEAR ;AN000; ;write a file from the data area in the buffer. ;Remember the caller is WRITE_FROM_BUFFER which use ES for ;the program data area and DS for the header in the buffer. MOV AH, Write ;AN000; = 40h MOV BX, ES:T_HANDLE ;AN000;handle saved in the program data area MOV DX, ES:BYTS_OF_HDR ;AC005;skip header MOV CX, DS:CX_BYTES ;AN000;get the # from the header INT 21h ;AN000; JC WAF_ERROR ;AN000;write error CMP AX, DS:CX_BYTES;AN000; JNE WAF_DISKFULL;AN000; JMP WAF_EXIT ;AN000; WAF_ERROR: ;AN000; CALL CLOSE_DELETE_FILE ;AN000;close delete troubled file OR COPY_STATUS, WRITE_ERROR_FLAG;AN000; CALL SWITCH_DS_ES ;AN000;DS = DATA SEG, ES = BUFFER CALL EXTENDED_ERROR_HANDLER;AN000; CALL SWITCH_DS_ES ;AN000;ES = DATA SEG, DS = BUFFER WAF_DISKFULL: ;AN000; ; MOV ERRORLEVEL, 4 ; SAR ;set errorlevel ; Set message parameters ; Target disk full, critical error PUSH DS ;AN000;DS = BUFFER PUSH ES ;AN000;ES = DATA SEG POP DS ;AN000;ES => DS = DATA SEG ;;;;; MOV AX,MSG_DISK_FULL ; SAR ;AN000; message number ; MOV MSG_NUM,AX ; SAR AN000; set message number ; MOV SUBST_COUNT,0 ; SAR AN000; no message substitution ; MOV MSG_CLASS,UTILITY_MSG_CLASS ; SAR AN000; message class ; MOV INPUT_FLAG,0 ; SAR AN000; no input ; CALL PRINT_STDERR ; SAR AN000; display error message OR COPY_STATUS, DISK_FULL_FLAG ;AN000;set disk_full_flag POP DS ;AN000;RESTORE DS = BUFFER CALL CLOSE_DELETE_FILE;AN000; STC ;AN000;set carry and return to caller WAF_EXIT:;AN000; RET ;AN000; WRITE_A_FILE ENDP;AN000; ; SET_FILE_DATE_TIME PROC NEAR;AN000; ;input: BX - target file handle ; MOV AH, File_date_time ;AN000; = 57h MOV AL, Set_file_time ;AN000; = 1 MOV CX, DS:FILE_TIME_FOUND;AN000; MOV DX, DS:FILE_DATE_FOUND;AN000; INT 21h ;AN000; RET ;AN000; SET_FILE_DATE_TIME ENDP;AN000; ; CLOSE_A_FILE PROC NEAR ;AN000; ;INPUT: BX - file handle to be closed CMP OPEN_FILE_COUNT,NUL ;AN005;ARE THERE ANY OPEN FILES? ; $IF A ;AN005; JNA $$IF42A ;AN000; DEC OPEN_FILE_COUNT ;AN005;IF SO, REDUCE THE COUNT BY 1. ; $ENDIF ;AN005; $$IF42A: ;AN000; MOV AH, Close ;AN000; = 3Eh INT 21H ;AN000; RET ;AN000; CLOSE_A_FILE ENDP ;AN000; ; DELETE_A_FILE PROC NEAR;AN000; ;input: DS:DX - points to ASCIIZ string MOV AH, 41h ;AN000; = 41h INT 21H ;AN000; RET ;AN000; DELETE_A_FILE ENDP;AN000; ; ; ;CHK_DISK_FULL PROC NEAR ;check target disk space, and if no more clusters then set carry, disk_full_flag. ;this routine is called by MAKE_DIR routine. ;INPUT: DS - buffer ; ES - data seg ; PUSH AX ; PUSH BX ; PUSH CX ; PUSH DX ; MOV AH, 36h ;GET DISK FREE SPACE ; MOV DL, ES:T_DRV_NUMBER ;OF TARGET ; INT 21h ; CMP BX, 0 ;NO MORE CLUSTER? ; JE CDF_FULL ; CLC ; JMP SHORT CDF_EXIT ;CDF_FULL: ; OR ES:COPY_STATUS, DISK_FULL_FLAG ;SET DISK FULL FLAG ; STC ;SET CARRY ;CDF_EXIT: ; POP DX ; POP CX ; POP BX ; POP AX ; RET ; ;CHK_DISK_FULL ENDP ;; ;;subttl string_length ;page ;****************************************************************************** ;PURPOSE: Get the length of a string pointed by ES:DI until it encounters ; the same character given by the user in AL. ; The length will be an output in CX. The number includes the ; charater found. ; For example, if you want to determine the length of an ASCIIZ string, ; set ES:DI to that string and set AL to 0. The output CX is the ; total length of the ASCIIZ string including 0. ; So, if the first character pointed by DI is the same as that of AL, ; then the length will be 1. ; !!! It is the user's responsibility to make it sure that the string ; contains the character given in AL. If not, unpredictable ; results will occur.!!! ; ; DATA INPUT ; REGISTERS: AL - ASCII CHARACTER ; ES:DI - POINTER TO THE STRING. ; DATA OUTPUT ; REGISTERS: AX,DX,SI etc - PRESERVED. ; BX - DISTROYED ; CX - STRING LENGTH UNTIL FOUND THE GIVEN CHARACTER. ; DI - POINTS TO THE NEXT CHARACTER AFTER THE STRING. ; DIRECTION FLAG - CLEARED ; ZERO FLAG - RESET ;****************************************************************************** ; ;STRING_LENGTH PROC NEAR ;PUBLIC STRING_LENGTH ; CLD ;CLEAR DIRECTION ; MOV BX,DI ;SAVE ORIGINAL DI VALUE ; MOV CX,80H ;TRY MAX 128 BYTES ; REPNE SCASB ;SCAN THE STRING UNTIL FOUND ; PUSH DI ;SAVE CURRENT DI VALUE WHICH POINTS TO NEXT CHR AFTER STRING ; SUB DI,BX ;GET THE LENGTH ; MOV CX,DI ;MOV THE LENGTH TO CX ; POP DI ; RET ;STRING_LENGTH ENDP ; ;subttl concat_asciiz ;page ;****************************************************************************** ;PURPOSE: Concatenate two ASCIIZ string into one ASCIIZ string. ; The ASCIIZ string pointed by DS:SI will be concatenated to ; the one pointed by ES:DI. The result string will be pointed by ; ES:DI. ; AL is used to put the delimeter character in between the strings. ; If you *DON'T* like to put the delimeter ***make AL to 0FFh***. ; For example, assume sting1 "ABCDE",0 pointed by DI and string2 ; "FGHI",0 pointed by SI. ; If you want a delimeter "\" between two string, set AL to "\" ; before calling. The result will "ABCDE\FGHI",0 pointed by DI. ; If you set AL to "0FFh", then it becomes "ABCDEFGHI",0. ; This feature is useful for handling PATH if you set AL to "\" ; and, for any general string processes if you set AL to "0FFh". ; This routine will call subroutine STRING_LENGTH. ;DATA INPUT ; REGISTERS: AL - DELIMETER OR 0FFh ; ES:DI - POINTER TO THE DESTINATION STRING. ; DS:SI - POINTER TO THE SOURCE TO BE CONCATENATED. ;DATA OUTPUT ; REGISTERS: AL, DX - preserved ; DI - preserved. POINTER TO THE RESULT STRING ; SI - DISTROYED ; CX - RESULT ASCIIZ STRING LENGTH INCLUDE 0 ; DIRECTION FLAG - CLEARED ;****************************************************************************** ;CONCAT_ASCIIZ PROC NEAR ; ;PUBLIC CONCAT_ASCIIZ ; PUSH DI ;SAVE POINTER VALUE WHICH WILL BE RETRUNED TO CALLER. ; PUSH AX ;SAVE VALUE IN AL. ; MOV AL, 0 ;DEALING WITH ASCIIZ STRING ; CALL STRING_LENGTH ;LET DI POINTS TO THE NEXT CHR AFTER THIS STRING ; ;DIRECTION WILL BE CLEARED. ; DEC DI ;MAKE DI POINT TO THE LAST CHARACTER 0 ; POP AX ;RESTORE AL. ; CMP AL, 0FFh ;; $IF NE ;IF THE USER WANTS TO PUT DIMIMETER, ; JE $$IF42 ; STOSB ; REPLACE 0 WITH IT. ;; $ELSE ; JMP SHORT $$EN42 ;$$IF42: ; DEC CX ;ELSE DECREASE LENGTH BY 1 ;; $ENDIF ;$$EN42: ;; $DO ;$$DO45: ; LODSB ;MOV [SI] TO AL ; STOSB ;STORE AL TO [DI] ; INC CX ;INCREASE LENGTH ; CMP AL, 0 ;WAS IT A LAST CHARACTER? ;; $ENDDO E ;THEN EXIT THIS LOOP ; JNE $$DO45 ; POP DI ; RET ;CONCAT_ASCIIZ ENDP ;; ; ;subttl last_dir_out ;page ;****************************************************************************** ;PURPOSE: Take off the last directory name from the path pointed by DI. ; This routine assumes the pattern of a path to be an ASCIIZ string ; in the form of "[d:][\]dir1\dir2". Notice that this path does not ; have entailing "\". This routine will simply travel the string ; until it found last "\" which will, then, be replaced with 0. ; If no "\" found, then carry will be set. ; *** This should be not be used for the path in the form of ; *** "d:\", 0 for the root directory, since in this case the returned ; *** string will be "d:",0 and AX value returned be meaningless (Just ; *** points to 0.) ;DATA INPUT ; REGISTERS: DI - points to an ASCIIZ path string. ; ES - assumed default segment for DI ;DATA OUTPUT ; REGISTERS: DI - points to the resultant path string. ; AX - offset value of the last subdirectory name taken out, in case ; of the user's need. ; Other register will be unchanged. ; CARRY FLAG WILL SET IF NOT FOUND. ;****************************************************************************** ; ;LAST_DIR_OUT PROC NEAR ;PUBLIC LAST_DIR_OUT ; ; PUSH DI ; PUSH SI ;save current DI, SI ; CLD ;clear direction ; MOV SI, 0FFFFh ;used as a not_found flag if unchanged. ;; $DO ;$$DO47: ; MOV AL, 0 ; SCASB ;; $LEAVE Z ;if [DI] = 0, then end of string. Ends this loop. ; JZ $$EN47 ; DEC DI ;if [DI] <> 0, then go back and scan char again ; MOV AL, "\" ;to see it was a back slash. ; SCASB ;; $IF Z ;if it was, then save the addr to SI. ; JNZ $$IF49 ; PUSH DI ; POP SI ; ; DEC SI ;; $ENDIF ;else do loop again. ;$$IF49: ;; $ENDDO ; JMP SHORT $$DO47 ;$$EN47: ; CLC ;clear carry flag. ; CMP SI, 0FFFFh ;Had SI been changed? ;; $IF E ; JNE $$IF52 ; STC ;No, set the carry. Not found. ;; $ELSE ; JMP SHORT $$EN52 ;$$IF52: ; MOV BYTE PTR ES:[SI], 0 ;Yes, replace "\" with 0. Seg override to get default DI seg. ; MOV AX, SI ; INC AX ;let AX have the last dir offset value. ; CLC ;clear carry ;; $ENDIF ;$$EN52: ; POP SI ;restore original value ; POP DI ;original string offset ; RET ;LAST_DIR_OUT ENDP ;; ; SET_DEFAULT_DRV PROC NEAR;AN000; ;change source drv as a default drv for conveniece of find, read operation ;of source. (handling target should be more specific as for as drive letter ;goes.) ;input: DL - drive # (0 = A, 1 = B ...) MOV AH, Select_Disk ;AN000; = 0Eh INT 21H ;AN000; OR SYS_FLAG, DEFAULT_DRV_SET_FLAG ;AN000;indicates default drv has been changed ;Used for exit the program to restore default drv RET ;AN000; SET_DEFAULT_DRV ENDP ;AN000; ; ORG_S_DEF PROC NEAR ;AN000; ;restore the original source directory. PUSH ES ;AN000; PUSH DS ;AN000; PUSH DS ;AN000; POP ES ;AN000;DS=ES=data seg TEST SYS_FLAG, DEFAULT_S_DIR_FLAG ;AN000;source default direcotry saved? ; $IF NZ JZ $$IF55 ;AN000; MOV DX, OFFSET SAV_S_DRV ;AN000;saved source drive letter & directory MOV AH, 3Bh ;AN000; INT 21h ;AN000;restore source AND SYS_FLAG, RESET_DEFAULT_S_DIR ;AN000;reset the flag ; $ENDIF $$IF55: ;AN000; POP DS ;AN000; POP ES ;AN000; RET ;AN000; ORG_S_DEF ENDP ;AN000; ; ORG_S_T_DEF PROC NEAR ;AN000; ;retore original target, source and default drv and directory ;check default_s(t)_dir_flag, default_drv_set_flag to restore source, ;or target directory and default drive. TEST SYS_FLAG, TURN_VERIFY_OFF_FLAG ;AN000;turn off verify? ; $IF NZ ;yes JZ $$IF57 ;AN000; MOV AX, 2E00h ;AN000;turn it off INT 21H ;AN000; ; $ENDIF $$IF57: ;AN000; TEST SYS_FLAG, DEFAULT_DRV_SET_FLAG ;AN000;default drive has been changed? ; $IF NZ ;yes JZ $$IF59 ;AN000; MOV DL, SAV_DEFAULT_DRV ;AN000; DEC DL ;AN000; CALL SET_DEFAULT_DRV ;AN000;restore default drv. ; Following is a fix for PTR 0000012 . The fix is to skip changing default ; drive directory if source drive is not the default drive. MOV AL, S_DRV_NUMBER ;AN002; get source drive number CMP AL, SAV_DEFAULT_DRV ;AN002; src drive is the default drv ? JNE SKIP_CH_DIR ;AN002; no, dont change directory MOV DX, OFFSET SAV_DEF_DIR_ROOT;AN000; MOV AH, Chdir ;AN000; INT 21H ;AN000;restore current dir of default dir SKIP_CH_DIR: ;AN000; ; $ENDIF $$IF59: ;AN000; TEST SYS_FLAG, DEFAULT_S_DIR_FLAG ;AN000;source default direcotry saved? ; $IF NZ JZ $$IF61 ;AN000; MOV DX, OFFSET SAV_S_DRV ;AN000;saved source drive letter & directory MOV AH, 3Bh ;AN000; INT 21h ;AN000;restore source. This is for the case of ERROR exit. ; $ENDIF $$IF61: ;AN000; TEST SYS_FLAG, DEFAULT_T_DIR_FLAG ;AN000;target default directory saved? ; $IF NZ ;then assume both source, target default saved JZ $$IF63 ;AN000; MOV DX, OFFSET SAV_T_DRV ;AN000;saved target drive letter & directory MOV AH, 3Bh ;AN000; INT 21h ;AN000;restore target ; $ENDIF $$IF63: ;AN000; RET ;AN000; ORG_S_T_DEF ENDP ;AN000; ; EXTENDED_ERROR_HANDLER PROC NEAR;AN000; ;This routine calls fun 59(Get extended error) and ;check the actions returned. If it is Immediate exit, then jmp to JUST_EXIT ;If it is abort, then jmp to MAIN_EXIT. ;Or else, it check the COPY_STATUS flag. If is not open, read, create or ;write, then it is considered as a critical error and jmp to MAIN_EXIT. ;If access denied ; too many open files ; sharing violation ; lock violation ; general failure ;then show the message and jmp to the MAIN_EXIT. ; *** Currently, this routine directly jump to the main_exit instead of ; *** returing to the caller. The reason is we regard the above error conditions ; *** as being not suitable to continue copying and, hence, to simplify ; *** the error process. ;INPUT: ; DS - DATA SEG ;OUTPUT: ; ALL THE REG PRESERVED GOTO_MAIN_EXIT: ;AN000; JMP MAIN_EXIT ;AN000;restore conditions ;and exit QUICK_EXIT: ;AN000; JMP JUST_EXIT ;AN000;immediate exit RET ;AN000; EXTENDED_ERROR_HANDLER ENDP;AN000; ; CLOSE_DELETE_FILE PROC NEAR;AN000; ;when writing error occurs, then this routine is called to ;clean up the troubled target file. ;INPUT: DS - buffer seg ; ES - data seg MOV BX, ES:T_HANDLE ;AN000;close target file PUSH DS ;AN005;SAVE THE BUFFER PTR PUSH ES ;AN005;WE NEED THE DATA PTR POP DS ;AN005;DS = THE DATA PTR CALL CLOSE_A_FILE;AN000; POP DS ;AN005;DS = THE BUFFER PTR AGAIN LEA DX, DS:target_drv_let ;AN000;target drv, filename CALL DELETE_A_FILE ;AN000;delete it RET ;AN000; CLOSE_DELETE_FILE ENDP;AN000; ; ; SWITCH_DS_ES PROC NEAR;AN000; ; switch DS, ES PUSH DS ;AN000; PUSH ES ;AN000; POP DS ;AN000; POP ES ;AN000; RET ;AN000; SWITCH_DS_ES ENDP ;AN000; ; ; INIT PROC NEAR ;AN000; CALL GET_CUR_DRV ;AN000;save current default drv MOV DL, SAV_DEFAULT_DRV;AN000; LEA SI, SAV_DEFAULT_DIR;AN000; CALL GET_CUR_DIR ;AN000;save current default dir CALL GET_DRIVES ;AN000; SAR CALL TOP_OF_MEM ;AN000;set top_of_memory CALL INIT_BUFFER ;AN000;init buffer information MOV DL, T_DRV_NUMBER ;AN000; SAR .IF < DL AE 3 > ;AN000; SAR LEA SI, SAV_T_CURDIR ;AN000; SAR CALL GET_CUR_DIR ;AN000; SAR OR SYS_FLAG, DEFAULT_T_DIR_FLAG ;AN000; SAR .ELSE ;AN000; SAR AND SYS_FLAG, NOT DEFAULT_T_DIR_FLAG ;AN000; SAR .ENDIF ;AN000; SAR MOV DL, S_DRV_NUMBER;AN000; DEC DL ;AN000; CALL SET_DEFAULT_DRV ;AN000;set source as a default drv CLC ;AN000; RET ;AN000; INIT ENDP ;AN000; ; GET_DRIVES PROC NEAR ;AN000; ;get source and target phisical drive letter from parser area. ;set ONE_DISK_COPY_FLAG, if the user XCOPY using the same drive letter. ;;;;; MOV AL, SO_DRIVE ;AN000;source drive letter ; CMP AL,SPACE ;AN000;IS DRIVE LETTER BLANK? ; $IF E ;AN000;YES, GET THE DEFAULT ; MOV AL, SAV_DEFAULT_DRV ;(1=A, 2=B,...) ; $ELSE ;AN000;NO, CHANGE FROM CHAR TO # ; SUB AL,BASE_OF_ALPHA_DRV ;AN000;NEED THE DRV # HERE ; $ENDIF MOV AL, 1 ;AN000; SAR A is the source drive MOV S_DRV_NUMBER, AL ;AN000;SAVE DRV # ADD AL, BASE_OF_ALPHA_DRV;AN000; MOV S_DRV, AL ;AN000;save source drive letter MOV S_DRV_1, AL;AN000; ;; MOV S_ARC_DRV, AL ; SAR MOV SAV_S_DRV, AL;AN000; .IF < DEST eq 3 > ;AN111;JW MOV AL,0 ;AN111;JW .ELSE ;AN111;JW MOV AL, DEST ;AN000; SAR target drive letter .ENDIF ;AN111;JW INC AL ;AN000; SAR ;;;;; CMP AL,SPACE ;AN000;IS DRIVE LETTER BLANK? ; ; $IF E ;AN000;YES, GET THE DEFAULT ; ; MOV AL, SAV_DEFAULT_DRV ;(1=A, 2=B,...) ; ; $ELSE ;AN000;NO, CHANGE FROM CHAR TO # ; ; SUB AL,BASE_OF_ALPHA_DRV ;AN000;NEED THE DRV # HERE ;;;;; $ENDIF MOV T_DRV_NUMBER, AL ;AN000;save target drv # ;;;;; CMP S_DRV_NUMBER, AL ;s_drv_number = t_drv_number? ; ; $IF E ; ; OR SYS_FLAG, ONE_DISK_COPY_FLAG ;same logical drv copy ;;;;; $ENDIF ADD AL, BASE_OF_ALPHA_DRV ;AN000;make target drv # to drive letter MOV T_DRV, AL ;AN000;target drive letter ;; MOV T_DRV_1, AL ; SAR ;; MOV T_DRV_2, AL ; SAR MOV SAV_T_DRV, AL;AN000; RET ;AN000; GET_DRIVES ENDP ;AN000; ; GET_CUR_DRV PROC NEAR;AN000; ;get the current default drive number (0 = A, 1 = B ..), ;change it to BIOS drive number and save it. MOV AH, Current_Disk ;AN000; = 19h INT 21h ;AN000; INC AL ;AN000;(1 = A, 2 = B ..) MOV SAV_DEFAULT_DRV, AL ;AN000;save it RET ;AN000; GET_CUR_DRV ENDP ;AN000; ; GET_CUR_DIR PROC NEAR ;AN000; ;get current directory and save it ;input: DL - drive # (0 = default, 1 = A etc) ; DS:SI - pointer to 64 byte user memory MOV AH, Get_Current_Directory;AN000; INT 21H ;AN000; RET ;AN000; GET_CUR_DIR ENDP ;AN000; ; TOP_OF_MEM PROC NEAR ;AN000; ;set Top_of_memory PUSH ES ;AN000; MOV BX, PSP_SEG ;AN000; MOV ES, BX ;AN000; MOV AX, ES:2 ;AN000;PSP top of memory location SUB AX, 100H ;AN000;subtract dos transient area (4k) MOV TOP_OF_MEMORY, AX ;AN000;save it for buffer top POP ES ;AN000; RET ;AN000; TOP_OF_MEM ENDP ;AN000; INIT_BUFFER PROC NEAR ;AN000; ;initialize buffer information ;set buffer_base, max_buffer_size ; call set_block ;SET BLOCK FOR BUFFR (for new 3.2 linker) MOV AX, 0 ;AN000; SAR ;;;; PUSH CS ; SAR cs segment is the highest segment in this program ;;;; POP DX ; SAR MOV DX, ALLOCATE_START ;AN000; SAR MOV BUFFER_PTR, DX ;AN000; CALL SET_BUFFER_PTR ;AN000; MOV AX, BUFFER_PTR ;AN000; MOV BUFFER_BASE, AX ;AN000;set buffer_base MOV AX, BUFFER_LEFT ;AN000; CMP AX, 140h ;AN000;BUFFER_LEFT < 5K which is the minimum size this program supports? JAE IB_CONT ;AN000; ;;;;;; PUSH AX ; SAR ;AN000; ; MOV AX, MSG_INSUF_MEMORY ; SAR ;AC000;GET THE MESSAGE ID ; MOV MSG_NUM,AX ; SAR ;AN000;NEED MESSAGE ID FOR PRINT ; MOV SUBST_COUNT,NUL ; SAR ;AN000;NO SUBSTITUTION TEXT ; MOV INPUT_FLAG,NUL ; SAR ;AN000;NO INPUT = 0 ; MOV MSG_CLASS,UTILITY_MSG_CLASS ; SAR ;AN000;MESSAGE CLASS = -1 ; CALL PRINT_STDERR ; SAR ;print error. AX points to message ID ; POP AX ; SAR ;AN000; ; MOV ERRORLEVEL, 4 ; SAR ;abnormal termination JMP MAIN_EXIT_A ;AN000;terminate this program IB_CONT: ;AN000; MOV MAX_BUFFER_SIZE, AX ;AN000;set max buffer size in para CMP AX, 0FFFh ;AN000;max_buffer_size > 64 K in para ? ; $IF B JNB $$IF65 ;AN000; MOV CX, 16;AN000; MUL CX ;AN000;AX = AX * 16 (DX part will be 0) SUB AX, 544 ;AN000;AN000;subtrack header size MOV MAX_CX, AX ;AN000;this will be max_cx ; $ELSE JMP SHORT $$EN65 ;AN000; $$IF65: ;AN000; MOV MAX_CX, 0FFD0h ;AN000;else max_cx = fff0 - 32 bytes ;which is the max # this program can support. ; $ENDIF ;(min # this program support for buffer is 5 k $$EN65: ;AN000; ; which has been decided by BIG_FILE ) RET ;AN000; INIT_BUFFER ENDP ;AN000; SELECT ENDS ;AN000; END ;AN000;