📄 gshare2.asm
字号:
;---------------------------------------
; (SI) points to a free block.
; We coalesce it by changing the size.
;---------------------------------------
cmp si,di
jz gcm15 ; do NOT coalesce a block with itself
add [di].mft_len,cx ; coalesce
gcm15:
add si,cx ; skip the empty one
JMP SHORT gcm1
;---------------------------------------
; (SI) points to a non-free,
; non-last block.
; (DI) points to the beginning of a
; free block.
;
; We move the non-free block down over
; the free block
;---------------------------------------
gcm2: cmp si,di
jnz gcm3 ; have to copy
;---------------------------------------
; SI = DI => we are at a boundary
; between allocated blocks.
; We do no copying.
;---------------------------------------
add si,cx
mov di,si ; no emptys yet... no need to copy
JMP SHORT gcm1
;---------------------------------------
; CX is length of allocated block.
; - Move it
;---------------------------------------
gcm3: mov bx,di ; (DS:BX) = new home for this record
mov ax,ds
mov es,ax
rep movsb
;---------------------------------------
; We've moved the record, now fix up
; the pointers in the SFT chain
;
; (si) = address of next record
; (di) = address of next free byte
; (bx) = address of record in its new home
; (TOS) = needed space
;---------------------------------------
push di
push ds
lds di,[bx].mft_sptr ; (ds:di) = chain of SFT
gcm4: or di,di
jz gcm5 ; no more SFT
mov [di].sf_mft,bx ; install new MFT position
lds di,[di].sf_chain ; link to next
JMP gcm4 ; fix next SFT
gcm5: pop ds
pop di
;---------------------------------------
; (DI) points to beginning of
; new free record (moved)
; (SI) points to next record
;
; Make sure that the (DI) record
; has correct format
;---------------------------------------
mov [di].mft_flag,MFLG_FRE ; indicate free record
mov [di].mft_len,si ; calculate correct length
sub [di].mft_len,di
;---------------------------------------
; MFT now has correct record structure.
; Go find more free blocks
;---------------------------------------
JMP SHORT gcm1
;---------------------------------------
; We have scanned the entire table,
; compacting all empty records together.
;
; (di) = first free byte in table
; (si) = address of END record
; (TOS) = size needed
;
; Be extra careful!!!
;---------------------------------------
gcm10: mov ax,si
sub ax,di ; (ax) = free space
pop bx ; (bx) = space wanted
sub ax,bx
ret
EndProc GCM
BREAK <RMN - Remove MFT Name record>
;******************* START OF SPECIFICATIONS ***********************************
;
; RMN - Remove MFT Name record
;
; RMN removes a name record from the MFT list. The record is marked
; free and all free space is coalesced.
;
; ENTRY (DS:BX) = FBA MFT name record
; EXIT to INTERR if lock and SFT chains are not empty
; USES ALL
;
;******************* END OF SPECIFICATIONS *************************************
Procedure RMN,NEAR
mov si,bx
mov ax,word ptr [si].mft_sptr
or ax,word ptr [si].mft_lptr
jnz RMNIER1 ; not clean - internal error
mov si,bx ; (ds:si) = fwa name record
mov [si].mft_flag,MFLG_FRE ; mark free
call mrg ; coalesce all free space
ret
RMNIER1:push ax
off ax,RmnErr1
RMNIER: call INTERR ; internal error
EndProc RMN
Break <MRG - merge all free space>
;******************* START OF SPECIFICATIONS ***********************************
;
; MRG - merge all free space
;
; MRG - walk through mft merging adjacent free space.
;
; Inputs: ds = CS
; Outputs: none (all free space coalesced)
; Registers Revised: none
;
;******************* END OF SPECIFICATIONS *************************************
Procedure MRG,near
assume ds:nothing,es:nothing
push si
push bx
off si,mft ; start at beginning
mrg1: mov bx,[si].mft_len ; get length
cmp [si].mft_flag,MFLG_FRE ; is record free?
jl mrg9 ; done.
jz mrg2 ; yes, try to merge with next
mrg15: add si,bx ; advance to next
jmp mrg1
;---------------------------------------
; (si) points to free record.
; - See if next is free
;---------------------------------------
mrg2: cmp [bx][si].mft_flag,MFLG_FRE
jnz mrg15 ; not free, go scan again
mov bx,[bx][si].mft_len ; get length of next guy
add [si].mft_len,bx ; increase our length
jmp mrg1 ; and check again
mrg9: pop bx
pop si
ret
EndProc MRG
BREAK <RSC - Remove SFT from SFT chain>
;******************* START OF SPECIFICATIONS ***********************************
;
; RSC - Remove SFT from SFT chain
;
; RSC removes a given SFT from its chain. The caller must insure that
; any locks have been cleared and that the SFT is indeed free. The
; sf_mft field is zeroed to indicate that this SFT is no longer chained.
;
; NOTE - RSC does NOT remove the name record if this was the last SFT on
; it. The caller must check for this and remove it, if
; necessary.
;
; ENTRY (ES:DI) = SFT address
; EXIT (DS:BX) = FBA name record for this SFT
; 'Z' set if this is the last SFT
; USES ALL
;
;******************* END OF SPECIFICATIONS *************************************
Procedure RSC,NEAR
push cs
pop ds
mov ax,es ; easy spot for compare
mov bx,es:[di].sf_mft
lea si,[bx].mft_sptr-sf_chain ; ds:[si].sf_chain point to prev link
rsc1: or si,si
jz rscier
cmp word ptr [si].sf_chain,di
jnz rsc15
cmp word ptr [si].sf_chain+2,ax
jz rsc2
rsc15: lds si,[si].sf_chain
jmp rsc1
;---------------------------------------
; (es:di) is sft
; (ds:si) is prev sft link
;---------------------------------------
rsc2: mov ax,word ptr es:[di].sf_chain
mov word ptr ds:[si].sf_chain,ax
mov ax,word ptr es:[di].sf_chain+2
mov word ptr ds:[si].sf_chain+2,ax
push cs
pop ds
xor bx,bx
xchg bx,es:[di].sf_MFT ; (DS:bx) = MFT address
; and 0 MFT pointer (show free)
cmp word ptr [bx].mft_sptr,0 ; set z flag if no more sft
ret
rscier: push ax
off ax,RscErr
call interr
EndProc RSC
BREAK <SLE - Scan for Lock Entry>
;******************* START OF SPECIFICATIONS ***********************************
;
; SLE - Scan for Lock Entry
;
; SLE scans a lock list looking for a lock range that overlaps the
; caller-supplied range. SLE indicates:
;
; no overlap
; partial overlay
; 1-to-1 match
;
; ENTRY (AX:BX) = FBA of area
; (CX:DX) = LBA of area
; (DS:SI) = address of name record
; (DI) = 0 to ignore locks by User_ID Proc_ID ThisSFT
; = 1 to consider all locks
; EXIT 'C' clear if no overlap
; AX,BX,CX,DX preserved
; 'C' set if overlap
; (di) = address of pointer to found record
; (i.e., DS:((di)) = address of lock record)
; 'Z' set if 1-to-1 match
; USES ALL but (ds), (es) (also see EXIT)
;
;******************* END OF SPECIFICATIONS *************************************
Procedure SLE,NEAR
push es
and di,di
pushf ; Z set to ignore own locks
lea di,[si].mft_lptr ; (ds:di) = addr of ptr to lock record
mov si,[di] ; (ds:si) = address of 1st lock record
;---------------------------------------
; check out next lock
;
; (ds:si) = address of next lock record
; (ds:di) = address of pointer to next
; lock record
; (TOS) = flags (Z set to ignore
; own locks)
; (TOS+1) = Saved ES
;---------------------------------------
sle1: and si,si
jz sle9 ; list exhaused, ergo no overlap
popf ;
pushf
jnz sle2 ; am to check all locks
;---------------------------------------
; am to ignore own locks...
; check the user and proc IDs on this one
;---------------------------------------
;dcl - this code used to compare the process id in the sft pointed to by the
; lock. now we compare the lock process id to the current process id. this
; allows a child process to lock an area and then do i/o with it. before,
; the child could lock it, but then could not access it
mov bp,[si].rlr_pid ;dcl
cmp bp,Proc_id ;dcl
jnz sce1$5 ;dcl
les si,[si].rlr_sptr ; (si) = sft address ;dcl
mov bp,es:[si].sf_UID ;dcl
cmp bp,User_ID ;dcl
jnz sce1$5 ; doesn't belong to user ;dcl
mov bp,es ;dcl
cmp bp,WORD PTR ThisSFT+2
jnz sce1$5
cmp si,WORD PTR ThisSFT
sce1$5: mov si,[di] ; (ds:si) = address of next lock record
jz sle3 ; owned by user - ignore
sle2: mov bp,dx
sub bp,[si].rlr_fba ; compare proposed last to first of record
mov bp,cx
sbb bp,[si].rlr_fba+2
jc sle3 ; proposed is above current
mov bp,[si].rlr_lba
sub bp,bx ; compare proposed first to last of record
mov bp,[si].rlr_lba+2
sbb bp,ax
jnc sle5 ; we have a hit
;---------------------------------------
; This entry is harmless...
; chain to the next one
;---------------------------------------
ERRNZ rlr_next
sle3: mov di,si ; save addr of pointer to next
mov si,[di]
JMP SHORT sle1
;---------------------------------------
; We have an overlap.
; - See if its an exact match
;
; (ds:di) = address of pointer
; (offset only) to the lock record
; (ds:si) = address of lock record
; (TOS) = flags ('Z' set if to ignore
; own locks)
; (TOS+1) = saved (es)
;---------------------------------------
sle5: xor ax,[si].rlr_fba+2 ; require a 4-word match
xor bx,[si].rlr_fba
xor cx,[si].rlr_lba+2
xor dx,[si].rlr_lba
or ax,bx
or ax,cx
or ax,dx ; 'Z' set if exact match
stc ; flag an overlap
mov ax,error_lock_violation
sle9: pop bp ; discard flags (pushf)
pop es ; restore (es)
;---------------------------------------
; (ds:si) = address of lock record
; for Chk_Block
;---------------------------------------
ret
EndProc SLE
BREAK <OFL - obtain free lock-record>
;******************* START OF SPECIFICATIONS ***********************************
;
; OFL - obtain free lock-record
;
; OFL returns a free lock-record, if one can be had.
;
; ENTRY (DS) = MFT Segment
; EXIT 'C' clear if OK
; (DI) = FBA lock record
; 'C' set if no space
; (ax) = error code
; USES DI, FLAGS
;
;******************* END OF SPECIFICATIONS *************************************
Procedure OFL,NEAR
mov di,Frelock
and di,di
; $if nz ; if something there
JZ $$IF1
push [di].rlr_next
pop Frelock ; chain off of the list
; exit with 'C' clear
; $else ; none on free list
JMP SHORT $$EN1
$$IF1:
mov ax,error_sharing_buffer_exceeded ; None on free list, give up until
stc ; garbage collector is ready
; $endif
$$EN1:
ret
EndProc OFL
Break <CPS - close process SFT>
;******************* START OF SPECIFICATIONS ***********************************
;
; CPS - close process SFT.
;
; During maintenance, it is necessary to close a
; file given ONLY the SFT. This necessitates walking all PDB's JFN
; tables looking for the SFN. The difficult part is in generating the
; SFN from the SFT. This is done by enumerating SFT's and comparing for
; the correct SFT. Finding all PDBs is easy: walk arena and check
; owner fields
;
; Inputs: ThisSFT points to SFT of interest
; Outputs: Handle is closed on user
; Registers Revised: none
;
;******************* END OF SPECIFICATIONS *************************************
Procedure CPS,NEAR
ASSUME DS:NOTHING,ES:NOTHING
SaveReg <DS,SI,ES,DI,AX,BX,CX>
lds si,ThisSFT
xor bx,bx
cps01:
CallInstall SFFromSFN,multDOS,22,bx,bx
jc cps31 ; no more SFN's. Must be FCB.
CallInstall PointComp,multDOS,20
jz cps02 ; found matching SFN, go scan.
inc bx ; did not match, go back for more
jmp cps01
;---------------------------------------
; BL is the sfn we want to find. Walk
; the memory arena enumerating all PDB's
; and zap the handle tables for the
; specified sfn.
;---------------------------------------
cps02:
mov al,bl
mov ds,Arena_Head ; get first arena pointer
;---------------------------------------
; DS:[0] is the arena header.
; AL is sfn to be closed
;---------------------------------------
cps1:
mov cx,ds:[arena_owner]
mov bx,ds
inc bx ; is the owner the same as the current
cmp cx,bx ; block?
jnz cps2 ; no, go skip some more...
;---------------------------------------
; CX:0 is the correct pointer to a PDB.
;---------------------------------------
push ds
mov ds,cx
;---------------------------------------
; Given a PDB at DS:0, scan his handle
; table and then loop through the next
; PDB link.
;---------------------------------------
cps15:
call CPJ ; free for this PDB
lds cx,DS:[PDB_Next_PDB] ; advance to next
cmp cx,-1
jnz cps15 ; there is another link to process
pop ds
;---------------------------------------
; We have processed the current
; allocation block pointed to by DS.
; DS:[0] is the allocation block
;---------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -