;*************************** bdos file system part 2 ***************** ; scndm: ;scan the disk map addressed by dptr for non-zero ;entries, the allocation vector entry corresponding ;to a non-zero entry is set to the value of cl (0,1) ;bx addresses the beginning of the directory entry ; call getdptra ;bx = buffa + dptr add bx,dskmap ;bx = diskmap address push cx ;save the 0/1 bit to set mov cl,fcblen-dskmap+1 ;size of single byte diskmap+1 scndm0: ;loop for each diskmap entry pop dx ;recall bit parity dec cl jnz $+3 ret ;all done scanning? ;no, get next entry for scan push dx ;replace bit parity cmp single,0 jz scndm1 ;single byte scan operation push cx ;save counter push bx ;save map address mov cl,[bx] mov ch,0 ;cx=block# jmps scndm2 scndm1: ;double byte scan operation dec cl ;count for double byte push cx ;save counter mov cx,[bx] ;cx=block inc bx push bx ;save map address scndm2: ;arrive here with cx=block#, ;dl= 0/1 or cx,cx ;skip if = 0000 jz scan3 mov bx,maxall ;check invalid index cmp bx,cx jnae $+5 call setallocbit ; ;bit set to 0/1 scan3: ; pop bx inc bx ;to next bit position pop cx ;recall counter jmps scndm0 ;for another item ; GET_NALBS: ;GET # OF ALLOCATION VECTOR BYTES mov bx,maxall mov cl,3 ;perform maxall/8 shr bx,cl inc bx RET8A: RET if MPM TEST_DIR: CALL HOME CALL SET_END_DIR TEST_DIR1: MOV CL,0FEH CALL RD_DIR CMP FLUSHED,FALSE JNE RET8A CALL END_OF_DIR JZ RET8A JMP TEST_DIR1 endif initialize: ;initialize the current disk ;lret = false ;set to true if $ file exists ;compute the length of the allocation vector - 2 if MPM MOV DX,TLOG CALL TEST_VECTOR ;IS TLOG(CURDSK) ON JZ INITIALIZE1 ;NO MOV BX,TLOG ;TLOG(CURDSK) = OFF CALL REMOVE_DRIVE MOV TLOG,BX MOV FLUSHED,FALSE MOV CH,1 ;IS A FILE CURRENTLY OPEN CALL SEARCH_OLIST ;ON THIS DRIVE? JNZ INITIALIZE1 ;NO - RELOG IN THE DRIVE CALL TEST_DIR ;HAS A CHANGE IN MEDIA OCCURRED? JZ RET8A ;NO - DO NOT RELOG IN DRIVE INITIALIZE1: ;LOG IN DRIVE endif CALL GET_NALBS ;BX = # OF ALLOCATION VECTOR BYTES mov cx,bx mov bx,alloca ;base of allocation vector ;fill the allocation vector ;with zeros init0: mov b[bx],0 inc bx ;alloc(i)=0 loop init0 ;set the reserved space for ;the directory MOV BX,DRVLBLA ;ZERO DIRECTORY LABEL DATA BYTE MOV B[BX],0 mov dx,dirblk mov bx,alloca ;bx=.alloc() mov [bx],dx ;sets reserved directory blks ;allocation vector initialized call home ;home disk ;cdrmax = 3 (scans at least ;one directory record) mov bx,cdrmaxa mov w[bx],3 ;cdrmax = 0000 call setenddir ;dcnt = enddir ;read directory entries and ;check for allocated storage init2: mov cl,true call rddir call endofdir jz ret8b ;rz ;not end of directory, ;valid entry ? call getdptra ;bx = buffa + dptr cmp b[bx],empty jz init2 ;go get another item ;not empty,user code the same? CMP B[BX],20H ;IS ENTRY DIRECTORY LABEL ? JE DRV_LBL ;YES TEST B[BX],70H ;IS ENTRY SPECIAL TYPE OF FCB ? JNZ INITIAL3 ;YES ;now scan the disk map for ;allocated blocks mov cl,1 ;set to allocated call scndm INITIAL3: call setcdr ;set cdrmax to dcnt jmps init2 ;for another entry DRV_LBL: MOV AL,EXTNUM[BX] MOV BX,DRV_LBLA MOV [BX],AL JMPS INITIAL3 ; cpydirloc: ;copy directory location to lret following ;delete, rename, ... ops mov al,dirloc jmp staret ; ret ; compext: ;compare extent# in al with that in cl, return nonzero ;if they do not match push cx ;save cl's original value mov ch,extmsk not ch ;ch has negated form of ;extent mask and cl,ch ;low bits removed from cl and al,ch ;low bits removed from al sub al,cl and al,maxext ;set flags pop cx ;restore original values ret8b: ret ; GET_DIR_EXT: ;COMPUTE DIRECTORY EXTENT FROM FCB ;SCAN FCB DISK MAP BACKWARDS ;UPON RETURN BX = .FCB(EXT), AL = DIR EXT ; DL IS NON-ZERO IF NO BLOCKS FOUND ; CALL GTFCBA ;BX = .FCB(VRECORD) MOV DX,1000H ;DH = DISK MAP POSITION (REL TO 1) ;DL = NO BLOCKS SWITCH GET_DE1: DEC DH DEC BX ;DECREMENT DISK MAP PTR CMP B[BX],0 ;IS DISK MAP BYTE NON-ZERO ? JNE GET_DE2 ;YES OR DH,DH ;NO - CONTINUE SCAN JNE GET_DE1 DEC DL ;DL NON-ZERO IF NO BLOCKS FOUND GET_DE2: CMP SINGLE,TRUE ;ARE DISK BLOCK INDEXES SINGLE BYTE ? MOV AL,DH ;AL = BLOCK OFFSET IN DISK MAP JZ GET_DE3 ;YES SHR AL,1 ;DIVIDE BLOCK OFFSET BY 2 ;AL = LAST NON-ZERO BLOCK INDEX IN FCB (REL TO 0) ;COMPUTE EXT OFFSET FROM LAST NON-ZERO BLOCK INDEX BY ;SHIFTING BLOCK INDEX RIGHT 7-BLKSHF GET_DE3: XOR AH,AH MOV CL,7 SUB CL,BLKSHF SHR AX,CL ;AL = EXT OFFSET MOV AH,EXTMSK ;IF EXT OFFSET > EXTMSK THEN CMP AH,AL ; CONTINUE SCAN JB GET_DE1 ;DIR EXT = (FCB EXT & (~EXTMSK) & MAXEXT) | EXT OFFSET CALL GETEXTA ;BX = .FCB(EXT) MOV CL,[BX] ;CL = FCB EXTENT VALUE NOT AH ;AH = ~EXTMSK AND AH,MAXEXT ;AH = AH & MAXEXT AND AH,CL ;AH = AH & FCB EXTENT OR AL,AH ;AL = DIR EXT RET ;DL NON-ZERO IF NO BLOCKS FND SEARCHI: ;SEARCH INITIALIZATION MOV BX,INFO MOV SRCHA,BX ;SEARCHA = INFO SEARCHI1: MOV DIRLOC,0FFH ;CHANGED IF ACTUALLY FOUND MOV SRCHL,CL ;SEARCHL = CL RET SEARCH: srch: ;search for directory element ;of length CL at INFO CALL SEARCHI; SEARCH1: ;ENTRY POINT USED BY RENAME call setenddir ;dcnt = enddir call home ;to start at the beginning ;(drop through to searchn) ; SEARCHN: srchn: ;search for the next directory element, assuming ;a previous call on search which sets searcha and searchhl if MPM MOV BX,OFFSET USER_ZERO_PASS TEST B[BX],TRUE JZ SRCHN1 ;IF USER_ZERO_PASS THEN DO; MOV B[BX],FALSE ; USER_ZERO_PASS = FALSE; CALL SWAP ; CALL SWAP: ; END; SRCHN1: endif if CPM MOV USER_ZERO_PASS,FALSE endif mov cl,false call rddir ;read next dir element call endofdir jz srchfin ;skip to end if so ;not end of directory, ;scan for match mov dx,srcha ;dx=beginning of user fcb mov si,dx lods al ;first character cmp al,empty ;keep scanning if empty jz srchnext ;not empty, may be end of ;logical directory push dx ;save search address call compcdr ;past logical end? pop dx ;recall address jnb srchfin ;artificial stop srchnext: call getdptra ;bx = buffa+dptr MOV CL,SRCHL ;LENGTH OF SEARCH TO CL XOR CH,CH ;ch counts up, cl counts down CMP B[BX],EMPTY ;IS DIR FCB EMPTY JNZ $+5 ;NO CALL SAVE_DCNT_POS1 ;YES - SAVE DCNT MOV SAVE_XFCB,FALSE MOV AL,[BX] ;IS FCB AN XFCB ? AND AL,11101111B CMP AL,[BX] JE SRCH_LOOP ;NO MOV SI,DX CMP AL,[SI] ;DOES USER # MATCH ? JNZ SRCH_LOOP ;NO TEST FIND_XFCB,TRUE ;IS FIND_XFCB TRUE ? JZ SEARCH_N ;NO MOV SAVE_XFCB,TRUE ; JMPS SRCHOK srchfin: ;end of directory, or empty name CALL SAVE_DCNT_POS1 call setenddir ;may be artifical end LRET_EQ_FF: mov al,255 MOV CH,AL INC CH ;ZERO FLAG SET ON UNSUCCESSFUL jmp staret ;SEARCHES srchloop: or cl,cl jz endsearch mov si,dx lods al ;FCB CHARACTER cmp al,'?' jz srchok ;? matches all ;scan next character if not ;ubytes cmp ch,ubytes jz srchok ;not the ubytes field, ;extent field cmp ch,extnum ;may be extent field jz srchext ;skip to search extent CMP CH,MODNUM ;IS FIELD MODULE # ? JNZ $+4 ;NO AND AL,3FH ;YES - MASK OFF HIGH ORDER BITS sub al,[bx] and al,7fh ;mask-out flags/extent modulus JNZ SEARCHNM jmps srchok ;matched character srchext: ;a has fcb character ;attempt an extent # match if MPM CMP BYTE PTR SDCNT+1,TRUE ;IF SDCNT+1 = FF THEN DO; JNE DONT_SAVE ; SDCNT = DCNT MOV SI,DCNT ; SDBLK = DBLK MOV SDCNT,SI ; END; MOV SI,DBLK MOV SDBLK,SI DONT_SAVE: endif push cx ;save counters mov cl,[bx] ;directory character to c call compext ;compare user/dir char pop cx ;recall counters LAHF ;SAVE COMPEXT RESULT TEST USER_ZERO_PASS,TRUE JNZ SAVE_DCNT_POS2 ;IF USER0_PASS GO TO SAVE_DCNT_POS2 ;DISABLE SEARCH UNDER USER ZERO IF ANY FCB IS FOUND UNDER ;THE CURRENT USER NUMBER MOV SEARCH_USER0,FALSE MOV FCB_EXISTS,TRUE SAHF JNZ SEARCHN_JMP ;skip if no match srchok: ;current character matches inc dx inc bx inc ch dec cl jmps srchloop endsearch: ;entire name matches, return dir position TEST SAVE_XFCB,TRUE ;IS SAVE_XFCB TRUE JZ ENDSEARCH1 ;NO CMP BYTE PTR XDCNT+1,0FEH ;IF XDCNT+1 = FE THEN JNE SEARCHN_JMP ; CALL SAVE_DCNT_POS CALL SAVE_DCNT_POS SEARCHN_JMP: JMP SEARCHN ENDSEARCH1: MOV DIRLOC,0 mov al,ldcnt and al,dskmsk mov lret,al MOV CH,AL INC CH ;ZERO FLAG RESET ON SUCCESSFUL ret9: ret ;SEARCHES SEARCHNM: ;SEARCH NO MATCH ROUTINE OR CH,CH ;FCB(0) ? JNZ SEARCHN_JMP ;NO TEST B[BX],0FFH ;IS DIR FCB(0) = 0 ? JNZ SEARCHN_JMP ;NO TEST SEARCH_USER0,TRUE ;IS SEARCH_USER0 TRUE JZ SEARCHN_JMP MOV USER_ZERO_PASS,TRUE if MPM CALL SWAP endif JMPS SRCHOK if MPM SWAP: ;SWAP SDCNT,SDBLK WITH SDCNT0,SDBLK0 MOV AX,SDCNT XCHG AX,SDCNT0 MOV SDCNT,AX MOV AX,SDBLK XCHG AX,SDBLK0 MOV SDBLK,AX RET endif ; SAVE_DCNT_POS2: ;SAVE DIRECTORY POSITION OF MATCHING FCB ;UNDER USER ZERO WITH MATCHING EXTENT & MODNUM = 0 SAHF JNE SEARCHN_JMP INC BX CMP B[BX],0 JNE SEARCHN_JMP CALL SAVE_DCNT_POS JMP SEARCHN SAVE_DCNT_POS1: CMP BYTE PTR XDCNT+1,0FFH JNE RET9 SAVE_DCNT_POS: MOV SI,DCNT MOV XDCNT,SI MOV SI,DBLK MOV XDBLK,SI RET ; INIT_XFCB_SEARCH: MOV AL,0FFH INIT_XFCB_SEARCH1: MOV FIND_XFCB,AL ;FIND_XFCB = FFH MOV AL,0FEH MOV BYTE PTR XDCNT+1,AL ;XDCNT+1 = FEH RET ; DOES_XFCB_EXIST: CMP BYTE PTR XDCNT+1,0FEH ;IF XDCNT+1 = FEH THEN RETURN JE RET9 CALL SET_DCNT_DBLK ;DCNT,DBLK = XDCNT,XDBLK - 1 XOR AL,AL CALL INIT_XFCB_SEARCH1 MOV BX,SRCHA ;OF 10H INTO FCB(0) OR B[BX],10H MOV CL,EXTNUM CALL SEARCHI1 ;SEARCH FOR XFCB JMP SEARCHN ;Z FLAG SET IF UNSUCCESSFUL ; ; delet: ;delete the currently addressed file call checkwrite ;write protected? CALL CHK_PWS ;CHECK FOR PASSWORD ERROR PUSHF ;SAVE RESULT FOR LATER CALL GET_ATTS ;GET & SAVE FCB ATTRIBUTES MOV ATTRIBUTES,AL CALL INIT_XFCB_SEARCH ;SAVE DCNT OF 1ST XFCB IN SEARCH ;PASS MOV CL,EXTNUM ;SEARCH FOR FILE CALL SEARCH POP AX ;IGNORE PASSWORD ERROR IF NO FILES JZ DELETE2 ;FOUND, DELETE XFCBS MOV AH,AL SAHF JZ $+5 JMP CHK_PW1 ;PASSWORD ERROR MOV AL,ATTRIBUTES ;IF DELETING XFCBS ONLY, A PASS RCL AL,1 ;THROUGH THE ENTIRE DIRECTORY JB DELETE015 ;IS REQUIRED TO LOCATE XFCBS MOV BX,INFO ;EACH DCNT MUST BE VERIFIED (MP/M) CALL CHK_WILD ;AND EACH FCB MUST BE CHECKED FOR JZ DELETE015 ;READ/ONLY ON WILD CARD DELETES if MPM CALL TST_OLIST ;VERIFY DCNT AGAINST OPEN LIST endif CALL CK_RODIR ;ONLY ONE PASS IS REQUIRED ON JMPS DELET0 ;NORMAL NON-WILD DELETES DELETE01: ;LOOP WHILE DIRECTORY MATCHES JZ DELETE02 DELETE015: if MPM CALL TST_OLIST ;VERIFY DCNT AGAINST OPEN LIST endif CALL CK_RODIR ;VERIFY FCB IS NOT READ/ONLY CALL SEARCHN JMPS DELETE01 DELETE02: MOV AL,ATTRIBUTES ;SKIP DELETE OF FCBS IF ATTRIBUTE RCL AL,1 ;F5' IS SET JB DELETE2 mov cl,extnum call srch ;search through file type delet0: ;loop while directory matches JZ DELETE2 DELETE1: ;set each non zero disk map ;entry to 0 ;in the allocation vector if MPM CALL CHK_OLIST ;REMOVE MATCHING OPEN LIST ITEMS endif call getdptra ;bx=.buff(dptr) TEST B[BX],10H mov b[bx],empty mov cl,0 JNZ $+5 ;DONT FREE BLOCKS FOR XFCBS call scndm ;alloc elts set to 0 call wrdir ;write the directory call srchn ;to next element jmps delet0 ;for another record DELETE2: CALL DOES_XFCB_EXIST ;IF XFCBS EXIST, DELETE THEM ON JNZ DELETE1 ;ANOTHER PASS THROUGH THE DIRECTORY JMP CPY_DIR_LOC ; getblock: ;given allocation vector position cx, find the zero bit ;closest to this position by searching left and right. ;if found, set the bit to 1 and return the bit position ;in bx. if not found (i.e., we pass 0 on the left, or ;maxall on the right), return 0000 in bx ; mov dx,cx ;copy start pos. to dx lefttst: or cx,cx jz righttst ;skip if left=0000 ;left not at position zero, ;bit zero ? dec cx push dx push cx ;left,right pushed call getallocbit rcr al,1 jae rblok ;return block number if zero ;bit is one, so try the right pop cx pop dx ;left, right restored righttst: cmp dx,maxall ;value of maximum allocation# jae rblok0 ;return block 0000 if so inc dx push cx push dx ;left, right pushed mov cx,dx ;ready right for call call getallocbit rcr al,1 jae rblok ;return block number if zero pop dx pop cx ;restore left and right ptr jmps lefttst ;for another attempt rblok: rcl al,1 inc al ;bit back into position ;and set to 1 ;dl contains the number of ;shifts required to reposition call rotr ;move bit back to position ;and store pop bx pop dx ;bx returned value, ;dx discarded ret rblok0: ;cannot find an available ;bit, return 0000 or cx,cx jnz lefttst mov bx,0000h ret ; ;copyfcb: ; ;copy the entire fcb ; mov cl,0 ; mov dl,fcblen ;start at 0, to fcblen-1 ; ; jmp copydir ; copy_dir: ;copy fcb information starting ;into the currently addressed directory entry MOV DH,80H ;DH = ATTRIBUTE MASK COPY_DIR0: CALL COPY_DIR2 ;INIT REGS BX, CX, DX FOR COPY INC CL COPY_DIR1: DEC CL JZ SEEK_COPY ;COPY OPERATION COMPLETE MOV AH,[BX] ;PICK UP DIR FCB BYTE AND AH,CH ;MASK WITH ATTRIBUTE MASK (0 | 80H) MOV SI,DX LODS AL ;PICK UP FCB BYTE AND AL,7FH ;CLEAR ATTRIBUTE BIT OR AL,AH ;OR IN DIR FCB ATT & ATT MASK MOV [BX],AL ;STORE IN DIR FCB BYTE INC BX ;ADVANCE FCB PTR INC DX ;ADVANCE DIR FCB PTR JMPS COPY_DIR1 COPY_DIR2: push dx ;save length for later mov ch,0 ;double index to cx mov dx,info ;bx = source for data add dx,cx ;dx=.fcb(cl), source for copy call getdptra ;bx=.buff(dptr), destination pop cx ;dx=source, bx=dest, c=length RET seekcopy: ;enter from close to seek and copy current element call seekdir ;to the directory element jmp wrdir ;write the directory element ;ret CHECK_WILD: ;CHECK FOR ? IN FILE NAME OR TYPE MOV BX,INFO CHECK_WILD0: ;ENTRY POINT USED BY RENAME CALL CHK_WILD JNZ RET10 MOV AL,9 ;EXTENDED ERROR 9 JMP SET_ARET CHK_WILD: ;CHECK FCB FOR ? MARKS ;ON ENTRY BX = .FCB(0) ;ON EXIT Z FLAG ON INDICATES ? MARK FOUND MOV CX,3F0BH ;CH = 3F, CL = 11 CHK_WILD1: INC BX ;ADVANCE FCB PTR MOV AL,CH SUB AL,[BX] AND AL,CH JZ RET10 ;RTN WITH Z FLAG SET IF ? FND DEC CL JNZ CHK_WILD1 OR AL,AL ;RTN WITH Z FLAG RESET - NO ?S RET COPY_USER_NO: MOV BX,INFO ;FCB(16) = FCB(0) MOV AL,[BX] ADD BX,DSKMAP MOV [BX],AL ;BX = .FCB(16) RET rename: ;rename the file described by the first half of ;the currently addressed file control block. the ;new name is contained in the last half of the ;currently addressed file conrol block. the file ;name and type are changed, but the reel number ;is ignored. the user number is identical. ; call checkwrite ;may be write protected CALL CHECK_WILD ;CHECK FOR ?S IN 1ST FILENAME CALL CHK_PASSWORD ;CHECK PASSWORD CALL INIT_XFCB_SEARCH CALL COPY_USER_NO ;FCB(16) = FCB(0) MOV SRCHA,BX CALL CHECK_WILD0 ;CHECK 2ND FILENAME FOR ?S MOV CL,EXTNUM ;CHECK TO SEE IF NEW FILENAME CALL SEARCHI1 ;ALREADY EXIST ON DRIVE CALL SEARCH1 JZ $+5 JMP FILE_EXISTS ;ERROR - FILE EXISTS CALL DOES_XFCB_EXIST ;DELETE XFCB IF PRESENT JZ $+5 CALL DELETE1 CALL COPY_USER_NO ;FCB(16) = FCB(0) AGAIN CALL INIT_XFCB_SEARCH ;search up to the extent field mov cl,extnum call srch ; ;copy position 0 ; mov bx,info ; mov al,[bx] ;bx=.fcb(0), a=fcb(0) ; add bx,dskmap ;bx=.fcb(diskmap) ; mov [bx],al ;fcb(dskmap)=fcb(0) ; ;assume the same disk ; ;for new named file JNZ $+3 RET10: RET CALL CK_RODIR ;CHECK FOR READ/ONLY FILE if MPM CALL CHK_OLIST endif renam0: ;not end of directory, ;rename next element mov cl,dskmap mov dl,extnum call copydir ;element renamed, move to next call srchn JNZ RENAM0 RENAME1: CALL DOES_XFCB_EXIST ;RENAME XFCB IF PRESENT JNZ $+5 JMP CPY_DIR_LOC CALL COPY_USER_NO ;XFCB(16) = XFCB(0) JMPS RENAM0 ; indicators: ;set file indicators for current fcb CALL GET_ATTS mov cl,extnum call srch ;through file type JZ RET10 if MPM CALL CHK_OLIST endif indic0: ;not end of directory, ;continue to change mov cl,0 mov dl,extnum ;copy name CALL COPY_DIR2 CALL MOVE CALL SEEK_COPY call srchn JNZ INDIC0 JMP CPY_DIR_LOC ; open: ;search for the directory entry, copy to fcb mov cl,namlen call srch OPEN1: jz ret10 ;return with lret=255 if end ;not end of directory,copy fcb opencopy: ;(referenced below to copy fcb CALL SETFWF ;AL = MODNUM | FWFMSK PUSH BX ;BX = .FCB(MODNUM) DEC BX DEC BX MOV AH,[BX] ;AH = EXTNUM push ax ;SAVE EXTNUM & MODNUM call getdptra xchg bx,dx ;dx = .buff(dptr) mov bx,info ;bx=.fcb(0) mov cl,nxtrec ;length of move operation push dx ;save .buff(dptr) call move ;from .buff(dptr) to .fcb(0) ;note that entire fcb is ;copied, including indicators call setfwf ;sets file write flag pop dx mov bx,extnum add bx,dx ;bx=.buff(dptr+extnum) mov cl,[bx] ; mov bx,reccnt ; add bx,dx ; mov ch,[bx] POP AX POP BX MOV [BX],AL ;RESTORE MODNUM DEC BX DEC BX MOV [BX],AH ;RESTORE EXTNUM NUMBER ; ;bx = .user extent#, ch = dir rec cnt, cl = dir extent# ;if user ext < dir ext then user := 128 records ;if user ext = dir ext then user := dir records ;if user ext > dir ext then user := 0 records ; ; cmp cl,[bx] ; mov al,ch ;ready dir reccnt ; jz openrcnt ;if same, user gets dir reccnt ; mov al,0 ; jb openrcnt ;user is larger ; mov al,128 ;directory is larger ;openrcnt: ;a has record count to fill ; mov bx,info ; mov dx,reccnt ; add bx,dx ; mov [bx],al ;ret11: ret ;BX = .USER EXTENT #, CL = DIR EXTENT # SET_RC: MOV CH,0 LEA SI,(RECCNT-EXTNUM)[BX] MOV AL,[BX] ;AL = CURRENT EXTENT CMP AL,CL ;COMPARE FCB EXT TO DIR EXT JZ SET_RC2 ;FCB EXT = DIR EXT ; ACTUAL_RC = 0, FCB(RC) = FCB(RC) MOV AL,0 JAE SET_RC1 ;FCB EXT > DIR EXT ; ACTUAL_RC = 0, FCB(RC) = 0 MOV AL,128 ;FCB EXT < DIR EXT MOV CH,[SI] ; ACTUAL_RC = FCB(RC), FCB(RC) = 128 SET_RC1: MOV [SI],AL SET_RC2: MOV ACTUAL_RC,CH RET11: RET mergezero: ;bx = .fcb1(i), dx = .fcb2(i), ;if fcb1(i) = 0 ;then fcb1(i) := fcb2(i) cmp w[bx],0 jnz ret11 ;rnz mov si,dx lods ax mov [bx],ax ret12: ret ; RESTORE_RC: ;BX = .FCB(EXTNUM) ;IF ACTUAL_RC ~= 0 THEN FCB(RC) = ACTUAL_RC MOV AL,ACTUAL_RC OR AL,AL JZ RET12 LEA SI,(RECCNT-EXTNUM)[BX] MOV [SI],AL RET close: ;locate the directory element and re-write it xor ax,ax mov lret,al if MPM MOV DONT_CLOSE,AL endif ; mov dcnt,ax call nowrite jnz ret12 ;skip close if r/o disk ;check file write flag - ;0 indicates written call getmodnum ;fcb(modnum) in a and al,fwfmsk jnz ret12 ;return if bit remains set CLOSE1: MOV COMP_FCB_CKS,TRUE CALL GETEXTA MOV AL,[BX] MOV SAVE_EXT,AL ;SAVE EXTENT CALL CLOSE_FCB CALL GETDPTRA MOV CL,EXTNUM[BX] ;CL = DIR EXTENT CALL GETEXTA MOV AL,SAVE_EXT ;RESTORE EXTENT MOV [BX],AL JMP SET_RC CLOSE_FCB: CALL GET_DIR_EXT ;BX = .FCB(EXT), AL = DIR EXT ;DL NON-ZERO INDICATES NO BLOCKS ;EXIST IN FCB MOV CH,[BX] ;SAVE CURRENT EXTENT MOV [BX],AL ;FCB(EXT) = DIR EXT INC AL CMP CH,AL ;DID ORIGINAL FCB(EXT) = DIR EXT + 1 ? JNE CLOSE2 ;NO OR DL,DL ;DO ALLOCATED BLOCKS EXIST IN FCB ? JNZ CLOSE2 ;NO LEA SI,(RECCNT-EXTNUM)[BX] CMP B[SI],0 ;IS FCB(RC) = 0 JNZ CLOSE2 ;NO MOV B[SI],80H ;SET FCB(RC) TO 128 CLOSE2: CALL RESTORE_RC ;RESTORE FCB(RC) mov cl,namlen call srch ;locate file ; call endofdir jz ret12 ;return if not found ;merge the disk map at info mov cx,dskmap call getdptra add bx,cx xchg bx,dx ;dx is .buff(dptr+16) mov bx,info add bx,cx ;dx=.buff(dptr+16), ;bx=.fcb(16) mov cl,(fcblen-dskmap) ;length of single byte dm merge0: cmp single,0 jz merged ;skip to double ; ;this is a single byte map ;if fcb(i) = 0 then fcb(i) = buff(i) ;if buff(i) = 0 then buff(i) = fcb(i) ;if fcb(i) <> buff(i) then error ; mov al,[bx] or al,al mov si,dx lods al jnz fcbnzero ;fcb(i) = 0 mov [bx],al ;fcb(i) = buff(i) fcbnzero: or al,al jnz buffnzero ;buff(i) = 0 mov al,[bx] mov di,dx cld stos al ;buff(i)=fcb(i) buffnzero: cmp al,[bx] jnz mergerr ;fcb(i) = buff(i)? jmps dmset ;if merge ok merged: ;this is a double byte merge call mergezero ;buff = fcb if buff 0000 xchg bx,dx call mergezero xchg bx,dx ;fcb = buff if fcb 0000 ;they should be identical ;at this point mov si,dx mov ax,[si] cmp ax,[bx] jnz mergerr inc dx inc bx ;merge ok for this pair dec cl ;extra count for double byte dmset: inc dx inc bx dec cl jnz merge0 ;for more ;end of disk map merge, ;check record count ;dx = .buff(dptr)+32, ;bx = .fcb(32) mov cx,-(fcblen-extnum) add bx,cx xchg bx,dx add bx,cx ;dx = .fcb(extnum), ;bx = .buff(dptr+extnum) mov si,dx lods al ;current user extent number ;if fcb(ext) >= buff(fcb) then ;buff(ext) := fcb(ext), ;buff(rec) := fcb(rec) cmp al,[bx] jb endmerge if MPM LAHF endif ;fcb extent number >= ;dir extent number mov [bx],al ;buff(ext) = fcb(ext) ;update dir. rec count field mov cx,(reccnt-extnum) add bx,cx xchg bx,dx add bx,cx ;dx=.buff(reccnt), ;bx=.fcb(reccnt) if MPM ;UNDER MP/M RECCNT MAY HAVE BEEN EXTENDED ;BY ANOTHER PROCESS - IF EXTENTS MATCH, SET ;BOTH RECCNT FIELDS TO THE HIGHER VALUE SAHF JNZ DMSET1 MOV SI,DX MOV AL,[SI] CMP AL,[BX] JB DMSET1 MOV [BX],AL DMSET1: endif mov al,[bx] mov di,dx stos al ;buff(reccnt)=fcb(reccnt) endmerge: if MPM TEST DONT_CLOSE,TRUE JNZ RET13 endif ;SET T3' OFF INDICATING FILE UPDATE CALL GETDPTRA ADD BX,11 MOV AL,[BX] AND AL,7FH MOV [BX],AL CALL SETFWF ; mov fcbcopied,true ;mark as copied jmp seekcopy ;ok to "wrdir" here - ;1.4 compatible ; ret mergerr: CALL MAKE_FCB_INV ;elements did not merge ok dec lret ;=255 non zero flag set ret13: ret SET_DCNT_DBLK: MOV BX,XDCNT AND BL,0FCH DEC BX MOV DCNT,BX MOV BX,XDBLK MOV DBLK,BX RET if MPM SDCNT_EQ_XDCNT: MOV BX,OFFSET SDCNT MOV DX,OFFSET XDCNT MOV CL,4 JMP MOVE endif ; make: ;create a new file by creating a directory entry ;then opening the file CMP XDCNT,0FFFFH JNE $+5 JMP LRET_EQ_FF CALL SET_DCNT_DBLK call checkwrite ;may be write protected push info mov info,offset efcb ;info = .empty mov cl,1 CALL SEARCHI CALL SEARCHN ;zero flag set if no space pop info ;recall word ptr info address jz ret13 ;return with error condition ;255 if not found TEST MAKE_XFCB,0FFH ;RETURN EARLY IF MAKING AN XFCB JNZ RET13 MOV BX,INFO ADD BX,13 MOV B[BX],0 ;CLEAR S1 BYTE INC BX MOV AL,[BX] ;CLEAR AND SAVE FILE WRITE FLAG PUSH AX PUSH BX AND B[BX],3FH INC BX ;clear the remainder of fcb mov cl,fcblen-namlen ;number of bytes to fill xor al,al ;clear al for fill make0: mov [bx],al inc bx dec cl jnz make0 call setcdr ;may have extended dir ;now copy entry to dir MOV CL,0 MOV DX,FCBLEN ;DH = 0 CALL COPY_DIR0 POP BX ;RESTORE FILE WRITE FLAG POP AX MOV [BX],AL MOV ACTUAL_RC,0 ;ACTUAL_RC = 0 ;set file write flag to "1" jmp setfwf ;ret ; openreel: ;close the current extent, and open the next one ;if possible. rmf is true if in read mode. ; xor al,al ; mov fcbcopied,al ;set true if actually copied CALL GETMODNUM MOV SAVE_MOD,AL ;SAVE CURRENT MODULE # CALL GETEXTA MOV AL,[BX] MOV CL,AL INC CL ;INCREMENT EXT # CALL COMP_EXT ;DID WE CROSS A DIR FCB BOUNDARY ? JZ OPENR3 ;NO PUSH BX PUSH CX call close ;close current extent ;lret remains at enddir ;if we cannot open next ext POP CX POP BX ; call endofdir ; jz ret13 ;return if end CMP LRET,0FFH JNE $+3 RET MOV AL,MAXEXT AND AL,CL MOV [BX],AL ;UPDATE FCB EXTENT FIELD JNZ OPENR0 ;BRANCH IF IN SAME MODULE ; ;increment extent number ; mov bx,info ; add bx,extnum ;bx=.fcb(extnum) ; mov al,[bx] ; inc al ; and al,maxext ; mov [bx],al ;fcb(extnum)=++1 ; jz openmod ;move to next module if 0 ; ;may be in same extent group ; mov ch,al ; mov al,extmsk ; and al,ch ; ;if 0, then not in same group ; and al,fcbcopied ;true if fcb was copied to dir ; ;puts 0 in al if not written ; jz openr0 ;go to next physical extent ; ;result is non zero, ; ;so we must be in same extent ; jmps openr1 ;to copy fcb info openmod: ;extent number overflow, go to next module add bx,(modnum-extnum) ;bx=.fcb(modnum) inc b[bx] ;fcb(modnum)=++1 ;module number incremented, ;check for overflow mov al,[bx] and al,maxmod ;mask high order bits jz openerr ;cannot overflow to 0 ;otherwise, ok to continue ;with new module openr0: MOV XDCNT,0FFFFH ;RESET XDCNT FOR MAKE if MPM MOV BYTE PTR SDCNT+1,0FFH endif mov cl,namlen call srch ;next extent found? jnz openr1 ;end of file encountered mov al,rmf inc al ;0ffh becomes 00 if read jz openerr ;sets lret = 1 ;try to extend current file call make ;cannot be end of directory ; call endofdir jz openerr ;with lret = 1 if MPM CALL FIX_OLIST_ITEM endif MOV COMP_FCB_CKS,TRUE jmps openr2 openr1: MOV COMP_FCB_CKS,TRUE ;SET FCB CHECKSUM FLAG ;not end of file, open call opencopy openr2: call getfcb ;set parameters xor al,al MOV VRECORD,AL jmp staret ;lret = 0 ; ret openerr: CALL GETMODNUM MOV AL,SAVE_MOD MOV [BX],AL CALL GETEXTA MOV AL,SAVE_EXT MOV [BX],AL CALL MAKE_FCB_INV MOV COMP_FCB_CKS,0FFH ;cannot move to next extent ;of this file call setlret1 ;lret = 1 jmp setfwf ;ensure that it will not ;be closed ;ret OPENR3: MOV [BX],CL ;INCREMENT EXTENT FIELD CALL GET_DIR_EXT MOV CL,AL CALL RESTORE_RC CALL SET_RC JMPS OPENR2 ; ;*************** end bdos file system part 2 *************** end