From 2d04cacc5322951f187bb17e017c12920ac8ebe2 Mon Sep 17 00:00:00 2001 From: Mark Zbikowski Date: Thu, 25 Apr 2024 21:24:10 +0100 Subject: MZ is back! --- v4.0/src/DOS/ROM.ASM | 938 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 938 insertions(+) create mode 100644 v4.0/src/DOS/ROM.ASM (limited to 'v4.0/src/DOS/ROM.ASM') diff --git a/v4.0/src/DOS/ROM.ASM b/v4.0/src/DOS/ROM.ASM new file mode 100644 index 0000000..ca34409 --- /dev/null +++ b/v4.0/src/DOS/ROM.ASM @@ -0,0 +1,938 @@ +; SCCSID = @(#)rom.asm 1.1 85/04/10 +TITLE ROM - Miscellaneous routines +NAME ROM +; Misc Low level routines for doing simple FCB computations, Cache +; reads and writes, I/O optimization, and FAT allocation/deallocation +; +; SKPCLP +; FNDCLUS +; BUFSEC +; BUFRD +; BUFWRT +; NEXTSEC +; OPTIMIZE +; FIGREC +; ALLOCATE +; RESTFATBYT +; RELEASE +; RELBLKS +; GETEOF +; +; Modification history: +; +; Created: ARR 30 March 1983 +; + +; +; get the appropriate segment definitions +; +.xlist +include dosseg.asm +include fastseek.inc ; DOS 4.00 +include fastxxxx.inc ; DOS 4.00 +include version.inc + +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + +.xcref +INCLUDE DOSSYM.INC +INCLUDE DEVSYM.INC +include EA.inc +.cref +.list + + i_need CLUSNUM,WORD + i_need NEXTADD,WORD + i_need LASTPOS,WORD + i_need SECCLUSPOS,BYTE + i_need FATBYT,WORD + i_need THISSFT,DWORD + i_need TRANS,BYTE + i_need BYTCNT1,WORD + i_need CURBUF,DWORD + i_need BYTSECPOS,WORD + i_need DMAADD,WORD + i_need SECPOS,DWORD ;F.C. >32mb + i_need VALSEC,DWORD ;F.C. >32mb + i_need ALLOWED,BYTE + i_need FSeek_drive,BYTE ; DOS 3.4 + i_need FSeek_firclus,WORD ; DOS 3.4 + i_need FSeek_logclus,WORD ; DOS 3.4 + i_need FSeek_logsave,WORD ; DOS 3.4 + i_need FastSeekFlg,BYTE ; DOS 3.4 + i_need XA_condition,BYTE ; DOS 3.4 + i_need HIGH_SECTOR,WORD ; DOS 3.4 + i_need DISK_FULL,BYTE ; DOS 3.4 + i_need Temp_VAR2,WORD ; DOS 3.4 + + + +Break + +; Inputs: +; CX = No. of clusters to skip +; ES:BP = Base of drive parameters +; [THISSFT] point to SFT +; Outputs: +; BX = Last cluster skipped to +; CX = No. of clusters remaining (0 unless EOF) +; DX = Position of last cluster +; Carry set if error (currently user FAILed to I 24) +; DI destroyed. No other registers affected. + + procedure FNDCLUS,NEAR + DOSAssume CS,,"FndClus" + ASSUME ES:NOTHING + + Assert ISDPB,,"FndCLus" +;; 10/31/86 FastSeek + PUSH ES + LES DI,[THISSFT] + Assert ISSFT,,"FndClus" + MOV [FSeek_logclus],CX ; presume CX is the position ;AN000; + MOV BX,ES:[DI.sf_lstclus] + MOV DX,ES:[DI.sf_cluspos] +;; 10/31/86 FastSeek + OR BX,BX + JNZ YCLUS + JMP NOCLUS +YCLUS: + SUB CX,DX + JNB FINDIT + ADD CX,DX + XOR DX,DX + MOV BX,ES:[DI.sf_firclus] +FINDIT: +;; 10/31/86 FastSeek + + + POP ES + OR CX,CX + JNZ skpclp + JMP RET10 + +entry SKPCLP + TEST [FastSeekflg],Fast_yes ; fastseek installed? ;AN000; + JZ do_norm ; no ;AN000; + TEST [FastSeekflg],FS_begin ; do fastseek ;AN000; + JZ do_norm ; no ;AN000; + TEST [FastSeekflg],FS_insert ; is in insert mode ? ;AN000; + JNZ do_norm ; yes ;AN000; + MOV [Temp_Var2],BX ; save physical cluster ;AN000; + ; PTR P005079 +SKPCLP2: + invoke FastSeek_Lookup ; ask for next cluster # ;AN000; + JNC clusfound ; yes, we got it ;AN000; + CMP DI,1 ; valid drive ,e.g. C,D... ;AN000; + JNZ par_found ; yes, ;AN000; + AND [FastSeekflg],Fast_yes ; no more, fastseek ;AN000; + JMP SHORT do_norm ;AN000; + ;AN000; +par_found: + CALL FS_Trunc_EOF ; check EOF and truncate ;AN000; + JNC SKPCLP2 ; redo lookup ;AN000; +noteof: + OR [FastSeekflg],FS_insert ; no, start to insert ;AN000; + CMP DX,[FSeek_logsave] ; is current better than new? ;AN000; + JBE OnCache ; no, let's use new ;AN000; + MOV [FSeek_logclus],DX ; use current ;AN000; + MOV BX,[Temp_Var2] ; retore pysical cluster ;AN000; + MOV DI,BX ; insert cureent cluster ;AN000; + invoke FastSeek_Insert ; insert cluster # to ;AN000; + INC [FSeek_logclus] ; get next inserted position ;AN000; + JMP SHORT do_norm +OnCache: + MOV CX,[FSeek_logclus] ; get the number of clusters ;AN000; + SUB CX,[FSeek_logsave] ; we need to skip ;AN000; + MOV DX,[FSeek_logsave] ; cluster position ;AN000; +dodo: + INC [FSeek_logsave] ; get next inserted position ;AN000; + PUSH [FSeek_logsave] ; logclus=logsave ;AN000; + POP [FSeek_logclus] ;AN000; + +do_norm: + + invoke UNPACK + retc + + invoke FastSeek_Insert ; insert cluster # to ;AN000; +cluss: ;AN000; + PUSH BX ; FastSeek ;AN000; + MOV BX,DI + Invoke IsEOF + POP BX + JAE RET10 + XCHG BX,DI + INC DX + INC [FSeek_logclus] ; increment for next inserted ;AN000; + LOOP SKPCLPX + JMP short RET10 +SKPCLPX: + JMP SKPCLP +RET10: ;AN000; + AND [FastSeekflg],FS_no_insert ; clear insert mode + CLC + return +NOCLUS: + POP ES + INC CX + DEC DX + CLC + return +clusfound: + MOV DX,[FSeek_logclus] ; get cluster position ;AN000; + MOV BX,[FSeek_logsave] ; bx=previous cluster # PTM ;AN000; + DEC DX ;AN000; + MOV CX,1 ; we found it ;AN000; + JMP cluss ;AN000; + +EndProc FNDCLUS + +Break + +; Inputs: +; AH = priority of buffer +; AL = 0 if buffer must be read, 1 if no pre-read needed +; ES:BP = Base of drive parameters +; [CLUSNUM] = Physical cluster number +; [SECCLUSPOS] = Sector position of transfer within cluster +; [BYTCNT1] = Size of transfer +; Function: +; Insure specified sector is in buffer, flushing buffer before +; read if necessary. +; Outputs: +; ES:DI = Pointer to buffer +; SI = Pointer to transfer address +; CX = Number of bytes +; [NEXTADD] updated +; [TRANS] set to indicate a transfer will occur +; Carry set if error (user FAILed to I 24) + + procedure BUFSEC,NEAR + DOSAssume CS,,"BufSec" + ASSUME ES:NOTHING + + Assert ISDPB,,"BufSec" + MOV DX,[CLUSNUM] + MOV BL,[SECCLUSPOS] + MOV [ALLOWED],allowed_FAIL + allowed_RETRY + allowed_IGNORE + CALL FIGREC + invoke GETBUFFR + retc + MOV BYTE PTR [TRANS],1 ; A transfer is taking place + MOV SI,[NEXTADD] + MOV DI,SI + MOV CX,[BYTCNT1] + ADD DI,CX + MOV [NEXTADD],DI + LES DI,[CURBUF] + Assert ISBUF,,"BufSec" + OR ES:[DI.buf_flags],buf_isDATA + LEA DI,[DI].BUFINSIZ ; Point to buffer + ADD DI,[BYTSECPOS] + CLC + return +EndProc BUFSEC + +Break + +; Do a partial sector read via one of the system buffers +; ES:BP Points to DPB +; Carry set if error (currently user FAILed to I 24) + + procedure BUFRD,NEAR + DOSAssume CS,,"BufRd" + ASSUME ES:NOTHING + + Assert ISDPB,,"BufRd" + PUSH ES + MOV AX,0 + CALL BUFSEC + JNC BUF_OK +BUF_IO_FAIL: + POP ES + JMP SHORT RBUFPLACED + +BUF_OK: + MOV BX,ES + MOV ES,[DMAADD+2] + MOV DS,BX +ASSUME DS:NOTHING + XCHG DI,SI + SHR CX,1 + JNC EVENRD + MOVSB +EVENRD: + REP MOVSW + POP ES + LDS DI,[CURBUF] + Assert ISBUF,,"BufRD/EvenRD" + LEA BX,[DI.BufInSiz] + SUB SI,BX ; Position in buffer + invoke PLACEBUF + Assert ISDPB,,"BufRD/EvenRD" + CMP SI,ES:[BP.dpb_sector_size] ; Read Last byte? + JB RBUFPLACEDC ; No, leave buf where it is + invoke PLACEHEAD ; Make it prime candidate for chucking + ; even though it is MRU. +RBUFPLACEDC: + CLC +RBUFPLACED: + PUSH SS + POP DS + return +EndProc BUFRD + +; Do a partial sector write via one of the system buffers +; ES:BP Points to DPB +; Carry set if error (currently user FAILed to I 24) + + procedure BUFWRT,NEAR + DOSAssume CS,,"BufWrt" + ASSUME ES:NOTHING + + Assert ISDPB,,"BufWrt" + MOV AX,WORD PTR [SECPOS] + ADD AX,1 ; Set for next sector + MOV WORD PTR [SECPOS],AX ;F.C. >32mb ;AN000; + ADC WORD PTR [SECPOS+2],0 ;F.C. >32mb ;AN000; + MOV AX,WORD PTR [SECPOS+2] ;F.C. >32mb ;AN000; + CMP AX,WORD PTR [VALSEC+2] ;F.C. >32mb ;AN000; + MOV AL,1 ;F.C. >32mb ;AN000; + JA NOREAD ;F.C. >32mb ;AN000; + JB doread ;F.C. >32mb ;AN000; + MOV AX,WORD PTR [SECPOS] ;F.C. >32mb ;AN000; + CMP AX,WORD PTR [VALSEC] ; Has sector been written before? + MOV AL,1 + JA NOREAD ; Skip preread if SECPOS>VALSEC +doread: + XOR AL,AL +NOREAD: + PUSH ES + CALL BUFSEC + JC BUF_IO_FAIL + MOV DS,[DMAADD+2] +ASSUME DS:NOTHING + SHR CX,1 + JNC EVENWRT + MOVSB +EVENWRT: + REP MOVSW + POP ES + LDS BX,[CURBUF] + Assert ISBUF,,"BufWrt/EvenWrt" + + TEST [BX.buf_flags],buf_dirty ;LB. if already dirty ;AN000; + JNZ yesdirty ;LB. don't increment dirty count ;AN000; + invoke INC_DIRTY_COUNT ;LB. ;AN000; + OR [BX.buf_flags],buf_dirty +yesdirty: + LEA SI,[BX.BufInSiz] + SUB DI,SI ; Position in buffer + MOV SI,DI + MOV DI,BX + invoke PLACEBUF + Assert ISDPB,,"BufWrt/EvenWrt" + CMP SI,ES:[BP.dpb_sector_size] ; Written last byte? + JB WBUFPLACED ; No, leave buf where it is + invoke PLACEHEAD ; Make it prime candidate for chucking + ; even though it is MRU. +WBUFPLACED: + CLC + PUSH SS + POP DS + return +EndProc BUFWRT + +Break + +; Compute the next sector to read or write +; ES:BP Points to DPB + + procedure NEXTSEC,NEAR + DOSAssume CS,,"NextSec" + ASSUME ES:NOTHING + + Assert ISDPB,,"NextSec" + TEST BYTE PTR [TRANS],-1 + JZ CLRET + MOV AL,[SECCLUSPOS] + INC AL + CMP AL,ES:[BP.dpb_cluster_mask] + JBE SAVPOS + MOV BX,[CLUSNUM] + Invoke IsEOF + JAE NONEXT +;; 11/5/86 FastSeek + TEST [FastSeekflg],Fast_yes ; fastseek installed? ;AN000; + JZ do_norm2 ; no ;AN000; + PUSH [LASTPOS] ; save logical cluster # ;AN000; + POP [FSeek_logclus] ;AN000; + INC [FSeek_logclus] ; get next cluster ;AN000; + ;AN000; + TEST [FastSeekflg],FS_begin ; from R/W ;AN000; + JZ do_norm2 ; no ;AN000; +look2: ;AN000; + invoke FastSeek_Lookup ; call lookup ;AN000; + JNC clusgot ; found one ;AN000; + + CMP DI,1 ; valid drive ,e.g. C,D... ;AN000; + JNZ parfound2 ; yes, ;AN000; + AND [FastSeekflg],Fast_yes ; no more, fastseek ;AN000; + JMP SHORT do_norm2 ;AN000; +parfound2: + CALL FS_TRUNC_EOF ; check EOF ;AN000; + MOV BX,[CLUSNUM] ; don't need partially found cluster + OR [FastSeekflg],FS_insert ; prepared for cluster insertion ;AN000; + ; use the old bx ;AN000; + ;AN000; +do_norm2: + invoke UNPACK + JC NONEXT + invoke FastSeek_Insert ; call insert ;AN000; + AND [FastSeekflg],FS_no_insert ; clear insert flag ;AN000; + ;AN000; +clusgot: +;; 11/5/86 FastSeek + MOV [CLUSNUM],DI + INC [LASTPOS] + MOV AL,0 +SAVPOS: + MOV [SECCLUSPOS],AL +CLRET: + CLC + return +NONEXT: + STC + return +EndProc NEXTSEC + +Break + +; Inputs: +; BX = Physical cluster +; CX = No. of records +; DL = sector within cluster +; ES:BP = Base of drives parameters +; [NEXTADD] = transfer address +; Outputs: +; AX = No. of records remaining +; BX = Transfer address +; CX = No. or records to be transferred +; DX = Physical sector address (LOW) +; [HIGH_SECTOR] = Physical sector address (HIGH) +; DI = Next cluster +; [CLUSNUM] = Last cluster accessed +; [NEXTADD] updated +; Carry set if error (currently user FAILed to I 24) +; ES:BP unchanged. Note that segment of transfer not set. + + procedure OPTIMIZE,NEAR + DOSAssume CS,,"Optimize" + ASSUME ES:NOTHING + + Assert ISDPB,,"Optimize" + PUSH DX + PUSH BX + MOV AL,ES:[BP.dpb_cluster_mask] + INC AL ; Number of sectors per cluster + MOV AH,AL + SUB AL,DL ; AL = Number of sectors left in first cluster + MOV DX,CX + MOV CX,0 +;;; 11/5/86 FastSeek + PUSH [LASTPOS] ; save logical cluster # ;AN000; + POP [FSeek_logclus] ;AN000; + INC [FSeek_logclus] ; get next cluster ;AN000; + ;AN000; +OPTCLUS: +; AL has number of sectors available in current cluster +; AH has number of sectors available in next cluster +; BX has current physical cluster +; CX has number of sequential sectors found so far +; DX has number of sectors left to transfer +; ES:BP Points to DPB +; ES:SI has FAT pointer + + TEST [FastSeekflg],Fast_yes ; fastseek installed? ;AN000; + JZ do_norm3 ; no ;AN000; + TEST [FastSeekflg],FS_begin ; from R/W ;AN000; + JZ do_norm3 ; no ;AN000; + TEST [FastSeekflg],FS_insert ; is in insert mode ? ;AN000; + JNZ do_norm3 ; yes ;AN000; + invoke FastSeek_Lookup ; call lookup ;AN000; + JNC clusgot2 ; found one ;AN000; + + CMP DI,1 ; valid drive ,e.g. C,D... ;AN000; + JNZ par_found3 ; yes, ;AN000; + AND [FastSeekflg],Fast_yes ; no more, fastseek ;AN000; + JMP SHORT do_norm3 ;AN000; +par_found3: + PUSH BX + CALL FS_TRUNC_EOF ; file entry not existing ;AN000; + POP BX ;AN000; + OR [FastSeekflg],FS_insert ; prepare for insertion ;AN000; + ; use old bx ;AN000; +do_norm3: + invoke UNPACK + JC OP_ERR +clusgot2: + invoke FastSeek_Insert ; call insert ;AN000; + INC [FSeek_logclus] ; insert to next position ;AN000; +;;; 11/5/86 FastSeek ;AN000; + ADD CL,AL + ADC CH,0 + CMP CX,DX + JAE BLKDON + MOV AL,AH + INC BX + CMP DI,BX + JZ OPTCLUS + DEC BX +FINCLUS: + MOV [CLUSNUM],BX ; Last cluster accessed + SUB DX,CX ; Number of sectors still needed + PUSH DX + MOV AX,CX + MUL ES:[BP.dpb_sector_size] ; Number of sectors times sector size + MOV SI,[NEXTADD] + ADD AX,SI ; Adjust by size of transfer + MOV [NEXTADD],AX + POP AX ; Number of sectors still needed + POP DX ; Starting cluster + SUB BX,DX ; Number of new clusters accessed + ADD [LASTPOS],BX + POP BX ; BL = sector postion within cluster + invoke FIGREC + MOV BX,SI + AND [FastSeekflg],FS_no_insert ; clear insert flag + CLC + return + +OP_ERR: + ADD SP,4 + AND [FastSeekflg],FS_no_insert ; clear insert flag + STC + return + +BLKDON: + SUB CX,DX ; Number of sectors in cluster we don't want + SUB AH,CL ; Number of sectors in cluster we accepted + DEC AH ; Adjust to mean position within cluster + MOV [SECCLUSPOS],AH + MOV CX,DX ; Anyway, make the total equal to the request + JMP SHORT FINCLUS +EndProc OPTIMIZE + +Break + +; Inputs: +; DX = Physical cluster number +; BL = Sector postion within cluster +; ES:BP = Base of drive parameters +; Outputs: +; DX = physical sector number (LOW) +; [HIGH_SECTOR] Physical sector address (HIGH) +; No other registers affected. + + procedure FIGREC,NEAR +ASSUME DS:NOTHING,ES:NOTHING + + Assert ISDPB,,"FigRec" + PUSH CX + MOV CL,ES:[BP.dpb_cluster_shift] + DEC DX + DEC DX + MOV [HIGH_SECTOR],0 ;F.C. >32mb + OR CL,CL ;F.C. >32mb + JZ noshift ;F.C. >32mb + XOR CH,CH ;F.C. >32mb +rotleft: ;F.C. >32mb + CLC ;F.C. >32mb + RCL DX,1 ;F.C. >32mb + RCL [HIGH_SECTOR],1 ;F.C. >32mb + LOOP rotleft ;F.C. >32mb +noshift: + +; SHL DX,CL + OR DL,BL + ADD DX,ES:[BP.dpb_first_sector] + ADC [HIGH_SECTOR],0 ;F.C. >32mb + POP CX + return +EndProc FIGREC + +Break + +;*** ALLOCATE - Allocate Disk Space +; +; ALLOCATE is called to allocate disk clusters. The new clusters are +; FAT-chained onto the end of the existing file. +; +; The DPB contains the cluster # of the last free cluster allocated +; (dpb_next_free). We start at this cluster and scan towards higher +; numbered clusters, looking for the necessary free blocks. +; +; Once again, fancy terminology gets in the way of corrct coding. When +; using next_free, start scanning AT THAT POINT and not the one following it. +; This fixes the boundary condition bug when only free = next_free = 2. +; +; If we get to the end of the disk without satisfaction: +; +; if (dpb_next_free == 2) then we've scanned the whole disk. +; return (insufficient_disk_space) +; ELSE +; dpb_next_free = 2; start scan over from the beginning. +; +; Note that there is no multitasking interlock. There is no race when +; examining the entrys in an in-core FAT block since there will be no +; context switch. When UNPACK context switches while waiting for a FAT read +; we are done with any in-core FAT blocks, so again there is no race. The +; only special concern is that V2 and V3 MSDOS left the last allocated +; cluster as "00"; marking it EOF only when the entire alloc request was +; satisfied. We can't allow another activation to think this cluster is +; free, so we give it a special temporary mark to show that it is, indeed, +; allocated. +; +; Note that when we run out of space this algorithem will scan from +; dpb_next_free to the end, then scan from cluster 2 through the end, +; redundantly scanning the later part of the disk. This only happens when +; we run out of space, so sue me. +; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; C A V E A T P A T T E R S O N ; +; ; +; The use of FATBYT and RESTFATBYT is somewhat mysterious. Here is the +; explanation: +; +; In the NUL file case (sf_firclus currently 0) ALLOCATE is called with +; entry BX = 0. What needs to be done in this case is to stuff the cluster +; number of the first cluster allocated in sf_firclus when the ALLOCATE is +; complete. THIS VALUE IS SAVED TEMPORARILY IN CLUSTER 0, HENCE THE CURRENT +; VALUE IN CLUSTER 0 MUST BE SAVED AND RESTORED. This is a side effect of +; the fact that PACK and UNPACK don't treat requests for clusters 0 and 1 as +; errors. This "stuff" is done by the call to PACK which is right before +; the +; LOOP findfre ; alloc more if needed +; instruction when the first cluster is allocated to the nul file. The +; value is recalled from cluster 0 and stored at sf_firclus at ads4: +; +; This method is obviously useless (because it is non-reentrant) for +; multitasking, and will have to be changed. Storing the required value on +; the stack is recommended. Setting sf_firclus at the PACK of cluster 0 +; (instead of actually doing the PACK) is BAD because it doesn't handle +; problems with INT 24 well. +; +; C A V E A T P A T T E R S O N ; +;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----; +; ; +; ENTRY BX = Last cluster of file (0 if null file) +; CX = No. of clusters to allocate +; ES:BP = Base of drive parameters +; [THISSFT] = Points to SFT +; +; EXIT 'C' set if insufficient space +; [FAILERR] can be tested to see the reason for failure +; CX = max. no. of clusters that could be added to file +; 'C' clear if space allocated +; BX = First cluster allocated +; FAT is fully updated +; sf_FIRCLUS field of SFT set if file was null +; +; USES ALL but SI, BP + + PROCEDURE ALLOCATE,NEAR + + DOSAssume CS,,"Allocate" + ASSUME ES:NOTHING + + Assert ISDPB,,"Allocate" + PUSH BX ; save (bx) + XOR BX,BX + invoke UNPACK + MOV [FATBYT],DI ; save correct cluster 0 value + POP BX + retc ; abort if error [INTERR?] + + PUSH CX + PUSH BX + + MOV DX,BX + Assert ISDPB,,"Allocate/Unpack" + mov bx,es:[bp.dpb_next_free] + cmp bx,2 + ja findfre + +; couldn't find enough free space beyond dpb_next_free, or dpb_next_free is +; <2 or >dpb_max_clus. Reset it and restart the scan + +ads1: + Assert ISDPB,,"Alloc/ads1" + mov es:[bp.dpb_next_free],2 + mov bx,1 ; Counter next instruction so first + ; cluster examined is 2 + +; Scanning both forwards and backwards for a free cluster +; +; (BX) = forwards scan pointer +; (CX) = clusters remaining to be allocated +; (DX) = current last cluster in file +; (TOS) = last cluster of file + +FINDFRE: + INC BX + Assert ISDPB,,"Alloc/findfre" + CMP BX,ES:[BP.dpb_max_cluster] + JBE aupk + jmp ads7 ; at end of disk +aupk: + invoke UNPACK ; check out this cluster + jc ads4 ; FAT error [INTERR?] + jnz findfre ; not free, keep on truckin + +; Have found a free cluster. Chain it to the file +; +; (BX) = found free cluster # +; (DX) = current last cluster in file + + mov es:[bp.dpb_next_free],bx ; next time start search here + xchg ax,dx ; save (dx) in ax + mov dx,1 ; mark this free guy as "1" + invoke PACK ; set special "temporary" mark + jc ads4 ; FAT error [INTERR?] + CMP ES:[BP.dpb_free_cnt],-1 ; Free count valid? + JZ NO_ALLOC ; No + DEC ES:[BP.dpb_free_cnt] ; Reduce free count by 1 +NO_ALLOC: + xchg ax,dx ; (dx) = current last cluster in file + XCHG BX,DX + MOV AX,DX + invoke PACK ; link free cluster onto file + ; CAVEAT.. On Nul file, first pass stuffs + ; cluster 0 with FIRCLUS value. + jc ads4 ; FAT error [INTERR?] + xchg BX,AX ; (BX) = last one we looked at + mov dx,bx ; (dx) = current end of file + LOOP findfre ; alloc more if needed + +; We've successfully extended the file. Clean up and exit +; +; (BX) = last cluster in file + + MOV DX,0FFFFH + invoke PACK ; mark last cluster EOF + +; Note that FAT errors jump here to clean the stack and exit. this saves us +; 2 whole bytes. Hope its worth it... +; +; 'C' set iff error +; calling (BX) and (CX) pushed on stack + +ads4: POP BX + POP CX ; Don't need this stuff since we're successful + retc + invoke UNPACK ; Get first cluster allocated for return + ; CAVEAT... In nul file case, UNPACKs cluster 0. + retc + invoke RESTFATBYT ; Restore correct cluster 0 value + retc + XCHG BX,DI ; (DI) = last cluster in file upon our entry + OR DI,DI ; clear 'C' + retnz ; we were extending an existing file + +; We were doing the first allocation for a new file. Update the SFT cluster +; info +;; Extended Attributes +; TEST [XA_condition],XA_No_SFT ;FT. don't update SFT when from ;AN000; +; JZ dofastk ;FT. GetSet_XA ;AN000; +; AND [XA_condition],not XA_No_SFT ;FT. clear the bit ;AN000; +; CLC ;FT. ;AN000; +; ret ;FT. ;AN000; +;; 11/6/86 FastSeek +dofastk: + PUSH DX + MOV DL,ES:[BP.dpb_drive] ; get drive # + + PUSH ES + LES DI,[THISSFT] + Assert ISSFT,,"Allocate/ads4" + MOV ES:[DI.sf_firclus],BX + MOV ES:[DI.sf_lstclus],BX + + TEST [FastSeekflg],Fast_yes ; fastseek installed + JZ do_norm5 ; no + TEST [FastSeekflg],FS_begin ; do fastseek + JZ do_norm5 ; no + PUSH CX + MOV CX,BX ; set up firclus # + MOV [FSeek_firclus],BX ; update firclus varible + invoke FastSeek_Open ; create this file entry + POP CX +do_norm5: + POP ES +;; 11/6/86 FastSeek + POP DX + return + + +;** we're at the end of the disk, and not satisfied. See if we've scanned ALL +; of the disk... + +ads7: cmp es:[bp.dpb_next_free],2 +if not debug + jz tmplab2 ; + jmp ads1 ; start scan from front of disk +tmplab2: +else + jz tmplab + jmp ads1 +tmplab: +endif + +; Sorry, we've gone over the whole disk, with insufficient luck. Lets give +; the space back to the free list and tell the caller how much he could have +; had. We have to make sure we remove the "special mark" we put on the last +; cluster we were able to allocate, so it doesn't become orphaned. +; +; (CX) = clusters remaining to be allocated +; (TOS) = last cluster of file (before call to ALLOCATE) +; (TOS+1) = # of clusters wanted to allocate + + + POP BX ; (BX) = last cluster of file + MOV DX,0FFFFH + invoke RELBLKS ; give back any clusters just alloced + POP AX ; No. of clusters requested + ; Don't "retc". We are setting Carry anyway, + ; Alloc failed, so proceed with return CX + ; setup. + SUB AX,CX ; AX=No. of clusters allocated + invoke RESTFATBYT ; Don't "retc". We are setting Carry anyway, + ; Alloc failed. +; fmt <>,<>,<"$p: disk full in allocate\n"> + MOV [DISK_FULL],1 ;MS. indicating disk full + STC + return + +EndProc ALLOCATE + +; SEE ALLOCATE CAVEAT +; Carry set if error (currently user FAILed to I 24) + + procedure RESTFATBYT,NEAR + DOSAssume CS,,"RestFATByt" + ASSUME ES:NOTHING + + PUSH BX + PUSH DX + PUSH DI + XOR BX,BX + MOV DX,[FATBYT] + invoke PACK + POP DI + POP DX + POP BX + return +EndProc RESTFATBYT + +Break + +; Inputs: +; BX = Cluster in file +; ES:BP = Base of drive parameters +; Function: +; Frees cluster chain starting with [BX] +; Carry set if error (currently user FAILed to I 24) +; AX,BX,DX,DI all destroyed. Other registers unchanged. + + procedure RELEASE,NEAR + DOSAssume CS,,"Release" + ASSUME ES:NOTHING + + XOR DX,DX +entry RELBLKS + DOSAssume CS,,"RelBlks" + Assert ISDPB,,"RelBlks" + +; Enter here with DX=0FFFFH to put an end-of-file mark in the first cluster +; and free the rest in the chain. + + invoke UNPACK + retc + retz + MOV AX,DI + PUSH DX + invoke PACK + POP DX + retc + OR DX,DX + JNZ NO_DEALLOC ; Was putting EOF mark + CMP ES:[BP.dpb_free_cnt],-1 ; Free count valid? + JZ NO_DEALLOC ; No + INC ES:[BP.dpb_free_cnt] ; Increase free count by 1 +NO_DEALLOC: + MOV BX,AX + dec ax ; check for "1" + retz ; is last cluster of incomplete chain + Invoke IsEOF + JB RELEASE ; Carry clear if JMP not taken +ret12: return +EndProc RELEASE + +Break + +; Inputs: +; ES:BP Points to DPB +; BX = Cluster in a file +; DS = CS +; Outputs: +; BX = Last cluster in the file +; Carry set if error (currently user FAILed to I 24) +; DI destroyed. No other registers affected. + + procedure GETEOF,NEAR + DOSAssume CS,,"GetEOF" + ASSUME ES:NOTHING + + Assert ISDPB,,"GetEof" + invoke UNPACK + retc + PUSH BX + MOV BX,DI + Invoke IsEOF + POP BX + JAE RET12 ; Carry clear if jmp + MOV BX,DI + JMP GETEOF +EndProc GETEOF + +Break + +; Inputs: +; ES:BP Points to DPB +; BX = Cluster in a file +; Functions: if BX=EOF then truncate it from Fastseek Cache +; Outputs: +; carry set: not EOF +; carry clear: EOF and do truncate + + procedure FS_TRUNC_EOF,NEAR + ASSUME ES:NOTHING,DS:NOTHING + + MOV BX,DI ; get beginning physical# ;AN000; + invoke IsEOF ; is EOF ;AN000; + JB noteof2 ; no ;AN000; + PUSH [FSeek_logclus] ; ;AN000; + PUSH [FSeek_logsave] ; logclus=logsave ;AN000; + POP [FSeek_logclus] ; delete EOF ;AN000; + invoke FastSeek_Truncate ; ;AN000; + POP [FSeek_logclus] ; redo the look up ;AN000; + CLC ;AN000; +noteof2: ;AN000; + return ;AN000; +EndProc FS_TRUNC_EOF ;AN000; + +CODE ENDS + END + \ No newline at end of file -- cgit v1.2.3