2 TITLE XCOPY WITH FULL MEMORY USE
- Ver
. 4.00
4 ;****************** START OF SPECIFICATIONS *****************************
7 ; DESCRIPTIVE NAME: selectively copy groups of files, which can include
8 ; lower level subdirectories.
10 ; FUNCTION: The modules of XCOPY will be placed in the following order -
11 ; SSEG, DSEG(MAIN DATA, MAIN MSG), CSEG (MAIN + INIT),
12 ; DSEG_INIT(INIT DATA, INIT MSG)
14 ; HEADER - informations needed about the file, subdirectory ...
15 ; Continue_Info -> 0 - a whole single file in this header
17 ; 1 - Continuation of a small file.
18 ; 2 - Continuation of a Big file
19 ; 3 - Eof of continuation
20 ; Next_Ptr -> points to the next header segment
21 ; Before_Ptr -> points to the old header segment
23 ; By optionally using the Archive bit in the directory of each
24 ; file, XCOPY can be used as an alternative method of creating
25 ; backup files which can be accessed directly by DOS and its
26 ; applications without the need to "restore" the backup files.
28 ; XCOPY is especially useful when several files are being copied
29 ; and there is a generous amount of RAM available, because XCOPY
30 ; will fill the memory with all the source files it can read in
31 ; before starting to create output files. If the memory is not
32 ; enough to hold all the source, this cycle will be repeated until
33 ; the process is completed. For single drive systems, this maximum
34 ; usage of the memory greatly reduces the amount of diskette
35 ; swapping that would be required by the usual COPY command.
39 ; INPUT: (DOS COMMAND LINE PARAMETERS)
41 ; SOURCE OPERAND: TARGET OPERAND:
43 ; [d:] [path] filename[.ext] [d:] [path] [filename[.ext]]
45 ; [d:] path [filename[.ext]]
47 ; d: [path] [filename[.ext]]
52 ; /A /D /E /M /P /S /V /W
54 ;The /A switch will copy only those files whose archive bit of the attribute is
55 ;set to one. The attribute of the source file is not changed. This option is
56 ;useful when making multiple backups when doing the non-final backup.
57 ;The archive bit is one when a file has be created or Revised since the last
58 ;time the bit was turned off. XCOPY /M or BACKUP /M will turn this bit off.
59 ;The ATTRIB command can also be used to change the setting of the archive bit.
61 ;The /D switch will copy only those files whose date is the same or later than
62 ;the date specified. Depending on the country code you selected using the
63 ;COUNTRY command, the date is specified in the format corresponding to the
66 ;The /E switch will create subdirectories on the target even if they end up
67 ;being empty after all copying is over. If /E is not specified, empty
68 ;subdirectories are not created.
70 ;The /M switch will copy only those files whose archive bit is set in its
71 ;attribute. Unlike the /A switch, /M will cause the archive bit in the source
72 ;file to be turned off. This allows XCOPY to be used in making a final backup.
73 ;The archive bit is one when a file has be created or Revised since the last
74 ;time the bit was turned off. XCOPY /M or BACKUP /M will turn this bit off.
75 ;The ATTRIB command can also be used to change the setting of the archive bit.
77 ;The /P switch will prompt the operator before copying each file. In this
78 ;situation, each file is copied onto the target before reading in the next
79 ;file. The multi-file copy into a large memory buffer is not done. The prompt
80 ;displays the complete filespec it proposes to copy and asks for (Y/N)
81 ;response, which is then read in from the standard input device.
83 ;The /S switch will not only copy the files in the current source directory but
84 ;also those in all the subdirectories below the current one, with XCOPY
85 ;following the Tree of the subdirectories to access these files. /S does not
86 ;create an empty subdirectory on the target (unless /E is also specified).
87 ;If the /S switch is not specified, XCOPY works only within the specified (or
88 ;current) subdirectory of the source.
90 ;The /V switch will cause DOS to verify that the sectors written on the target
91 ;are recorded properly. This option has been provided so you can verify that
92 ;critical data has been correctly recorded. This option will cause XCOPY to
93 ;run more slowly, due to the additional overhead of verification.
95 ;The /W switch will instruct XCOPY to pause before actually starting the
96 ;movement of data, thus permit the copying of diskettes that do not actually
97 ;have XCOPY available on them. The diskette containing XCOPY can be mounted
98 ;first, the XCOPY command given with the /W option, then when the prompt
99 ;requesting permission to continue is given, that diskette can then be removed
100 ;and the source diskette mounted in its place, then the operator can press any
101 ;key to continue after the pause. This feature is especially useful in a
102 ;non-hardfile system.
104 ; EXIT-NORMAL: ERRORLEVEL_0 - This is the normal completion code.
105 ; ERRORLEVEL_2 - This is due to termination via Control-Break.
106 ; ERRORLEVEL_4 - This is used to indicate an error condition.
108 ; There are many types of problems that are detected and result in this
109 ; return code, such as:
111 ; write failure due to hard disk error
113 ; conflict between name of new subdirectory and existing filename
115 ; too many open files
123 ; reserved file name as source
124 ; insufficient memory
125 ; incorrect DOS version
128 ; INTERNAL REFERENCES:
136 ; EXTERNAL REFERENCES:
144 ; NOTES: This module should be processed with the SALUT pre-processor
145 ; with the re-alignment not requested, as:
149 ; To assemble these modules, the sequential
150 ; ordering of segments may be used.
152 ; For LINK instructions:
153 ; link profile ..\lib
155 ; REVISION HISTORY: A000 Version 4.00: add PARSER, System Message Handler,
156 ; Remove the BELL char.,turn off APPEND during TREE
157 ; search,Extended Attribute processing, Uppercasing
158 ; and "Out Of Space" during write to standard out.
159 ; A001 PTM0011 XCOPY not handling path >63 characters.
160 ; CHK_MAX_LENGTH proc(XCPYINIT) is Revised to err if
162 ; A002 PTM0012 XCOPY unnecessarily accessing current drive.
163 ; ORG_S_T_DEF is Revised to ignore CHDIR if drive
164 ; is not TARGET or SOURCE.
165 ; A003 PTM0088 XCOPY (\) missing in 'FILE SHARING ERROR'.
166 ; This problem is fixed with incorporation of the
167 ; new message services.
168 ; A004 PTM0700 9/02/87 Avoid duplicate switches and
169 ; display parm in error.
170 ; A005 DCR0201 9/11/87 Incorperate new format for EXTENDED
172 ; A006 PTM1490 10/04/87 XCOPY /D CAUSES "INVALID PARAMETER"
173 ; MSG AND SHOULD BE "INVALID NUMBER OF PARAMETERS" ALSO
174 ; DATE IS NOT VALIDATED.
175 ; A007 PTM1657 10/14/87 XCOPY INVALIDLY FAILS TO READ A READ
176 ; ONLY FILE, AND OUTPUTS THE WRONG MSG.
177 ; A008 PTM1688 10/15/87 XCOPY NOT CREATING EMPTY SUBDIRS IF
178 ; THE SOURCE DIR. IS EMPTY.
179 ; A009 PTM2199 11/02/87 XCOPY NOT HANDELING FILENAMES GREATER
180 ; THAN 12 CHARACTERS.
181 ; A010 PTM2203 11/03/87 XCOPY NOT HANDELING DBCS PATH NAMES
182 ; PROPERLY. (INCORP. CHK. IF 1st BYTE IS DBCS)
183 ; A011 PTM2271 11/04/87 XCOPY NOT HANDELING FILENAMES GREATER
184 ; THAN 12 CHARACTERS.(S_FILE BUFFER OVERFLOWES).
185 ; A012 PTM2347 11/09/87 XCOPY SETTING THE CODE PAGE OF A DEV.
186 ; AND A DEV. IS NOT ALLOWED FOR A TARGET.
187 ; A013 PTM2565 11/17/87 XCOPY HANGS AUTOTEST. SET EXTENDED
188 ; ATTRIBUTE CALL TO DOS POINTS TO INVALID BUFFER.
189 ; A014 PTM2597 11/20/87 XCOPY REPORTS FILE CREATION ERROR
190 ; IF TARGET FILE IS GREATER THAN 12 CHARACTERS.
191 ; A015 PTM2782 12/04/87 XCOPY FILENAME (EXTENSION)
192 ; TRUNCATION ERROR. INCREASE HEADER BUFFER TO 3 PARA.
193 ; A016 PTM2783 12/09/87 XCOPY ALLOWS 'ASSIGN' DRIVES TO
194 ; BE COPIED ONTO THEMSELVS. ADD NEW CODE TO INIT.
195 ; A017 PTM3139 01/15/88 XCOPY HANGS WHEN TRYING TO OUTPUT
196 ; "INSUFFICIENT DISK SPACE" FOR MAKE DIRECTORY.
197 ; A018 PTM3283 02/01/88 XCOPY NEEDS TO CHANGE 'FILE NOT
198 ; FOUND' MSG TO EXTENDED ERROR MSG FORMAT. ALSO
199 ; DELETED DEF 28 IN XCOPY.SKL & XMAINMSG.EQU
200 ; A019 PTM3395 02/08/88 XCOPY FAILING TO SUSPEND THE
201 ; 'APPEND /X' FUNCTION. FIX IN XCOPY.SAL, XCOPY.EQU,
203 ; A020 PTM3344 02/09/88 XCOPY READING PAST TOP_OF_MEMORY,
204 ; OVER-WRITING VIDIO BUFFER SET BY MODE 13H ON PS2s.
205 ; A021 PTM3513 02/19/88 XCOPY READING PAST TOP_OF_MEMORY,
206 ; OVER-WRITING VIDIO BUFFER SET BY MODE 13H ON PS2s.
207 ; A022 PTM3933 03/18/88 XCOPY NOT RESTORING DIRECTORY OF
208 ; DEFAULT DRIVE. FIX IN XCOPY.SAL.
209 ; A023 PTM3904 03/18/88 XCOPY NOT USING PARSE 03 MSG. FOR
210 ; 'INVALID SWITCH'. FIX IN XCOPY.SKL & XCPYINIT.SAL.
211 ; A024 PTM3958 03/22/88 XCOPY MSGS DO NOT CONFORM TO SPEC.
212 ; NEED NULL DELIMITER IN XCPYINIT.SAL.
213 ; A025 PTM3965 03/23/88 XCOPY LEAVING CURRENT TARGET DIR.
214 ; CHANGED. FIX IN XCPYINIT.SAL.
215 ; A026 PTM4920 05/19/88 XCOPY NOT OVERLAYING FILES ON FULL
216 ; TARGET DISK. FIX IN XCOPY.SAL.
217 ; A027 PTM5022 06/03/88 'PATH TOO LONG' MSG. WITH TWO CHAR.
218 ; SOURCE SUBDIR. FILESPEC. FIX IN XCPYINIT.SAL.
220 ; Label: "The DOS XCOPY Utility"
221 ; "Version 4.00 (C) Copyright 1988 Microsoft"
222 ; "Licensed Material - Program Property of Microsoft"
224 ;****************** END OF SPECIFICATIONS *****************************
226 ;--------------------------------
228 ;--------------------------------
229 INCLUDE XMAINMSG
.EQU
;AN000;message file
230 INCLUDE DOS
.EQU
;AN000;
231 INCLUDE XCOPY
.EQU
;AN000;
233 INCLUDE SYSMSG
.INC ;AN000;
235 MSG_UTILNAME
<XCOPY
> ;AN000;
237 ;-------------------------------
239 ;-------------------------------
240 ;HEADER - informations needed about the file, subdirectory ...
241 ;Continue_Info -> 0 - a whole single file in this header segment, or dir.
242 ; 1 - Continuation of a small file.
243 ; 2 - Continuation of a Big file
244 ; 3 - EOF of continuation
245 ;Next_Ptr -> points to the next header segment
246 ;Before_Ptr -> points to the old header segment
249 CONTINUE_INFO
DB 0 ;set for filesize bigger then 0FFD0h
250 NEXT_PTR
DW ?
;next buffer ptr in para
251 BEFORE_PTR
DW ?
;before ptr in para
252 DIR_DEPTH
DB ?
;same as S_DEPTH
253 CX_BYTES
DW 0 ;actual # of bytes in this buffer seg.
254 ATTR_FOUND
DB ?
;attribute found
259 TARGET_DRV_LET
DB " :" ;used for writing
260 FILENAME_FOUND
DB 13 DUP (0) ;AC015; FILENAME
261 TERMINATE_STRING
DB 16 DUP (0) ;AC015;TERM FILENAME STRING FOR DOS
262 ATTRIB_LIST
DW ?
;AC005;EXTENDED ATTRIBUTE BUFFER
263 ;-------------------------------------------------------------------
264 ; extended attribute list used by extended open & get extended
265 ;-------------------------------------------------------------------
266 ; ATTRIB_LIST LABEL BYTE extended attribute buffer
268 ;EA STRUC ; EXTENDED ATTRIBUTE
270 ;EAISUNDEF EQU 0 ; UNDEFINED TYPE (ATTRIB SKIPS)
271 ; ; (OR TYPE NOT APPLICABLE)
272 ; ; LENGTH: 0 TO 64K-1 BYTES
273 ;EAISLOGICAL EQU 1 ; LOGICAL (0 OR 1) (ATTRIB DISPLAYS) ; LENGTH: 1 BYTE
274 ;EAISBINARY EQU 2 ; BINARY INTEGER (ATTRIB DISPLAYS)
275 ; ; LENGTH: 1, 2, 4 BYTES
276 ;EAISASCII EQU 3 ; ASCII TYPE (ATTRIB DISPLAYS)
277 ; ; LENGTH: 0 TO 128 BYTES
278 ;EAISDATE EQU 4 ; DOS FILE DATE FORMAT (ATTRIB DISPLAYS)
280 ;EAISTIME EQU 5 ; DOS FILE TIME FORMAT (ATTRIB DISPLAYS)
282 ; ; OTHER VALUES RESERVED
283 ;EA_FLAGS DW ? ; FLAGS
284 ;EASYSTEM EQU 8000H ; EA IS SYSTEM DEFINED
285 ; ; (BUILTIN, NOT APPLICATION DEFINED)
286 ;EAREADONLY EQU 4000H ; EA IS READ ONLY (CANT BE CHANGED)
287 ;EAHIDDEN EQU 2000H ; EA IS HIDDEN FROM ATTRIB
288 ;EACREATEONLY EQU 1000H ; EA IS SETABLE ONLY AT CREATE TIME
289 ; ; OTHER BITS RESERVED
290 ;EA_RC DB ? ; FAILURE REASON CODE (SET BY DOS)
291 ;EARCNOTFOUND EQU 1 ; NAME NOT FOUND
292 ;EARCNOSPACE EQU 2 ; NO SPACE TO HOLD NAME OR VALUE
293 ;EARCNOTNOW EQU 3 ; NAME CAN'T BE SET ON THIS FUNCTION
294 ;EARCNOTEVER EQU 4 ; NAME CAN'T BE SET
295 ;EARCUNDEF EQU 5 ; NAME KNOWN TO THIS FS BUT NOT SUPPORTED
296 ;EARCDEFBAD EQU 6 ; EA DEFINTION BAD (TYPE, LENGTH, ETC)
297 ;EARCACCESS EQU 7 ; EA ACCESS DENIED
298 ;EARCUNKNOWN EQU -1 ; UNDETERMINED CAUSE
299 ;EA_NAMELEN DB ? ; LENGTH OF NAME
300 ;EA_VALLEN DW ? ; LENGTH OF VALUE
301 ;EA_NAME DB ? ; FIRST BYTE OF NAME
303 ;EA_VALUE DB ? ; FIRST BYTE OF VALUE
310 DATA_OFF
DW 0 ;AN000; offset of data to be inserted
311 DATA_SEG
DW 0 ;AN000; offset of data to be inserted
312 MSG_ID
DB 0 ;AN000; n of %n
313 FLAGS
DB 0 ;AN000; Flags
314 MAX_WIDTH
DB 0 ;AN000; Maximum field width
315 MIN_WIDTH
DB 0 ;AN000; Minimum field width
316 PAD_CHAR
DB 0 ;AN000; character for pad field
323 ;******************************************************************************
324 SSEG
SEGMENT PARA
STACK
325 DB 64 DUP ('STACK ') ;256 words
330 ;******************************************************************************
331 DGROUP GROUP DSEG
,DSEG_INIT
;FOR CONVENIENT ADDRESSIBLITY OF
332 ;DSEG_INIT in INIT routine
333 ;******************************************************************************
334 DSEG
SEGMENT PARA
PUBLIC ; DATA Segment
335 ;--- EXTERNAL VARIABLES ---
336 EXTRN PARM_FLAG
: BYTE
337 EXTRN COMMAND_LINE
: BYTE ;AN000;THE COMMAND LINE FOR THE PARSER
338 ;--- PUBLIC VARIABLES ---
360 PUBLIC SAV_DEFAULT_DRV
361 PUBLIC SAV_DEFAULT_DIR
372 PUBLIC MAX_BUFFER_SIZE
382 PUBLIC SUBST_COUNT
;AN000;
383 PUBLIC MSG_CLASS
;AN000;
384 PUBLIC INPUT_FLAG
;AN000;
385 PUBLIC MSG_NUM
;AN000;
387 PUBLIC SUBLIST1
;AN000;MSG SUBLIST USED BY INIT
390 ;--- VARIABLES DEFINED ---
392 MSG_SERVICES
<MSGDATA
> ;AN000;
394 ERRORLEVEL
DB 0 ;errorlevel
398 SAV_DEFAULT_DRV
DB ?
;1 = A, 2 = B etc. saved default
399 SAV_DEF_DIR_ROOT
DB '\'
400 SAV_DEFAULT_DIR DB 80 DUP (0)
402 SAV_S_CURDIR
DB 80 DUP (0)
404 SAV_T_CURDIR DB 80 DUP (0)
407 DISP_S_PATH DB 67 DUP (0) ;mirror image of source path. used for display message when copying
408 DISP_S_FILE DB 13 DUP (0)
409 DISP_T_PATH DB 67 DUP (0) ;mirror image of target path
410 DISP_T_FILE DB 13 DUP (0)
412 B_SLASH DB '\',0 ;AN000;
415 FILE_COUNT
LABEL WORD ;AN000;
416 FILE_CNT_LOW
DW 0 ;copied file count
420 ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
421 APPENDFLAG
DW 0 ;AN000;append /X status save area
422 FOUND_FILE_FLAG
DB 0 ;used for showing the message "File not found"
424 S_DRV_NUMBER
DB 0 ;source, target drv #
427 S_DRV_PATH
LABEL BYTE ;source drv, path used for single_drv_copy
429 S_PATH DB 80 DUP (0) ;AN000;Initialized by calling GET CUR DIR
432 S_FILE DB '????????
.???
',0 ;default filename to find file
433 S_FILE_OVERFLO DB 20 DUP (0) ;AN011;BUFFER IF MORE THAN 12 CHARS.
434 S_DIR DB '????????
.???
',0 ;to find any subdirectory name
435 S_DIR_OVERFLO DB 20 DUP (0) ;AN011;BUFFER IF MORE THAN 12 CHARS.
437 S_PARENT DB '..',0 ;source parent used for non single_drv_copy
438 S_HANDLE DW 0 ;file handle opened
440 S_ARC_DRV_PATH LABEL BYTE ;informations used to change source file's
441 S_ARC_DRV DB 'A
:\' ;archieve bits.
442 S_ARC_PATH
DB 64 DUP (0)
445 T_DRV_PATH
LABEL BYTE ;target drv, path used all the time
447 T_PATH DB 80 DUP (0) ;AC016;init by call GET CUR DIR in INIT
449 T_FILE LABEL BYTE ;target filename for file creation
450 T_DRV_1 DB 'B
:' ;target drv letter
451 T_FILENAME DB 15 DUP (0) ;target filename
452 T_TEMPLATE DB 15 DUP (0) ;if global chr entered, this will be used instead of filename.
457 T_HANDLE DW 0 ;target handle created
458 T_MKDIR_LVL DB 0 ;# of target starting directories created.
460 ;------------------------------------------
461 ; PRINT_STDOUT input parameter save area
462 ;------------------------------------------
463 SUBST_COUNT DW 0 ;AN000; message substitution count
464 MSG_CLASS DB 0 ;AN000; message class
465 INPUT_FLAG DB 0 ;AN000; Type of INT 21 used for KBD input
466 MSG_NUM DW 0 ;AN000; message number
469 INPUT_BUFF db 20 dup(0) ;AN000; keyboard input buffer used
470 ;for user response (Y/N)
472 ;--------------------------------------------------------------
473 ; Following three sublists are used by the Message Retriever
474 ;--------------------------------------------------------------
475 SUBLIST1 LABEL DWORD ;AN000;SUBSTITUTE LIST 1
476 DB 11 ;AN000;sublist size
478 DD 0 ;AN000;substition data Offset
480 DB 0 ;AN000;data type
481 DB 0 ;AN000;maximum field width
482 DB 0 ;AN000;minimum field width
483 DB 0 ;AN000;characters for Pad field
486 SUBLIST2 LABEL DWORD ;AN000;SUBSTITUTE LIST 2
487 DB 11 ;AN000;sublist size
489 DD 0 ;AN000;substition data Offset
491 DB 0 ;AN000;data type
492 DB 0 ;AN000;maximum field width
493 DB 0 ;AN000;minimum field width
494 DB 0 ;AN000;characters for Pad field
497 SUBLIST3 LABEL DWORD ;AN000;SUBSTITUTE LIST 3
498 DB 11 ;AN000;sublist size
500 DD 0 ;AN000;substition data Offset
502 DB 0 ;AN000;data type
503 DB 0 ;AN000;maximum field width
504 DB 0 ;AN000;minimum field width
505 DB 0 ;AN000;characters for Pad field
508 FILE_SEARCH_ATTR DW NORM_ATTR
509 DIR_SEARCH_ATTR DW INCL_H_S_DIR_ATTR
511 OPEN_MODE DB Read_Only_Deny_Write ;READ_ONLY_DENY_WRITE ;access, sharing mode
513 ;Equates are defined in XCOPY.EQU
515 MY_FLAG DB 0 ;informations for a tree walk
516 ; find_first_flag equ 01h ;set MY_FLAG by "OR"
517 ; findfile_flag equ 02h
518 ; no_more_file equ 04h
519 ; single_copy_flag equ 08h ;single copy instead of multi copy
520 ; visit_parent_flag equ 10h ;visit parent node
521 ; found_flag equ 20h ;found flag - for find subdir
522 ; missing_link_flag equ 40h ;insuffiecient info. for not creating empty dir
523 ; is_source_flag equ 80h ;if set, dealing with source
524 ; reset_find_first equ 0FEh ;reset by AND
525 ; reset_findfile equ 0FDh
526 ; reset_no_more equ 0FBh
527 ; reset_visit_parent equ 0EFh
528 ; reset_found equ 0DFh
529 ; reset_missing_link equ 0BFh
530 ; reset_is_source equ 07Fh
535 ; big_file_flag equ 04h
536 ; file_bigger_flag equ 08h
537 ; created_flag equ 10h
538 ; reset_cont equ 0FEh
540 ; reset_big_file equ 0FBh
541 ; reset_file_bigger equ 0F7h
542 ; reset_created equ 0EFh
543 ; reset_readfile equ 0F0h ;reset FILE_FLAG for read a file
546 ; open_error_flag equ 01h
547 ; read_error_flag equ 02h
548 ; create_error_flag equ 04h
549 ; write_error_flag equ 08h
550 ; mkdir_error_flag equ 10h
551 ; chdir_error_flag equ 20h
552 ; maybe_itself_flag equ 40h
553 ; disk_full_flag equ 80h
554 ; reset_open_error equ 0FEh
555 ; reset_read_error equ 0FDh
556 ; reset_create_error equ 0FBh
557 ; reset_write_error equ 0F7h
558 ; reset_close_error equ 0EFh
559 ; reset_chdir_error equ 0DFh
562 ; reading_flag equ 01h ;display "Reading source files..."
563 ; reset_reading equ 0FEh ;do not display.
565 SYS_FLAG DB 0 ;system information
566 ; one_disk_copy_flag equ 01h ;xcopy with only one logical drive.
567 ; default_drv_set_flag equ 02h ;default drive has been changed by this program
568 ; default_s_dir_flag equ 04h ;source current directory saved.
569 ; default_t_dir_flag equ 08h ;target current directory saved.
570 ; removalble_drv_flag equ 10h
571 ; sharing_source_flag equ 20h ;source shared
572 ; sharing_target_flag equ 40h
573 ; turn_verify_off_flag equ 80h ;turn the verify off when exit to dos
574 ; reset_default_s_dir equ 0FBh ;reset default_s_dir_flag
577 ; slash_a equ 01h ;soft archieve ?
578 ; slash_d equ 02h ;date?
579 ; slash_e equ 04h ;create empty dir?
580 ; slash_m equ 08h ;hard archieve ? (turn off source archieve bit)
581 ; slash_p equ 10h ;prompt?
582 ; slash_s equ 20h ;walk the tree?
583 ; slash_v equ 40h ;verify on?
584 ; slash_w equ 80h ;show "Press any key to begin copying" msg)
585 ; reset_slash_a equ 0FEh ;turn off soft archieve
586 ; reset_slash_m equ 0F7h ;turn off hard archieve
588 MAX_CX DW 0 ;less than 0FFD0h
589 ACT_BYTES DW 0 ;actual bytes read.
593 TOP_OF_MEMORY DW 0 ;para
594 BUFFER_BASE DW 0 ;para
595 MAX_BUFFER_SIZE DW 0 ;para. BUFFER_LEFT at INIT time.
596 BUFFER_LEFT DW 0 ;para
597 BUFFER_PTR DW 0 ;para. If buffer_left=0 then invalid value
598 DATA_PTR DW 0 ;buffer_ptr + HEADER
599 OLD_BUFFER_PTR DW 0 ;last buffer_ptr
600 SIZ_OF_BUFF DW ? ;AN005;para. EXTENDED ATTRIB BUFF SIZE
601 BYTS_OF_HDR DW ? ;AN005;bytes TOTAL HEADER SIZE
602 PARA_OF_HDR DW 3 ;AC008;para. TOTAL HDR SIZE INIT TO 3
603 OPEN_FILE_COUNT DW ? ;AN005;TRACKING OF OPEN FLS FOR BUFFER
605 DBCSEV_OFF DW 0 ;AN010; remember where dbcs vector is
606 DBCSEV_SEG DW 0 ;AN010;next time I don't have to look
608 ;structured data storage allocation
609 FILE_DTA Find_DTA <> ;DTA for find file
610 DTAS Find_DTA 32 dup (<>) ;DTA STACK for find dir
611 ;** Througout the program BP will be used for referencing fieldsname in DTAS.
612 ;For example, DS:[BP].dta_filename.
615 ;******************************************************************************
618 ASSUME CS:CSEG, DS:DGROUP, SS:SSEG
620 MSG_SERVICES <LOADmsg,GETmsg,DISPLAYmsg,INPUTmsg,CHARmsg,NUMmsg> ;AN000;
621 MSG_SERVICES <XCOPY.CLA,XCOPY.CL1,XCOPY.CL2> ;AN000;
626 ;--- EXTERNAL PROCEDURES ---
627 EXTRN INIT: NEAR ;INIT PROC
629 ;--- PUBLIC PROCEDURES --- ;USED BY INIT
630 PUBLIC SET_BUFFER_PTR
634 PUBLIC CHK_DRV_LETTER
635 PUBLIC COMPRESS_FILENAME
638 PUBLIC SET_DEFAULT_DRV
641 PUBLIC CTRL_BREAK_EXIT
645 ;--- INT 24 ADDR ----------
649 PUBLIC SYSLOADMSG ;AN000;
653 SAV_INT24 LABEL DWORD
654 SAV_INT24_OFF DW 0 ;original int 24 addr holder
656 ;--- START OF A PROGRAM ---
657 ASSUME DS:NOTHING ;AN000;
658 ASSUME ES:NOTHING ;AN000;
660 PUSH AX ;AN000;PRESERVE FOR INIT DRV VALIDITY
662 MOV ES,BX ;AN000;SET UP ADDRESS OF DSEG IN ES
663 ASSUME ES:DGROUP ;AN000;
664 MOV SI,81H ;AN000;POINT TO THE INPUT STRING
665 LEA DI,COMMAND_LINE ;AN000;POINT TO THE SAVE AREA IN PARSER
666 MOV CX,127 ;AN000;GET ALL THE DATA(LOOP COUNT)
667 REP MOVSB ;AN000;MOVE IT
668 MOV PSP_SEG,DS ;AN000;REMEMBER WHERE THE PSP IS
669 MOV DS,BX ;AN000;SET UP ADDRESS OF DSEG IN DS
670 ASSUME DS:DGROUP ;AN000;
672 CALL SYSLOADMSG ;AN000; preload all messages
673 jnc XCOPY_INIT ;AN000; no error, do xcopy init
675 CALL SYSDISPMSG ;AN000; else display error message
676 POP AX ;AN000;WAS PRESERVED FOR DRV VALIDATION
677 JMP JUST_EXIT ;AN000; exit
680 POP AX ;AN000;WAS PRESERVED FOR DRV VALIDATION
681 CALL INIT ;initialization
682 JC MAIN_EXIT ;error. (Already message has been displayed)
683 MOV BP, OFFSET DTAS ;initialize BP
684 OR ACTION_FLAG, READING_FLAG ;set reading flag for copy message
686 ;Before walking the tree, find out the /X status of APPEND and save it.
687 ;Then terminate the /X feature. After the tree search, restore the
688 ;original /X status. This is done at EXIT time.
690 MOV AX,CHK_APPEND ;AN000;CHECK IF APPEND INSTALLED
692 OR AL,AL ;AN000;INSTALLED?
695 MOV AX,VER_APPEND ;AN019;ASK IF DOS VERSION OF APPEND
696 INT 2FH ;AN019;CALL THE FUNCTION
697 CMP AX,D_V_APPEND ;AN000;DOS VERSION?
700 MOV AX,GET_APPEND ;AN000;GET THE APPEND STATE
702 MOV APPENDFLAG,BX ;AN000;SAVE THE STATE TO RESTORE
703 TEST APPENDFLAG,F_APPEND ;AN019;IS THE /X BIT ON?
706 MOV AX,SET_APPEND ;AN000;SET THE APPEND STATE
707 MOV BX,APPENDFLAG ;AN000;GET THE SAVED STATE
708 XOR BX,F_APPEND ;AN000;TURN OFF THE /X BIT
718 CALL ORG_S_DEF ;restore the original source default dir
719 CALL WRITE_FROM_BUFFER ;write from buffer if we missed it.
723 MOV DS, BX ;re initialize ds, es
724 MOV ES, BX ;exit here if the status of source, target or default drv has been changed.
725 CALL CHK_FILE_NOT_FOUND ;if no files has been found, show the message.
727 ; Set message substitution list
728 LEA SI,SUBLIST1 ;AN000; get addressability to sublist
729 LEA DX,FILE_COUNT ;AN000; offset to file count
730 MOV [SI].DATA_OFF,DX ;AN000; save data offset
731 MOV [SI].DATA_SEG,DS ;AN000; save data segment
732 MOV [SI].MSG_ID,1 ;AN000; message ID
733 MOV [SI].FLAGS,RIGHT_ALIGN+UNSGN_BIN_DWORD ;AN018;
734 MOV [SI].MAX_WIDTH,9 ;AN018; MAXIMUM FIELD WITH
735 MOV [SI].MIN_WIDTH,9 ;AN018; MINIMUM FIELD WITH
736 MOV [SI].PAD_CHAR,SPACE ;AN018; MINIMUM FIELD WITH
738 ; Set message parameters
739 MOV AX,MSG_FILES_COPIED ;AN000; message number
740 MOV MSG_NUM,AX ;AN000; set message number
741 MOV SUBST_COUNT,PARM_SUBST_ONE ;AN000; one message substitution
742 MOV MSG_CLASS,UTILITY_MSG_CLASS ;AN000; message class
743 MOV INPUT_FLAG,NO_INPUT ;AN000; no user input
744 CALL PRINT_STDOUT ;AN000; display file count
748 MOV DS, BX ;re initialize ds, es
749 MOV ES, BX ;exit here if the status of source, target or default drv has been changed.
750 CALL CHK_MKDIR_LVL ;starting target directory has been created?
751 CALL ORG_S_T_DEF ;restore original target, source, default drv, and verify status
753 JUST_EXIT: ;unconditional immediate exit
755 ; Restore the original status of APPEND if active.
758 MOV BX,APPENDFLAG ;AN000;GET THE STATUS WORD
759 OR BX,BX ;AN019;IF FLAGS SAVED, THIS IS DOS VER.
760 ; $IF NZ ;AN019;IF ACTIVE,
762 MOV AX,SET_APPEND ;AN000;SET TO THE ORIGINAL STATE
763 INT 2FH ;AN000; turn on the /X feature
767 MOV AH, 4Ch ;return to dos
768 MOV AL, ERRORLEVEL ;set return code whatever
771 MOV ERRORLEVEL, 2 ;set errorlevel to 2 for control break
778 ;----------------- SUBROUTINES ---------------------------------------------
782 ;Walk the source tree to read files and subdirectories
784 OR MY_FLAG, FINDFILE_FLAG ;deals with files
785 OR MY_FLAG, FIND_FIRST_FLAG ;find first
786 CALL SET_MY_DTA ;set DTA to FILE_DTA
789 CALL FIND_FILE ;find first (next)
790 TEST MY_FLAG, NO_MORE_FILE ;no more file?
791 ; $LEAVE NZ ;then exit loop
793 CALL READ_INTO_BUFFER ;else read the file into the buffer
798 TEST OPTION_FLAG, SLASH_S ;walk the tree?
804 AND MY_FLAG, RESET_FINDFILE ;now, deals with directory
805 OR MY_FLAG, FIND_FIRST_FLAG ;find first
808 CALL SET_MY_DTA ;set DTA to DTAS according to BP
809 CALL FIND_DIR ;find first (next)
810 TEST MY_FLAG, NO_MORE_FILE ;no more subdirectory?
811 ; $LEAVE NZ ;then leave this loop to return to caller
814 LEA SI, [BP].DTA_FILENAME
815 CMP S_PATH, 0 ;root directory?
818 MOV AL, 0FFh ;then '\' is already provided
. Just concat
.
822 MOV AL, PATH_DELIM
;put delimiter
825 CALL CONCAT_ASCIIZ
;make new path
826 test option_flag
, slash_p
;prompt mode?
829 call p_concat_display_path
832 INC S_DEPTH
;increase depth
833 CALL MAKE_HEADER
;make header in the buffer
834 OR MY_FLAG
, IS_SOURCE_FLAG
;dealing with source
835 AND MY_FLAG
, RESET_VISIT_PARENT
;going to visit child node
836 CALL CHANGE_S_DIR
;change source dir
837 ADD BP, type FIND_DTA
;increase DTAS stack pointer
838 CALL TREE_COPY
;tree copy the sub directory
843 CMP S_DEPTH
, 0 ;starting directory? then exit
846 DEC S_DEPTH
;dec depth
847 TEST OPTION_FLAG
, SLASH_E
;copy subdirectories even if empty?
850 CALL DEL_EMPTY
;then check the old_buffer_ptr and
851 ;if it is a directory, then restore
856 CALL LAST_DIR_OUT
;change environments
857 test option_flag
, slash_p
;prompt mode?
860 call p_cut_display_path
863 LEA DX, S_DRV_PATH
;before returning to the caller
864 OR MY_FLAG
, IS_SOURCE_FLAG
865 OR MY_FLAG
, VISIT_PARENT_FLAG
867 SUB BP, type FIND_DTA
870 ; $ENDIF ;walk the tree
877 ;If buffer is not full, and the tree walk is going to return to the parents,
878 ;this routine should be called.
879 ;If old_buffer_ptr points to a directory, then set buffer_ptr to this, and
880 ;increase buffer_left by HEADER (para) and set old_buffer_ptr to that of
881 ;BEFORE_PTR. i.e. delete the empty directory entry from the buffer.
887 CMP OLD_BUFFER_PTR
, AX ;buffer is empty?
888 JE DE_EXIT
;yes, exit
890 MOV ES, OLD_BUFFER_PTR
891 TEST ES:ATTR_FOUND
, 10h
;directory?
892 JZ DE_EXIT
;if not, exit
893 MOV AX, OLD_BUFFER_PTR
894 MOV BUFFER_PTR
, AX ;set new BUFFER_PTR
895 MOV AX, ES:BEFORE_PTR
896 MOV OLD_BUFFER_PTR
, AX ;set new OLD_BUFFER_PTR
897 MOV AX, PARA_OF_HDR
;AN005;GET THE HEADER SIZE (para.)
898 ADD BUFFER_LEFT
, AX ;AC005;dir entry must be only hdr SIZE.
907 P_concat_display_path proc
near
908 ;concatenate subdirectory name found from DTAS to the
909 ;DISP_S_PATH which will be used for prompts
911 MOV DI, OFFSET DISP_S_PATH
912 LEA SI, [BP].DTA_FILENAME
913 CMP S_DEPTH
, 0 ;this will be the first subdir?
916 MOV AL, 0FFh ;then do not put '\'
925 P_concat_display_path endp
929 P_cut_display_path proc
near
930 ;take the last dir out from the DISP_S_PATH for prompt.
932 MOV SI, OFFSET DISP_S_PATH
933 MOV DI, OFFSET DISP_S_PATH
940 MOV BYTE PTR DS:[SI], 0
955 MOV BYTE PTR [DI], '\'
956 MOV BYTE PTR [DI+1], 0
962 P_cut_display_path endp
966 READ_INTO_BUFFER PROC NEAR
967 ;Read *** a *** file into buffer
968 TEST MY_FLAG, SINGLE_COPY_FLAG ;single copy?
969 ; $IF Z,AND ;no, multi copy
971 TEST ACTION_FLAG, READING_FLAG ;show message?
974 MOV AX,MSG_READING_SOURCE ;AN000; message number
975 MOV MSG_NUM,AX ;AN000; set message number
976 MOV SUBST_COUNT,NO_SUBST ;AN000; no message substitution
977 MOV MSG_CLASS,UTILITY_MSG_CLASS ;AN000; message class
978 MOV INPUT_FLAG,NO_INPUT ;AN000; no input
979 CALL PRINT_STDOUT ;AN000;show message "Reading source files"
981 AND ACTION_FLAG, RESET_READING ;reset it
985 AND FILE_FLAG, RESET_READFILE ;reset file_flag to read a file
986 MOV AX,FILE_DTA.DTA_FILE_SIZE_HIGH
987 MOV HIGH_FILE_SIZE, AX
988 MOV AX,FILE_DTA.DTA_FILE_SIZE_LOW
989 MOV LOW_FILE_SIZE, AX
990 CALL CMP_FILESIZE_TO_BUFFER_LEFT ;compare sizes
992 MOV AX, PARA_OF_HDR ;AN005;GET THE HEADER SIZE (para.)
993 CMP MAX_BUFFER_SIZE, AX ;AN005;IS EA BUFFER TOO LARGE?
996 CLC ;AN005;CLEAR CARRY
997 MOV AX, MSG_INSUF_MEMORY ;AC005;GET THE MESSAGE ID
998 MOV MSG_NUM,AX ;AN005;NEED MESSAGE ID FOR PRINT
999 MOV SUBST_COUNT,NO_SUBST ;AN005;NO SUBSTITUTION TEXT
1000 MOV INPUT_FLAG,NO_INPUT ;AN005;NO INPUT = 0
1001 MOV MSG_CLASS,UTILITY_MSG_CLASS ;AN005;MESSAGE CLASS = -1
1002 CALL PRINT_STDERR ;AN005;print error. AX points to msg ID
1003 ; $ENDIF ;AN005;WE HAVE ENOUGH MEMORY
1005 MOV AX, PARA_OF_HDR ;AN005;GET THE HEADER SIZE (para.)
1006 CMP MAX_BUFFER_SIZE,AX ;AN005;IS EA BUFFER TOO LARGE?
1007 JB RIB_ERROR ;AN005;CLOSE THE FILE AND GET THE NEXT
1009 TEST FILE_FLAG, FILE_BIGGER_FLAG ;filesize > buffer_left - HEADER ?
1010 JZ RIB_SMALL ;if not, then small file
1011 MOV BX, S_HANDLE ;AN005;
1012 CALL CLOSE_A_FILE ;AN005;ONLY OPENED TO GET BUFFER SIZE
1013 CALL WRITE_FROM_BUFFER
1014 CALL CMP_FILESIZE_TO_BUFFER_LEFT ;compare again
1015 TEST FILE_FLAG, FILE_BIGGER_FLAG ;still bigger?
1016 JNZ RIB_BIG ;yes. Big file
1022 MOV BX, S_HANDLE ;AN005;
1023 CALL CLOSE_A_FILE ;AN005;ONLY OPENED TO GET BUFFER SIZE
1027 TEST COPY_STATUS, OPEN_ERROR_FLAG ;open error?
1028 JNZ RIB_EXIT ;just exit. find next file
1029 MOV BX, S_HANDLE ;else write error
1030 CALL CLOSE_A_FILE ;close the troubled file
1033 TEST MY_FLAG, SINGLE_COPY_FLAG ;single copy?
1036 CALL WRITE_FROM_BUFFER ;then write a file
1040 READ_INTO_BUFFER ENDP
1044 SMALL_FILE PROC NEAR
1045 ;handles a file smaller than max_buffer_size or buffer_left, i.e. fit in memory.
1046 ;This routine will call MAKE_HEADER, SET_BUFFER_PTR< READ_A_FILE,
1047 ;CALC_FILE_SIZE, CMP_FILE_FFD0h, CLOSE_A_FILE.
1050 CALL CMP_FILE_FFD0h ;filesize > 0FFD0h ?
1051 TEST FILE_FLAG, FILE_BIGGER_FLAG
1052 JZ SMF_EOF ;filesize <= 0FFD0h
1053 OR FILE_FLAG, CONT_FLAG ;filesize > 0FFD0h. set cont_flag
1054 MOV CX, 0FFD0h ;# of bytes to read
1056 JC SMF_ERROR ;unsuccessful read?
1057 CALL MAKE_HEADER ;else make header and ready for next
1058 CALL CALC_FILE_SIZE ;filesize = filesize - bytes read
1059 JMP SMF_CONT ;loop. compare again with the rest
1062 MOV CX, LOW_FILE_SIZE ;rest of the bytes to read
1063 OR FILE_FLAG, EOF_FLAG ;AN000;set EOF
1079 ;handles a file which is bigger than max_buffer_size
1080 ;Needs 2 file handles open concurrently for read and write
1082 OR FILE_FLAG, BIG_FILE_FLAG
1083 OR FILE_FLAG, CONT_FLAG
1085 JC BIF_ERROR ;error in open?
1086 CMP MAX_BUFFER_SIZE, 0FFFh ;max buffer size > 0FFFh in para ?
1087 JA BIF_BIG ;yes. large buffer system
1089 MOV CX, MAX_CX ;CX = max_buffer_size * 16 - HEADER
1092 JC BIF_ERROR ;read error?
1094 CALL WRITE_FROM_BUFFER
1095 JC BIF_ERROR ;write error?
1096 TEST FILE_FLAG, EOF_FLAG ;end of file set by READ_A_FILE?
1097 JZ BIF_SM ;if not, read again
1100 JMP BIF_EXIT ;finished.
1102 MOV CX, 0FFD0h ;max # of data bytes this program supports
1107 CALL CALC_FILE_SIZE ;modify file size
1109 CALL CMP_FILESIZE_TO_BUFFER_LEFT ;filesize > buffer_left?
1110 TEST FILE_FLAG, FILE_BIGGER_FLAG ;yes.
1111 JZ BIF_END ;if it is not, call small_file
1112 MOV AX, PARA_OF_HDR ;AN021;GET THE ATTR. HDR SIZE
1113 ADD AX, 0FFFh ;AN021;
1114 CMP BUFFER_LEFT, AX ;AC021;BUFFER_LEFT >= 0FFF0h+HDR SIZE?
1115 JAE BIF_BIG ;then loop again.
1116 MOV AX, PARA_OF_HDR ;AN021;GET THE ATTR. HDR SIZE
1117 ADD AX, 140H ;AN021;
1118 CMP BUFFER_LEFT, AX ;AC021;BUFFER_LEFT >= 5Kbytes+HDR SIZE?
1119 ;minimum buffer size this pgm supports.
1120 JL BIF_BIG3 ;then flush buffer and try again. **IF system buffer left < 5 K then infinit loop can happen.
1122 SUB AX,PARA_OF_HDR ;AC005;FOR HEADER SIZE para.
1124 MUL CX ;AN020;MAKE IT NUMBER OF BYTES
1125 MOV CX,AX ;AN020;FOR READ
1126 JMP BIF_BIG1 ;read again
1128 CALL WRITE_FROM_BUFFER
1130 JMP BIF_BIG2 ;flush buffer and compare again.
1132 CALL SMALL_FILE ;when filesize <= buffer_left then SMALL_FILE will finish it.
1133 JC BIF_ERROR ;something wrong?
1134 CALL WRITE_FROM_BUFFER ;else finish copying this file
1144 MAKE_HEADER PROC NEAR
1145 ;When called by READ_A_FILE after the data had been read into the buffer, this
1146 ;routine will put the header which is just below the data area where the
1147 ;current BUFFER_PTR points. The header E.A.BUFFER SIZE + (3 para) long. And
1148 ;this routine will also call SET_BUFFER_PTR to set the BUFFER_PTR, BUFFER_LEFT
1149 ;for the next process.
1150 ;If called by TREE_COPY for a SUBDIRECTORY handle, this routine should
1151 ;check the BUFFER_LEFT (when called by READ_A_FILE, the caller is assumed
1152 ;to check the size of buffer_left before calling.) In this case, this
1153 ;routine will set the next BUFFER_PTR, BUFFER_LEFT, OLD_BUFFER_PTR
1154 ;instead of SET_BUFFER_PTR routine.
1155 ;Informations are obtained from the DTA area (for file - FILE_DTA.xxx
1156 ;dir - DS:[BP].xxx ) and stored into the header by referencing ES:field;s name.
1157 ;DS - Program Data area
1158 ;ES - will be used for a header segment in the buffer.
1164 MOV AX,BUFFER_PTR ;buffer_ptr is a segment
1165 MOV ES, AX ;now, ES is a header seg.
1168 MOV AX, PARA_OF_HDR ;AN005;GET THE HEADER SIZE (para.)
1169 CMP BUFFER_LEFT,AX ;AC005;buffer_left=less than NEEDED?
1171 CALL WRITE_FROM_BUFFER ;if so, flush buffer
1172 JC MH_ERROR_BRIDGE ;write error?
1173 JMP SHORT MH_AGAIN ;reinitialize ES to new buffer ptr
1175 TEST MY_FLAG, FINDFILE_FLAG ;identify caller.
1176 JNZ MH_FILE ;if a file, jmp to MH_FILE
1177 ;else deals with directory.
1178 MOV ES:CONTINUE_INFO, 0 ;not a continuation.
1179 MOV AX,OLD_BUFFER_PTR
1180 MOV ES:BEFORE_PTR, AX ;set before_ptr in header
1182 MOV OLD_BUFFER_PTR, AX ;set variable OLD_BUFFER_PTR
1183 ADD AX,PARA_OF_HDR ;AC005;AX = BUFFER_PTR+HEADER(para)
1184 MOV BUFFER_PTR, AX ;set new BUFFER_PTR
1185 MOV ES:NEXT_PTR, AX ;set NEXT_PTR in the header
1186 MOV AX, PARA_OF_HDR ;AN005;GET THE HEADER SIZE (para.)
1187 SUB BUFFER_LEFT,AX ;AC005;adjust BUFFER_LEFT
1188 CMP BUFFER_LEFT,AX ;AC005;less than HEADER SIZE (para) ?
1191 MOV BUFFER_LEFT, 0 ;indicate buffer_full
1195 MOV ES:DIR_DEPTH, AL ;now save other info's
1196 MOV AL, DS:[BP].DTA_ATTRIBUTE
1197 MOV ES:ATTR_FOUND, AL ;in this case, DIR
1198 MOV AL, BYTE PTR T_DRV
1199 MOV ES:TARGET_DRV_LET, AL ;mov target drive letter
1200 MOV ES:TARGET_DRV_LET+1, DRV_delim ; ':'
1202 LEA SI, [BP].DTA_FILENAME ;DS:SI
1203 MOV DI, OFFSET ES:FILENAME_FOUND ;ES:DI
1204 REP MOVSB ;mov sting until cx = 0
1206 MH_ERROR_BRIDGE: JMP MH_ERROR
1207 MH_FILE: ;handles a file header hereafter.
1208 TEST FILE_FLAG, CONT_FLAG ;continuation?
1209 JZ MH_WHOLE_FILE ;no, just a whole file
1210 TEST FILE_FLAG, EOF_FLAG ;Eof flag set?
1211 JNZ MH_CONT_END ;yes, must be end of continuation
1212 TEST FILE_FLAG, BIG_FILE_FLAG ;Is this a big file?
1214 MOV ES:CONTINUE_INFO, 1 ;else small file continuation.
1217 MOV ES:CONTINUE_INFO, 0
1220 MOV ES:CONTINUE_INFO, 3
1223 MOV ES:CONTINUE_INFO, 2
1225 MOV AX,FILE_DTA.DTA_FILE_TIME
1226 MOV ES:FILE_TIME_FOUND, AX
1227 MOV AX, FILE_DTA.DTA_FILE_DATE
1228 MOV ES:FILE_DATE_FOUND, AX
1229 MOV AX, FILE_DTA.DTA_FILE_SIZE_LOW
1230 MOV ES:LOW_SIZE_FOUND, AX
1231 MOV AX, FILE_DTA.DTA_FILE_SIZE_HIGH
1232 MOV ES:HIGH_SIZE_FOUND, AX
1233 MOV AL, BYTE PTR T_DRV
1234 MOV ES:TARGET_DRV_LET, AL
1235 MOV ES:TARGET_DRV_LET+1, DRV_DELIM
1237 MOV SI, OFFSET FILE_DTA.DTA_FILENAME
1238 MOV DI, OFFSET ES:FILENAME_FOUND
1241 ; Get Extended Attribute list of the opened file and save in attribute buff.
1243 MOV BX,S_HANDLE ;AN005; BX = handle
1244 MOV SI,ALL_ATTR ;AN005; SELECT ALL ATTRIBUTES SIZE
1245 MOV CL, PARAGRAPH ;AN005; PARAGRAPH = 4 FOR DIV BY 16
1246 MOV AX,SIZ_OF_BUFF ;AN005; GET THE SIZE EXPRESSED IN para.
1247 SHL AX, CL ;AN005; GET # OF BYTES FROM para.
1248 MOV CX, AX ;AN005; NEEDS TO BE IN CX
1249 MOV DI, OFFSET ES:ATTRIB_LIST ;AN005; ES:DI = E A LIST IN BUFFER
1250 MOV AX, GET_ATTRIB ;AN005; extended attribute code 5702H
1251 INT 21H ;AN005; get extended attribute list
1253 JC MH_ERROR ;AN000; jump if error
1255 MOV AX, OLD_BUFFER_PTR
1256 MOV ES:BEFORE_PTR, AX
1259 CALL SET_BUFFER_PTR ;set buffer_ptr for next. AX is already set.
1261 MOV ES:NEXT_PTR, AX ;next buffer_ptr is next_ptr
1263 MOV ES:DIR_DEPTH, AL ;same as source depth
1264 MOV AL, FILE_DTA.DTA_ATTRIBUTE
1265 MOV ES:ATTR_FOUND, AL ;attribute found
1268 OR COPY_STATUS, OPEN_ERROR_FLAG ;AN000;
1269 CALL EXTENDED_ERROR_HANDLER ;AN000;
1278 OPEN_A_FILE PROC NEAR
1280 ;-------------------------------------------------------------------------
1281 ; Use extended open DOS call to open source file,
1282 ; if successfully open, then save filehand to S_HANDLE.
1283 ; And update the open file count.
1284 ;-------------------------------------------------------------------------
1286 LEA SI,FILE_DTA.DTA_FILENAME ;AN005; DS:SI-->NAME TO OPEN
1287 MOV DX,OPN_FLAG ;AN000; flag = 0101H
1288 MOV CX,OPN_ATTR ;AN000; attribute = 0
1289 MOV BX,OPN_MODE ;AN007; open mode = 0000H (READ)
1290 MOV DI, NUL_LIST ;AN005; ES:DI = -1
1291 MOV AX, Ext_Open ;AN000; = 6Ch
1292 INT 21H ;AN000; OPEN SOURCE FILE
1295 MOV S_HANDLE, AX ;save filehandle
1296 INC OPEN_FILE_COUNT ;AN005;UPDATE THE OPEN FILE COUNTER
1298 JMP OF_EXIT ;AN000; exit
1301 OR COPY_STATUS, OPEN_ERROR_FLAG
1302 CALL EXTENDED_ERROR_HANDLER
1309 CMP_FILE_FFD0h PROC NEAR
1310 ;check whether the filesize in HIGH_FILE_SIZE, LOW_FILE_SIZE is bigger than
1311 ;0FFD0h. If it is, then set FILE_BIGGER_FLAG, else reset it.
1312 CMP HIGH_FILE_SIZE, 0
1315 CMP LOW_FILE_SIZE, 0FFD0h
1318 AND FILE_FLAG, RESET_FILE_BIGGER ;filesize <= 0FFD0h
1322 OR FILE_FLAG, FILE_BIGGER_FLAG
1329 CALC_FILE_SIZE PROC NEAR
1330 ;subtract the bytes read (ACT_BYTES) from the filesize in HIGH_FILE_SIZE,
1333 SUB LOW_FILE_SIZE, AX
1334 SBB HIGH_FILE_SIZE, 0
1340 READ_A_FILE PROC NEAR
1342 ;if after reading, AX < CX or AX = 0 the set EOF_FLAG.
1343 ;INPUT:CX - # of bytes to read
1348 PUSH DS ;save program data seg
1351 MOV DX, BUFFER_PTR ;current buffer header seg
1352 ADD DX, PARA_OF_HDR ;AC005;skip the header part
1353 MOV DS, DX ;now DS = buffer_ptr + HDR, data area
1354 XOR DX, DX ;offset DX = 0
1356 POP DS ;restore program data area
1357 JC RF_ERROR ;read error?
1360 OR FILE_FLAG, EOF_FLAG ;EOF reached. AX = 0 or AX < CX
1362 CLC ;clear carry caused from CMP
1363 MOV ACT_BYTES, AX ;save actual bytes read
1366 OR COPY_STATUS, READ_ERROR_FLAG
1367 CALL EXTENDED_ERROR_HANDLER
1375 ;set first or next depending on FIND_FIRST_FLAG.
1376 ;once called, reset FIND_FIRST_FLAG.
1377 TEST MY_FLAG, FIND_FIRST_FLAG
1387 AND MY_FLAG, RESET_FIND_FIRST ;reset FIND_FIRST_FLAG
1396 ;set NO_MORE_FILE if carry.
1399 TEST MY_FLAG, FIND_FIRST_FLAG ;find first ?
1402 MOV DX, OFFSET S_FILE
1403 MOV CX, File_Search_Attr ;normal = 0
1407 MOV DX, OFFSET FILE_DTA
1413 OR MY_FLAG, NO_MORE_FILE ;no more file in this directory
1417 MOV FOUND_FILE_FLAG, 1 ;set the flag for "File not found" msg.
1418 CALL FILTER_FILES ;found. filter it with options
1419 TEST MY_FLAG, FOUND_FLAG
1420 ; $ENDLOOP NZ ;if found, leave this loop else start again
1422 AND MY_FLAG, RESET_NO_MORE
1429 ;find directory entry
1430 ;set NO_MORE_FLAG if carry.
1433 TEST MY_FLAG, FIND_FIRST_FLAG
1436 MOV DX, OFFSET S_DIR
1437 MOV CX, DIR_SEARCH_ATTR
1445 ; $EXITIF C ;no more file
1447 OR MY_FLAG, NO_MORE_FILE ;set MY_FLAG and exit this loop
1448 ; $ORELSE ;otherwise found a file
1451 CMP DS:[BP].DTA_ATTRIBUTE, Is_subdirectory ; directory?
1454 CMP DS:[BP].DTA_FILENAME, A_dot ;starts with . ?
1455 ; $IF NE ;if not, then desired subdir
1457 OR MY_FLAG, FOUND_FLAG ;found
1461 AND MY_FLAG, RESET_FOUND
1464 TEST MY_FLAG, FOUND_FLAG
1465 ; $ENDLOOP NZ ;if found, leave this loop else start again
1467 AND MY_FLAG, RESET_NO_MORE ;found. set my_flag and exit
1475 FILTER_FILES PROC NEAR
1476 ;FILE_DTA.XXX HAS INFORMATIONS
1477 ;this routine also show the prompt of source path, filename, if SLASH_P is on.
1479 TEST OPTION_FLAG, SLASH_A ;soft archieve?
1480 JNZ SLASH_AM_RTN ;yes
1481 TEST OPTION_FLAG, SLASH_M ;then hard archieve?
1482 JNZ SLASH_AM_RTN ;yes
1484 TEST OPTION_FLAG, SLASH_D ;date?
1487 TEST OPTION_FLAG, SLASH_P ;prompt mode? ** this should be placed last.
1489 JMP SHORT FF_FOUND ;no more selective options. copy this file.
1490 SLASH_AM_RTN: ;soft or hard archieve.
1491 CALL CHK_ARCHIEVE_BIT
1493 JMP SHORT FF_D ;check other options
1495 CALL CHK_DATE_FILE ;check file's date
1499 call prompt_path_file ;show message and get input from the user
1500 jc ff_not_found ;user does not want this file
1502 OR MY_FLAG, FOUND_FLAG ;set found_flag
1505 AND MY_FLAG, RESET_FOUND ;this file is not what we want to copy
1510 CHK_ARCHIEVE_BIT PROC NEAR
1511 ;check the current FILE.DTA area and if archieve bit is on, found.
1512 TEST FILE_DTA.DTA_ATTRIBUTE, 20h ;archieve on?
1519 STC ;archieve bit is off. Don't
1520 ; $ENDIF ;have to copy this file
1523 CHK_ARCHIEVE_BIT ENDP
1525 CHK_DATE_FILE PROC NEAR
1527 MOV CX, FILE_DTA.DTA_FILE_DATE
1528 CMP CX, INPUT_DATE ;FILE_DATE < INPUT_DATE
1535 CLC ;found desired file
1543 PROMPT_PATH_FILE PROC NEAR
1545 ;show the current source path, filename found, and get the user input.
1546 ;if it is yes, then reset carry, no, set carry otherwise show
1547 ;the whole message again.
1551 LEA SI, FILE_DTA.DTA_FILENAME
1552 MOV DI, OFFSET DISP_S_FILE
1553 REP MOVSB ;filename => disp_s_file
1555 LEA SI,SUBLIST1 ;AN000; get addressability to sublist
1556 LEA DX,DISP_S_PATH ;AN000; offset to PATH NAME
1557 MOV [SI].DATA_OFF,DX ;AN000; save offset
1558 MOV [SI].DATA_SEG,DS ;AN000; save data segment
1559 MOV [SI].MSG_ID,1 ;AN000; message ID
1560 MOV [SI].FLAGS,010H ;AN000; ASCIIZ string, left align
1561 MOV [SI].MAX_WIDTH,0 ;AN000; MAXIMUM FIELD WITH
1562 MOV [SI].MIN_WIDTH,0 ;AN000; MINIMUM FIELD WITH
1564 LEA SI,SUBLIST2 ;AN000; get addressability to sublist
1565 LEA DX,DISP_S_FILE ;AN000; offset to FILE NAME
1566 MOV [SI].DATA_OFF,DX ;AN000; save offset
1567 MOV [SI].DATA_SEG,DS ;AN000; save data segment
1568 MOV [SI].MSG_ID,2 ;AN000; message ID
1569 MOV [SI].FLAGS,010H ;AN000; ASCIIZ string, left align
1570 MOV [SI].MAX_WIDTH,0 ;AN000; MAXIMUM FIELD WITH
1571 MOV [SI].MIN_WIDTH,0 ;AN000; MINIMUM FIELD WITH
1572 LEA SI,SUBLIST1 ;AN000;
1574 CMP S_DEPTH,0 ;now dealing with starting dir?
1575 JE PATH_FILE_QUERY ;ask (Y/N)
1580 MOV AX,P_S_PATH_FILE0 ;no back slash, since it is already there
1585 MOV AX,P_S_PATH_FILE1 ; Path and file name with
1586 ; back slash delemeter
1588 MOV MSG_NUM,AX ;AN000; set message number
1589 MOV SUBST_COUNT,PARM_SUBST_TWO ;AN000; substitution count
1590 MOV MSG_CLASS,UTILITY_MSG_CLASS ;AN000; message class
1591 MOV INPUT_FLAG,DOS_KEYB_INP ;AN000; Y or N INPUT
1592 CALL PRINT_STDOUT ;AN000; Display message
1593 PUSH AX ;AN000; SAVE IT
1595 MOV AX,MSG_CR_LF_STR ;AN000; JUST CR,LF
1596 MOV MSG_NUM,AX ;AN000; set message number
1597 MOV SUBST_COUNT,NO_SUBST ;AN000; substitution count = 0
1598 MOV MSG_CLASS,UTILITY_MSG_CLASS ;AN000; message class
1599 MOV INPUT_FLAG,NO_INPUT ;AN000; NO INPUT
1600 CALL PRINT_STDOUT ;AN000; Display message
1602 POP AX ;AN000; GET IT BACK
1603 ; On return from prompt msg, AX contains Y or N response character
1606 MOV AL,023H ;AN000; Y/N check function
1607 INT 21H ;AN000; Issue Extended country to
1608 ; capitalize the Y/N response
1609 JC PPF_RETRY ;AN000; NOT Y OR N, ASK AGAIN
1610 CMP AX,1 ;AN000; look for Y
1611 JG PPF_RETRY ;AN000; NOT Y OR N, ASK AGAIN
1613 CMP AX,0 ;AN000; look for N
1616 CLC ;AN000;CLEAR CARRY
1619 JMP PPF_AGAIN ;AN000;ASK AGAIN
1621 STC ;AN000;set carry
1624 PROMPT_PATH_FILE ENDP
1629 SET_MY_DTA PROC NEAR
1630 ;set DS:DX for find_first(next). If MY_FLAG is set to FINDFILE_FLAG then
1631 ;set it to the offset FILE_DTA, otherwise to BP.
1632 ;DS should be set to the area whre FILE_DTA, DTAS are.
1633 PUSH DX ;save current DX
1634 TEST MY_FLAG, FINDFILE_FLAG ;handling file?
1637 MOV DX, OFFSET FILE_DTA
1651 CHANGE_S_DIR PROC NEAR
1652 ;change source directory
1653 ;DS points to program data seg.
1655 CMP S_DRV[2], 0 ;LAST_DIR_OUT have took '\' out?
1658 MOV S_DRV
[2], '\' ;then restore '\' for root dir
1663 TEST SYS_FLAG
, ONE_DISK_COPY_FLAG
;one drive letter copy?
1666 TEST OPTION_FLAG
, SLASH_M
;hard archive option? (should use full path
1667 ; $IF NZ ; since hard archieve operation will corrupt the current directory)
1670 MOV DX, OFFSET S_DRV_PATH
;always use full path
1674 TEST MY_FLAG
, VISIT_PARENT_FLAG
;now going toward the root?
1677 MOV DX, OFFSET S_PARENT
;just '..',0
1681 LEA DX, [BP].DTA_FILENAME
;use the subdir name just found
1686 MOV AH, Chdir
; = 3Bh
1690 OR COPY_STATUS
, CHDIR_ERROR_FLAG
;chdir error in source. critical
1691 CALL EXTENDED_ERROR_HANDLER
1699 CHANGE_T_DIR PROC
NEAR
1700 ;change target dir according to t_drv_path.
1701 ;Since this routine is called by WRITE_FROM_BUFFER and DS now points
1702 ;to buffer area while ES points to the program data area, we set DS
1703 ;to data seg again here for the function call Chdir.
1704 PUSH DS ;save current buffer seg
1705 PUSH ES ;currentpy es is a data seg
1706 POP DS ;restore DS value as program data seg
1708 CMP T_DRV
[2], 0 ;LAST_DIR_OUT took '\' out?
1711 MOV T_DRV
[2], '\' ;then put it back for root dir
1716 MOV DX, OFFSET T_DRV_PATH
1720 POP DS ;restore caller's DS value
1725 CMP_FILESIZE_TO_BUFFER_LEFT PROC NEAR
1726 ;Compare buffer_left (paragraph) with filesize (high_file_size, low_file_size.)
1727 ;if filesize is bigger than buffer_left, then set FILE_BIGGER_FLAG
1728 ;indicating filesize > buffer_left.
1733 CMP OPEN_FILE_COUNT,NUL ;AN005;ARE THERE ANY OPEN FILES
1734 ; $IF Z ;AN005;NO, THEN GO AHEAD AND OPEN
1736 CALL OPEN_A_FILE ;AN005;OPEN A FILE USING FILE_DTA
1738 ; Get extended Attribute list size.
1740 MOV BX,S_HANDLE ;AN005; BX = handle
1741 MOV AX, GET_ATTRIB ;AN005; extended attribute code 5702H
1742 MOV SI,ALL_ATTR ;AN005; SELECT ALL ATTRIBUTES SIZE
1743 XOR CX,CX ;AN005; JUST QUERY SIZE NEEDED
1744 MOV DI,NUL_LIST ;AN005; DI = LIST FOR NO DATA RETURNED
1745 INT 21H ;AN005; get extended attribute SIZE
1746 ADD CX,PARA_BOUND ;AN005; TO FIGURE THE NEXT PARAGRAPH
1748 MOV CL,PARAGRAPH ;AN005; GET PARAGRAPHS (DIV BY 16)
1750 MOV SIZ_OF_BUFF,AX ;AN005;SAVE BUFF SIZE FOR THE HEADER
1751 ADD AX,FIXD_HD_SIZ ;AN005;GET THE TOTAL HEADER SIZE
1752 MOV PARA_OF_HDR,AX ;AN005;SAVE FOR LATER
1753 SHL AX, CL ;AN005;CONVERT BACK TO TOTAL BYTES
1754 MOV BYTS_OF_HDR,AX ;AN005;SAVE FOR LATER
1758 AND FILE_FLAG, RESET_FILE_BIGGER
1759 MOV AX,PARA_OF_HDR ;AN005;GET THE HEADER SIZE (para.)
1760 CMP BUFFER_LEFT,AX ;AC005;buffer_left >= HEADER SIZE
1763 MOV AX, BUFFER_LEFT ;buffer_left in para
1764 SUB AX,PARA_OF_HDR ;AC005;consider header size in advance
1766 MUL CX ;* 16. result in DX;AX
1767 CMP HIGH_FILE_SIZE, DX
1768 ; $IF A ;if high_filesize > dx
1770 OR FILE_FLAG, FILE_BIGGER_FLAG
1776 CMP LOW_FILE_SIZE, AX
1779 OR FILE_FLAG, FILE_BIGGER_FLAG
1789 OR FILE_FLAG, FILE_BIGGER_FLAG ;buffer_left < HEADER SIZE
1796 CMP_FILESIZE_TO_BUFFER_LEFT ENDP
1799 SET_BUFFER_PTR PROC NEAR
1800 ;set BUFFER_PTR, BUFFER_LEFT, OLD_BUFFER_PTR in paragraph boundary
1801 ;to be used when reading a file into buffer.
1802 ;this routine uses current BUFFER_PTR to figure out the next BUFFER_PTR.
1803 ;So, at initialization time set BUFFER_PTR to CS, and set AX to the offset
1804 ;of INIT, then the resultant BUFFER_PTR indicates the BUFFER_BASE and
1805 ;OLD_BUFFER_PTR indicates CS.(This means if old_buffer_ptr = cs, then
1806 ;it is the start of buffer)
1807 ;To get the next BUFFER_PTR during multi-copy, just set the AX to the
1808 ;number of bytes read. This routine will add E.A.BUFFER SIZE + 3 para.
1809 ;for header size and will set the next BUFFER_PTR.
1810 ;input: AX - offset of buffer
1811 ; Top_of_memory in segment
1812 ; current BUFFER_PTR
1813 ; current OLD_BUFFER_PTR
1814 ; current BUFFER_LEFT
1815 ;output: BUFFER_PTR for next reading
1817 ; BUFFER_LEFT (Top_of_memory - Buffer_Ptr. If it is 0, then indicates
1818 ; the BUFFER is FULL. In this case, the BUFFER_PTR is
1819 ; invalid, but OLD_BUFFER_PTR keep the former buffer_ptr
1820 ; value which says that it is the last header in the buffer)
1821 ;** Currently this program support maxium top of memory in seg 0FFFF - resident
1822 ; area. This routine will check the overflow case to gaurd the next buffer_ptr
1823 ; not to exceed FFFF.
1827 MOV OLD_BUFFER_PTR, CX ;set old_buffer_ptr
1829 SHR AX, CL ;get paragraphs
1830 INC AX ;get next paragraph
1831 ADD AX,PARA_OF_HDR ;AC005;consider header size
1832 ADD BUFFER_PTR, AX ;add this to the current buffer_ptr
1834 ; $IF NC,AND ;not exceed 16 bit.
1836 MOV AX, Top_of_memory
1837 SUB AX, BUFFER_PTR ;AX = Top_of_memory - Buffer_ptr
1838 ; $IF A ;if buffer_left > 0
1844 MOV BUFFER_LEFT, 0 ;indication of buffer full
1852 WRITE_FROM_BUFFER PROC NEAR
1853 ;Write from the first header starting at buffer_base until finishes
1854 ;the last header which, actually, happens to be the old_buffer_ptr
1855 ;at the time of the call. After the writing, reset the buffer_ptr
1856 ;to buffer_base again for the next read_into_buffer.
1857 ;If continue_info is 1 or 2 (Continue of small, bigfile) then after
1858 ;the creation of a target file, it will set the CREATED_FLAG.
1859 ;This flag will be reset when it found the continue_info to be 3
1861 ;For convenience of use of function call, ES will be used for
1862 ;the program data seg while DS will be used for the BUFFER seg.
1865 PUSH ES ;save ds, es
1868 POP ES ;set ES to program data seg
1870 OR ACTION_FLAG, READING_FLAG ;show reading message next time
1871 ; AND ES:MY_FLAG, RESET_IS_SOURCE ;now, deals with target
1872 ;set this for change_dir
1873 MOV AX, ES:BUFFER_BASE
1877 CMP ES:OLD_BUFFER_PTR, AX ;if old_buffer_ptr = CS then
1878 ;buffer is empty. Just exit
1882 JC WFB_ERROR_BRIDGE ;error?
1884 CMP DS:ATTR_FOUND, Is_subdirectory ;a subdirectory? = 10H
1885 JNE WFB_FILE ;no. a file
1887 MOV AH, ES:T_DEPTH ;yes. a subdir.
1888 CMP DS:DIR_DEPTH, AH ;DIR_DEPTH > T_DEPTH ?
1889 JBE WFB_DEC_DEPTH ;if not, go to parent node
1890 LEA DI, ES:T_DRV_PATH ;else goto child node
1891 LEA SI, DS:FILENAME_FOUND
1892 CMP ES:T_PATH, 0 ;root directory?
1895 MOV AL, 0FFh ;then don't need to put delim since it is already there
1899 MOV AL, Path_delim ;path_delim '\'
1903 call concat_display_path
;modify the path for display
1905 CALL MAKE_DIR
;try to make a new sub directory
1906 JC WFB_EXIT_A_BRIDGE
;there exists a file with same name.
1907 MOV AX, DS ;current buffer seg = old_buffer_ptr?
1908 CMP ES:OLD_BUFFER_PTR
, AX
1909 JNE WFB_NEXT
;not finished yet. jmp to next
1910 OR ES:MY_FLAG
, MISSING_LINK_FLAG
;Finished. Missing link condition occurred regarding empty sub dir
1911 JMP WFB_EXIT_A
;check archieve options.
1913 MOV DS, DS:NEXT_PTR
;let's handles next header.
1914 JMP WFB_CD
;change directory first.
1915 WFB_EXIT_BRIDGE: JMP WFB_EXIT
1916 WFB_ERROR_BRIDGE: JMP WFB_ERROR
1917 WFB_EXIT_A_BRIDGE: JMP WFB_EXIT_A
1919 LEA DI, ES:T_DRV_PATH
1920 CALL RM_EMPTY_DIR
;check flags and remove empty dir
1921 CALL LAST_DIR_OUT
;take off the last dir from path
1922 call cut_display_path
;modify path for display purpose
1923 DEC ES:T_DEPTH
;and decrease depth
1924 JMP WFB_CD
;CHANGE DIR AND compare the depth again.
1926 WFB_FILE: ;Handling a file
1927 AND ES:MY_FLAG
, RESET_MISSING_LINK
;if found a file, then current dir is not empty.
1928 TEST ES:FILE_FLAG
, CREATED_FLAG
; A file handle is created ?
1929 JNZ WFB_WRITE
;yes, skip create again.
1930 CALL CREATE_A_FILE
;create a file in the cur dir
1931 JC WFB_ERROR
;file creation error?
1934 JC WFB_EXIT_A
;target file has been already deleted.
1935 CMP DS:CONTINUE_INFO
, 0
1936 ; $IF E,OR ;if continue_info = 0 or 3
1938 CMP DS:CONTINUE_INFO
, 3
1943 CALL SET_FILE_DATE_TIME
;then set file's date, time
1944 PUSH DS ;AN005;SAVE THE BUFFER PTR
1945 PUSH ES ;AN005;WE NEED THE DATA PTR
1946 POP DS ;AN005;DS = THE DATA PTR
1947 CALL CLOSE_A_FILE
;and close the handle
1948 POP DS ;AN005;DS = THE BUFFER PTR AGAIN
1949 CALL RESTORE_FILENAME_FOUND
;if filename_found has been changed, restore it for reset_s_archieve.
1950 AND ES:FILE_FLAG
, RESET_CREATED
;and reset created_flag
1951 CALL INC_FILE_COUNT
;increase file count
1955 CMP ES:OLD_BUFFER_PTR
, AX ;current header is the last one?
1956 JE WFB_EXIT_A
;then exit
1957 MOV DS, DS:NEXT_PTR
;else set ds to the next ptr
1958 JMP WFB_CHATT
;handle the next header
1960 jmp main_exit
;meaningful when MKDIR failed because
1961 ;of there already exist same named file,
1964 test ES:option_flag
, slash_m
;hard archieve ? - turn off source archieve bit.
1965 jz wfb_exit_B
;no, chk error flag and exit
1966 call reset_s_archieve
;reset source file(s) archieve bit using header info(s).
1968 test ES:copy_status
, mkdir_error_flag
;mkdir error happened?
1969 JNZ WFB_ERROR
;yes, exit
1970 test ES:copy_status
, disk_full_flag
;disk full happened?
1971 JNZ WFB_ERROR
;yes, exit
1973 MOV ES:OLD_BUFFER_PTR
, CS ;set old_buffer_ptr to CS
1974 MOV AX, ES:BUFFER_BASE
1975 MOV ES:BUFFER_PTR
, AX ;set buffer_ptr to base
1976 MOV AX, ES:MAX_BUFFER_SIZE
1977 MOV ES:BUFFER_LEFT
, AX ;set buffer_left
1980 TEST SYS_FLAG
, ONE_DISK_COPY_FLAG
;one drive letter copy?
1983 CALL CHANGE_S_DIR
;then change current dir to s dir
1987 WRITE_FROM_BUFFER ENDP
1989 INC_FILE_COUNT PROC
NEAR
1990 ;increase the file count by one.
1991 ;increase file_cnt_low, file_cnt_high.
1996 INC ES:FILE_CNT_HIGH
;if carry over, then inc file_cnt_high
2001 RM_EMPTY_DIR PROC
NEAR
2002 ;check the slash_E option, missing_link_flag. Remove the empty directory
2003 ;from the target disk.
2006 ; DI - points to the current target drv, path
2008 TEST ES:OPTION_FLAG
, SLASH_E
;user want to copy empty subdir?
2009 JNZ RED_EXIT
;then exit
2010 TEST ES:MY_FLAG
, MISSING_LINK_FLAG
;missing informations for not to copying empty dir
2011 ;at the tree travesal phase?
2013 CALL SWITCH_DS_ES
;ds - data, es - buffer
2014 MOV DX, OFFSET T_PARENT
;chdir to parent dir
2018 POP DX ;DS:DX points to drv, path
2019 MOV AH, 3
Ah ;REMOVE SUBDIR
2021 CALL SWITCH_DS_ES
;restore ds, es
2026 RESTORE_FILENAME_FOUND PROC
NEAR
2027 ;when the filename_found has been Revised according to the user's specified
2028 ;input parm, then restore the original source filename in filename_found.
2029 ;This will be used when reset_s_archieve routine reset the source file's
2034 CMP ES:T_FILENAME
, 0 ;if t_filename ot t_template is not blank,
2035 ; $IF NE,OR ;then filename_found has been Revised.
2037 CMP ES:T_TEMPLATE
, 0
2041 CALL SWITCH_DS_ES
;DS - data seg, ES - buffer
2043 LEA SI, DS:DISP_S_FILE
;we know filename_found has been save into DISP_S_FILE when create the file.
2044 LEA DI, ES:FILENAME_FOUND
;use this to restore source filename this time.
2045 REP MOVSB ;disp_s_file => filename_found
2046 CALL SWITCH_DS_ES
;restore ds, es
2050 RESTORE_FILENAME_FOUND ENDP
2052 RESET_S_ARCHIEVE PROC
NEAR
2056 TEST ES:COPY_STATUS
, DISK_FULL_FLAG
;called when disk full?
2057 JZ RSA_START
;no, just goto start
2059 MOV AX, DS ;current DS when called
2060 CMP ES:BUFFER_BASE
, AX ;current DS(BUFFER) is the first one?
2061 JE RSA_EXIT_BRIDGE
;yes, just exit
2062 MOV AX, DS:BEFORE_PTR
;set old_buffer_ptr to the header
2063 MOV ES:OLD_BUFFER_PTR
, AX ;that is just before the troubled one.
2065 MOV AX, ES:BUFFER_BASE
2066 MOV DS, AX ;set DS to buffer base again to start traveling
2068 CALL CHANGE_ARC_S_DIR
;change souce dir
2070 CMP DS:ATTR_FOUND
, Is_subdirectory
; = 10h
2071 JNE RSA_FILE
;no a file
2073 MOV AH, ES:S_ARC_DEPTH
;yes, a subdir
2074 CMP DS:DIR_DEPTH
, AH ;dir_depth > s_arc_depth?
2075 JBE RSA_DEC_DEPTH
;if not, goto parent node
2076 LEA DI, ES:S_ARC_DRV_PATH
2077 LEA SI, DS:FILENAME_FOUND
2078 CMP ES:S_ARC_PATH
, 0 ;root dir?
2085 MOV AL, Path_delim
;path_delim '\'
2091 CMP ES:OLD_BUFFER_PTR
, AX
2092 JE RSA_EXIT_A
;finished. Set the source current dir and return to caller
2093 MOV DS, DS:NEXT_PTR
;else let's handles next header
2094 JMP RSA_CD
;chdir first.
2096 CALL CHANGE_ARC_S_DIR
;to restore the same current source dir
2097 ;as that of the READ_INTO_BUFFER proc.
2098 RSA_EXIT_BRIDGE:JMP RSA_EXIT
2100 LEA DI, ES:S_ARC_DRV_PATH
2105 CMP DS:CONTINUE_INFO
, 0
2108 CMP DS:CONTINUE_INFO
, 3
2112 CALL CHANGE_S_FILEMODE
;change source file mode
2116 CMP ES:OLD_BUFFER_PTR
, AX ;current header is the last one?
2121 OR ES:SYS_FLAG
, DEFAULT_S_DIR_fLAG
;this is for restoring default source dir before exit to DOS.
2122 RET ;return to caller
2123 RESET_S_ARCHIEVE ENDP
2125 CHANGE_S_FILEMODE PROC
NEAR
2129 LEA DX, DS:FILENAME_FOUND
2131 MOV AL, 0 ;get attribute in CX
2135 AND CX, 0FFDFh ;turn off the archieve bit
2138 CHANGE_S_FILEMODE ENDP
2140 CHANGE_ARC_S_DIR PROC
NEAR
2141 ;change the source directory according to S_ARC_DRV_PATH
2148 MOV S_ARC_DRV
[2], '\' ;LAST_DIR_OUT have took '\' out?
2149 MOV S_ARC_DRV
[3],0 ;then restore it
2152 MOV DX, OFFSET S_ARC_DRV_PATH
;use full drv, path
2153 MOV AH, CHDIR
; = 3Bh
2157 OR COPY_STATUS
, CHDIR_ERROR_FLAG
2158 CALL EXTENDED_ERROR_HANDLER
2163 CHANGE_ARC_S_DIR ENDP
2166 CONCAT_DISPLAY_PATH PROC
NEAR
2167 ;concatenate subdirectory name found from the header to DISP_S_PATH which
2168 ;will be used for display copying file messages.
2169 ;if slash_p option has been set, then just return.
2173 TEST ES:OPTION_FLAG
, SLASH_P
;prompt option?
2176 LEA DI, ES:DISP_S_PATH
2177 LEA SI, DS:FILENAME_FOUND
2178 CMP ES:T_DEPTH
, 0 ;this will be the first child directory?
2181 MOV AL, 0FFh ;then do not put '\' between them
2185 MOV AL, Path_delim
;else put '\'
2189 ; $ENDIF ;else just return
2192 CONCAT_DISPLAY_PATH ENDP
2194 CUT_DISPLAY_PATH PROC
NEAR
2195 ;take the last dir out from the DISP_S_PATH for display copy messages.
2196 ;if prompt option has been set, just return.
2197 ;INPUT: DS - buffer header
2201 TEST ES:OPTION_FLAG
, SLASH_P
;prompt?
2206 POP DS ;ds = es = data seg
2207 MOV SI, OFFSET DISP_S_PATH
;for CHK_DRV_LETTER
2208 MOV DI, OFFSET DISP_S_PATH
;for LASR_DIR_OUT
2211 ; $IF C ;failure? no '\' found
2213 CALL CHK_DRV_LETTER
;drive letter?
2214 ; $IF NC ;yes. "D:filename",0 case
2216 MOV BYTE PTR DS:[SI], 0 ;make it "D:",0 since SI now points to the next chr
2217 ; $ELSE ;no. "filename",0 case
2220 MOV BYTE PTR [DI], 0 ;set DISP_S_PATH to 0
2223 ; $ELSE ;found '\' and last '\' became 0
2226 CMP T_DEPTH
, 1 ;now going to the starting path?
2227 ; $IF E ;yes. restore it for concat_display_path routine.
2229 MOV DI, AX ;we want to restore '\' and put 0 just after that.
2230 DEC DI ;for ex, "D:\DIR1"=>"D:"=>"D:\" -- original starting path
2231 MOV BYTE PTR [DI], '\' ; "D:dir1\dir2"=>"D:dir1"(starting path) => "D:dir1\"
2232 MOV BYTE PTR [DI+1], 0
2237 POP DS ;restore ds to buffer header
2241 CUT_DISPLAY_PATH ENDP
2245 ;***************************************************************************
2246 CHK_DRV_LETTER PROC NEAR
2247 ; ** CHECK CURRENT CHR IS ALPHA CHR FOLLOWED BY COLON. *
2248 ; INPUT: DS:SI POINTS TO THE CURRENT CHR TO BE CHECKED. *
2249 ; OUTPUT: FOUND - SI POINTS TO THE NEXT CHR. *
2250 ; IF THIS HAD BEEN A LAST WORD, ZERO FLAG WILL BE SET. *
2251 ; NOT FOUND - CARRY IS SET. DI, CX UNCHANGED. *
2252 ;***************************************************************************
2255 PUSH SI ;AN010;IN CASE DRIVE LETTER NOT FOUND
2258 CLC ;AN010;INITIALIZE TO NOT DBCS
2259 MOV AL,DS:BYTE PTR [SI] ;AN010;GET THE 1st CHAR TO TEST
2260 CALL CHK_DBCS ;AN010;SEE IF WE ARE IN DBCS
2261 ; $LEAVE NC ;AN010;THIS IS NOT DBCS
2263 INC SI ;AN010;GO TO THE NEXT CHAR TO CHECK
2269 JB CK_DR_1 ;LESS THAN 'A
', THEN NOT FOUND.
2271 JA CK_DR_1 ;ABOVE 'Z', THEN NOT FOUND.
2272 MOV AL, DS:BYTE PTR [SI+1] ;LOOK AHEAD THE FOLLOWING CHR.
2273 CMP AL, ':' ;SHOULD BE A COLON.
2274 JNZ CK_DR_1 ;NOT FOUND.
2275 POP AX ;AN010;THROW AWAY SAVED SI
2276 INC SI ;FOUND. SI TO THE NEXT CHR.
2281 POP SI ;AN010;RESTORE SI TO ENTRY VALUE
2289 CREATE_A_FILE PROC NEAR
2290 ;create a file in the header and return the file handle in T_HANDLE.
2291 ;Set CREATED_FLAG. This will be reset by WRITE_FROM_BUFFER when it
2293 ;this routine will check the T_FILENAME and T_TEMPLATE if any target
2294 ;filename has been entered. If T_FILENAME is there, then DX will
2295 ;points to this (This is the case when the user has specified non_global
2296 ;chr filename and any source filename be changed to this name.)
2297 ;If T_TEMPLATE is present, then modify the filename found in the
2299 ;Also, this routine show copy messages just before a file creation using
2307 ;save the original filename from the header
2308 MOV CX, 13 ;max 13 chr
2309 LEA SI, DS:FILENAME_FOUND ;original source file name
2310 LEA DI, ES:DISP_S_FILE ;filename to be displayed
2311 REP MOVSB ;filename_found => disp_s_file
2312 test es:option_flag, slash_p
2315 CALL SHOW_COPY_MESSAGE ;show the source path, file
2319 CMP ES:T_FILENAME, 0
2320 ; $IF NE ;non_global target filename entered.
2322 TEST ES:COPY_STATUS, MAYBE_ITSELF_FLAG
2325 LEA SI, DS:FILENAME_FOUND
2326 LEA DI, ES:T_FILENAME
2327 CALL COMP_FILENAME ;compare it. if same then show
2328 ;file cannot be copied onto itself and
2333 CALL SWITCH_DS_ES ;now ds - data, es - buffer
2335 LEA SI, DS:T_FILENAME
2336 LEA DI, ES:FILENAME_FOUND
2337 REP MOVSB ; t_filename => filename_found
2338 MOV AL, NUL ;AN014;DOS NEEDS A NUL TO TERM.
2339 MOV ES:TERMINATE_STRING,AL ;AN014;PUT IT IN THE HEADER
2340 CALL SWITCH_DS_ES ;now ds - buffer, es - data seg
2345 CMP ES:T_TEMPLATE, 0 ;global chr target filename entered?
2346 ; $IF NE ;yes, entered. modify the filename found
2348 CALL MODIFY_FILENAME
2349 TEST ES:COPY_STATUS, MAYBE_ITSELF_FLAG
2352 LEA SI, DS:FILENAME_FOUND ;compare the Revised filename
2353 LEA DI, ES:DISP_S_FILE ;with original name
2354 CALL COMP_FILENAME ;if same, then issue error message and exit
2360 TEST ES:COPY_STATUS, MAYBE_ITSELF_FLAG ;*.* CASE
2364 POP DS ;ds - data seg
2366 ; Set message parameters
2367 MOV AX,MSG_COPY_ITSELF ;AN000;
2368 MOV MSG_NUM,AX ;AN000; set message number
2369 MOV SUBST_COUNT,NO_SUBST ;AN000; no message subst.
2370 MOV MSG_CLASS,UTILITY_MSG_CLASS ;AN000; message class
2371 MOV INPUT_FLAG,NO_INPUT ;AN000; no user input
2372 CALL PRINT_STDERR ;AN000; display error
2380 ;-------------------------------------------------------------------------
2381 ; Use extended open DOS call to create the target file, use attribute list
2382 ; obtained from the previous Get Extended attribute DOS call
2383 ;-------------------------------------------------------------------------
2384 MOV AX, Ext_Open ;AN000; = 6Ch
2385 MOV BX,CREATE_MODE ;AN000;CREATE MODE = 0002H
2386 MOV CX,CREATE_ATTR ;AN000; attribute = 0
2387 MOV DX,CREATE_FLAG ;AN000; flag = 0112H
2388 MOV SI,OFFSET TARGET_DRV_LET ;AN005; DS:SI-->NAME TO CREATE
2389 MOV DI,NUL_LIST ;AN012; ES:DI = -1
2390 INT 21H ;AN000; create file
2392 JC CAF_ERROR ;AN000;
2393 MOV ES:T_HANDLE, AX ;AN000;save handle
2395 CALL CHK_T_RES_DEVICE ;check target handle is a reserved dev
2397 MOV AX,SET_ATTRIB ;AN012;5704H
2398 CALL SWITCH_DS_ES ;AN013;now ds - data, es - buffer
2399 MOV BX,T_HANDLE ;AC013;THE FILE HANDLE
2400 LEA DI,ES:ATTRIB_LIST ;AN013;PARAMETER LIST (ES:DI)
2401 INT 21H ;AN012;SET EXTENDED ATTRIBUTES
2402 CALL SWITCH_DS_ES ;AN013;now es - data, ds - buffer
2403 JC CAF_ERROR ;AN012;
2405 OR ES:FILE_FLAG, CREATED_FLAG ;set created_flag
2411 OR COPY_STATUS, CREATE_ERROR_FLAG
2412 CALL EXTENDED_ERROR_HANDLER
2420 chk_t_res_device proc near
2421 ;check the target handle if it is for reserved device
2422 ;input: ES - data seg
2424 ; AX - filehandle created
2426 cmp es:t_filename,0 ;if no user specified filename
2427 jne ctrd_ioctl ;then should not be a reserved device name
2431 mov bx, ax ;file handle
2432 mov ax, 4400h ;IOCTL get device info.
2434 test dx, 80h ;is device? (not a block device?)
2437 POP DS ;AN000;ds - data seg
2439 ; Set message parameters
2440 MOV AX,MSG_RES_T_NAME ;AN000; message number
2441 MOV MSG_NUM,AX ;AN000; set message number
2442 MOV SUBST_COUNT,NO_SUBST ;AN000; no message substitution
2443 MOV MSG_CLASS,UTILITY_MSG_CLASS ;AN000; message class
2444 MOV INPUT_FLAG,NO_INPUT ;AN000; no input
2445 CALL PRINT_STDOUT ;AN000; display message
2449 chk_t_res_device endp
2451 MODIFY_FILENAME PROC NEAR
2452 ;modify the filename in the header using T_TEMPLATE.
2457 PUSH DS ;save ds, es = data seg
2462 MOV ES, ES:PSP_SEG ;ES points to PSP
2463 MOV DI, PSPFCB2_DRV ;DI points to FCB2, 6c
2464 MOV SI, OFFSET DS:TARGET_DRV_LET ;filename found, DS = buffer header
2465 MOV AH, 29H ;parse a filename
2466 MOV AL, 0 ;control bits
2467 INT 21h ;unfold the filename found into PSP FCB2 area
2469 POP DS ;now DS=data seg, ES=PSP seg
2470 MOV SI, OFFSET T_TEMPLATE ;SI points to template
2472 INC DI ;DI points to the formatted filename
2478 ; $LEAVE E ;yes. exit
2480 LODSB ;[SI] => AL, SI = SI + 1
2481 CMP AL, '?
' ;global chr?
2484 INC DI ;just skip the corresponding target chr
2488 STOSB ;change the target chr to this. DI = DI + 1
2496 POP ES ;now ES = Buffer
2497 MOV DI, OFFSET ES:FILENAME_FOUND ; di points to filename in the header
2498 MOV DS, PSP_SEG ;DS = PSP seg
2500 INC SI ;di points to Revised filename
2501 CALL COMPRESS_FILENAME ;fold it
2506 MODIFY_FILENAME ENDP
2509 COMP_FILENAME PROC NEAR
2510 ;this routine is called when MAYBE_COPY_ITSELF flag in on.
2511 ;SI, DI asciiz string will be compared and if they are identical
2512 ;the show "Cannot copy onto itself" msg and jmp to main_exit.
2519 CALL STRING_LENGTH ;CX get the length of string
2520 MOV BX, CX ;now, BX got the length of the target filename entered.
2525 POP ES ;now ES set to DS
2527 POP DI ;now DI points to the source filename found.
2530 CALL STRING_LENGTH ;CX got the length of the string
2536 CMP BX, CX ;COMPARE LENGTH
2537 JNE CF_EXIT ;IF THEY ARE DIFFERENT, EXIT
2539 REPE CMPSB ;compare SI, DI until not equal,
2540 CMP CX, 0 ;finish at cx = 0?
2545 POP DS ;ds = data seg
2547 ; Set message parameters
2548 MOV AX,MSG_COPY_ITSELF ;AN000; message number
2549 MOV MSG_NUM,AX ;AN000; set message number
2550 MOV SUBST_COUNT,NO_SUBST ;AN000; no message substitution
2551 MOV MSG_CLASS,UTILITY_MSG_CLASS ;AN000; message class
2552 MOV INPUT_FLAG,NO_INPUT ;AN000; no input
2553 CALL PRINT_STDERR ;AN000; display error message
2560 SHOW_COPY_MESSAGE PROC NEAR
2561 ;show the source path, filename that is ready for creation in the target disk.
2562 ;INPUT: ES - data seg
2563 ; DS - buffer header seg
2567 POP DS ;DS = data seg
2569 LEA SI,SUBLIST1 ;AN000; get addressability to list
2570 LEA DX,DISP_S_PATH ;AN000; offset to path name
2571 MOV [SI].DATA_OFF,DX ;AN000; save offset
2572 MOV [SI].DATA_SEG,DS ;AN000; save data segment
2573 MOV [SI].MSG_ID,1 ;AN000; message ID
2574 MOV [SI].FLAGS,010H ;AN000; ASCIIZ string, left align
2575 MOV [SI].MAX_WIDTH,0 ;AN000; MAXIMUM FIELD WITH
2576 MOV [SI].MIN_WIDTH,0 ;AN000; MINIMUM FIELD WITH
2578 LEA SI,SUBLIST2 ;AN000; get addressability to list
2579 LEA DX,DISP_S_FILE ;AN000; offset to file name
2580 MOV [SI].DATA_OFF,DX ;AN000; save offset
2581 MOV [SI].DATA_SEG,DS ;AN000; save data segment
2582 MOV [SI].MSG_ID,2 ;AN000; message ID
2583 MOV [SI].FLAGS,010H ;AN000; ASCIIZ string, left align
2584 MOV [SI].MAX_WIDTH,0 ;AN000; MAXIMUM FIELD WITH
2585 MOV [SI].MIN_WIDTH,0 ;AN000; MINIMUM FIELD WITH
2587 LEA SI,SUBLIST1 ;AN000;
2588 CMP ES:T_DEPTH, 0 ;starting directory?
2591 MOV AX,S_PATH_FILE0 ;AN000;NO BACK SLASH BETWEEN PATH,FNAME
2596 MOV AX,S_PATH_FILE1 ;AN000;BACK SLASH IS BETWEEN PATH,FNAME
2600 MOV MSG_NUM,AX ;AN000; set message number
2601 MOV SUBST_COUNT,PARM_SUBST_TWO ;AN000; substitution count = 2
2602 MOV MSG_CLASS,UTILITY_MSG_CLASS ;AN000; message class
2603 MOV INPUT_FLAG,NO_INPUT ;AN000; no input
2604 CALL PRINT_STDOUT ;show message "Reading source
2607 SHOW_COPY_MESSAGE ENDP
2609 WRITE_A_FILE PROC NEAR
2610 ;write a file from the data area in the buffer.
2611 ;Remember the caller is WRITE_FROM_BUFFER which use ES for
2612 ;the program data area and DS for the header in the buffer.
2614 MOV AH, Write ; = 40h
2615 MOV BX, ES:T_HANDLE ;handle saved in the program data area
2616 MOV DX, ES:BYTS_OF_HDR ;AC005;skip header
2617 MOV CX, DS:CX_BYTES ;get the # from the header
2619 JC WAF_ERROR ;write error
2624 CALL CLOSE_DELETE_FILE ;close delete troubled file
2625 OR COPY_STATUS, WRITE_ERROR_FLAG
2626 CALL SWITCH_DS_ES ;AN000;DS = DATA SEG, ES = BUFFER
2627 CALL EXTENDED_ERROR_HANDLER
2628 CALL SWITCH_DS_ES ;AN000;ES = DATA SEG, DS = BUFFER
2630 MOV ERRORLEVEL, 4 ;set errorlevel
2632 ; Set message parameters
2633 ; Target disk full, critical error
2635 PUSH DS ;AN000;DS = BUFFER
2636 PUSH ES ;AN000;ES = DATA SEG
2637 POP DS ;AN000;ES => DS = DATA SEG
2638 MOV AX,MSG_DISK_FULL ;AN000; message number
2639 MOV MSG_NUM,AX ;AN000; set message number
2640 MOV SUBST_COUNT,NO_SUBST ;AN000; no message substitution
2641 MOV MSG_CLASS,UTILITY_MSG_CLASS ;AN000; message class
2642 MOV INPUT_FLAG,NO_INPUT ;AN000; no input
2643 CALL PRINT_STDERR ;AN000; display error message
2644 OR COPY_STATUS, DISK_FULL_FLAG ;set disk_full_flag
2645 POP DS ;AN000;RESTORE DS = BUFFER
2646 CALL CLOSE_DELETE_FILE
2647 STC ;set carry and return to caller
2652 SET_FILE_DATE_TIME PROC NEAR
2653 ;input: BX - target file handle
2655 MOV AH, File_date_time ; = 57h
2656 MOV AL, Set_file_time ; = 1
2657 MOV CX, DS:FILE_TIME_FOUND
2658 MOV DX, DS:FILE_DATE_FOUND
2661 SET_FILE_DATE_TIME ENDP
2663 CLOSE_A_FILE PROC NEAR
2665 ;CLOSE A FILE AND UPDATE COUNT OF OPEN FILES
2667 ;INPUT: BX - file handle to be closed
2669 CMP OPEN_FILE_COUNT,NUL ;AN005;ARE THERE ANY OPEN FILES?
2672 DEC OPEN_FILE_COUNT ;AN005;IF SO, REDUCE THE COUNT BY 1.
2675 MOV AH, Close ; = 3Eh
2680 DELETE_A_FILE PROC NEAR
2681 ;input: DS:DX - points to ASCIIZ string
2689 ;make a subdirectory in the current target directory.
2690 ;The directory name is in the header part Target_drv_Let
2691 ;with the drive letter.
2695 MOV AH, Mkdir ; = 39h
2696 MOV DX, OFFSET DS:TARGET_DRV_LET ;target drv and filename
2701 ;cannot distinguish between cases of: 1. already there exists a directory.
2702 ; 2. there has been a file exist with the same name in the target.
2703 ; 3. no disk space to make dir.
2704 ; Case 1, should ignore and just exit this routine
2705 ; Case 2, critical error.
2706 ; Case 3, critical error.
2707 call chk_disk_full ;check disk full condition first
2708 jc MD_EXIST ;AC026;yes, disk full, check if exist
2709 push es ;else check a file with the same name.
2712 mov ah, 2fH ;get current DTA addr in ES:BX
2717 int 21h ;set dta to psp default dta area
2718 pop dx ;restore DX - target drv and filename
2719 pop ds ;restore DS - buffer
2720 mov cx, 6 ;HIDDEN + SYSTEM inclusive search
2721 mov ah, 4Eh ;FIND FIRST MATCHING FILE
2723 jc md_ok ;not found. There exists subdir. ignore
2724 stc ;else found a file with same name.
2725 jmp short MD_RESTORE
2728 clc ;else there exists dir., ignore error.
2731 push ds ;save ds again - buffer
2732 push es ;es - save dta seg
2733 pop ds ;ds = saved DTA seg
2734 mov dx, bx ; saved DTA off
2736 int 21h ;restore DTA
2740 jnc md_exit ;if no error, then exit
2743 ;else check a file with the same name.
2749 mov ah, 2fH ;AN026;get current DTA addr in ES:BX
2751 mov ds, es:psp_seg ;AN026;
2754 int 21h ;AN026;set dta to psp default dta area
2755 pop dx ;AN026;restore DX - tar drv and filenm
2756 pop ds ;AN026;restore DS - buffer
2757 mov cx, 10h ;AN026;sub-directory search
2758 mov ah, 4Eh ;AN026;FIND FIRST MATCHING dir.
2761 pushf ;AN026;save carry state
2762 push ds ;AN026;save ds again - buffer
2763 push es ;AN016;es - save dta seg
2764 pop ds ;AN026;ds = saved DTA seg
2765 mov dx, bx ;AN026; saved DTA off
2767 int 21h ;AN026;restore DTA
2768 pop ds ;AN026;restore ds
2769 popf ;AN026;get carry state from find
2770 pop es ;AN026;restore ES
2771 jnc md_exit ;AN026;if no error, then dir. exits
2774 call switch_ds_es ;switch ds, es
2775 mov errorlevel, 4 ;set the errorlevel to 4
2776 test copy_status, disk_full_flag ;disk full?
2777 jnz MD_FULL ;yes, full.
2778 mov ax,msg_unable_create ; else make dir fails because of
2779 ; the same file name
2780 or copy_status, mkdir_error_flag ;set make dir error flag
2783 mov ax,msg_disk_full
2785 ; Set message parameters
2786 PUSH ES ;AN017;ES = BUFFER
2787 PUSH DS ;AN017;DS = DATA SEG
2788 POP ES ;AN017;DS => ES = DATA SEG
2789 MOV MSG_NUM,AX ;AN000; set message number
2790 MOV SUBST_COUNT,NO_SUBST ;AN000; no message substitution
2791 MOV MSG_CLASS,UTILITY_MSG_CLASS ;AN000; message class
2792 MOV INPUT_FLAG,NO_INPUT ;AN000; no input
2793 CALL PRINT_STDERR ;AN000; display message
2794 POP ES ;AN017;RESTORE ES = BUFFER
2796 call switch_ds_es ;restore ds, es
2797 stc ;error - set carry
2802 CHK_DISK_FULL PROC NEAR
2803 ;check target disk space, and if no more clusters then set carry, disk_full_flag.
2804 ;this routine is called by MAKE_DIR routine.
2811 MOV AH, 36h ;GET DISK FREE SPACE
2812 MOV DL, ES:T_DRV_NUMBER ;OF TARGET
2814 CMP BX, 0 ;NO MORE CLUSTER?
2819 OR ES:COPY_STATUS, DISK_FULL_FLAG ;SET DISK FULL FLAG
2831 CHK_FILE_NOT_FOUND PROC NEAR
2832 ;if FILE_CNT_LOW=FILE_CNT_HIGH=FOUND_FILE_FLAG=0 AND NO INIT ERROR,
2833 ; then show "File not found" msg
2834 ;INPUT: ES, DS = data seg
2836 TEST PARM_FLAG, INIT_ERROR_FLAG
2837 ; $IF Z,AND ;no init error
2842 CMP FILE_CNT_HIGH, 0
2845 CMP FOUND_FILE_FLAG, 0
2848 MOV ES, PSP_SEG ;use PSP area for parsing
2850 MOV SI, OFFSET S_FILE
2852 MOV AL, 0 ;control byte
2854 CALL SWITCH_DS_ES ;now, ds - psp seg, es - data seg
2855 MOV DI,OFFSET DISP_S_FILE
2857 INC SI ;now SI points to the formatted filename area
2858 CALL COMPRESS_FILENAME ;[pspfcb1_drv+1] => disp_s_file
2860 POP DS ;now DS=ES=data seg
2861 LEA SI,SUBLIST1 ;AN000;
2862 MOV DI,OFFSET DISP_S_FILE ;AN000;
2863 MOV [SI].DATA_OFF,DI ;AN000; SI-->File name
2864 MOV [SI].DATA_SEG,DS ;AN000; DS-->Segment
2865 MOV [SI].MSG_ID,0 ;AN018; message ID
2866 MOV [SI].FLAGS,010H ;AN000; ASCIIZ string, left align
2867 MOV [SI].MAX_WIDTH,0 ;AN000; MAXIMUM FIELD WITH
2868 MOV [SI].MIN_WIDTH,0 ;AN000; MINIMUM FIELD WITH
2869 MOV AX,MSG_FILE_NOT_ERR ;AN018;
2870 MOV MSG_NUM,AX ;AN000; set message number
2871 MOV SUBST_COUNT,PARM_SUBST_ONE ;AN000; substitution count
2872 MOV MSG_CLASS,UTILITY_MSG_CLASS ;AN000; message class
2873 MOV INPUT_FLAG,NO_INPUT ;AN000; no input
2874 CALL PRINT_STDOUT ;AN000; display message
2880 CHK_FILE_NOT_FOUND ENDP
2883 subttl string_length
2885 ;******************************************************************************
2886 ;PURPOSE: Get the length of a string pointed by ES:DI until it encounters
2887 ; the same character given by the user in AL.
2888 ; The length will be an output in CX. The number includes the
2890 ; For example, if you want to determine the length of an ASCIIZ string,
2891 ; set ES:DI to that string and set AL to 0. The output CX is the
2892 ; total length of the ASCIIZ string including 0.
2893 ; So, if the first character pointed by DI is the same as that of AL,
2894 ; then the length will be 1.
2895 ; !!! It is the user's responsibility to make it sure that the string
2896 ; contains the character given in AL. If not, unpredictable
2897 ; results will occur.!!!
2900 ; REGISTERS: AL - ASCII CHARACTER
2901 ; ES:DI - POINTER TO THE STRING.
2903 ; REGISTERS: AX,DX,SI etc - PRESERVED.
2905 ; CX - STRING LENGTH UNTIL FOUND THE GIVEN CHARACTER.
2906 ; DI - POINTS TO THE NEXT CHARACTER AFTER THE STRING.
2907 ; DIRECTION FLAG - CLEARED
2909 ;******************************************************************************
2911 STRING_LENGTH PROC NEAR
2912 PUBLIC STRING_LENGTH
2913 CLD ;CLEAR DIRECTION
2914 MOV BX,DI ;SAVE ORIGINAL DI VALUE
2915 MOV CX,80H ;TRY MAX 128 BYTES
2916 REPNE SCASB ;SCAN THE STRING UNTIL FOUND
2917 PUSH DI ;SAVE CURRENT DI VALUE WHICH POINTS TO NEXT CHR AFTER STRING
2918 SUB DI,BX ;GET THE LENGTH
2919 MOV CX,DI ;MOV THE LENGTH TO CX
2924 subttl concat_asciiz
2926 ;******************************************************************************
2927 ;PURPOSE: Concatenate two ASCIIZ string into one ASCIIZ string.
2928 ; The ASCIIZ string pointed by DS:SI will be concatenated to
2929 ; the one pointed by ES:DI. The result string will be pointed by
2931 ; AL is used to put the delimeter character in between the strings.
2932 ; If you *DON'T* like to put the delimeter ***make AL to 0FFh***.
2933 ; For example, assume sting1 "ABCDE",0 pointed by DI and string2
2934 ; "FGHI",0 pointed by SI.
2935 ; If you want a delimeter "\" between two string, set AL to "\"
2936 ; before calling. The result will "ABCDE\FGHI",0 pointed by DI.
2937 ; If you set AL to "0FFh", then it becomes "ABCDEFGHI",0.
2938 ; This feature is useful for handling PATH if you set AL to "\"
2939 ; and, for any general string processes if you set AL to "0FFh".
2940 ; This routine will call subroutine STRING_LENGTH.
2942 ; REGISTERS: AL - DELIMETER OR 0FFh
2943 ; ES:DI - POINTER TO THE DESTINATION STRING.
2944 ; DS:SI - POINTER TO THE SOURCE TO BE CONCATENATED.
2946 ; REGISTERS: AL, DX - preserved
2947 ; DI - preserved. POINTER TO THE RESULT STRING
2949 ; CX - RESULT ASCIIZ STRING LENGTH INCLUDE 0
2950 ; DIRECTION FLAG - CLEARED
2951 ;******************************************************************************
2952 CONCAT_ASCIIZ PROC NEAR
2954 PUBLIC CONCAT_ASCIIZ
2955 PUSH DI ;SAVE POINTER VALUE WHICH WILL BE RETRUNED TO CALLER.
2956 PUSH AX ;SAVE VALUE IN AL.
2957 MOV AL, 0 ;DEALING WITH ASCIIZ STRING
2958 CALL STRING_LENGTH ;LET DI POINTS TO THE NEXT CHR AFTER THIS STRING
2959 ;DIRECTION WILL BE CLEARED.
2960 DEC DI ;MAKE DI POINT TO THE LAST CHARACTER 0
2963 ; $IF NE ;IF THE USER WANTS TO PUT DIMIMETER,
2965 STOSB ; REPLACE 0 WITH IT.
2969 DEC CX ;ELSE DECREASE LENGTH BY 1
2974 LODSB ;MOV [SI] TO AL
2975 STOSB ;STORE AL TO [DI]
2976 INC CX ;INCREASE LENGTH
2977 CMP AL, 0 ;WAS IT A LAST CHARACTER?
2978 ; $ENDDO E ;THEN EXIT THIS LOOP
2987 ;******************************************************************************
2988 ;PURPOSE: Take off the last directory name from the path pointed by DI.
2989 ; This routine assumes the pattern of a path to be an ASCIIZ string
2990 ; in the form of "[d:][\]dir1\dir2". Notice that this path does not
2991 ; have entailing "\". This routine will simply travel the string
2992 ; until it found last "\" which will, then, be replaced with 0.
2993 ; If no "\" found, then carry will be set.
2994 ; *** This should be not be used for the path in the form of
2995 ; *** "d:\", 0 for the root directory, since in this case the returned
2996 ; *** string will be "d:",0 and AX value returned be meaningless (Just
2999 ; REGISTERS: DI - points to an ASCIIZ path string.
3000 ; ES - assumed default segment for DI
3002 ; REGISTERS: DI - points to the resultant path string.
3003 ; AX - offset value of the last subdirectory name taken out, in case
3004 ; of the user's need.
3005 ; Other register will be unchanged.
3006 ; CARRY FLAG WILL SET IF NOT FOUND.
3007 ;******************************************************************************
3009 LAST_DIR_OUT PROC NEAR
3013 PUSH SI ;save current DI, SI
3014 CLD ;clear direction
3015 MOV SI, 0FFFFh ;used as a not_found flag if unchanged.
3020 CLC ;AN010;INITIALIZE TO NOT DBCS
3021 MOV AL,BYTE PTR [DI] ;AN010;GET THE 1st CHAR TO TEST
3022 CALL CHK_DBCS ;AN010;SEE IF WE ARE IN DBCS
3023 ; $LEAVE NC ;AN010;THIS IS NOT DBCS
3025 INC DI ;AN010;GO TO THE NEXT CHAR TO CHECK
3032 ; $LEAVE Z ;if [DI] = 0, then end of string. Ends this loop.
3034 DEC DI ;if [DI] <> 0, then go back and scan char again
3035 MOV AL, "\" ;to see it was a back slash.
3037 ; $IF Z ;if it was, then save the addr to SI.
3043 ; $ENDIF ;else do loop again.
3048 CLC ;clear carry flag.
3049 CMP SI, 0FFFFh ;Had SI been changed?
3052 STC ;No, set the carry. Not found.
3056 MOV BYTE PTR ES:[SI], 0 ;Yes, replace "\" with 0. Seg override to get default DI seg.
3058 INC AX ;let AX have the last dir offset value.
3062 POP SI ;restore original value
3063 POP DI ;original string offset
3067 ; HEADER <CHK_DBCS -SEE IF SPECIFIED BYTE IS A DBCS LEAD BYTE>
3068 ;*****************************************************************************
3069 ; Check DBCS environment
3070 ;*****************************************************************************
3072 ; Function: Check if a specified byte is in ranges of the DBCS lead bytes
3073 ; Input: AL = Code to be examined
3074 ; Output: If CF is on then a lead byte of DBCS
3075 ; Register: FL is used for the output, others are unchanged.
3078 Chk_DBCS PROC ;AN010;
3079 PUSH DS ;AN010; save these regs, about to be clobbered
3081 CMP DBCSEV_SEG,0 ;AN010; ALREADY SET ?
3082 ; $IF E ;AN010; if the vector not yet found
3085 MOV AX,6300H ;AN010; GET DBCS EV CALL
3086 INT 21H ;AN010; ds:si points to the dbcs vector
3088 ASSUME DS:NOTHING ;AN010; that function clobbered old DS
3090 MOV DBCSEV_OFF,SI ;AN010; remember where the dbcs vector is
3091 MOV DBCSEV_SEG,DS ;AN010; so next time I don't have to look for it
3095 LDS SI,DWORD PTR DBCSEV_OFF ;AN010;SET DS:SI TO POINT TO THE DBCS VECTOR
3098 CMP WORD PTR [SI],0 ;AN010; vector ends with a nul terminator entry
3099 ; $LEAVE E ;AN010; if that was the terminator entry, quit
3101 CMP AL,[SI] ;AN010; look at LOW value of vector
3102 ; $EXITIF NB,AND ;AN010; if this byte is in range with respect to LOW
3104 CMP AL,[SI+1] ;AN010; look at HIGH value of vector
3105 ; $EXITIF NA ;AN010; if this byte is still in range
3107 STC ;AN010; set flag to say, found a DBCS char.
3108 ; $ORELSE ;AN010; since char not in this vector
3111 ADD SI,2 ;AN010; go look at next vector in dbcs table
3112 ; $ENDLOOP ;AN010; go back and check out new vector entry
3115 CLC ;AN010; set flag to say, this is not a DBCS character
3118 POP SI ;AN010; restore the regs
3121 ; ASSUME DS:DSEG ;AN010; tell masm, DS back to normal
3124 chk_DBCS ENDP ;AN010;
3128 subttl Compress_Filename
3132 ;******************************************************************************
3136 ; Compress the FCB style filename into an ASCIIZ packed name.
3137 ; For example, 'ABC?????EXE
' = > 'ABC?????
.EXE
',0
3138 ; or 'ABC EXE
' = > 'ABC
.EXE
',0
3139 ; Note that the length of the source is *** 11 *** byte long.
3140 ; The max length of result is *** 13 *** bytes long.
3141 ; In the usual practice, the source filename with extention can be obtained
3142 ; by using function call 29h (Parse a Filename). So this routine is
3143 ; an inverse function of fun. 29h except DI should be the *** starting point
3144 ; of destination string *** instead of that of an unopened FCB (When you use
3145 ; fun 29h together with this routine, keep this thing in mind. Also if ES, DS
3146 ; values are different in your program, be careful to use them correctly.)
3147 ;------------------------------------------------------------------------------
3154 ; SI: offset of source unpacked filename with extention
3155 ; DI: offset where the resultant asciiz filename(.ext) will be placed.
3166 ;-----------------------------------------------------------------------------
3186 ;******************************************************************************
3188 COMPRESS_FILENAME PROC NEAR
3189 PUBLIC COMPRESS_FILENAME
3194 LODSB ;[SI] => AL, SI = SI + 1
3195 CMP CX, 10 ;CX > 10 then exit
3198 CMP CX, 8 ;filename extention position
3199 ; $IF B ;CX < 8. handling filename
3201 CMP AL, ' ' ;AL = blank ?
3206 ADD SI, AX ;SI = SI + (7 - CX)
3207 MOV CX, 8 ;then skip to handles extention
3211 STOSB ;AL => [DI], DI = DI + 1
3215 ; $ELSE ;extention part
3221 MOV CX, 11 ;exit this loop
3225 CMP CX, 8 ;the first chr of extention?
3228 PUSH AX ;save cur chr
3229 MOV AL, '.' ;and put a dot
3230 STOSB ; . => [DI], DI = DI + 1
3234 STOSB ;AL => [DI], DI = DI + 1
3244 STOSB ;put 0 at the current [DI]
3248 COMPRESS_FILENAME ENDP
3252 SET_DEFAULT_DRV PROC NEAR
3253 ;change source drv as a default drv for conveniece of find, read operation
3254 ;of source. (handling target should be more specific as for as drive letter
3256 ;input: DL - drive # (0 = A, 1 = B ...)
3258 MOV AH, Select_Disk ; = 0Eh
3260 OR SYS_FLAG, DEFAULT_DRV_SET_FLAG ;indicates default drv has been changed
3261 ;Used for exit the program to restore default drv
3263 SET_DEFAULT_DRV ENDP
3268 ;restore the original source directory.
3273 POP ES ;DS=ES=data seg
3275 TEST SYS_FLAG, DEFAULT_S_DIR_FLAG ;source default direcotry saved?
3278 MOV DX, OFFSET SAV_S_DRV ;saved source drive letter & directory
3280 INT 21h ;restore source
3281 AND SYS_FLAG, RESET_DEFAULT_S_DIR ;reset the flag
3291 ORG_S_T_DEF PROC NEAR
3292 ;retore original target, source and default drv and directory
3293 ;check default_s(t)_dir_flag, default_drv_set_flag to restore source,
3294 ;or target directory and default drive.
3296 TEST SYS_FLAG, TURN_VERIFY_OFF_FLAG ;turn off verify?
3299 MOV AX, 2E00h ;turn it off
3303 TEST SYS_FLAG, DEFAULT_DRV_SET_FLAG ;default drive has been changed?
3306 MOV DL, SAV_DEFAULT_DRV
3308 CALL SET_DEFAULT_DRV ;restore default drv.
3310 ; Following is a fix for PTR 0000012 . The fix is to skip changing default
3311 ; drive directory if source drive is not the default drive.
3313 MOV AL, S_DRV_NUMBER ;AN002; get source drive number
3314 CMP AL, SAV_DEFAULT_DRV ;AN002; src drive is the default drv ?
3315 ; $IF NE ;AC022;NO, SO SEE IF DEF. DRV. IS CHGD.
3317 TEST SYS_FLAG, DEFAULT_DRV_SET_FLAG ;AN022;DEF DRV CHGD?
3318 ; $IF NZ ;AN022;YES, RESET IT
3320 MOV DX, OFFSET SAV_DEF_DIR_ROOT ;AN022;GET THE SETTING
3321 MOV AH, Chdir ;AN022;MAKE THE CALL
3325 ; $ELSE ;AN022;SRC IS DEF DRIVE!
3328 MOV DX, OFFSET SAV_DEF_DIR_ROOT
3330 INT 21H ;restore current dir of default dir
3337 TEST SYS_FLAG, DEFAULT_S_DIR_FLAG ;source default direcotry saved?
3340 MOV DX, OFFSET SAV_S_DRV ;saved source drive letter & directory
3342 INT 21h ;restore source. This is for the case of ERROR exit.
3346 TEST SYS_FLAG, DEFAULT_T_DIR_FLAG ;target default directory saved?
3347 ; $IF NZ ;then assume both source, target default saved
3349 MOV DX, OFFSET SAV_T_DRV ;saved target drive letter & directory
3351 INT 21h ;restore target
3359 CHK_MKDIR_LVL PROC NEAR
3360 ;if starting target directories has been created, and no files has been found to copy,
3361 ;and /E option is not specified, then remove the directories created.
3363 CMP T_MKDIR_LVL, 0 ;target starting directory created?
3366 TEST OPTION_FLAG, SLASH_E ;/E option taken?
3369 CMP FOUND_FILE_FLAG, 0 ;found any file?
3372 CALL T_RM_STARTING_DIR ;then, remove created directories.
3379 T_RM_STARTING_DIR PROC NEAR
3380 ;based on the current target directory, remove directories T_MKDIR_LVL times
3387 MOV DL, T_DRV_NUMBER
3389 MOV AH, Get_Current_Directory
3393 MOV DX, OFFSET T_PARENT ;chdir to the parent directory
3396 MOV DX, OFFSET T_DRV_PATH
3399 MOV DI, OFFSET T_DRV_PATH
3400 CALL LAST_DIR_OUT ;take out the last removed dir name
3401 DEC T_MKDIR_LVL ;decrease the number
3402 CMP T_MKDIR_LVL, 0 ;no more?
3406 T_RM_STARTING_DIR ENDP
3410 ;************************************************************
3412 ;* SUBROUTINE NAME: PRINT_STDOUT
3414 ;* SUBROUTINE FUNCTION:
3415 ;* Display the requested message to the specified handle
3418 ;* Paramters in parater storage area
3419 ;* DS:SI-->Substitution List
3420 ;* ES:DI-->PTR to input buffer if buffered keyboard
3421 ;* input is specified (DL = 0A)
3423 ;* AX = Single character entered if DL=01
3425 ;* ES:DI-->input buffer where string is returned if DL=0A
3427 ;* The message corresponding to the requested msg number will
3428 ;* be written to Standard Out. Message substitution will
3429 ;* be performed if specified
3432 ;* Message will be successfully written to requested handle.
3435 ;* None. Note that theoretically an error can be returned from
3436 ;* SYSDISPMSG, but there is nothing that the application can do.
3438 ;* INTERNAL REFERENCES: SysDispMsg
3440 ;* EXTERNAL REFERENCES:
3443 ;************************************************************
3444 PRINT_STDOUT PROC NEAR ;AN000:
3450 MOV AX,MSG_NUM ;AN000; Message ID
3451 MOV BX,STDOUT ;AN000; standard input message handle
3452 MOV CX,SUBST_COUNT ;AN000; message substitution count
3453 MOV DH,MSG_CLASS ;AN000; message class
3454 MOV DL,INPUT_FLAG ;AN000; Type of INT 10 for KBD input
3456 CALL SYSDISPMSG ;AN000: AX=Extended key value if wait
3458 JNC DISP_DONE ;AN000: If CARRY SET then registers
3459 ;will contain extended error info
3460 ; AX - Extended error Number
3462 ; BL - Suggested action
3463 DISP_DONE: ;AN000: CH - Locus
3469 PRINT_STDOUT ENDP ;AN000:
3474 ;************************************************************
3476 ;* SUBROUTINE NAME: PRINT_STDERR
3478 ;* FUNCTION: Display the requested message to Standard Out
3481 ;* Parameters in parameter storage area
3482 ;* DS:SI-->Substitution List
3483 ;* ES:DI-->PTR to input buffer if buffered keyboard
3484 ;* input is specified (DL = 0A)
3487 ;* AX = Single character entered if DL=01
3489 ;* ES:DI-->input buffer where string is returned if DL=0A
3490 ;* The message corresponding to the requested msg number will
3491 ;* be written to the Standard Error. Message substitution will
3492 ;* be performed if specified
3495 ;* Message will be successfully written to requested handle.
3498 ;* None. Note that theoretically an error can be returned from
3499 ;* SYSDISPMSG, but there is nothing that the application can do.
3501 ;* INTERNAL REFERENCES: SysDispMsg
3503 ;* EXTERNAL REFERENCES: None
3505 ;************************************************************
3506 PRINT_STDERR PROC NEAR ;AN000:
3513 MOV AX,MSG_NUM ;AN000; Message ID
3514 MOV BX,STDERR ;AN000; Handle
3515 MOV CX,SUBST_COUNT ;AN000; message substitution count
3516 MOV DH,MSG_CLASS ;AN000; message class
3517 MOV DL,INPUT_FLAG ;AN000; INT 10 KBD input type
3519 CALL SYSDISPMSG ;AN000: AX=Extended key value if wait
3521 JNC DISP_EXIT ;AN000: If CARRY SET then registers
3522 ;will contain extended error info
3523 ; AX - Extended error Number
3525 ; BL - Suggested action
3526 DISP_EXIT: ;AN000: CH - Locus
3533 PRINT_STDERR ENDP ;AN000:
3540 EXTENDED_ERROR_HANDLER PROC NEAR
3541 ;This routine calls fun 59(Get extended error) and
3542 ;check the actions returned. If it is Immediate exit, then jmp to JUST_EXIT
3543 ;If it is abort, then jmp to MAIN_EXIT.
3544 ;Or else, it check the COPY_STATUS flag. If is not open, read, create or
3545 ;write, then it is considered as a critical error and jmp to MAIN_EXIT.
3547 ; too many open files
3551 ;then show the message and jmp to the MAIN_EXIT.
3552 ; *** Currently, this routine directly jump to the main_exit instead of
3553 ; *** returing to the caller. The reason is we regard the above error conditions
3554 ; *** as being not suitable to continue copying and, hence, to simplify
3555 ; *** the error process.
3559 ; ALL THE REG PRESERVED
3566 POP ES ;AN000;DS = ES = DATA SEG
3570 MOV AH, 59h ;get extended error
3571 MOV BX, 0 ;version 3.0
3575 MOV ERRORLEVEL, 4 ;error in operation
3576 TEST COPY_STATUS, OPEN_ERROR_FLAG ;open error?
3577 JNZ OPEN_ERROR_RTN ;yes
3578 TEST COPY_STATUS, READ_ERROR_FLAG ;read error?
3580 TEST COPY_STATUS, CREATE_ERROR_FLAG ;create error?
3581 JNZ CREATE_ERROR_RTN
3582 TEST COPY_STATUS, WRITE_ERROR_FLAG ;write error?
3584 TEST COPY_STATUS, CHDIR_ERROR_FLAG ;chdir error?
3586 JMP SHORT GOTO_MAIN_EXIT
3588 OPEN_ERROR_RTN: ;open error. show error message and exit
3589 CALL SHOW_S_PATH_FILE_ERR ;show the troubled path filename
3590 CALL SHOW_ERROR_MESSAGE
3591 JMP SHORT GOTO_MAIN_EXIT ;abort
3594 CALL SHOW_S_PATH_FILE_ERR
3595 CALL SHOW_ERROR_MESSAGE ;show message and abort
3596 JMP SHORT GOTO_MAIN_EXIT
3599 CMP AX, 2 ;"file not found" to create?
3601 ; Set message parameters
3602 MOV AX,MSG_FILE_CREATE_ERR ;AN000; message number
3603 MOV MSG_NUM,AX ;AN000; set message number
3604 MOV SUBST_COUNT,NO_SUBST ;AN000; no message substitution
3605 MOV MSG_CLASS,UTILITY_MSG_CLASS ;AN000; message class
3606 MOV INPUT_FLAG,NO_INPUT ;AN000; no input
3607 CALL PRINT_STDERR ;show "File creation error" message
3608 ;instead of "File not found"
3609 JMP SHORT GOTO_MAIN_EXIT
3611 CALL SHOW_ERROR_MESSAGE ;show error_message
3612 JMP SHORT GOTO_MAIN_EXIT
3614 CALL SHOW_ERROR_MESSAGE ;show message
3615 JMP SHORT GOTO_MAIN_EXIT
3619 ; Set substitution list
3620 LEA SI,SUBLIST1 ;AN000; get addressability to sublist
3621 LEA DX,S_DRV_PATH ;AN000; offset to PATH NAME
3622 MOV [SI].DATA_OFF,DX ;AN000; save offset
3623 MOV [SI].DATA_SEG,DS ;AN000; save data segment
3624 MOV [SI].MSG_ID,1 ;AN000; message ID
3625 MOV [SI].FLAGS,010H ;AN000; ASCIIZ string, left align
3626 MOV [SI].MAX_WIDTH,0 ;AN000; MAXIMUM FIELD WITH
3627 MOV [SI].MIN_WIDTH,0 ;AN000; MINIMUM FIELD WITH
3629 ; Set message parameters
3630 MOV AX,DISPLAY_S_PATH ;AN000; message number
3631 MOV MSG_NUM,AX ;AN000; set message number
3632 MOV SUBST_COUNT,PARM_SUBST_ONE ;AN000; one message substitution
3633 MOV MSG_CLASS,UTILITY_MSG_CLASS ;AN000; message class
3634 MOV INPUT_FLAG,NO_INPUT ;AN000; no input
3635 CALL PRINT_STDERR ;show source drv,path
3637 CALL SHOW_ERROR_MESSAGE ;display error message
3640 JMP MAIN_EXIT ;restore conditions
3643 JMP JUST_EXIT ;immediate exit
3646 MOV ERRORLEVEL, 0 ;reset errorlevel
3654 EXTENDED_ERROR_HANDLER ENDP
3658 SHOW_ERROR_MESSAGE PROC NEAR
3659 ;called immediately after Get_extended error
3660 ;This will show simple error message according to error_code in AX
3661 ;If the message is not what it wanted, just exit without message- Set carry.
3662 ;input: DS - data seg
3663 ;output: Carry flag is distroyed.
3666 CMP AX, 5 ;access denied?
3667 JE ACCESS_DENIED_MESSAGE
3668 CMP AX, 4 ;too many open files?
3669 JE TOO_MANY_OPEN_MESSAGE
3670 CMP AX, 31 ;general failure?
3671 JE GENERAL_FAIL_MESSAGE
3672 CMP AX, 32 ;sharing violation?
3673 JE SHARING_VIOL_MESSAGE
3674 CMP AX, 33 ;lock violation?
3675 JE LOCK_VIOL_MESSAGE
3676 CMP AX, 3 ;path not found?
3678 CMP AX, 2 ;file not found error?
3679 JE FILE_NOT_ERR_MESSAGE
3680 CMP AX, 65 ;access denied on the network?
3681 JE ACCESS_DENIED_MESSAGE
3682 CMP AX, 82 ;no more directory entry to create a file?
3683 JE FILE_CREATE_ERR_MESSAGE
3688 JMP GOTO_MAIN_EXIT ;and exit
3690 ACCESS_DENIED_MESSAGE:
3691 MOV AX, MSG_ACCESS_DENIED ;AN000;
3692 JMP SHORT SHOW_MESSAGE
3693 TOO_MANY_OPEN_MESSAGE:
3694 MOV AX, MSG_TOO_MANY_OPEN ;AN000;
3695 JMP SHORT SHOW_MESSAGE
3696 GENERAL_FAIL_MESSAGE:
3697 MOV AX, MSG_GENERAL_FAIL ;AN000;
3698 JMP SHORT SHOW_MESSAGE
3699 SHARING_VIOL_MESSAGE:
3700 MOV AX, MSG_SHARING_VIOL ;AN000;
3701 JMP SHORT SHOW_MESSAGE
3703 MOV AX, MSG_LOCK_VIOL ;AN000;
3704 JMP SHORT SHOW_MESSAGE
3706 MOV AX, MSG_PATH_NOT ;AN000;
3708 JMP SHORT SHOW_MESSAGE
3709 FILE_NOT_ERR_MESSAGE:
3710 MOV AX, MSG_FILE_NOT_ERR ;AN000;
3711 JMP SHORT SHOW_MESSAGE
3712 FILE_CREATE_ERR_MESSAGE:
3713 MOV AX, MSG_FILE_CREATE_ERR ;AN000;
3716 SHOW_MESSAGE: ; Display error message
3717 ; Set message parameters
3718 MOV MSG_NUM,AX ;AN000; set message number
3719 MOV SUBST_COUNT,NO_SUBST ;AN000; NO message substitution
3720 MOV MSG_CLASS,UTILITY_MSG_CLASS ;AN000; message class
3721 MOV INPUT_FLAG,NO_INPUT ;AN000; no input
3722 CALL PRINT_STDERR ;AN000; print it
3725 SHOW_ERROR_MESSAGE ENDP
3729 SHOW_S_PATH_FILE_ERR PROC NEAR
3730 ;show current source path(drv, full path), and filename to the
3731 ;standard error display device.
3732 ;input: ds: data seg
3734 PUSH AX ;save ERROR_CODE
3737 MOV DI,OFFSET S_DRV_PATH
3738 CALL STRING_LENGTH ;cx got the length
3739 MOV SI,OFFSET S_DRV_PATH ;full path of source
3740 MOV DI,OFFSET DISP_S_PATH
3741 REP MOVSB ;S_DRV_PATH => DISP_S_PATH
3742 MOV CX, 13 ;max 13 chr
3743 MOV SI,OFFSET FILE_DTA.DTA_FILENAME
3744 MOV DI,OFFSET DISP_S_FILE
3745 REP MOVSB ;dta_filename => disp_s_file
3747 LEA SI,SUBLIST1 ;AN000; get addressability to list
3748 LEA DX,DISP_S_PATH ;AN000; offset to path name
3749 MOV [SI].DATA_OFF,DX ;AN000; save offset
3750 MOV [SI].DATA_SEG,DS ;AN000; save data segment
3751 MOV [SI].MSG_ID,1 ;AN000; message ID
3752 MOV [SI].FLAGS,010H ;AN000; ASCIIZ string, left align
3753 MOV [SI].MAX_WIDTH,0 ;AN000; MAXIMUM FIELD WITH
3754 MOV [SI].MIN_WIDTH,0 ;AN000; MINIMUM FIELD WITH
3756 LEA SI,SUBLIST2 ;AN000; get addressability to list
3757 LEA DX,DISP_S_FILE ;AN000; offset to file name
3758 MOV [SI].DATA_OFF,DX ;AN000; save offset
3759 MOV [SI].DATA_SEG,DS ;AN000; save data segment
3760 MOV [SI].MSG_ID,2 ;AN000; message ID
3761 MOV [SI].FLAGS,010H ;AN000; ASCIIZ string, left align
3762 MOV [SI].MAX_WIDTH,0 ;AN000; MAXIMUM FIELD WITH
3763 MOV [SI].MIN_WIDTH,0 ;AN000; MINIMUM FIELD WITH
3766 CMP S_DEPTH,0 ;AN000;it happened, when dealing with the starting dir?
3769 LEA SI,SUBLIST2 ;AN007;PIONT TO THE FIRST LIST
3770 MOV [SI].MSG_ID,1 ;AN007; message ID
3771 MOV AX,DISPLAY_S_PATH ;AC007;ITS ONLY A FILE NAME
3772 MOV SUBST_COUNT,PARM_SUBST_ONE ;AN007; ONE message sub
3776 LEA SI,SUBLIST1 ;AN007;PIONT TO THE FIRST LIST
3777 MOV AX,S_PATH_FILE1 ;AN000;put '\'
3778 MOV SUBST_COUNT
,PARM_SUBST_TWO
;AN007;TWO message subs
3782 ; Set message parameters
3784 MOV MSG_NUM
,AX ;AN000; set message number
3785 MOV MSG_CLASS
,UTILITY_MSG_CLASS
;AN000; message class
3786 MOV INPUT_FLAG
,NO_INPUT
;AN000; no input
3787 CALL PRINT_STDERR
;display error message
3789 POP AX ;restore ERROR_CODE
3793 SHOW_S_PATH_FILE_ERR ENDP
3797 CLOSE_DELETE_FILE PROC
NEAR
3798 ;when writing error occurs, then this routine is called to
3799 ;clean up the troubled target file.
3800 ;INPUT: DS - buffer seg
3803 MOV BX, ES:T_HANDLE
;close target file
3804 PUSH DS ;AN005;SAVE THE BUFFER PTR
3805 PUSH ES ;AN005;WE NEED THE DATA PTR
3806 POP DS ;AN005;DS = THE DATA PTR
3807 CALL CLOSE_A_FILE
;and close the handle
3808 POP DS ;AN005;DS = THE BUFFER PTR AGAIN
3809 LEA DX, DS:target_drv_let
;target drv, filename
3810 CALL DELETE_A_FILE
;delete it
3812 CLOSE_DELETE_FILE ENDP
3816 SWITCH_DS_ES PROC
NEAR
3828 CMP CS:INT24_ABORT_CNT
, 0 ;if aborted more than once, then just exit.
3830 PUSHF ;we are calling interrupt handler
3831 CALL DWORD PTR CS:SAV_INT24
;call original int 24 handler
3834 CMP AL, 0 ;ignore? Cannot ignore. Try again
3836 POP CX ;remove IP, CS, FLAGS
3837 POP CX ;since we are not going back
3838 POP CX ;to the place int 24 was called.
3841 CMP AL, 3 ;AN000;fail?
3843 JMP MAIN_EXIT
;show files copied message
3844 ;restore default value and exit
3846 INC CS:INT24_ABORT_CNT
;increase the count of int24_abort
3847 JMP MAIN_EXIT_A
;restore default value and exit
3854 IRET ;return where it happened
3855 ;and retry that operation.
3857 INT24_ABORT_CNT
DB 0
3862 DSEG_INIT
SEGMENT PARA
PUBLIC ;AN000;
3863 DSEG_INIT ENDS
;AN000;