title 'FCB - DOS file system FCB support' ; File : $FCBS.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$ ; FCBS.A86 1.10 93/11/11 15:38:14 ; Chart Master fix - fcb_readblk over > 64k is truncated to 64k and ; error 2 (Segment boundry overlap) is returned ; FCBS.A86 1.9 93/10/18 17:37:06 ; fix for >255 open files (PNW Server) ; ENDLOG eject ! include i:fdos.equ eject ! include i:msdos.equ eject ! include i:mserror.equ eject ! include i:doshndl.def ; DOS Handle Structures eject BDOS_DATA dseg word BDOS_CODE cseg extrn ifn2dhndl:near extrn parse_one:near extrn fdos_entry:near Public fdos_exit eject ; TERMINATE CHILD (EXIT) ; +----+----+ ; | 24 | ; +----+----+ ; entry: ; ------ ; -none- ; exit: ; ----- ; -none- ; Close down all FCB handles associated with the current PSP ; fdos_exit: ;--------- push ds push ss ! pop ds ; DS -> PCM_DSEG sub ax,ax ; start with first DHNDL_ fdos_exit10: call ifn2dhndl ; get DHNDL_ jc fdos_exit40 ; stop if we have run out mov fcb_pb+2,ax ; we may close this IFN push ax mov cx,es:DHNDL_COUNT[bx] ; get the open count jcxz fdos_exit30 ; skip if nothing to do mov ax,current_psp ; get current PSP cmp ax,es:DHNDL_PSP[bx] ; does it belong to this PSP jne fdos_exit30 mov ax,ss:machine_id ; get current process cmp ax,es:DHNDL_UID[bx] jne fdos_exit30 test es:DHNDL_MODE[bx],DHM_FCB jz fdos_exit20 ; skip close if not FCB push es push bx ; save the DHNDL mov ax,MS_X_CLOSE call fcb_fdos ; make the FDOS do the work pop bx pop es ; recover the DHNDL fdos_exit20: mov es:DHNDL_COUNT[bx],0 ; always free the handle if it's ours fdos_exit30: pop ax inc al ; onto next IFN jnz fdos_exit10 fdos_exit40: pop ds ret Public fdos_fcb eject ; GENERIC FCB FUNCTION (FCB) ; +----+----+----+----+----+----+----+----+ ; | 22 | fcbadr | count | ; +----+----+----+----+----+----+----+----+ ; | func | ; +----+----+ ; entry: ; ------ ; fcbadr: FCB address ; count: multi-sector count for read/write ; func: FCB sub-function ; exit: ; ----- ; AX: return code or error code ( < 0) fdos_fcb: ;-------- mov bx,2[bp] ; BX -> parameter block mov bx,8[bx] ; get subfunction code shl bx,1 ; make it word index sub bl,15*WORD ; adjust to base address jc fcb_error ; reject if too low cmp bl,FCB_MAX1 ; is it in 1st block jb fdos_fcb10 sub bl,(33-24)*WORD ; adjust for gap jc fcb_error cmp bl,FCB_MAX2 ; is it in 2nd block jb fdos_fcb10 sub bl,(39-37)*WORD ; adjust for gap jc fcb_error fdos_fcb10: cmp bx,FCB_MAX3 ; check the range jae fcb_error ; skip if invalid function jmp fcb_table[bx] ; call the right function fcb_error: mov bx,ED_FUNCTION ret fcb_table dw fcb_open ; 15-open file dw fcb_close ; 16-close file dw fcb_first ; 17-find first dw fcb_next ; 18-find next dw fcb_delete ; 19-delete file dw fcb_read ; 20-read from file dw fcb_write ; 21-write to file dw fcb_make ; 22-make file dw fcb_rename ; 23-rename file FCB_MAX1 equ (offset $ - offset fcb_table) dw fcb_readrand ; 33-read from file dw fcb_writerand ; 34-write to file dw fcb_size ; 35-compute file size dw fcb_setrecord ; 36-set relative record FCB_MAX2 equ (offset $ - offset fcb_table) dw fcb_readblk ; 39-read from file dw fcb_writeblk ; 40-write to file FCB_MAX3 equ (offset $ - offset fcb_table) fcb_make: ;-------- call fcb_path_prep ; build pathname mov ax,MS_X_CREAT jmps fcb_open_make_common fcb_open: ;-------- call fcb_path_prep ; build pathname mov ax,MS_X_OPEN fcb_open_make_common: mov fcb_pb+6,DHM_RW+DHM_FCB ; open as an FCB for read/write call fcb_fdos ; lets try and open the file jnc fcb_open10 ; skip if we can't ret fcb_open10: call ifn2dhndl ; ES:BX -> DHNDL_ we have opened push ds push es ! push bx ; save DHNDL_ call fcb_point ; ES:BX = FCB pop si ! pop ds ; DS:SI -> DHNDL_ mov es:MSF_IFN[bx],al ; store IFN away mov es:MSF_BLOCK[bx],0 ; current block number mov es:MSF_RECSIZE[bx],128 ; current logical record size call fcb_update ; update misc changing fields mov ax,ds:DHNDL_DEVOFF[si] mov es:word ptr MSF_DEVPTR[bx],ax mov ax,ds:DHNDL_DEVSEG[si] mov es:word ptr MSF_DEVPTR+2[bx],ax mov ax,ds:DHNDL_BLK1[si] mov es:MSF_BLOCK1[bx],ax mov al,ds:DHNDL_ATTR[si] mov es:MSF_IOCTL[bx],al mov al,es:MSF_DRIVE[bx] ; get drive from FCB dec al ; was absolute drive specified ? jns fcb_open20 ; if so use it mov al,ss:current_dsk ; else use default drive fcb_open20: inc al ; make drive 1 rather than 0 based mov es:MSF_DRIVE[bx],al ; drive code if 0 test ds:DHNDL_DATRB[si],DA_VOLUME else test ss:fcb_pb+8,DA_VOLUME endif pop ds jnz fcb_close ; don't leave VOL label's open xor bx,bx ; no errors ! ret fcb_update: ;---------- ; On Entry: ; DS:SI -> DHNDL_ ; ES:BX -> FCB ; On Exit: ; DATE/TIME/SIZE/DBLK/DCNT fields updated ; mov ax,ds:DHNDL_TIME[si] mov es:MSF_TIME[bx],ax mov ax,ds:DHNDL_DATE[si] mov es:MSF_DATE[bx],ax mov ax,ds:DHNDL_SIZELO[si] mov es:MSF_SIZE[bx],ax mov ax,ds:DHNDL_SIZEHI[si] mov es:MSF_SIZE+2[bx],ax mov ax,ds:DHNDL_DBLK[si] mov es:MSF_DBLK[bx],ax mov al,ds:DHNDL_DCNTLO[si] mov ah,ds:DHNDL_DCNTHI[si] mov es:MSF_DCNT[bx],ax ret fcb_close: ;--------- ; close file (DOS function 10h) call fcb_point ; ES:BX -> FCB mov al,0FFh cmp al,es:MSF_IFN[bx] ; is it a multiple close ? je fcb_fdos_common10 ; don't re-open for this... call fcb_handle_vfy ; verify we have a sensible handle mov es:MSF_IFN[bx],al ; mark FCB as closed (it will be) mov ax,MS_X_CLOSE ; now close it ; jmps fcb_fdos_common fcb_fdos_common: ;--------------- call fcb_fdos ; make the FDOS do the work jc fcb_fdos_common20 ; return any error codes fcb_fdos_common10: xor bx,bx ; else return zero fcb_fdos_common20: ret fcb_rename: ;---------- call fcb_path_prep call fcb_path2_prep mov ax,MS_X_RENAME ; it's a rename jmps fcb_fdos_common fcb_delete: ;---------- call fcb_path_prep mov ax,MS_X_UNLINK ; it's a delete jmps fcb_fdos_common fcb_first: ;--------- call fcb_path_prep ; prepare pathname mov ax,MS_X_FIRST ; we want to search 1st jmps fcb_search_common fcb_next: ;-------- call fcb_restore_search_state mov ax,MS_X_NEXT fcb_search_common: call fcb_search ; 0 of OK, otherwise ED_.. jc fcb_search_common10 call fcb_save_search_state ; save sucessful state xor bx,bx ; return code in BX fcb_search_common10: ret fcb_setrecord: ;------------- call fcb_point ; ES:BX -> FCB mov ax,128 ; multiply current block by 128 mul es:MSF_BLOCK[bx] ; to give current record number xor cx,cx mov cl,es:MSF_CR[bx] ; Add in the current record add ax,cx ; to DX:AX to give the adc dx,0 ; relative record mov es:MSF_RR[bx],ax ; save the result mov es:MSF_RR2[bx],dl xor bx,bx ; we did OK ret fcb_write: ;--------- mov ax,MS_X_WRITE ; make it a write jmps fcb_seq_rw fcb_read: ;-------- mov ax,MS_X_READ ; make it a read fcb_seq_rw: call fcb_handle_vfy ; verify we have a sensible handle push ax ; save the operation call fcb_get_count ; AX = bytes to read push ax ; save byte count call fcb_seek_seq ; Seek to position in the file pop cx ; recover byte to xfer pop ax ; and the Operation Code jc fcb_seq_rw10 call fcb_rw ; do the Op jc fcb_seq_rw10 push bx ; save the error code call fcb_update_seq ; update FCB filepos pop bx ; recover error fcb_seq_rw10: ret fcb_rw: ; On Entry: ; AX = operation code ; CX = count ; fcb_pb+2 = IFN ; On Exit: ; BX = error code les dx,ss:dword ptr dma_offset add cx,dx ; see if we overflow jc fcb_rw20 sub cx,dx ; count back to normal push cx ; save target count mov fcb_pb+4,dx mov fcb_pb+6,es ; setup buffer address mov fcb_pb+8,cx ; and target count call fcb_fdos ; ask the FDOS to do the read/write jc fcb_rw10 ; we got a real error... push ds push es mov ax,fcb_pb+2 ; get IFN call ifn2dhndl ; ES:BX -> DHNDL_ we have open push es ! push bx ; save DHNDL_ call fcb_point ; ES:BX = FCB pop si ! pop ds ; DS:SI -> DHNDL_ call fcb_update ; update file size/time-stamp pop es pop ds pop ax ; recover target count mov cx,fcb_pb+8 ; we xfered this much cmp cx,ax ; did we xfer enough jb fcb_rw30 ; nope.. xor bx,bx ; xfer went OK ret fcb_rw10: pop ax ; discard target count ret fcb_rw20: ; Our DTA is too small - return 2 mov bx,2 ; indicate the DTA is too small ; stc ; error - don't update FCB ret fcb_rw30: ; We have some form of EOF - lets look into it call fcb_point ; ES:BX = FCB mov bx,es:MSF_RECSIZE[bx] ; BX = record size mov ax,cx xor dx,dx ; DX:AX = bytes xfer'd div bx ; did we xfer a complete test dx,dx ; number of records ? jz fcb_rw40 ; if so return 1 ; Partial data was read - fill out with zero's and return 3 inc ax ; allow for incomplete record push ax ; save rounded up xfer count les di,ss:dword ptr dma_offset add di,cx ; point to 1st byte after xfer mov cx,bx ; this many in a record sub cx,dx ; so this many weren't xfer'd xor ax,ax ; fill them with zero's rep stosb ; zap the bytes we didn't xfer to pop ax ; recover xfer count mul bx ; and work out # bytes xfered xchg ax,cx ; return bytes in CX mov bx,3 ; indicate EOF (partial read) ; clc ; update FCB ret fcb_rw40: ; No Data was xfered - return 1 mov bx,1 ; indicate EOF (no data read) ; clc ; update FCB ret fcb_writerand: ;------------- mov ax,MS_X_WRITE ; make it a write jmps fcb_random_rw fcb_readrand: ;------------ mov ax,MS_X_READ ; make it a read fcb_random_rw: call fcb_handle_vfy ; check the handle is OK push ax ; save the code call fcb_get_count ; AX = bytes to read push ax ; save byte count xor cx,cx ; cause update of seq posn from call fcb_update_rr ; random record position call fcb_seek_rr ; Seek to position in the file pop cx ; recover byte to xfer pop ax ; and the Operation Code jc fcb_random_rw10 call fcb_rw ; do the Op fcb_random_rw10: ret fcb_writeblk: ;------------ mov ax,MS_X_WRITE ; make it a write jmps fcb_block_rw fcb_readblk: ;----------- mov ax,MS_X_READ ; make it a read fcb_block_rw: call fcb_handle_vfy ; check the handle is OK push ax ; save the code call fcb_get_count ; AX = bytes per record, CX = # records xchg ax,cx ; CX = bytes per record mul cx ; AX = bytes to xfer test dx,dx ; more than 64K ? jz fcb_block_rw10 ; then we should truncate it mov ax,15 ; AX = handy mask cwd ; DX = 0 and ax,ss:dma_offset ; get dma offset for para not ax ; DX/AX = maximum bytes we can xfer div cx ; AX = maximum blocks we can xfer mul cx ; AX = bytes to xfer (now < 64K) fcb_block_rw10: push ax ; save byte count call fcb_seek_rr ; Seek to position in the file pop cx ; recover byte to xfer pop ax ; and the Operation Code jc fcb_block_rw20 call fcb_rw ; do the Op jc fcb_block_rw20 push bx ; save the error code call fcb_update_rr ; update FCB filepos, get records xferd mov bx,2[bp] ; BX -> parameter block xchg cx,6[bx] ; update amount xfered sub cx,6[bx] ; CX = # we didn't xfer (normally 0) pop bx ; recover (possible) error jcxz fcb_block_rw20 ; skip if we read all we wanted to test bx,bx ; did we have a partial read for jnz fcb_block_rw20 ; a reason like EOF ? mov bx,2 ; no, we must have truncated it fcb_block_rw20: ret fcb_size: ;-------- call fcb_path_prep mov ax,MS_X_CHMOD ; it's a get info mov fcb_pb+6,0 call fcb_fdos jc fcb_size40 call fcb_point ; ES:BX = FCB mov cx,es:MSF_RECSIZE[bx] ; get the record size test cx,cx ; is it non-zero ? jnz fcb_size10 ; if not mov cx,128 ; make it 128 bytes fcb_size10: mov ax,fcb_pb+10 mov dx,fcb_pb+12 ; DX:AX = file length in bytes call div_32 ; DX:AX = file length in records jcxz fcb_size20 ; was there an overflow add ax,1 adc dx,0 ; include an extra record fcb_size20: call fcb_point ; ES:BX = FCB mov es:MSF_RR[bx],ax ; low word of size mov es:MSF_RR2[bx],dl ; hi byte of size cmp es:MSF_RECSIZE[bx],64 ; if record size < 64 bytes jae fcb_size30 ; then we use a 4 byte mov es:MSF_RR2+1[bx],dh ; random record position fcb_size30: xor bx,bx ; good return fcb_size40: ret ; Utility FCB subroutines ;======================== fcb_handle_vfy: ;-------------- ; Verify FCB is valid and open, do not return if it isn't ; nb. Called with nothing on stack ; ; On Entry: ; FCB address in parameter block ; On Exit: ; AX preserved ; ES:BX -> FCB (skipping EXT bit if present) ; fcb_pb+2 = IFN of handle ; On Error - blow away caller and return error in BX ; ; DEBUG - on reopen we could do more checks to ensure we are re-opening the ; same file push ax call fcb_point cmp es:MSF_RECSIZE[bx],0 jne fcb_handle_vfy10 mov es:MSF_RECSIZE[bx],128 fcb_handle_vfy10: mov al,es:MSF_IFN[bx] ; get IFN call ifn2dhndl ; ES:BX -> DHNDL_ jc fcb_handle_vfy20 ; it must be a valid IFN test es:DHNDL_MODE[bx],DHM_FCB jz fcb_handle_vfy20 ; it must be an FCB.. cmp es:DHNDL_COUNT[bx],0 jne fcb_handle_vfy30 ; it must also be open.. fcb_handle_vfy20: call fcb_point push es:MSF_RECSIZE[bx] ; save current record size push es:MSF_BLOCK[bx] ; save current block number push es ! push bx call fcb_open ; try to re-open the file pop bx ! pop es ; point back at FCB pop es:MSF_BLOCK[bx] ; restore current block number pop es:MSF_RECSIZE[bx] ; restore record size jc fcb_handle_err mov al,es:MSF_IFN[bx] ; get new IFN fcb_handle_vfy30: xor ah,ah mov fcb_pb+2,ax ; set parameter block accordingly call fcb_point ; ES:BX -> MSF_ pop ax clc ret fcb_handle_err: add sp,2*WORD ; discard AX and near return address cmp ax,ED_HANDLE ; if we have run out of handles then jne fcb_handle_err10 ; say no FCB's, else return error mov ax,ED_NOFCBS fcb_handle_err10: xchg ax,bx ; error code in BX stc ret fcb_path2_prep: ;-------------- ; On Entry: ; FCB address in parameter block ; On Exit: ; ES:BX -> FCB (skipping EXT bit if present) ; fcb_pb+6/8 -> unparse name from FCB ; call fcb_point ; point at the FCB mov al,es:MSF_DRIVE[bx] ; get drive add bx,16 ; point at 2nd name in FCB mov di,offset fcb_path2 mov fcb_pb+6,di mov fcb_pb+8,ds ; point at buffer we want jmps fcb_path_prep_common fcb_path_prep: ;------------- ; On Entry: ; FCB address in parameter block ; On Exit: ; ES:BX -> FCB (skipping EXT bit if present) ; fcb_pb+2/4 -> unparse name from FCB ; xor ax,ax ; assume no attribute mov bx,2[bp] ; BX -> parameter block les bx,2[bx] ; ES:BX -> FCB cmp es:MSF_EXTFLG[bx],0ffh ; is it an extended FCB jne fcb_path_prep10 or al,es:MSF_ATTRIB[bx] ; we can use file mode from XFCB add bx,7 ; skip EXT bit of FCB fcb_path_prep10: mov fcb_pb+8,ax ; remember the attribute mov al,es:MSF_DRIVE[bx] ; get drive mov di,offset fcb_path mov fcb_pb+2,di mov fcb_pb+4,ds ; point at buffer we want fcb_path_prep_common: dec al ; 0 = default drive jns fcb_path_prep20 mov al,current_dsk ; use default drive fcb_path_prep20: push ds push ds ! push es pop ds ! pop es ; ES:DI -> name buffer add al,'A' ; make drive ASCII stosb mov al,':' stosb ; now we have 'd:' lea si,MSF_NAME[bx] ; DS:SI -> source name movsw ! movsw movsw ! movsw ; copy the name leaving spaces intact mov al,'.' stosb movsw ! movsb ; copy the extention pop ds ; jmps fcb_point ; point ES:BX at FCB again fcb_point: ;--------- ; On Entry: ; FCB address in parameter block ; On Exit: ; ES:BX -> FCB (skipping EXT bit if present) ; (All other regs preserved) ; mov bx,2[bp] ; BX -> parameter block les bx,2[bx] ; ES:BX -> FCB cmp es:MSF_EXTFLG[bx],0ffh ; is it an extended FCB jne fcb_point10 add bx,7 ; skip EXT bit of FCB fcb_point10: ret fcb_get_count: ;------------- ; On Entry: ; none ; On Exit: ; AX = bytes per record ; CX = callers CX count ; All regs fair game ; call fcb_point ; ES:BX -> FCB mov si,2[bp] ; SI -> parameter block mov cx,6[si] ; CX = count mov ax,es:MSF_RECSIZE[bx] ; get record size ret fcb_update_seq: ;-------------- ; On Entry: ; CX = byte count actually transferred ; On Exit: ; CX = record count transferred ; All other regs fair game ; CR/BLOCK updated with new value ; mov ax,cx xor dx,dx ; DX:AX = byte count transfered call fcb_point ; ES:BX -> FCB div es:MSF_RECSIZE[bx] ; make records xfered push ax ; save records xfered xchg ax,cx ; also in CX for later mov ax,128 mul es:MSF_BLOCK[bx] ; DX:AX = record of block add ax,cx adc dx,0 ; add in amount just xfered mov cl,es:MSF_CR[bx] xor ch,ch ; now add in CR as a word add ax,cx adc dx,0 ; DX:AX = record mov dh,dl ; DH:AX = record for common code jmps fcb_update_common fcb_update_rr: ;------------- ; On Entry: ; CX = byte count actually transferred ; On Exit: ; CX = record count transferred ; All other regs fair game ; Random Record and CR/BLOCK updated with new value ; xchg ax,cx xor dx,dx ; DX:AX = byte count transfered call fcb_point ; ES:BX -> FCB div es:MSF_RECSIZE[bx] ; make records xfered push ax ; save records xfered add es:MSF_RR[bx],ax ; update the RR field adc es:MSF_RR2[bx],0 ; and the overflow mov ax,es:MSF_RR[bx] ; get low part of RR mov dh,es:MSF_RR2[bx] ; and the hi part fcb_update_common: mov dl,ah ; DX will be block number shl al,1 ; get top bit of CR into CY adc dx,dx ; then into DX shr al,1 ; AL = CR (remember mod 128) mov es:MSF_CR[bx],al ; set the CR field mov es:MSF_BLOCK[bx],dx ; and the block field pop cx ; recover records xfered ret fcb_seek_seq: ;------------ ; Seek to position in file indicated by the RR position ; On Entry: ; ES:BX -> FCB_ ; On Exit: ; CY clear if no problem, fcb_pb+2=IFN ; else ; CY set, AX = BX = error code ; All other regs fair game ; call fcb_point ; ES:BX -> FCB_ mov ax,128 mul es:MSF_BLOCK[bx] ; get record in DX:AX mov cl,es:MSF_CR[bx] xor ch,ch add ax,cx ; add in CR adc dx,0 ; so DX:AX is really the record push ax ; save low word of record mov ax,dx mul es:MSF_RECSIZE[bx] ; DX:AX = byte offset in file/10000h mov cx,ax ; save the important word pop ax ; recover low word of record jmps fcb_seek_common fcb_seek_rr: ;----------- ; Seek to position in file indicated by the RR position ; On Entry: ; ES:BX -> FCB_ ; On Exit: ; CY clear if no problem, fcb_pb+2=IFN ; else ; CY set, AX = BX = error code ; All other regs fair game ; call fcb_point ; ES:BX -> FCB_ mov al,es:MSF_RR2[bx] xor ah,ah mul es:MSF_RECSIZE[bx] ; DX:AX = byte offset in file/10000h mov cx,ax ; save the important word mov ax,es:MSF_RR[bx] fcb_seek_common: mul es:MSF_RECSIZE[bx] ; DX:AX = byte offset in file add dx,cx ; add the two bits together mov fcb_pb+4,ax mov fcb_pb+6,dx ; save position mov fcb_pb+8,0 ; seek from start xor ax,ax mov al,es:MSF_IFN[bx] ; AX = IFN mov fcb_pb+2,ax ; save IFN mov ax,MS_X_LSEEK jmp fcb_fdos ; try and seek to this position fcb_search: ;---------- ; On Entry: ; AX = operation to perform ; On Exit: ; AX = 0, or ED_ error code (CY set if error) push dma_offset push dma_segment mov dma_offset,offset fcb_search_buf mov dma_segment,ds call fcb_fdos ; do the search pop dma_segment pop dma_offset test ax,ax ; was there an error stc ; assume there was js fcb_search10 ; return the error xor ax,ax ; no problems fcb_search10: ret fcb_save_search_state: ;--------------------- ; On entry DS=PCMODE call fcb_point lea di,MSF_NAME[bx] ; ES:DI -> FCB name mov si,offset fcb_search_buf lodsb ; get 1st byte = drive info mov cx,20/WORD ; copy 20 bytes to FCB rep movsw ; (the rest of the search template) stosb ; drive info byte follow them les di,dword ptr dma_offset ; ES:DI -> search state in DMA address mov si,2[bp] ; SI -> parameter block lds si,2[si] ; DS:SI -> FCB_ cmp ds:MSF_EXTFLG[si],0ffh ; extended FCB ? jne fcb_sss10 mov cx,7 ; copy extended FCB portions too rep movsb ; we have copied up to name fcb_sss10: stosb ; save drive byte info push di mov al,' ' ; space fill name mov cx,11 rep stosb ; all blanks now pop di push ss ! pop ds ; DS:SI -> pathname mov si,offset fcb_search_buf+1Eh push di ; unparse knowing name is good mov cx,8 ; length of name field fcb_sss20: lodsb ; treat '.' and '..' specially cmp al,'.' ; is either possible ? jne fcb_sss30 ; no, continue as normal stosb ; copy the '.' loop fcb_sss20 ; go around for another '.' jmps fcb_sss40 ; this name is rubbish!! fcb_sss30: dec si ; forget the non '.' call parse_one ; parse just the name fcb_sss40: pop di add di,8 ; di -> fcb ext field cmp al,'.' ; do we have an extention ? jne fcb_sss50 mov cx,3 ; length of ext field push di call parse_one ; parse just extension pop di fcb_sss50: add di,3 ; di -> rest of fcb mov si,offset fcb_search_buf+15h movsb ; copy the attribute field xor ax,ax mov cx,10/WORD rep stosw ; 10 bytes of zeros movsw ; copy time movsw ; copy date mov ax,word ptr srch_buf+21+DBLOCK1 stosw ; 1st block movsw ! movsw ; copy filesize ret fcb_restore_search_state: ;------------------------ ; On entry DS=PCMODE push ds call fcb_point ; ES:BX -> FCB_ push es ! push ds pop es ! pop ds ; swap DS/ES mov di,offset fcb_search_buf+1 ; ES:DI -> internal state lea si,1[bx] ; DS:SI -> FCB+1 mov cx,10 rep movsw ; copy info from FCB lodsb ; get "drive" info mov es:fcb_search_buf,al ; it's the 1st byte in the srch state pop ds ret fcb_fdos: ;-------- ; Make an FDOS call (NB. We don't have MX here, so it's OK) ; Set top bit of remote_call flag so we use IFN's not XFN's ; On Entry: ; AX = FDOS operation ; fcb_pb -> FDOS parameter block ; On Exit: ; As FDOS call ; mov fcb_pb,ax ; save operation type or remote_call,DHM_FCB ; forget about PSP during FCB call mov dx,offset fcb_pb ; DS:DX -> parameter block push ds push bp call fdos_entry ; call the FDOS pop bp pop ds and remote_call,not DHM_FCB ; FCB operation over cmp ax,ED_LASTERROR cmc ; CY set if an error occurred ret div_32: ; Entry: DX,AX = long dividend ; CX = word divisor ; Exit: DX,AX = long result ; CX = remainder jcxz div0 ; divide by 0 cmp cx,1 je div1 ; divide by 1 push di push bx xor bx,bx ; BX = 0 xchg ax,bx ; low word in BX, AX = 0 xchg ax,dx ; high word in DX:AX push ax ; save high word div cx ; divide high part mov di,ax ; save result mul cx ; AX = even divisor part pop dx ; old high in DX sub dx,ax ; eliminate even part xchg ax,bx ; AX = low word div cx ; low part in AX mov cx,dx ; CX = remainder mov dx,di ; high result in DX pop bx pop di ret div0: mov ax,-1 mov dx,ax ret div1: dec cx ; CX = remainder = 0 ret PCMODE_DATA DSEG WORD extrn fcb_pb:word extrn fcb_path:byte extrn fcb_path2:byte extrn fcb_search_buf:byte extrn current_dsk:byte extrn current_psp:word extrn dma_offset:word extrn dma_segment:word extrn machine_id:word extrn remote_call:word extrn srch_buf:byte end