1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
|
; SCCSID = @(#)util.asm 1.1 85/04/10
TITLE UTIL - Handle utilities
NAME UTIL
;
; Handle related utilities for MSDOS 2.X.
;
; pJFNFromHandle written
; SFFromHandle written
; SFFromSFN written
; JFNFree written
; SFNFree written
;
; Modification history:
;
; Created: MZ 1 April 1983
;
.xlist
;
; get the appropriate segment definitions
;
include dosseg.asm
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.xcref
INCLUDE DOSSYM.INC
INCLUDE DEVSYM.INC
.cref
.list
.sall
I_need CurrentPDB,WORD ; current process data block location
I_need SFT_Addr,DWORD ; pointer to beginning of table
I_Need PROC_ID,WORD ; current process ID
I_Need USER_ID,WORD ; current user ID
if debug
I_need BugLev,WORD
I_need BugTyp,WORD
include bugtyp.asm
endif
BREAK <pJFNFromHandle - return pointer to JFN table entry>
;
; pJFNFromHandle - Given a handle, return the pointer to the JFN location
; in the user's data space
; Inputs: BX - Handle
; Outputs: Carry Set
; AX has error code
; Carry reset
; ES:DI point to the handle spot
; Registers modified:
; If no error, ES:DI, else AX,ES
; NOTE:
; This routine is called from $CREATE_PROCESS_DATA_BLOCK which is called
; at DOSINIT time with SS NOT DOSGROUP
procedure pJFNFromHandle,NEAR
ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
MOV ES,[CurrentPDB] ; get user process data block
CMP BX,ES:[PDB_JFN_Length] ; is handle greater than allocated
JB JFNAdd ; no, get offset
fmt TypAccess,LevSFN,<"$p: Illegal JFN %x\n">,<BX>
MOV AL,error_invalid_handle ; appropriate error
ReturnCarry:
STC ; signal error
return ; go back
JFNAdd: LES DI,ES:[PDB_JFN_Pointer] ; get pointer to beginning of table
ADD DI,BX ; add in offset
ReturnNoCarry:
CLC ; no holes
return ; bye!
EndProc pJFNFromHandle
BREAK <SFFromHandle - return pointer (or error) to SF entry from handle>
;
; SFFromHandle - Given a handle, get JFN and then index into SF table
;
; Input: BX has handle
; Output: Carry Set
; AX has error code
; Carry Reset
; ES:DI has pointer to SF entry
; Registers modified: If error, AX,ES, else ES:DI
; NOTE:
; This routine is called from $CREATE_PROCESS_DATA_BLOCK which is called
; at DOSINIT time with SS NOT DOSGROUP
procedure SFFromHandle,NEAR
ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
CALL pJFNFromHandle ; get jfn pointer
retc ; return if error
CMP BYTE PTR ES:[DI],-1 ; unused handle
JNZ GetSF ; nope, suck out SF
fmt TypAccess,LevSFN,<"$p: Illegal SFN $x:$x\n">,<ES,DI>
MOV AL,error_invalid_handle ; appropriate error
jump ReturnCarry ; signal it
GetSF:
SaveReg <BX> ; save handle
MOV BL,BYTE PTR ES:[DI] ; get SFN
XOR BH,BH ; ignore upper half
CALL SFFromSFN ; get real sf spot
RestoreReg <BX> ; restore
return ; say goodbye
EndProc SFFromHandle
BREAK <SFFromSFN - index into SF table for SFN>
;
; SFFromSFN - index into SF tables for SFN.
;
; Input: BX has SF index
; Output: ES:DI points to SF entry
; Registers modified: ES:DI, BX only
; NOTE:
; This routine is called from SFFromHandle which is called
; at DOSINIT time with SS NOT DOSGROUP
procedure SFFromSFN,NEAR
ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
LES DI,[SFT_Addr] ; get pointer to beginning of table
ScanLoop:
CMP BX,ES:[DI].SFCount ; is handle in this table?
JB GetOffset ; yes, go grab it
SUB BX,ES:[DI].SFCount
LES DI,ES:[DI].SFLink ; get next table segment
CMP DI,-1 ; end of tables?
JNZ ScanLoop ; no, try again
STC ; error...
JMP SHORT Restore ; go restore
GetOffset:
SaveReg <AX> ; save AX
MOV AX,SIZE SF_Entry ; put it in a nice place
MUL BL ; times size
ADD DI,AX ; offset by size
RestoreReg <AX> ; get world back
ADD DI,SFTable ; offset into structure
CLC ; no holes
Restore:
return ; bye!
EndProc SFFromSFN
BREAK <JFNFree - return a jfn pointer if one is free>
;
; JFNFree - scan through the JFN table and return a pointer to a free slot
;
; Input: None.
; Output: Carry Set
; AX has error code, BX,ES,DI garbage
; Carry Reset
; BX has new handle, ES:DI is pointer to JFN slot
; Registers modified: As above only.
procedure JFNFree,NEAR
ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGROUP
XOR BX,BX ; try starting low
JFNScan:
CALL pJFNFromHandle ; get the appropriate handle
JC JFNNone ; no more handles
CMP BYTE PTR ES:[DI],-1 ; free?
JZ JFNFound ; yes, carry is clear
INC BX ; no, next handle
JMP JFNScan ; and try again
JFNNone:
MOV AL,error_too_many_open_files
JFNFound:
return ; bye
EndProc JFNFree
BREAK <SFNFree - find a free SFN>
;
; SFNFree - scan through the sf table looking for free entries
; Inputs: none
; Outputs: Carry Set - AX has error code, BX destroyed
; Carry Clear - BX has SFN
; ES:DI - pointer to SFT
; SFT_ref_count is set to 1
; Registers modified: none
Procedure SFNFree,NEAR
ASSUME CS:DOSGROUP,DS:NOTHING,ES:NOTHING,SS:DOSGROUP
XOR BX,BX ; start at beginning
SFNFreeLoop:
SaveReg <BX> ; Next call zaps BX
CALL SFFromSFN ; get the potential handle
RestoreReg <BX>
JNC SFNCheck ; no carry, check to see if its free
MOV AL,error_too_many_open_files ; appropriate error
JMP SFNDone
SFNCheck:
CMP ES:[DI.sf_Ref_Count],0 ; free?
IF NOT DEBUG
JZ SFNGot ; yep, got return him
ELSE
JNZ NoGot
JMP SFNGot
NoGot:
ENDIF
CMP ES:[DI.sf_ref_count],sf_busy
JNZ SFNNext ; not marked busy...
fmt TypAccess,LevSFN,<"$p: SFT $x:$x($x)is busy, owner $x:$x\n">,<ES,DI,BX,ES:[DI].sf_UID,ES:[DI].sf_pid>
SaveReg <BX>
MOV BX,User_ID
CMP ES:[DI.sf_UID],BX
JNZ SFNNextP
MOV BX,Proc_ID
CMP ES:[DI.sf_PID],BX
JZ SFNGotP
SFNNextP:
fmt TypAccess,LevSFN,<"$p: SFT unusable\n">
RestoreReg <BX>
SFNNext:
INC BX ; no, try next sf number
JMP SFNFreeLoop ; and go until it fails
SFNGot:
SaveReg <BX>
SFNGotP:
CLC ; no error
fmt TypAccess,LevSFN,<"$p: SFT $x:$x($x) marked busy\n">,<ES,DI,BX>
MOV ES:[DI.sf_ref_count],sf_busy ; make sure that this is allocated
MOV BX,User_ID
MOV ES:[DI.sf_UID],BX
MOV BX,Proc_ID
MOV ES:[DI.sf_PID],BX
RestoreReg <BX>
SFNDone:
return ; bye
EndProc SFNFree
CODE ENDS
END
|