Metropoli BBS
VIEWER: filecopy.asm MODE: TEXT (ASCII)
;FileCopy.ASM - copies a source file to a target file.
;Written by J. R. Conrad, Baltimore, MD

;----------------------------------------------------------------------
;   1) Assemble FileCopy.Asm to FileCopy.Obj
;   2) Use BuildLib to add FileCopy.Obj to UserLib.Exe
;----------------------------------------------------------------------
;Basic Syntax:  Call FileCopy(InFile$, OutFile$, Buffer$, ErrCode%).
;       Where:  InFile$  =      source path and filename,
;               OutFile$ =      target path and filename,
;               Buffer$  =      blank string (64 < Len < 32768)
;               ErrCode% =      1 if source path not found
;                               2 if source file not found (3 not used)
;                               4 if source file is a directory
;                               5 if source file not accessible
;                               6 if target path not found
;                               7 if target filename is invalid
;                               8 if target directory is full
;                               9 if target file is a directory
;                              10 if target file is read-only
;                              11 if target file not accessible
;                              12 if target disk is full
;                              13 if length of Buffer$ < 65 bytes
;
;       Notes:  1) Critical errors must be captured with On Error,
;               2) Always reenter with ErrCode% = -1 after critical errors.
;-----------------------------------------------------------------------
Code            Segment Byte Public 'Code'
                Assume  CS:Code
                Public  FileCopy

FileCopy        Proc    Far
Begin:          Jmp     Start           ;Local data follows:
Source_Handle   DW      0
Target_Handle   DW      0
Buffer_Size     DW      0
Bytes_Read      DW      0
File_Time       DW      ?
File_Date       DW      ?
Root_Test       DB      ':\',0

Start:          Push    BP              ;Save BP.
                Mov     BP,SP           ;Get stack pointer to parameters.
                Mov     AX,DS           ;Insure ES = DS.
                Mov     ES,AX
                Xor     BX,BX           ;Zero error code.
                Cld                     ;Forward string primitives.
                Mov     SI,[BP+6]       ;Recover from critical error?
                Cmp     Word Ptr [SI],-1  ;If ErrCode% = -1,
                Jne     Check_Buffer      ;  then close open files from
                Jmp     Close_Files       ;  previous call.
Check_Buffer:   Mov     SI,[BP+8]         ;Make sure buffer is big enough:
                Cmp     Word Ptr [SI],64  ;  is it longer than 64 char?
                Ja      Open_Source       ;If so, then continue.
                Mov     BX,13             ;Else, set ErrCode% and return.
                Jmp     Close_Files

Open_Source:    Mov     AX,[SI]           ;Save buffer size.
                Mov     Buffer_Size,AX
                Mov     DX,[SI+2]         ;DX = offset of Buffer$
                Mov     SI,[BP+12]        ;Point SI to InFile$.
                Mov     BX,1              ;Init error code.
                Call    Load_File         ;Convert to ASCIIZ.
                Mov     AX,3D00h          ;Request Open File (read-only).
                Int     21h
                Jnc     Open_Target       ;Did an error occur?
                Call    Find_Err          ;If so, run the error analysis.
                Je      Source_Err        ;   If ZF, error was found.
                Inc     BX                ;   Else, access denied.
Source_Err:     Jmp     Close_Files

Open_Target:    Mov     Source_Handle,AX  ;Save the source file handle.
                Mov     BX,AX             ;Save file handle in BX
                Mov     AX,5700h          ;Get time and date from source
                Push    DX                ;Save buffer$ address in DX
                Int     21h               ;Get source file's date and time
                Mov     File_Time,CX      ;  save them
                Mov     File_Date,DX      ;  internally
                Pop     DX                ;Retrieve DX
                Mov     SI,[BP+10]        ;Point SI to OutFile$.
                Mov     BX,6              ;Init error code.
                Call    Load_File         ;Convert to ASCIIZ.
                Mov     AH,3Ch            ;Request Create/Clear File:
                Mov     CX,0              ;  target is normal file,
                Int     21h               ;  do it.
                Jnc     Prep_Copy         ;Did an error occur?
                Call    Find_Err          ;If so, run the error analysis:
                Jc      Target_Err        ;  If CF, directory is full.
                Je      Target_Err        ;  If ZF, error was found.
                Inc     BX
                Test    AX,1              ;  Else, if NOT (attribute AND 1),
                Jz      Target_Err        ;    target is read-only.
                Inc     BX                ;  Else, access denied.
