summaryrefslogtreecommitdiff
path: root/v4.0/src/CMD/SHARE/GSHARE.ASM
diff options
context:
space:
mode:
Diffstat (limited to 'v4.0/src/CMD/SHARE/GSHARE.ASM')
-rw-r--r--v4.0/src/CMD/SHARE/GSHARE.ASM2405
1 files changed, 2405 insertions, 0 deletions
diff --git a/v4.0/src/CMD/SHARE/GSHARE.ASM b/v4.0/src/CMD/SHARE/GSHARE.ASM
new file mode 100644
index 0000000..de9b1b3
--- /dev/null
+++ b/v4.0/src/CMD/SHARE/GSHARE.ASM
@@ -0,0 +1,2405 @@
1 Title Share_1 - IBM CONFIDENTIAL
2; $SALUT (0,36,41,44)
3 include SHAREHDR.INC
4;
5; Label: "The DOS SHARE Utility"
6; "Version 4.00 (C) Copyright 1988 Microsoft"
7; "Licenced Material - Program Property of Microsoft"
8;
9;******************* END OF SPECIFICATIONS *************************************
10
11extrn fnm:near, rsc:near, rmn:near, cps:near, ofl:near, sle:near, interr:near
12
13 NAME Sharer
14
15 .xlist
16 .xcref
17 INCLUDE DOSSYM.INC
18 include dpl.asm
19 .cref
20 .list
21
22AsmVars <IBM, Installed>
23
24Installed = TRUE ; for installed version
25
26OFF Macro reg,val
27 IF installed
28 mov reg,OFFSET val
29 ELSE
30 mov si,OFFSET DOSGROUP:val
31 ENDIF
32 ENDM
33
34ERRNZ Macro x
35 IF x NE 0
36 %out ERRNZ failed
37 ENDIF
38 ENDM
39; if we are installed, then define the base code segment of the sharer first
40
41 IF Installed
42Share SEGMENT PARA PUBLIC 'SHARE'
43Share ENDS
44; include the rest of the segment definitions for normal msdos
45; We CANNOT include dosseg because start is not declared para in that file
46
47; $SALUT (4,9,17,36)
48
49START SEGMENT PARA PUBLIC 'START'
50START ENDS
51
52CONSTANTS SEGMENT WORD PUBLIC 'CONST'
53CONSTANTS ENDS
54
55DATA SEGMENT WORD PUBLIC 'DATA'
56DATA ENDS
57
58TABLE SEGMENT BYTE PUBLIC 'TABLE'
59TABLE ENDS
60
61CODE SEGMENT BYTE PUBLIC 'CODE'
62CODE ENDS
63
64LAST SEGMENT PARA PUBLIC 'LAST'
65LAST ENDS
66
67DOSGROUP GROUP START,CONSTANTS,DATA,TABLE,CODE,LAST
68 ELSE
69 include dosseg.asm
70 ENDIF
71
72DATA SEGMENT WORD PUBLIC 'DATA'
73 Extrn ThisSFT:DWORD ; pointer to SFT entry
74 Extrn User_ID:WORD
75 Extrn Proc_ID:WORD
76 Extrn WFP_START:WORD
77 Extrn BytPos:DWORD
78 extrn OpenBuf:BYTE
79 extrn user_in_ax:WORD
80 IF debug
81 Extrn BugLev:WORD
82 Extrn BugTyp:WORD
83 include bugtyp.asm
84 ENDIF
85DATA ENDS
86
87; if we are not installed, then the code here is just part of the normal
88; MSDOS code segment otherwise, define our own code segment
89
90 .sall
91 IF NOT INSTALLED
92CODE SEGMENT BYTE PUBLIC 'CODE'
93 ASSUME SS:DOSGROUP,CS:DOSGROUP
94 ELSE
95Share SEGMENT PARA PUBLIC 'SHARE'
96 ASSUME SS:DOSGROUP,CS:SHARE
97 ENDIF
98
99 extrn MFT:BYTE
100 extrn skip_check:BYTE
101
102 include mft.inc
103
104 PUBLIC FreLock,Serial
105
106 IF installed
107Frelock DW ? ; FWA of lock free list
108 ELSE
109Frelock DW OFFSET DOSGROUP:lck8 ; FWA of lock free list
110 ENDIF
111Serial DW 0 ; serial number
112DS_Org dw 0 ;an000;DS on entry to routine
113
114ZERO EQU 0
115ONE EQU 1
116
117FRAME struc
118
119SavedBP dw ?
120RetOFF dw ?
121Parm_1 dw ?
122Parm_2 dw ?
123
124FRAME ends
125
126; $SALUT (4,4,9,41)
127
128 BREAK <Sharer - MultiProcess File Sharer>
129
130;******************* START OF SPECIFICATIONS ***********************************
131;
132; MSDOS MFT Functions
133;
134; The Master File Table (MFT) associates the cannonicalized pathnames,
135; lock records and SFTs for all files open on this machine.
136;
137; These functions are supplied to maintain the MFT and extract
138; information from it. All MFT access should be via these routines so
139; that the MFT structure can remain flexible.
140;
141;******************* END OF SPECIFICATIONS *************************************
142
143 BREAK <Mft_enter - Make an MFT entry and check access>
144
145;******************* START OF SPECIFICATIONS ***********************************
146;
147; mft_enter - make an entry in the MFT
148;
149; mft_enter is called to make an entry in the MFT.
150; mft_enter checks for a file sharing conflict:
151; No conflict:
152; A new MFT entry is created, or the existing one updated,
153; as appropriate.
154; Conflicts:
155; The existing MFT is left alone. Note that if we had to
156; create a new MFT there cannot be, by definition, sharing
157; conflicts.
158; If no conflict has been discovered, the SFT list for the file is
159; checked for one that matches the following conditions:
160;
161; If mode == 70 then
162; don't link in SFT
163; increment refcount
164; If mode&sfIsFCB and userids match and process ids match then
165; don't link in SFT
166;
167; ENTRY ThisSFT points to an SFT structure. The sf_mode field
168; contains the desired sharing mode.
169; WFP_Start is an offset from DOSGroup of the full pathname for
170; the file
171; User_ID = 16-bit user id of issuer
172; Proc_ID = 16-bit process id of issuer
173; (DS) = (SS) = DOSGroup
174; EXIT 'C' clear if no error'
175; 'C' set if error
176; (ax) = error code
177; USES ALL but DS
178;
179;******************* END OF SPECIFICATIONS *************************************
180
181 Procedure mft_enter,NEAR
182
183; int 3
184 nop
185 nop
186
187 EnterCrit critShare
188
189 DOSAssume SS <DS>,"MFT_Enter entry"
190 ASSUME ES:NOTHING,SS:DOSGROUP
191 push ds
192
193; find or make a name record
194
195 mov si,WFP_Start ; (DS:SI) = FBA of file name
196 mov al,1 ; allow creation of MFT entry
197 push es
198
199 ASSUME DS:NOTHING
200
201 call FNM ; find or create name in MFT
202 pop es
203 mov ax,error_sharing_buffer_exceeded
204 jc ent9 ; not enough space
205;
206; (bx) = fwa name record
207;
208 lds si,ThisSFT
209 call ASC ; try to add to chain
210
211; As noted above, we don't have to worry about an "empty" name record
212; being left if ASC refuses to add the SFT - ASC cannot refuse if we had
213; just created the MFT...
214
215; return.
216;
217; 'C' and (Ax) setup appropriately
218
219ent9: pop ds
220
221 LeaveCrit critShare
222
223 ret
224
225 EndProc mft_enter
226
227 BREAK <MftClose - Close out an MFT for given SFT>
228
229;******************* START OF SPECIFICATIONS ***********************************
230;
231; MFTclose
232;
233; MFTclose(SFT)
234;
235; MFTclose removes the SFT entry from the MFT structure. If this was
236; the last SFT for the particular file the file's entry is also removed
237; from the MFT structure. If the sharer is installed after some
238; processing has been done, the MFT field of the SFTs will be 0; we must
239; ignore these guys.
240;
241; If the sft indicates FCB, we do nothing special. The SFT behaves
242; EXACTLY like a normal handle.
243;
244; If the sft indicates mode 70 then we do nothing special. These are
245; normal HANDLES.
246;
247; Note that we always care about the SFT refcount. A refcount of 1
248; means that the SFT is going idle and that we need to remove the sft
249; from the chain.
250;
251; ENTRY (ES:DI) points to an SFT structure
252; (DS) = (SS) = DOSGroup
253; EXIT NONE
254; USES ALL but DS, ES:DI
255;
256;******************* END OF SPECIFICATIONS *************************************
257
258 Procedure MFTclose,NEAR
259
260; int 3
261 nop
262 nop
263
264 EnterCrit critShare
265
266 DOSAssume SS,<DS>,"MFTClose entry"
267 ASSUME ES:NOTHING
268 mov ax,es:[di].sf_MFT
269
270 fmt TypShare,LevShEntry,<"MFTClose by $x:$x of $x:$x ($x)\n">,<User_ID,Proc_id,ES,DI,AX>
271
272 or ax,ax
273 jz mcl10 ; No entry for it, ignore (carry clear)
274 push ds
275 push es
276 push di
277;;;call CSL ; clear SFT locks ;AC008;
278
279 ASSUME DS:NOTHING
280
281 mov ax,es:[di].sf_ref_count ; (ax) = ref count
282;
283; We need to release information in one of two spots. First, when the SFT has
284; a ref count of 0. Here, there are no more referents and, thus, no sharing
285; record need be kept. Second, the ref count may be -1 indicating that the
286; sft is being kept but that the sharing information is no longer needed.
287; This occurs in creates of existing files, where we verify the allowed
288; access, truncate the file and regain the access. If the truncation
289; generates an error, we do NOT want to have the access locked down.
290;
291
292
293 OR AX,AX
294 jz mcl85 ; ref count is 0 - don't dechain
295 inc ax ; -1 + 1 = 0. Busy sft.
296 jnz mcl9
297mcl85:
298 call CSL ; clear SFT locks ;AC008;
299 call RSC ; remove sft from chain
300 jnz mcl9 ; not the last sft for this name
301 call RMN ; remove name record
302mcl9:
303 pop di ; restore regs for exit
304 pop es
305 pop ds
306mcl10:
307 LeaveCrit critShare
308
309 ret
310
311 EndProc MFTclose
312
313 BREAK <MftClU - Close out all MFTs for given UID>
314
315;******************* START OF SPECIFICATIONS ***********************************
316;
317; MFTcloseU
318;
319; MFTcloseM(UID)
320;
321; MFTcloseM removes all entrys for user UID from the MFT structure. We
322; walk the MFT structure closing all relevant SFT's for the user.
323; We do it the dumb way, iterating closes until the SF ref count is
324; 0.
325;
326; ENTRY User_ID = 16-bit user id of issuer
327; (SS) + DOSGroup
328; EXIT 'C' clear
329; USES ALL
330;
331;******************* END OF SPECIFICATIONS *************************************
332
333 Procedure MFTclU,NEAR
334
335; int 3
336 nop
337 nop
338
339 ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP
340
341 EnterCrit critShare
342 mov ax,User_ID
343
344 fmt TypShare,LevShEntry,<"\nCloseUser $x\n">,<AX>
345
346 sub bx,bx ; insensitive to PID
347 sub dx,dx
348 invoke BCS ; bulk close the SFTs
349 LeaveCrit critShare
350 return
351 EndProc MFTclU
352
353 BREAK <MftCloseP - Close out all MFTs for given UID/PID>
354
355;******************* START OF SPECIFICATIONS ***********************************
356;
357; MFTcloseP
358;
359; MFTcloseP(PID, UID)
360;
361; MFTcloseP removes all entrys for process PID on machine MID from the
362; MFT structure. We walk the MFT structure closing all relevant
363; SFT's. Do it the dumb way by iterating closes until the SFTs
364; disappear.
365;
366; ENTRY (SS) = DOSGROUP
367; User_ID = 16-bit user id of issuer
368; Proc_ID = 16-bit process id of issuer
369; EXIT 'C' clear
370; USES ALL
371;
372;******************* END OF SPECIFICATIONS *************************************
373
374 Procedure MFTcloseP,NEAR
375
376; int 3
377 nop
378 nop
379
380 ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP
381
382 EnterCrit critShare
383 mov ax,User_ID
384 mov bx,-1
385 mov dx,Proc_ID
386
387 fmt TypShare,LevShEntry,<"\nClose UID/PID $x:$x\n">,<AX,DX>
388
389 call BCS ; Bulk close the SFTs
390 LeaveCrit critShare
391
392 ret
393
394 EndProc MFTcloseP
395
396 BREAK <MftCloN - Close file by name>
397
398;******************* START OF SPECIFICATIONS ***********************************
399;
400; MFTcloseN
401;
402; MFTcloseN(name)
403;
404; MFTcloseN removes all entrys for the given file from the MFT
405; structure.
406;
407; NOTE: this function is used infrequently and need not be fast.
408; (although for typical use it's not all that slow...)
409;
410; ENTRY DS:SI point to dpl.
411; (SS) = DOSGroup
412; EXIT 'C' clear if no error
413; 'C' set if error
414; AX = error_path_not_found if not currently open
415; USES ALL
416;
417;******************* END OF SPECIFICATIONS *************************************
418
419 Procedure MFTcloN,NEAR
420
421; int 3
422 nop
423 nop
424
425 ASSUME SS:DOSGROUP,ES:NOTHING,DS:NOTHING
426
427 EnterCrit critShare
428 MOV DX,[SI.DPL_DX]
429 MOV DS,[SI.DPL_DS]
430 mov si,dx ; (DS:SI) = fwa name
431 sub al,al ; don't create if not found
432 push ds
433 push si
434 call FNM ; find name in MFT
435 mov ax,error_path_not_found ; assume error
436 jc mclo9 ; not found exit
437
438; Name was found. Lets yank the SFT entrys one at a time.
439
440mclo1: les di,[bx].mft_sptr ; (ES:DI) = SFT address
441 mov WORD PTR ThisSFT,di
442 mov WORD PTR ThisSFT+2,es ; point to SFT
443 cmp es:[di].sf_ref_count,1
444 jnz mclo15
445 call CPS
446mclo15:
447 Context DS
448
449 IF installed
450 MOV AX,(multDOS SHL 8) + 1
451 INT 2FH
452 ELSE
453 call DOS_Close
454 ENDIF
455mclo2:
456
457 ASSUME DS:NOTHING
458
459 pop si
460 pop ds
461 push ds
462 push si
463 sub al,al ; don't create an entry
464 call FNM ; find the name gain
465 jnc mclo1 ; got still more
466 clc
467
468; exit. 'C' and (ax) setup
469;
470; (TOS+2:TOS) = address of ASCIZ string
471
472mclo9: pop si ; clean stack
473 pop ds
474 LeaveCrit critShare
475
476 ret
477
478 EndProc MFTcloN
479
480 BREAK <Set_Mult_Block - Try to set multiple locks>
481
482;******************* START OF SPECIFICATIONS ***********************************
483;
484; NAME: Set_Mult_Block - Set Multiple Block Locks
485;
486; FUNCTION: Set_Mult_Block sets a lock on 1 or more specified ranges
487; of a file. An error is returned if any lock range conflicts
488; with another. Ranges of Locks are cleared via Clr_Mult_Block.
489;
490; In DOS 3.3 only one lock range could be set at a time using
491; Set_Block. For DOS 4.00 this routine will replace Set_Block
492; in the jump table and will make repeated calls to Set_Block
493; in order to process 1 or more lock ranges.
494;
495; NOTE: - This is an all new interface to IBMDOS
496;
497; INPUT: (AL) = 0 - lock all
498; = 80 - lock write
499; (CX) = the number of lock ranges
500; (DS:DX) = pointer to the range list
501; (ES:DI) = SFT address
502; User_ID = 16-bit user id of issuer
503; Proc_ID = 16-bit process id of issuer
504; (SS) = DOSGroup
505;
506; OUTPUT: Lock records filled in for all blocks specified
507;
508; REGISTERS USED: ALL but DS
509; (NOT RESTORED)
510;
511; LINKAGE: IBMDOS Jump Table
512;
513; EXTERNAL Invoke: Load_Regs, Set_Block, Clr_Block
514; REFERENCES:
515;
516; NORMAL 'C' clear if no error
517; EXIT:
518;
519; ERROR 'C' set if error
520; EXIT: (ax) = error code
521; ('error_lock_violation' if conflicting locks)
522;
523; CHANGE 04/15/87 - First release
524; LOG:
525;
526;******************* END OF SPECIFICATIONS *************************************
527;******************+ START OF PSEUDOCODE +**************************************
528;
529; START Set_Mult_Block
530;
531; count = start_count
532; search till count = 0
533; invoke Load_Regs
534; invoke Set_Block
535; exit if error
536; clear_count = start_count - current_count
537; loop till clear_count = 0
538; invoke Load_Regs
539; invoke Clr_Block
540; leave if error
541; end loop
542; set error status
543; orelse
544; endloop
545; set successful status
546; endsrch
547; if error status
548; load return code
549; endif
550; return
551;
552; END Set_Mult_Block
553;
554;******************+ END OF PSEUDOCODE +**************************************
555
556 Procedure Set_Mult_Block,NEAR
557
558; PUSH DS ;ICE
559; push bx ;ICE
560; push ax ;ICE
561
562; mov bx,0140H ;ICE
563; xor ax,ax ;ICE
564; mov ds,ax ;ICE
565; mov ax,word ptr ds:[bx] ;ICE
566; mov word ptr ds:[bx],ax ;ICE
567
568; pop ax ;ICE
569; pop bx ;ICE
570; POP DS ;ICE
571
572
573
574 EnterCrit critShare ; ;AN000;
575
576 ASSUME ES:NOTHING,DS:NOTHING ; ;AN000;
577; set up for loop
578
579; WE HAVE: (from IBMDOS) | WE NEED: (for Set_Block)
580
581; (AL) = 0 - lock all | (BX) = 0 lock all operations
582; = 80- lock write | = 1 lock write operations
583; (CX) = the number of lock ranges | (CX:DX) = offset of area
584; (DS:DX) = pointer to the range list | (SI:AX) = length of area
585; (ES:DI) = SFT address | (ES:DI) = SFT address
586
587; int 3
588 nop
589 nop
590
591 mov DS_Org,ds ;an000;save entry DS
592
593 Context DS ; ;AN000;
594 CMP CX,01h ;DO WE HAVE A COUNT? ;AN000;
595
596;; $if ae ; if the count was valid ;AN000;
597; $if e ; if the count was valid ;AC006;
598 JNE $$IF1
599
600;; PUSH CX ; count = start_count ;AN000;
601;; PUSH DX ; save pointer to range list ;AN000;
602 MOV BP,DX ; save current index into list ;AN000;
603;; AND AX,0080H ; clear high byte and be sure low is ;AN000;
604 ; set if applicable
605;; ROL AL,1 ; move high bit to bit 0
606;; MOV BX,AX ; SET UP TYPE OF LOCK ;AN000;
607
608;; $do ; loop till count = 0 ;AN000;
609;; cmp cx,00 ;an000;see if at end
610;; $leave e ;an000;exit if at end
611;; push cx ;an000;save cx - our counter
612;; push di ;an000;save di - our SFT pointer
613 call load_regs ;an000;load the registers for call
614 ; to set_block
615 call set_block ;an000;set the lock block
616;; pop di ;an000;restore our SFT pointer
617;; pop cx ;an000;restore cx - our counter
618;; $leave c ;an000;on error exit loop
619;; dec cx ;an000;decrease counter
620;; $enddo ;an000;end loop
621
622;; $if c ;an000;if an error occurred
623;; pop dx ;an000;restore range list pointer
624;; pop ax ;an000;obtain original count
625;; sub ax,cx ;an000;determine how many locks set
626;; mov cx,ax ;an000;set the loop counter with count
627;; mov bp,dx ;an000;set bp to point to range list
628;; $do ;an000;while cx not = 0
629;; cmp cx,00 ;an000;at end?
630;; $leave e ;an000;yes, exit
631;; push cx ;an000;save cx - our counter
632;; push di ;an000;save di - our SFT pointer
633;; call load_regs ;an000;load the registers for call
634 ; to clr_block
635;; call clr_block ;an000;clear the locks
636;; pop di ;an000;restore our SFT pointer
637;; pop cx ;an000;restore cx - our counter
638;; $leave c ;an000;on error exit
639;; dec cx ;an000;decrease counter
640;; $enddo ;an000;
641;; stc ;an000;signal an error occurred
642;; $else ;an000;no error occurred in locking
643;; pop ax ;an000;clear off the stack
644;; pop ax ;an000; to balance it
645;; clc ;an000;signal no error occurred
646;; $endif ;an000;
647; $else ;an000;cx was 0 - this is an error
648 JMP SHORT $$EN1
649$$IF1:
650 stc ;an000;signal an error occurred
651; $endif ; ;an000;
652$$EN1:
653
654; $if c ; if there was an error ;AN000;
655 JNC $$IF4
656 MOV AX,error_lock_violation ; load the return code ;AN000;
657; $endif ; endif there was an error ;AN000;
658$$IF4:
659
660 LeaveCrit critShare ; ;AN000;
661
662 ret ; return - all set ;AN000;
663
664 EndProc Set_Mult_Block
665
666 BREAK <Load_Regs - Load Registers for ?_Block call>
667
668;******************* START OF SPECIFICATIONS ***********************************
669;
670; NAME: Load_Regs - Load Registers for ?_Block calls
671;
672; FUNCTION: This subroutine loads the High and Low Offsets and the
673; High and Low lengths for Lock ranges from the Range List.
674;
675; INPUT: (DS_Org:PB) - Range list entry to be loaded
676;
677; OUTPUT: (DX) - Low Offset
678; (CX) - High Offset
679; (AX) - Low Length
680; (SI) - High Length
681;
682; REGISTERS USED: AX CX DX BP SI
683; (NOT RESTORED)
684;
685; LINKAGE: Called by: Set_Mult_Block, Clr_Mult_Block
686;
687; EXTERNAL none
688; REFERENCES:
689;
690; NORMAL none
691; EXIT:
692;
693; ERROR none
694; EXIT:
695;
696; CHANGE 04/15/87 - first release
697; LOG:
698;
699;******************* END OF SPECIFICATIONS *************************************
700;******************+ START OF PSEUDOCODE +**************************************
701;
702; START Load_Regs
703;
704; recover index into range list
705; advance pointer to next entry
706; load DX - Low Offset
707; load CX - High Offset
708; load AX - Low Length
709; load SI - High Length
710; return
711;
712; END Load_Regs
713;
714;******************+ END OF PSEUDOCODE +**************************************
715
716 Procedure Load_Regs,NEAR
717
718 push ds ; save our DS ;an000;
719 mov ds,DS_Org ; get range list segment ;an000;
720 mov si,bp ; recover pointer ;AN000;
721 ADD BP,08h ; move to next entry in list ;AN000;
722 MOV DX,[SI] ; low position ;AN000;
723 MOV CX,[SI+2] ; high position ;AN000;
724 MOV AX,[SI+4] ; low length ;AN000;
725 MOV SI,[SI+6] ; high length ;AN000;
726 pop ds ; restore DS ;an000;
727
728 ret ; ;AN000;
729
730 EndProc Load_Regs
731
732 BREAK <Clr_Mult_Block - Try to clear multiple locks>
733
734;******************* START OF SPECIFICATIONS ***********************************
735;
736; NAME: Clr_Mult_Block - Clear Multiple Block Locks
737;
738; FUNCTION: Clr_Mult_Block removes the locks on 1 or more specified
739; ranges of a file. An error is returned if any lock range
740; does not exactly match. Ranges of Locks are set via
741; Set_Mult_Block.
742;
743; In DOS 3.3 only one lock range could be cleared at a time
744; using Clr_Block. For DOS 4.00 this routine will replace
745; Clr_Block in the jump table and will make repeated calls
746; to Set_Block in order to process 1 or more lock ranges.
747;
748; NOTE: - This is an all new interface to IBMDOS
749; - an unlock all 'lock all' request will unlock both
750; 'lock all' and 'lock write'.
751; - an unlock all 'lock write' request will not unlock
752; 'lock all's. It will only unlock 'lock write's.
753; (if you can understand the above statement,
754; understanding the code will be easy!)
755;
756; INPUT: (AL) = 0 - lock all
757; = 80- lock write
758; (CX) = the number of lock ranges - NB: all if -1 ***
759; (DS:DX) = pointer to the range list
760; (ES:DI) = SFT address
761; User_ID = 16-bit user id of issuer
762; Proc_ID = 16-bit process id of issuer
763; (SS) = DOSGroup
764;
765; OUTPUT: Lock records filled in for all blocks specified
766;
767; REGISTERS USED: ALL but DS
768; (NOT RESTORED)
769;
770; LINKAGE: IBMDOS Jump Table
771;
772; EXTERNAL Invoke: Load_Regs, Set_Block, Clr_Block, Clr_List
773; REFERENCES:
774;
775; NORMAL 'C' clear if no error
776; EXIT:
777;
778; ERROR 'C' set if error
779; EXIT: (ax) = error code
780; ('error_lock_violation' if conflicting locks)
781;
782; CHANGE 04/15/87 - First release
783; LOG:
784;
785;******************* END OF SPECIFICATIONS *************************************
786;******************+ START OF PSEUDOCODE +**************************************
787;
788; START Clr_Mult_Block
789;
790; if count is valid and
791; if file (SFT) is 'shared' then
792; if count = all
793; find first RLR
794; loop till all RLR cleared
795; if PROC_ID matches and
796; if UID matches and
797; if SFT matches then
798; if ulocking lock_all or
799; if this RLR is lock_write
800; clear the lock
801; endif
802; endif
803; find next RLR
804; end loop
805; else
806; invoke Clr_List
807; endif
808; set successful status
809; else
810; set error status
811; endif
812; if error
813; load return code
814; endif
815;
816; ret
817;
818; END Clr_Mult_Block
819;
820;******************+ END OF PSEUDOCODE +**************************************
821
822 Procedure clr_mult_block,NEAR
823
824
825lock_all equ 0h
826
827; PUSH DS ;ICE
828; push bx ;ICE
829; push ax ;ICE
830
831; mov bx,0140H ;ICE
832; xor ax,ax ;ICE
833; mov ds,ax ;ICE
834; mov ax,word ptr ds:[bx] ;ICE
835; mov word ptr ds:[bx],ax ;ICE
836
837; pop ax ;ICE
838; pop bx ;ICE
839; POP DS ;ICE
840
841 EnterCrit critShare ; ;AN000;
842
843 ASSUME ES:NOTHING,DS:NOTHING ; ;AN000;
844
845; int 3
846 nop
847 nop
848
849 mov DS_Org,DS ;an000;save entry DS
850
851 Context DS ; ;AN000;
852
853 CMP CX,01h ; do we have a count? ;AN000;
854;; $IF AE,AND ; IF A VALID COUNT
855; $IF E,AND ; IF A VALID COUNT ;AC006;
856 JNE $$IF6
857 cmp es:[di].sf_mft,0 ; is this SFT shared? ;AN000;
858; $IF NE ; AND IF FILE IS 'SHARED' THEN
859 JE $$IF6
860
861; WE HAVE: (from IBMDOS) | WE NEED:
862
863; (AL) = 0 - lock all | (AX) = 0 lock all operations
864; = 80- lock write | = 1 lock write operations
865; (CX) = - 1 (unlock all locks) | (DS) = CS
866; | (DS:DI) = previous RLR
867; | (DS:SI) = current RLR
868; (ES:DI) = current SFT |
869
870;; and ax,0080h ;be sure it is set right (mask 80 bit) ;AC002;
871 ; existing interface
872;; rol al,1 ;put high bit in bit 0 ;AC002;
873
874;; CMP CX,-1h ; ;AN000;
875;; $IF E ; IF unlock all locks then ;AN000;
876
877;; push cs ; ;AN000;
878;; pop ds ; ;AN000;
879;; mov cx,di ; ES:CX is the SFT ;AN004;
880
881; ASSUME ds:nothing
882
883;; mov si,es:[di].sf_mft ; DS:SI points to MFT ;AN000;
884
885;; lea di,[si].mft_lptr ; DS:DI = addr of ptr to lock record ;AN000;
886;; mov si,[di] ; DS:SI = address of 1st lock record ;AN000;
887
888;; $DO ; loop through the RLR's ;AN000;
889
890; DS:DI = points to previous RLR or MFT if no RLR.
891; DS:SI = points to current RLR
892; ES:CX = SFT address
893; AX = lock type
894
895;; and si,si ; are we at the end of the chain? ;AN000;
896;; $LEAVE Z ; we'er done with CF = 0 ;AN000;
897
898;; mov bp,[si].rlr_pid ; get PROC_ID ;AN000;
899;; cmp bp,PROC_ID ; is it ours? ;AN000;
900;; $IF E,AND ; ;AN000;
901;; mov bp,es ; ;AN000;
902;; cmp bp,WORD PTR [si].rlr_sptr+2 ; ;AC004;
903;; $IF E,AND ; ;AN000;
904;; cmp cx,WORD PTR [si].rlr_sptr ; ;AC004;
905;; mov si,[di] ; restore pointer to current (using ;AN000;
906 ; previous)
907;; $IF E ; if it is ours ;AN000;
908
909; this is it. its OURS !
910
911;; cmp ax,lock_all ; ;AN000;
912
913;; $IF E,OR ; if unlocking all or ;AN000;
914
915;; mov bp,[si].rlr_type ; get lock type ;AN000;
916;; cmp bp,rlr_lall ; is it lock all? ;AN000;
917
918;; $IF NE ; if not a LOCK ALL lock ;AN000;
919
920; remove the RLR from the chain
921
922;; mov bx,[si].rlr_next ; get the pointer to the next RLR ;AN000;
923;; mov [di],bx ; install it in the last ;AN000;
924
925; put defunct lock record on the free chain
926
927;; mov bx,Frelock ; ;AN000;
928;; mov [si].rlr_next,bx ; ;AN000;
929;; mov Frelock,si ; ;AN000;
930;; mov si,di ; back up to last ;AN000;
931
932;; $ENDIF ; should we unlock it ;AN000;
933
934;; $ENDIF ; it was ours! ;AN000;
935
936; advance to next RLR
937
938;; mov di,si ; load address of next RLR ;AN000;
939;; mov si,[di] ; update pointer to next RLR ;AN000;
940
941;; $ENDDO ; loop back to the start ;AN000;
942
943;; $ELSE ; else, its a LIST ! ;AN000;
944
945; set up for loop
946
947; WE HAVE: (from IBMDOS) | WE NEED: (for Clr_Block)
948
949; (AX) = 0 - lock all | (BX) = 0 lock all operations
950; = 1 - lock write | = 1 lock write operations
951; (CX) = the number of lock ranges | (CX:DX) = offset of area
952; (DS:DX) = pointer to the range list | (SI:AX) = length of area
953; (ES:DI) = SFT address | (ES:DI) = SFT address
954
955;; PUSH CX ; count = start_count ;AN000;
956;; PUSH DX ; save pointer to range list ;AN000;
957 MOV BP,DX ; save current index into list ;AN000;
958;; MOV BX,AX ; SET UP TYPE OF LOCK ;AN000;
959
960 call Clr_List ; call Clr_List to process the list ;AN000;
961
962;; $ENDIF ; ;AN000;
963
964; $ELSE ; NOT VALID
965 JMP SHORT $$EN6
966$$IF6:
967
968 STC ; ;AN000;
969
970; $ENDIF ; VALID/INVALID ;AN000;
971$$EN6:
972
973; $IF C ; if carry is set ;AN000;
974 JNC $$IF9
975 MOV AX,error_lock_violation ; load error condition ;AN000;
976; $ENDIF ; carry not set ;AN000;
977$$IF9:
978
979 LeaveCrit critShare ; ;AN000;
980
981 ret ; return - all set ;AN000;
982
983 EndProc clr_mult_block
984
985 BREAK <Clr_List - Clear a list of user specified locks>
986
987;******************* START OF SPECIFICATIONS ***********************************
988;
989; NAME: Clr_List - Clear a list of user specified locks
990;
991; FUNCTION: Clr_List makes multiple calls to Clr_Block to clear
992; multiple lock ranges of a file. An error is returned
993; if any lock range does not exactly match. Ranges of
994; Locks are then set via Set_Mult_Block.
995;
996;
997; INPUT: (BX) = 0 lock all operations
998; = 1 lock write operations
999; (CX:DX) = offset of area
1000; (SI:AX) = length of area
1001; (ES:DI) = SFT address
1002; (SS:SP+2)= original index \ see FRAME struc
1003; (SS:SP+4)= original count /
1004;
1005; OUTPUT: Lock records removed for all blocks specified
1006; Stack cleard on return
1007;
1008; REGISTERS USED: ALL but DS
1009; (NOT RESTORED)
1010;
1011; LINKAGE: IBMDOS Jump Table
1012;
1013; EXTERNAL Invoke: Load_Regs, Set_Block, Clr_Block
1014; REFERENCES:
1015;
1016; NORMAL 'C' clear if no error
1017; EXIT:
1018;
1019; ERROR 'C' set if error
1020; EXIT: (ax) = error code
1021; ('error_lock_violation' if conflicting locks)
1022;
1023; CHANGE 04/15/87 - First release
1024; LOG:
1025;
1026;******************* END OF SPECIFICATIONS *************************************
1027;******************+ START OF PSEUDOCODE +**************************************
1028;
1029; START Clr_List
1030;
1031; search till count = 0
1032; set up for call
1033; call clr_Block
1034; exit if c
1035; clear_count = start_count - current_count
1036; loop till clear_count = 0
1037; set up for call
1038; call Set_Block
1039; end loop
1040; set error status
1041; orelse
1042; endloop
1043; set successful status
1044; endsrch
1045; return
1046;
1047; END Clr_List
1048;
1049;******************+ END OF PSEUDOCODE +**************************************
1050
1051 Procedure Clr_List,NEAR
1052
1053;; $do ;an000;while cx not = 0
1054;; cmp cx,00 ;an000;at end?
1055;; $leave e ;an000;yes
1056;; push cx ;an000;save cx - our counter
1057;; push di ;an000;save di - our SFT pointer
1058 call load_regs ;an000;set up for clr_block call
1059;; push bp ; save pointer to range entry ;AN000;
1060 call clr_block ;an000;remove the lock
1061;; pop bp ; recover pointer to range entry ;AN000;
1062;; pop di ;an000;restore our SFT pointer
1063;; pop cx ;an000;restore cx - our counter
1064;; $leave c ;an000;leave on error
1065;; dec cx ;an000;decrease counter
1066;; $enddo ;an000;
1067
1068;; $if c ;an000;an error occurred
1069;; push bp ;an000;save bp
1070;; mov bp,sp ;an000;get sp
1071;; mov dx,[bp].parm_1 ;an000;recover original index
1072;; mov ax,[bp].Parm_2 ; original count ;AN000;
1073;; pop bp
1074;; SUB AX,CX ; how many did we do? ;AN000;
1075;; MOV CX,AX ; set up the loop ;AN000;
1076;; MOV BP,DX ; save the index ;AN000;
1077
1078;; $DO ; ;AN000;
1079;; cmp cx,00 ;an000;at end?
1080;; $leave e ;an000;yes
1081;; push cx ;an000;save cx - our counter
1082;; push di ;an000;save di - our SFT pointer
1083;; call load_regs ;an000;set up for set_block call
1084;; call set_block ;an000;reset the locks
1085;; pop di ;an000;restore our SFT pointer
1086;; pop cx ;an000;restore cx - our counter
1087;; $leave c ;an000;leave on error
1088;; dec cx ;an000;decrease counter
1089;; $enddo ;an000;
1090;; stc ;an000;signal an error
1091;; $else ;an000;
1092;; clc ;an000;signal no error
1093;; $endif ;an000;
1094
1095;; ret 4 ; return (clear Parm_1 & Parm_2) ;AN000;
1096 ret ; return (clear Parm_1 & Parm_2) ;AC006;
1097
1098 EndProc Clr_List
1099
1100
1101 BREAK <Set_Block - Try to set a lock>
1102
1103;******************* START OF SPECIFICATIONS ***********************************
1104;
1105; NAME: Set_Block - set byte range lock on a file
1106;
1107; FUNCTION: Set_Block sets a lock on a specified range of a file. An
1108; error is returned if the lock conflicts with another.
1109; Locks are cleared via clr_block.
1110;
1111; INPUT: (ES:DI) = SFT address
1112; (CX:DX) = offset of area
1113; (SI:AX) = length of area
1114; (BX) = 0 lock all operations
1115; = 1 lock write operations
1116; User_ID = 16-bit user id of issuer
1117; Proc_ID = 16-bit process id of issuer
1118; (SS) = DOSGroup
1119;
1120; OUTPUT: Lock records removed for all blocks specified
1121;
1122; REGISTERS USED: ALL but DS, BP
1123; (NOT RESTORED)
1124;
1125; LINKAGE: Invoked by: Set_Mult_Block
1126;
1127; EXTERNAL Invoke: CLP (SLE), OFL
1128; REFERENCES:
1129;
1130; NORMAL 'C' clear if no error
1131; EXIT:
1132;
1133; ERROR 'C' set if error
1134; EXIT:
1135;
1136; CHANGE 04/15/87 - lock only write support
1137; LOG:
1138;
1139;******************* END OF SPECIFICATIONS *************************************
1140;******************+ START OF PSEUDOCODE +**************************************
1141;
1142; START Set_Block
1143;
1144; if a valid SFT and
1145; invoke CLP
1146; if no lock conflicts and
1147; invoke OFL
1148; if empty lock record available
1149; store SFT pointer
1150; store lock range
1151; add RLR to the chain
1152; store PROC_ID
1153; store rlr_type
1154; set successful return status
1155; else
1156; set error return status
1157; endif
1158; return
1159;
1160; END Set_Block
1161;
1162;******************+ END OF PSEUDOCODE +**************************************
1163
1164 Procedure Set_Block,NEAR
1165
1166 ASSUME ES:NOTHING,DS:NOTHING
1167
1168 Context DS
1169
1170 push bp ; preserve (bp) ;AN000;
1171 push ds ; preserve (ds)
1172;; push bx ; preserve (bx) ;AN000;
1173 cmp es:[di].sf_mft,ZERO
1174; $if nz,and ; if file is SHARED and ;AC000;
1175 JZ $$IF11
1176 push di
1177 call clp ; do common setup code
1178
1179 ASSUME DS:NOTHING
1180
1181 pop bp
1182; $if nc,and ; if no (lock conflict) error and ;AC000;
1183 JC $$IF11
1184
1185; Its ok to set this lock. Get a free block and fill it in
1186; (es:bp) = sft
1187; (ds:si) = pointer to name record
1188; (ax:bx) = fba lock area
1189; (cx:dx) = lba lock area
1190; (ds:di) = pointer to pointer to previous lock
1191; (TOS) = saved (bx)
1192; (TOS+1) = saved (ds)
1193; (TOS+2) = saved (bp)
1194
1195 call OFL ; (ds:di) = pointer to new, orphan lock record
1196; $if nc ; if space available ;AC000;
1197 JC $$IF11
1198 mov WORD PTR [di].rlr_sptr,bp ; store SFT offset
1199 mov WORD PTR [di].rlr_sptr+2,es ; store SFT offset
1200 mov [di].rlr_fba+2,ax
1201 mov [di].rlr_fba,bx ; store lock range
1202 mov [di].rlr_lba+2,cx
1203 mov [di].rlr_lba,dx
1204
1205; add to front of chain
1206;
1207; (ds:si) = fwa MFT name record
1208
1209 mov ax,[si].mft_lptr
1210 mov [di].rlr_next,ax
1211 mov [si].mft_lptr,di
1212;
1213; Set process ID of lock
1214;
1215 mov ax,proc_id
1216 mov [di].rlr_pid,ax
1217
1218;
1219;; pop bx ; recover lock type ;AN000;
1220;; push bx ; restore the stack ;AN000;
1221;; mov [di].rlr_type,bx ; set the rlr_type field ;AN000;
1222 clc ; we finished OK
1223
1224; $else ; ;AC000;
1225 JMP SHORT $$EN11
1226$$IF11:
1227
1228 mov ax,error_lock_violation
1229 stc
1230
1231; $endif ; ;AC000;
1232$$EN11:
1233
1234;; pop bx ; ;AN000;
1235 pop ds
1236 pop bp ; ;AC000;
1237
1238 ret ; return - all set
1239
1240 EndProc Set_Block
1241
1242 BREAK <Clr_Block - Try to clear a lock>
1243
1244;******************* START OF SPECIFICATIONS ***********************************
1245;
1246; NAME: Clr_Block - clear byte range lock on a file
1247;
1248; FUNCTION: Clr_Block clears a lock on a specified range of a file.
1249; Locks are set via set_block.
1250;
1251; INPUT: (ES:DI) = SFT address
1252; (CX:DX) = offset of area
1253; (SI:AX) = length of area
1254; (BX) = 0 lock all operations
1255; = 1 lock write operations
1256; User_ID = 16-bit user id of issuer
1257; Proc_ID = 16-bit process id of issuer
1258; (SS) = DOSGroup
1259;
1260; OUTPUT: Lock record removed for block specified.
1261;
1262; REGISTERS USED: ALL but DS
1263; (NOT RESTORED)
1264;
1265; LINKAGE: Invoked by: Clr_Mult_Block
1266;
1267; EXTERNAL Invoke: CLP (SLE), OFL
1268; REFERENCES:
1269;
1270; NORMAL 'C' clear if no error
1271; EXIT:
1272;
1273; ERROR 'C' set if error
1274; EXIT: (ax) = error code
1275; ('error_lock_violation' if conflicting locks or
1276; range does not exactly match previous lock)
1277;
1278; CHANGE 04/15/87 - lock only write support
1279; LOG:
1280;
1281;******************* END OF SPECIFICATIONS *************************************
1282;******************+ START OF PSEUDOCODE +**************************************
1283;
1284; START Clr_Block
1285;
1286; if file is SHARED and
1287; if lock is valid and
1288; if SFT matches and
1289; if PROC_ID matches
1290; if lock_reqest = lock_type
1291; unchain the lock
1292; put defunct lock on free chain
1293; clear error status
1294; else
1295; set error status
1296; endif
1297; else
1298; flush the stack
1299; set error status
1300; endif
1301; if error
1302; load return code
1303; endif
1304; return
1305;
1306; END Clr_Block
1307;
1308;******************+ END OF PSEUDOCODE +**************************************
1309
1310 Procedure Clr_Block,NEAR
1311
1312 ASSUME ES:NOTHING,DS:NOTHING
1313
1314 Context DS
1315 push ds
1316;; push bx ; save type of operation ;AN000;
1317 cmp es:[di].sf_mft,ZERO
1318
1319; $if nz,and ; if file is SHARED and ;AC000;
1320 JZ $$IF14
1321
1322 push di
1323 call clp ; do common setup code
1324
1325 ASSUME DS:NOTHING
1326
1327 pop bp ; ES:BP points to sft.
1328;; pop bx ; recover the type of operation ;AN000;
1329
1330; $if c,and ; if lock exists and ;AC000;
1331 JNC $$IF14
1332; $if z,and ; if range given correctly and ;AC000;
1333 JNZ $$IF14
1334;
1335; We've got the lock
1336;
1337; (ds:di) = address of pointer (offset) to previous lock record
1338; (es:BP) = sft address
1339;
1340; Now comes the tricky part. Is the lock for us? Does the lock match the SFT
1341; that was given us? If not, then error.
1342;
1343 mov si,[di] ; (DS:SI) = address of lock record
1344 cmp word ptr [si].rlr_sptr,bp
1345
1346; $if z,and ; if SFT matches and ;AC000;
1347 JNZ $$IF14
1348
1349 mov bp,es
1350 cmp word ptr [si].rlr_sptr+2,bp
1351; $if z,and ; (check both words of SFT pointer) ;AC000;
1352 JNZ $$IF14
1353 mov bp,proc_id
1354 cmp [si].rlr_pid,bp
1355
1356;; $if z,and ; if PROC_ID matches ;AC000;
1357; $if z ; if PROC_ID matches ;AC006;
1358 JNZ $$IF14
1359;
1360; Make sure that the type of request and the lock type match
1361;
1362;; cmp bx,lock_all ; ;AN000;
1363
1364;; $IF E,OR ; if unlocking all or ;AN000;
1365
1366;; mov bp,[si].rlr_type ; get lock type ;AN000;
1367;; cmp bp,rlr_lall ; is it lock all? ;AN000;
1368
1369;; $IF NE ; if not a LOCK ALL lock ;AN000;
1370;
1371; The locks match the proper open invocation. Unchain the lock
1372;
1373 mov ax,[si].rlr_next
1374 mov [di],ax ; chain it out
1375
1376; put defunct lock record on the free chain
1377;
1378; (ds:si) = address of freed lock rec
1379
1380 mov ax,Frelock
1381 mov [si].rlr_next,ax
1382 mov Frelock,si
1383 clc
1384
1385; $else ; we have an error ;AC000;
1386 JMP SHORT $$EN14
1387$$IF14:
1388
1389 stc
1390
1391; $endif ; Endif - an error ;AC000;
1392$$EN14:
1393
1394; $if c ; If an error was found ;AC000;
1395 JNC $$IF17
1396
1397 mov ax,error_lock_violation
1398
1399; $endif ; Endif - an error was found ;AC000;
1400$$IF17:
1401
1402 pop ds ; restore DS
1403
1404 ret
1405
1406
1407 EndProc Clr_Block
1408
1409 BREAK <CLP - Common Lock Preamble>
1410
1411;******************* START OF SPECIFICATIONS ***********************************
1412;
1413; NAME: CLP - Common Lock Preamble
1414;
1415; FUNCTION: This routine contains a common code fragment for set_block
1416; and clr_block.
1417;
1418; INPUT: (ES:DI) = SFT address
1419; (CX:DX) = offset of area
1420; (SI:AX) = length of area
1421; User_ID = 16-bit user id of issuer
1422; Proc_ID = 16-bit process id of issuer
1423; (SS) = (DS) = DOSGroup
1424;
1425; OUTPUT: (ds:si) = MFT address
1426;
1427; REGISTERS USED: ALL but ES
1428; (NOT RESTORED)
1429;
1430; LINKAGE: Invoked by: Set_Block, Clr_Block
1431;
1432; EXTERNAL Invoke: SLE
1433; REFERENCES:
1434;
1435; NORMAL 'C' clear if no overlap
1436; EXIT: (ax:bx) = offset of first byte in range
1437; (cx:dx) = offset of last byte in range
1438;
1439; ERROR 'C' set if overlap
1440; EXIT: 'Z' set if 1-to-1 match
1441; (di) points to previous lock
1442;
1443; CHANGE 04/15/87 - lock only write support
1444; LOG:
1445;
1446;******************* END OF SPECIFICATIONS *************************************
1447;******************+ START OF PSEUDOCODE +**************************************
1448;
1449; START CLP
1450;
1451; shuffle arguments
1452; if valid length
1453; invoke SLE
1454; set successful return status
1455; else
1456; set error return status
1457; endif
1458; return
1459;
1460; END CLP
1461;
1462;******************+ END OF PSEUDOCODE +**************************************
1463
1464 Procedure CLP,NEAR
1465
1466 mov bx,dx ; shuffle arguments
1467 xchg dx,ax
1468 xchg ax,cx ; (ax:bx) = offset
1469 mov cx,si ; (cx:dx) = length
1470
1471 or si,dx ; see if length is 0
1472
1473; $if nz,and ; if length is > 0 and ;AC000;
1474 JZ $$IF19
1475
1476 add dx,bx
1477 adc cx,ax ; (cx:dx) = lba+1
1478
1479; $if nc,or ; no carry is ok ;AC000;
1480 JNC $$LL19
1481
1482 mov si,dx
1483 or si,cx
1484
1485; $if z ; if !> 0 then ;AC000;
1486 JNZ $$IF19
1487$$LL19:
1488
1489 sub dx,1 ; (cx:dx) = lba of locked region
1490 sbb cx,0
1491
1492 push cs
1493 pop ds
1494; (es:di) is sft
1495 push si
1496 mov si,es:[di].sf_mft
1497 push si
1498 mov di,1 ; Find own locks
1499 call SLE
1500; di points to previous lock record
1501 pop si
1502 pop bp
1503
1504; $else ; we have an error ;AC000;
1505 JMP SHORT $$EN19
1506$$IF19:
1507
1508 xor si,si
1509 inc si ; carry unchanged, zero reset
1510 mov ax,error_lock_violation ; assume error
1511 stc
1512
1513; $endif ; endif - we have an error ;AC000;
1514$$EN19:
1515
1516 ret
1517
1518 EndProc CLP
1519
1520 BREAK <Chk_Block - See if the specified I/O violates locks>
1521
1522;******************* START OF SPECIFICATIONS ***********************************
1523;
1524; NAME: Chk_Block - check range lock on a file
1525;
1526; FUNCTION: Chk_Block is called to interogate the lock status of a
1527; region of a file.
1528;
1529; NOTE: This routine is called for every disk I/O operation
1530; and MUST BE FAST
1531;
1532; INPUT: (ES:DI) points to an SFT structure
1533; (AL) = 80h - Write operation = 0 - any non write operation
1534; (CX) is the number of bytes being read or written
1535; BytPos is a long (low first) offset into the file
1536; of the I/O
1537; User_ID = 16-bit user id of issuer
1538; Proc_ID = 16-bit process id of issuer
1539; (SS) = DOSGroup
1540;
1541; OUTPUT: CF set according to status and presence of locks (see below)
1542;
1543; REGISTERS USED: ALL but ES,DI,CX,DS
1544; (NOT RESTORED)
1545;
1546; LINKAGE: IBMDOS Jump Table
1547;
1548; NORMAL 'C' clear if no error
1549; EXIT:
1550;
1551; ERROR 'C' set if error
1552; EXIT: (ax) = error code
1553; ('error_lock_violation' if conflicting locks)
1554;
1555; CHANGE 04/15/87 - lock only write support
1556; LOG:
1557;
1558;******************* END OF SPECIFICATIONS *************************************
1559;******************+ START OF PSEUDOCODE +**************************************
1560;
1561; START Chk_Block
1562;
1563; if shared SFT and
1564; if locks exist
1565; invoke SLE
1566; if lock conflicts occur (error)
1567; if this is !write operation and
1568; if a write lock found
1569; set successfull status
1570; else
1571; set error status
1572; endif
1573; else no error
1574; flush stack
1575; endif
1576; endif
1577;
1578; ret
1579;
1580; END Chk_Block
1581;
1582;******************+ END OF PSEUDOCODE +**************************************
1583
1584 Procedure Chk_Block,NEAR
1585
1586 ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP
1587
1588write_op equ 080h ; write operation requested ;AN000;
1589lock_all equ 0h ; lock all specified ;AN000;
1590
1591; PUSH DS ;ICE
1592; push bx ;ICE
1593; push ax ;ICE
1594
1595; mov bx,0140H ;ICE
1596; xor ax,ax ;ICE
1597; mov ds,ax ;ICE
1598; mov ax,word ptr ds:[bx] ;ICE
1599; mov word ptr ds:[bx],ax ;ICE
1600
1601; pop ax ;ICE
1602; pop bx ;ICE
1603; POP DS ;ICE
1604 EnterCrit critShare
1605
1606; int 3
1607 nop
1608 nop
1609
1610 PUSH ES
1611 PUSH DI
1612 PUSH CX
1613 PUSH DS
1614 cmp es:[di].sf_mft,0
1615
1616; $if nz,and ; if the file is SHARED and ;AC000;
1617 JZ $$IF22
1618
1619 push cs
1620 pop ds
1621 mov si,es:[di].sf_MFT ; (DS:SI) = address of MFT record
1622 test [si].mft_lptr,-1
1623
1624; $if nz,and ; if there are locks on this file and ;AC000;
1625 JZ $$IF22
1626
1627 sub cx,1 ; (cx) = count-1
1628 cmc
1629
1630; $if c ; there are bytes to lock ;AC000;
1631 JNC $$IF22
1632
1633;; push ax ; preserve type of operation ;AN000;
1634 ; DOS passes AL = 80 for writes
1635 ; = 00 for reads
1636
1637 mov ax,WORD PTR BytPos+2
1638 mov bx,WORD PTR BytPos ; (ax:bx) = offset
1639 mov dx,cx
1640 sub cx,cx
1641 add dx,bx
1642 adc cx,ax ; (cx:dx) = lba of lock area
1643 sub di,di ; ignore own locks
1644 call SLE
1645;; pop ax ; recover type of opperation ;AN000;
1646
1647; upon return DS:SI points to the RLR with the conflict
1648
1649;; $if c ; if lock conflicts occur - error ;AC000;
1650
1651; now we must check what type of lock exists
1652; and the type of operation in progress.
1653
1654;; cmp al,write_op ; ;AN000;
1655
1656;; $if ne,and ; if NOT a write operation and ;AN000;
1657
1658;; cmp [si].rlr_type,rlr_lwr ; ;AN000;
1659
1660;; $if e ; if write locked (NOT all locked) ;AN000;
1661
1662;; clc ; then not true conflict - clear error ;AN000;
1663
1664;; $else ; else it IS a valid conflict ;AC000;
1665
1666;; stc ; true error - set error status
1667
1668;; $endif ; endif - a valid conflict ;AC000;
1669
1670
1671;; $endif ; endif - conflicts ;AC000;
1672
1673 mov ax,error_lock_violation ; assume error
1674
1675; $endif ; endif - no need to check ;AC000;
1676$$IF22:
1677
1678; exit
1679;
1680; 'C' and (ax) setup
1681
1682 POP DS
1683 POP CX
1684 POP DI
1685 POP ES
1686 LeaveCrit critShare
1687
1688 ret ; exit
1689
1690 EndProc Chk_Block
1691
1692 BREAK <MFT_get - get an entry from the MFT>
1693
1694;******************* START OF SPECIFICATIONS ***********************************
1695;
1696; MFT_get - get an entry from the MFT
1697;
1698; MFT_get is used to return information from the MFT. System utilities
1699; use this capability to produce status displays.
1700;
1701; MFT_get first locates the (BX)'th file in the list (no particular
1702; ordering is promised). It returns that name and the UID of
1703; the (CX)'th SFT on that file and the number of locks on that
1704; file via that SFT.
1705;
1706; ENTRY DS:SI point to DPL which contains:
1707; (dBX) = zero-based file index
1708; (dCX) = zero-based SFT index
1709; (SS) = DOSGroup
1710; EXIT 'C' clear if no error
1711; ES:DI buffer is filled in with BX'th file name
1712; (BX) = user id of SFT
1713; (CX) = # of locks via SFT
1714; 'C' set if error
1715; (ax) = error code
1716; ('error_no_more_files' if either index is out
1717; of range)
1718;
1719;******************* END OF SPECIFICATIONS *************************************
1720
1721 Procedure MFT_get,NEAR
1722
1723; int 3
1724 nop
1725 nop
1726
1727 ASSUME DS:NOTHING,ES:NOTHING
1728
1729 EnterCrit critShare
1730 MOV BX,[SI.DPL_BX]
1731 MOV CX,[SI.DPL_CX]
1732 Context ES
1733 MOV DI,OFFSET DOSGROUP:OpenBuf
1734
1735 xchg bx,cx ; (cx) = file index
1736 push cs
1737 pop ds
1738
1739 Off SI,mft ; (ds:si) = fwa of OFFSET MFT
1740
1741; scan forward until next name
1742
1743mget1: cmp [si].mft_flag,MFLG_FRE
1744 jz mget3 ; is free space
1745 jl mget7 ; is END
1746
1747; have another name. see if this satisfies caller
1748
1749 jcxz mget4 ; caller is happy
1750 dec cx
1751mget3: add si,[si].mft_len ; skip name record
1752 JMP SHORT mget1
1753
1754; we've located the file name.
1755;
1756; (bx) = SFT index
1757; (DS:SI) = MFT entry
1758; (ES:DI) = address of caller's buffer
1759
1760mget4: push di
1761 push si ; save table offset
1762 add si,mft_name
1763mget5: lodsb
1764 stosb ; copy name into caller's buffer
1765 or al,al
1766 jnz mget5
1767 pop si ; (DS:SI) = name record address
1768 xchg bx,cx ; (cx) = SFT chain count
1769 lds di,[si].mft_sptr
1770mget6: jcxz mget8 ; have reached the SFT we wanted
1771 dec cx
1772 lds di,[di].sf_chain ; get next link
1773 or di,di
1774 jnz mget6 ; follow chain some more
1775 pop di ; (es:di) = buffer address
1776
1777;** The file or SFT index was too large - return w/ error
1778
1779mget7: mov ax,error_no_more_files
1780 stc
1781 LeaveCrit critShare
1782
1783 ret
1784
1785;** We've got the SFT he wants. Lets count the locks
1786;
1787; (es:TOS) = buffer address
1788; (DS:DI) = address of SFT
1789; (si) = address of mft
1790
1791mget8: mov ax,[DI].sf_flags
1792 mov dx,ds ; save segment
1793 push cs
1794 pop ds
1795 mov si,[si].mft_lptr ; (DS:SI) = Lock record address
1796 sub cx,cx ; clear counter
1797
1798mget9: or si,si
1799 jz mget11 ; no more
1800 cmp di,WORD PTR [si].rlr_sptr
1801 jnz mget10
1802 cmp dx,word PTR [si].rlr_sptr+2
1803 jnz mget10
1804 inc cx
1805mget10: mov si,[si].rlr_next
1806 JMP SHORT mget9
1807
1808; Done counting locks. return the info
1809;
1810; (cx) = count of locks
1811; (es:TOS) = buffer address
1812
1813mget11: mov ds,dx
1814 mov bx,[di].SF_UID ; (bx) = UID
1815 pop di
1816 clc
1817 LeaveCrit critShare
1818
1819 ret
1820
1821 EndProc MFT_get
1822
1823 BREAK <ASC - Add SFT to Chain>
1824
1825;******************* START OF SPECIFICATIONS ***********************************
1826;
1827; ASC - Add SFT to Chain
1828;
1829; ASC is called to add an SFT to the front of the chain.
1830;
1831; ASC checks the file share mode bits on the other SFTs in the chain and
1832; reports a conflict. The new SFT is NOT ADDED in the case of
1833; conflicts.
1834;
1835; ENTRY (BX) = FBA MFT name record
1836; (DS:SI) = SFT address
1837; EXIT 'C' clear if added
1838; (ds:si) point to sft
1839; (bx) offset of mft
1840; 'C' set if conflict
1841; (ax) = error code
1842; USES ALL
1843;
1844;******************* END OF SPECIFICATIONS *************************************
1845
1846 Procedure ASC,NEAR
1847
1848 cmp [si].sf_MFT,0
1849 jnz asc9 ; already on chain - internal error
1850
1851; The SFT looks good... lets see if there are any use conflicts
1852
1853; Message 1,<"Adding sft ">
1854
1855 mov ax,User_ID ; place user information in SFT
1856 mov [si].sf_UID,ax ; do it before CUC (he checks UID)
1857 mov ax,Proc_ID
1858 mov [si].sf_PID,ax
1859
1860 cmp skip_check,1
1861; $if ne ;
1862 JE $$IF24
1863
1864 call CUC ; check use conflicts
1865
1866; $endif
1867$$IF24:
1868
1869 jc asc8 ; use conflicts - forget it
1870
1871; MessageNum AX
1872
1873; MessageNum AX
1874; Message 1,<" to ">
1875; MEssageNum DS
1876; Message 1,<":">
1877; MessageNum SI
1878; Message 1,<" ">
1879
1880 mov [si].sf_MFT,bx ; make SFT point to MFT
1881
1882; MessageNum [si].sf_mft
1883; Message 1,<13,10>
1884
1885 mov cx,[si].sf_mode ; (cx) = open mode
1886 mov dx,ds ; (dx:si) = SFT address
1887 push cs
1888 pop ds ; (ds:bx) = MFT address
1889
1890;
1891; Not special file and no previous sft found OR normal SFT. We link it in
1892; at the head of the list.
1893;
1894; (dx:si) point to sft
1895; (ds:bx) point to mft
1896;
1897 les di,[bx].mft_sptr ; get first link
1898 mov word ptr [bx].mft_sptr,si ; link in this sft
1899 mov word ptr [bx].mft_sptr+2,dx ; link in this sft
1900 mov ds,dx
1901 mov word ptr [si].sf_chain,di
1902 mov word ptr [si].sf_chain+2,es
1903asc75: mov ds,dx ; point back to sft
1904
1905 clc
1906asc8: ret
1907
1908; the SFT is already in use... internal error
1909
1910asc9: push ax
1911 off ax,ascerr
1912 call INTERR ; NEVER RETURNS
1913ascerr db "ASC: sft already in use", 13, 10, 0
1914
1915 EndProc ASC
1916
1917
1918 BREAK <BCS - Bulk Close of SFTs>
1919
1920;******************* START OF SPECIFICATIONS ***********************************
1921;
1922; BCS - Bulk Close of SFTs
1923;
1924; BCS scans the MFT structures looking for SFTs that match a UID (and
1925; perhaps a PID). The SFTs are closed. The MFT name record is removed
1926; if all its SFTs are closed.
1927;
1928; BCS is called with a PID and a PID MASK. The SFT is closed if its UID
1929; matches the supplied UID AND (PID_ & PIDMASK) == PID_supplied
1930;
1931; We walk the MFT structure closing all relevant SFT's. There is no
1932; need for special handling of 70 handles or FCBs.
1933;
1934; Note that we call DOS_close to close the SFT; DOS_close in turn calls
1935; mftclose which may remove the SFT and even the MFT. This means that
1936; the MFT may vanish as we are working on it. Whenever we call
1937; DOS_close we'll know the next SFT and, if there is no next SFT we'll
1938; know the next MFT. (If the MFT were released a pointer to the carcass
1939; is not of any help. An MFT carcass cannot help find the next MFT
1940; record)
1941;
1942; ENTRY (AX) = UID to match
1943; (BX) = PID mask
1944; (DX) = PID value
1945; EXIT 'C' clear
1946; USES ALL
1947;
1948;******************* END OF SPECIFICATIONS *************************************
1949
1950 ASSUME SS:DOSGROUP
1951
1952 Procedure BCS,NEAR
1953
1954 push cs
1955 pop ds
1956
1957 Off SI,mft ; start at beginning of buffer
1958
1959; scan forward to the nearest name record (we may be at it now)
1960;
1961; (DS:SI) = record pointer
1962
1963bcs1: cmp [si].mft_flag,MFLG_FRE
1964 jl bcs16 ; at end of names, all done
1965 jg bcs2 ; have a name record
1966
1967bcs1$5: add si,[si].mft_len ; skip record and loop
1968 jmp bcs1
1969
1970bcs16: jmp bcs9
1971
1972bcs2: les di,[si].mft_sptr ; got name record - get first SFT
1973; run down SFT chain
1974;
1975; (es:di) = FBA next SFT
1976; (ds:si) = FBA name record
1977; (ax) = UID to match
1978; (bx) = PID mask
1979; (dx) = PID value
1980
1981bcs3: or di,di
1982 jz bcs1$5 ; at end of SFT chain
1983 cmp ax,es:[di].sf_UID
1984 jnz bcs4 ; not a match
1985 mov cx,es:[di].sf_PID
1986 and cx,bx ; apply mask
1987 cmp cx,dx
1988 jz bcs51 ; got a match
1989bcs4:
1990 les di,es:[di].sf_chain
1991 JMP bcs3 ; chain to next SFT
1992
1993
1994; We have an SFT to close
1995;
1996; (es:di) = FBA SFT to be closed
1997;
1998; (ds:si) = FBA name record
1999; (ax) = UID to match
2000; (bx) = PID mask
2001; (dx) = PID value
2002
2003bcs51: mov es:[di].sf_ref_count,1
2004 push ax
2005 push bx
2006 push dx ; save ID values (ax,bx,dx) and mask
2007 push ds
2008 push si ; save name record address (ds:si)
2009 mov si,word ptr es:[di].sf_chain
2010 or si,si
2011 jnz bcs7 ; isnt last sft, MFT will remain
2012
2013; yup, this is the last sft for this MFT, the MFT may evaporate. we have
2014; to find the next one NOW, and remember it
2015
2016 pop si ; undo saved name record address
2017 pop ds
2018bcs6: add si,[si].mft_len ; go to next guy
2019 cmp [si].mft_flag,MFLG_FRE
2020 jz bcs6 ; must be a non-free guy
2021 push ds
2022 push si ; resave our new next MFT
2023 sub si,si ; no next sft
2024
2025; Allright, we're ready to call the DOS.
2026;
2027; (es:di) = FBA sft to be closed
2028; ((sp)) = long address of current or next MFT
2029; ((sp)+4) = PID value
2030; ((sp)+6) = PID mask
2031; ((sp)+8) = UID value
2032
2033bcs7: mov WORD PTR ThisSFT,di
2034 mov WORD PTR ThisSFT+2,es
2035 mov es,word ptr es:[di].sf_chain+2
2036 SaveReg <es,si>
2037 call CPS ; clear JFN
2038 Context DS
2039
2040 CallInstall DOS_Close,multDos,1
2041
2042 ASSUME DS:NOTHING
2043
2044 RestoreReg <di,es> ; (es:DI) = offset of next sft
2045 pop si
2046 pop ds ; (DS:SI) = fwa of current or next MFT
2047 pop dx
2048 pop bx
2049 pop ax
2050 or di,di
2051 jnz bcs85 ; have more sft's
2052 JMP bcs1 ; look at this new MFT
2053bcs85: jmp bcs3
2054
2055; All Done
2056
2057bcs9: clc
2058
2059 ret
2060
2061 EndProc BCS
2062
2063 BREAK <CSL - Clear SFT Locks>
2064
2065;******************* START OF SPECIFICATIONS ***********************************
2066;
2067; CSL - Clear SFT Locks
2068;
2069; CSL clears any locks associated with this SFT.
2070;
2071; ENTRY (ES:DI) = SFT address
2072; EXIT (ES:DI) unchanged
2073; USES All but ES,DI
2074;
2075;******************* END OF SPECIFICATIONS *************************************
2076
2077 Procedure CSL,NEAR
2078
2079 mov si,es:[di].sf_MFT
2080 push cs
2081 pop ds
2082 lea bx,[si].mft_lptr ; (DS:BX) = addr of lock ptr
2083 mov si,[bx] ; (DS:SI) = fba first lock record
2084
2085; scan the locks looking for belongers.
2086;
2087; (es:di) = SFT address
2088; (ds:si) = this lock address
2089; (ds:bx) = address of link (offset value) to this lock (prev lock)
2090
2091csl1: or si,si
2092 jz csl3 ; done with lock list
2093 cmp di,word ptr [si].rlr_sptr
2094 jnz csl2 ; not my lock
2095 mov ax,es
2096 cmp ax,word ptr [si].rlr_sptr+2
2097 jnz csl2 ; not my lock
2098;
2099; Make sure that the lock REALLY belongs to the correct process
2100;
2101 cmp user_in_ax, (ServerCall shl 8) + 4 ; only check if ; @@01
2102 jnz csl15 ; process specific; @@01
2103 mov ax,Proc_ID
2104 cmp ax,[si].rlr_pid ; is process ID of lock = this PID?
2105 jnz csl2 ; nope, skip this lock
2106
2107; got a lock to remove
2108
2109csl15:
2110 mov dx,[si].rlr_next
2111 mov [bx],dx ; link him out
2112 mov ax,Frelock
2113 mov [si].rlr_next,ax
2114 mov Frelock,si
2115 mov si,dx ; (DS:SI) = next lock address
2116 JMP SHORT csl1
2117
2118 ERRNZ rlr_next ; lock is not ours... follow chain
2119csl2: mov bx,si
2120 mov si,[si].rlr_next
2121 JMP SHORT csl1
2122
2123; All done
2124
2125csl3: ret
2126
2127 EndProc CSL
2128
2129 ASSUME DS:NOTHING
2130
2131 BREAK <CUC - check usage conflicts>
2132
2133;******************* START OF SPECIFICATIONS ***********************************
2134;
2135; Use conflict table
2136;
2137; Algorithm:
2138;
2139; if ((newmode == COMPAT) or (oldmode == COMPAT))
2140; and (user ID's match)
2141; then accept
2142; else
2143; for new and old mode, compute index of (SH*3)+ACC
2144; shift right table[new_index] by old_index+2;
2145; 'C' set if FAIL
2146;
2147; The bit in the old_index position indicates the success or failure. 0
2148; => allow access, 1 => fail access
2149;
2150;******************* END OF SPECIFICATIONS *************************************
2151
2152 PUBLIC CUCA
2153
2154CUCA: DW 0ffffh ; Compat Read
2155 DW 0ffffh ; Compat Write
2156 DW 0ffffh ; Compat Read/Write
2157 DW 0ffffh ; Deny R/W Read
2158 DW 0ffffh ; Deny R/W Write
2159 DW 0ffffh ; Deny R/W Read/Write
2160 DW 0df7fh ; Deny W Read
2161 DW 0dbffh ; Deny W Write
2162 DW 0dfffh ; Deny W Read/Write
2163 DW 0beffh ; Deny R Read
2164 DW 0b7ffh ; Deny R Write
2165 DW 0bfffh ; Deny R Read/Write
2166 DW 01c7fh ; Deny None Read
2167 DW 003ffh ; Deny None Write
2168 DW 01fffh ; Deny None Read/Write
2169
2170; 4443 3322 2111 000
2171; Deny/Compat / DDDD DDDD DDDD CCCx
2172; DenyRead / R RR RRR
2173; DenyWrite 1st Access =< WW WWWW
2174; AccessRead \ R RR RR RR R R R
2175; AccessWrite \ WW W W WW WW WW
2176; x 1111 1111 1111 1111
2177; C R 00 1111 1111 1111 1111 ffff
2178; C W 01 1111 1111 1111 1111 ffff
2179; C RW 02 1111 1111 1111 1111 ffff
2180
2181; DRWR 10 1111 1111 1111 1111 ffff
2182; DRW W 11 1111 1111 1111 1111 ffff
2183; DRWRW 12 1111 1111 1111 1111 ffff
2184; D WR 20 1101 1111 0111 1111 df7f
2185
2186; D W W 21 1101 1011 1111 1111 dbff
2187; D WRW 22 1101 1111 1111 1111 dfff
2188; DR R 30 1011 1110 1111 1111 beff
2189; DR W 31 1011 0111 1111 1111 b7ff
2190
2191; DR RW 32 1011 1111 1111 1111 bfff
2192; D R 40 0001 1100 0111 1111 1c7f
2193; D W 41 0000 0011 1111 1111 03ff
2194; D RW 42 0001 1111 1111 1111 1fff
2195
2196; In order to allow the greatest number of accesses, compatability read mode
2197; is treated as deny-write read. The other compatability modes are treated
2198; as deny-both.
2199
2200;******************* START OF SPECIFICATIONS ***********************************
2201;
2202; CUC - check usage conflicts
2203;
2204; CUC is called to see if a would-be open would generate a share
2205; conflict with an existing open. See CUCA for the algorithm and table
2206; format.
2207;
2208; ENTRY (BX) = FBA MFT name record
2209; (DS:SI) = SFT address
2210; EXIT 'C' clear if OK
2211; 'C' set if conflict
2212; (ax) = error code
2213; USES ALL but arguments (BX, DS:SI)
2214;
2215;******************* END OF SPECIFICATIONS *************************************
2216
2217 Procedure CUC,NEAR
2218
2219 push ds
2220 pop es
2221 mov di,si ; (es:di) = FBA SFT record
2222 call gom ; get open mode
2223 mov ch,al
2224 and ch,sharing_mask ; (ch) = new guy share
2225 jz cuc0 ; new guy is compatability mode
2226 mov ch,sharing_mask
2227cuc0: call csi ; compute share index
2228 add ax,ax ; *2 for word index
2229 xchg ax,si ; (si) = share table index
2230 push cs
2231 pop ds ; (ds:bx) = FBA MFT record
2232 mov dx,WORD PTR CUCA[si] ; (dx) = share mask
2233 lds si,[bx].mft_sptr ; (ds:si) = first sft guy
2234
2235; ready to do access compares.
2236;
2237; (ds:si) = address of next sft
2238; (es:di) = address of new sft
2239; (dx) = share word from CUCA
2240; (cs:bx) = MFT offset
2241; (ch) = 0 if new SFT is compatibilty mode, else sharing_mask
2242
2243cuc1: or si,si
2244 jz cuc9 ; at end of chain, no problems
2245 call gom ; if not FCB, then mode in al is good
2246 mov ah,al
2247 and ah,sharing_mask ; (ah) = sharing mode
2248 or ah,ch ; (ah) = 0 iff new and old is SH_COMP
2249 jnz cuc2 ; neither is SH_COMP
2250
2251; Both the old and the new guy are SH_COMP mode. If the UIDs match,
2252; step onward. If they don't match do normal share check.
2253
2254 mov bp,es:[di].sf_UID
2255 cmp bp,[si].sf_UID
2256 jz cuc20 ; equal => next sft to check
2257
2258cuc2: call csi ; compute the share index
2259 inc ax
2260 inc ax
2261 xchg al,cl ; (cl) = shift count
2262 mov ax,dx
2263 sar ax,cl ; select the bit
2264 jc cuc8 ; a conflict!
2265cuc20:
2266 lds si,[si].sf_chain
2267 JMP cuc1 ; chain to next SFT and try again
2268
2269; Have a share conflict
2270
2271cuc8: mov ax,error_sharing_violation ; assume share conflict
2272 stc
2273
2274; done with compare. Restore regs and return
2275;
2276; 'C' set as appropriate
2277; (es:di) = new SFT address
2278; (ax) set as appropriate
2279; (bx) = MFT offset
2280
2281cuc9: push es
2282 pop ds
2283 mov si,di
2284
2285 ret
2286
2287 EndProc CUC
2288
2289 BREAK <csi - compute share index>
2290
2291;******************* START OF SPECIFICATIONS ***********************************
2292;
2293; csi - compute share index
2294;
2295;
2296; If the mode byte has a leading 7 then it is interpreted as a 0
2297; csi turns a mode byte into an index from 0 to 14:
2298;
2299; (share index)*3 + (access index)
2300;
2301; ENTRY (al) = mode byte
2302; EXIT (ax) = index
2303; USES AX, CL
2304;
2305;******************* END OF SPECIFICATIONS *************************************
2306
2307 Procedure CSI,NEAR
2308
2309 mov ah,al
2310 and ah,access_mask ; (ah) = access bits
2311 and al,sharing_mask ; (al) = share bites
2312 ERRNZ sharing_mask-0F0h
2313 cmp al,sharing_net_FCB
2314 jnz csi1
2315 xor al,al
2316csi1:
2317 shr al,1
2318 shr al,1
2319 shr al,1
2320 mov cl,al ; (cl) = SHVAL*2
2321 shr al,1
2322 add al,cl ; (al) = SHVAL*3
2323 add al,ah ; (al) = SH*3 + ACC
2324 sub ah,ah
2325
2326 ret
2327
2328 EndProc CSI
2329
2330 Break <GOM - get open mode>
2331
2332;******************* START OF SPECIFICATIONS ***********************************
2333;
2334; GOM - get open mode
2335;
2336; Find the correct open mode given the encoded sf_mode. Note that files
2337; marked READ-ONLY and are opened in compatability read-only are treated as
2338; deny-write read-only. FCB opens are sharing_compat open_for_both and
2339; net FCB opens are sharing_compat
2340;
2341; Entry: (DS:SI) points to SFT
2342; Exit: (AL) has correct mode
2343; Uses: (AX)
2344;******************* END OF SPECIFICATIONS *************************************
2345
2346 Procedure GOM,NEAR
2347
2348 mov ax,[si].sf_mode
2349 TEST AX,sf_IsFCB
2350 jz gom1 ; if not FCB, then mode in al is good
2351 mov al,sharing_compat+open_for_both
2352gom1:
2353 mov ah,al
2354 and ah,sharing_mask
2355 cmp ah,sharing_net_FCB ; is sharing from net FCB?
2356 jnz gom2 ; no, got good mode
2357 and al,access_mask ; yes, convert to compat mode sharing
2358 or al,sharing_compat
2359;
2360; The sharing mode and access mode in AL is now correct for the file. See if
2361; mode is compatability. If so and file is read-only, convert access mode to
2362; deny-write read.
2363;
2364gom2:
2365 mov ah,al
2366 and ah,sharing_mask
2367 retnz ; not compatability, return.
2368 test [si].sf_attr,attr_read_only
2369 retz ; not read-only
2370 mov al,sharing_deny_write + open_for_read
2371
2372 ret
2373
2374 EndProc GOM
2375
2376 SHARE ENDS
2377
2378 END
2379 ELSE
2380CODE ENDS
2381 ENDIF
2382 END ; This can't be inside the if
2383; mode is compatability. If so and file is read-only, convert access mode to
2384; deny-write read.
2385;
2386gom2:
2387 mov ah,al
2388 and ah,sharing_mask
2389 retnz ; not compatability, return.
2390 test [si].sf_attr,attr_read_only
2391 retz ; not read-only
2392 mov al,sharing_deny_write + open_for_read
2393
2394 ret
2395
2396 EndProc GOM
2397
2398 SHARE ENDS
2399
2400 END
2401 ELSE
2402CODE ENDS
2403 ENDIF
2404 END ; This can't be inside the if
2405 \ No newline at end of file