title 'FDOS IOCTL - DOS file system input/output control' ; File : $FIOCTL.A86$ ; ; Description : ; ; Original Author : DIGITAL RESEARCH ; ; Last Edited By : $CALDERA$ ; ;-----------------------------------------------------------------------; ; Copyright Work of Caldera, Inc. All Rights Reserved. ; ; THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL, ; PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC. ; ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES ; WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF ; THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO ; HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE ; AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE ; AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED, ; COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED, ; CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST, ; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF ; CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT ; AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND ; CIVIL LIABILITY. ;-----------------------------------------------------------------------; ; ; *** Current Edit History *** ; *** End of Current Edit History *** ; $Log$ ; FIOCTL.A86 1.18 93/12/09 23:39:17 ; Move non-inherited bit to correct place in file handle ; FIOCTL.A86 1.17 93/11/03 13:38:29 ; Int 21 4409 return 0x0080 if drive is joined ; FIOCTL.A86 1.16 93/11/02 18:04:17 ; Int21/4400 from file returns AH=0 ; FIOCTL.A86 1.15 93/09/14 20:03:15 ; Trust LFLG_PHYSICAL ; FIOCTL.A86 1.12 93/06/17 22:11:50 ; support for ioctl 10/11 query ioctl support ; FIOCTL.A86 1.11 93/06/16 16:21:37 ; Codepage preparation bug fixed ; ENDLOG ; Date Modification ; --------- --------------------------------------- ; 29 Jun 89 Initial version splits from FDOS ; 21 Nov 89 iocE/F use relative unit number ; 12 Dec 89 ioc2/3 zero the unused portions of req hdr ; save a few bytes in other ioc's while I'm here ; 4 Jun 90 default file access permissions and user group support ; 5 Jun 90 ioc0/1 tidied up ; 12 Jun 90 get_doshndl parameter in BX not AX ; 2 Oct 90 net_vec moves to per-VC basis (info held in CCB_) ; 13 feb 91 ioc1 tests FHIO_DEV, not HM_DEV, (123 MSNet printing) ; 7 may 91 ioc2,ioc3,ioc6,ioc7,iocC destabilised for Lanstatic ; by-product is ioc6 for disks returns read-ahead char ; in AH ; 28 feb 92 ioctl C checks bit 6 not bit 14 in DH_ATTRIB ; 3 aug 92 ioctl C/D pass thru' SI/DI ; 5 aug 92 substatial ioctl rework saves a few bytes - ioctl ; request header now built by PCMODE eject ! include i:fdos.equ eject ! include rh.equ eject ! include i:msdos.equ eject ! include i:mserror.equ eject ! include i:doshndl.def ; DOS Handle Structures eject ! include i:driver.equ eject ! include i:f52data.def ; DRDOS Structures eject PCMODE_DATA dseg BYTE extrn ioctlRH:byte ; request header is build in PCMODE ; data area BDOS_DATA dseg word extrn fdos_pb:word extrn fdos_ret:word extrn last_drv:byte extrn req_hdr:byte if PASSWORD extrn global_password:word endif BDOS_CODE cseg extrn local_disk:near extrn device_driver:near extrn block_device_driver:near extrn fdos_error:near extrn fdos_ED_DRIVE:near extrn fdos_ED_FUNCTION:near extrn fdos_read:near extrn get_ddsc:near extrn vfy_dhndl_ptr:near extrn get_pb2_drive:near extrn ioc6_dev:near ; IOCTL(6): input status for device extrn ioc7_dev:near ; IOCTL(7): output status for device extrn vfy_dhndl_ptr:near extrn verify_handle:near extrn reload_registers:near if JOIN extrn get_ldt:near endif if PASSWORD extrn hash_pwd:near endif public fdos_ioctl eject ; INPUT/OUTPUT CONTROL (IOCTL) ; +----+----+----+----+----+----+----+----+----+----+ ; | 26 | param | func | request header | ; +----+----+----+----+----+----+----+----+----+----+ ; entry: ; ------ ; param: handle/drive on some functions ; func: sub function (0-A) ; request header: far pointer to IOCTL request header ; exit: ; ----- ; AX: return code or error code ( < 0) ; param: return value from some functions ioctl_tbl dw ioctl0 ; 0-get handle status dw ioctl1 ; 1-set handle status dw ioctl2 ; 2-receive control string (handle) dw ioctl3 ; 3-send control string (handle) dw ioctl4 ; 4-receive control string (drive) dw ioctl5 ; 5-send control string (drive) dw ioctl6 ; 6-input status dw ioctl7 ; 7-output status dw ioctl8 ; 8-removable media check dw ioctl9 ; 9-networked drive check dw ioctlA ; A-networked handle check if PASSWORD dw ioctl54 ; B-set global password else dw device_ED_FUNCTION endif dw ioctlC ; C-code page support dw ioctlD ; D-generic IOCTL disk i/o dw ioctlE ; E-get logical drive dw ioctlF ; F-set logical drive dw ioctl10 ; 10-query IOCTL for char devs dw ioctl11 ; 11-query IOCTL for disks NUM_IOCTL equ (offset $ - offset ioctl_tbl)/WORD fdos_ioctl: ;---------- mov bx,2[bp] ; BX -> parameter block mov bx,4[bx] ; get I/O control subfunction cmp bx,NUM_IOCTL ; is it in the supported range? jae device_ED_FUNCTION ; skip if value too large shl bx,1 ; else make it word index jmp ioctl_tbl[bx] ; call the right function device_ED_FUNCTION: mov bx,ED_FUNCTION ; "invalid function" ret ioctl0: ; get device status ;------ ; Note: We store the binary flag for the standard console ; handles in the console mode, not in the file handle, ; as the handles are shared across all consoles... call vfy_dhndl_ptr ; check if good handle mov ax,es:DHNDL_WATTR[bx] ; get attrib from doshndl test ah,DHAT_REMOTE/256 mov ah,0 ; files/networks return 0 in AH/DH jnz device_OK ; return attrib if network device test al,DHAT_DEV ; or a file jz device_OK les bx,es:DHNDL_DEVPTR[bx] ; get real device driver address mov ah,es:byte ptr 5[bx] ; get device driver attribute ; jmp device_OK device_OK: ;--------- mov bx,2[bp] ; get parameter block address mov 6[bx],ax ; save returned status xor bx,bx ; successful return code ret ioctl1: ; set device status ;------ call vfy_dhndl_ptr ; make sure this is an open handle test es:DHNDL_WATTR[bx],DHAT_DEV jz device_ED_FUNCTION ; can't set status of disk files mov ax,word ptr ioctlRH+14 ; pick up new device status test ah,ah ; test if high byte is zero jnz device_ED_FUNCTION ; skip if O.K. or al,DHAT_DEV ; make sure it stays a device mov es:DHNDL_ATTR[bx],al ; store ioctl state in doshndl jmps device_OK ; success ioctl2: ; receive control string (devicehandle) ;------ ioctl3: ; send control string (device handle) ;------ ioctlC: ; generic ioctl (device handle) ;------ ioctl10: ; query ioctl support (device handle) ;------- call vfy_dhndl_ptr ; check file handle # call local_disk ; get MXdisk call verify_handle ; make sure the handle is good jnc short_fdos_ED_FUNCTION ; and is for a DEVICE xor cx,cx ; device relative unit # always zero les si,es:DHNDL_DEVPTR[bx] ; ES:SI -> device driver jmps ioc2345CDcommon ; now use common code ioctl4: ; receive control string (drive) ;------ ioctl5: ; send control string (drive) ;------ ioctlD: ; generic ioctl (drive) ;------ ioctl11: ; query ioctl support (drive) ;------- call local_disk ; get MXdisk, switch stack call get_pb2_ddsc ; get drives DDSC_ mov cl,es:DDSC_RUNIT[bx] ; get relative unit # les si,es:DDSC_DEVHEAD[bx] ; ES:SI -> device header ; jmps ioctl2345Common ; now use common code ioc2345CDcommon: ;--------------- ; On Entry: ; ES:SI -> device driver header ; CL = media byte (0 if character device) ; CH = relative unit (0 if character device) ; MXDisk obtained ; On Exit: ; IOCTL performed ; mov ax,fdos_pb+6 ; device driver support required test es:DH_ATTRIB[si],ax ; does device driver support function ? jz short_fdos_ED_FUNCTION push ds push es ! pop ds ; DS:SI -> device driver push ss ! pop es mov bx,offset ioctlRH ; ES:BX -> request header mov es:RH_UNIT[bx],cl ; set relative unit for block devices call device_driver ; call the device driver pop ds ; check for errors on return ; jmp fdos_error_check fdos_error_check: ;------------- ; On Entry: ; AX = Req Status ; On Exit: ; SIGN set if an error, AX&BX = Internal DOS error code ; test ax,ax ; top bit == 1 if error jns fdos_ioc_ec10 ; skip if no errors xor ah,ah add ax,-ED_PROTECT neg ax jmp fdos_error ; return critical error fdos_ioc_ec10: ret ; IOCTL subfunctions: get_pb2_ddsc: ;------------ ; On Entry: ; local_disk called, pick us drive from pb2 ; On Exit: ; ES:BX -> DDSC_ for the drive ; call get_pb2_drive ; get specified drive cmp al,last_drv ; is it a valid drive ja bad_drive call get_ldt ; ES:BX -> LDT for this drive jc get_pb2_ddsc10 ; no LDT, physical=logical mov ax,es:LDT_FLAGS[bx] test ah,LFLG_NETWRKD/256 jnz short_fdos_ED_FUNCTION ; reject network drives test ah,LFLG_PHYSICAL/256 jz bad_drive test ah,LFLG_JOINED/256 jnz bad_drive ; reject JOIN'd drives mov al,es:LDT_NAME[bx] ; get physical drive from LDT and al,1Fh ; convert to 1 based drive dec ax ; make that zero based get_pb2_ddsc10: call get_ddsc ; ES:BX -> DDSC_ jc bad_drive ; or does it? ret bad_drive: jmp fdos_ED_DRIVE ; invalid drive specified short_fdos_ED_FUNCTION: jmp fdos_ED_FUNCTION ioctl8: ; removable media check ;------ call local_disk ; get MXdisk, switch stack call get_pb2_ddsc ; get drives DDSC_ push ds lds si,es:DDSC_DEVHEAD[bx] ; DS:SI -> device driver test ds:DH_ATTRIB[si],DA_REMOVE pop ds ; do we support the check ? jz short_fdos_ED_FUNCTION ; if we don't then don't ask mov req_hdr,RH15_LEN mov req_hdr+2,CMD_FIXED_MEDIA call block_device_driver ; call the device driver js short_fdos_ED_FUNCTION and ax,RHS_BUSY ; BUSY bit set if permanent - we just xchg ah,al ; need to get bit in the right place shr ax,1 ; now 1 if permanent media mov fdos_pb+6,ax ; return status removable (=0) ioctl8_10: ret ioctl6: ; file input status ;------ call vfy_dhndl_ptr ; make sure this is an open handle mov ax,es:DHNDL_WATTR[bx] test ax,DHAT_REMOTE jnz ioctl6_10 ; always ask networked handles test ax,DHAT_DEV jz ioctl6_10 ; files are always askable jmp ioc6_dev ioctl6_10: ; disk files/network devices push es:DHNDL_POSLO[bx] ; save current position in file push es:DHNDL_POSHI[bx] ; so we can read ahead push es push bx ; save DHNDL_ too.. push bp ; save stack frame mov si,2[bp] ; SI -> parameter block mov ax,1 push ax ; read 1 byte ahead push ds ; use fdos_pb as read-ahead lea ax,6[si] ; buffer push ax push ds:word ptr 2[si] ; user file number mov ax,MS_X_READ ; READ function #, so we create push ax ; a dummy fdos_pb mov bx,sp ; SS:BX -> dummy fdos_pb mov cx,offset ioctl6_20 ; CX -> return address push cx ; Return to here push ss ; save parameter segment push bx ; save parameter offset push ax ; save sub-function mov bp,sp ; SS:BP -> working variables call fdos_read ; make FDOS_READ do the hard word add sp,4*WORD ; discard param's on stack ioctl6_20: add sp,4*WORD ; discard most of dummy fdos_pb pop cx ; return # read cmp bx,ED_LASTERROR ; did we succeed ? jb ioctl6_30 ; if so we can trust # read xor cx,cx ; else in error assume nothing ioctl6_30: pop bp ; recover stack frame pop bx ; rewind DHNDL_POS to where pop es pop es:DHNDL_POSHI[bx] ; it was before we started pop es:DHNDL_POSLO[bx] mov ax,1a00h ; assume not ready jcxz ioctl6_40 dec ax ; AL = FF, ie. ready mov si,2[bp] ; SI -> parameter block mov ah,ds:byte ptr 6[si] ; get character we read ioctl6_40: jmp device_OK ioctl7: ; file output status ;------ call vfy_dhndl_ptr ; make sure this is an open handle mov ax,0FFh ; assume it's networked/disk mov dx,es:DHNDL_WATTR[bx] test dx,DHAT_REMOTE jnz ioctl6_40 ; networked handles are always ready test dx,DHAT_DEV jz ioctl6_40 ; files are always ready jmp ioc7_dev ; devices we ask... ioctl9: ; networked drive check ;------ call local_disk ; get disk semaphore call get_pb2_drive ; get specified drive call get_ldt ; ES:BX -> LDT for this drive jc ioctl940 mov ax,es:LDT_FLAGS[bx] test ah,LFLG_NETWRKD/256 jz ioctl910 if 1 mov ax,1000h ; return drive as remote else les di,es:LDT_PDT[bx] ; pick up network internal pointer mov ax,es:4[di] ; pick up garbage or ah,10h ; return drive as remote endif jmps ioctl930 ioctl910: test ah,LFLG_PHYSICAL/256 jz ioctl940 test ah,LFLG_SUBST/256 xchg ax,dx ; save flags mov ax,8000h ; assume it's SUBST'd jnz ioctl920 test dh,LFLG_JOINED/256 xchg al,ah ; assume it's JOIN'd jnz ioctl930 xor ax,ax ; clear if not ioctl920: push ax call get_pb2_ddsc ; get drives DDSC_ pop ax les si,es:DDSC_DEVHEAD[bx] ; ES:SI -> device driver or ax,es:4[si] ; get device attributes ioctl930: mov fdos_pb+6,ax ; return updated status ret ioctl940: jmp fdos_ED_DRIVE ; return ED_DRIVE error ioctlA: ; networked handle check ;------ call vfy_dhndl_ptr mov ax,es:DHNDL_WATTR[bx] jmp device_OK ; return attributes ioctlE: ;------ call local_disk mov al,CMD_GET_DEVICE ; get logical device jmps iocEFcommon ; common code for IOCTL(E)/IOCTL(F) ioctlF: ;------ call local_disk mov al,CMD_SET_DEVICE ; set logical device iocEFcommon: mov req_hdr,RH24_LEN mov req_hdr+2,al call get_pb2_ddsc ; get drives DDSC_ inc ax ; make drive one-relative mov req_hdr+13,al ; set this as new drive xor ax,ax ; assume not supported push ds lds si,es:DDSC_DEVHEAD[bx] ; does device driver support function ? test ds:DH_ATTRIB[si],DA_GETSET pop ds jz iocF_single ; skip if not supported call block_device_driver ; call the device driver call fdos_error_check ; return any errors mov al,req_hdr+1 ; get returned drive iocF_single: ; AX = return value mov ah,7 mov fdos_pb+6,ax ; return the drive ret if PASSWORD ioctl54: ; set global password ;------- call local_disk ; get the MX disk push ds lds si,dword ptr ioctlRH+14 call hash_pwd ; encrypt new default password pop ds mov global_password,ax ret endif end