Target_Err:     Jmp     Close_Files

Prep_Copy:      Mov     Target_Handle,AX  ;Save the target file handle.
                Mov     CX,Buffer_Size    ;Put buffer size in CX.
Do_Copy:        Mov     AH,3Fh            ;Request Read from File service:
                Mov     BX,Source_Handle  ;  retrieve source handle,
                Int     21h               ;  do it.
                Mov     Bytes_Read,AX     ;Store bytes actually read,
                Mov     CX,AX             ;  store in CX for write.
                Mov     AH,40h            ;Request Write to File service:
                Mov     BX,Target_Handle  ;  retrieve handle,
                Int     21h               ;  do it.
                Mov     BX,12             ;Test for full disk:
                Cmp     AX,CX             ;  if bytes written <> read,
                Jne     Close_Files       ;  then disk is full.
                Mov     CX,Buffer_Size    ;Retrieve buffer size.
                Cmp     CX,Bytes_Read     ;Test for EOF.
                Je      Do_Copy
                Mov     AX,5701h          ;Set target file date and time
                Mov     BX,Target_Handle  ;Specify target file handle
                Mov     CX,File_Time      ;Use the source date and time
                Mov     DX,File_Date      ;  saved earlier
                Int     21h
                Xor     BX,BX             ;Successful copy, error code = 0!

Close_Files:    Cmp     Source_Handle,0   ;Is source open?
                Je      Basic_Return      ;  If no, then no files open.
                Push    BX                ;Save BX for widow check.
                Cmp     Target_Handle,0   ;Is target open?
                Je      Source_Only       ;  If no, then only source open.
                Mov     AH,3Eh            ;Request file closing service.
                Mov     BX,Target_Handle  ;Close target file.
                Int     21h
                Mov     Target_Handle,0
Source_Only:    Mov     AH,3Eh            ;Request file closing service.
                Mov     BX,Source_Handle  ;Close source file.
                Int     21h
                Mov     Source_Handle,0
Widow_Check:    Pop     BX                ;Check for disk full case.
                Cmp     BX,12             ;If disk full error, then delete
                Jne     Basic_Return      ;  partial target file.
                Mov     SI,[BP+10]        ;Point SI to OutFile$.
                Call    Load_File         ;Convert to ASCIIZ.
                Mov     AH,41h            ;Request file deletion service.
                Int     21h
Basic_Return:   Mov     DI,[BP+6]         ;Set error flag.
                Mov     [DI],BX
                Pop     BP                ;Restore BP.
                Ret     8                 ;Cleanup stack and return.


Load_File       Proc    Near              ;Convert filename to ASCIIZ format:
                Mov     CX,[SI]           ;Get length of string,
                Cmp     CX,64             ;Is the string too long?
                Jbe     Do_Load           ;If not, continue w/ load.
                Add     SP,2              ;Else, fix the stack
                Jmp     Close_Files       ;  and jump to exit.
Do_Load:        Mov     SI,[SI+2]         ;Point SI to filename.
                Mov     DI,DX             ;Point DI to buffer.
                Rep     Movsb             ;Transfer pathname
                Mov     Byte Ptr [DI],0   ;  and make ASCIIZ.
                Ret
Load_File       Endp


Find_Err        Proc    Near              ;Determine source of error.
                Cmp     AX,3              ;If AX = 3,
                Je      End_Find          ;  then invalid path.
                Inc     BX
                Cmp     AX,2              ;Else, if AX = 2,
                Je      End_Find          ;  then file not found.
                Inc     BX
                Mov     AX,4300h          ;Else, retrieve file attribute.
                Int     21h
                Jc      End_Find          ;If carry, file does not exist.
                Inc     BX
                Mov     AX,CX             ;Save attribute in AX.
                Xor     AX,0FFFFh         ;Use inverted logic!
                Test    AX,10h            ;Test for a subdirectory.
                Je      End_Find          ;If ZF, then subdirectory.
                Mov     CX,3              ;Else, check for root directory:
                Mov     SI,Offset Root_Test ;  point SI to root string,
                Mov     DI,DX               ;  point DI to 2nd character,
                Inc     DI
                Repe    Cmps CS:Byte Ptr [SI],[DI]  ;compare strings,
                Clc                       ; cancel side-effect on carry.
End_Find:       Ret
Find_Err        Endp

FileCopy        Endp
Code            Ends
End             Begin

[ RETURN TO DIRECTORY ]