Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1093 lines
28 KiB

page ,132
title COMMAND COPY routines.
;/*
; * Microsoft Confidential
; * Copyright (C) Microsoft Corporation 1991
; * All Rights Reserved.
; */
comment % -----------------------------------------------------------------
;*** COPY.ASM
Source files: copy.asm, copypr1.asm, copypr2.asm
;*** MODIFICATION HISTORY
11/01/83 EE Added a few lines at the end of SCANSRC2 to get multiple
file concatenations (eg copy a.*+b.*+c.*) to work properly.
11/02/83 EE Commented out the code in CPARSE which added drive designators
to tokens which begin with path characters so that PARSELINE
will work correctly.
11/04/83 EE Commented out the code in CPARSE that considered paren's to be
individual tokens. That distinction is no longer needed for
FOR loop processing.
11/17/83 EE CPARSE upper case conversion is now flag dependent. Flag is
1 when Cparse is called from COPY.
11/17/83 EE Took out the comment chars around code described in 11/04/83
mod. It now is conditional on flag like previous mod.
11/21/83 NP Added printf
12/09/83 EE CPARSE changed to use CPYFLAG to determine when a colon should
be added to a token.
05/30/84 MZ Initialize all copy variables. Fix confusion with destclosed
NOTE: DestHand is the destination handle. There are two
special values: -1 meaning destination was never opened and
0 which means that the destination has been openned and
closed.
06/01/84 MZ Above reasoning totally specious. Returned things to normal
06/06/86 EG Change to fix problem of source switches /a and /b getting
lost on large and multiple file (wildcard) copies.
06/09/86 EG Change to use xnametrans call to verify that source and
destination are not equal.
06/24/90 DO If the destination of a file concatenation is the same as
first source file AND we run out of disk space before
completing the concatenation, restore the first source
file as best we can. See SeekEnd and CopErr. Bug #859.
M031 SR 10/11/90 Bug #3069. Use deny write sharing mode to open files
instead of compatibility mode. This gives lesser sharing
violations when files are opened for read on a copy.
% -------------------------------------------------------------------------
.xlist
.xcref
include comsw.asm
include dossym.inc
include syscall.inc
include sf.inc
include comseg.asm
include comequ.asm
.list
.cref
DATARES segment public byte
extrn VerVal:word
DATARES ends
TRANDATA segment public byte
extrn BadCd_Ptr:word
extrn Copied_Ptr:word
extrn Extend_Buf_Ptr:word
extrn Extend_Buf_Sub:byte
extrn File_Name_Ptr:word
extrn InBDev_Ptr:word
extrn Msg_Disp_Class:byte
extrn Overwr_Ptr:word
TRANDATA ends
TRANSPACE segment public byte
extrn AllSwitch:word
extrn ArgC:byte
extrn Ascii:byte
extrn Binary:byte
extrn BytCnt:word
extrn CFlag:byte
extrn Comma:byte
extrn Concat:byte
extrn Copy_Num:word
extrn CpDate:word
extrn CpTime:word
extrn CpyFlag:byte
extrn CurDrv:byte
extrn DestBuf:byte
extrn DestClosed:byte
extrn DestFcb:byte
extrn DestFcb2:byte
extrn DestHand:word
extrn DestInfo:byte
extrn DestIsDir:byte
extrn DestSiz:byte
extrn DestSwitch:word
extrn DestTail:word
extrn DestVars:byte
extrn DirBuf:byte
extrn Expand_Star:byte
extrn FileCnt:word
extrn FirstDest:byte
extrn FrstSrch:byte
extrn Inexact:byte
extrn MelCopy:byte
extrn MelStart:word
extrn Msg_Flag:byte
extrn NoWrite:byte
extrn NxtAdd:word
extrn ObjCnt:byte
extrn OCtrlZ:byte
extrn OFilePtr_Hi:word
extrn OFilePtr_Lo:word
extrn One_Char_Val:byte
extrn Parse_Last:word
extrn Plus:byte
extrn Plus_Comma:byte
extrn RdEof:byte
extrn ResSeg:word
extrn ScanBuf:byte
extrn SDirBuf:byte
extrn SrcBuf:byte
extrn SrcHand:word
extrn SrcInfo:byte
extrn SrcIsDev:byte
extrn SrcPt:word
extrn SrcSiz:byte
extrn SrcTail:word
extrn SrcVars:byte
extrn SrcXName:byte
extrn StartEl:word
extrn String_Ptr_2:word
extrn TermRead:byte
extrn Tpa:word
extrn UserDir1:byte
extrn Written:word
TRANSPACE ends
;*** COPY CODE
TRANCODE segment public byte
extrn CError:near
extrn CopErr:near
extrn TCommand:near
public Copy
assume cs:TRANGROUP,ds:TRANGROUP,es:TRANGROUP,ss:NOTHING
break Copy
Copy:
assume ds:TRANGROUP,es:TRANGROUP
; Initialize internal variables.
xor ax,ax ; AX = 0
mov Copy_Num,ax ; # files copied (destinations) = 0
mov SrcPt,ax ; cmd line ptr for source scan = 0
mov SrcTail,ax ; ptr to last element of source pathname = 0
mov CFlag,al ; 'destination file created' = false
mov NxtAdd,ax ; ptr into TPA buffer = 0
mov DestSwitch,ax ; destination switches = none
mov StartEl,ax ; CParse ptr to last pathname element = 0
mov DestTail,ax ; ptr to last element of dest pathname = 0
mov DestClosed,al ; 'destination file closed' = false
mov DestSiz,al ; length of destination pathname = 0
mov SrcSiz,al ; length of source pathname = 0
mov DestInfo,al ; destination pathname flags = none
mov SrcInfo,al ; source pathname flags = none
mov Inexact,al ; 'inexact copy' = false
mov DestVars,al ; 'dest pathname is directory' = false
mov SrcVars,al ; 'source pathname is directory' = false
mov UserDir1,al ; saved working directory = null
mov NoWrite,al ; 'no write' (source = dest) = false
mov RdEof,al ; 'read end of file' = false
mov SrcHand,ax ; source handle = 0
mov CpDate,ax ; copy date = 0
mov CpTime,ax ; copy time = 0
mov SrcIsDev,al ; 'source is device' = false
mov OCtrlZ,al ; 'Ctrl+Z removed from original' = false
mov OFilePtr_Lo,ax
mov OFilePtr_Hi,ax ; original destination file ptr = null
mov TermRead,al ; 'terminate read' = false
mov Comma,al ; '"+,," found' = false
mov Plus_Comma,al ; '"+,," found last time' = false (?)
mov Msg_Flag,al ;AN022; 'non-utility msg issued' = false
mov AllSwitch,ax ; all switches = none
mov ArgC,al ; source/dest argument count = 0
mov Plus,al ; '"+" in command line' = false
mov Binary,al ; 'binary copy' = false
mov Ascii,al ; 'ascii copy' = false
mov FileCnt,ax ; # files copied (destinations) = 0
mov Written,ax ; 'destination written to' = false
mov Concat,al ; 'concatenating' = false
mov MelCopy,al ; 'Mel Hallerman copy' = false
mov MelStart,ax ; Mel Hallerman cmd line ptr = 0
; Initialize buffers with double-nulls.
mov word ptr ScanBuf,ax
mov word ptr DestBuf,ax
mov word ptr SrcBuf,ax
mov word ptr SDirBuf,ax
mov word ptr DirBuf,ax
mov word ptr DestFcb,ax
mov ObjCnt,al ; # CParse cmd-line objects found = 0
dec ax ; AX = 0FFFFh
mov DestHand,ax ; destination handle = 'never opened'
mov FrstSrch,al ; 'first search for source' = true
mov FirstDest,al ; 'first time for dest' = true
mov DestIsDir,al ; 'haven't analyzed destination'
mov si,81h ; SI = ptr to command line
mov bl,PLUS_CHR ; BL = special delimiter = "+"
inc Expand_Star ; CParse 'expand * to ?s' = true
mov CpyFlag,1 ; CParse 'called from COPY' = true
;* Scan the command line for destination information.
DestScan:
xor bp,bp ; BP = switch flag accumulator
mov di,offset TRANGROUP:ScanBuf ; ES:DI = ptr to pathname buf
mov Parse_Last,si ;AN018; save cmd line ptr
invoke CParse ; parse next object
pushf ; save CParse flags
inc ObjCnt ; count object
test bh,80h
jz @f ; no "+" delimiter
mov Plus,1 ; "+" delimiter occurred
@@:
test bh,1
jz TestP2 ; not a switch
; Found a switch.
test bp,SwitchV ;AN038; Verify requested?
jz Not_SlashV ;AN038; No - set the switch
test AllSwitch,SwitchV ;AN038; Verify already entered?
jz Not_SlashV ;AN038; No - set the switch
;AD018; or AllSwitch,FBadSwitch ;AN038; Set up bad switch
or bp,FBadSwitch ;AN018; Set up bad switch
Not_SlashV: ;AN038;
or DestSwitch,bp ; assume destination
or AllSwitch,bp ; keep tabs on all switches
test bp,not SwitchCopy ;AN018; Bad switch?
jz Not_Bad_Switch ;AN018; Switches are okay
popf ;AN018; fix up stack
mov ax,BadSwt_ptr ;AN018; get "Invalid switch" message number
invoke Setup_Parse_Error_Msg ;AN018; setup to print the message
jmp CError ;AC018; exit
Not_Bad_Switch: ;AN018; switch okay
popf ; restore CParse flags
jc CheckDone ; found CR
jmp short DestScan ; continue scanning for destination
TestP2:
popf ; restore CParse flags
jc CheckDone ; found CR
test bh,80h
jnz @f ; found a "+pathname" argument
inc ArgC ; count independent pathname args
@@:
push si ; save cmd line ptr
mov ax,StartEl ; AX = ptr to last path element
mov si,offset TRANGROUP:ScanBuf ; SI = ptr to path string
sub ax,si ; AX = offset of last element
mov di,offset TRANGROUP:DestBuf ; DI = ptr to destination buf
add ax,di ; AX = ptr to last element in
; destination path buffer
mov DestTail,ax ; save ptr to last element
mov DestSiz,cl ; save path string length
inc cx ; CX = mov length (incl null)
rep movsb ; DestBuf = possible destination path
mov DestInfo,bh ; save CParse info flags
mov DestSwitch,0 ; clear destination switches
pop si ; SI = ptr into cmd line again
jmp DestScan ;AC018; continue scanning for dest
CheckDone:
; We reached the CR. The destination scan is finished.
; Disallow "copy file1+" as file overwriting itself.
;
; (Note that "copy file1+file2+" will be accepted, and
; equivalent to "copy file1+file2".)
; Bugbug: it looks like "copy /x file1+" would slip
; through this check, since the switch would count
; as another object in ObjCnt.
cmp Plus,1 ; "+" with
jne cdCont
cmp ArgC,1 ; one arg,
jne cdCont
cmp ObjCnt,2 ; two objects..
jne cdCont
mov dx,offset TRANGROUP:OverWr_ptr
jmp CopErr ; is file overwrite.
cdCont: mov al,Plus ; AL = '"+" occurred'
mov Concat,al ; if "+" occurred, we're concatenating
shl al,1
shl al,1
mov Inexact,al ; therefore making an inexact copy
mov al,ArgC ; AL = # independent arguments
or al,al
jnz Try_Too_Many ; more than 0 args; check if too many
mov dx,offset TRANGROUP:Extend_Buf_Ptr ; DX = ptr to msg block
mov Extend_Buf_Ptr,LessArgs_Ptr ; set msg # "param missing"
jmp short CError_ParseJ ; take parse error exit
Try_Too_Many:
cmp al,2
jbe ACountOk ; <= 2 arguments - ok
mov dx,offset TRANGROUP:Extend_Buf_Ptr ; DX = ptr to msg block
mov Extend_Buf_Ptr,MoreArgs_Ptr ; set msg # "too many params"
CError_ParseJ:
mov Msg_Disp_Class,PARSE_MSG_CLASS ; parse error message
CError4J:
jmp CError ; command error exit
ACountOk:
mov bp,offset TRANGROUP:DestVars ; BP = base of dest variables
; Bugbug: use of BP without segment override implies SS.
; SS is implicitly assumed to point at TRANGROUP.
cmp al,1
jne Got2Args ; we have 2 arguments
; Only one independent pathname argument on command line.
; Set destination to d:*.*, where d: is current drive.
; Bugbug: but is this appropriate for "copy x:file1+x:file2"?
; The two files would be appended as d:file1, rather than x:file1.
mov al,CurDrv ; AL = current drive (0 = A)
add al,CAPITAL_A ; AL = current drive letter
mov ah,':' ; AX = "d:"
mov [bp].siz,2 ; pathname length = 2
mov di,offset TRANGROUP:DestBuf ; ES:DI = ptr to dest path buf
stosw ; store "d:"
mov DestSwitch,0 ; clear destination switches
mov [bp].info,2 ; mark destination 'wildcard present'
mov [bp].isdir,0 ; mark destination 'not a directory'
invoke SetStars ; add wildcards
Got2Args:
; If destination pathname is "d:", add full wildcard filename
cmp [bp].siz,2
jne NotShortDest ; not two chars, can't be "d:"
mov al,':'
cmp destbuf+1,al
jne NotShortDest ; it's just a 2-character filename
or [bp].info,2 ; mark destination 'wildcard present'
mov di,offset TRANGROUP:DestBuf+2
; ES:DI = ptr after "d:"
mov [bp].isdir,0 ; mark destination 'not a directory'
invoke SetStars ; add wildcards
NotShortDest:
; If destination pathname ends with "\", try to make
; sure it's "d:\".
mov di,[bp].ttail ; DI = ptr to last path element
cmp byte ptr [di],0
jne ChkSwtches ; not a null, so last char not "\"
mov dx,offset TRANGROUP:BadCD_Ptr ; DX = ptr to msg block
mov al,':'
cmp byte ptr [di-2],al
jne CError4J ; it's not "d:\", exit with error msg
mov [bp].isdir,2 ; destination 'is a directory'
or [bp].info,6 ; destination wildcarded and contains
; path character
invoke SetStars ; add wildcards
ChkSwtches:
;AD018; mov ax,[ALLSWITCH]
;AD018; test ax,NOT SwitchCopy
;AD018; jz NOT_BAD_SWITCH ;AN000; Switches are okay
;AD018; MOV DX,OFFSET TranGroup:Extend_Buf_ptr ;AC000; get extended message pointer
;AD018; mov Extend_Buf_ptr,BadSwt_ptr ;AN000; get "Invalid switch" message number
;AD018; jmp short CERROR_PARSEJ ;AC000; Switch specified which is not known
;AD018; NOT_BAD_SWITCH:
; We have enough information about the destination for now.
; Turn on verify if requested. Save the current verify flag.
mov ax,AllSwitch ; AX = all switch flags
test ax,SwitchV
jz NoVerif ; no /v, no verify
mov ah,GET_VERIFY_ON_WRITE ; AH = 'Get Verify Flag'
int 21h ; call DOS
push ds
mov ds,ResSeg
assume ds:RESGROUP
xor ah,ah
mov VerVal,ax ; save current verify flag
pop ds
assume ds:TRANGROUP
mov ax,(SET_VERIFY_ON_WRITE shl 8) or 1 ; AX = 'Set Verify Flag'
int 21h ; call DOS
NoVerif:
;* Scan for first source.
xor bp,bp ; BP = switch flags accumulator
mov si,81h ; SI = ptr into command line
mov bl,PLUS_CHR ; BL = special CParse delimiter = "+"
ScanFSrc:
mov di,offset TRANGROUP:ScanBuf ; DI = ptr to pathname buf
invoke CParse ; parse first source pathname
test bh,1 ; switch?
jnz ScanFSrc ; yes, try again
or DestSwitch,bp ; include copy-wide switches on dest
; Set ascii copying mode if concatenating, unless /b is specified.
test bp,SWITCHB
jnz NoSetCAsc ; /b - explicit binary copy
cmp Concat,0
je NoSetCAsc ; we're not concatenating
mov Ascii,SWITCHA ; set ascii copy
NoSetCAsc:
call Source_Set ; set source variables
call FrstSrc ; set up first source copy
jmp FirstEnt ; jump into the copy loop
public EndCopy
EndCopy:
;* End of the road. Close destination, display # files
; copied (meaning # destinations), and go back to main
; transient COMMAND code.
call CloseDest
EndCopy2:
mov dx,offset TRANGROUP:Copied_Ptr
mov si,FileCnt
mov Copy_Num,si
invoke Std_PrintF
jmp TCommand ; stack could be messed up
SrcNonexist:
;* Source doesn't exist. If concatenating, ignore and continue.
; Otherwise, say 'file not found' and quit.
cmp Concat,0
jne NextSrc ; concatenating - go on to next source
; Set up error message.
mov Msg_Disp_Class,EXT_MSG_CLASS ; extended error msg
mov dx,offset TRANGROUP:Extend_Buf_Ptr ; DX = ptr to msg block
mov Extend_Buf_Ptr,ERROR_FILE_NOT_FOUND ; 'file not found' msg#
mov String_Ptr_2,offset TRANGROUP:SrcBuf ; point at bad pathname
mov Extend_Buf_Sub,ONE_SUBST ; 1 substitution
jmp CopErr ; print msg and clean up
SourceProc:
;* Preparatory processing for each source file.
; Called at FrstSrc for first source file.
call Source_Set ; set source variables & ascii/binary
cmp Concat,0
jne LeaveCFlag ; concatenating - leave CFlag alone
FrstSrc:
xor ax,ax
mov CFlag,al ; 'destination not created'
mov NxtAdd,ax ; copy buffer ptr = 0
mov DestClosed,al ; 'destination not closed'
LeaveCFlag:
mov SrcPt,si ; save cmd-line ptr
mov di,offset TRANGROUP:UserDir1 ; DI = ptr to buf for user's
; current dir
mov bp,offset TRANGROUP:SrcVars ; BP = base of source variables
invoke BuildPath ; cd to source dir, figure
; out stuff about source
mov si,SrcTail ; SI = ptr to source filename
return
NextSrc:
;* Next source. Come here after handling each pathname.
; We're done unless there are additional source pathnames
; to be appended.
;
; Note that all files matching an ambiguous pathname
; are processed before coming here.
cmp Plus,0
jne MoreCp ; copying "+" sources - keep going
EndCopyJ2:
jmp EndCopy ; done copying
MoreCp:
xor bp,bp ; BP = switch flags accumulator
mov si,SrcPt ; SI = ptr to current pos'n in cmd line
mov bl,PLUS_CHR ; BL = special delimiter = "+"
ScanSrc:
mov di,offset TRANGROUP:ScanBuf ; DI = ptr to pathname buf
invoke CParse ; parse first source name
jc EndCopyJ2 ; CR found - we're done
test bh,80h
jz EndCopyJ2 ; no "+" delimiter - we're done
test bh,1
jnz ScanSrc ; switch found - keep looking
; ScanBuf contains the next source pathname.
call SourceProc ; prepare this source
cmp Comma,1 ;g was +,, found last time?
jne NoStamp ;g no - try for a file
mov Plus_Comma,1 ;g yes - set flag
jmp SrcNonexist ;g we know we won't find it
NoStamp: ;g
mov Plus_Comma,0 ;g reset +,, flag
FirstEnt:
;
;M047
; The only case we need to worry about is when the source is wildcarded and
;the destination is not. For this case, ConCat is not yet set to indicate
;concatenation. We check for this case.
;
;NB: This change has been backed out and replaced by M048. This is not the
;right place to do this check.
;
; This is where we enter the loop with the first source.
mov di,FCB ; DI = ptr to FCB
mov ax,PARSE_FILE_DESCRIPTOR shl 8 ; 'Parse Filename'
int 21h ; call DOS
cmp byte ptr [si],0 ; did we parse the whole thing?
jne SrchDone ; no, error, simulate 'not found'
mov ax,word ptr SrcBuf ; AX = possible "d:"
cmp ah,':'
je @f ; AX = definite "d:"
mov al,'@' ; AL = drive 'letter' for current drive
@@:
or al,20h ; AL = lowercase drive letter
sub al,60h ; AL = drive id (0=current,1=A,..)
mov ds:FCB,al ; put drive id in FCB
; FCB contains drive and filename to search.
mov ah,DIR_SEARCH_FIRST ; AH = 'Find First File'
call Search
SrchDone:
pushf ; save flags from Search
invoke RestUDir1 ; restore users current directory
popf ; restore flags from search
jz @f ; found the source - continue
jmp SrcNonexist ; didn't find the source
@@:
xor al,al
xchg al,FrstSrch
or al,al
jz NextAmbig
SetNMel:
mov cx,12
mov di,offset TRANGROUP:SDirBuf
mov si,offset TRANGROUP:DirBuf
rep movsb ; save very first source name
NextAmbig:
xor al,al
mov NoWrite,al ; turn off nowrite
mov di,SrcTail
mov si,offset TRANGROUP:DirBuf + 1
invoke Fcb_To_Ascz ; SrcBuf has complete name
MelDo:
cmp Concat,0
jne ShowCpNam ; concatenating - show name
test SrcInfo,2 ; wildcard - show name
jz DoRead
ShowCpNam:
mov dx,offset TRANGROUP:File_Name_Ptr
invoke Std_PrintF
invoke CrLf2
DoRead:
call DoCopy
cmp Concat,0
jne NoDClose ; concatenating - don't close dest
call CloseDest ; close current destination
jc NoDClose ; concatenating - dest not closed
mov CFlag,0 ; 'destination not created'
NoDClose:
cmp Concat,0
je NoFlush ; not concatenating - don't flush
; Concatenating - flush output between source files so LostErr
; stuff works correctly.
invoke FlshFil
test MelCopy,0FFh
jz @f
jmp short DoMelCopy
@@:
NoFlush:
call SearchNext ; try next match
jnz NextSrcJ ; not found - finished with
; this source spec
mov DestClosed,0 ; 'destination not closed'
jmp NextAmbig ; do next ambig match
DoMelCopy:
cmp MelCopy,0FFh
je ContMel
mov si,SrcPt
mov MelStart,si
mov MelCopy,0FFh
ContMel:
xor bp,bp
mov si,SrcPt
mov bl,PLUS_CHR
ScanSrc2:
mov di,offset TRANGROUP:ScanBuf
invoke CParse
test bh,80h
jz NextMel ; no "+" - go back to start
test bh,1
jnz ScanSrc2 ; switch - keep scanning
call SourceProc
invoke RestUDir1
mov di,offset TRANGROUP:DestFcb2
mov ax,PARSE_FILE_DESCRIPTOR shl 8
int 21h
mov bx,offset TRANGROUP:SDirBuf + 1
mov si,offset TRANGROUP:DestFcb2 + 1
mov di,SrcTail
invoke BuildName
cmp Concat,0
je MelDoJ ; not concatenating - continue
; Yes, turn off nowrite because this part of the code
; is only reached after the first file has been dealt with.
mov NoWrite,0
MelDoJ:
jmp MelDo
NextSrcJ:
jmp NextSrc
NextMel:
call CloseDest
xor ax,ax
mov CFlag,al
mov NxtAdd,ax
mov DestClosed,al
mov si,MelStart
mov SrcPt,si
call SearchNext
jz SetNMelJ
jmp EndCopy2
SetNMelJ:
jmp SetNMel
SearchNext:
mov ah,DIR_SEARCH_NEXT
test SrcInfo,2
jnz Search ; do search-next if ambig
or ah,ah ; reset zero flag
return
Search:
push ax
mov ah,SET_DMA
mov dx,offset TRANGROUP:DirBuf
int 21h ; put result of search in dirbuf
pop ax ; restore search first/next command
mov dx,FCB
int 21h ; Do the search
or al,al
return
DoCopy:
mov si,offset TRANGROUP:SrcBuf ;g do name translate of source
mov di,offset TRANGROUP:SrcXName ;g save for name comparison
mov ah,XNAMETRANS ;g
int 21h ;g
mov RdEof,0 ; no EOF yet
mov ax,EXTOPEN shl 8 ; open the file
;M046
; For reads, the sharing mode should be deny none so that any process can
;open this file again in any other sharing mode. This is mainly to allow
;multiple command.com's to access the same file without getting sharing
;violations
;
mov bx,DENY_NONE or READ_OPEN_MODE ; open mode for COPY ;M046
xor cx,cx ; no special files
mov dx,READ_OPEN_FLAG ; set up open flags
int 21h
jnc OpenOk
; Bogosity: IBM wants us to issue Access Denied in this case.
; They asked for it...
jmp short Error_On_Source ;AC022; clean up and exit
OpenOk:
mov bx,ax ; save handle
mov SrcHand,bx ; save handle
mov ax,(FILE_TIMES shl 8)
int 21h
jc Error_On_Source
mov CpDate,dx ; save date
mov CpTime,cx ; save time
jmp short No_Copy_Xa ; (xa copy code removed)
Error_On_Source: ;AN022; we have a BAD error
invoke Set_Ext_Error_Msg ;AN022; set up the error message
mov String_Ptr_2,offset TRANGROUP:SrcBuf ;AN022; get address of failed string
mov Extend_Buf_Sub,ONE_SUBST ;AN022; put number of subst in control block
invoke Std_EprintF ;AN022; print it
cmp SrcHand,0 ;AN022; did we open the file?
je No_Close_Src ;AN022; no - don't close
call CloseSrc ;AN022; clean up
No_Close_Src: ;AN022;
cmp CFlag,0 ;AN022; was destination created?
je EndCopyJ3 ;AN022; no - just cleanup and exit
jmp EndCopy ;AN022; clean up concatenation and exit
EndCopyJ3: ;AN022;
jmp EndCopy2 ;AN022;
No_Copy_Xa:
mov bx,SrcHand ;AN022; get handle back
mov ax,(IOCTL shl 8)
int 21h ; get device stuff
and dl,DEVID_ISDEV
mov SrcIsDev,dl ; set source info
jz CopyLp ; source not a device
cmp Binary,0
je CopyLp ; ascii device ok
mov dx,offset TRANGROUP:InBDev_Ptr ; cannot do binary input
jmp CopErr
CopyLp:
mov bx,SrcHand
mov cx,BytCnt
mov dx,NxtAdd
sub cx,dx ; compute available space
jnz GotRoom
invoke FlshFil
cmp TermRead,0
jne CloseSrc ; give up
mov cx,BytCnt
GotRoom:
push ds
mov ds,Tpa
assume ds:NOTHING
mov ah,READ
int 21h
pop ds
assume ds:TRANGROUP
jc Error_On_Source ;AC022; give up if error
mov cx,ax ; get count
jcxz CloseSrc ; no more to read
cmp SrcIsDev,0
jne NoTestA ; is a device, ascii mode
cmp Ascii,0
je BinRead
NoTestA:
mov dx,cx
mov di,NxtAdd
mov al,1Ah
push es
mov es,Tpa
repne scasb ; scan for EOF
pop es
jne UseAll
inc RdEof
inc cx
UseAll:
sub dx,cx
mov cx,dx
BinRead:
add cx,NxtAdd
mov NxtAdd,cx
cmp cx,BytCnt ; is buffer full?
jb TestDev ; if not, we may have found eof
invoke FlshFil
cmp TermRead,0
jne CloseSrc ; give up
jmp short CopyLp
TestDev:
cmp SrcIsDev,0
je CloseSrc ; if file then EOF
cmp RdEof,0
je CopyLp ; on device, go till ^Z
CloseSrc:
mov bx,SrcHand
mov ah,CLOSE
int 21h
return
CloseDest:
; We are called to close the destination.
; We need to note whether or not there is any internal data left
; to be flushed out.
cmp DestClosed,0
retnz ; don't double close
mov al,byte ptr DestSwitch
invoke SetAsc ; check for b or a switch
jz BinClos ; on destination
mov bx,NxtAdd
;
;M048 -- TryFlush changes the state of ConCat flag. So, before we append a
;^Z, let's always flush out. This way if the ConCat flag changes, we will
;just return without appending a ^Z incorrectly for the first file(since we
;are concatenating now). Also, in case it is a single file copy, we will
;anyway write the ^Z out separately. The only drawback is that there is a
;performance overhead on single ASCII file copies which now always involve
;2 writes instead of 1 before. Is this really that important?
;
;M048; cmp bx,BytCnt ; is memory full?
;M048; jne PutZ
invoke TryFlush ; flush (and double-check for concat)
je NoConc
ConChng: ; concat flag changed on us
stc
return
NoConc:
xor bx,bx
PutZ:
push ds
mov ds,Tpa
mov word ptr [bx],1Ah ; add EOF mark (ctrl-Z)
pop ds
inc NxtAdd
mov NoWrite,0 ; make sure our ^z gets written
mov ax,Written
add ax,NxtAdd
jc BinClos ; > 1
cmp ax,1
je ForgetItJ ; Written = 0 NxtAdd = 1 (the ^Z)
BinClos:
invoke TryFlush
jnz ConChng
cmp Written,0
ForgetItJ:
jne No_Forget ; wrote something
jmp ForgetIt ; never wrote nothing
No_Forget:
mov bx,DestHand
mov cx,CpTime
mov dx,CpDate
cmp Inexact,0 ; copy not exact?
je DoDClose ; if no, copy date & time
mov ah,GET_TIME
int 21h
shl cl,1
shl cl,1 ; left justify min in cl
shl cx,1
shl cx,1
shl cx,1 ; hours to high 5 bits, min to 5-10
shr dh,1 ; divide seconds by 2 (now 5 bits)
or cl,dh ; and stick into low 5 bits of cx
push cx ; save packed time
mov ah,GET_DATE
int 21h
sub cx,1980
xchg ch,cl
shl cx,1 ; year to high 7 bits
shl dh,1 ; month to high 3 bits
shl dh,1
shl dh,1
shl dh,1
shl dh,1 ; most sig bit of month in carry
adc ch,0 ; put that bit next to year
or dl,dh ; or low three of month into day
mov dh,ch ; get year and high bit of month
pop cx ; get time back
DoDClose:
cmp bx,0
jle CloseDone
mov ax,(FILE_TIMES shl 8) or 1
int 21h ; set date and time
jc Cleanup_Err ;AN022; handle error
; See if the destination has *anything* in it.
; If not, just close and delete it.
mov ax,(LSEEK shl 8) + 2 ; seek to EOF
xor dx,dx
mov cx,dx
int 21h
; DX:AX is file size
or dx,ax
pushf
mov ax,(IOCTL SHL 8) + 0 ; get the destination attributes
int 21h
push dx ; save them away
mov ah,CLOSE
int 21h
pop dx
jnc Close_Cont ;AN022; handle error on close
popf ;AN022; get the flags back
Cleanup_Err: ;AN022;
call CleanUpErr ;AN022; attempt to delete the target
call DestDelete ;AN022; attempt to delete the target
jmp short FileClosed ;AN022; close the file
Close_Cont: ;AN022; no error - continue
popf
jnz CloseDone
test dx,80h ; is the destination a device?
jnz CloseDone ; yes, copy succeeded
call DestDelete
jmp short FileClosed
CloseDone:
inc FileCnt
FileClosed:
inc DestClosed
Ret50:
clc
return
ForgetIt:
mov bx,DestHand
call DoDClose ; close the dest
call DestDelete
mov FileCnt,0 ; no files transferred
jmp Ret50
DestDelete:
mov dx,offset TRANGROUP:DestBuf
mov ah,UNLINK
int 21h ; and delete it
return
Source_Set proc near
push si
mov ax,StartEl
mov si,offset TRANGROUP:ScanBuf ; adjust to copy
sub ax,si
mov di,offset TRANGROUP:SrcBuf
add ax,di
mov SrcTail,ax
mov SrcSiz,cl ; save its size
inc cx ; include the nul
rep movsb ; save this source
mov SrcInfo,bh ; save info about it
pop si
mov ax,bp ; switches so far
invoke SetAsc ; set a,b switches accordingly
invoke Switch ; get any more switches on this arg
invoke SetAsc ; set
return
Source_Set endp
;****************************************************************
;*
;* ROUTINE: CleanupErr
;*
;* FUNCTION: Issues extended error message for destination
;* if not alreay issued
;*
;* INPUT: return from INT 21
;*
;* OUTPUT: none
;*
;****************************************************************
CleanupErr proc near ;AN022;
cmp Msg_Flag,0 ;AN022; have we already issued a message?
jnz CleanupErr_Cont ;AN022; yes - don't issue duplicate error
invoke Set_Ext_Error_Msg ;AN022; set up error message
mov String_Ptr_2,offset TRANGROUP:DestBuf ;AN022; get address of failed string
mov Extend_Buf_Sub,ONE_SUBST ;AN022; put number of subst in control block
invoke Std_EPrintF ;AN022; issue the error message
CleanupErr_Cont: ;AN022;
ret ;AN022; return to caller
CleanupErr endp ;AN022;
TRANCODE ends
end