📄 gshare.asm
字号:
EndProc ASC
BREAK <BCS - Bulk Close of SFTs>
;******************* START OF SPECIFICATIONS ***********************************
;
; BCS - Bulk Close of SFTs
;
; BCS scans the MFT structures looking for SFTs that match a UID (and
; perhaps a PID). The SFTs are closed. The MFT name record is removed
; if all its SFTs are closed.
;
; BCS is called with a PID and a PID MASK. The SFT is closed if its UID
; matches the supplied UID AND (PID_ & PIDMASK) == PID_supplied
;
; We walk the MFT structure closing all relevant SFT's. There is no
; need for special handling of 70 handles or FCBs.
;
; Note that we call DOS_close to close the SFT; DOS_close in turn calls
; mftclose which may remove the SFT and even the MFT. This means that
; the MFT may vanish as we are working on it. Whenever we call
; DOS_close we'll know the next SFT and, if there is no next SFT we'll
; know the next MFT. (If the MFT were released a pointer to the carcass
; is not of any help. An MFT carcass cannot help find the next MFT
; record)
;
; ENTRY (AX) = UID to match
; (BX) = PID mask
; (DX) = PID value
; EXIT 'C' clear
; USES ALL
;
;******************* END OF SPECIFICATIONS *************************************
ASSUME SS:DOSDATA
Procedure BCS,NEAR
push cs
pop ds
Off SI,mft ; start at beginning of buffer
; scan forward to the nearest name record (we may be at it now)
;
; (DS:SI) = record pointer
bcs1: cmp [si].mft_flag,MFLG_FRE
jl bcs16 ; at end of names, all done
jg bcs2 ; have a name record
bcs1$5: add si,[si].mft_len ; skip record and loop
jmp bcs1
bcs16: jmp short bcs9
bcs2: les di,[si].mft_sptr ; got name record - get first SFT
; run down SFT chain
;
; (es:di) = FBA next SFT
; (ds:si) = FBA name record
; (ax) = UID to match
; (bx) = PID mask
; (dx) = PID value
bcs3: or di,di
jz bcs1$5 ; at end of SFT chain
cmp ax,es:[di].sf_UID
jnz bcs4 ; not a match
mov cx,es:[di].sf_PID
and cx,bx ; apply mask
cmp cx,dx
jz bcs51 ; got a match
bcs4:
les di,es:[di].sf_chain
JMP bcs3 ; chain to next SFT
; We have an SFT to close
;
; (es:di) = FBA SFT to be closed
;
; (ds:si) = FBA name record
; (ax) = UID to match
; (bx) = PID mask
; (dx) = PID value
bcs51: mov es:[di].sf_ref_count,1
push ax
push bx
push dx ; save ID values (ax,bx,dx) and mask
push ds
push si ; save name record address (ds:si)
mov si,word ptr es:[di].sf_chain
or si,si
jnz bcs7 ; isnt last sft, MFT will remain
; yup, this is the last sft for this MFT, the MFT may evaporate. we have
; to find the next one NOW, and remember it
pop si ; undo saved name record address
pop ds
bcs6: add si,[si].mft_len ; go to next guy
cmp [si].mft_flag,MFLG_FRE
jz bcs6 ; must be a non-free guy
push ds
push si ; resave our new next MFT
sub si,si ; no next sft
; Allright, we're ready to call the DOS.
;
; (es:di) = FBA sft to be closed
; ((sp)) = long address of current or next MFT
; ((sp)+4) = PID value
; ((sp)+6) = PID mask
; ((sp)+8) = UID value
bcs7: mov WORD PTR ThisSFT,di
mov WORD PTR ThisSFT+2,es
mov es,word ptr es:[di].sf_chain+2
SaveReg <es,si>
call CPS ; clear JFN
Context DS
CallInstall DOS_Close,multDos,1
ASSUME DS:NOTHING
RestoreReg <di,es> ; (es:DI) = offset of next sft
pop si
pop ds ; (DS:SI) = fwa of current or next MFT
pop dx
pop bx
pop ax
or di,di
jnz bcs85 ; have more sft's
JMP bcs1 ; look at this new MFT
bcs85: jmp bcs3
; All Done
bcs9: clc
ret
EndProc BCS
BREAK <CSL - Clear SFT Locks>
;******************* START OF SPECIFICATIONS ***********************************
;
; CSL - Clear SFT Locks
;
; CSL clears any locks associated with this SFT.
;
; ENTRY (ES:DI) = SFT address
; EXIT (ES:DI) unchanged
; USES All but ES,DI
;
;******************* END OF SPECIFICATIONS *************************************
Procedure CSL,NEAR
mov si,es:[di].sf_MFT
push cs
pop ds
lea bx,[si].mft_lptr ; (DS:BX) = addr of lock ptr
mov si,[bx] ; (DS:SI) = fba first lock record
; scan the locks looking for belongers.
;
; (es:di) = SFT address
; (ds:si) = this lock address
; (ds:bx) = address of link (offset value) to this lock (prev lock)
csl1: or si,si
jz csl3 ; done with lock list
cmp di,word ptr [si].rlr_sptr
jnz csl2 ; not my lock
mov ax,es
cmp ax,word ptr [si].rlr_sptr+2
jnz csl2 ; not my lock
;
; Make sure that the lock REALLY belongs to the correct process
;
cmp user_in_ax, (ServerCall shl 8) + 4 ; only check if ; @@01
jnz csl15 ; process specific; @@01
mov ax,Proc_ID
cmp ax,[si].rlr_pid ; is process ID of lock = this PID?
jnz csl2 ; nope, skip this lock
; got a lock to remove
csl15:
mov dx,[si].rlr_next
mov [bx],dx ; link him out
mov ax,Frelock
mov [si].rlr_next,ax
mov Frelock,si
mov si,dx ; (DS:SI) = next lock address
JMP SHORT csl1
ERRNZ rlr_next ; lock is not ours... follow chain
csl2: mov bx,si
mov si,[si].rlr_next
JMP SHORT csl1
; All done
csl3: ret
EndProc CSL
ASSUME DS:NOTHING
BREAK <CUC - check usage conflicts>
;******************* START OF SPECIFICATIONS ***********************************
;
; Use conflict table
;
; Algorithm:
;
; if ((newmode == COMPAT) or (oldmode == COMPAT))
; and (user ID's match)
; then accept
; else
; for new and old mode, compute index of (SH*3)+ACC
; shift right table[new_index] by old_index+2;
; 'C' set if FAIL
;
; The bit in the old_index position indicates the success or failure. 0
; => allow access, 1 => fail access
;
;******************* END OF SPECIFICATIONS *************************************
PUBLIC CUCA
CUCA: DW 0ffffh ; Compat Read
DW 0ffffh ; Compat Write
DW 0ffffh ; Compat Read/Write
DW 0ffffh ; Deny R/W Read
DW 0ffffh ; Deny R/W Write
DW 0ffffh ; Deny R/W Read/Write
DW 0df7fh ; Deny W Read
DW 0dbffh ; Deny W Write
DW 0dfffh ; Deny W Read/Write
DW 0beffh ; Deny R Read
DW 0b7ffh ; Deny R Write
DW 0bfffh ; Deny R Read/Write
DW 01c7fh ; Deny None Read
DW 003ffh ; Deny None Write
DW 01fffh ; Deny None Read/Write
; 4443 3322 2111 000
; Deny/Compat / DDDD DDDD DDDD CCCx
; DenyRead / R RR RRR
; DenyWrite 1st Access =< WW WWWW
; AccessRead \ R RR RR RR R R R
; AccessWrite \ WW W W WW WW WW
; x 1111 1111 1111 1111
; C R 00 1111 1111 1111 1111 ffff
; C W 01 1111 1111 1111 1111 ffff
; C RW 02 1111 1111 1111 1111 ffff
; DRWR 10 1111 1111 1111 1111 ffff
; DRW W 11 1111 1111 1111 1111 ffff
; DRWRW 12 1111 1111 1111 1111 ffff
; D WR 20 1101 1111 0111 1111 df7f
; D W W 21 1101 1011 1111 1111 dbff
; D WRW 22 1101 1111 1111 1111 dfff
; DR R 30 1011 1110 1111 1111 beff
; DR W 31 1011 0111 1111 1111 b7ff
; DR RW 32 1011 1111 1111 1111 bfff
; D R 40 0001 1100 0111 1111 1c7f
; D W 41 0000 0011 1111 1111 03ff
; D RW 42 0001 1111 1111 1111 1fff
; In order to allow the greatest number of accesses, compatability read mode
; is treated as deny-write read. The other compatability modes are treated
; as deny-both.
;******************* START OF SPECIFICATIONS ***********************************
;
; CUC - check usage conflicts
;
; CUC is called to see if a would-be open would generate a share
; conflict with an existing open. See CUCA for the algorithm and table
; format.
;
; ENTRY (BX) = FBA MFT name record
; (DS:SI) = SFT address
; EXIT 'C' clear if OK
; 'C' set if conflict
; (ax) = error code
; USES ALL but arguments (BX, DS:SI)
;
;******************* END OF SPECIFICATIONS *************************************
Procedure CUC,NEAR
push ds
pop es
mov di,si ; (es:di) = FBA SFT record
call gom ; get open mode
mov ch,al
and ch,sharing_mask ; (ch) = new guy share
jz cuc0 ; new guy is compatability mode
mov ch,sharing_mask
cuc0: call csi ; compute share index
add ax,ax ; *2 for word index
xchg ax,si ; (si) = share table index
push cs
pop ds ; (ds:bx) = FBA MFT record
mov dx,WORD PTR CUCA[si] ; (dx) = share mask
lds si,[bx].mft_sptr ; (ds:si) = first sft guy
; ready to do access compares.
;
; (ds:si) = address of next sft
; (es:di) = address of new sft
; (dx) = share word from CUCA
; (cs:bx) = MFT offset
; (ch) = 0 if new SFT is compatibilty mode, else sharing_mask
cuc1: or si,si
jz cuc9 ; at end of chain, no problems
call gom ; if not FCB, then mode in al is good
mov ah,al
and ah,sharing_mask ; (ah) = sharing mode
or ah,ch ; (ah) = 0 iff new and old is SH_COMP
jnz cuc2 ; neither is SH_COMP
; Both the old and the new guy are SH_COMP mode. If the UIDs match,
; step onward. If they don't match do normal share check.
mov bp,es:[di].sf_UID
cmp bp,[si].sf_UID
jz cuc20 ; equal => next sft to check
cuc2: call csi ; compute the share index
inc ax
inc ax
xchg al,cl ; (cl) = shift count
mov ax,dx
sar ax,cl ; select the bit
jc cuc8 ; a conflict!
cuc20:
lds si,[si].sf_chain
JMP cuc1 ; chain to next SFT and try again
; Have a share conflict
cuc8: mov ax,error_sharing_violation ; assume share conflict
stc
; done with compare. Restore regs and return
;
; 'C' set as appropriate
; (es:di) = new SFT address
; (ax) set as appropriate
; (bx) = MFT offset
cuc9: push es
pop ds
mov si,di
ret
EndProc CUC
BREAK <csi - compute share index>
;******************* START OF SPECIFICATIONS ***********************************
;
; csi - compute share index
;
;
; If the mode byte has a leading 7 then it is interpreted as a 0
; csi turns a mode byte into an index from 0 to 14:
;
; (share index)*3 + (access index)
;
; ENTRY (al) = mode byte
; EXIT (ax) = index
; USES AX, CL
;
;******************* END OF SPECIFICATIONS *************************************
Procedure CSI,NEAR
mov ah,al
and ah,access_mask ; (ah) = access bits
and al,sharing_mask ; (al) = share bites
ERRNZ sharing_mask-0F0h
cmp al,sharing_net_FCB
jnz csi1
xor al,al
csi1:
shr al,1
shr al,1
shr al,1
mov cl,al ; (cl) = SHVAL*2
shr al,1
add al,cl ; (al) = SHVAL*3
add al,ah ; (al) = SH*3 + ACC
sub ah,ah
ret
EndProc CSI
Break <GOM - get open mode>
;******************* START OF SPECIFICATIONS ***********************************
;
; GOM - get open mode
;
; Find the correct open mode given the encoded sf_mode. Note that files
; marked READ-ONLY and are opened in compatability read-only are treated as
; deny-write read-only. FCB opens are sharing_compat open_for_both and
; net FCB opens are sharing_compat
;
; Entry: (DS:SI) points to SFT
; Exit: (AL) has correct mode
; Uses: (AX)
;******************* END OF SPECIFICATIONS *************************************
Procedure GOM,NEAR
mov ax,[si].sf_mode
TEST AX,sf_IsFCB
jz gom1 ; if not FCB, then mode in al is good
mov al,sharing_compat+open_for_both
gom1:
mov ah,al
and ah,sharing_mask
cmp ah,sharing_net_FCB ; is sharing from net FCB?
jnz gom2 ; no, got good mode
and al,access_mask ; yes, convert to compat mode sharing
or al,sharing_compat
;
; The sharing mode and access mode in AL is now correct for the file. See if
; mode is compatability. If so and file is read-only, convert access mode to
; deny-write read.
;
gom2:
mov ah,al
and ah,sharing_mask
retnz ; not compatability, return.
test [si].sf_attr,attr_read_only
retz ; not read-only
mov al,sharing_deny_write + open_for_read
ret
EndProc GOM
SHARE ENDS
END
ELSE
CODE ENDS
ENDIF
END ; This can't be inside the if
; mode is compatability. If so and file is read-only, convert access mode to
; deny-write read.
;
gom2:
mov ah,al
and ah,sharing_mask
retnz ; not compatability, return.
test [si].sf_attr,attr_read_only
retz ; not read-only
mov al,sharing_deny_write + open_for_read
ret
EndProc GOM
SHARE ENDS
END
ELSE
CODE ENDS
ENDIF
END ; This can't be inside the if
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -