587 lines
12 KiB
NASM
587 lines
12 KiB
NASM
page ,132
|
||
;/*
|
||
; * Microsoft Confidential
|
||
; * Copyright (C) Microsoft Corporation 1991
|
||
; * All Rights Reserved.
|
||
; */
|
||
|
||
;
|
||
; Revision History
|
||
; ================
|
||
;
|
||
;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 operation.
|
||
;
|
||
;
|
||
|
||
|
||
|
||
|
||
.xlist
|
||
.xcref
|
||
include comsw.asm
|
||
include dossym.inc
|
||
include syscall.inc
|
||
include sf.inc
|
||
include comseg.asm
|
||
include comequ.asm
|
||
.list
|
||
.cref
|
||
|
||
|
||
TRANDATA segment public byte
|
||
extrn FulDir_Ptr:word ;AN052;
|
||
TRANDATA ends
|
||
|
||
TRANSPACE segment public byte
|
||
extrn Ascii:byte
|
||
extrn Binary:byte
|
||
extrn Concat:byte
|
||
extrn DestBuf:byte
|
||
extrn DestFcb:byte
|
||
extrn DestInfo:byte
|
||
extrn DestIsDir:byte
|
||
extrn DestTail:word
|
||
extrn DestVars:byte
|
||
extrn DirBuf:byte
|
||
extrn DirChar:byte
|
||
extrn FirstDest:byte
|
||
extrn Inexact:byte
|
||
extrn MelCopy:byte
|
||
extrn NxtAdd:word
|
||
extrn Plus:byte
|
||
extrn SDirBuf:byte
|
||
extrn SrcInfo:byte
|
||
extrn SrcXName:byte
|
||
extrn Tpa:word
|
||
extrn TrgXName:byte
|
||
extrn UserDir1:byte
|
||
TRANSPACE ends
|
||
|
||
TRANCODE segment public byte
|
||
|
||
extrn BadPath_Err:near ;AN022;
|
||
extrn CopErr:near ;AN052;
|
||
extrn Extend_Setup:near ;AN022;
|
||
|
||
public BuildPath
|
||
public SetStars
|
||
public SetAsc
|
||
|
||
ASSUME cs:TRANGROUP,ds:TRANGROUP,es:TRANGROUP,ss:NOTHING
|
||
|
||
|
||
|
||
|
||
;*** SetAsc - set Ascii, Binary, Inexact flags based on switches
|
||
;
|
||
; Given switch vector in AX,
|
||
; Set Ascii flag if /a is set
|
||
; Clear Ascii flag if /b is set
|
||
; Binary set if /b specified
|
||
; Leave Ascii unchanged if neither or both are set
|
||
; Also sets Inexact if Ascii is ever set.
|
||
; AL = Ascii on exit, flags set
|
||
;
|
||
|
||
SetAsc:
|
||
|
||
and al,SWITCHA+SWITCHB ; AL = /a, /b flags
|
||
jpe LoadSw ; even parity - both or neither
|
||
push ax
|
||
and al,SWITCHB
|
||
mov Binary,al
|
||
pop ax
|
||
and al,SWITCHA
|
||
mov Ascii,al
|
||
or Inexact,al
|
||
|
||
LoadSw:
|
||
mov al,Ascii
|
||
or al,al
|
||
return
|
||
|
||
|
||
|
||
|
||
;*** BuildDest
|
||
|
||
public BuildDest
|
||
|
||
BuildDest:
|
||
|
||
cmp DestIsDir,-1
|
||
jne KnowAboutDest ; figuring already done
|
||
mov di,offset TRANGROUP:UserDir1
|
||
mov bp,offset TRANGROUP:DestVars
|
||
call BuildPath
|
||
invoke RestUDir1
|
||
|
||
; We now know all about the destination.
|
||
|
||
KnowAboutDest:
|
||
xor al,al
|
||
xchg al,FirstDest
|
||
or al,al
|
||
jnz FirstDst
|
||
jmp NotFirstDest
|
||
|
||
FirstDst:
|
||
|
||
; Create an fcb of the original dest.
|
||
|
||
mov si,DestTail
|
||
mov di,offset TRANGROUP:DestFcb
|
||
mov ax,PARSE_FILE_DESCRIPTOR shl 8
|
||
int 21h
|
||
cmp byte ptr [si],0
|
||
je GoodParse
|
||
;AD052; mov byte ptr [di+1],"|" ; must be illegal file name character
|
||
mov dx,offset TRANGROUP:FulDir_Ptr ;AN052; issue "file creation error"
|
||
jmp CopErr ;AN052;
|
||
|
||
GoodParse:
|
||
mov ax,word ptr DestBuf ; AX = possible "d:"
|
||
cmp ah,':'
|
||
je @f
|
||
mov al,'@'
|
||
@@:
|
||
; AX = "d:" for following FCB drive computation
|
||
|
||
mov cl,Ascii ; CL = saved Ascii flag
|
||
or al,20h
|
||
sub al,60h
|
||
mov DestFcb,al ; store drive # in FCB
|
||
|
||
;* Figure out what copy mode we're in.
|
||
; Letters stand for unambiguous, * for ambiguous pathnames.
|
||
; +n stands for additional sources delimited by +'s.
|
||
;
|
||
; copy a b not concatenating
|
||
; copy a * not concatenating
|
||
; copy * a concatenating
|
||
; copy * * not concatenating
|
||
; copy a+n b concatenating
|
||
; copy *+n a concatenating
|
||
; copy *+n * concatenating, Mel Hallorman style
|
||
|
||
; Bugbug: copy *.a+a.b *.t picks up only 1st *.a file.. Why?
|
||
; copy a.b+*.a *.t picks up all *.a files.
|
||
|
||
mov al,DestInfo ; AL = destination CParse flags
|
||
mov ah,SrcInfo ; AH = source CParse flags
|
||
and ax,0202h ; AH,AL = source,dest wildcard flags
|
||
or al,al
|
||
jz NotMelCopy ; no destination wildcard
|
||
|
||
; Destination is wildcarded.
|
||
|
||
cmp al,ah
|
||
jne NotMelCopy ; no source wildcard
|
||
|
||
; Source and destination are both wildcarded.
|
||
|
||
cmp Plus,0
|
||
je NotMelCopy ; no +'s in source
|
||
|
||
; Source and destination are wildcarded, and source includes +'s.
|
||
; It's Mel Hallorman copy time.
|
||
|
||
inc MelCopy ; 'Mel copy' = true
|
||
xor al,al
|
||
jmp short SetConc
|
||
|
||
NotMelCopy:
|
||
xor al,2 ; AL=0 -> ambiguous destination, 2 otherwise
|
||
and al,ah
|
||
shr al,1 ; AL=1 -> ambiguous source, unambiguous dest
|
||
; (implies concatenation)
|
||
|
||
SetConc:
|
||
or al,Plus ; "+" always infers concatenation
|
||
|
||
; Whew. AL = 1 if concatenating, 0 if not.
|
||
|
||
mov Concat,al
|
||
shl al,1
|
||
shl al,1
|
||
mov Inexact,al ; concatenation -> inexact copy
|
||
cmp Binary,0
|
||
jne NotFirstDest ; explicit binary copy
|
||
|
||
mov Ascii,al ; otherwise, concatenate in ascii mode
|
||
or cl,cl
|
||
jnz NotFirstDest ; Ascii flag set before, data read correctly
|
||
or al,al
|
||
jz NotFirstDest ; Ascii flag did not change state
|
||
|
||
; At this point there may already be binary read data in the read
|
||
; buffer. We need to find the first ^Z (if there is one) and trim the
|
||
; amount of data in the buffer correctly.
|
||
|
||
mov cx,NxtAdd
|
||
jcxz NotFirstDest ; no data, everything ok
|
||
mov al,1Ah
|
||
push es
|
||
xor di,di
|
||
mov es,Tpa
|
||
repne scasb ; scan for EOF
|
||
pop es
|
||
jne NotFirstDest ; no ^z in buffer, everything ok
|
||
dec di ; point at ^z
|
||
mov NxtAdd,di ; new buffer length
|
||
|
||
NOTFIRSTDEST:
|
||
mov bx,offset trangroup:DIRBUF+1 ; Source of replacement chars
|
||
cmp CONCAT,0
|
||
jz GOTCHRSRC ; Not a concat
|
||
mov bx,offset trangroup:SDIRBUF+1 ; Source of replacement chars
|
||
|
||
GOTCHRSRC:
|
||
mov si,offset trangroup:DESTFCB+1 ; Original dest name
|
||
mov di,DESTTAIL ; Where to put result
|
||
|
||
public buildname
|
||
BUILDNAME:
|
||
|
||
ifdef DBCS ; ### if DBCS ###
|
||
|
||
mov cx,8
|
||
call make_name
|
||
cmp byte ptr [si],' '
|
||
jz @f ; if no extention
|
||
mov al,dot_chr
|
||
stosb
|
||
mov cx,3
|
||
call make_name
|
||
@@:
|
||
xor al,al
|
||
stosb ; nul terminate
|
||
return
|
||
|
||
else ; ### if Not DBCS ###
|
||
|
||
mov cx,8
|
||
|
||
BUILDMAIN:
|
||
lodsb
|
||
cmp al,'?'
|
||
jnz NOTAMBIG
|
||
mov al,byte ptr [BX]
|
||
|
||
NOTAMBIG:
|
||
cmp al,' '
|
||
jz NOSTORE
|
||
stosb
|
||
|
||
NOSTORE:
|
||
inc bx
|
||
loop BUILDMAIN
|
||
mov cl,3
|
||
mov al,' '
|
||
cmp byte ptr [SI],al
|
||
jz ENDDEST ; No extension
|
||
mov al,dot_chr
|
||
stosb
|
||
|
||
BUILDEXT:
|
||
lodsb
|
||
cmp al,'?'
|
||
jnz NOTAMBIGE
|
||
mov al,byte ptr [BX]
|
||
|
||
NOTAMBIGE:
|
||
cmp al,' '
|
||
jz NOSTOREE
|
||
stosb
|
||
|
||
NOSTOREE:
|
||
inc bx
|
||
loop BUILDEXT
|
||
ENDDEST:
|
||
xor al,al
|
||
stosb ; NUL terminate
|
||
return
|
||
|
||
endif ; ### end if Not DBCS ###
|
||
|
||
|
||
ifdef DBCS ; ### if DBCS ###
|
||
make_name:
|
||
mov ah,0 ; reset DBCS flag
|
||
mov dh,cl ; save length to do
|
||
mkname_loop:
|
||
cmp ah,1 ; if it was lead byte
|
||
jz mkname_dbcs
|
||
mov ah,0 ; reset if it was single or tail byte
|
||
mov al,[bx] ; get source char
|
||
invoke testkanj
|
||
jz mkname_load ; if not lead byte
|
||
mkname_dbcs:
|
||
inc ah ; set dbcs flag
|
||
mkname_load:
|
||
lodsb ; get raw char
|
||
cmp al,'?'
|
||
jnz mkname_store ; if not '?'
|
||
cmp ah,0
|
||
jz mkname_conv ; if source is single
|
||
cmp ah,1
|
||
jnz mkname_pass ; if source is not lead
|
||
cmp cl,dh
|
||
jnz mkname_lead ; if this is not 1st char
|
||
cmp byte ptr [si],' '
|
||
jz mkname_double ; if this is the end
|
||
mkname_lead:
|
||
cmp byte ptr [si],'?'
|
||
jnz mkname_pass ; if no '?' for tail byte
|
||
cmp cx,1
|
||
jbe mkname_pass ; if no room for tail byte
|
||
mkname_double:
|
||
mov al,[bx]
|
||
stosb
|
||
inc bx
|
||
inc si
|
||
dec cx
|
||
inc ah ; tail byte will be loaded
|
||
mkname_conv:
|
||
mov al,[bx]
|
||
mkname_store:
|
||
cmp al,' '
|
||
jz mkname_pass
|
||
stosb ; store in destination
|
||
mkname_pass:
|
||
inc bx
|
||
loop mkname_loop
|
||
return
|
||
endif ; ### end if DBCS ###
|
||
|
||
BUILDPATH:
|
||
test [BP.INFO],2
|
||
jnz NOTPFILE ; If ambig don't bother with open
|
||
mov dx,bp
|
||
add dx,BUF ; Set DX to spec
|
||
|
||
push di ;AN000;
|
||
MOV AX,EXTOPEN SHL 8 ;AC000; open the file
|
||
mov bx,DENY_NONE or READ_OPEN_MODE ; open mode for COPY ;M046
|
||
xor cx,cx ;AN000; no special files
|
||
mov si,dx ;AN030; get file name offset
|
||
mov dx,read_open_flag ;AN000; set up open flags
|
||
INT 21h
|
||
pop di ;AN000;
|
||
jnc pure_file ;AN022; is pure file
|
||
invoke get_ext_error_number ;AN022; get the extended error
|
||
cmp ax,error_file_not_found ;AN022; if file not found - okay
|
||
jz notpfile ;AN022;
|
||
cmp ax,error_path_not_found ;AN022; if path not found - okay
|
||
jz notpfile ;AN022;
|
||
cmp ax,error_access_denied ;AN022; if access denied - okay
|
||
jz notpfile ;AN022;
|
||
jmp extend_setup ;AN022; exit with error
|
||
|
||
pure_file:
|
||
mov bx,ax ; Is pure file
|
||
mov ax,IOCTL SHL 8
|
||
INT 21h
|
||
mov ah,CLOSE
|
||
INT 21h
|
||
test dl,devid_ISDEV
|
||
jnz ISADEV ; If device, done
|
||
test [BP.INFO],4
|
||
jz ISSIMPFILE ; If no path seps, done
|
||
|
||
NOTPFILE:
|
||
mov dx,word ptr [BP.BUF]
|
||
cmp dl,0 ;AN034; If no drive specified, get
|
||
jz set_drive_spec ;AN034; default drive dir
|
||
cmp dh,':'
|
||
jz DRVSPEC5
|
||
|
||
set_drive_spec: ;AN034;
|
||
mov dl,'@'
|
||
|
||
DRVSPEC5:
|
||
or dl,20h
|
||
sub dl,60h ; A = 1
|
||
invoke SAVUDIR1
|
||
jnc curdir_ok ;AN022; if error - exit
|
||
invoke get_ext_error_number ;AN022; get the extended error
|
||
jmp extend_setup ;AN022; exit with error
|
||
|
||
curdir_ok: ;AN022;
|
||
mov dx,bp
|
||
add dx,BUF ; Set DX for upcomming CHDIRs
|
||
mov bh,[BP.INFO]
|
||
and bh,6
|
||
cmp bh,6 ; Ambig and path ?
|
||
jnz CHECKAMB ; jmp if no
|
||
mov si,[BP.TTAIL]
|
||
mov bl,':'
|
||
cmp byte ptr [si-2],bl
|
||
jnz KNOWNOTSPEC
|
||
mov [BP.ISDIR],2 ; Know is d:/file
|
||
jmp short DOPCDJ
|
||
|
||
KNOWNOTSPEC:
|
||
mov [BP.ISDIR],1 ; Know is path/file
|
||
dec si ; Point to the /
|
||
|
||
DOPCDJ:
|
||
jmp DOPCD ;AC022; need long jump
|
||
|
||
CHECKAMB:
|
||
cmp bh,2
|
||
jnz CHECKCD
|
||
|
||
ISSIMPFILE:
|
||
ISADEV:
|
||
mov [BP.ISDIR],0 ; Know is file since ambig but no path
|
||
return
|
||
|
||
CHECKCD:
|
||
invoke SETREST1
|
||
mov ah,CHDIR
|
||
INT 21h
|
||
jc NOTPDIR
|
||
mov di,dx
|
||
xor ax,ax
|
||
mov cx,ax
|
||
dec cx
|
||
|
||
Kloop: ;AN000; 3/3/KK
|
||
MOV AL,ES:[DI] ;AN000; 3/3/KK
|
||
INC DI ;AN000; 3/3/KK
|
||
OR AL,AL ;AN000; 3/3/KK
|
||
JZ Done ;AN000; 3/3/KK
|
||
xor ah,ah ;AN000; 3/3/KK
|
||
invoke Testkanj ;AN000; 3/3/KK
|
||
JZ Kloop ;AN000; 3/3/KK
|
||
INC DI ;AN000; 3/3/KK
|
||
INC AH ;AN000; 3/3/KK
|
||
jmp Kloop ;AN000; 3/3/KK
|
||
|
||
Done: ;AN000; 3/3/KK
|
||
dec di
|
||
mov al,DIRCHAR
|
||
mov [bp.ISDIR],2 ; assume d:/file
|
||
OR AH, AH ;AN000; 3/3/KK
|
||
JNZ Store_pchar ;AN000; 3/3/KK this is the trailing byte of ECS code
|
||
cmp al,[di-1]
|
||
jz GOTSRCSLSH
|
||
|
||
Store_pchar: ;AN000; 3/3/KK
|
||
stosb
|
||
mov [bp.ISDIR],1 ; know path/file
|
||
|
||
GOTSRCSLSH:
|
||
or [bp.INFO],6
|
||
call SETSTARS
|
||
return
|
||
|
||
|
||
NOTPDIR:
|
||
invoke get_ext_error_number ;AN022; get the extended error
|
||
cmp ax,error_path_not_found ;AN022; if path not found - okay
|
||
jz notpdir_try ;AN022;
|
||
cmp ax,error_access_denied ;AN022; if access denied - okay
|
||
jnz extend_setupj ;AN022; otherwise - exit error
|
||
|
||
notpdir_try: ;AN022;
|
||
mov [bp.ISDIR],0 ; assume pure file
|
||
mov bh,[bp.INFO]
|
||
test bh,4
|
||
retz ; Know pure file, no path seps
|
||
mov [bp.ISDIR],2 ; assume d:/file
|
||
mov si,[bp.TTAIL]
|
||
cmp byte ptr [si],0
|
||
jz BADCDERRJ2 ; Trailing '/'
|
||
mov bl,dot_chr
|
||
cmp byte ptr [si],bl
|
||
jz BADCDERRJ2 ; If . or .. pure cd should have worked
|
||
mov bl,':'
|
||
cmp byte ptr [si-2],bl
|
||
jz DOPCD ; Know d:/file
|
||
mov [bp.ISDIR],1 ; Know path/file
|
||
dec si ; Point at last '/'
|
||
|
||
DOPCD:
|
||
xor bl,bl
|
||
xchg bl,[SI] ; Stick in a NUL
|
||
invoke SETREST1
|
||
CMP DX,SI ;AN000; 3/3/KK
|
||
JAE LookBack ;AN000; 3/3/KK
|
||
PUSH SI ;AN000; 3/3/KK
|
||
PUSH CX ;AN000; 3/3/KK
|
||
MOV CX,SI ;AN000; 3/3/KK
|
||
MOV SI,DX ;AN000; 3/3/KK
|
||
|
||
Kloop2: ;AN000; 3/3/KK
|
||
LODSB ;AN000; 3/3/KK
|
||
invoke TestKanj ;AN000; 3/3/KK
|
||
jz NotKanj4 ;AN000; 3/3/KK
|
||
LODSB ;AN000; 3/3/KK
|
||
CMP SI,CX ;AN000; 3/3/KK
|
||
JB Kloop2 ;AN000; 3/3/KK
|
||
POP CX ;AN000; 3/3/KK
|
||
POP SI ;AN000; 3/3/KK
|
||
JMP SHORT DoCdr ;AN000; 3/3/KK Last char is ECS code, don't check for
|
||
; trailing path sep
|
||
NotKanj4: ;AN000; 3/3/KK
|
||
CMP SI,CX ;AN000; 3/3/KK
|
||
JB Kloop2 ;AN000; 3/3/KK
|
||
POP CX ;AN000; 3/3/KK
|
||
POP SI ;AN000; 3/3/KK
|
||
|
||
LookBack: ;AN000; 3/3/KK
|
||
CMP BL,[SI-1] ; if double slash, then complain.
|
||
JZ BadCDErrJ2
|
||
|
||
DoCdr: ;AN000; 3/3/KK
|
||
mov ah,CHDIR
|
||
INT 21h
|
||
xchg bl,[SI]
|
||
retnc
|
||
invoke get_ext_error_number ;AN022; get the extended error
|
||
|
||
EXTEND_SETUPJ: ;AN022;
|
||
JMP EXTEND_SETUP ;AN022; go issue the error message
|
||
|
||
BADCDERRJ2:
|
||
jmp badpath_err ;AC022; go issue path not found message
|
||
|
||
SETSTARS:
|
||
mov [bp.TTAIL],DI
|
||
add [bp.SIZ],12
|
||
mov ax,dot_qmark
|
||
mov cx,8
|
||
rep stosb
|
||
xchg al,ah
|
||
stosb
|
||
xchg al,ah
|
||
mov cl,3
|
||
rep stosb
|
||
xor al,al
|
||
stosb
|
||
return
|
||
|
||
PUBLIC CompName
|
||
COMPNAME:
|
||
|
||
mov si,offset trangroup:DESTBUF ;g do name translate of target
|
||
mov di,offset trangroup:TRGXNAME ;g save for name comparison
|
||
mov ah,xnametrans ;g
|
||
int 21h ;g
|
||
|
||
MOV si,offset trangroup:SRCXNAME ;g get name translate of source
|
||
MOV di,offset trangroup:TRGXNAME ;g get name translate of target
|
||
|
||
|
||
invoke STRCOMP
|
||
|
||
return
|
||
|
||
TRANCODE ENDS
|
||
END
|
||
|