From 2d04cacc5322951f187bb17e017c12920ac8ebe2 Mon Sep 17 00:00:00 2001 From: Mark Zbikowski Date: Thu, 25 Apr 2024 21:24:10 +0100 Subject: MZ is back! --- v4.0/src/CMD/SHARE/GSHARE.ASM | 2405 +++++++++++++++++++++++++++++++ v4.0/src/CMD/SHARE/GSHARE2.ASM | 2979 +++++++++++++++++++++++++++++++++++++++ v4.0/src/CMD/SHARE/MAKEFILE | 67 + v4.0/src/CMD/SHARE/SHARE.LNK | 9 + v4.0/src/CMD/SHARE/SHARE.SKL | 27 + v4.0/src/CMD/SHARE/SHAREHDR.INC | 72 + v4.0/src/CMD/SHARE/SHARELNK.ASM | 213 +++ v4.0/src/CMD/SHARE/SHARESR.ASM | 73 + 8 files changed, 5845 insertions(+) create mode 100644 v4.0/src/CMD/SHARE/GSHARE.ASM create mode 100644 v4.0/src/CMD/SHARE/GSHARE2.ASM create mode 100644 v4.0/src/CMD/SHARE/MAKEFILE create mode 100644 v4.0/src/CMD/SHARE/SHARE.LNK create mode 100644 v4.0/src/CMD/SHARE/SHARE.SKL create mode 100644 v4.0/src/CMD/SHARE/SHAREHDR.INC create mode 100644 v4.0/src/CMD/SHARE/SHARELNK.ASM create mode 100644 v4.0/src/CMD/SHARE/SHARESR.ASM (limited to 'v4.0/src/CMD/SHARE') 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 @@ + Title Share_1 - IBM CONFIDENTIAL +; $SALUT (0,36,41,44) + include SHAREHDR.INC +; +; Label: "The DOS SHARE Utility" +; "Version 4.00 (C) Copyright 1988 Microsoft" +; "Licenced Material - Program Property of Microsoft" +; +;******************* END OF SPECIFICATIONS ************************************* + +extrn fnm:near, rsc:near, rmn:near, cps:near, ofl:near, sle:near, interr:near + + NAME Sharer + + .xlist + .xcref + INCLUDE DOSSYM.INC + include dpl.asm + .cref + .list + +AsmVars + +Installed = TRUE ; for installed version + +OFF Macro reg,val + IF installed + mov reg,OFFSET val + ELSE + mov si,OFFSET DOSGROUP:val + ENDIF + ENDM + +ERRNZ Macro x + IF x NE 0 + %out ERRNZ failed + ENDIF + ENDM +; if we are installed, then define the base code segment of the sharer first + + IF Installed +Share SEGMENT PARA PUBLIC 'SHARE' +Share ENDS +; include the rest of the segment definitions for normal msdos +; We CANNOT include dosseg because start is not declared para in that file + +; $SALUT (4,9,17,36) + +START SEGMENT PARA PUBLIC 'START' +START ENDS + +CONSTANTS SEGMENT WORD PUBLIC 'CONST' +CONSTANTS ENDS + +DATA SEGMENT WORD PUBLIC 'DATA' +DATA ENDS + +TABLE SEGMENT BYTE PUBLIC 'TABLE' +TABLE ENDS + +CODE SEGMENT BYTE PUBLIC 'CODE' +CODE ENDS + +LAST SEGMENT PARA PUBLIC 'LAST' +LAST ENDS + +DOSGROUP GROUP START,CONSTANTS,DATA,TABLE,CODE,LAST + ELSE + include dosseg.asm + ENDIF + +DATA SEGMENT WORD PUBLIC 'DATA' + Extrn ThisSFT:DWORD ; pointer to SFT entry + Extrn User_ID:WORD + Extrn Proc_ID:WORD + Extrn WFP_START:WORD + Extrn BytPos:DWORD + extrn OpenBuf:BYTE + extrn user_in_ax:WORD + IF debug + Extrn BugLev:WORD + Extrn BugTyp:WORD + include bugtyp.asm + ENDIF +DATA ENDS + +; if we are not installed, then the code here is just part of the normal +; MSDOS code segment otherwise, define our own code segment + + .sall + IF NOT INSTALLED +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + ELSE +Share SEGMENT PARA PUBLIC 'SHARE' + ASSUME SS:DOSGROUP,CS:SHARE + ENDIF + + extrn MFT:BYTE + extrn skip_check:BYTE + + include mft.inc + + PUBLIC FreLock,Serial + + IF installed +Frelock DW ? ; FWA of lock free list + ELSE +Frelock DW OFFSET DOSGROUP:lck8 ; FWA of lock free list + ENDIF +Serial DW 0 ; serial number +DS_Org dw 0 ;an000;DS on entry to routine + +ZERO EQU 0 +ONE EQU 1 + +FRAME struc + +SavedBP dw ? +RetOFF dw ? +Parm_1 dw ? +Parm_2 dw ? + +FRAME ends + +; $SALUT (4,4,9,41) + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; MSDOS MFT Functions +; +; The Master File Table (MFT) associates the cannonicalized pathnames, +; lock records and SFTs for all files open on this machine. +; +; These functions are supplied to maintain the MFT and extract +; information from it. All MFT access should be via these routines so +; that the MFT structure can remain flexible. +; +;******************* END OF SPECIFICATIONS ************************************* + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; mft_enter - make an entry in the MFT +; +; mft_enter is called to make an entry in the MFT. +; mft_enter checks for a file sharing conflict: +; No conflict: +; A new MFT entry is created, or the existing one updated, +; as appropriate. +; Conflicts: +; The existing MFT is left alone. Note that if we had to +; create a new MFT there cannot be, by definition, sharing +; conflicts. +; If no conflict has been discovered, the SFT list for the file is +; checked for one that matches the following conditions: +; +; If mode == 70 then +; don't link in SFT +; increment refcount +; If mode&sfIsFCB and userids match and process ids match then +; don't link in SFT +; +; ENTRY ThisSFT points to an SFT structure. The sf_mode field +; contains the desired sharing mode. +; WFP_Start is an offset from DOSGroup of the full pathname for +; the file +; User_ID = 16-bit user id of issuer +; Proc_ID = 16-bit process id of issuer +; (DS) = (SS) = DOSGroup +; EXIT 'C' clear if no error' +; 'C' set if error +; (ax) = error code +; USES ALL but DS +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure mft_enter,NEAR + +; int 3 + nop + nop + + EnterCrit critShare + + DOSAssume SS ,"MFT_Enter entry" + ASSUME ES:NOTHING,SS:DOSGROUP + push ds + +; find or make a name record + + mov si,WFP_Start ; (DS:SI) = FBA of file name + mov al,1 ; allow creation of MFT entry + push es + + ASSUME DS:NOTHING + + call FNM ; find or create name in MFT + pop es + mov ax,error_sharing_buffer_exceeded + jc ent9 ; not enough space +; +; (bx) = fwa name record +; + lds si,ThisSFT + call ASC ; try to add to chain + +; As noted above, we don't have to worry about an "empty" name record +; being left if ASC refuses to add the SFT - ASC cannot refuse if we had +; just created the MFT... + +; return. +; +; 'C' and (Ax) setup appropriately + +ent9: pop ds + + LeaveCrit critShare + + ret + + EndProc mft_enter + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; MFTclose +; +; MFTclose(SFT) +; +; MFTclose removes the SFT entry from the MFT structure. If this was +; the last SFT for the particular file the file's entry is also removed +; from the MFT structure. If the sharer is installed after some +; processing has been done, the MFT field of the SFTs will be 0; we must +; ignore these guys. +; +; If the sft indicates FCB, we do nothing special. The SFT behaves +; EXACTLY like a normal handle. +; +; If the sft indicates mode 70 then we do nothing special. These are +; normal HANDLES. +; +; Note that we always care about the SFT refcount. A refcount of 1 +; means that the SFT is going idle and that we need to remove the sft +; from the chain. +; +; ENTRY (ES:DI) points to an SFT structure +; (DS) = (SS) = DOSGroup +; EXIT NONE +; USES ALL but DS, ES:DI +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure MFTclose,NEAR + +; int 3 + nop + nop + + EnterCrit critShare + + DOSAssume SS,,"MFTClose entry" + ASSUME ES:NOTHING + mov ax,es:[di].sf_MFT + + fmt TypShare,LevShEntry,<"MFTClose by $x:$x of $x:$x ($x)\n">, + + or ax,ax + jz mcl10 ; No entry for it, ignore (carry clear) + push ds + push es + push di +;;;call CSL ; clear SFT locks ;AC008; + + ASSUME DS:NOTHING + + mov ax,es:[di].sf_ref_count ; (ax) = ref count +; +; We need to release information in one of two spots. First, when the SFT has +; a ref count of 0. Here, there are no more referents and, thus, no sharing +; record need be kept. Second, the ref count may be -1 indicating that the +; sft is being kept but that the sharing information is no longer needed. +; This occurs in creates of existing files, where we verify the allowed +; access, truncate the file and regain the access. If the truncation +; generates an error, we do NOT want to have the access locked down. +; + + + OR AX,AX + jz mcl85 ; ref count is 0 - don't dechain + inc ax ; -1 + 1 = 0. Busy sft. + jnz mcl9 +mcl85: + call CSL ; clear SFT locks ;AC008; + call RSC ; remove sft from chain + jnz mcl9 ; not the last sft for this name + call RMN ; remove name record +mcl9: + pop di ; restore regs for exit + pop es + pop ds +mcl10: + LeaveCrit critShare + + ret + + EndProc MFTclose + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; MFTcloseU +; +; MFTcloseM(UID) +; +; MFTcloseM removes all entrys for user UID from the MFT structure. We +; walk the MFT structure closing all relevant SFT's for the user. +; We do it the dumb way, iterating closes until the SF ref count is +; 0. +; +; ENTRY User_ID = 16-bit user id of issuer +; (SS) + DOSGroup +; EXIT 'C' clear +; USES ALL +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure MFTclU,NEAR + +; int 3 + nop + nop + + ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP + + EnterCrit critShare + mov ax,User_ID + + fmt TypShare,LevShEntry,<"\nCloseUser $x\n">, + + sub bx,bx ; insensitive to PID + sub dx,dx + invoke BCS ; bulk close the SFTs + LeaveCrit critShare + return + EndProc MFTclU + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; MFTcloseP +; +; MFTcloseP(PID, UID) +; +; MFTcloseP removes all entrys for process PID on machine MID from the +; MFT structure. We walk the MFT structure closing all relevant +; SFT's. Do it the dumb way by iterating closes until the SFTs +; disappear. +; +; ENTRY (SS) = DOSGROUP +; User_ID = 16-bit user id of issuer +; Proc_ID = 16-bit process id of issuer +; EXIT 'C' clear +; USES ALL +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure MFTcloseP,NEAR + +; int 3 + nop + nop + + ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP + + EnterCrit critShare + mov ax,User_ID + mov bx,-1 + mov dx,Proc_ID + + fmt TypShare,LevShEntry,<"\nClose UID/PID $x:$x\n">, + + call BCS ; Bulk close the SFTs + LeaveCrit critShare + + ret + + EndProc MFTcloseP + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; MFTcloseN +; +; MFTcloseN(name) +; +; MFTcloseN removes all entrys for the given file from the MFT +; structure. +; +; NOTE: this function is used infrequently and need not be fast. +; (although for typical use it's not all that slow...) +; +; ENTRY DS:SI point to dpl. +; (SS) = DOSGroup +; EXIT 'C' clear if no error +; 'C' set if error +; AX = error_path_not_found if not currently open +; USES ALL +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure MFTcloN,NEAR + +; int 3 + nop + nop + + ASSUME SS:DOSGROUP,ES:NOTHING,DS:NOTHING + + EnterCrit critShare + MOV DX,[SI.DPL_DX] + MOV DS,[SI.DPL_DS] + mov si,dx ; (DS:SI) = fwa name + sub al,al ; don't create if not found + push ds + push si + call FNM ; find name in MFT + mov ax,error_path_not_found ; assume error + jc mclo9 ; not found exit + +; Name was found. Lets yank the SFT entrys one at a time. + +mclo1: les di,[bx].mft_sptr ; (ES:DI) = SFT address + mov WORD PTR ThisSFT,di + mov WORD PTR ThisSFT+2,es ; point to SFT + cmp es:[di].sf_ref_count,1 + jnz mclo15 + call CPS +mclo15: + Context DS + + IF installed + MOV AX,(multDOS SHL 8) + 1 + INT 2FH + ELSE + call DOS_Close + ENDIF +mclo2: + + ASSUME DS:NOTHING + + pop si + pop ds + push ds + push si + sub al,al ; don't create an entry + call FNM ; find the name gain + jnc mclo1 ; got still more + clc + +; exit. 'C' and (ax) setup +; +; (TOS+2:TOS) = address of ASCIZ string + +mclo9: pop si ; clean stack + pop ds + LeaveCrit critShare + + ret + + EndProc MFTcloN + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; NAME: Set_Mult_Block - Set Multiple Block Locks +; +; FUNCTION: Set_Mult_Block sets a lock on 1 or more specified ranges +; of a file. An error is returned if any lock range conflicts +; with another. Ranges of Locks are cleared via Clr_Mult_Block. +; +; In DOS 3.3 only one lock range could be set at a time using +; Set_Block. For DOS 4.00 this routine will replace Set_Block +; in the jump table and will make repeated calls to Set_Block +; in order to process 1 or more lock ranges. +; +; NOTE: - This is an all new interface to IBMDOS +; +; INPUT: (AL) = 0 - lock all +; = 80 - lock write +; (CX) = the number of lock ranges +; (DS:DX) = pointer to the range list +; (ES:DI) = SFT address +; User_ID = 16-bit user id of issuer +; Proc_ID = 16-bit process id of issuer +; (SS) = DOSGroup +; +; OUTPUT: Lock records filled in for all blocks specified +; +; REGISTERS USED: ALL but DS +; (NOT RESTORED) +; +; LINKAGE: IBMDOS Jump Table +; +; EXTERNAL Invoke: Load_Regs, Set_Block, Clr_Block +; REFERENCES: +; +; NORMAL 'C' clear if no error +; EXIT: +; +; ERROR 'C' set if error +; EXIT: (ax) = error code +; ('error_lock_violation' if conflicting locks) +; +; CHANGE 04/15/87 - First release +; LOG: +; +;******************* END OF SPECIFICATIONS ************************************* +;******************+ START OF PSEUDOCODE +************************************** +; +; START Set_Mult_Block +; +; count = start_count +; search till count = 0 +; invoke Load_Regs +; invoke Set_Block +; exit if error +; clear_count = start_count - current_count +; loop till clear_count = 0 +; invoke Load_Regs +; invoke Clr_Block +; leave if error +; end loop +; set error status +; orelse +; endloop +; set successful status +; endsrch +; if error status +; load return code +; endif +; return +; +; END Set_Mult_Block +; +;******************+ END OF PSEUDOCODE +************************************** + + Procedure Set_Mult_Block,NEAR + +; PUSH DS ;ICE +; push bx ;ICE +; push ax ;ICE + +; mov bx,0140H ;ICE +; xor ax,ax ;ICE +; mov ds,ax ;ICE +; mov ax,word ptr ds:[bx] ;ICE +; mov word ptr ds:[bx],ax ;ICE + +; pop ax ;ICE +; pop bx ;ICE +; POP DS ;ICE + + + + EnterCrit critShare ; ;AN000; + + ASSUME ES:NOTHING,DS:NOTHING ; ;AN000; +; set up for loop + +; WE HAVE: (from IBMDOS) | WE NEED: (for Set_Block) + +; (AL) = 0 - lock all | (BX) = 0 lock all operations +; = 80- lock write | = 1 lock write operations +; (CX) = the number of lock ranges | (CX:DX) = offset of area +; (DS:DX) = pointer to the range list | (SI:AX) = length of area +; (ES:DI) = SFT address | (ES:DI) = SFT address + +; int 3 + nop + nop + + mov DS_Org,ds ;an000;save entry DS + + Context DS ; ;AN000; + CMP CX,01h ;DO WE HAVE A COUNT? ;AN000; + +;; $if ae ; if the count was valid ;AN000; +; $if e ; if the count was valid ;AC006; + JNE $$IF1 + +;; PUSH CX ; count = start_count ;AN000; +;; PUSH DX ; save pointer to range list ;AN000; + MOV BP,DX ; save current index into list ;AN000; +;; AND AX,0080H ; clear high byte and be sure low is ;AN000; + ; set if applicable +;; ROL AL,1 ; move high bit to bit 0 +;; MOV BX,AX ; SET UP TYPE OF LOCK ;AN000; + +;; $do ; loop till count = 0 ;AN000; +;; cmp cx,00 ;an000;see if at end +;; $leave e ;an000;exit if at end +;; push cx ;an000;save cx - our counter +;; push di ;an000;save di - our SFT pointer + call load_regs ;an000;load the registers for call + ; to set_block + call set_block ;an000;set the lock block +;; pop di ;an000;restore our SFT pointer +;; pop cx ;an000;restore cx - our counter +;; $leave c ;an000;on error exit loop +;; dec cx ;an000;decrease counter +;; $enddo ;an000;end loop + +;; $if c ;an000;if an error occurred +;; pop dx ;an000;restore range list pointer +;; pop ax ;an000;obtain original count +;; sub ax,cx ;an000;determine how many locks set +;; mov cx,ax ;an000;set the loop counter with count +;; mov bp,dx ;an000;set bp to point to range list +;; $do ;an000;while cx not = 0 +;; cmp cx,00 ;an000;at end? +;; $leave e ;an000;yes, exit +;; push cx ;an000;save cx - our counter +;; push di ;an000;save di - our SFT pointer +;; call load_regs ;an000;load the registers for call + ; to clr_block +;; call clr_block ;an000;clear the locks +;; pop di ;an000;restore our SFT pointer +;; pop cx ;an000;restore cx - our counter +;; $leave c ;an000;on error exit +;; dec cx ;an000;decrease counter +;; $enddo ;an000; +;; stc ;an000;signal an error occurred +;; $else ;an000;no error occurred in locking +;; pop ax ;an000;clear off the stack +;; pop ax ;an000; to balance it +;; clc ;an000;signal no error occurred +;; $endif ;an000; +; $else ;an000;cx was 0 - this is an error + JMP SHORT $$EN1 +$$IF1: + stc ;an000;signal an error occurred +; $endif ; ;an000; +$$EN1: + +; $if c ; if there was an error ;AN000; + JNC $$IF4 + MOV AX,error_lock_violation ; load the return code ;AN000; +; $endif ; endif there was an error ;AN000; +$$IF4: + + LeaveCrit critShare ; ;AN000; + + ret ; return - all set ;AN000; + + EndProc Set_Mult_Block + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; NAME: Load_Regs - Load Registers for ?_Block calls +; +; FUNCTION: This subroutine loads the High and Low Offsets and the +; High and Low lengths for Lock ranges from the Range List. +; +; INPUT: (DS_Org:PB) - Range list entry to be loaded +; +; OUTPUT: (DX) - Low Offset +; (CX) - High Offset +; (AX) - Low Length +; (SI) - High Length +; +; REGISTERS USED: AX CX DX BP SI +; (NOT RESTORED) +; +; LINKAGE: Called by: Set_Mult_Block, Clr_Mult_Block +; +; EXTERNAL none +; REFERENCES: +; +; NORMAL none +; EXIT: +; +; ERROR none +; EXIT: +; +; CHANGE 04/15/87 - first release +; LOG: +; +;******************* END OF SPECIFICATIONS ************************************* +;******************+ START OF PSEUDOCODE +************************************** +; +; START Load_Regs +; +; recover index into range list +; advance pointer to next entry +; load DX - Low Offset +; load CX - High Offset +; load AX - Low Length +; load SI - High Length +; return +; +; END Load_Regs +; +;******************+ END OF PSEUDOCODE +************************************** + + Procedure Load_Regs,NEAR + + push ds ; save our DS ;an000; + mov ds,DS_Org ; get range list segment ;an000; + mov si,bp ; recover pointer ;AN000; + ADD BP,08h ; move to next entry in list ;AN000; + MOV DX,[SI] ; low position ;AN000; + MOV CX,[SI+2] ; high position ;AN000; + MOV AX,[SI+4] ; low length ;AN000; + MOV SI,[SI+6] ; high length ;AN000; + pop ds ; restore DS ;an000; + + ret ; ;AN000; + + EndProc Load_Regs + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; NAME: Clr_Mult_Block - Clear Multiple Block Locks +; +; FUNCTION: Clr_Mult_Block removes the locks on 1 or more specified +; ranges of a file. An error is returned if any lock range +; does not exactly match. Ranges of Locks are set via +; Set_Mult_Block. +; +; In DOS 3.3 only one lock range could be cleared at a time +; using Clr_Block. For DOS 4.00 this routine will replace +; Clr_Block in the jump table and will make repeated calls +; to Set_Block in order to process 1 or more lock ranges. +; +; NOTE: - This is an all new interface to IBMDOS +; - an unlock all 'lock all' request will unlock both +; 'lock all' and 'lock write'. +; - an unlock all 'lock write' request will not unlock +; 'lock all's. It will only unlock 'lock write's. +; (if you can understand the above statement, +; understanding the code will be easy!) +; +; INPUT: (AL) = 0 - lock all +; = 80- lock write +; (CX) = the number of lock ranges - NB: all if -1 *** +; (DS:DX) = pointer to the range list +; (ES:DI) = SFT address +; User_ID = 16-bit user id of issuer +; Proc_ID = 16-bit process id of issuer +; (SS) = DOSGroup +; +; OUTPUT: Lock records filled in for all blocks specified +; +; REGISTERS USED: ALL but DS +; (NOT RESTORED) +; +; LINKAGE: IBMDOS Jump Table +; +; EXTERNAL Invoke: Load_Regs, Set_Block, Clr_Block, Clr_List +; REFERENCES: +; +; NORMAL 'C' clear if no error +; EXIT: +; +; ERROR 'C' set if error +; EXIT: (ax) = error code +; ('error_lock_violation' if conflicting locks) +; +; CHANGE 04/15/87 - First release +; LOG: +; +;******************* END OF SPECIFICATIONS ************************************* +;******************+ START OF PSEUDOCODE +************************************** +; +; START Clr_Mult_Block +; +; if count is valid and +; if file (SFT) is 'shared' then +; if count = all +; find first RLR +; loop till all RLR cleared +; if PROC_ID matches and +; if UID matches and +; if SFT matches then +; if ulocking lock_all or +; if this RLR is lock_write +; clear the lock +; endif +; endif +; find next RLR +; end loop +; else +; invoke Clr_List +; endif +; set successful status +; else +; set error status +; endif +; if error +; load return code +; endif +; +; ret +; +; END Clr_Mult_Block +; +;******************+ END OF PSEUDOCODE +************************************** + + Procedure clr_mult_block,NEAR + + +lock_all equ 0h + +; PUSH DS ;ICE +; push bx ;ICE +; push ax ;ICE + +; mov bx,0140H ;ICE +; xor ax,ax ;ICE +; mov ds,ax ;ICE +; mov ax,word ptr ds:[bx] ;ICE +; mov word ptr ds:[bx],ax ;ICE + +; pop ax ;ICE +; pop bx ;ICE +; POP DS ;ICE + + EnterCrit critShare ; ;AN000; + + ASSUME ES:NOTHING,DS:NOTHING ; ;AN000; + +; int 3 + nop + nop + + mov DS_Org,DS ;an000;save entry DS + + Context DS ; ;AN000; + + CMP CX,01h ; do we have a count? ;AN000; +;; $IF AE,AND ; IF A VALID COUNT +; $IF E,AND ; IF A VALID COUNT ;AC006; + JNE $$IF6 + cmp es:[di].sf_mft,0 ; is this SFT shared? ;AN000; +; $IF NE ; AND IF FILE IS 'SHARED' THEN + JE $$IF6 + +; WE HAVE: (from IBMDOS) | WE NEED: + +; (AL) = 0 - lock all | (AX) = 0 lock all operations +; = 80- lock write | = 1 lock write operations +; (CX) = - 1 (unlock all locks) | (DS) = CS +; | (DS:DI) = previous RLR +; | (DS:SI) = current RLR +; (ES:DI) = current SFT | + +;; and ax,0080h ;be sure it is set right (mask 80 bit) ;AC002; + ; existing interface +;; rol al,1 ;put high bit in bit 0 ;AC002; + +;; CMP CX,-1h ; ;AN000; +;; $IF E ; IF unlock all locks then ;AN000; + +;; push cs ; ;AN000; +;; pop ds ; ;AN000; +;; mov cx,di ; ES:CX is the SFT ;AN004; + +; ASSUME ds:nothing + +;; mov si,es:[di].sf_mft ; DS:SI points to MFT ;AN000; + +;; lea di,[si].mft_lptr ; DS:DI = addr of ptr to lock record ;AN000; +;; mov si,[di] ; DS:SI = address of 1st lock record ;AN000; + +;; $DO ; loop through the RLR's ;AN000; + +; DS:DI = points to previous RLR or MFT if no RLR. +; DS:SI = points to current RLR +; ES:CX = SFT address +; AX = lock type + +;; and si,si ; are we at the end of the chain? ;AN000; +;; $LEAVE Z ; we'er done with CF = 0 ;AN000; + +;; mov bp,[si].rlr_pid ; get PROC_ID ;AN000; +;; cmp bp,PROC_ID ; is it ours? ;AN000; +;; $IF E,AND ; ;AN000; +;; mov bp,es ; ;AN000; +;; cmp bp,WORD PTR [si].rlr_sptr+2 ; ;AC004; +;; $IF E,AND ; ;AN000; +;; cmp cx,WORD PTR [si].rlr_sptr ; ;AC004; +;; mov si,[di] ; restore pointer to current (using ;AN000; + ; previous) +;; $IF E ; if it is ours ;AN000; + +; this is it. its OURS ! + +;; cmp ax,lock_all ; ;AN000; + +;; $IF E,OR ; if unlocking all or ;AN000; + +;; mov bp,[si].rlr_type ; get lock type ;AN000; +;; cmp bp,rlr_lall ; is it lock all? ;AN000; + +;; $IF NE ; if not a LOCK ALL lock ;AN000; + +; remove the RLR from the chain + +;; mov bx,[si].rlr_next ; get the pointer to the next RLR ;AN000; +;; mov [di],bx ; install it in the last ;AN000; + +; put defunct lock record on the free chain + +;; mov bx,Frelock ; ;AN000; +;; mov [si].rlr_next,bx ; ;AN000; +;; mov Frelock,si ; ;AN000; +;; mov si,di ; back up to last ;AN000; + +;; $ENDIF ; should we unlock it ;AN000; + +;; $ENDIF ; it was ours! ;AN000; + +; advance to next RLR + +;; mov di,si ; load address of next RLR ;AN000; +;; mov si,[di] ; update pointer to next RLR ;AN000; + +;; $ENDDO ; loop back to the start ;AN000; + +;; $ELSE ; else, its a LIST ! ;AN000; + +; set up for loop + +; WE HAVE: (from IBMDOS) | WE NEED: (for Clr_Block) + +; (AX) = 0 - lock all | (BX) = 0 lock all operations +; = 1 - lock write | = 1 lock write operations +; (CX) = the number of lock ranges | (CX:DX) = offset of area +; (DS:DX) = pointer to the range list | (SI:AX) = length of area +; (ES:DI) = SFT address | (ES:DI) = SFT address + +;; PUSH CX ; count = start_count ;AN000; +;; PUSH DX ; save pointer to range list ;AN000; + MOV BP,DX ; save current index into list ;AN000; +;; MOV BX,AX ; SET UP TYPE OF LOCK ;AN000; + + call Clr_List ; call Clr_List to process the list ;AN000; + +;; $ENDIF ; ;AN000; + +; $ELSE ; NOT VALID + JMP SHORT $$EN6 +$$IF6: + + STC ; ;AN000; + +; $ENDIF ; VALID/INVALID ;AN000; +$$EN6: + +; $IF C ; if carry is set ;AN000; + JNC $$IF9 + MOV AX,error_lock_violation ; load error condition ;AN000; +; $ENDIF ; carry not set ;AN000; +$$IF9: + + LeaveCrit critShare ; ;AN000; + + ret ; return - all set ;AN000; + + EndProc clr_mult_block + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; NAME: Clr_List - Clear a list of user specified locks +; +; FUNCTION: Clr_List makes multiple calls to Clr_Block to clear +; multiple lock ranges of a file. An error is returned +; if any lock range does not exactly match. Ranges of +; Locks are then set via Set_Mult_Block. +; +; +; INPUT: (BX) = 0 lock all operations +; = 1 lock write operations +; (CX:DX) = offset of area +; (SI:AX) = length of area +; (ES:DI) = SFT address +; (SS:SP+2)= original index \ see FRAME struc +; (SS:SP+4)= original count / +; +; OUTPUT: Lock records removed for all blocks specified +; Stack cleard on return +; +; REGISTERS USED: ALL but DS +; (NOT RESTORED) +; +; LINKAGE: IBMDOS Jump Table +; +; EXTERNAL Invoke: Load_Regs, Set_Block, Clr_Block +; REFERENCES: +; +; NORMAL 'C' clear if no error +; EXIT: +; +; ERROR 'C' set if error +; EXIT: (ax) = error code +; ('error_lock_violation' if conflicting locks) +; +; CHANGE 04/15/87 - First release +; LOG: +; +;******************* END OF SPECIFICATIONS ************************************* +;******************+ START OF PSEUDOCODE +************************************** +; +; START Clr_List +; +; search till count = 0 +; set up for call +; call clr_Block +; exit if c +; clear_count = start_count - current_count +; loop till clear_count = 0 +; set up for call +; call Set_Block +; end loop +; set error status +; orelse +; endloop +; set successful status +; endsrch +; return +; +; END Clr_List +; +;******************+ END OF PSEUDOCODE +************************************** + + Procedure Clr_List,NEAR + +;; $do ;an000;while cx not = 0 +;; cmp cx,00 ;an000;at end? +;; $leave e ;an000;yes +;; push cx ;an000;save cx - our counter +;; push di ;an000;save di - our SFT pointer + call load_regs ;an000;set up for clr_block call +;; push bp ; save pointer to range entry ;AN000; + call clr_block ;an000;remove the lock +;; pop bp ; recover pointer to range entry ;AN000; +;; pop di ;an000;restore our SFT pointer +;; pop cx ;an000;restore cx - our counter +;; $leave c ;an000;leave on error +;; dec cx ;an000;decrease counter +;; $enddo ;an000; + +;; $if c ;an000;an error occurred +;; push bp ;an000;save bp +;; mov bp,sp ;an000;get sp +;; mov dx,[bp].parm_1 ;an000;recover original index +;; mov ax,[bp].Parm_2 ; original count ;AN000; +;; pop bp +;; SUB AX,CX ; how many did we do? ;AN000; +;; MOV CX,AX ; set up the loop ;AN000; +;; MOV BP,DX ; save the index ;AN000; + +;; $DO ; ;AN000; +;; cmp cx,00 ;an000;at end? +;; $leave e ;an000;yes +;; push cx ;an000;save cx - our counter +;; push di ;an000;save di - our SFT pointer +;; call load_regs ;an000;set up for set_block call +;; call set_block ;an000;reset the locks +;; pop di ;an000;restore our SFT pointer +;; pop cx ;an000;restore cx - our counter +;; $leave c ;an000;leave on error +;; dec cx ;an000;decrease counter +;; $enddo ;an000; +;; stc ;an000;signal an error +;; $else ;an000; +;; clc ;an000;signal no error +;; $endif ;an000; + +;; ret 4 ; return (clear Parm_1 & Parm_2) ;AN000; + ret ; return (clear Parm_1 & Parm_2) ;AC006; + + EndProc Clr_List + + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; NAME: Set_Block - set byte range lock on a file +; +; FUNCTION: Set_Block sets a lock on a specified range of a file. An +; error is returned if the lock conflicts with another. +; Locks are cleared via clr_block. +; +; INPUT: (ES:DI) = SFT address +; (CX:DX) = offset of area +; (SI:AX) = length of area +; (BX) = 0 lock all operations +; = 1 lock write operations +; User_ID = 16-bit user id of issuer +; Proc_ID = 16-bit process id of issuer +; (SS) = DOSGroup +; +; OUTPUT: Lock records removed for all blocks specified +; +; REGISTERS USED: ALL but DS, BP +; (NOT RESTORED) +; +; LINKAGE: Invoked by: Set_Mult_Block +; +; EXTERNAL Invoke: CLP (SLE), OFL +; REFERENCES: +; +; NORMAL 'C' clear if no error +; EXIT: +; +; ERROR 'C' set if error +; EXIT: +; +; CHANGE 04/15/87 - lock only write support +; LOG: +; +;******************* END OF SPECIFICATIONS ************************************* +;******************+ START OF PSEUDOCODE +************************************** +; +; START Set_Block +; +; if a valid SFT and +; invoke CLP +; if no lock conflicts and +; invoke OFL +; if empty lock record available +; store SFT pointer +; store lock range +; add RLR to the chain +; store PROC_ID +; store rlr_type +; set successful return status +; else +; set error return status +; endif +; return +; +; END Set_Block +; +;******************+ END OF PSEUDOCODE +************************************** + + Procedure Set_Block,NEAR + + ASSUME ES:NOTHING,DS:NOTHING + + Context DS + + push bp ; preserve (bp) ;AN000; + push ds ; preserve (ds) +;; push bx ; preserve (bx) ;AN000; + cmp es:[di].sf_mft,ZERO +; $if nz,and ; if file is SHARED and ;AC000; + JZ $$IF11 + push di + call clp ; do common setup code + + ASSUME DS:NOTHING + + pop bp +; $if nc,and ; if no (lock conflict) error and ;AC000; + JC $$IF11 + +; Its ok to set this lock. Get a free block and fill it in +; (es:bp) = sft +; (ds:si) = pointer to name record +; (ax:bx) = fba lock area +; (cx:dx) = lba lock area +; (ds:di) = pointer to pointer to previous lock +; (TOS) = saved (bx) +; (TOS+1) = saved (ds) +; (TOS+2) = saved (bp) + + call OFL ; (ds:di) = pointer to new, orphan lock record +; $if nc ; if space available ;AC000; + JC $$IF11 + mov WORD PTR [di].rlr_sptr,bp ; store SFT offset + mov WORD PTR [di].rlr_sptr+2,es ; store SFT offset + mov [di].rlr_fba+2,ax + mov [di].rlr_fba,bx ; store lock range + mov [di].rlr_lba+2,cx + mov [di].rlr_lba,dx + +; add to front of chain +; +; (ds:si) = fwa MFT name record + + mov ax,[si].mft_lptr + mov [di].rlr_next,ax + mov [si].mft_lptr,di +; +; Set process ID of lock +; + mov ax,proc_id + mov [di].rlr_pid,ax + +; +;; pop bx ; recover lock type ;AN000; +;; push bx ; restore the stack ;AN000; +;; mov [di].rlr_type,bx ; set the rlr_type field ;AN000; + clc ; we finished OK + +; $else ; ;AC000; + JMP SHORT $$EN11 +$$IF11: + + mov ax,error_lock_violation + stc + +; $endif ; ;AC000; +$$EN11: + +;; pop bx ; ;AN000; + pop ds + pop bp ; ;AC000; + + ret ; return - all set + + EndProc Set_Block + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; NAME: Clr_Block - clear byte range lock on a file +; +; FUNCTION: Clr_Block clears a lock on a specified range of a file. +; Locks are set via set_block. +; +; INPUT: (ES:DI) = SFT address +; (CX:DX) = offset of area +; (SI:AX) = length of area +; (BX) = 0 lock all operations +; = 1 lock write operations +; User_ID = 16-bit user id of issuer +; Proc_ID = 16-bit process id of issuer +; (SS) = DOSGroup +; +; OUTPUT: Lock record removed for block specified. +; +; REGISTERS USED: ALL but DS +; (NOT RESTORED) +; +; LINKAGE: Invoked by: Clr_Mult_Block +; +; EXTERNAL Invoke: CLP (SLE), OFL +; REFERENCES: +; +; NORMAL 'C' clear if no error +; EXIT: +; +; ERROR 'C' set if error +; EXIT: (ax) = error code +; ('error_lock_violation' if conflicting locks or +; range does not exactly match previous lock) +; +; CHANGE 04/15/87 - lock only write support +; LOG: +; +;******************* END OF SPECIFICATIONS ************************************* +;******************+ START OF PSEUDOCODE +************************************** +; +; START Clr_Block +; +; if file is SHARED and +; if lock is valid and +; if SFT matches and +; if PROC_ID matches +; if lock_reqest = lock_type +; unchain the lock +; put defunct lock on free chain +; clear error status +; else +; set error status +; endif +; else +; flush the stack +; set error status +; endif +; if error +; load return code +; endif +; return +; +; END Clr_Block +; +;******************+ END OF PSEUDOCODE +************************************** + + Procedure Clr_Block,NEAR + + ASSUME ES:NOTHING,DS:NOTHING + + Context DS + push ds +;; push bx ; save type of operation ;AN000; + cmp es:[di].sf_mft,ZERO + +; $if nz,and ; if file is SHARED and ;AC000; + JZ $$IF14 + + push di + call clp ; do common setup code + + ASSUME DS:NOTHING + + pop bp ; ES:BP points to sft. +;; pop bx ; recover the type of operation ;AN000; + +; $if c,and ; if lock exists and ;AC000; + JNC $$IF14 +; $if z,and ; if range given correctly and ;AC000; + JNZ $$IF14 +; +; We've got the lock +; +; (ds:di) = address of pointer (offset) to previous lock record +; (es:BP) = sft address +; +; Now comes the tricky part. Is the lock for us? Does the lock match the SFT +; that was given us? If not, then error. +; + mov si,[di] ; (DS:SI) = address of lock record + cmp word ptr [si].rlr_sptr,bp + +; $if z,and ; if SFT matches and ;AC000; + JNZ $$IF14 + + mov bp,es + cmp word ptr [si].rlr_sptr+2,bp +; $if z,and ; (check both words of SFT pointer) ;AC000; + JNZ $$IF14 + mov bp,proc_id + cmp [si].rlr_pid,bp + +;; $if z,and ; if PROC_ID matches ;AC000; +; $if z ; if PROC_ID matches ;AC006; + JNZ $$IF14 +; +; Make sure that the type of request and the lock type match +; +;; cmp bx,lock_all ; ;AN000; + +;; $IF E,OR ; if unlocking all or ;AN000; + +;; mov bp,[si].rlr_type ; get lock type ;AN000; +;; cmp bp,rlr_lall ; is it lock all? ;AN000; + +;; $IF NE ; if not a LOCK ALL lock ;AN000; +; +; The locks match the proper open invocation. Unchain the lock +; + mov ax,[si].rlr_next + mov [di],ax ; chain it out + +; put defunct lock record on the free chain +; +; (ds:si) = address of freed lock rec + + mov ax,Frelock + mov [si].rlr_next,ax + mov Frelock,si + clc + +; $else ; we have an error ;AC000; + JMP SHORT $$EN14 +$$IF14: + + stc + +; $endif ; Endif - an error ;AC000; +$$EN14: + +; $if c ; If an error was found ;AC000; + JNC $$IF17 + + mov ax,error_lock_violation + +; $endif ; Endif - an error was found ;AC000; +$$IF17: + + pop ds ; restore DS + + ret + + + EndProc Clr_Block + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; NAME: CLP - Common Lock Preamble +; +; FUNCTION: This routine contains a common code fragment for set_block +; and clr_block. +; +; INPUT: (ES:DI) = SFT address +; (CX:DX) = offset of area +; (SI:AX) = length of area +; User_ID = 16-bit user id of issuer +; Proc_ID = 16-bit process id of issuer +; (SS) = (DS) = DOSGroup +; +; OUTPUT: (ds:si) = MFT address +; +; REGISTERS USED: ALL but ES +; (NOT RESTORED) +; +; LINKAGE: Invoked by: Set_Block, Clr_Block +; +; EXTERNAL Invoke: SLE +; REFERENCES: +; +; NORMAL 'C' clear if no overlap +; EXIT: (ax:bx) = offset of first byte in range +; (cx:dx) = offset of last byte in range +; +; ERROR 'C' set if overlap +; EXIT: 'Z' set if 1-to-1 match +; (di) points to previous lock +; +; CHANGE 04/15/87 - lock only write support +; LOG: +; +;******************* END OF SPECIFICATIONS ************************************* +;******************+ START OF PSEUDOCODE +************************************** +; +; START CLP +; +; shuffle arguments +; if valid length +; invoke SLE +; set successful return status +; else +; set error return status +; endif +; return +; +; END CLP +; +;******************+ END OF PSEUDOCODE +************************************** + + Procedure CLP,NEAR + + mov bx,dx ; shuffle arguments + xchg dx,ax + xchg ax,cx ; (ax:bx) = offset + mov cx,si ; (cx:dx) = length + + or si,dx ; see if length is 0 + +; $if nz,and ; if length is > 0 and ;AC000; + JZ $$IF19 + + add dx,bx + adc cx,ax ; (cx:dx) = lba+1 + +; $if nc,or ; no carry is ok ;AC000; + JNC $$LL19 + + mov si,dx + or si,cx + +; $if z ; if !> 0 then ;AC000; + JNZ $$IF19 +$$LL19: + + sub dx,1 ; (cx:dx) = lba of locked region + sbb cx,0 + + push cs + pop ds +; (es:di) is sft + push si + mov si,es:[di].sf_mft + push si + mov di,1 ; Find own locks + call SLE +; di points to previous lock record + pop si + pop bp + +; $else ; we have an error ;AC000; + JMP SHORT $$EN19 +$$IF19: + + xor si,si + inc si ; carry unchanged, zero reset + mov ax,error_lock_violation ; assume error + stc + +; $endif ; endif - we have an error ;AC000; +$$EN19: + + ret + + EndProc CLP + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; NAME: Chk_Block - check range lock on a file +; +; FUNCTION: Chk_Block is called to interogate the lock status of a +; region of a file. +; +; NOTE: This routine is called for every disk I/O operation +; and MUST BE FAST +; +; INPUT: (ES:DI) points to an SFT structure +; (AL) = 80h - Write operation = 0 - any non write operation +; (CX) is the number of bytes being read or written +; BytPos is a long (low first) offset into the file +; of the I/O +; User_ID = 16-bit user id of issuer +; Proc_ID = 16-bit process id of issuer +; (SS) = DOSGroup +; +; OUTPUT: CF set according to status and presence of locks (see below) +; +; REGISTERS USED: ALL but ES,DI,CX,DS +; (NOT RESTORED) +; +; LINKAGE: IBMDOS Jump Table +; +; NORMAL 'C' clear if no error +; EXIT: +; +; ERROR 'C' set if error +; EXIT: (ax) = error code +; ('error_lock_violation' if conflicting locks) +; +; CHANGE 04/15/87 - lock only write support +; LOG: +; +;******************* END OF SPECIFICATIONS ************************************* +;******************+ START OF PSEUDOCODE +************************************** +; +; START Chk_Block +; +; if shared SFT and +; if locks exist +; invoke SLE +; if lock conflicts occur (error) +; if this is !write operation and +; if a write lock found +; set successfull status +; else +; set error status +; endif +; else no error +; flush stack +; endif +; endif +; +; ret +; +; END Chk_Block +; +;******************+ END OF PSEUDOCODE +************************************** + + Procedure Chk_Block,NEAR + + ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP + +write_op equ 080h ; write operation requested ;AN000; +lock_all equ 0h ; lock all specified ;AN000; + +; PUSH DS ;ICE +; push bx ;ICE +; push ax ;ICE + +; mov bx,0140H ;ICE +; xor ax,ax ;ICE +; mov ds,ax ;ICE +; mov ax,word ptr ds:[bx] ;ICE +; mov word ptr ds:[bx],ax ;ICE + +; pop ax ;ICE +; pop bx ;ICE +; POP DS ;ICE + EnterCrit critShare + +; int 3 + nop + nop + + PUSH ES + PUSH DI + PUSH CX + PUSH DS + cmp es:[di].sf_mft,0 + +; $if nz,and ; if the file is SHARED and ;AC000; + JZ $$IF22 + + push cs + pop ds + mov si,es:[di].sf_MFT ; (DS:SI) = address of MFT record + test [si].mft_lptr,-1 + +; $if nz,and ; if there are locks on this file and ;AC000; + JZ $$IF22 + + sub cx,1 ; (cx) = count-1 + cmc + +; $if c ; there are bytes to lock ;AC000; + JNC $$IF22 + +;; push ax ; preserve type of operation ;AN000; + ; DOS passes AL = 80 for writes + ; = 00 for reads + + mov ax,WORD PTR BytPos+2 + mov bx,WORD PTR BytPos ; (ax:bx) = offset + mov dx,cx + sub cx,cx + add dx,bx + adc cx,ax ; (cx:dx) = lba of lock area + sub di,di ; ignore own locks + call SLE +;; pop ax ; recover type of opperation ;AN000; + +; upon return DS:SI points to the RLR with the conflict + +;; $if c ; if lock conflicts occur - error ;AC000; + +; now we must check what type of lock exists +; and the type of operation in progress. + +;; cmp al,write_op ; ;AN000; + +;; $if ne,and ; if NOT a write operation and ;AN000; + +;; cmp [si].rlr_type,rlr_lwr ; ;AN000; + +;; $if e ; if write locked (NOT all locked) ;AN000; + +;; clc ; then not true conflict - clear error ;AN000; + +;; $else ; else it IS a valid conflict ;AC000; + +;; stc ; true error - set error status + +;; $endif ; endif - a valid conflict ;AC000; + + +;; $endif ; endif - conflicts ;AC000; + + mov ax,error_lock_violation ; assume error + +; $endif ; endif - no need to check ;AC000; +$$IF22: + +; exit +; +; 'C' and (ax) setup + + POP DS + POP CX + POP DI + POP ES + LeaveCrit critShare + + ret ; exit + + EndProc Chk_Block + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; MFT_get - get an entry from the MFT +; +; MFT_get is used to return information from the MFT. System utilities +; use this capability to produce status displays. +; +; MFT_get first locates the (BX)'th file in the list (no particular +; ordering is promised). It returns that name and the UID of +; the (CX)'th SFT on that file and the number of locks on that +; file via that SFT. +; +; ENTRY DS:SI point to DPL which contains: +; (dBX) = zero-based file index +; (dCX) = zero-based SFT index +; (SS) = DOSGroup +; EXIT 'C' clear if no error +; ES:DI buffer is filled in with BX'th file name +; (BX) = user id of SFT +; (CX) = # of locks via SFT +; 'C' set if error +; (ax) = error code +; ('error_no_more_files' if either index is out +; of range) +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure MFT_get,NEAR + +; int 3 + nop + nop + + ASSUME DS:NOTHING,ES:NOTHING + + EnterCrit critShare + MOV BX,[SI.DPL_BX] + MOV CX,[SI.DPL_CX] + Context ES + MOV DI,OFFSET DOSGROUP:OpenBuf + + xchg bx,cx ; (cx) = file index + push cs + pop ds + + Off SI,mft ; (ds:si) = fwa of OFFSET MFT + +; scan forward until next name + +mget1: cmp [si].mft_flag,MFLG_FRE + jz mget3 ; is free space + jl mget7 ; is END + +; have another name. see if this satisfies caller + + jcxz mget4 ; caller is happy + dec cx +mget3: add si,[si].mft_len ; skip name record + JMP SHORT mget1 + +; we've located the file name. +; +; (bx) = SFT index +; (DS:SI) = MFT entry +; (ES:DI) = address of caller's buffer + +mget4: push di + push si ; save table offset + add si,mft_name +mget5: lodsb + stosb ; copy name into caller's buffer + or al,al + jnz mget5 + pop si ; (DS:SI) = name record address + xchg bx,cx ; (cx) = SFT chain count + lds di,[si].mft_sptr +mget6: jcxz mget8 ; have reached the SFT we wanted + dec cx + lds di,[di].sf_chain ; get next link + or di,di + jnz mget6 ; follow chain some more + pop di ; (es:di) = buffer address + +;** The file or SFT index was too large - return w/ error + +mget7: mov ax,error_no_more_files + stc + LeaveCrit critShare + + ret + +;** We've got the SFT he wants. Lets count the locks +; +; (es:TOS) = buffer address +; (DS:DI) = address of SFT +; (si) = address of mft + +mget8: mov ax,[DI].sf_flags + mov dx,ds ; save segment + push cs + pop ds + mov si,[si].mft_lptr ; (DS:SI) = Lock record address + sub cx,cx ; clear counter + +mget9: or si,si + jz mget11 ; no more + cmp di,WORD PTR [si].rlr_sptr + jnz mget10 + cmp dx,word PTR [si].rlr_sptr+2 + jnz mget10 + inc cx +mget10: mov si,[si].rlr_next + JMP SHORT mget9 + +; Done counting locks. return the info +; +; (cx) = count of locks +; (es:TOS) = buffer address + +mget11: mov ds,dx + mov bx,[di].SF_UID ; (bx) = UID + pop di + clc + LeaveCrit critShare + + ret + + EndProc MFT_get + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; ASC - Add SFT to Chain +; +; ASC is called to add an SFT to the front of the chain. +; +; ASC checks the file share mode bits on the other SFTs in the chain and +; reports a conflict. The new SFT is NOT ADDED in the case of +; conflicts. +; +; ENTRY (BX) = FBA MFT name record +; (DS:SI) = SFT address +; EXIT 'C' clear if added +; (ds:si) point to sft +; (bx) offset of mft +; 'C' set if conflict +; (ax) = error code +; USES ALL +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure ASC,NEAR + + cmp [si].sf_MFT,0 + jnz asc9 ; already on chain - internal error + +; The SFT looks good... lets see if there are any use conflicts + +; Message 1,<"Adding sft "> + + mov ax,User_ID ; place user information in SFT + mov [si].sf_UID,ax ; do it before CUC (he checks UID) + mov ax,Proc_ID + mov [si].sf_PID,ax + + cmp skip_check,1 +; $if ne ; + JE $$IF24 + + call CUC ; check use conflicts + +; $endif +$$IF24: + + jc asc8 ; use conflicts - forget it + +; MessageNum AX + +; MessageNum AX +; Message 1,<" to "> +; MEssageNum DS +; Message 1,<":"> +; MessageNum SI +; Message 1,<" "> + + mov [si].sf_MFT,bx ; make SFT point to MFT + +; MessageNum [si].sf_mft +; Message 1,<13,10> + + mov cx,[si].sf_mode ; (cx) = open mode + mov dx,ds ; (dx:si) = SFT address + push cs + pop ds ; (ds:bx) = MFT address + +; +; Not special file and no previous sft found OR normal SFT. We link it in +; at the head of the list. +; +; (dx:si) point to sft +; (ds:bx) point to mft +; + les di,[bx].mft_sptr ; get first link + mov word ptr [bx].mft_sptr,si ; link in this sft + mov word ptr [bx].mft_sptr+2,dx ; link in this sft + mov ds,dx + mov word ptr [si].sf_chain,di + mov word ptr [si].sf_chain+2,es +asc75: mov ds,dx ; point back to sft + + clc +asc8: ret + +; the SFT is already in use... internal error + +asc9: push ax + off ax,ascerr + call INTERR ; NEVER RETURNS +ascerr db "ASC: sft already in use", 13, 10, 0 + + EndProc ASC + + + BREAK + +;******************* 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:DOSGROUP + + 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 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 + call CPS ; clear JFN + Context DS + + CallInstall DOS_Close,multDos,1 + + ASSUME DS:NOTHING + + RestoreReg ; (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 + +;******************* 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 + +;******************* 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 + +;******************* 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 + +;******************* 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 + \ No newline at end of file diff --git a/v4.0/src/CMD/SHARE/GSHARE2.ASM b/v4.0/src/CMD/SHARE/GSHARE2.ASM new file mode 100644 index 0000000..6341c5a --- /dev/null +++ b/v4.0/src/CMD/SHARE/GSHARE2.ASM @@ -0,0 +1,2979 @@ + Title Share_2 +; $SALUT (0,36,41,44) + include SHAREHDR.INC +; +; Label: "The DOS SHARE Utility" +; "Version 4.00 (C) Copyright 1988 Microsoft" +; "Licenced Material - Program Property of Microsoft" +; +;******************* END OF SPECIFICATIONS ************************************* + + NAME Sharer2 + + ; INCLUDE DOSSYM.INC + ; INCLUDE SYSMSG.INC + .xlist + .xcref + INCLUDE DOSSYM.INC + INCLUDE SYSMSG.INC + .cref + .list + page 80,132 + + MSG_UTILNAME + +ShareDataVersion = 1 + +AsmVars + +Installed = TRUE ; for installed version + +OFF Macro reg,val + IF installed + mov reg,OFFSET val + ELSE + mov si,OFFSET DOSGROUP:val + ENDIF + ENDM + +ERRNZ Macro x + IF x NE 0 + %out ERRNZ failed + ENDIF + ENDM + ;--------------------------------------- + ; if we are installed, then define the + ; base code segment of the sharer first + ;--------------------------------------- +; $SALUT (4,9,17,36) + + IF Installed + + Share SEGMENT BYTE PUBLIC 'SHARE' + Share ENDS + + ENDIF + + ;--------------------------------------- + ; include the rest of the segment + ; definitions for normal msdos + + ; segment ordering for MSDOS + + ;--------------------------------------- + include dosseg.asm + + CONSTANTS SEGMENT + + extrn DataVersion:BYTE ; version number of DOS data. + extrn JShare:BYTE ; location of DOS jump table. + extrn sftFCB:DWORD ; [SYSTEM] pointer to FCB cache table + extrn KeepCount:WORD ; [SYSTEM] LRU count for FCB cache + extrn CurrentPDB:WORD + + CONSTANTS ENDS + + DATA SEGMENT + + extrn ThisSFT:DWORD ; pointer to SFT entry + extrn WFP_start:WORD ; pointer to name string + extrn User_ID:WORD + extrn Proc_ID:WORD + extrn SFT_addr:DWORD + extrn Arena_Head:WORD + extrn fshare:BYTE + extrn pJFN:DWORD + extrn JFN:WORD + + IF DEBUG + + extrn BugLev:WORD + extrn BugTyp:WORD + include bugtyp.asm + + ENDIF + + + DATA ENDS + + ;--------------------------------------- + ; if we are not installed, then the + ; code here is just part of the normal + ; MSDOS code segment otherwise, + ; define our own code segment + ;--------------------------------------- + + .sall + IF NOT INSTALLED + + CODE SEGMENT BYTE PUBLIC 'CODE' + + ASSUME SS:DOSGROUP,CS:DOSGROUP + + ELSE + + Share SEGMENT BYTE PUBLIC 'SHARE' + + ASSUME SS:DOSGROUP,CS:SHARE + + ENDIF + + Extrn FreLock:WORD,Serial:WORD + Extrn MFT_Enter:NEAR,MFTClose:NEAR,MFTClu:NEAR,MFTCloseP:NEAR + Extrn MFTCloN:NEAR + Extrn Set_Mult_Block:NEAR,Clr_Mult_Block:NEAR,Chk_Block:NEAR + Extrn MFT_Get:NEAR + + include mft.inc + +; $SALUT (4,4,9,41) + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; FNM - Find name in MFT +; +; FNM searches the MFT for a name record. +; +; ENTRY (DS:SI) = pointer to name string (.asciz) +; (al) = 1 to create record if non exists +; = 0 otherwise +; EXIT 'C' clear if found or created +; (DS:BX) = address of MFT name record +; 'C' set if error +; If not to create, item not found +; (DS:SI) unchanged +; If to create, am out of space +; (ax) = error code +; USES ALL +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure FNM,NEAR + + push ds ; save string address + push si + xchg bh,al ; (bh) = create flag + or bh,bh ; if not creating + jz fnm01 ; skip sft test + + ;--------------------------------------- + ; run down through string counting + ; and summing + ;--------------------------------------- + +fnm01: sub dx,dx ; (dx) = byte count + sub bl,bl ; (bl) = sum + +fnm1: lodsb ; (al) = next char + add bl,al + adc bl,0 + inc dx + and al,al + jnz fnm1 ; terminate after null char + + ;--------------------------------------- + ; Info computed. + ; Start searching name list + + ; (bh) = create flag + ; (bl) = sum byte + ; (dx) = byte count + ; (TOS+2:TOS) = name string address + ;--------------------------------------- + push cs + pop ds + + Off SI,mft + +fnm2: cmp [si].mft_flag,MFLG_FRE + jl fnm10 ; at end - name not found + jz fnm4 ; is free, just skip it + cmp bl,[si].mft_sum ; do sums compare? + jz fnm5 ; its a match - look further +fnm4: add si,[si].mft_len ; not a match... skip it + JMP SHORT fnm2 + ;--------------------------------------- + ; name checksums match + ; - compare the actual strings + ; + ; (dx) = length + ; (ds:si = MFT address + ; (bh) = create flag + ; (bl) = sum byte + ; (dx) = byte count + ; (TOS+2:TOS) = name string address + ;--------------------------------------- + +fnm5: mov cx,dx ; (cx) = length to match + pop di + pop es ; (ES:DI) = fba given name + push es + push di + push si ; save MFT offset + add si,mft_name ; (ds:si) = fwa string in record + repz cmpsb + pop si ; (ds:si) = fwa name record + jnz fnm4 ; not a match + + ;--------------------------------------- + ; Yes, we've found it. Return the info + ; + ; (TOS+2:TOS) = name string address + ;--------------------------------------- + + fmt TypShare,LevMFTSrch,<"FNM found name record at $x\n">, + pop ax ; discard unneeded stack stuff + pop ax + mov bx,si ; (ds:bx) = fwa name record + clc + + ret + ;--------------------------------------- + ;** + ;** Its not in the list + ;** - lets find a free spot and put + ;** it there + ; + ; (bh) = create flag + ; (bl) = sum byte + ; (dx) = string length + ; (TOS+2:TOS) = ASCIZ string address + ; (ds) = SEG CODE + ;--------------------------------------- +fnm10: + and bh,bh + jnz fnm10$5 ; yes, insert it + pop si + pop ds ; no insert, its a "not found" + stc + + fmt TypShare,LevMFTSrch,<"FNM failing\n"> + + mov ax,error_path_not_found + + ret + +fnm10$5: + add dx,mft_name ; (dx) = minimum space needed + + off SI,mft + +fnm11: cmp [si].mft_flag,MFLG_FRE + + IF NOT DEBUG + jl fnm20 ; at END, am out of space + ELSE + jl fnm20j + ENDIF + + jz fnm12 ; is a free record + add si,[si].mft_len ; skip name record + JMP SHORT fnm11 + + IF DEBUG +fnm20j: jmp fnm20 + ENDIF + +fnm12: mov ax,[si].mft_len ; Have free record, (ax) = total length + cmp ax,dx + jnc fnm13 ; big enough + add si,ax + JMP SHORT fnm11 ; not large enough - move on + + ;--------------------------------------- + ; OK, we have a record which is big + ; enough. If its large enough to hold + ; another name record of 6 characters + ; than we'll split the block, else + ; we'll just use the whole thing + ; + ; (ax) = size of free record + ; (dx) = size needed + ; (ds:si) = address of free record + ; (bl) = sum byte + ; (TOS+2:TOS) = name string address + ;--------------------------------------- + +fnm13: sub ax,dx ; (ax) = total size of proposed fragment + cmp ax,mft_name+6 + jc fnm14 ; not big enough to split + push bx ; save sum byte + mov bx,dx ; (bx) = offset to start of new name record + mov [bx][si].mft_flag,MFLG_FRE + mov [bx][si].mft_len,ax ; setup tail as free record + sub ax,ax ; don't extend this record + pop bx ; restore sum byte +fnm14: add dx,ax ; (dx) = total length of this record + mov [si].mft_len,dx + mov [si].mft_sum,bl + mov [si].mft_flag,MFLG_NAM + + fmt TypShare,LevMFTSrch,<"FNM creating record at $x\n">, + + push ds + pop es ; (es) = MFT segment for "stow" + sub ax,ax + mov di,si + add di,mft_lptr + stosw ; zero LCK pointer + ERRNZ mft_sptr-mft_lptr-2 +; add di,mft_sptr-mft_lptr-2 + stosw ; zero SFT pointer + stosw ; zero SFT pointer + inc serial ; bump serial number + mov ax,serial + ERRNZ mft_serl-mft_sptr-4 +; ADD di,mft_serl-mft_sptr-4 + stosw + ;--------------------------------------- + ; We're all setup except for the name. + ; Note that we'll block copy the whole + ; name field, even though the name may + ; be shorter than that (we may have + ; declined to fragment this memory block) + ; + ; (dx) = total length of this record + ; (ds:si) = address of working record + ; (es) = (ds) + ; (TOS+2:TOS) = name string address + ;--------------------------------------- + mov cx,dx + sub cx,mft_name ; compute total size of name area + ERRNZ mft_name-mft_serl-2 +; add di,mft_name-mft_serl-2 ; (ES:DI) = target address + mov ax,si ; save name record offset + pop si + pop ds + rep movsb + mov bx,ax ; (bx) = name record offset + push es + pop ds ; (DS:BX) = name record offset + clc + + ret + +;** +;** OUT OF FREE SPACE +;** +;** This is tough, folks. Lets trigger a garbage collection and see if +;** there is enough room. If there is, we'll hop back and relook for a +;** free hunk; if there isnt enough space, its error-city! +; +; WARNING: it is important that the garbage collector be told how big a +; name record hole we're looking for... if the size given GCM +; is too small we'll loop doing "no space; collect; no space; +; ...) +; +; (dx) = total length of desired name record +; (ds) = SEG CODE +; (bl) = sum byte +; (TOS+2:TOS) = name string address + +fnm20: + mov ax,dx ; (ax) = size wanted + sub dx,mft_name ; (dx) = string length for reentry at fnm10 + push dx + push bx + call GCM ; garbage collect MFT + pop bx + pop dx + + IF DEBUG + jnc fnm10j + ELSE + jnc fnm10 ; go back and find that space + ENDIF + + ;--------------------------------------- + ; no space, return w/error + ;--------------------------------------- + +fnm50: pop ax + pop ax ; clean stack + mov ax,error_sharing_buffer_exceeded + stc + + ret + + IF DEBUG +fnm10j: jmp fnm10 + ENDIF + + EndProc FNM + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; GCM - Garbage Collect MFT +; +; GCM runs down the MFT structure squeezing out the free space and +; putting it into one free block at the end. This is a traditional heap +; collection process. We must be sure to update the pointer in the +; SFTs. This presumes no adjacent free blocks. +; +; ENTRY (ax) = space desired in last free block +; (DS) + SEG CODE +; EXIT 'C' clear if enough space in block +; 'C' set if not enough space +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure GCM,NEAR + + push ax ; save target + off si,mft ; (si) = from pointer + mov di,si ; (di) = to pointer + + ;--------------------------------------- + ; (DI) points to the beginning of + ; a free space block + ; (SI) points to the next block. + ;--------------------------------------- + +gcm1: mov cx,[si].mft_len ; (cx) = size of whatever it is + cmp [si].mft_flag,MFLG_FRE + jl gcm10 ; END marker + jnz gcm2 ; have a name record + + ;--------------------------------------- + ; (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 + +;******************* 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 + +rmnerr1 db "RMN: SFT LCK fields not 0", 13, 10, 0 + + EndProc RMN + + Break + +;******************* 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 + +;******************* 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 + +rscerr db "RSC: SFT not in SFT list", 13, 10, 0 + + EndProc RSC + + BREAK + +;******************* 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 + +;******************* 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 + +;******************* 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 + + 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 + ;--------------------------------------- +cps2: + cmp ds:[arena_signature],arena_signature_end + jz cps3 ; no more blocks to do + mov bx,ds ; get current address + add bx,DS:[Arena_size] ; add on size of block + inc bx ; remember size of header + mov ds,bx ; link to next + jmp cps1 + ;--------------------------------------- + ; Just for good measure, use CurrentPDB + ; and clean off him + ;--------------------------------------- +cps3: + mov ds,CurrentPDB + + call CPJ + +cps31: + + RestoreReg < + + RestoreReg + + ret + + EndProc CPS + +;******************* START OF SPECIFICATIONS *********************************** +; +; CPJ - +; +; Scan JFN table for SFT # and put in -1 if found +; +; Input: DS:0 is PDB +; AL is SFT index # of interest +; +; Output: None +; +; Uses: Flags,CX,ES,DI +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure CPJ,NEAR + + assume ds:nothing,es:nothing + + mov cx,ds:[PDB_JFN_length] + les di,ds:[PDB_JFN_pointer] + cld +cpj1: repne scasb + + retnz ; none found + + mov byte ptr es:[di-1],-1 ; free this + jcxz CPJret ; Found one in last JFN entry + jmp cpj1 ; keep looking +CPJret: + + ret + + EndProc CPJ + + Break + +;******************* START OF SPECIFICATIONS *********************************** +; +; SFM - convert a pointer to a mft entry into the serial number for that +; entry. We keep these around to see if a FCB really points to the correct +; SFT. +; +; Inputs: BX is the mft pointer +; Outputs: BX is the serial number +; Registers Revised: none +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure SFM,NEAR + + ASSUME CS:SHARE,DS:NOTHING,ES:NOTHING,SS:DOSGROUP + + mov bx,cs:[bx].mft_serl + + ret + + EndProc SFM + + Break + +;******************* START OF SPECIFICATIONS *********************************** +; +; ShChk - check a fcb for share related information +; +; ShChk - checks the reserved field contents of an FCB with a SFT to see +; if they represent the same file. The open ref count must be > 0. +; +; Inputs: DS:SI point to FCB +; ES:DI point to SFT +; Outputs: Carry Set if contents do not match +; Carry clear if contents match +; BX has first cluster +; Registers Revised: none +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure ShChk,NEAR + + ASSUME CS:SHARE,DS:NOTHING,ES:NOTHING,SS:DOSGROUP + + CMP ES:[DI].sf_ref_count,0 + JZ BadSFT + MOV BX,ES:[DI].sf_mft ; Local file or dev with sharing + + call SFM + + CMP BX,[SI].fcb_l_mfs + JNZ BadSFT + MOV BX,[SI].fcb_l_firclus + + ret + +BadSFT: stc + + ret + + EndProc ShChk + + Break + +;******************* START OF SPECIFICATIONS *********************************** +; +; ShSave - save information from SFT into an FCB +; +; ShSave - copy information into the reserved area of an FCB from a SFT. +; This is so that we can later match the SFT with the FCB. +; +; Inputs: ES:DI point to SFT +; DS:SI point to FCB +; Outputs: FCB reserved field is filled in +; BL = FCBSHARE +; Registers Revised: AX,BX +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure ShSave,NEAR + + ASSUME CS:SHARE,DS:NOTHING,ES:NOTHING,SS:DOSGROUP + + MOV AL,ES:[DI].sf_attr ; move attribute (for reopen) + MOV [SI].FCB_l_attr,AL + MOV AX,ES:[DI].sf_firclus ; get first cluster + MOV [SI].FCB_l_firclus,AX + MOV BX,ES:[DI].sf_mft ; get sharing pointer + + call SFM + + MOV [SI].FCB_l_mfs,BX + MOV BL,FCBSHARE + + ret + + EndProc ShSave + + Break + +;******************* START OF SPECIFICATIONS *********************************** +; +; ShCol - collapse identical handle SFTs in mode 70 only +; +; ShCol - collapse same 70-mode handles together. This represents network +; originated FCBs. Since FCB's are incredibly mis-behaved, we collapse the +; SFT's for identical files, thus using a single sft for each file instead +; of a separate sft for each instance of the file. +; +; Note that the redirectors will collapse multiple instances of these +; files together. FCB's are pretty misbehaved, so the redirector will +; inform us of EACH close done on an FCB. Therefore, we must increment +; the ref count each time we see a collapse here. +; +; Inputs: DS:SI ThisSFT has new sft to find. +; Outputs: Carry set - no matching SFT was found +; Carry clear - matching SFT was found and all collapsing done. +; AX has proper handle +; Registers Revised: all. +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure ShCol,NEAR + + ASSUME CS:SHARE,DS:NOTHING,ES:NOTHING,SS:DOSGROUP + + ;--------------------------------------- + ; Collapse the files ONLY if + ; the mode is for net FCB's + ;--------------------------------------- + + MOV AL,BYTE PTR [SI].sf_mode + AND AL,sharing_mask + CMP AL,sharing_net_FCB + JNZ UseJFN + + ;--------------------------------------- + ; In share support + ;--------------------------------------- + + XOR BX,BX ; for (i=0; sffromsfn(i); i++) { +OpenScan: + + CallInstall SFFromSFN,multDOS,22,bx,bx + + JC UseJFN + + CallInstall PointComp,multDOS,20 ; if (!pointcomp (s,d)) + + JZ OpenNext + CMP ES:[DI].sf_ref_count,0 + JZ OpenNext + MOV AX,ES:[DI].sf_mode + CMP AX,[SI].sf_mode + JNZ OpenNext + MOV AX,ES:[DI].sf_mft + CMP AX,[SI].sf_mft + JNZ OpenNext + MOV AX,WORD PTR ES:[DI].sf_UID + CMP AX,WORD PTR [SI].sf_uid + JNZ OpenNext + MOV AX,WORD PTR ES:[DI].sf_pid + CMP AX,WORD PTR [SI].sf_pid + JZ OpenFound +OpenNext: + INC BX + JMP OpenScan + ;-------------------------------------- + ; DS:SI points to an sft which is a + ; duplicate of that found in + ; ES:DI is the older one. + ; + ; We call mftclose to release the + ; appropriate info. + ;-------------------------------------- +OpenFound: + MOV [SI].sf_ref_count,0 ; free 'new' sft + + SaveReg + + Context DS + + LES DI,ThisSFT + + call MFTClose + + RestoreReg + + ASSUME DS:NOTHING + + INC ES:[DI].sf_ref_count ; d->refcount++; + XOR BX,BX ; find jfn with sfn as contents +JFNScan: + + CallInstall pJFNFromHandle,multDOS,32,AX,AX + + JC UseJFN ; ran out of handles? + CMP AL,BYTE PTR ES:[DI] ; does JFN have SFN? + jz JFNfound ; YES, go return JFN + INC BX ; no, look at next + JMP JFNScan +JFNFound: + LDS SI,pJFN + MOV BYTE PTR [SI],0FFh ; free JFN + MOV AX,BX ; return JFN + + ret + +UseJFN: + MOV AX,JFN + + ret + + EndProc ShCol + + Break + +;******************* START OF SPECIFICATIONS *********************************** +; +; ShCloseFile - close a particular file for a particular UID/PID +; +; ShCloseFile - Compatability mode programs will often delete files that +; they had open. This was perfectly valid in the 2.0 days, but this +; presents a reliability problem in the network based operating environment. +; As a result, both RENAME and DELETE will call us to see if the file is +; open by is only. If it is not open or is open by us only, we close it. +; Note that we will ONLY close compatability SFTs. +; Otherwise, we signal and error. +; +; Inputs: WFT_Start has a DOSGROUP offset to the file name +; DS is DOSGroup +; Outputs: nothing relevant. +; Registers Revised: None. +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure ShCloseFile,NEAR + + ASSUME DS:DOSGroup,ES:NOTHING,SS:DOSGroup + + SaveReg + + EnterCrit critShare + +ShCl: + MOV SI,WFP_Start + XOR AL,AL + + call FNM ; attempt to find name in list + + ASSUME DS:NOTHING + + JC ShCloseDone ; can't find, signal success + + ;-------------------------------------- + ; We have found a file in the MFT. + ; Walk the open sft list to find + ; the SFTs for the current UID/PID. + ;-------------------------------------- + MOV CX,DS + LDS SI,[BX].mft_sptr +ShClCheck: + MOV AX,Proc_ID + CMP [SI].sf_PID,AX + JNZ ShCloseDone + MOV AX,User_ID + CMP [SI].sf_UID,AX + JNZ ShCloseDone + MOV AX,[SI].sf_mode + AND AX,sharing_mask + CMP AX,sharing_net_fcb + jz ShClNext + CMP AX,sharing_compat + jnz ShCloseDOne +ShClNext: + LDS SI,[SI].sf_chain + OR SI,SI + JNZ ShClCheck + MOV DS,CX + LDS SI,[BX].mft_sptr + ;-------------------------------------- + ; Everything matches. Set up ThisSFT + ; and walk the chain from the beginning. + ;-------------------------------------- + MOV WORD PTR ThisSFT,SI + MOV WORD PTR ThisSFT+2,DS + ;-------------------------------------- + ; Close all handles for this SFT + ;-------------------------------------- + call CPS + ;-------------------------------------- + ; Close the sft itself. + ;-------------------------------------- + Context DS + + CallInstall DOS_Close,multDos,1 + ;-------------------------------------- + ; The SFT may be free and we have no + ; idea where the next is. Go and loop + ; all over. + ;-------------------------------------- + JMP ShCl + ;-------------------------------------- + ; There are no more SFTs to close. Leave + ;--------------------------------------- +ShCloseDone: + + LeaveCrit critShare + + STC + + RestoreReg + + ret + + EndProc ShCloseFile + + .xall + Break +;******************* START OF SPECIFICATIONS *********************************** +; +; NAME: ShSU - update all SFTs for a specified change> +; +; FUNCTION: In a shared environment, we want to propogate the SFT +; changes for a particular file to all other SFTs for that +; file. The types of things we propogate are: +; +; - Time of last write - we only do this on CLOSE and on +; FILETIMES. +; +; - Size and allocation information - we do this ONLY when +; we change sf_size. +; +; We achieve this by walking the linked list of SFTs for the +; file. See PSEUDOCODE below +; +; INPUT: ES.DI has SFT that was just Revised. +; AX = 0 for updating of time from ES:DI into old sfts +; AX = 1 for updating of size/allocation for growth from ES:DI +; AX = 2 for updating of size/allocation for shrink from ES:DI +; AX = 3 for new instance copy into ES:DI +; AX = 4 for update of codepage and high attribute +; +; OUTPUT: All relevant SFTs are updated. +; +; REGISTERS USED: All except ES:DI and DS:SI +; (NOT RESTORED) +; +; LINKAGE: DOS Jump Table +; +; EXTERNAL Invoke: New_Sft, Call_IFS +; REFERENCES: Callinstall +; +; NORMAL - +; EXIT: +; +; ERROR - +; EXIT: +; +; CHANGE 04/15/87 - Major overhaul and IFS support +; LOG: +; +;******************* END OF SPECIFICATIONS ************************************* +;******************+ START OF PSEUDOCODE +************************************** +; +; START ShSU +; +; if not a device and +; if not a network +; search +; if our SFT +; advance to next SFT +; endif +; leave if no more SFT's +; exitif cx = 3 +; invoke New_Sft +; orelse +; if cx = 0 +; update time +; update date +; if non - FAT file system +; call IFSFUNC +; endif +; else cx = 1 or 2 +; update size +; if non - FAT file system +; call IFSFUNC +; else +; update first cluster +; if cx = 2 or +; if lstclus un-set from create +; update cluster position +; update last cluster +; endif +; endif +; endif +; advance to next SFT +; endloop +; endsearch +; endif +; return +; +; END ShSU +; +;******************+ END OF PSEUDOCODE +************************************** + + Procedure ShSU,near + + ASSUME DS:NOTHING,ES:NOTHING + + nop +; int 3 + nop + +ifs_flag equ 8000h ; ;AN000; + ;--------------------------------------- + ; Do nothing for device or network + ;--------------------------------------- + mov bx,es:[di].sf_mode + and bx,sf_isnet + devid_device + +; $if z,and,long ; if not device and ;AC000; + JZ $$XL1 + JMP $$IF4 +$$XL1: + + mov bx,es:[di].sf_MFT + or bx,bx + +; $if nz,,long ; if not network ;AC000; + JNZ $$XL2 + JMP $$IF4 +$$XL2: + + EnterCrit critShare + ;--------------------------------------- + ; Walk the sft chain for this file and + ; skip the current SFT (ES:DI) + ;--------------------------------------- + SaveReg + + lds si,cs:[bx].MFT_SPTR + mov cx,ax + +; $search ; ;AC000; +$$DO5: + + CallInstall PointComp,multDOS,20 ; pointers different? + +; $if z ; if ourselves ;AC000; + JNZ $$IF6 + + lds si,[si].sf_chain ; move to next ;AC000; + +; $endif ; endif - ourselves ;AC000; +$$IF6: + + or si,si + +; $leave z ; ;AC000; + JZ $$EN5 + + ;--------------------------------------- + ; CX = 0 for updating of time + ; CX = 1 for updating of size/allocation + ; for growth + ; CX = 2 for updating of size/allocation + ; for shrink + ; CX = 3 for new instance copy. + ;--------------------------------------- + cmp cx,2 ; ;AC000; + +; $exitif a ; ;AC000; + JNA $$IF5 + ;--------------------------------------- + ; CX = 3 for new instance copy. + ; CX = 4 for codepage and high attrib update + ;--------------------------------------- + cmp cx,3 ; cx = 3 ? ;an000; +; $if e ; yes ;an000; + JNE $$IF10 + call New_Sft ; ;AN000; +;; $else ; cx = 4 ;an000; +;; call New_CP_Attrib ; update codepage and high attrib ;an000; +; $endif ; ;an000; +$$IF10: + +; $orelse ; ;AC000; + JMP SHORT $$SR5 +$$IF5: + + or cx,cx + +; $if z ; if cx = 0 then ;AC000; + JNZ $$IF13 + ;--------------------------------------- + ; CX = 0 for updating of time + ; + ; Copy time from ES:DI into DS:SI + ;--------------------------------------- + mov bx,es:[di].sf_time + mov [si].sf_time,bx + mov bx,es:[di].sf_date + mov [si].sf_date,bx + test [si].sf_flags,ifs_flag ; ;AN000; + +; $if nz ; if non-FAT ;AC003; + JZ $$IF14 + + call Call_IFS ; tell IFS of SFT change ;AN000; + +; $endif ; endif non- FAT ;AN000; +$$IF14: + +; $else ; else - must be >0 and <2 ;AC000; + JMP SHORT $$EN13 +$$IF13: + ;--------------------------------------- + ; CX = 1 for updating of size/allocation + ; for growth + ; CX = 2 for updating of size/allocation + ; for shrink + ; + ; We always copy size and firclus + ;--------------------------------------- + mov bx,word ptr es:[di].sf_size + mov word ptr [si].sf_size,bx + mov bx,word ptr es:[di].sf_size+2 + mov word ptr [si].sf_size+2,bx + test [si].sf_flags,ifs_flag ; ;AN000; + +; $if nz ; if non-FAT ;AC003; + JZ $$IF17 + + invoke Call_IFS ; tell IFS of SFT change ;AN000; + +; $else ; else - its FAT ;AN000; + JMP SHORT $$EN17 +$$IF17: + + mov bx,es:[di].sf_firclus + mov [si].sf_firclus,bx + cmp cx,2 ; ;AC000; + +; $if z,or ; if SFT is shrinking or ;AC000; + JZ $$LL19 + + cmp [si].sf_lstclus,0 ; lstclus UN-set from a create? ;AC000; + +; $if z ; If it is, set lstclus and cluspos too;AC000; + JNZ $$IF19 +$$LL19: + ;--------------------------------------- + ; Shrink the file, move in new cluspos + ; and lstclus + ;--------------------------------------- + mov [si].sf_cluspos,0 ; retrace from start + mov [si].sf_lstclus,bx ; ditto + +; $endif ; endif - set lstclus and cluspos ;AC000; +$$IF19: + +; $endif ; endif FAT ;AN000; +$$EN17: + +; $endif ; enndif - > 0 ;AC000; +$$EN13: + ;--------------------------------------- + ; Link to next SFT + ;--------------------------------------- + lds si,[si].sf_chain + +; $endloop ; ;AC000; + JMP SHORT $$DO5 +$$EN5: + +; $endsrch ; ;AC000; +$$SR5: + ;--------------------------------------- + ; All Done + ;--------------------------------------- + RestoreReg + + LeaveCrit critShare + +; $endif ; endif - device and network ;AC000; +$$IF4: + + ret + + EndProc ShSU + + Break + +;******************* START OF SPECIFICATIONS *********************************** +; +; NAME: New_Sft - update a new SFT +; +; FUNCTION: Copy all SFT information into a NEW sft of a SHARED file. +; +; +; INPUT: ES.DI has SFT that was just Revised. +; DS:SI has SFT that is to be updated +; +; OUTPUT: SFT is updated. +; +; REGISTERS USED: AX, BX +; (NOT RESTORED) +; +; LINKAGE: Invoked by: ShSU +; +; EXTERNAL Invoke: Call_IFS +; REFERENCES: +; +; CHANGE 04/15/87 - First release +; LOG: +; +;******************* END OF SPECIFICATIONS ************************************* +;******************+ START OF PSEUDOCODE +************************************** +; +; START New_Sft +; +; update time +; update date +; update size +; if non - FAT file system +; call IFSFUNC +; else +; update first cluster +; update cluster position +; update last cluster +; endif +; return +; +; END New_Sft +; +;******************+ END OF PSEUDOCODE +************************************** + + Procedure New_Sft,near ; ;AN000; + + mov bx,[si].sf_time ; update time + mov es:[di].sf_time,bx + mov bx,[si].sf_date ; update date + mov es:[di].sf_date,bx + mov bx,word ptr [si].sf_size ; update size + mov word ptr es:[di].sf_size,bx + mov bx,word ptr [si].sf_size+2 + mov word ptr es:[di].sf_size+2,bx + test es:[di].sf_flags,ifs_flag ; ;AN000; + +; $if nz ; if non-FAT ;AC003; + JZ $$IF26 + + call Call_IFS ; tell IFS of SFT change ;AN000; + +; $else ; else - its FAT ;AN000; + JMP SHORT $$EN26 +$$IF26: + + mov bx,[si].sf_firclus ; update first cluster + mov es:[di].sf_firclus,bx + mov es:[di].sf_cluspos,0 ; retrace from start + mov es:[di].sf_lstclus,bx ; ditto + +; $endif ; endif FAT ;AN000; +$$EN26: + + ret ; we'er done ;AN000; + + EndProc New_Sft ; ;AN000; + + Break + +;******************* START OF SPECIFICATIONS *********************************** +; +; NAME: New_CP_Attrib - Update codepage and attrib in SFT +; +; FUNCTION: Copy all codepage and attrib into SFT of a SHARED file. +; +; +; INPUT: ES.DI has SFT that was just Revised. +; DS:SI has SFT that is to be updated +; +; OUTPUT: SFT is updated. +; +; REGISTERS USED: AX, BX +; (NOT RESTORED) +; +; LINKAGE: Invoked by: ShSU +; +; EXTERNAL Invoke: Call_IFS +; REFERENCES: +; +; CHANGE 10/06/87 - First release - D. M. Sewell +; LOG: +; +;******************* END OF SPECIFICATIONS ************************************* +;******************+ START OF PSEUDOCODE +************************************** +; +; START New_CP_Attrib +; +; Update codepage +; Update high attribute +; $if ifs_flag +; call Call_IFS +; $endif +; return +; +; END New_CP_Attrib +; +;******************+ END OF PSEUDOCODE +************************************** + +;; Procedure New_CP_Attrib,near ; ;AN000; + +;; mov bx,es:[di].SF_Codepage ; update codepage ;an000; +;; mov [si].SF_Codepage,bx ;an000; dms; +;; mov bl,es:[di].SF_Attr_Hi ; update high attribute ;an000; +;; mov [si].SF_Attr,bl ;an000; dms; +;; test es:[di].sf_flags,ifs_flag ; ;AN000; + +;; $if nz ; if non-FAT ;AC003; + +;; call Call_IFS ; tell IFS of SFT change ;AN000; + +;; $endif ; endif FAT ;AN000; + +;; ret ; we'er done ;AN000; + +;; EndProc New_CP_Attrib ; ;AN000; + + + Break + +;******************* START OF SPECIFICATIONS *********************************** +; +; NAME: Call_IFS - warn IFS that SFT has changed +; +; FUNCTION: Call IFS thru 2F interupt. +; +; INPUT: DS.SI points to SFT that was just Revised. +; +; OUTPUT: none +; +; REGISTERS USED: AX +; (NOT RESTORED) +; +; LINKAGE: Invoked by: ShSU, New_SFT +; +; EXTERNAL Callinstall +; REFERENCES: +; +; CHANGE 04/15/87 - First release +; LOG: +; +;******************* END OF SPECIFICATIONS ************************************* +;******************+ START OF PSEUDOCODE +************************************** +; +; START Call_IFS +; +; set up for INT +; INT 2F +; return +; +; END Call_IFS +; +;******************+ END OF PSEUDOCODE +************************************** + + Procedure Call_IFS,near ; ;AN000; + + CallInstall BlockUpdate,MultIFS,44,CX,CX ; ;AC005; + + ret ; ;AN000; + + EndProc Call_IFS ; ;AN000; + + Break + +;******************* START OF SPECIFICATIONS *********************************** +; +; INTERR - INTernal ERRor routines +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure INTERR,NEAR + + ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING + + SaveReg ; save registers that get clobbered + + push cs ; gain addressability + pop ds + mov si,ax ; get message to print + + call gout + + off si,IntErrMSG + + call gout + + RestoreReg + +INTERRL:jmp INTERRL ; hang here - we're sick + +gout: lodsb + or al,al + retz + mov ah,14 + int 10h + jmp gout + +IntErrMsg DB "Share: Internal error", 13, 10, 0 + + EndProc INTERR + + Break + + IF installed + + public skip_check + +skip_check db 0 ; start with do checking + +state_change db 0 ; SHARE change in state flag + ; 0 - no change in state + ; 1 - SHARE load state has changed + +CONT DD ? + +INT2F PROC FAR + + ASSUME CS:SHARE,DS:NOTHING,ES:NOTHING,SS:NOTHING + cmp ah,multSHARE + jnz ContJ + +; Its for SHARE! Check to see who is calling: + +; AL = +; 81h its us, with /NC - set skip_check +; - return 0F0h - end init +; 80h its us +; if skip_check is reset +; - return 0FFh - loaded +; if skip_check is set +; - reset skip_check +; - return 0F0h - end init +; +; 40h its IFSFUNC - return 0FFh - loaded +; +; 00h its anyone else - clear skip_check +; - return 0FFh - loaded + + test al,80h ; is it share? ;AN010; +; $if nz ; if it is ;AN010; + JZ $$IF29 + and al,1 ; is /NC set ;AN010; + mov al,0F0H ; assume a quiet return ;AN010; +; $if nz ; if it is ;AN010; + JZ $$IF30 + cmp skip_check,1 ; is skip_check set ? ;AN011; +; $if ne ; if it is ;AN011; + JE $$IF31 + mov state_change,1 ; set the change state flag ;AN011; +; $endif ; ;AN011; +$$IF31: + mov skip_check,1 ; set skip_check ;AN010; +; $else ; /NC not requested ;AN010; + JMP SHORT $$EN30 +$$IF30: + cmp skip_check,1 ; is skip_check set ? ;AN010; +; $if e ; if it is ;AN010; + JNE $$IF34 + mov state_change,1 ; set the change state flag ;AN011; + mov skip_check,0 ; reset skip_check ;AN010; +; $else ; else , its already clear ;AN010; + JMP SHORT $$EN34 +$$IF34: + mov al,0FFH ; and we are loaded ;AN010; +; $endif ; ;AN010; +$$EN34: +; $endif ; ;AN010; +$$EN30: + +; $else ; ;AN010; + JMP SHORT $$EN29 +$$IF29: + cmp al,40h ; is it IFSFUNC? ;AN010; +; $if ne ; if it is not ;AN010; + JE $$IF39 + + or al,al ; loop it any other value caus' ;AC010; +Freeze: + jnz freeze ; no one should EVER issue this ;AC010; + cmp skip_check,1 ; is skip_check set ? ;AN010; +; $if e ; if it is ;AN011; + JNE $$IF40 + mov state_change,1 ; set the change state flag ;AN011; +; $endif ; ;AN011; +$$IF40: + mov skip_check,0 ; and believe it ! ;AN011; + +; $endif ; ;AN010; +$$IF39: + mov al,0FFH ; else - say we are here ;AN010; +; $endif ; ;AN010; +$$EN29: + cmp state_change,1 ; SHARE installed state may have change;AN011;d +; $if e ; - update DOS ;AN011; + JNE $$IF44 + push ax ; ;AN011; + push es ; this is interesting - ;AN011; + MOV AH,Get_In_Vars ; if SHARE =1 and DOS =1 - no change;AN011; + INT 21h ; if SHARE = ;AN011; + + ASSUME ES:DOSGROUP + + mov al,skip_check ; get the SHARE operating mode ;AN011; + cmp al,1 ; is it a /nc - tell DOS " 1 " ;AN011; +; $if ne ; if not ;AN011; + JE $$IF45 + dec al ; "full" SHARE - tell DOS " -1 " ;AN011; +; $endif ; ;AN011; +$$IF45: + MOV fShare,al ; tell DOS we are here ;AN011; + pop es ; ;AN011; + pop ax ; ;AN011; + mov state_change,0 ; REset the change state flag ;AN011; +; $endif ; ;AN011; +$$IF44: + + ASSUME ES:nothing + + iret +ContJ: + JMP CONT +INT2F ENDP + + ASSUME CS:SHARE,DS:NOTHING,ES:NOTHING,SS:DOSGroup + +IRP rtn, +J&rtn proc far + call rtn + ret +j&rtn endp +endm + +IRP rtn, +J&rtn proc far + call rtn + ret +j&rtn endp +endm + +IRP sect, + Procedure E§,NEAR + PUSH AX + MOV AX,8000h+sect + INT int_ibm + POP AX + ret + EndProc E§ + + Procedure L§,NEAR + PUSH AX + MOV AX,8100h+sect + INT int_ibm + POP AX + ret + EndProc L§ + ENDM + + ENDIF + + BREAK + +;******************* START OF SPECIFICATIONS *********************************** +; +; first MFT record +; +; Note that the name field can have garbage after the trailing +; 00 byte. This is because the field might be too long, but +; not long enough (at least 16 extra bytes) to fragment. +; in this case we copy the length of the string area, not +; the length of the string and thus may copy tailing garbage. +; +;******************* END OF SPECIFICATIONS ************************************* + +PoolSize = 2048 + + PUBLIC MFT + +MFT DB 0 ; free + DW PoolSize ; PoolSize bytes long + + IF not Installed + + DB (PoolSize-3) DUP(0) ; leave rest of record +MEND DB -1 ; END record + +lck1 DW 0 ; link + DB SIZE RLR_entry-2 DUP(0) +lck2 DW OFFSET DOSGROUP:lck1 ; link + DB SIZE RLR_entry-2 DUP(0) +lck3 DW OFFSET DOSGROUP:lck2 ; link + DB SIZE RLR_entry-2 DUP(0) +lck4 DW OFFSET DOSGROUP:lck3 ; link + DB SIZE RLR_entry-2 DUP(0) +lck5 DW OFFSET DOSGROUP:lck4 ; link + DB SIZE RLR_entry-2 DUP(0) +lck6 DW OFFSET DOSGROUP:lck5 ; link + DB SIZE RLR_entry-2 DUP(0) +lck7 DW OFFSET DOSGROUP:lck6 ; link + DB SIZE RLR_entry-2 DUP(0) +lck8 DW OFFSET DOSGROUP:lck7 ; link + DB SIZE RLR_entry-2 DUP(0) + + CODE ENDS + + %out Ignore this END error (blasted assembler) + + ENDIF + +IF Installed + + ASSUME CS:SHARE,DS:NOTHING,ES:NOTHING,SS:NOTHING + + IF1 +InitSpace DW PoolSize + ELSE + IF shareinit-MFT LT PoolSize +InitSpace DW PoolSize + ELSE +InitSpace DW shareinit-MFT + ENDIF + ENDIF +InitLocks DW 20 + + +JTable LABEL BYTE + DD ? + DD JMFT_Enter ; 1 MFT_enter + DD JMFTClose ; 2 MFTClose + DD JMFTclU ; 3 MFTclU + DD JMFTcloseP ; 4 MFTCloseP + DD JMFTcloN ; 5 MFTCloN + DD JSet_Mult_Block ; 6 Set_Mult_Block + DD JClr_Mult_Block ; 7 Clr_Mult_Block + DD JChk_Block ; 8 Chk_Block + DD JMFT_Get ; 9 MFT_get + DD JShSave ; 10 ShSave + DD JShChk ; 11 ShChk + DD JShCol ; 12 ShCol + DD JShCloseFile ; 13 ShCloseFile + DD JShSU ; 14 ShSU +JTableLen = $ - JTable + +; $SALUT (4,9,17,36) + ;--------------------------------------- + ; STRUCTURE TO DEFINE ADDITIONAL + ; COMMAND LINE PARAMETERS + ;--------------------------------------- +PARMS LABEL DWORD + DW OFFSET PARMSX ; POINTER TO PARMS STRUCTURE + DB 0 ; NO DELIMITER LIST FOLLOWS + DB 0 ; NUMBER OF ADDITIONAL DELIMITERS + + ;--------------------------------------- + ; STRUCTURE TO DEFINE SORT + ; SYNTAX REQUIREMENTS + ;--------------------------------------- +PARMSX LABEL BYTE + DB 0,0 ; THERE ARE NO POSITIONAL PARAMETERS + DB 1 ; THERE ARE ONLY ONE TYPE OF SWITCH + DW OFFSET SW ; POINTER TO THE SWITCH DEFINITION AREA + DW 0 ; THERE ARE NO KEYWORDS IN SHARE SYNTAX + + ;--------------------------------------- + ; STRUCTURE TO DEFINE THE SWITCHES + ;--------------------------------------- + +SW LABEL WORD + DW 08001H ; MUST BE NUMERIC + DW 0 ; NO FUNCTION FLAGS + DW OFFSET SWITCH_BUFF ; PLACE RESULT IN SWITCH BUFFER + DW OFFSET VALUES ; NEED VALUE LIST + DB 3 ; TWO SWITCHES IN FOLLOWING LIST +F_SW DB "/F",0 ; /F: INDICATES n FILESPACE REQUESTED +L_SW DB "/L",0 ; /L: INDICATES m LOCKS REQUESTED +N_SW DB "/NC",0 ; /NC: INDICATES no checking required + + + ;--------------------------------------- + ; VALUE LIST DEFINITION FOR n + ;--------------------------------------- + +VALUES LABEL BYTE + DB 1 ; ONE VALUE ALLOWED + DB 1 ; ONLY ONE RANGE + DB FILE_SWITCH ; IDENTIFY IT AS n + DD 1,65535 ; USER CAN SPECIFY /+1 THROUGH /+65535 + + ;--------------------------------------- + ; RETURN BUFFER FOR SWITCH INFORMATION + ;--------------------------------------- +; $SALUT (4,17,27,36) + +SWITCH_BUFF LABEL BYTE +SW_TYPE DB ? ; TYPE RETURNED +SW_ITEM_TAG DB ? ; SPACE FOR ITEM TAG +SW_SYN DW ? ; POINTER TO SWITCH LIST ENTRY +SW_VALUE DD ? ; SPACE FOR VALUE + +; $SALUT (4,4,9,41) + + Break + +;******************* START OF SPECIFICATIONS *********************************** +; +; INIT - INITalization routines +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure Init,NEAR + + PUSH CS + POP DS + + ASSUME DS:SHARE + + MOV BX,InitSpace + + SUB BX,3 + MOV SI,OFFSET MFT + MOV WORD PTR [SI+1],BX ; length of first item + ADD SI,BX ; link to end of structure + MOV BYTE PTR [SI],-1 ; signal end + INC SI ; point to next free byte + + MOV CX,initlocks ; count for loop + MOV AX,0 + +; $do ; ;AC000; +$$DO48: + + MOV [SI].RLR_next,AX ; link in previous + MOV AX,SI ; this is now previous + ADD SI,SIZE RLR_Entry ; move to next object + +; $enddo loop ; ;AC000; + LOOP $$DO48 + + MOV FreLock,AX ; point to beginning of free list + + MOV DX,CS + MOV BX,ES + SUB DX,BX + ADD SI,15 + RCR SI,1 + SHR SI,1 + SHR SI,1 + SHR SI,1 + + ADD SI,DX + PUSH SI ; # of paras for share on stack + + MOV AX,(Get_Interrupt_Vector SHL 8) + 2Fh + INT 21h + MOV WORD PTR CONT,BX + MOV WORD PTR CONT+2,ES + MOV AX,(Set_Interrupt_Vector SHL 8) + 2Fh + MOV DX,OFFSET INT2F + INT 21h + ;--------------------------------------- + ; Notify the DOS that we are around so that + ; the DOS can make expensive calls to us. + ;--------------------------------------- + MOV AH,Get_In_Vars + INT 21h + + ASSUME ES:DOSGROUP + + mov al,skip_check ; get the SHARE operating mode ;AN011; + cmp al,1 ; is it a /nc - tell DOS " 1 " ;AN011; + +; $if ne ; if not ;AN011; + JE $$IF50 + dec al ; "full" SHARE - tell DOS " -1 " ;AN011; +; $endif ; +$$IF50: + + MOV fShare,al ; tell DOS we are here ;AC011; + ;--------------------------------------- + ; Cram in the new jump table + ;--------------------------------------- + CLI + MOV SI,OFFSET JTable + MOV DI,OFFSET JShare + MOV CX,JTableLen/2 + REP MOVSW + ;--------------------------------------- + ; Examine the size of the FCB cache. + ; If it is NOT the system default of 4,0 + ; change it (via reallocation) to 16,8. + ; The old table is lost. + ;--------------------------------------- + ASSUME DS:NOTHING + + CMP KeepCount,0 + +; $if z,and ; if the ",0" part and ;AC000; + JNZ $$IF52 + + LDS SI,ES:[BX].SYSI_FCB ; point to the existing cache + CMP [SI].sfCount,4 + +; $if z ; if the "4," part then ;AC000; + JNZ $$IF52 + + ;--------------------------------------- + ; Whammo, we need to allocate 16 * size + ; of SF_entry + size of sfTable. + ; Compute this size in paragraphs + ;--------------------------------------- + MOV AX,16 + MOV CX,size sf_entry + MUL CX + ADD AX,(size sf) - 2 + ;--------------------------------------- + ; This size is in bytes... + ; Round up to paragraph size + ;--------------------------------------- + ADD AX,0Fh + RCR AX,1 + SHR AX,1 + SHR AX,1 + SHR AX,1 + ;--------------------------------------- + ; AX is the number of paragraphs to add. + ; Word on stack is current TNR size. + ; Make dos point to new table + ;--------------------------------------- + MOV WORD PTR ES:[BX].SYSI_FCB,0 + MOV WORD PTR ES:[BX].SYSI_FCB+2,SS + POP SI + ADD WORD PTR ES:[BX].SYSI_FCB+2,SI + ;--------------------------------------- + ; Initialize table parts, next link + ; and size + ;--------------------------------------- + MOV DS,WORD PTR ES:[BX].SYSI_FCB+2 + MOV WORD PTR DS:[sfLink],-1 + MOV WORD PTR DS:[sfLink+2],-1 + MOV DS:[sfcount],16 + ;--------------------------------------- + ; Set up succeeding LRU size + ;--------------------------------------- + MOV KeepCount,8 + + ADD SI,AX + PUSH SI + +; $endif ; endif - "4,0" ;AC000; +$$IF52: + + ;--------------------------------------- + ; Clean out the FCB Cache + ;--------------------------------------- + LES DI,ES:[BX].SYSI_FCB + + ASSUME ES:Nothing + + MOV CX,ES:[DI].SFCount + LEA DI,[DI].SFTable + +; $do ; ;AC000; +$$DO54: + + MOV ES:[DI].sf_ref_count,0 + MOV WORD PTR ES:[DI].sf_position,0 + MOV WORD PTR ES:[DI].sf_position+2,0 + ADD DI,SIZE sf_entry + +; $enddo loop ; ;AC000; + LOOP $$DO54 + + STI + + ASSUME ES:NOTHING + + XOR BX,BX + MOV CX,5 ; StdIN,StdOUT,StdERR,StdAUX,StdPRN + +; $do ; Close STD handles before ;AC000; +$$DO56: + ; keep process + MOV AH,CLOSE + INT 21H + INC BX + +; $enddo loop ; ;AC000; + LOOP $$DO56 + + POP DX ; T+R size in DX + MOV AX,(Keep_Process SHL 8) + 0 + INT 21h + MOV AX,(EXIT SHL 8) + 1 + INT 21h ; We'er now resident, return to DOS + + EndProc Init + + Break + +;******************* START OF SPECIFICATIONS *********************************** +; +; SHAREINIT - Share initialization entry point +; +;******************* END OF SPECIFICATIONS ************************************* + + Procedure SHAREINIT,NEAR + + ASSUME CS:SHARE,DS:NOTHING,ES:NOTHING,SS:STACK + +; int 3 + nop + nop + + + PUSH DS ; save PSP segment for later stack ;AC001; + ; relocation + + ;--------------------------------------- + ; Load Messages + ;--------------------------------------- + call ShLoadMsg ; ;AN000; + ;--------------------------------------- + ; At this point, the DOS version is OK. + ; (checked by SYSLOADMSG) + ; Now - Check the DOS data version + ;--------------------------------------- +; $if c,or ; if not same as us ;AC009; + JC $$LL58 + + MOV AH,Get_In_Vars + INT 21h + + ASSUME ES:DOSGROUP + + CMP DataVersion,ShareDataVersion + + ASSUME ES:NOTHING + +; $if ne ; if not same as us ;AC000; + JE $$IF58 +$$LL58: + mov ax,(Utility_Msg_CLASS shl 8) + Bad_DOS_Ver ; ;AN000; + call ShDispMsg ; ;AN000; +; $endif ; endif - not same as us ;AC000; +$$IF58: + + ;--------------------------------------- + ; Deallocate memory if possible + ;--------------------------------------- + mov ax,ds:[pdb_environ] + or ax,ax + +; $if nz ; if > 0 deallocate memory ;AC000; + JZ $$IF60 + mov es,ax + mov ah,dealloc + int 21h +; $endif ; endif - > 0 deallocate memory ;AC000; +$$IF60: + + ;--------------------------------------- + ; Parse the command line + ;--------------------------------------- + call ShComndParse ; ;AN000; + ;--------------------------------------- + ; Check to see if share already installed. + ;--------------------------------------- + mov al,skip_check ; ;AN010; + or al,80h ; signal its SHARE calling ;AN010; + mov ah,multShare ; ;AC010; + INT 2Fh ; ;AC010; + CMP AL,0FFh ; ;AC010; + +; $if z ; if we'er already loaded ;AC010; + JNZ $$IF62 + mov ax,(UTILITY_MSG_CLASS shl 8) + Sh_Already_Loaded ; ;AC010; + call ShDispMsg ; ;AC010; +; $endif ; endif - we'er already loaded ;AC010; +$$IF62: + + ;--------------------------------------- + ; Check to see if share installed and + ; a toggle was just performed + ;--------------------------------------- + CMP AL,0F0h ; ;AN010; + +; $if z ; if we'er already loaded ;AN010; + JNZ $$IF64 + + MOV AX,(EXIT SHL 8) ; ;AN010; + INT 21h ; Return to DOS with RC = 0 ;AN010; + +; $endif ; endif - we'er already loaded ;AN010; +$$IF64: + + ;--------------------------------------- + ; All set to initialize the world. + ; Make sure that we have enough memory + ; for everything in our little 64K here. + ; First get avail count of paras. + ;--------------------------------------- + pop es ; recover PSP segment ;AC002; + push es ; ;AC002; + MOV BX,CS + MOV AX,ES:[PDB_Block_Len] + SUB AX,BX + ;--------------------------------------- + ; AX has the number of paragraphs + ; available to us after the beginning + ; of CS. Max this out at 64K. + ;--------------------------------------- + CMP AX,1000h + +; $if a ; if more than we can handle ;AC000; + JNA $$IF66 + MOV AX,1000h ; force it +; $endif ; endif - more than we can handle ;AC000; +$$IF66: + + ;--------------------------------------- + ; Take AX paragraphs and convert them + ; into BX:CX bytes. + ;--------------------------------------- + XOR BX,BX + SHL AX,1 + SHL AX,1 + SHL AX,1 + SHL AX,1 + ADC BX,0 + MOV CX,AX + ;--------------------------------------- + ; compute in DX:AX, the size + ; requested by the user + ;--------------------------------------- + MOV AX,initlocks + MOV SI,size RLR_Entry + MUL SI + ADD AX,OFFSET MFT + ADC DX,0 + ADD AX,InitSpace + ADC DX,0 + ;--------------------------------------- + ; Compare the 32 bit sizes DX:AX and BX:CX. + ; If BX:CX is smaller, then we + ; are out of memory. + ;--------------------------------------- + + CMP DX,BX ; try upper half first + +; $if a,or ; if most significant is bigger or ;AC000; + JA $$LL68 + +; $if e,and ; if equal and ;AC000; + JNE $$IF68 + + CMP AX,CX ; + +; $if a ; if least significant is bigger ;AC000; + JNA $$IF68 +$$LL68: + + mov ax,(EXT_ERR_CLASS shl 8) + No_Mem_Error ; issue error message ;AN000; + + call ShDispMsg ; ;AN000; + +; $endif ; endif - bigger ;AC000; +$$IF68: + + ;-------------------------------------- + ; Move stack to PSP area. Otherwise we + ; will run into problems with growing + ; the stack into the lock records. + ;--------------------------------------- + POP AX ; this is the entry value for DS (PSP) ;AC001; + MOV SS,AX ; ;AC001; + MOV SP,100h ; ;AC001; + + ASSUME SS:NOTHING + ;--------------------------------------- + ; Continue with rest of initialization + ;--------------------------------------- + JMP INIT + + EndProc SHAREINIT + + Break + +;******************* START OF SPECIFICATIONS *********************************** +; +; NAME: ShLoadMsg - Share Load Message +; +; FUNCTION: Load the Share messages into the message buffer. +; +; INPUT: None +; +; OUTPUT: Messages loaded into the message buffer and Message +; Sevices code initalized +; +; REGISTERS USED: DI AX CX DX +; (NOT RESTORED) +; +; LINKAGE: Call near +; +; NORMAL CF = O +; EXIT: +; +; ERROR CF = 1 +; EXIT: +; +; CHANGE 04/15/87 - First release +; LOG: +; +;******************* END OF SPECIFICATIONS ************************************* + + ;--------------------------------------- + ; Message Equates + ;--------------------------------------- + +; $SALUT (4,27,34,41) + +Bad_DOS_Ver equ 1 ; Incorrect DOS version ;AN000; +Sh_Already_Loaded equ 2 ; SHARE already loaded message number ;AN000; +No_Mem_Error equ 8 ; insufficient memory message number ;AN000; + +; $SALUT (4,4,9,41) + + Procedure ShLoadMsg,near ; ;AN000; + ;--------------------------------------- + ; Load the Messages + ;--------------------------------------- +EXTRN SYSLOADMSG:NEAR ; ;AN000; + + call SYSLOADMSG ; ;AN000; + +; $IF C ; if we have a MAJOR problem ;AN000; + JNC $$IF70 + mov ah,dh ; save the class + call ShDispMsg ; ;AN000; + ; For pre DOS 2.0, we may come back + xor ax,ax ; here - so do it the old way + push ss ; just in case + push ax ; + +xxx proc far ; ;AN000; + ret ; ;AN000; +xxx endp ; ;AN000; + +; $ENDIF ; endif - we have a MAJOR problem ;AN000; +$$IF70: + + + ret ; ;AN000; + + EndProc ShLoadMsg ; + + Break + +;******************* START OF SPECIFICATIONS *********************************** +; +; NAME: ShDispMsg - Share Display Message +; +; FUNCTION: Display the messages for share +; +; INPUT: AX = message number - AH - Class +; AL - Number +; +; OUTPUT: - Messages output to Output Device +; - Exit to DOS +; +; REGISTERS USED: CX DX +; (NOT RESTORED) +; +; LINKAGE: Call near +; +; NORMAL CF = O +; EXIT: +; +; ERROR CF = 1 +; EXIT: CX = 0 - INCORRECT DOS VERSION +; +; CHANGE 04/15/87 - First release +; LOG: +; +;******************* END OF SPECIFICATIONS ************************************* + +; $SALUT (4,27,34,41) + + ; The following structure is a + ; SYSMSG SUBLIST control block. + ; It is initalized for the "already + ; installed " message. The parse + ; routine will set it up to work + ; for parseing. +SUBLIST LABEL WORD + + db sub_size ; size of sublist + db 0 ; reserved +msg_offset dw offset SHARE_Name ; insert 'SHARE' + +msg_segment LABEL WORD + +IF NOT INSTALLED + + dw CODE + +ELSE + + dw SHARE + +ENDIF + +num_ins db 1 ; only one insert + db Char_Field_ASCIIZ ; data type flag - ascii z string +max_ins db SHARE_Name_Size ; maximum field size +min_ins db SHARE_Name_Size ; minimum field size + db " " ; pad character + +sub_size equ $ - SUBLIST + +SHARE_Name LABEL WORD + + db "SHARE" + +SHARE_Name_Size equ $ - Share_Name + + db 0 ; make it a Z string +; $SALUT (4,4,9,41) + + Procedure ShDispMsg,near ; ;AN000; + ;--------------------------------------- + ; Set up required parameters + ;-------------------------------------- + MOV BX,STDERR ;display message on STD ERROR ;AN000; + XOR CX,CX ;no substitution required ;AN000; + XOR DX,DX ;set flags to 0 ;AN000; + DEC DH ;and class to utility ;AN000; + cmp ah,PARSE_ERR_CLASS ; +; $if be,and ; ;AC009; + JNBE $$IF72 + mov dh,ah ; +; $if e ; set up implied substitution ;AC009; + JNE $$IF72 + + ASSUME DS:nothing,ES:DOSGROUP + + mov num_ins,cl ; set number of inserts to 0 ;AN009; + mov BYTE PTR max_ins,030h ; set maximum size of insert ;AN009; + mov BYTE PTR min_ins,1 ; set minimum size of insert ;AN009; + push ds ; set up segment ;AN009; + pop [msg_segment] ; ;AN009; + mov BYTE PTR ds:[si],0 ; turn it into a ASCIIZ string ;AN009; + cmp si,msg_offset ; is there something there? ;AN009; +; $if a ; if it is... ;AN009; + JNA $$IF73 + inc cx ; ;AN009; +; $endif ; ;AN009; +$$IF73: +; $endif ; +$$IF72: + cmp al,Sh_Already_Loaded ; SHARE already loaded message ? ;AN000; +; $if e ; if it is... ;AN000; + JNE $$IF76 + inc cx ; + mov msg_offset,OFFSET SHARE_name ; ensure the pointer is right ;AN010; +; $endif ; +$$IF76: + push cs ; ensure that SYSMSG has proper ;AC009; + pop ds ; addressability ;AC009; + lea si,SUBLIST ; point to sublist ;AC009; + xor ah,ah ; ;AN000; + + ;-------------------------------------- + ; Output the Message + ;--------------------------------------- +EXTRN SYSDISPMSG:NEAR ; ;AN000; + + CALL SYSDISPMSG ; ;AN000; + +; $IF C ; if error occured ;AN000; + JNC $$IF78 + + CALL Get_DOS_Error ; a DOS extended error occured ;AN000; + CALL SYSDISPMSG ; try to issue it ;AN000; + +; $ENDIF ; endif - error occured ;AN000; +$$IF78: + + MOV AX,(EXIT SHL 8) + 0FFH ; exit to DOS ;AN000; + INT 21h ; ;AN000; + + ret ; may return if pre DOS 2.0 ;AN000; + + EndProc ShDispMsg ; ;AN000; + + BREAK < Get_DOS_Error > + +;******************* START OF SPECIFICATIONS *********************************** +;Routine name: Get_DOS_Error +;******************************************************************************* +; +;Description: Call DOS to obtain DOS extended error # +; +;Called Procedures: None +; +;Input: None +; +;Output: AX = error number +; DH = DOS extended error class +; +;Change History: Created 5/01/87 FG +; +;******************* END OF SPECIFICATIONS ************************************* +;******************+ START OF PSEUDOCODE +************************************** +; +; START Get_DOS_Error +; +; call DOS for extended error (INT21 GetExtendedError + 00 <5900>) +; set up registers for return +; ret +; +; END Get_DOS_Error +; +;******************- END OF PSEUDOCODE -************************************** + + public Get_DOS_Error + + Get_DOS_Error PROC NEAR + + mov ax,(GetExtendedError shl 8) ; DOS ext. error ;AN000; + xor bx,bx + push es ; ;AN000; + INT 21h ; GetExtendedError + not_used <5900>;AN000; + pop es + mov bx,STDERR ; fix up bx ;AN000; + xor cx,cx ; fix up cx ;AN000; + mov dh,EXT_ERR_CLASS ; set class to dos error + + ret ; ;AN000; + + ENDPROC Get_DOS_Error + + Break + +;******************* START OF SPECIFICATIONS *********************************** +; +; NAME: ShComndParse - Share Command line Parser +; +; FUNCTION: Call the DOS PARSE Service Routines to process the command +; line. Search for valid switches (/F:n and /L:m) and +; update the values for file size and number of locks accordingly +; +; INPUT: Parameter string from command line in the PSP +; +; OUTPUT: INITspace and INITlocks are updated. +; +; REGISTERS USED: ES DI AX BX CX DX +; (NOT RESTORED) +; +; LINKAGE: Call +; +; NORMAL - If /F:n specified, then INITspace is updated. +; EXIT: - If /L:m specified, then INITlocks is updated. +; +; ERROR If user enters: +; EXIT: - any parameter or switch other than /F:n or /L:m +; - an invalid value for "n" or "m" +; then this routine will display the "Invalid Parameter" +; error message and terminate. +; +; EXTERNAL - System parse service routines +; REFERENCES: - INT21 - GET PSP Function Call 062h +; +; CHANGE 04/15/87 - First release +; LOG: +; +;******************* END OF SPECIFICATIONS ************************************* +;******************+ START OF PSEUDOCODE +************************************** +; +; START +; +; return +; +; END +; +;******************- END OF PSEUDOCODE -************************************* + +; $SALUT (4,27,34,41) + + ;-------------------------------------- + ; Parse Equates + ;-------------------------------------- + +EOL equ -1 ; Indicator for End-Of-Line ;AN000; +NOERROR equ 0 ; Return Indicator for No Errors ;AN000; +FILE_SWITCH equ 1 ; this is a file switch ;AN000; +LOCK_SWITCH equ 2 ; this is a lock switch ;AN000; +Syntax_Error equ 9 ; maximum PARSE error # ;AN000; + +; $SALUT (4,4,9,41) + + Procedure ShComndParse,near ; ;AN000; + ;-------------------------------------- + ; Get address of command line + ;-------------------------------------- +EXTRN SYSPARSE:NEAR ; ;AN000; + + MOV SI,0081H ; OFFSET OF COMMAND LINE IN PSP ;AN000; + MOV AH,62H ; AH=GET PSP ADDRESS FUNCTION CALL ;AN000; + INT 21H ; PSP SEGMENT RETURNED IN BX ;AN000; + MOV DS,BX ; PUT PSP SEG IN DS ;AN000; + MOV CX,0 ; NUMBER OF PARMS PROCESSED SO FAR ;AN000; + PUSH CS ; ;AN000; + POP ES ; ;AN000; + + ASSUME ES:SHARE ; ;AN000; + + ;-------------------------------------- + ; Loop for each operand at DS:SI + ;-------------------------------------- +; $do ; ;AN000; +$$DO80: + + LEA DI,PARMS ; ADDRESS OF PARSE CONTROLS ;AN000; + MOV DX,0 ; RESERVED ;AN000; + mov msg_offset,si ; save the start scan point ;AC009; + CALL SYSPARSE ; PARSE IT! ;AN000; + CMP AX,EOL ; ARE WE AT END OF COMMAND LINE ? ;AN000; + +; $leave e ; ;AN000; + JE $$EN80 + + CMP AX,NOERROR ; ANY ERRORS? ;AN000; + +; $if ne,or ; if parse says error or ;AN000; + JNE $$LL82 + + MOV AX,Syntax_Error ; Parse syntax error - just in case ;AN000; + MOV BX,DX ; PLACE RESULT ADDRESS IN BX ;AN000; + CMP BX,OFFSET SWITCH_BUFF ; ;AN000; + +; $if ne ; if no pointer ;AN000; + JE $$IF82 +$$LL82: + + call PARSE_ERROR ; call error routine ;AN000; + +; $endif ; endif - error ;AN000; +$$IF82: + + MOV AX,WORD PTR SW_VALUE ; load the value ;AN000; + MOV BX,SW_SYN ; load pointer to synonym ;AN000; + + ;-------------------------------------- + ; If user said /F:n, then + ;-------------------------------------- + + CMP BX,OFFSET F_SW ; IF USER SPECIFIED /F ;AN000; + +; $if e ; ;AN000; + JNE $$IF84 + + CMP INITspace,AX ; is default < requested ? ;AN000; + +; $if b ; if default is < ;AN000; + JNB $$IF85 + MOV INITspace,AX ; save the new value ;AN000; +; $endif ; endif (else leave it alone) ;AN000; +$$IF85: + +; $else ; else - CHECK FOR LOCKS ;AN000; + JMP SHORT $$EN84 +$$IF84: + + ;--------------------------------------- + ; If user said /L:m, then update INITlocks + ;--------------------------------------- + CMP BX,OFFSET L_SW ; IF USER SPECIFIED /L ;AN000; + +; $if e ; if it is ;AN000; + JNE $$IF88 + + CMP INITlocks,AX ; is default < requested ? ;AN000; + +; $if b ; if default is < ;AN000; + JNB $$IF89 + MOV INITlocks,AX ; save the value ;AN000; +; $endif ; endif (else leave it alone) ;AN000; +$$IF89: + +; $else ; else - CHECK FOR TOGGLE ;AN010; + JMP SHORT $$EN88 +$$IF88: + + ;--------------------------------------- + ; If user said /NC, then update check_flag + ;--------------------------------------- + CMP BX,OFFSET N_SW ; IF USER SPECIFIED /NC ;AN010; +; $if ne ; if error ;AC010; + JE $$IF92 + MOV AX,Syntax_Error ; Parse syntax error ;AN000; + call PARSE_ERROR ; call error routine ;AN000; +; $endif ; endif - error ;AC010; +$$IF92: + + mov skip_check,1 ; set the skip check flag ;AN010; + +; $endif ; endif - CHECK FOR TOGGLE ;AN010; +$$EN88: + +; $endif ; endif - CHECK FOR LOCKS ;AN000; +$$EN84: + +; $enddo ; CHECK FOR NEXT PARM ;AN000; + JMP SHORT $$DO80 +$$EN80: + + ret ; NORMAL RETURN TO CALLER ;AN000; + + ;--------------------------------------- + ; If any other parameter specified, + ; display message and quit + ;--------------------------------------- +PARSE_ERROR: ; ;AN000; + + cmp al,Syntax_Error ; error 1 to 9 ? ;AN000; + +; $if a ; if parse error ;AN000; + JNA $$IF97 + + mov al,Syntax_Error ; Parse syntax error + +; $endif ; endif errors ;AN000; +$$IF97: + + lea bx,Parse_Ret_Code + xlat cs:[bx] + mov ah,PARSE_ERR_CLASS ; set class to parse error ;AN000; + + CALL ShDispMsg ; display the parse error ;AN000; + + ret ; this should never be used + +Parse_Ret_Code label byte + + db 0 ; Ret Code 0 - + db 9 ; Ret Code 1 - Too many parameters + db 9 ; Ret Code 2 - Required parameter missing + db 3 ; Ret Code 3 - Invalid switch + db 9 ; Ret Code 4 - Invalid keyword + db 9 ; Ret Code 5 - (reserved) + db 6 ; Ret Code 6 - Parm val out of range + db 9 ; Ret Code 7 - Parameter val not allowed + db 9 ; Ret Code 8 - Parameter val not allowed + db 9 ; Ret Code 9 - Parm format not correct + + EndProc ShComndParse ; ;AN000; + + include msgdcl.inc + + SHARE ENDS + + STACK SEGMENT STACK + DB 278 + 128 DUP (?) ; 278 == IBM's ROM requirements + STACK ENDS + +ENDIF + + END shareinit + + \ No newline at end of file diff --git a/v4.0/src/CMD/SHARE/MAKEFILE b/v4.0/src/CMD/SHARE/MAKEFILE new file mode 100644 index 0000000..d40282f --- /dev/null +++ b/v4.0/src/CMD/SHARE/MAKEFILE @@ -0,0 +1,67 @@ +#************************ makefile for cmd\share ************************* + +msg =..\..\messages +dos =..\..\dos +inc =..\..\inc +hinc =..\..\h +here =..\cmd\share # This is the path from INC or MAP dir's to here. +make =nmake -i + +# +####################### dependencies begin here. ######################### +# + +all: share.exe + +msdos.cl1: $(dos)\msdos.skl \ + $(msg)\$(COUNTRY).msg \ + $(dos)\makefile + copy $(dos)\msdos.skl + nosrvbld msdos.skl $(msg)\$(COUNTRY).msg + + +share.ctl: share.skl $(msg)\$(COUNTRY).msg + +$(inc)\dossym.inc: $(inc)\dosmac.inc $(inc)\bpb.inc $(inc)\curdir.inc \ + $(inc)\buffer.inc $(inc)\sysvar.inc $(inc)\vector.inc \ + $(inc)\mult.inc $(inc)\dirent.inc $(inc)\dpb.inc \ + $(inc)\cpmfcb.inc $(inc)\find.inc $(inc)\pdb.inc \ + $(inc)\exe.inc $(inc)\sf.inc $(inc)\arena.inc \ + $(inc)\intnat.inc $(inc)\mi.inc $(inc)\filemode.inc \ + $(inc)\error.inc $(inc)\syscall.inc + echo " touch dossym.inc " + +gshare.obj: gshare.asm $(inc)\dossym.inc $(inc)\mft.inc \ + $(inc)\bugtyp.asm + +gshare2.obj: gshare2.asm $(inc)\dossym.inc $(inc)\dosseg.asm $(inc)\mft.inc \ + $(inc)\bugtyp.asm + +sharesr.obj: sharesr.asm $(inc)\parse.asm $(inc)\psdata.inc + +sharelnk.obj: sharelnk.asm + +$(inc)\nibdos.obj: + cd $(inc) + $(make) + cd $(here) + +$(inc)\const2.obj: + cd $(inc) + $(make) + cd $(here) + +$(inc)\msdata.obj: + cd $(inc) + $(make) + cd $(here) + +$(inc)\msdosme.obj: + cd $(inc) + $(make) + cd $(here) + +share.exe: share.ctl gshare.obj gshare2.obj sharesr.obj $(inc)\nibdos.obj \ + $(inc)\const2.obj $(inc)\msdata.obj $(inc)\msdosme.obj sharelnk.obj \ + share.lnk + link @share.lnk diff --git a/v4.0/src/CMD/SHARE/SHARE.LNK b/v4.0/src/CMD/SHARE/SHARE.LNK new file mode 100644 index 0000000..879e756 --- /dev/null +++ b/v4.0/src/CMD/SHARE/SHARE.LNK @@ -0,0 +1,9 @@ +gshare+ +gshare2+ +sharesr+ +sharelnk+ +..\..\inc\nibdos+ +..\..\inc\const2+ +..\..\inc\msdata+ +..\..\inc\msdosme +share,share.map /m; diff --git a/v4.0/src/CMD/SHARE/SHARE.SKL b/v4.0/src/CMD/SHARE/SHARE.SKL new file mode 100644 index 0000000..0be6308 --- /dev/null +++ b/v4.0/src/CMD/SHARE/SHARE.SKL @@ -0,0 +1,27 @@ +;================================================ +; SHARE Message Skeleton File +;================================================ + +:util SHARE + +:class 1 + +:use EXTEND8 + +:class 2 + ;1 - Too many operands + ;2 - Required operand missing +:use PARSE3 ;3 - Not in switch list provided + ;4 - Not in keyword list provided +:use PARSE6 ;6 - Out of range specified + ;7 - Not in value list provided + ;8 - Not in string list provided +:use PARSE9 ;9 - Invalid Parameter + +:class A + +:use 1 COMMON1 ; Incorrect DOS version +:use 2 COMMON2 ; "%1 already installed" + +:end + \ No newline at end of file diff --git a/v4.0/src/CMD/SHARE/SHAREHDR.INC b/v4.0/src/CMD/SHARE/SHAREHDR.INC new file mode 100644 index 0000000..e00d5f6 --- /dev/null +++ b/v4.0/src/CMD/SHARE/SHAREHDR.INC @@ -0,0 +1,72 @@ + page 80,132 +;******************* START OF SPECIFICATIONS *********************************** +; +; MODULE NAME: SHARE.EXE (a true EXE file) +; +; DESCRIPTIVE NAME: SHARE resident service routines - part 1 - GSHARE.SAL +; - part 2 - GSHARE2.SAL +; - part 3 - SHARESR.SAL +; +; FUNCTION: Provide file sharing services for DOS +; +; ENTRY POINT: DOS Jump Table - installed by SHARE at initalization +; +; MFT_Enter 1 +; MFTClose 2 +; MFTClu 3 +; MFTCloseP 4 +; MFTCloN 5 +; Set_Mult_Block 6 +; Clr_Mult_Block 7 +; Chk_Block 8 +; MFT_Get 9 +; +; INPUT: See Prolog to individual entry points +; +; EXIT NORMAL: CF = 0 and requested task performed. +; +; EXIT ERROR: CF = 1 ans error code in AX +; +; INTERNAL REFERENCES: +; +; ROUTINES: Set_Block BCS +; Clr_Block CSL +; CLP CUC +; Load_Regs CSI +; ASC GOM +; +; DATA AREAS: +; +; EXTERNAL REFERENCES: INT 21 INT 2F +; together with: +; +; fnm:near, rsc:near, rmn:near, cps:near, ofl:near, sle:near, interr:near +; +; ROUTINES: +; +; DATA AREAS: +; +; NOTES: The second part of this utility is GSHARE2.ASM +; +; REVISION HISTORY: Version 1.0 09/09/83 - first release GL +; 09/13/83 - Installability MZ +; 01/11/84 - FCB compatability changes MZ +; PTM P000438 08/21/86 - SFT LCK FIELDS not 0 error DL +; Ax000 Ver 4.0 04/15/87 - changed:- Set_Block FJG +; - Clr_Block FJG +; - Chk_Block FJG +; - CLP FJG +; new: - Set_Mult_Block FJG +; - Clr_Mult_Block FJG +; - Load_Regs FJG +; - Clr_List FJG +; Ax002 PTM P001658 10/15/87 - changed I/F to IBMDOS FJG +; Ax003 PTM P002064 10/15/87 - ShSU SFT - IFS call error FJG +; Ax004 PTM P002121 10/29/87 - Clr_Mult_Block cx=-1 err FJG +; Ax005 PTM P002322 11/06/87 - Call_IFS - 2F semaphore FJG +; Ax006 DCR D000494 12/17/87 - DOS 4.00 function reductionFJG +; Ax007 PTM P003841 03/17/88 - access error for Turbo L FJG +; Ax008 PTM P003880 03/17/88 - duped handle error FJG +; Ax009 PTM P003910 03/17/88 - wrong parse error format FJG +; Ax010 DCR D000526 04/27/88 - add /nc switch support FJG +; Ax011 PTM P004546 05/03/88 - add /nc support to fShare FJG diff --git a/v4.0/src/CMD/SHARE/SHARELNK.ASM b/v4.0/src/CMD/SHARE/SHARELNK.ASM new file mode 100644 index 0000000..c264032 --- /dev/null +++ b/v4.0/src/CMD/SHARE/SHARELNK.ASM @@ -0,0 +1,213 @@ + PAGE ,132 ;  +; SCCSID = @(#)SHARELNK.asm 1.0 87/05/11 +TITLE SHARELNK LINK FIX ROUTINES - Routines to resolve SHARE externals +NAME SHARELNK + +.xlist +.xcref +INCLUDE DOSSYM.INC +INCLUDE DEVSYM.INC +.cref +.list + +CODE SEGMENT BYTE PUBLIC 'CODE' +code ENDS + +include dosseg.asm + + +code SEGMENT BYTE PUBLIC 'code' + ASSUME CS:dosgroup + + PUBLIC IRETT, SWAP_AREA_LEN, Hash_Temp +IRETT DW 0 +SWAP_AREA_LEN DW 0 +Hash_Temp DW 0 + +procedure LCRITDEVICE,FAR + NOP +Endproc LCRITDEVICE,FAR + +procedure SETMEM,FAR + NOP +endproc SETMEM,FAR + +procedure SKIPONE,FAR + NOP +endproc SKIPONE,FAR + +procedure TWOESC,FAR + NOP +endproc TWOESC,FAR + +procedure $STD_CON_STRING_INPUT_NO_ECHO,FAR + NOP +endproc $STD_CON_STRING_INPUT_NO_ECHO,FAR + +procedure $STD_CON_INPUT_NO_ECHO,FAR + NOP +endproc $STD_CON_INPUT_NO_ECHO,FAR + +procedure INT2F,FAR + NOP +endproc INT2F,FAR + +procedure $dup_pdb,FAR + NOP +endproc $dup_pdb,FAR + +procedure LEAVEDOS,FAR + NOP +endproc LEAVEDOS,FAR + +procedure GETCH,FAR + NOP +endproc GETCH,FAR + +procedure COPYONE,FAR + NOP +endproc COPYONE,FAR + +procedure $SETDPB,FAR + NOP +endproc $SETDPB,FAR + +procedure CALL_ENTRY,FAR + NOP +endproc CALL_ENTRY,FAR + +procedure ECRITDISK,FAR + NOP +endproc ECRITDISK,FAR + +procedure COPYLIN,FAR + NOP +endproc COPYLIN,FAR + +procedure LCRITDISK,FAR + NOP +endproc LCRITDISK,FAR + +procedure QUIT,FAR + NOP +endproc QUIT,FAR + +procedure BACKSP,FAR + NOP +endproc BACKSP,FAR + +procedure DIVOV,FAR + NOP +endproc DIVOV,FAR + +procedure STAY_RESIDENT,FAR + NOP +endproc STAY_RESIDENT,FAR + +procedure CTRLZ,FAR + NOP +endproc CTRLZ,FAR + +procedure EXITINS,FAR + NOP +endproc EXITINS,FAR + +procedure OKCALL,FAR + NOP +endproc OKCALL,FAR + +procedure SKIPSTR,FAR + NOP +endproc SKIPSTR,FAR + +procedure ABSDWRT,FAR + NOP +endproc ABSDWRT,FAR + +procedure BADCALL,FAR + NOP +endproc BADCALL,FAR + +procedure REEDIT,FAR + NOP +endproc REEDIT,FAR + + +procedure INULDEV,FAR + NOP +endproc INULDEV,FAR + +procedure ABSDRD,FAR + NOP +endproc ABSDRD,FAR + +procedure SNULDEV,FAR + NOP +endproc SNULDEV,FAR + +procedure COPYSTR,FAR + NOP +endproc COPYSTR,FAR + +procedure ECRITDEVICE,FAR + NOP +endproc ECRITDEVICE,FAR + +procedure COMMAND,FAR + NOP +endproc COMMAND,FAR + +procedure ENTERINS,FAR + NOP +endproc ENTERINS,FAR + +procedure DEVIOCALL2,FAR + NOP +endproc DEVIOCALL2,FAR + +procedure FASTOPENTABLE,FAR + NOP +endproc FASTOPENTABLE,FAR + +procedure HEADER,FAR + NOP +endproc HEADER,FAR + +procedure SYSINITTABLE,FAR + NOP +endproc SYSINITTABLE,FAR + +procedure FETCHI_TAG,FAR + NOP +endproc FETCHI_TAG,FAR + +procedure IFS_DOSCALL,FAR + NOP +endproc IFS_DOSCALL,FAR + +procedure KILNEW,FAR + NOP +endproc KILNEW,FAR + +procedure PACKET_TEMP,FAR + NOP +endproc PACKET_TEMP,FAR + +procedure Swap_in_DOS_Len,FAR + NOP +endproc Swap_in_DOS_Len,FAR + +procedure swap_always_area,far + NOP +endproc swap_always_area,FAR + +procedure swap_always_area_len,FAR + NOP +endproc swap_always_area_len,FAR + +procedure swap_in_dos,FAR + NOP +endproc swap_in_dos,FAR + +code ENDS + END diff --git a/v4.0/src/CMD/SHARE/SHARESR.ASM b/v4.0/src/CMD/SHARE/SHARESR.ASM new file mode 100644 index 0000000..4da66db --- /dev/null +++ b/v4.0/src/CMD/SHARE/SHARESR.ASM @@ -0,0 +1,73 @@ + Title Sharesr - IBM CONFIDENTIAL +; $SALUT (0,36,41,44) + include SHAREHDR.INC +; +; Label: "The DOS SHARE Utility" +; "Version 4.00 (C) Copyright 1988 Microsoft" +; "Licenced Material - Program Property of Microsoft" +; +;******************* END OF SPECIFICATIONS ************************************* + + NAME Sharsr + + .xlist + .xcref + + include SYSMSG.INC + + .cref + .list + + MSG_UTILNAME + +Share SEGMENT BYTE PUBLIC 'SHARE' + + PUBLIC SYSDISPMSG, SYSLOADMSG, SYSPARSE + + ASSUME CS:Share,DS:nothing,ES:nothing + + ; include Message Code + + + .xlist + .xcref + + + MSG_SERVICES + + MSG_SERVICES + + MSG_SERVICES + + MSG_SERVICES + + .cref + .list + + +false = 0 + +DateSW equ false +TimeSW equ false +CmpxSW equ false +KeySW equ false +DrvSW equ false +FileSW equ false +QusSW equ false +Val2SW equ false +Val3SW equ false + + + ; include parse.asm + .xlist + .xcref + include parse.asm + include msgdcl.inc + .cref + .list + + + +Share ENDS +END + \ No newline at end of file -- cgit v1.2.3