page ,132 ; SCCSID = @(#)tcmd1b.asm 1.1 85/05/14 ; SCCSID = @(#)tcmd1b.asm 1.1 85/05/14 TITLE PART4 COMMAND Transient routines. ;/* ; * Microsoft Confidential ; * Copyright (C) Microsoft Corporation 1991 ; * All Rights Reserved. ; */ ; Internal commands DIR,PAUSE,ERASE,TYPE,VOL,VER .xlist .xcref include dossym.inc include bpb.inc include syscall.inc include filemode.inc include sf.inc include comseg.asm include comsw.asm ;ac000; include comequ.asm include ioctl.inc ;an000; .list .cref DATARES SEGMENT PUBLIC BYTE ;AN020;AC068; EXTRN append_flag:byte ;AN020;AC068; EXTRN append_state:word ;AN020;AC068; EXTRN SCS_PAUSE:BYTE ; yst 4-5-93 DATARES ENDS ;AN020;AC068; TRANDATA SEGMENT PUBLIC BYTE ;AC000; EXTRN badcpmes_ptr:word ;AC022; EXTRN Extend_buf_ptr:word ;AC000; EXTRN Extend_buf_sub:byte ;AN000; EXTRN inornot_ptr:word EXTRN msg_disp_class:byte ;AC000; EXTRN parse_erase:byte ;AC000; EXTRN parse_mrdir:byte ;AC000; EXTRN parse_rename:byte ;AC000; EXTRN parse_vol:byte ;AC000; EXTRN PauseMes_ptr:word EXTRN renerr_ptr:word EXTRN slash_p_syn:word ;AC000; EXTRN volmes_ptr:word ;AC000; EXTRN volmes_ptr_2:word ;AC000; EXTRN volsermes_ptr:word ;AC000; TRANDATA ENDS TRANSPACE SEGMENT PUBLIC BYTE ;AC000; EXTRN bytcnt:word EXTRN charbuf:byte EXTRN comsw:word EXTRN curdrv:byte EXTRN destinfo:byte EXTRN destisdir:byte EXTRN dirbuf:byte EXTRN msg_numb:word ;AN022; EXTRN one_char_val:byte EXTRN parse1_addr:dword ;AN000; EXTRN parse1_syn:word ;AN000; EXTRN resseg:word ;AN020;AC068; EXTRN srcbuf:byte ;AN000; EXTRN string_ptr_2:word ;AN000; EXTRN TPA:word EXTRN vol_drv:byte EXTRN vol_ioctl_buf:byte ;AC000; EXTRN vol_label:byte ;AC000; EXTRN vol_serial:dword ;AC000; EXTRN zflag:byte extrn TypeFilSiz:dword TRANSPACE ENDS TRANCODE SEGMENT PUBLIC BYTE ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING ;--------------- TRANSPACE SEGMENT PUBLIC BYTE ;AC000; EXTRN arg:byte ; the arg structure! transpace ends ;--------------- EXTRN cerror:near EXTRN error_output:near EXTRN notest2:near EXTRN slashp_erase:near ;AN000; EXTRN std_printf:near EXTRN tcommand:near PUBLIC badpath_err ;AN022; PUBLIC crename PUBLIC DisAppend PUBLIC erase PUBLIC extend_setup ;AN022; PUBLIC Get_ext_error_number ;AN022; PUBLIC pause PUBLIC Set_ext_error_msg ;AN000; PUBLIC typefil PUBLIC volume break Pause PAUSE: push ds mov ds, ResSeg assume ds:resgroup cmp SCS_PAUSE, 0 pop ds jne pause_break assume ds:trangroup,es:trangroup mov dx,offset trangroup:pausemes_ptr call std_printf invoke GetKeystroke invoke crlf2 pause_break: return break Erase ;**************************************************************** ;* ;* ROUTINE: DEL/ERASE - erase file(s) ;* ;* FUNCTION: PARSE command line for file or path name and /P ;* and invoke PATHCRUNCH. If an error occurs, set ;* up an error message and transfer control to CERROR. ;* Otherwise, transfer control to NOTEST2 if /P not ;* entered or SLASHP_ERASE if /P entered. ;* ;* INPUT: command line at offset 81H ;* ;* OUTPUT: if no error: ;* FCB at 5ch set up with filename(s) entered ;* Current directory set to entered directory ;* ;**************************************************************** assume ds:trangroup,es:trangroup ERASE: mov si,81H ;AC000; get command line mov comsw,0 ;AN000; clear switch indicator mov di,offset trangroup:parse_erase ;AN000; Get adderss of PARSE_erase xor cx,cx ;AN000; clear cx,dx erase_scan: xor dx,dx ;AN000; invoke parse_with_msg ;AC018; call parser cmp ax,end_of_line ;AN000; are we at end of line? jz good_line ;AN000; yes - done parsing cmp ax,result_no_error ;AC000; did we have an error? jnz errj2 ;AC000; yes exit cmp parse1_syn,offset trangroup:slash_p_syn ;AN000; was /P entered? je set_erase_prompt ;AN000; yes - go set prompt ; ; Must be filespec since no other matches occurred. move filename to srcbuf ; push si ;AC000; save position in line lds si,parse1_addr ;AC000; get address of filespec cmp byte ptr[si+1],colon_char ;AC000; drive specified? jnz Erase_drive_ok ;AC000; no - continue cmp byte ptr[si+2],end_of_line_out ;AC000; was only drive entered? jnz erase_drive_ok ;AC000; no - continue mov ax,error_file_not_found ;AN022; get message number in control block jmp short extend_setup ;AC000; exit erase_drive_ok: invoke move_to_srcbuf ;AC000; move to srcbuf pop si ;AC000; get position back jmp short erase_scan ;AN000; continue parsing set_erase_prompt: cmp comsw,0 ;AN018; was /P already entered? jz ok_to_set_erase_prompt ;AN018; no go set switch mov ax,moreargs_ptr ;AN018; set up too many arguments invoke setup_parse_error_msg ;AN018; set up an error message jmp short errj2 ;AN018; exit ok_to_set_erase_prompt: ;AN018; inc comsw ;AN000; indicate /p specified jmp short erase_scan ;AN000; continue parsing good_line: ;G We know line is good invoke pathcrunch jnc checkdr mov ax,[msg_numb] ;AN022; get message number cmp ax,0 ;AN022; was message flag set? jnz extend_setup ;AN022; yes - print out message cmp [destisdir],0 ; No CHDIRs worked jnz badpath_err ;AC022; see if they should have checkdr: cmp comsw,0 ;AN000; was /p specified jz notest2j ;AN000; no - go to notest2 jmp slashp_erase ;AN000; yes - go to slashp_erase notest2j: jmp notest2 badpath_err: ;AN022; "Path not found" message mov ax,error_path_not_found ;AN022; set up error number extend_setup: ;AN022; mov msg_disp_class,ext_msg_class ;AN022; set up extended error msg class mov dx,offset TranGroup:Extend_Buf_ptr ;AC022; get extended message pointer mov Extend_Buf_ptr,ax ;AN022; get message number in control block errj2: ;AC022; exit jump jmp Cerror ;AN022; break Rename ; **************************************************************** ; * ; * ROUTINE: CRENAME - rename file(s) ; * ; * FUNCTION: PARSE command line for one full filespec and one ; * filename. Invoke PATHCRUNCH on the full filespec. ; * Make sure the second filespec only contains a ; * filename. If both openands are valid, attempt ; * to rename the file. ; * ; * INPUT: command line at offset 81H ; * ; * OUTPUT: none ; * ; **************************************************************** assume ds:trangroup,es:trangroup CRENAME: mov si,81H ;AC000; Point to command line mov di,offset trangroup:parse_rename;AN000; Get adderss of PARSE_RENAME xor cx,cx ;AN000; clear cx,dx xor dx,dx ;AN000; invoke parse_with_msg ;AC018; call parser cmp ax,result_no_error ;AC000; did we have an error? ;; jz crename_no_parse_error ;AC000; no - continue jnz crename_parse_error ;AC000; Yes, fail. (need long jump) ; ; Get first file name returned from parse into our buffer ; crename_no_parse_error: push si ;AN000; save position in line lds si,parse1_addr ;AN000; get address of filespec invoke move_to_srcbuf ;AN000; move to srcbuf pop si ;AN000; restore position in line xor dx,dx ;AN000; clear dx invoke parse_with_msg ;AC018; call parser cmp ax,result_no_error ;AN000; did we have an error? JNZ crename_parse_error ;AN000; Yes, fail. ; ; Check the second file name for drive letter colon ; push si ;AN000; save position in line lds si,parse1_addr ;AC000; get address of path mov al,':' ;AC000; cmp [si+1],al ;AC000; Does the 2nd parm have a drive spec? jnz ren_no_drive ;AN000; Yes, error mov msg_disp_class,parse_msg_class ;AN000; set up parse error msg class mov dx,offset TranGroup:Extend_Buf_ptr ;AC000; get extended message pointer mov Extend_Buf_ptr,BadParm_ptr ;AN000; get "Invalid parameter" message number pop si ;AN000; crename_parse_error: ;AC022; jmp short errj ;AC000; ; ; Get second file name returned from parse into the fCB. Save ; character after file name so we can later check to make sure it ; isn't a path character. ; ren_no_drive: mov di,FCB+10H ;AC000; set up to parse second file name mov ax,(Parse_File_Descriptor SHL 8) OR 01H ;AC000; int 21h ;AC000; do the function lodsb ;AC000; Load char after filename mov one_char_val,al ;AN000; save char after filename pop si ;AN000; get line position back ; ; We have source and target. See if any args beyond. ; mov di,offset trangroup:parse_rename;AC000; get address of parse_rename invoke parse_check_eol ;AC000; are we at end of line? jnz crename_parse_error ;AN000; no, fail. invoke pathcrunch mov dx,offset trangroup:badcpmes_ptr jz errj2 ; If 1st parm a dir, print error msg jnc notest3 mov ax,[msg_numb] ;AN022; get message number cmp ax,0 ;AN022; was message flag set? jnz extend_setup ;AN022; yes - print out message cmp [destisdir],0 ; No CHDIRs worked jz notest3 ; see if they should have Jmp badpath_err ;AC022; set up error notest3: mov al,one_char_val ;AN000; move char into AX mov dx,offset trangroup:inornot_ptr ; Load invalid fname error ptr invoke pathchrcmp ; Is the char in al a path sep? jz errj ; Yes, error - 2nd arg must be ; filename only. mov ah,FCB_Rename mov dx,FCB int 21h cmp al, 0FFH ; Did an error occur?? jnz renameok invoke get_ext_error_number ;AN022; get extended error SaveReg ;AC022; Save results mov al, 0FFH ; Restore original error state renameok: push ax invoke restudir pop ax inc al retnz RestoreReg ;AC022; get the error number back cmp ax,error_file_not_found ;AN022; error file not found? jz use_renerr ;AN022; yes - use generic error message cmp ax,error_access_denied ;AN022; error file not found? jz use_renerr ;AN022; yes - use generic error message jmp extend_setup ;AN022; need long jump - use extended error use_renerr: mov dx,offset trangroup:RenErr_ptr ;AC022; ERRJ: jmp Cerror ret56: ret break Type ;**************************************************************** ;* ;* ROUTINE: TYPEFIL - Display the contents of a file to the ;* standard output device ;* ;* SYNTAX: TYPE filespec ;* ;* FUNCTION: If a valid filespec is found, read the file until ;* 1Ah and display the contents to STDOUT. ;* ;* INPUT: command line at offset 81H ;* ;* OUTPUT: none ;* ;**************************************************************** assume ds:trangroup,es:trangroup TYPEFIL: mov si,81H mov di,offset trangroup:parse_mrdir ;AN000; Get adderss of PARSE_MRDIR xor cx,cx ;AN000; clear cx,dx xor dx,dx ;AN000; invoke parse_with_msg ;AC018; call parser cmp ax,result_no_error ;AC000; did we have an error? jnz typefil_parse_error ;AN000; yes - issue error message push si ;AC000; save position in line lds si,parse1_addr ;AC000; get address of filespec invoke move_to_srcbuf ;AC000; move to srcbuf pop si ;AC000; get position back mov di,offset trangroup:parse_mrdir ;AC000; get address of parse_mrdir invoke parse_check_eol ;AC000; are we at end of line? jz gottarg ;AC000; yes - continue typefil_parse_error: ;AN000; no - set up error message and exit jmp Cerror gottarg: invoke setpath test [destinfo],00000010b ; Does the filespec contain wildcards jz nowilds ; No, continue processing mov dx,offset trangroup:inornot_ptr ; Yes, report error jmp Cerror nowilds: mov ax,ExtOpen SHL 8 ;AC000; open the file mov bx,read_open_mode ;AN000; get open mode for TYPE xor cx,cx ;AN000; no special files mov dx,read_open_flag ;AN000; set up open flags mov si,offset trangroup:srcbuf ;AN030; get file name int 21h jnc typecont ; If open worked, continue. Otherwise load Typerr: ;AN022; push cs ;AN022; make sure we have local segment pop ds ;AN022; invoke set_ext_error_msg ;AN022; mov string_ptr_2,offset trangroup:srcbuf ;AC022; get address of failed string mov Extend_buf_sub,one_subst ;AC022; put number of subst in control block jmp cerror ;AC022; exit typecont: mov bx,ax ;AC000; get Handle ;M043 ; We should do the LSEEK for filesize only if this handle belongs to a file ;and not if it belongs to a device. If device, set TypeFilSiz+2 to -1 to ;indicate it is a device. ; mov ax,(IOCTL shl 8) or 0 int 21h test dl,80h ;is it a device? jz not_device ;no, a file mov word ptr TypeFilSiz+2,-1 ;indicate it is a device jmp short dotype not_device: ;SR; ; Find the filesize by seeking to the end and then reset file pointer to ;start of file ; mov ax,(LSEEK shl 8) or 2 xor dx,dx mov cx,dx ;seek to end of file int 21h mov word ptr TypeFilSiz,ax mov word ptr TypeFilSiz+2,dx ;store filesize mov ax,(LSEEK shl 8) or 0 xor dx,dx int 21h ;reset file pointer to start dotype: ;M043 mov zflag,0 ; Reset ^Z flag mov ds,[TPA] xor dx,dx ASSUME DS:NOTHING typelp: cmp cs:[zflag],0 ;AC050; Is the ^Z flag set? retnz ; Yes, return mov cx,cs:[bytcnt] ;AC056; No, continue ; ;Update the filesize left to read ; cmp word ptr cs:TypeFilSiz+2,-1 ;is it a device? M043 je typ_read ;yes, just read from it; M043 cmp word ptr cs:TypeFilSiz+2,0 ;more than 64K left? jz lt64k ;no, do word subtraction sub word ptr cs:TypeFilSiz, cx sbb word ptr cs:TypeFilSiz+2, 0 ;update filesize jmp short typ_read ;do the read lt64k: cmp cx,word ptr cs:TypeFilSiz ;readsize <= buffer? jbe gtbuf ;yes, just update readsize ; ;Buffer size is larger than bytes to read ; mov cx,word ptr cs:TypeFilSiz jcxz typelp_ret mov word ptr cs:TypeFilSiz,0 jmp short typ_read gtbuf: sub word ptr cs:TypeFilSiz,cx ;update filesize remaining typ_read: mov ah,read int 21h jnc @f ;M043 jmp typerr ;M043 @@: ;M043 ;M043; jc typerr ;AN022; Exit if error mov cx,ax jcxz typelp_ret ;AC000; exit if nothing read push ds pop es ; Check to see if a ^Z was read. assume es:nothing xor di,di push ax mov al,1ah repnz scasb pop ax xchg ax,cx cmp ax,0 jnz foundz ; Yes, handle it cmp byte ptr [di-1],1ah ; No, double check jnz typecont2 ; No ^Z, continue foundz: sub cx,ax ; Otherwise change cx so that only those dec cx ; bytes up to but NOT including the ^Z push cs ; will be typed. pop es assume es:trangroup not zflag ; Turn on ^Z flag so that the routine typecont2: ; will quit after this write. push bx mov bx,1 mov ah,write int 21h pop bx jc Error_outputj cmp ax,cx jnz @f ;M043 jmp typelp ;M043 @@: ;M043 ;M043; jz typelp dec cx cmp ax,cx retz ; One less byte OK (^Z) Error_outputj: mov bx,1 mov ax,IOCTL SHL 8 int 21h test dl,devid_ISDEV retnz ; If device, no error message jmp error_output typelp_ret: ret break Volume assume ds:trangroup,es:trangroup ; ; VOLUME command displays the volume ID on the specified drive ; VOLUME: mov si,81H mov di,offset trangroup:parse_vol ;AN000; Get adderss of PARSE_VOL xor cx,cx ;AN000; clear cx,dx xor dx,dx ;AN000; invoke parse_with_msg ;AC018; call parser cmp ax,end_of_line ;AC000; are we at end of line? jz OkVolArg ;AC000; Yes, display default volume ID cmp ax,result_no_error ;AC000; did we have an error? jnz BadVolArg ;AC000; Yes, fail. ; ; We have parsed off the drive. See if there are any more chars left ; mov di,offset trangroup:parse_vol ;AC000; get address of parse_vol xor dx,dx ;AC000; invoke parse_check_eol ;AC000; call parser jz OkVolArg ;AC000; yes, end of road ; ; The line was not interpretable. Report an error. ; badvolarg: jmp Cerror ;*** DisAppend - disable APPEND ; ; ENTRY nothing ; ; EXIT nothing ; ; USED AX,BX ; ; EFFECTS ; ; APPEND is disabled. If it was active, it will be re-enabled ; after the command finishes, by the HeadFix routine. ; ; NOTE ; ; This routine must not be called more than once during a single ; command cycle. The second call would permanently disable APPEND. DisAppend proc assume ds:TRANGROUP,es:NOTHING push ds ; save DS push es ; save ES push di mov ax,APPENDINSTALL ; AX = Append Installed Check code int 2Fh ; talk to APPEND via multiplex or al,al jz daRet ; APPEND not installed, return mov ax,APPENDDOS ; AX = Get Append Version code int 2Fh ; talk to APPEND via multiplex cmp ax,0FFFFh jne daRet ; it's not a local version, return mov ax,APPENDGETSTATE ; AX = Get Function State code int 2Fh ; talk to APPEND via multiplex mov ds,ResSeg ; DS = resident seg addr assume ds:RESGROUP mov Append_State,bx ; Append_State = saved APPEND state mov Append_Flag,-1 ; Append_Flag = true, restore state xor bx,bx ; BX = APPEND state = off mov AX,APPENDSETSTATE ; AX = Set Append State code int 2Fh ; talk to APPEND via multiplex daRet: pop di pop es ; restore ES pop ds ; restore DS assume ds:TRANGROUP ret DisAppend endp ; ; Find the Volume ID on the disk. ; PUBLIC OkVolArg OKVOLARG: assume ds:TRANGROUP,es:TRANGROUP call DisAppend ; disable APPEND invoke crlf2 mov al,blank ;AN051; Print out a blank invoke print_char ;AN051; before volume message push ds pop es ; ; Volume IDs are only findable via extended FCBs or find_first with attributes ; of volume_id ONLY. ; mov di,FCB-7 ; Point to extended FCB beginning mov al,-1 ; Tag to indicate Extention stosb xor ax,ax ; Zero padding to volume label stosw stosw stosb mov al,attr_volume_ID ; Look for volume label stosb inc di ; Skip drive byte; it is already set mov cx,11 ; fill in remainder of file mov al,'?' rep stosb ; ; Set up transfer address (destination of search first information) ; mov dx,offset trangroup:dirbuf mov ah,set_DMA int 21h ; ; Do the search ; mov dx,FCB-7 mov ah,Dir_Search_First int 21h ;******************************** ; Print volume ID info push ax ;AC000; AX return from SEARCH_FIRST for VOL ID mov al,DS:[FCB] ;AC000; get drive letter add al,'@' cmp al,'@' jnz drvok mov al,[curdrv] add al,capital_A drvok: mov vol_drv,al ;AC000; get drive letter into argument pop ax ;AC000; get return code back or al,al ;AC000; volume label found? jz Get_vol_name ;AC000; volume label exists - go get it mov dx,offset trangroup:VolMes_ptr_2 ;AC000; set up no volume message jmp short print_serial ;AC000; go print it Get_vol_name: mov di,offset trangroup:charbuf mov dx,di mov si,offset trangroup:dirbuf + 8 ;AN000; 3/3/KK mov cx,11 ;AN000; 3/3/KK rep movsb ;AN000; 3/3/KK xor al,al ;AC000; store a zero to terminate the string stosb mov dx,offset trangroup:VolMes_ptr ;AC000; set up message PRINT_SERIAL: ; ; Attempt to get the volume serial number from the disk. If an error ; occurs, do not print volume serial number. ; push dx ;AN000; save message offset mov ax,(GetSetMediaID SHL 8) ;AC036; Get the volume serial info mov bl,DS:[FCB] ;AN000; get drive number from FCB mov dx,offset trangroup:vol_ioctl_buf ;AN000;target buffer int 21h ;AN000; do the call pop dx ;AN000; get message offset back jc printvol_end ;AN000; if error, just go print label call std_printf ;AC000; go print volume message mov al,blank ;AN051; Print out a blank invoke print_char ;AN051; before volume message mov dx,offset trangroup:VolSerMes_ptr ;AN000; get serial number message printvol_end: jmp std_printf ;AC000; go print and exit ;**************************************************************** ;* ;* ROUTINE: Set_ext_error_msg ;* ;* FUNCTION: Sets up extended error message for printing ;* ;* INPUT: return from INT 21 ;* ;* OUTPUT: extended error message set up in extended error ;* buffer. ;* ;**************************************************************** Set_ext_error_msg proc near ;AN000; call get_ext_error_number ;AC022; get the extended error mov msg_disp_class,ext_msg_class ;AN000; set up extended error msg class mov dx,offset TranGroup:Extend_Buf_ptr ;AC000; get extended message pointer mov Extend_Buf_ptr,ax ;AN000; get message number in control block stc ;AN000; make sure carry is set ret ;AN000; return Set_ext_error_msg endp ;AN000; ;**************************************************************** ;* ;* ROUTINE: Get_ext_error_number ;* ;* FUNCTION: Does get extended error function call ;* ;* INPUT: return from INT 21 ;* ;* OUTPUT: AX - extended error number ;* ;**************************************************************** Get_ext_error_number proc near ;AN022; SaveReg ;AN022; save registers mov ah,GetExtendedError ;AN022; get extended error xor bx,bx ;AN022; clear BX int 21h ;AN022; RestoreReg ;AN022; restore registers ret ;AN022; return Get_ext_error_number endp ;AN022; trancode ends end