;******************** bdos file system part 3 **************** ; ; sqread: ;sequential disk read operation mov seqio,1 ;drop through to diskread ; diskread: ;(may enter from seqdiskread) CALL TST_INV_FCB ;VERIFY FCB HAS NOT BEEN FLAGGED ;AS INVALID mov rmf,true ;read mode flag = ;true (open$reel) ;read the next record from ;the current fcb if MPM MOV DONT_CLOSE,TRUE endif call getfcb ;sets parameters for the read DISK_READ0: mov al,vrecord cmp al,rcount ;vrecord-rcount ;skip if rcount > vrecord jb recordok if MPM ;IF FCB WAS OPENED IN UNLOCKED MODE, CHECK THE DIRECTORY FCB ;TO MAKE SURE ANOTHER PROCESS HAS NOT ALLOCATED A BLOCK TO ;THE FCB SINCE THIS PROCESS OPENED THE FCB CALL TEST_DISK_FCB ;JUMP BACK TO DISKREAD0 IF DONT_CLOSE JNZ DISKREAD0 ;TRUE, FILE OPENED IN UNLOCKED MODE, ;AND ACCESS OF DIR FCB SUCCESSFUL ;DONT_CLOSE SET TO FALSE MOV AL,VRECORD endif ;not enough records in extent ;record count must be 128 ;to continue cmp al,128 ;vrecord = 128? jnz diskeof ;skip if vrecord<>128 call openreel ;go to next extent if so ; mov vrecord,0 ;vrecord=00 ;now check for open ok cmp lret,0 ;stop at eof jnz diskeof recordok: ;arrive with fcb addressing a record to read call index ;error 2 if reading ;unwritten data ;(returns 1 to be compatible ;with 1.4) call alloct ;arecord=0000? if MPM JNZ RECORDOK1 CALL TEST_DISK_FCB ;JUMP BACK TO DISKREAD0 IF DONT_CLOSE JNZ DISKREAD0 ;TRUE, FILE OPENED IN UNLOCKED MODE, ;AND ACCESS OF DIR FCB SUCCESSFUL endif jz diskeof RECORDOK1: ;record has been allocated, ;read it call atran ;arecord now a disk address call seek ;to proper track,sector call rdbuff ;to dma address jmp setfcb ;replace parameter ; ret diskeof: jmp setlret1 ;lret = 1 ;ret if MPM TEST_DISK_FCB: TEST HIGH_EXT,80H ;WAS FILE OPENED IN UNLOCKED MODE JZ RET14 ;NO TEST DONT_CLOSE,0FFH ;RETURN IF DONT_CLOSE FALSE JZ RET14 CALL CLOSE1 ;FCB IN MEMORY TEST_DISK_FCB1: POP SI MOV BX,OFFSET LRET CMP B[BX],0FFH MOV AL,11 JNE $+5 JMP STA_RET ;ERROR - CLOSE OPERATION UNSUCCESSFUL MOV B[BX],0 ;LRET = 0 PUSH SI CALL GET_RCNTA MOV AL,[BX] MOV RCOUNT,AL XOR AL,AL MOV DONT_CLOSE,AL ;DONT_CLOSE = FALSE INC AL ;SUCCESSFUL OPERATION, RESET ZERO FLAG RET endif ; RESET_FWF: call getmodnum ;bx=.fcb(modnum) ;al=fcb(modnum) ;reset the fcb write flag to ;mark as written fcb and al,not fwfmsk ;high order bit of modnum fld reset mov [bx],al ;fcb(modnum) = fcb(modnum) & 7fh RET14: RET sqwrite: ;sequential disk write mov seqio,1 ;drop through to diskwrite ; diskwite: ;(may enter here from ;seqdiskwrite above) mov rmf,false ;read mode flag ;write record to currently ;selected file call checkwrite ;in case write protected TEST XFCB_READ_ONLY,TRUE ;READ/ONLY ERROR IF XFCB_READ_ONLY TRUE MOV AL,3 ;XFCB_READ_ONLY TRUE IF FILE IS JZ $+5 ;PASSWORD PROTECTED IN WRITE MODE ;AND PASSWORD WAS NOT SUPPLIED ;WHEN THE FILE WAS OPENED. JMP_SET_ARET: JMP SET_ARET TEST HIGH_EXT,40H ;READ/ONLY ERROR IF FCB OPENED JNZ JMP_SET_ARET ;IN READ/ONLY MODE mov bx,info ;bx = .fcb(0) call ckrofile ;may be a read-only file CALL TST_INV_FCB ;TTEST FOR VALID FCB call getfcb ;to set local parameters mov al,vrecord cmp al,lstrec+1 ;vrecord-128 ;skip if vrecord > lstrec ;vrecord = 128, cannot open ;next extent jb dskwr0 CALL OPEN_REEL ;TRY TO OPEN NEXT EXTENT TEST LRET,TRUE JNZ RET14 dskwr0: ; if MPM MOV DONT_CLOSE,TRUE DISK_WRITE1: endif call index call alloct if MPM JZ DISKWRITE2 ;IF FILE IS UNLOCKED, VERIFY RECORD IS NOT LOCKED ;RECORD HAS TO BE ALLOCATED TO BE LOCKED TEST HIGH_EXT,80H ;WAS FILE OPENED IN UNLOCKED MODE? JZ NOT_UNLOCKED ;NO CALL ATRAN MOV CH,MULT_CNT ;TEST_LOCK EXPECTS MULT_CNT PUSH CX ;PUSHED ON STACK CALL TEST_LOCK ;VERIFY RECORD IS NOT LOCKED BY ;ANOTHER PROCESS POP CX MOV WFLAG,0 JMPS DISKWR10 NOT_UNLOCKED: OR AL,TRUE ;RESET Z FLAG FOR FOLLOWING JNZ endif mov cl,0 ;marked as normal write ;operation for wrbuff jnz dskwr1 if MPM DISK_WRITE2: CALL TEST_DISK_FCB ;JUMP BACK TO DISK_WRITE1 IF ;DONT_CLOSE IS TRUE, FILE WAS OPENED ;IN UNLOCKED MODE, AND ACCESS OF ;DIR FCB WAS SUCCESSFUL JNZ DISK_WRITE1 endif ;not allocated: ;the argument to getblock is the starting ;position for the disk search, and should be ;the last allocated block for this file, or ;the value 0 if no space has been allocated ; call dmposition mov dminx,al ;save for later xor cx,cx ;may use block zero or al,al jz nopblock ;skip if no previous block ;previous block exists at a mov cl,al dec cx call getdm ;previous block # to bx mov cx,bx ;cx=prev block# nopblock: ;cx = 0, or previous block # call getblock ;block # to bx ;arrive with block# or zero or bx,bx jnz blockok ;cannot find block to allocate mov al,2 jmp staret ;lret=2 blockok: MOV COMP_FCB_CKS,TRUE ;MUST RECOMPUTE FCB CHECKSUM ;bx contains allocated block # mov arecord,bx xchg bx,dx ;block number to dx mov bx,info add bx,dskmap ;bx=.fcb(diskmap) cmp single,0 ;set flags for single byte dm mov al,dminx ;recall dm index mov ah,0 jz allocwd ;skip if allocating word ;allocating a byte value add bx,ax mov [bx],dl ;single byte alloc jmps dskwru ;to continue allocwd: ;allocate a word value add bx,ax add bx,ax ;bx=.fcb(dminx*2) mov [bx],dx ;double wd inc bx dskwru: ;disk write to previously unallocated block mov cl,2 ;marked as unallocated write dskwr1: ;continue the write operation of no allocation error ;c = 0 if normal write, 2 if to prev unalloc block ; ; cmp lret,0 ; jz dskwr10 ; ret ;dskwr10: ;stop if non zero value mov wflag,cl ;save the write flag call atran ;arecord set DISKWR10: cmp seqio,2 ;check random with 0 fill jnz dskw11 ; ; this is random write with zero fill ; cmp wflag,2 ;check for new allocation jnz dskw11 ;old allocation ; ; new alloction for random with zero fill ; mov di,buffa xor ax,ax ;zero and fill mov cx,64 ;zero 64 words in dirbuf rep stos ax call setdir PUSH ARECORD ;SAVE ARECORD mov bx,ablock fill1: mov arecord,bx call seek ;reg cl used for deblocking call wrbufflg ;write fill record mov bx,arecord ;restore last record mov wflag,0 ;change allocate flag mov al,bl ;arecord in bx mov dh,blkmsk and al,dh inc bx cmp al,dh jnz fill1 ;cont until cluster is zeroed POP ARECORD ;RESTORE ARECORD MOV WFLAG,2 ;RESTORE WFLAG call setdata dskw11: call seek ;to proper file position ;(cl=2 if new block,0 if not) ;SET WFLAG TO ZERO IF VRECORD MOV AL,VRECORD ;DOES NOT SPECIFY 1ST RECORD OF MOV AH,BLKMSK ;NEW BLOCK AND AH,AL JZ WRITE MOV WFLAG,0 WRITE: CALL WRBUFFLG ;written to disk ;increment record count ;if rcount <= vrecord mov al,vrecord mov bx,offset rcount cmp al,[bx] ;vrecord-rcount jb dskwr2 ;rcount <= vrecord mov [bx],al inc b[bx] ;rcount = vrecord+1 if MPM TEST HIGH_EXT,80H JZ WRITE1 ;FOR UNLOCKED FILE ; RCOUNT = VRECORD & (~ BLKMSK) + BLKMSK + 1 MOV CH,BLKMSK MOV CL,CH NOT CL INC CH AND AL,CL ADD AL,CH MOV [BX],AL WRITE1: endif MOV WFLAG,2 ;mark as record count ;incremented dskwr2: CMP WFLAG,2 ;WFLAG=2 IF NEW BLOCK OR NEW RECORD # JNZ NOUPDATE if MPM TEST HIGH_EXT,80H ;IS FILE OPEN MODE UNLOCKED? JZ DSKWR2A MOV AL,[BX] CALL GET_RCNTA ;RESTORE FCB(RCOUNT) MOV [BX],AL CALL CLOSE CALL TEST_DISK_FCB1 DSKWR2A: endif CALL RESET_FWF noupdate: CALL GETMODNUM ;SET FILE WRITE FLAG IF RESET AND AL,40H JNZ DSKWR3 OR B[BX],40H CALL RESET_FWF ;RESET FCB WRITE FLAG TO ENSURE ;T3' GETS RESET BY THE CLOSE FUNCTION dskwr3: jmp setfcb ;replace parameters ;ret ; rseek: ;random access seek operation, c=0ffh if read mode ;fcb is assumed to address an active fcb ;(modnum has been set to 1100$0000b if previous bad seek) ; mov seqio,0 ;marked as random access op. rseek1: push cx ;save r/w flag mov dx,info ;dx will hold base of fcb mov bx,ranrec add bx,dx ;bx=.fcb(ranrec) mov al,[bx] and al,7fh push ax ;record number mov al,[bx] rcl al,1 ;cy=lsb of extent# inc bx MOV CH,[BX] RCL CH,1 AND CH,11111B ;CH=EXT# ;CH holds extent number, ;record stacked MOV AL,[BX] AND AL,11110000B INC BX OR AL,[BX] MOV CL,4 ROL AL,CL MOV CL,AL XCHG CH,CL ;CH=MOD#, CL=EXT# pop ax ;recall sought record # MOV AH,[BX] ;HIGH BYTE OF RR FIELD MUST AND AH,11111100B ;BE <= 3 mov bl,6 ;zero flag, l=6 ;produce error 6, ;seek past physical eod JZ $+5 JMP SEEKERR ;otherwise, high byte = 0 mov bx,nxtrec add bx,dx ;bx=.fcb(nxtrec) mov [bx],al ;sought rec# stored away ; ;arrive here with ch=mod#, cl=ext#, dx=.fcb, rec stored ;the r/w flag is still stacked. compare fcb values ; PUSH DX CALL CHK_INV_FCB POP DX JZ RANCLOSE mov bx,modnum ;CHECK MODULE # FIRST add bx,dx mov al,ch ;b=seek mod# ;could be overflow at eof, ;producing module# of 90h ;or 10h, so compare all ;but fwf sub al,[bx] AND AL,3FH JNZ RANCLOSE ;same? mov bx,extnum add bx,dx MOV AL,[BX] CMP AL,CL JZ SEEKOK1 ;EXTENTS EQUAL CALL COMPEXT JNZ RANCLOSE MOV [BX],CL ;EXTENTS IN SAME DIR FCB ;FCB(EXT) = CL CALL GET_DIR_EXT MOV CL,AL CALL RESTORE_RC CALL SET_RC JMPS SEEKOK1 ranclose: push cx push dx ;save seek mod#,ext#, .fcb call close ;current extent closed pop dx pop cx ;recall parameters and fill mov bl,3 ;cannot close error #3 mov al,lret inc al jz badseek MOV XDCNT,0FFFFH ;RESET XDCNT FOR MAKE if MPM MOV BYTE PTR SDCNT+1,0FFH endif mov bx,extnum add bx,dx mov [bx],cl ;fcb(extnum)=ext# INC BX INC BX MOV AL,[BX] ;FCB(MODNUM)=MOD# AND AL,40H ;COPY FILE WRITE FLAG OR AL,CH MOV [BX],AL call open ;is the file present? mov al,lret inc al jnz seekok ;open successful? ;cannot open file, read mode? pop cx ;r/w flag to c (=0ffh if read) push cx ;everyone expects this ;item stacked mov bl,4 ;seek to unwritten extent #4 inc cl ;becomes 00 if read operation jz badseek ;error if read operation ;write, make new extent call make mov bl,5 ;cannot create new extent #5 mov al,lret inc al jz badseek ;no dir space ;file make successful if MPM CALL FIX_OLIST_ITEM endif seekok: MOV COMP_FCB_CKS,TRUE SEEKOK1: pop cx ;discard r/w flag xor al,al jmp staret ;with zero set badseek: ; ;fcb no longer contains a valid fcb, mark ;with 1100$000b in modnum field so that it ;appears as overflow with file write flag set ; push bx ;save error flag MOV COMP_FCB_CKS,TRUE CALL MAKE_FCB_INV pop bx ;and drop through seekerr: pop cx ;discard r/w flag MOV LRET,BL ;lret=#, nonzero RET ;close ok ;ret ; rdread: ; ;random disk read operation ; mov cl,true ;marked as read operation call rseek JNZ RET19 JMP DISKREAD ;if seek successful ; rdwrite: ;random disk write operation mov cl,false ;marked as write operation call rseek JNZ RET19 JMP DISKWITE ;if seek successful ; cmperr: ;compute random record position for getfilesize/setrandom xchg bx,dx add bx,dx ;dx=.buf(dptr) or .fcb(0), ;bx=.f(nxtrec/reccnt) mov cl,[bx] ;pick up record no. mov ch,0 ;cx = 0000 0000 ?rrr rrrr mov bx,extnum add bx,dx mov ah,[bx] mov al,0 shr ax,1 and ah,0fh add cx,ax ;cx = 000? eeee errrr rrrr mov bx,modnum add bx,dx mov al,[bx] ;AL = XXMM MMMM AND AL,3FH mov ah,16 mul ah ;AX = 0000 00MM MMMM 0000 add ch,al ;cx = mmmm eeee errr rrrr MOV AL,0 ADC AL,AH ;AL = 0000 0?MM RET19: ret ; getfilesize: ;compute logical file size for current fcb CALL GET_RRA ;ZERO RECEIVING RANREC FIELD PUSH BX XOR AL,AL MOV [BX],AL INC BX MOV [BX],AL INC BX MOV [BX],AL mov cl,extnum call srch getsize: jz setsize ;current fcb addressed by dptr call getdptra mov dx,reccnt ;ready for compute size call cmperr ;al=0000 000?, ;cx = mmmm eeee errr rrrr ;compare with memory, larger? pop bx push bx ;recall, replace .fcb(ranrec) mov dl,al ;save cy mov ax,cx sub ax,[bx] mov al,dl sbb al,2[bx] ;carry if .fcb(ranrec) > ;directory jb getnextsize ;for another try ;fcb is less or equal, ;fill from directory mov 2[bx],dl mov [bx],cx getnextsize: call srchn MOV LRET,0 jmps getsize setsize: pop bx ;discard .fcb(ranrec) ret ; setrandom: ;set random record from the current fcb MOV BX,DX mov dx,nxtrec ;ready params for computesize call cmperr ;dx=info, al=cy, ;cx=mmmm eeee errr rrrr mov bx,ranrec add bx,dx ;bx=.fcb(ranrec) mov [bx],cx mov 2[bx],al ;to ranrec ret ; TMP_SELECT: ;DL=DRIVE TO SELECT (0-F) MOV BX,OFFSET SELDSK MOV AL,[BX] PUSH AX MOV [BX],DL CALL CUR_SELECT POP AX MOV SELDSK,AL RET ; XCURSELECT: MOV RETURN_FFFF,TRUE CALL CURSELECT MOV RETURN_FFFF,FALSE RET20A: RET ; CURSELECT: MOV AL,SELDSK CMP AL,CURDSK JE TEST_FF_DISK ;DON'T SELECT IF SELDSK = CURDSK ; SELECT: ;select disk word ptr info for subsequent input or output ops MOV DX,DLOG CALL TEST_VECTOR PUSH DX ;DL = 1 IF DRIVE LOGGED IN ;save it for test below, ;send to seldsk call selectdisk pop bx ;recall dlog vector JNZ $+5 call selerror ;returns true if select ok ;is the disk logged in? rcr bl,1 if MPM JNB SELECT1 MOV DX,RLOG CALL TEST_VECTOR MOV REM_DRV,DL RET SELECT1: endif if CPM JB RET20A ;rc endif ;return if bit is set ;disk not logged in, ;set bit and initialize mov cx,dlog call setcdisk mov dlog,bx ;dlog=set$cdisk(dlog) if MPM MOV AL,BYTE PTR CHKSIZ+1 ;IF HIGH ORDER BIT OF CHKSUM RCL AL,1 ;VECTOR IS ZERO, THEN DRIVE MOV AL,0 JB SELECT2 ;IS REMOVEABLE MOV CX,RLOG CALL SETCDISK MOV RLOG,BX ;RLOG=SET_CDISK(RLOG) MOV AL,1 SELECT2: MOV REM_DRV,AL endif jmp initialize ;ret ; TEST_FF_DISK: INC AL JNZ RET20A JMP SEL_ERROR ; SET_SELDSK: MOV AL,LINFO MOV SELDSK,AL RET ; RESELECTX: MOV HIGH_EXT,0 JMP RESELECT1 ; reselect: MOV CX,807FH ;CH = 80H, CL = 7FH MOV BX,INFO ADD BX,7 MOV AL,[BX] ;IF FCB(7) & 80H AND AL,CH ;THEN XFCB_READ_ONLY = 80H MOV XFCB_READ_ONLY,AL ;ELSE XFCB_READ_ONLY = 00H AND [BX],CL ;FCB(7) = FCB(7) & 7FH INC BX MOV AL,[BX] AND AL,CL ;FCB(8) = FCB(8) & 7FH CMP AL,[BX] MOV [BX],AL ;IF FCB(8) & 80H MOV AL,60H ;THEN HIGH_EXT = 60H JNZ RESELECT0 ADD BX,4 ;ELSE HIGH_EXT = FCB(12) & E0H MOV AL,0E0H AND AL,[BX] RESELECT0: MOV HIGH_EXT,AL CALL CLR_EXT CALL GETRCNTA MOV AL,[BX] ;IF FCB(RCOUNT) & 80H AND AL,CH ;THEN ACTUAL_RC = FCB(RCOUNT) & 7FH JZ RESELECT1 ; FCB(RCOUNT) = 80H MOV AL,[BX] ;ELSE ACTUAL_RC = 0 AND AL,CL MOV [BX],CH RESELECT1: MOV ACTUAL_RC,AL ;check current fcb to see if reselection necessary mov resel,true ;mark possible reselect mov bx,info mov al,[bx] ;drive select code and al,00011111b ;non zero is auto drive select dec al ;drive code normalized to ;0...30, or 255 mov linfo,al ;save drive code cmp al,0FFH JZ NOSELECT ;auto select function, ;save curdsk MOV AL,SELDSK mov olddsk,al ;olddsk=curdsk mov al,[bx] mov fcbdsk,al ;save drive code and al,11100000b mov [bx],al ;preserve hi bits CALL SET_SELDSK noselect: CALL CURSELECT ;set user code mov al,usrcode ;0...31 mov bx,info or al,[bx] mov [bx],al ret20: ret ; ; parsave33r: call parsave33 jmp reselect ; parsave36r: call parsave36 jmp reselect ; COPY_DMA_IN: ;COPY (CL) BYTES FROM USER'S MOV SI,DMAAD ;DMA TO COMMON_DMA MOV DI,OFFSET COMMON_DMA PUSH DS MOV DS,DMABASE XOR CH,CH REP MOVS AL,AL POP DS RET ; COPY_DMA_OUT: ;COPY (CL) BYTES FROM COMMON_DMA MOV DI,DMAAD ;TO USER'S DMA MOV SI,OFFSET COMMON_DMA PUSH ES MOV ES,DMABASE XOR CH,CH REP MOVS AL,AL POP ES RET ; CHK_PASSWORD: CALL GET_DIR_MODE ;AL = DIR LBL DATA BYTE AND AL,80H JNZ CHK_PW ;BIT 0 ON => PASSWORDS ACTIVE RET ; GET_DIR_MODE: MOV BX,DRVLBLA ;RETURN DIR LBL DATA BYTE IN AL MOV AL,[BX] RET ; CHK_PW: CALL GET_XFCB ;AL = XFCB PASSWORD MODE | 01H JZ RET20 ;ZERO SET IF NO XFCB FOUND DEC AL ;REMOVE LOW ORDER BIT JZ RET20 ;ZERO SET IF PASSWORD MODE = 0 CALL CMP_PW ;COMPARE PASSWORDS JZ RET20 ;ZERO SET IF PASSWORD OK CHK_PW1: ;PASSWORD ERROR MOV AL,7 JMP SET_ARET ; CMP_PW: ;COMPARE PASSWORDS ;BX = .XFCB(12) INC BX MOV CH,[BX] ;FCB(13) = XFCB CHECKSUM OR CH,CH JNZ CMP_PW2 ;JUMP IF XFCB(13) ~= 0 MOV DX,BX ;SAVE BX INC BX ;BECAUSE XFCB CHECKSUM IS ZERO INC BX ;TEST FOR NULL PASSWORD MOV CL,9 ;NULL PASSWORDS ARE ALL BLANKS AND/OR CMP_PW1: ;ZEROS THAT SUM TO ZERO INC BX ;ANY PASSWORD MATCHES A NULL PASSWORD MOV AL,[BX] DEC CL JZ RET20 ;PASSWORD IS ALL BLANKS AND/OR ZEROS OR AL,AL JZ CMP_PW1 CMP AL,20H JZ CMP_PW1 MOV BX,DX ;PASSWORD CONTAINS A VALUE OTHER ;THAN BLANK OR ZERO CMP_PW2: ;BX = .XFCB(13) LEA SI,10[BX] LEA DX,3[BX] ;DX = .XFCB(16) MOV BX,XDMAAD MOV CL,8 CMP_PW3: STD ;LODS DECREMENTS SI LODS AL XOR AL,CH ;EXCLUSIVE OR PASSWORD BYTE WITH CKS CMP AL,[BX] JNZ CMP_PW4 ;PASSWORD MISMATCH INC BX DEC CL JNZ CMP_PW3 CLD RET ;PASSWORD MATCHES ; CMP_PW4: CLD MOV BX,OFFSET DF_PASSWORD ;COMPARE XFCB PASSWORD TO DEFAULT PW MOV CL,8 ;BX = .DEFAULT PW, DX = .XFCB PASSWORD JMP COMPARE ; SET_PW: ;SET PASSWORD IN XFCB PUSH BX ;SAVE .XFCB(12) MOV CX,8 ;CH = 0, CL = 8 LEA SI,11[BX] ;SI = .XFCB(23) MOV BX,XDMAAD SET_PW0: SUB AH,AH ;ZERO NULL PASSWORD FLAG SET_PW1: MOV AL,[BX] MOV [SI],AL ;COPY PASSWORD CHAR TO XFCB OR AL,AL ;IS PASSWORD CHAR ZERO? JZ SET_PW2 ;YES CMP AL,20H ;IS PASSWORD CHAR BLANK? JZ SET_PW2 ;YES INC AH ;PASSWORD IS NOT NULL SET_PW2: ADD CH,AL ;ADD PASSWORD CHAR TO XFCB CHKSUM INC BX DEC SI DEC CL JNZ SET_PW1 OR AH,CH ;IF (AH | CH) = 0 THEN PASSWORD IS NULL POP BX JNZ SET_PW3 MOV [BX],AH ;XFCB(EX) = 0, ZERO PASSWORD MODE SET_PW3: INC SI MOV CL,8 SET_PW4: MOV AL,[SI] XOR AL,CH ;ENCRYPT PASSWORD CHARS IN XFCB MOV [SI],AL INC SI DEC CL JNZ SET_PW4 INC BX ;BX = .XFCB(13) RET ;CH = XFCB PASWORD CHECKSUM ; GET_XFCB: ;GET XFCB (SEARCH MODE) SUB CH,CH GET_XFCB0: ;GET NEXT XFCB (SEARCHN MODE) MOV BX,INFO MOV AL,[BX] PUSH AX OR B[BX],10H ;FCB(0) = FCB(0) | 10H MOV CL,EXTNUM CMP CH,0 ;TEST FOR MODE JNZ GET_XFCB00 CALL SEARCH ;RETURNS WITH ZERO FLAG SET IF JMPS GET_XFCB01 ;XFCB NOT FOUND GET_XFCB00: CALL SEARCHN ;RETURNS WITH ZERO FLAG SET IF GET_XFCB01: ;XFCB NOT FOUND MOV AL,0 MOV LRET,AL ;ZERO LRET MOV BX,INFO POP CX MOV [BX],CL ;RESTORE FCB(0) JNZ GET_XFCB1 RET ;XFCB NOT FOUND - AL = 0, ZFLAG SET GET_XFCB1: CALL GET_DPTRA MOV DX,BX ADD BX,EXTNUM MOV AL,[BX] AND AL,0E0H OR AL,1 ;AL = XFCB(EXTNUM) & 0E0H + 1 RET ;XFCB FOUND, ZERO FLAG RESET ; INIT_XFCB: CALL SETCDR ;MAY HAVE EXTENDED THE DIRECTORY MOV CX,1014H ;CH = 16, CL = 20 INIT_XFCB0: ;CH = FCB(0) LOGICAL OR MASK ;CL = ZERO COUNT PUSH CX CALL GETDPTRA ;DOES NOT USE CX MOV SI,INFO ;XFCB(0) = FCB(0) | CH MOV AL,[SI] OR AL,CH MOV [BX],AL INC SI INC BX MOV CL,11 MOV DX,SI CALL MOVE ;XFCB(1..11) = FCB(1..11) MOV DX,SI ;DX = .FCB(12) MOV BX,DI ;BX = .XFCB(12) POP CX ;CL CONTAINS # OF REMAINING BYTES SUB CH,CH ;OF XFCB TO ZERO XOR AL,AL ;MOVE SETS DI TO ADDR OF NEXT CHAR REP STOS AL RET21: RET ; CHK_XFCB_PASSWORD: CALL GET_XFCB1 ;ACCESS XFCB IN DIRECTORY BUFFER ;BX = .XFCB(EX) ;AL = (XFCB(EXT) & E0H) | 1 DEC AL CHK_XFCB_PASSWORD1: JZ RET21 PUSH BX CALL CMP_PW ;CHECK PASSWORD POP BX JZ RET21 ;RETURN WITH BX = .XFCB(EX) JMP CHK_PW1 ; CHK_PWS: CALL GET_DIR_MODE ;GET DIR LBL DATA BYTE AND AL,80H JZ RET21 ;RETURN IF PASSWORDS NOT ACTIVE CALL GET_XFCB ;GET 1ST XFCB CHK_PWS1: JZ RET21 ;ZERO SET IF XFCB NOT FOUND DEC AL JZ $+7 CALL CMP_PW ;CHK PWS FOR XFCBS WITH NON-ZERO ;PASSWORD MODE JNZ RET21 ;ZERO FLAG RESET => PASSWORD ERROR MOV CH,1 CALL GET_XFCB0 ;GET NEXT XFCB JMPS CHK_PWS1 ; STAMP1: MOV CX,24 JMPS STAMP3 STAMP2: MOV CX,28 STAMP3: if MPM MOV DX,OFFSET TOD endif if CPM MOV DX,OFFSET STAMP endif CALL GETDPTRA ADD BX,CX MOV CL,4 JMP MOVE ; COMPARE: MOV CH,0 MOV SI,BX MOV DI,DX REP CMPS AL,AL RET if MPM PACK_SDCNT: ; ;Packed_dcnt = dblk(low 15 bits) || dcnt (low 9 bits) ; ; if sdblk = 0 then dblk = shr(sdcnt,blkshf+2) ; else dblk = sdblk ; dcnt = sdcnt & (blkmsk || '11'b) ; ; packed_dcnt format (24 bits) ; ; 12345678 12345678 12345678 ; 23456789 .......1 ........ sdcnt (low 9 bits) ; ........ 9abcdef. 12345678 sdblk (low 15 bits) ; MOV BX,SDBLK CMP BX,0 ;DOES SDBLK = 0? JNE PACK_SDCNT1 ;NO MOV BX,SDCNT MOV CL,BLKSHF ADD CL,2 SHR BX,CL PACK_SDCNT1: SHL BX,1 ;SHIFT DBLK LEFT 1 MOV DX,SDCNT XOR AH,AH MOV AL,BLKMSK SHL AX,1 SHL AX,1 OR AL,11B AND AX,DX ;DCNT = SDCNT & (BLKMSK || '11'B) OR BL,AH MOV PACKED_DCNT,AL MOV WORD PTR PACKED_DCNT+1,BX RET ; ; ;olist element = link(2) || atts(1) || dcnt (3) || ; pdaddr(2) || opncnt(2) ; ; link = 0 -> end of list ; ; atts - 80 - open in locked mode ; 40 - open in unlocked mode ; 20 - open in read/only mode ; 10 - deleted item ; 0n - drive code (0-f) ; ; dcnt = packed sdcnt+sdblk ; pdaddr = process descriptor addr ; opncnt = # of open calls - # of close calls ; olist item freed by close when opncnt = 0 ; ;llist element = link(2) || drive(1) || arecord(3) ; pdaddr(2) || .olist_item(2) ; ; link = 0 -> end of list ; ; drive - 0n - drive code (0-f) ; ; arecord = record number of locked record ; pdaddr = process descriptor addr ; .olist_item = address of file's olist item ; SEARCH_OLIST: mov bx,offset open_root! jmps search_listo SEARCH_LLIST: mov bx,offset lock_root! jmps search_listo SEARCHN_LIST: mov bx,cur_pos search_listo: mov prv_pos,bx ; ;search_olist, search_llist, searchn_list conventions ; ; CH = 0 -> return next item ; CH = 1 -> search for matching drive ; CH = 2 -> search for matching DCNT ; CH = 5 -> search for matching dcnt + pdaddr ; ; if found then z flag is set ; prv_pos -> previous list element ; cur_pos -> found list element ; else prv_pos -> list element to insert after ; ; olist and llist are maintained in drive order ; srch_list1: mov bx,[bx]! or bx,bx! jz srch_list3 or ch,ch! je srch_list6 inc bx! inc bx! mov cl,[bx]! and cl,0fh mov dx,offset curdsk! mov si,dx lods al! cmp al,cl! jne srch_list4 cmp ch,1! je srch_list5 mov cl,ch! push cx! push bx inc dx! inc bx! call compare! pop bx pop cx! jz srch_list5 srch_list2: dec bx! dec bx mov prv_pos,bx! jmp srch_list1 srch_list3: or al,1! ret srch_list4: jae srch_list2 srch_list5: pushf! dec bx! dec bx! popf srch_list6: mov cur_pos,bx! ret DELETE_ITEM: ;BX -> item to be deleted pushf! cli mov si,[bx]! mov di,prv_pos! mov cur_pos,di ;prv_pos.link = delete_item.link mov [di],si ; mov si,free_root! mov free_root,bx ;delete_item.link = previous free_root mov [bx],si! popf! ret CREATE_ITEM: ;BX -> new item if successful ;Z flag set if no free items mov bx,free_root! cmp bx,0! jnz $+3! ret mov cur_pos,bx ;free_root = free_root.link mov si,[bx]! mov free_root,si ; mov si,prv_pos! mov di,[si] ;create_item.link = prv_pos.link mov [bx],di ;prv_pos.link = .create_item mov [si],bx! ret SET_OLIST_ITEM: ;AL = attributes ;BX = olist entry address inc bx! inc bx mov si,offset curdsk! mov ah,[si]! or al,ah lea dx,1[si]! mov [bx],al! inc bx mov cl,5! call move mov w[di],0 retl1: ret TST_OLIST: mov chk_olist_flag,false! jmp chk_olist0 CHK_OLIST: mov chk_olist_flag,true chk_olist0: mov dx,offset dcnt! mov bx,offset sdcnt mov cl,4! call move call pack_sdcnt! mov ch,3! call search_olist! jnz retl1 pop dx! test byte ptr 2[bx],80h! jz chk_olist05 push dx! push bx! call compare_pds! pop bx! pop dx! jz $+5 chk_olist05: jmp openx06 push dx test chk_olist_flag,true jz retl1 call delete_item inc_pdcnt: mov al,pdcnt chk_olist1: add al,16! jz chk_olist1 mov pdcnt,al ret PR_TERM: mov dx,pdaddr mov bx,offset open_root! mov cur_pos,bx pr_term1: mov ch,0! push dx! call search_nlist! pop dx! jnz pr_term2 mov cx,6! push bx! call tst_tbl_lmt! pop bx! jnz pr_term1 call remove_locks! call delete_item jmp pr_term1 pr_term2: call func48 retl2: ret FLUSH_FILES: test flushed,true! jnz retl2 mov flushed,true FLUSH_FILE0: mov bx,offset open_root! mov cur_pos,bx flush_file1: push ds! pop es mov ch,1! call search_nlist! jnz retl2 push bx! call remove_locks! call delete_item! pop bx mov bx,6[bx]! mov es,p_uda[bx] test u_pd_cnt,1! jnz flush_file1 or u_pd_cnt,1! push ds! pop es cmp bx,pdaddr! jnz flush_file1 call inc_pdcnt! jmps flush_file1 FREE_FILES: ;free_mode = 1 - remove curdsk files for process ; 0 - remove all files for process mov dx,pdaddr! mov bx,offset open_root! mov cur_pos,bx free_files1: mov ch,free_mode push dx! call search_nlist! pop dx! jnz retl25 mov cx,6! push bx! call tst_tbl_lmt! pop bx! jnz free_files1 cmp word ptr 3[bx],0ffffh! jnz free_files2 cmp byte ptr 5[bx],0ffh! jz free_files3 free_files2: mov incr_pdcnt,true free_files3: call remove_locks! call delete_item jmp free_files1 REMOVE_LOCKS: ;BX -> .olist_item test byte ptr 2[bx],40h! jz retl25 push dx! push prv_pos mov dx,bx! mov bx,offset lock_root! mov cur_pos,bx remove_lock1: mov ch,0! push dx! call searchn_list! pop dx jnz remove_lock2 mov cx,8! push bx! call tst_tbl_lmt! pop bx! jnz remove_lock1 call delete_item jmp remove_lock1 remove_lock2: pop prv_pos! mov bx,dx! pop dx retl25: ret TST_TBL_LMT: add bx,cx lea si,[bx]! cmp [si],dx! ret CREATE_OLIST_ITEM: mov ch,1! call search_olist call create_item! mov al,attributes! call set_olist_item ret COUNT_OPENS: mov open_cnt,0 mov dx,pdaddr! mov bx,offset open_root! mov cur_pos,bx count_open1: mov ch,0! push dx! call searchn_list! pop dx! jnz count_open2 mov cx,6! call tst_tbl_lmt! jnz count_open1 inc open_cnt! jmp count_open1 count_open2: mov al,open_cnt! sub al,open_max retl3: ret COUNT_LOCKS: mov lock_cnt,0 mov dx,bx! mov bx,offset lock_root! mov cur_pos,bx count_lock1: mov ch,0! push dx! call searchn_list! pop dx! jnz retl3 mov cx,8! call tst_tbl_lmt! jnz count_lock1 inc lock_cnt! jmp count_lock1 CHECK_FREE: mov dl,mult_cnt CHECK_FREE0: mov dh,0 mov bx,offset free_root! mov cur_pos,bx check_free1: mov ch,0! push dx! call searchn_list! pop dx! jnz check_free2 inc dh! cmp dh,dl! jb check_free1 retl4: ret check_free2: pop bx! mov al,14! jmp sta_ret LOCK: mov cl,2! call copy_dma_in call parsave36r! call check_fcb test high_ext,80h! jz retl4 mov bx,xdmaad! mov bx,[bx] mov al,curdsk! sub al,2[bx]! and al,0fh! jnz lock8 mov file_id,bx test lock_unlock,true! jz lock1 ; jump if unlock call count_locks mov al,lock_cnt! add al,mult_cnt! jb lock0 cmp lock_max,al! jae lock05 lock0: mov al,12! jmp sta_ret ; too many locks lock05: call check_free lock1: call save_rr! mov bx,offset lock9! push bx! mov ah,mult_cnt lock2: push ax! call get_lock_add test lock_unlock,true! jz lock3 ; jump if unlock call test_lock lock3: pop ax! dec ah! jz lock4 call incr_rr! jmps lock2 lock4: call reset_rr! mov ah,mult_cnt lock5: push ax! call get_lock_add test lock_unlock,true! jz lock6 ; jump if unlock call set_lock! jmp lock7 lock6: call free_lock lock7: pop ax! dec ah! jz retl5 call incr_rr! jmps lock5 lock8: mov al,13! jmp sta_ret lock9: call reset_rr retl5: ret GET_LOCKADD: mov lock_sp,sp! mov lock_shell,true call rseek mov lock_shell,false call getfcb cmp aret,0! jnz lock_err call index! call alloct mov bx,1! jz lock_err call atran ret LOCK_PERR: mov lock_shell,false! mov sp,lock_sp LOCK_ERR: pop dx ; discard return address pop cx ; CH = mult_cnt - # recs processed mov al,mult_cnt! sub al,ch mov cl,4! shl al,cl! or bh,al! mov aret,bx retl6: ret TEST_LOCK: call move_arecord mov ch,3! call search_llist! jnz retl6 call compare_pds! jz retl6 mov bx,8! jmp lock_err SET_LOCK: call move_arecord mov ch,1! call search_llist pushf! cli call create_item xor al,al! call set_olist_item mov dx,file_id! mov [di],dx popf retl7: ret FREE_LOCK: call move_arecord mov ch,5! call search_llist! jnz retl7 free_lock0: call delete_item mov ch,5! call searchn_list! jnz retl7 jmp free_lock0 COMPARE_PDS: add bx,6! mov dx,offset pdaddr mov cl,2! jmp compare MOVE_ARECORD: mov dx,offset arecord! mov bx,offset packed_dcnt mov cl,3! jmp move FIX_OLIST_ITEM: mov si,offset xdcnt! mov di,offset sdcnt mov cx,2 rep cmps ax,ax ; is xdcnt < sdcnt? jae retl7 ; no ;yes - update olist entries call swap! call sdcnt_eq_xdcnt mov bx,offset open_root! mov cur_pos,bx ;find file's olist entries & change dcnt values fix_ol1: call swap! call pack_sdcnt! call swap mov ch,3! call searchn_list! jnz retl8 ;update olist entry with new dcnt value push bx! call pack_sdcnt! pop bx add bx,3! mov dx,offset packed_dcnt mov cl,3! call move! jmp fix_ol1 REMOVE_DRIVE: mov cl,curdsk! mov dx,1! shl dx,cl not dx! and bx,dx retl8: ret DISKRESET: mov ntlog,0! mov set_ro_flag,0 mov bx,info intrnl_disk_reset: cmp open_root,0! jz retl8 mov al,curdsk! push ax! mov ch,0 dskrst1: shr bx,1! jb dskrst3 dskrst2: inc ch! cmp bx,0! jnz dskrst1 pop ax! mov curdsk,al mov bx,ntlog! or tlog,bx inc al! ret dskrst3: push cx! push bx! mov curdsk,ch! mov cl,ch mov dx,tlog! call test_vector1! push dx mov dx,rlog! call test_vector1! push dx mov dx,rodsk! call test_vector1! pop bx or bl,set_ro_flag! or bl,dl! pop dx! or bl,dl! mov check_disk,bl mov bx,offset open_root! mov cur_pos,bx dskrst4: mov ch,1! call search_nlist! jnz dskrst6 test check_disk,true! jz dskrst5 push bx! call compare_pds! jz dskrst45 pop dx! xor al,al! jmp dskrst6 dskrst45: mov cx,ntlog! mov al,curdsk! call set_cdisk1 mov ntlog,bx! pop bx! jmp dskrst4 dskrst5: mov bx,info! call remove_drive! mov info,bx or al,1 dskrst6: pop bx! pop cx! jz $+5! jmp dskrst2 ;error - olist item exists for another process ; on a removeable or read/only drive to be reset ; or any kind of drive if function is write protect disk pop ax! mov curdsk,al cmp error_mode,0ffh! je dskrst7 add ch,41h! mov denieddrv,ch mov bx,dx! mov bx,6[bx]! mov al,p_cns[bx]! add al,30h mov deniedcns,al lea dx,p_name[bx]! mov bx,offset deniedprc mov cl,8! call move mov cx,offset deniedmsg call xprint dskrst7: pop bx! mov aret,0ffffh! ret endif